diff options
Diffstat (limited to 'drivers/ide/ide-taskfile.c')
-rw-r--r-- | drivers/ide/ide-taskfile.c | 96 |
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 | ||
191 | static void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, | 195 | void 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 | ||
242 | static 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 | } |
250 | EXPORT_SYMBOL_GPL(ide_pio_bytes); | ||
251 | 251 | ||
252 | static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, | 252 | static 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 | } |