aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-taskfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/ide-taskfile.c')
-rw-r--r--drivers/ide/ide-taskfile.c96
1 files changed, 50 insertions, 46 deletions
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 84532be97c0..243421ce40d 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -80,8 +80,14 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
80 80
81 if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { 81 if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
82 ide_tf_dump(drive->name, tf); 82 ide_tf_dump(drive->name, tf);
83 tp_ops->set_irq(hwif, 1); 83 tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
84 SELECT_MASK(drive, 0); 84 SELECT_MASK(drive, 0);
85
86 if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
87 u8 data[2] = { tf->data, tf->hob_data };
88
89 tp_ops->output_data(drive, cmd, data, 2);
90 }
85 tp_ops->tf_load(drive, cmd); 91 tp_ops->tf_load(drive, cmd);
86 } 92 }
87 93
@@ -100,9 +106,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
100 ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE); 106 ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
101 return ide_started; 107 return ide_started;
102 case ATA_PROT_DMA: 108 case ATA_PROT_DMA:
103 if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || 109 if (ide_dma_prepare(drive, cmd))
104 ide_build_sglist(drive, cmd) == 0 ||
105 dma_ops->dma_setup(drive, cmd))
106 return ide_stopped; 110 return ide_stopped;
107 hwif->expiry = dma_ops->dma_timer_expiry; 111 hwif->expiry = dma_ops->dma_timer_expiry;
108 ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); 112 ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
@@ -188,70 +192,68 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
188 return stat; 192 return stat;
189} 193}
190 194
191static void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, 195void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
192 unsigned int write, unsigned int nr_bytes) 196 unsigned int write, unsigned int len)
193{ 197{
194 ide_hwif_t *hwif = drive->hwif; 198 ide_hwif_t *hwif = drive->hwif;
195 struct scatterlist *sg = hwif->sg_table; 199 struct scatterlist *sg = hwif->sg_table;
196 struct scatterlist *cursg = cmd->cursg; 200 struct scatterlist *cursg = cmd->cursg;
197 struct page *page; 201 struct page *page;
198#ifdef CONFIG_HIGHMEM
199 unsigned long flags; 202 unsigned long flags;
200#endif
201 unsigned int offset; 203 unsigned int offset;
202 u8 *buf; 204 u8 *buf;
203 205
204 cursg = cmd->cursg; 206 cursg = cmd->cursg;
205 if (!cursg) { 207 if (cursg == NULL)
206 cursg = sg; 208 cursg = cmd->cursg = sg;
207 cmd->cursg = sg;
208 }
209 209
210 page = sg_page(cursg); 210 while (len) {
211 offset = cursg->offset + cmd->cursg_ofs; 211 unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
212 212
213 /* get the current page and offset */ 213 if (nr_bytes > PAGE_SIZE)
214 page = nth_page(page, (offset >> PAGE_SHIFT)); 214 nr_bytes = PAGE_SIZE;
215 offset %= PAGE_SIZE;
216 215
217#ifdef CONFIG_HIGHMEM 216 page = sg_page(cursg);
218 local_irq_save(flags); 217 offset = cursg->offset + cmd->cursg_ofs;
219#endif
220 buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
221 218
222 cmd->nleft -= nr_bytes; 219 /* get the current page and offset */
223 cmd->cursg_ofs += nr_bytes; 220 page = nth_page(page, (offset >> PAGE_SHIFT));
221 offset %= PAGE_SIZE;
224 222
225 if (cmd->cursg_ofs == cursg->length) { 223 if (PageHighMem(page))
226 cmd->cursg = sg_next(cmd->cursg); 224 local_irq_save(flags);
227 cmd->cursg_ofs = 0;
228 }
229 225
230 /* do the actual data transfer */ 226 buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
231 if (write)
232 hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
233 else
234 hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
235 227
236 kunmap_atomic(buf, KM_BIO_SRC_IRQ); 228 cmd->nleft -= nr_bytes;
237#ifdef CONFIG_HIGHMEM 229 cmd->cursg_ofs += nr_bytes;
238 local_irq_restore(flags);
239#endif
240}
241 230
242static void ide_pio_multi(ide_drive_t *drive, struct ide_cmd *cmd, 231 if (cmd->cursg_ofs == cursg->length) {
243 unsigned int write) 232 cursg = cmd->cursg = sg_next(cmd->cursg);
244{ 233 cmd->cursg_ofs = 0;
245 unsigned int nsect; 234 }
235
236 /* do the actual data transfer */
237 if (write)
238 hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
239 else
240 hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
241
242 kunmap_atomic(buf, KM_BIO_SRC_IRQ);
246 243
247 nsect = min_t(unsigned int, cmd->nleft >> 9, drive->mult_count); 244 if (PageHighMem(page))
248 while (nsect--) 245 local_irq_restore(flags);
249 ide_pio_bytes(drive, cmd, write, SECTOR_SIZE); 246
247 len -= nr_bytes;
248 }
250} 249}
250EXPORT_SYMBOL_GPL(ide_pio_bytes);
251 251
252static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, 252static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
253 unsigned int write) 253 unsigned int write)
254{ 254{
255 unsigned int nr_bytes;
256
255 u8 saved_io_32bit = drive->io_32bit; 257 u8 saved_io_32bit = drive->io_32bit;
256 258
257 if (cmd->tf_flags & IDE_TFLAG_FS) 259 if (cmd->tf_flags & IDE_TFLAG_FS)
@@ -263,9 +265,11 @@ static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
263 touch_softlockup_watchdog(); 265 touch_softlockup_watchdog();
264 266
265 if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) 267 if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
266 ide_pio_multi(drive, cmd, write); 268 nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
267 else 269 else
268 ide_pio_bytes(drive, cmd, write, SECTOR_SIZE); 270 nr_bytes = SECTOR_SIZE;
271
272 ide_pio_bytes(drive, cmd, write, nr_bytes);
269 273
270 drive->io_32bit = saved_io_32bit; 274 drive->io_32bit = saved_io_32bit;
271} 275}