diff options
Diffstat (limited to 'drivers/ide/ide-taskfile.c')
-rw-r--r-- | drivers/ide/ide-taskfile.c | 448 |
1 files changed, 205 insertions, 243 deletions
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 16138bce84a7..84532be97c00 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c | |||
@@ -39,88 +39,86 @@ void ide_tf_dump(const char *s, struct ide_taskfile *tf) | |||
39 | 39 | ||
40 | int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) | 40 | int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) |
41 | { | 41 | { |
42 | ide_task_t args; | 42 | struct ide_cmd cmd; |
43 | 43 | ||
44 | memset(&args, 0, sizeof(ide_task_t)); | 44 | memset(&cmd, 0, sizeof(cmd)); |
45 | args.tf.nsect = 0x01; | 45 | cmd.tf.nsect = 0x01; |
46 | if (drive->media == ide_disk) | 46 | if (drive->media == ide_disk) |
47 | args.tf.command = ATA_CMD_ID_ATA; | 47 | cmd.tf.command = ATA_CMD_ID_ATA; |
48 | else | 48 | else |
49 | args.tf.command = ATA_CMD_ID_ATAPI; | 49 | cmd.tf.command = ATA_CMD_ID_ATAPI; |
50 | args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; | 50 | cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; |
51 | args.data_phase = TASKFILE_IN; | 51 | cmd.protocol = ATA_PROT_PIO; |
52 | return ide_raw_taskfile(drive, &args, buf, 1); | 52 | |
53 | return ide_raw_taskfile(drive, &cmd, buf, 1); | ||
53 | } | 54 | } |
54 | 55 | ||
55 | static ide_startstop_t task_no_data_intr(ide_drive_t *); | 56 | static ide_startstop_t task_no_data_intr(ide_drive_t *); |
56 | static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); | 57 | static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *); |
57 | static ide_startstop_t task_in_intr(ide_drive_t *); | 58 | static ide_startstop_t task_pio_intr(ide_drive_t *); |
58 | 59 | ||
59 | ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) | 60 | ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) |
60 | { | 61 | { |
61 | ide_hwif_t *hwif = drive->hwif; | 62 | ide_hwif_t *hwif = drive->hwif; |
62 | struct ide_taskfile *tf = &task->tf; | 63 | struct ide_cmd *cmd = &hwif->cmd; |
64 | struct ide_taskfile *tf = &cmd->tf; | ||
63 | ide_handler_t *handler = NULL; | 65 | ide_handler_t *handler = NULL; |
64 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 66 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
65 | const struct ide_dma_ops *dma_ops = hwif->dma_ops; | 67 | const struct ide_dma_ops *dma_ops = hwif->dma_ops; |
66 | 68 | ||
67 | if (task->data_phase == TASKFILE_MULTI_IN || | 69 | if (orig_cmd->protocol == ATA_PROT_PIO && |
68 | task->data_phase == TASKFILE_MULTI_OUT) { | 70 | (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) && |
69 | if (!drive->mult_count) { | 71 | drive->mult_count == 0) { |
70 | printk(KERN_ERR "%s: multimode not set!\n", | 72 | printk(KERN_ERR "%s: multimode not set!\n", drive->name); |
71 | drive->name); | 73 | return ide_stopped; |
72 | return ide_stopped; | ||
73 | } | ||
74 | } | 74 | } |
75 | 75 | ||
76 | if (task->tf_flags & IDE_TFLAG_FLAGGED) | 76 | if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED) |
77 | task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS; | 77 | orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS; |
78 | 78 | ||
79 | memcpy(&hwif->task, task, sizeof(*task)); | 79 | memcpy(cmd, orig_cmd, sizeof(*cmd)); |
80 | 80 | ||
81 | if ((task->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->set_irq(hwif, 1); |
84 | SELECT_MASK(drive, 0); | 84 | SELECT_MASK(drive, 0); |
85 | tp_ops->tf_load(drive, task); | 85 | tp_ops->tf_load(drive, cmd); |
86 | } | 86 | } |
87 | 87 | ||
88 | switch (task->data_phase) { | 88 | switch (cmd->protocol) { |
89 | case TASKFILE_MULTI_OUT: | 89 | case ATA_PROT_PIO: |
90 | case TASKFILE_OUT: | 90 | if (cmd->tf_flags & IDE_TFLAG_WRITE) { |
91 | tp_ops->exec_command(hwif, tf->command); | 91 | tp_ops->exec_command(hwif, tf->command); |
92 | ndelay(400); /* FIXME */ | 92 | ndelay(400); /* FIXME */ |
93 | return pre_task_out_intr(drive, task->rq); | 93 | return pre_task_out_intr(drive, cmd); |
94 | case TASKFILE_MULTI_IN: | 94 | } |
95 | case TASKFILE_IN: | 95 | handler = task_pio_intr; |
96 | handler = task_in_intr; | ||
97 | /* fall-through */ | 96 | /* fall-through */ |
98 | case TASKFILE_NO_DATA: | 97 | case ATA_PROT_NODATA: |
99 | if (handler == NULL) | 98 | if (handler == NULL) |
100 | handler = task_no_data_intr; | 99 | handler = task_no_data_intr; |
101 | ide_execute_command(drive, tf->command, handler, | 100 | ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE); |
102 | WAIT_WORSTCASE, NULL); | ||
103 | return ide_started; | 101 | return ide_started; |
104 | default: | 102 | case ATA_PROT_DMA: |
105 | if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || | 103 | if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || |
106 | dma_ops->dma_setup(drive)) | 104 | ide_build_sglist(drive, cmd) == 0 || |
105 | dma_ops->dma_setup(drive, cmd)) | ||
107 | return ide_stopped; | 106 | return ide_stopped; |
108 | dma_ops->dma_exec_cmd(drive, tf->command); | 107 | hwif->expiry = dma_ops->dma_timer_expiry; |
108 | ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); | ||
109 | dma_ops->dma_start(drive); | 109 | dma_ops->dma_start(drive); |
110 | default: | ||
110 | return ide_started; | 111 | return ide_started; |
111 | } | 112 | } |
112 | } | 113 | } |
113 | EXPORT_SYMBOL_GPL(do_rw_taskfile); | 114 | EXPORT_SYMBOL_GPL(do_rw_taskfile); |
114 | 115 | ||
115 | /* | ||
116 | * Handler for commands without a data phase | ||
117 | */ | ||
118 | static ide_startstop_t task_no_data_intr(ide_drive_t *drive) | 116 | static ide_startstop_t task_no_data_intr(ide_drive_t *drive) |
119 | { | 117 | { |
120 | ide_hwif_t *hwif = drive->hwif; | 118 | ide_hwif_t *hwif = drive->hwif; |
121 | ide_task_t *task = &hwif->task; | 119 | struct ide_cmd *cmd = &hwif->cmd; |
122 | struct ide_taskfile *tf = &task->tf; | 120 | struct ide_taskfile *tf = &cmd->tf; |
123 | int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0; | 121 | int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0; |
124 | int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1; | 122 | int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1; |
125 | u8 stat; | 123 | u8 stat; |
126 | 124 | ||
@@ -142,28 +140,26 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) | |||
142 | } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { | 140 | } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { |
143 | if ((stat & (ATA_ERR | ATA_DRQ)) == 0) { | 141 | if ((stat & (ATA_ERR | ATA_DRQ)) == 0) { |
144 | ide_set_handler(drive, &task_no_data_intr, | 142 | ide_set_handler(drive, &task_no_data_intr, |
145 | WAIT_WORSTCASE, NULL); | 143 | WAIT_WORSTCASE); |
146 | return ide_started; | 144 | return ide_started; |
147 | } | 145 | } |
148 | } | 146 | } |
149 | return ide_error(drive, "task_no_data_intr", stat); | 147 | return ide_error(drive, "task_no_data_intr", stat); |
150 | /* calls ide_end_drive_cmd */ | ||
151 | } | 148 | } |
152 | 149 | ||
153 | if (!custom) | 150 | if (custom && tf->command == ATA_CMD_SET_MULTI) |
154 | ide_end_drive_cmd(drive, stat, ide_read_error(drive)); | ||
155 | else if (tf->command == ATA_CMD_IDLEIMMEDIATE) { | ||
156 | hwif->tp_ops->tf_read(drive, task); | ||
157 | if (tf->lbal != 0xc4) { | ||
158 | printk(KERN_ERR "%s: head unload failed!\n", | ||
159 | drive->name); | ||
160 | ide_tf_dump(drive->name, tf); | ||
161 | } else | ||
162 | drive->dev_flags |= IDE_DFLAG_PARKED; | ||
163 | ide_end_drive_cmd(drive, stat, ide_read_error(drive)); | ||
164 | } else if (tf->command == ATA_CMD_SET_MULTI) | ||
165 | drive->mult_count = drive->mult_req; | 151 | drive->mult_count = drive->mult_req; |
166 | 152 | ||
153 | if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE || | ||
154 | tf->command == ATA_CMD_CHK_POWER) { | ||
155 | struct request *rq = hwif->rq; | ||
156 | |||
157 | if (blk_pm_request(rq)) | ||
158 | ide_complete_pm_rq(drive, rq); | ||
159 | else | ||
160 | ide_finish_cmd(drive, cmd, stat); | ||
161 | } | ||
162 | |||
167 | return ide_stopped; | 163 | return ide_stopped; |
168 | } | 164 | } |
169 | 165 | ||
@@ -192,12 +188,12 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) | |||
192 | return stat; | 188 | return stat; |
193 | } | 189 | } |
194 | 190 | ||
195 | static void ide_pio_sector(ide_drive_t *drive, struct request *rq, | 191 | static void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, |
196 | unsigned int write) | 192 | unsigned int write, unsigned int nr_bytes) |
197 | { | 193 | { |
198 | ide_hwif_t *hwif = drive->hwif; | 194 | ide_hwif_t *hwif = drive->hwif; |
199 | struct scatterlist *sg = hwif->sg_table; | 195 | struct scatterlist *sg = hwif->sg_table; |
200 | struct scatterlist *cursg = hwif->cursg; | 196 | struct scatterlist *cursg = cmd->cursg; |
201 | struct page *page; | 197 | struct page *page; |
202 | #ifdef CONFIG_HIGHMEM | 198 | #ifdef CONFIG_HIGHMEM |
203 | unsigned long flags; | 199 | unsigned long flags; |
@@ -205,14 +201,14 @@ static void ide_pio_sector(ide_drive_t *drive, struct request *rq, | |||
205 | unsigned int offset; | 201 | unsigned int offset; |
206 | u8 *buf; | 202 | u8 *buf; |
207 | 203 | ||
208 | cursg = hwif->cursg; | 204 | cursg = cmd->cursg; |
209 | if (!cursg) { | 205 | if (!cursg) { |
210 | cursg = sg; | 206 | cursg = sg; |
211 | hwif->cursg = sg; | 207 | cmd->cursg = sg; |
212 | } | 208 | } |
213 | 209 | ||
214 | page = sg_page(cursg); | 210 | page = sg_page(cursg); |
215 | offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE; | 211 | offset = cursg->offset + cmd->cursg_ofs; |
216 | 212 | ||
217 | /* get the current page and offset */ | 213 | /* get the current page and offset */ |
218 | page = nth_page(page, (offset >> PAGE_SHIFT)); | 214 | page = nth_page(page, (offset >> PAGE_SHIFT)); |
@@ -223,19 +219,19 @@ static void ide_pio_sector(ide_drive_t *drive, struct request *rq, | |||
223 | #endif | 219 | #endif |
224 | buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; | 220 | buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; |
225 | 221 | ||
226 | hwif->nleft--; | 222 | cmd->nleft -= nr_bytes; |
227 | hwif->cursg_ofs++; | 223 | cmd->cursg_ofs += nr_bytes; |
228 | 224 | ||
229 | if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) { | 225 | if (cmd->cursg_ofs == cursg->length) { |
230 | hwif->cursg = sg_next(hwif->cursg); | 226 | cmd->cursg = sg_next(cmd->cursg); |
231 | hwif->cursg_ofs = 0; | 227 | cmd->cursg_ofs = 0; |
232 | } | 228 | } |
233 | 229 | ||
234 | /* do the actual data transfer */ | 230 | /* do the actual data transfer */ |
235 | if (write) | 231 | if (write) |
236 | hwif->tp_ops->output_data(drive, rq, buf, SECTOR_SIZE); | 232 | hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes); |
237 | else | 233 | else |
238 | hwif->tp_ops->input_data(drive, rq, buf, SECTOR_SIZE); | 234 | hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); |
239 | 235 | ||
240 | kunmap_atomic(buf, KM_BIO_SRC_IRQ); | 236 | kunmap_atomic(buf, KM_BIO_SRC_IRQ); |
241 | #ifdef CONFIG_HIGHMEM | 237 | #ifdef CONFIG_HIGHMEM |
@@ -243,188 +239,137 @@ static void ide_pio_sector(ide_drive_t *drive, struct request *rq, | |||
243 | #endif | 239 | #endif |
244 | } | 240 | } |
245 | 241 | ||
246 | static void ide_pio_multi(ide_drive_t *drive, struct request *rq, | 242 | static void ide_pio_multi(ide_drive_t *drive, struct ide_cmd *cmd, |
247 | unsigned int write) | 243 | unsigned int write) |
248 | { | 244 | { |
249 | unsigned int nsect; | 245 | unsigned int nsect; |
250 | 246 | ||
251 | nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count); | 247 | nsect = min_t(unsigned int, cmd->nleft >> 9, drive->mult_count); |
252 | while (nsect--) | 248 | while (nsect--) |
253 | ide_pio_sector(drive, rq, write); | 249 | ide_pio_bytes(drive, cmd, write, SECTOR_SIZE); |
254 | } | 250 | } |
255 | 251 | ||
256 | static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, | 252 | static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, |
257 | unsigned int write) | 253 | unsigned int write) |
258 | { | 254 | { |
259 | u8 saved_io_32bit = drive->io_32bit; | 255 | u8 saved_io_32bit = drive->io_32bit; |
260 | 256 | ||
261 | if (rq->bio) /* fs request */ | 257 | if (cmd->tf_flags & IDE_TFLAG_FS) |
262 | rq->errors = 0; | 258 | cmd->rq->errors = 0; |
263 | 259 | ||
264 | if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { | 260 | if (cmd->tf_flags & IDE_TFLAG_IO_16BIT) |
265 | ide_task_t *task = rq->special; | 261 | drive->io_32bit = 0; |
266 | |||
267 | if (task->tf_flags & IDE_TFLAG_IO_16BIT) | ||
268 | drive->io_32bit = 0; | ||
269 | } | ||
270 | 262 | ||
271 | touch_softlockup_watchdog(); | 263 | touch_softlockup_watchdog(); |
272 | 264 | ||
273 | switch (drive->hwif->data_phase) { | 265 | if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) |
274 | case TASKFILE_MULTI_IN: | 266 | ide_pio_multi(drive, cmd, write); |
275 | case TASKFILE_MULTI_OUT: | 267 | else |
276 | ide_pio_multi(drive, rq, write); | 268 | ide_pio_bytes(drive, cmd, write, SECTOR_SIZE); |
277 | break; | ||
278 | default: | ||
279 | ide_pio_sector(drive, rq, write); | ||
280 | break; | ||
281 | } | ||
282 | 269 | ||
283 | drive->io_32bit = saved_io_32bit; | 270 | drive->io_32bit = saved_io_32bit; |
284 | } | 271 | } |
285 | 272 | ||
286 | static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, | 273 | static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) |
287 | const char *s, u8 stat) | ||
288 | { | 274 | { |
289 | if (rq->bio) { | 275 | if (cmd->tf_flags & IDE_TFLAG_FS) { |
290 | ide_hwif_t *hwif = drive->hwif; | 276 | int nr_bytes = cmd->nbytes - cmd->nleft; |
291 | int sectors = hwif->nsect - hwif->nleft; | 277 | |
292 | 278 | if (cmd->protocol == ATA_PROT_PIO && | |
293 | switch (hwif->data_phase) { | 279 | ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) { |
294 | case TASKFILE_IN: | 280 | if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) |
295 | if (hwif->nleft) | 281 | nr_bytes -= drive->mult_count << 9; |
296 | break; | 282 | else |
297 | /* fall through */ | 283 | nr_bytes -= SECTOR_SIZE; |
298 | case TASKFILE_OUT: | ||
299 | sectors--; | ||
300 | break; | ||
301 | case TASKFILE_MULTI_IN: | ||
302 | if (hwif->nleft) | ||
303 | break; | ||
304 | /* fall through */ | ||
305 | case TASKFILE_MULTI_OUT: | ||
306 | sectors -= drive->mult_count; | ||
307 | default: | ||
308 | break; | ||
309 | } | 284 | } |
310 | 285 | ||
311 | if (sectors > 0) { | 286 | if (nr_bytes > 0) |
312 | struct ide_driver *drv; | 287 | ide_complete_rq(drive, 0, nr_bytes); |
313 | |||
314 | drv = *(struct ide_driver **)rq->rq_disk->private_data; | ||
315 | drv->end_request(drive, 1, sectors); | ||
316 | } | ||
317 | } | 288 | } |
318 | return ide_error(drive, s, stat); | ||
319 | } | ||
320 | |||
321 | void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) | ||
322 | { | ||
323 | if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { | ||
324 | u8 err = ide_read_error(drive); | ||
325 | |||
326 | ide_end_drive_cmd(drive, stat, err); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | if (rq->rq_disk) { | ||
331 | struct ide_driver *drv; | ||
332 | |||
333 | drv = *(struct ide_driver **)rq->rq_disk->private_data;; | ||
334 | drv->end_request(drive, 1, rq->nr_sectors); | ||
335 | } else | ||
336 | ide_end_request(drive, 1, rq->nr_sectors); | ||
337 | } | 289 | } |
338 | 290 | ||
339 | /* | 291 | void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) |
340 | * We got an interrupt on a task_in case, but no errors and no DRQ. | ||
341 | * | ||
342 | * It might be a spurious irq (shared irq), but it might be a | ||
343 | * command that had no output. | ||
344 | */ | ||
345 | static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat) | ||
346 | { | 292 | { |
347 | /* Command all done? */ | 293 | struct request *rq = drive->hwif->rq; |
348 | if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) { | 294 | u8 err = ide_read_error(drive); |
349 | task_end_request(drive, rq, stat); | ||
350 | return ide_stopped; | ||
351 | } | ||
352 | 295 | ||
353 | /* Assume it was a spurious irq */ | 296 | ide_complete_cmd(drive, cmd, stat, err); |
354 | ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); | 297 | rq->errors = err; |
355 | return ide_started; | 298 | ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); |
356 | } | 299 | } |
357 | 300 | ||
358 | /* | 301 | /* |
359 | * Handler for command with PIO data-in phase (Read/Read Multiple). | 302 | * Handler for command with PIO data phase. |
360 | */ | 303 | */ |
361 | static ide_startstop_t task_in_intr(ide_drive_t *drive) | 304 | static ide_startstop_t task_pio_intr(ide_drive_t *drive) |
362 | { | 305 | { |
363 | ide_hwif_t *hwif = drive->hwif; | 306 | ide_hwif_t *hwif = drive->hwif; |
364 | struct request *rq = hwif->rq; | 307 | struct ide_cmd *cmd = &drive->hwif->cmd; |
365 | u8 stat = hwif->tp_ops->read_status(hwif); | 308 | u8 stat = hwif->tp_ops->read_status(hwif); |
309 | u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); | ||
366 | 310 | ||
367 | /* Error? */ | 311 | if (write == 0) { |
368 | if (stat & ATA_ERR) | 312 | /* Error? */ |
369 | return task_error(drive, rq, __func__, stat); | 313 | if (stat & ATA_ERR) |
314 | goto out_err; | ||
370 | 315 | ||
371 | /* Didn't want any data? Odd. */ | 316 | /* Didn't want any data? Odd. */ |
372 | if ((stat & ATA_DRQ) == 0) | 317 | if ((stat & ATA_DRQ) == 0) { |
373 | return task_in_unexpected(drive, rq, stat); | 318 | /* Command all done? */ |
319 | if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) | ||
320 | goto out_end; | ||
374 | 321 | ||
375 | ide_pio_datablock(drive, rq, 0); | 322 | /* Assume it was a spurious irq */ |
323 | goto out_wait; | ||
324 | } | ||
325 | } else { | ||
326 | if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) | ||
327 | goto out_err; | ||
376 | 328 | ||
377 | /* Are we done? Check status and finish transfer. */ | 329 | /* Deal with unexpected ATA data phase. */ |
378 | if (!hwif->nleft) { | 330 | if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0)) |
379 | stat = wait_drive_not_busy(drive); | 331 | goto out_err; |
380 | if (!OK_STAT(stat, 0, BAD_STAT)) | ||
381 | return task_error(drive, rq, __func__, stat); | ||
382 | task_end_request(drive, rq, stat); | ||
383 | return ide_stopped; | ||
384 | } | 332 | } |
385 | 333 | ||
386 | /* Still data left to transfer. */ | 334 | if (write && cmd->nleft == 0) |
387 | ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); | 335 | goto out_end; |
388 | 336 | ||
389 | return ide_started; | 337 | /* Still data left to transfer. */ |
390 | } | 338 | ide_pio_datablock(drive, cmd, write); |
391 | |||
392 | /* | ||
393 | * Handler for command with PIO data-out phase (Write/Write Multiple). | ||
394 | */ | ||
395 | static ide_startstop_t task_out_intr (ide_drive_t *drive) | ||
396 | { | ||
397 | ide_hwif_t *hwif = drive->hwif; | ||
398 | struct request *rq = hwif->rq; | ||
399 | u8 stat = hwif->tp_ops->read_status(hwif); | ||
400 | |||
401 | if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) | ||
402 | return task_error(drive, rq, __func__, stat); | ||
403 | 339 | ||
404 | /* Deal with unexpected ATA data phase. */ | 340 | /* Are we done? Check status and finish transfer. */ |
405 | if (((stat & ATA_DRQ) == 0) ^ !hwif->nleft) | 341 | if (write == 0 && cmd->nleft == 0) { |
406 | return task_error(drive, rq, __func__, stat); | 342 | stat = wait_drive_not_busy(drive); |
343 | if (!OK_STAT(stat, 0, BAD_STAT)) | ||
344 | goto out_err; | ||
407 | 345 | ||
408 | if (!hwif->nleft) { | 346 | goto out_end; |
409 | task_end_request(drive, rq, stat); | ||
410 | return ide_stopped; | ||
411 | } | 347 | } |
412 | 348 | out_wait: | |
413 | /* Still data left to transfer. */ | 349 | /* Still data left to transfer. */ |
414 | ide_pio_datablock(drive, rq, 1); | 350 | ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); |
415 | ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); | ||
416 | |||
417 | return ide_started; | 351 | return ide_started; |
352 | out_end: | ||
353 | if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) | ||
354 | ide_finish_cmd(drive, cmd, stat); | ||
355 | else | ||
356 | ide_complete_rq(drive, 0, cmd->rq->nr_sectors << 9); | ||
357 | return ide_stopped; | ||
358 | out_err: | ||
359 | ide_error_cmd(drive, cmd); | ||
360 | return ide_error(drive, __func__, stat); | ||
418 | } | 361 | } |
419 | 362 | ||
420 | static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq) | 363 | static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, |
364 | struct ide_cmd *cmd) | ||
421 | { | 365 | { |
422 | ide_startstop_t startstop; | 366 | ide_startstop_t startstop; |
423 | 367 | ||
424 | if (ide_wait_stat(&startstop, drive, ATA_DRQ, | 368 | if (ide_wait_stat(&startstop, drive, ATA_DRQ, |
425 | drive->bad_wstat, WAIT_DRQ)) { | 369 | drive->bad_wstat, WAIT_DRQ)) { |
426 | printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", | 370 | printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", |
427 | drive->name, drive->hwif->data_phase ? "MULT" : "", | 371 | drive->name, |
372 | (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "", | ||
428 | (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : ""); | 373 | (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : ""); |
429 | return startstop; | 374 | return startstop; |
430 | } | 375 | } |
@@ -432,13 +377,15 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq) | |||
432 | if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0) | 377 | if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0) |
433 | local_irq_disable(); | 378 | local_irq_disable(); |
434 | 379 | ||
435 | ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); | 380 | ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); |
436 | ide_pio_datablock(drive, rq, 1); | 381 | |
382 | ide_pio_datablock(drive, cmd, 1); | ||
437 | 383 | ||
438 | return ide_started; | 384 | return ide_started; |
439 | } | 385 | } |
440 | 386 | ||
441 | int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) | 387 | int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, |
388 | u16 nsect) | ||
442 | { | 389 | { |
443 | struct request *rq; | 390 | struct request *rq; |
444 | int error; | 391 | int error; |
@@ -456,11 +403,11 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) | |||
456 | rq->hard_nr_sectors = rq->nr_sectors = nsect; | 403 | rq->hard_nr_sectors = rq->nr_sectors = nsect; |
457 | rq->hard_cur_sectors = rq->current_nr_sectors = nsect; | 404 | rq->hard_cur_sectors = rq->current_nr_sectors = nsect; |
458 | 405 | ||
459 | if (task->tf_flags & IDE_TFLAG_WRITE) | 406 | if (cmd->tf_flags & IDE_TFLAG_WRITE) |
460 | rq->cmd_flags |= REQ_RW; | 407 | rq->cmd_flags |= REQ_RW; |
461 | 408 | ||
462 | rq->special = task; | 409 | rq->special = cmd; |
463 | task->rq = rq; | 410 | cmd->rq = rq; |
464 | 411 | ||
465 | error = blk_execute_rq(drive->queue, NULL, rq, 0); | 412 | error = blk_execute_rq(drive->queue, NULL, rq, 0); |
466 | blk_put_request(rq); | 413 | blk_put_request(rq); |
@@ -470,19 +417,19 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) | |||
470 | 417 | ||
471 | EXPORT_SYMBOL(ide_raw_taskfile); | 418 | EXPORT_SYMBOL(ide_raw_taskfile); |
472 | 419 | ||
473 | int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task) | 420 | int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd) |
474 | { | 421 | { |
475 | task->data_phase = TASKFILE_NO_DATA; | 422 | cmd->protocol = ATA_PROT_NODATA; |
476 | 423 | ||
477 | return ide_raw_taskfile(drive, task, NULL, 0); | 424 | return ide_raw_taskfile(drive, cmd, NULL, 0); |
478 | } | 425 | } |
479 | EXPORT_SYMBOL_GPL(ide_no_data_taskfile); | 426 | EXPORT_SYMBOL_GPL(ide_no_data_taskfile); |
480 | 427 | ||
481 | #ifdef CONFIG_IDE_TASK_IOCTL | 428 | #ifdef CONFIG_IDE_TASK_IOCTL |
482 | int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | 429 | int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg) |
483 | { | 430 | { |
484 | ide_task_request_t *req_task; | 431 | ide_task_request_t *req_task; |
485 | ide_task_t args; | 432 | struct ide_cmd cmd; |
486 | u8 *outbuf = NULL; | 433 | u8 *outbuf = NULL; |
487 | u8 *inbuf = NULL; | 434 | u8 *inbuf = NULL; |
488 | u8 *data_buf = NULL; | 435 | u8 *data_buf = NULL; |
@@ -536,53 +483,63 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | |||
536 | } | 483 | } |
537 | } | 484 | } |
538 | 485 | ||
539 | memset(&args, 0, sizeof(ide_task_t)); | 486 | memset(&cmd, 0, sizeof(cmd)); |
540 | 487 | ||
541 | memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2); | 488 | memcpy(&cmd.tf_array[0], req_task->hob_ports, |
542 | memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); | 489 | HDIO_DRIVE_HOB_HDR_SIZE - 2); |
490 | memcpy(&cmd.tf_array[6], req_task->io_ports, | ||
491 | HDIO_DRIVE_TASK_HDR_SIZE); | ||
543 | 492 | ||
544 | args.data_phase = req_task->data_phase; | 493 | cmd.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE | |
494 | IDE_TFLAG_IN_TF; | ||
545 | 495 | ||
546 | args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE | | ||
547 | IDE_TFLAG_IN_TF; | ||
548 | if (drive->dev_flags & IDE_DFLAG_LBA48) | 496 | if (drive->dev_flags & IDE_DFLAG_LBA48) |
549 | args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB); | 497 | cmd.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB); |
550 | 498 | ||
551 | if (req_task->out_flags.all) { | 499 | if (req_task->out_flags.all) { |
552 | args.tf_flags |= IDE_TFLAG_FLAGGED; | 500 | cmd.ftf_flags |= IDE_FTFLAG_FLAGGED; |
553 | 501 | ||
554 | if (req_task->out_flags.b.data) | 502 | if (req_task->out_flags.b.data) |
555 | args.tf_flags |= IDE_TFLAG_OUT_DATA; | 503 | cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA; |
556 | 504 | ||
557 | if (req_task->out_flags.b.nsector_hob) | 505 | if (req_task->out_flags.b.nsector_hob) |
558 | args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT; | 506 | cmd.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT; |
559 | if (req_task->out_flags.b.sector_hob) | 507 | if (req_task->out_flags.b.sector_hob) |
560 | args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL; | 508 | cmd.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL; |
561 | if (req_task->out_flags.b.lcyl_hob) | 509 | if (req_task->out_flags.b.lcyl_hob) |
562 | args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM; | 510 | cmd.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM; |
563 | if (req_task->out_flags.b.hcyl_hob) | 511 | if (req_task->out_flags.b.hcyl_hob) |
564 | args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH; | 512 | cmd.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH; |
565 | 513 | ||
566 | if (req_task->out_flags.b.error_feature) | 514 | if (req_task->out_flags.b.error_feature) |
567 | args.tf_flags |= IDE_TFLAG_OUT_FEATURE; | 515 | cmd.tf_flags |= IDE_TFLAG_OUT_FEATURE; |
568 | if (req_task->out_flags.b.nsector) | 516 | if (req_task->out_flags.b.nsector) |
569 | args.tf_flags |= IDE_TFLAG_OUT_NSECT; | 517 | cmd.tf_flags |= IDE_TFLAG_OUT_NSECT; |
570 | if (req_task->out_flags.b.sector) | 518 | if (req_task->out_flags.b.sector) |
571 | args.tf_flags |= IDE_TFLAG_OUT_LBAL; | 519 | cmd.tf_flags |= IDE_TFLAG_OUT_LBAL; |
572 | if (req_task->out_flags.b.lcyl) | 520 | if (req_task->out_flags.b.lcyl) |
573 | args.tf_flags |= IDE_TFLAG_OUT_LBAM; | 521 | cmd.tf_flags |= IDE_TFLAG_OUT_LBAM; |
574 | if (req_task->out_flags.b.hcyl) | 522 | if (req_task->out_flags.b.hcyl) |
575 | args.tf_flags |= IDE_TFLAG_OUT_LBAH; | 523 | cmd.tf_flags |= IDE_TFLAG_OUT_LBAH; |
576 | } else { | 524 | } else { |
577 | args.tf_flags |= IDE_TFLAG_OUT_TF; | 525 | cmd.tf_flags |= IDE_TFLAG_OUT_TF; |
578 | if (args.tf_flags & IDE_TFLAG_LBA48) | 526 | if (cmd.tf_flags & IDE_TFLAG_LBA48) |
579 | args.tf_flags |= IDE_TFLAG_OUT_HOB; | 527 | cmd.tf_flags |= IDE_TFLAG_OUT_HOB; |
580 | } | 528 | } |
581 | 529 | ||
582 | if (req_task->in_flags.b.data) | 530 | if (req_task->in_flags.b.data) |
583 | args.tf_flags |= IDE_TFLAG_IN_DATA; | 531 | cmd.ftf_flags |= IDE_FTFLAG_IN_DATA; |
584 | 532 | ||
585 | switch(req_task->data_phase) { | 533 | if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) { |
534 | /* fixup data phase if needed */ | ||
535 | if (req_task->data_phase == TASKFILE_IN_DMAQ || | ||
536 | req_task->data_phase == TASKFILE_IN_DMA) | ||
537 | cmd.tf_flags |= IDE_TFLAG_WRITE; | ||
538 | } | ||
539 | |||
540 | cmd.protocol = ATA_PROT_DMA; | ||
541 | |||
542 | switch (req_task->data_phase) { | ||
586 | case TASKFILE_MULTI_OUT: | 543 | case TASKFILE_MULTI_OUT: |
587 | if (!drive->mult_count) { | 544 | if (!drive->mult_count) { |
588 | /* (hs): give up if multcount is not set */ | 545 | /* (hs): give up if multcount is not set */ |
@@ -592,11 +549,14 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | |||
592 | err = -EPERM; | 549 | err = -EPERM; |
593 | goto abort; | 550 | goto abort; |
594 | } | 551 | } |
552 | cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; | ||
595 | /* fall through */ | 553 | /* fall through */ |
596 | case TASKFILE_OUT: | 554 | case TASKFILE_OUT: |
555 | cmd.protocol = ATA_PROT_PIO; | ||
597 | /* fall through */ | 556 | /* fall through */ |
598 | case TASKFILE_OUT_DMAQ: | 557 | case TASKFILE_OUT_DMAQ: |
599 | case TASKFILE_OUT_DMA: | 558 | case TASKFILE_OUT_DMA: |
559 | cmd.tf_flags |= IDE_TFLAG_WRITE; | ||
600 | nsect = taskout / SECTOR_SIZE; | 560 | nsect = taskout / SECTOR_SIZE; |
601 | data_buf = outbuf; | 561 | data_buf = outbuf; |
602 | break; | 562 | break; |
@@ -609,8 +569,10 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | |||
609 | err = -EPERM; | 569 | err = -EPERM; |
610 | goto abort; | 570 | goto abort; |
611 | } | 571 | } |
572 | cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; | ||
612 | /* fall through */ | 573 | /* fall through */ |
613 | case TASKFILE_IN: | 574 | case TASKFILE_IN: |
575 | cmd.protocol = ATA_PROT_PIO; | ||
614 | /* fall through */ | 576 | /* fall through */ |
615 | case TASKFILE_IN_DMAQ: | 577 | case TASKFILE_IN_DMAQ: |
616 | case TASKFILE_IN_DMA: | 578 | case TASKFILE_IN_DMA: |
@@ -618,6 +580,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | |||
618 | data_buf = inbuf; | 580 | data_buf = inbuf; |
619 | break; | 581 | break; |
620 | case TASKFILE_NO_DATA: | 582 | case TASKFILE_NO_DATA: |
583 | cmd.protocol = ATA_PROT_NODATA; | ||
621 | break; | 584 | break; |
622 | default: | 585 | default: |
623 | err = -EFAULT; | 586 | err = -EFAULT; |
@@ -627,7 +590,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | |||
627 | if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) | 590 | if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) |
628 | nsect = 0; | 591 | nsect = 0; |
629 | else if (!nsect) { | 592 | else if (!nsect) { |
630 | nsect = (args.tf.hob_nsect << 8) | args.tf.nsect; | 593 | nsect = (cmd.tf.hob_nsect << 8) | cmd.tf.nsect; |
631 | 594 | ||
632 | if (!nsect) { | 595 | if (!nsect) { |
633 | printk(KERN_ERR "%s: in/out command without data\n", | 596 | printk(KERN_ERR "%s: in/out command without data\n", |
@@ -637,15 +600,14 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) | |||
637 | } | 600 | } |
638 | } | 601 | } |
639 | 602 | ||
640 | if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) | 603 | err = ide_raw_taskfile(drive, &cmd, data_buf, nsect); |
641 | args.tf_flags |= IDE_TFLAG_WRITE; | ||
642 | |||
643 | err = ide_raw_taskfile(drive, &args, data_buf, nsect); | ||
644 | 604 | ||
645 | memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2); | 605 | memcpy(req_task->hob_ports, &cmd.tf_array[0], |
646 | memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE); | 606 | HDIO_DRIVE_HOB_HDR_SIZE - 2); |
607 | memcpy(req_task->io_ports, &cmd.tf_array[6], | ||
608 | HDIO_DRIVE_TASK_HDR_SIZE); | ||
647 | 609 | ||
648 | if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) && | 610 | if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) && |
649 | req_task->in_flags.all == 0) { | 611 | req_task->in_flags.all == 0) { |
650 | req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; | 612 | req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; |
651 | if (drive->dev_flags & IDE_DFLAG_LBA48) | 613 | if (drive->dev_flags & IDE_DFLAG_LBA48) |