diff options
Diffstat (limited to 'drivers/ide/ide-taskfile.c')
-rw-r--r-- | drivers/ide/ide-taskfile.c | 72 |
1 files changed, 31 insertions, 41 deletions
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 0c9d71485728..99d6ed434978 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c | |||
@@ -55,7 +55,7 @@ int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) | |||
55 | 55 | ||
56 | static ide_startstop_t task_no_data_intr(ide_drive_t *); | 56 | static ide_startstop_t task_no_data_intr(ide_drive_t *); |
57 | static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *); | 57 | static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *); |
58 | static ide_startstop_t task_in_intr(ide_drive_t *); | 58 | static ide_startstop_t task_pio_intr(ide_drive_t *); |
59 | 59 | ||
60 | ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) | 60 | ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) |
61 | { | 61 | { |
@@ -92,7 +92,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) | |||
92 | ndelay(400); /* FIXME */ | 92 | ndelay(400); /* FIXME */ |
93 | return pre_task_out_intr(drive, cmd); | 93 | return pre_task_out_intr(drive, cmd); |
94 | } | 94 | } |
95 | handler = task_in_intr; | 95 | handler = task_pio_intr; |
96 | /* fall-through */ | 96 | /* fall-through */ |
97 | case ATA_PROT_NODATA: | 97 | case ATA_PROT_NODATA: |
98 | if (handler == NULL) | 98 | if (handler == NULL) |
@@ -329,68 +329,57 @@ static ide_startstop_t task_in_unexpected(ide_drive_t *drive, | |||
329 | } | 329 | } |
330 | 330 | ||
331 | /* Assume it was a spurious irq */ | 331 | /* Assume it was a spurious irq */ |
332 | ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); | 332 | ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE, NULL); |
333 | |||
333 | return ide_started; | 334 | return ide_started; |
334 | } | 335 | } |
335 | 336 | ||
336 | /* | 337 | /* |
337 | * Handler for command with PIO data-in phase (Read/Read Multiple). | 338 | * Handler for command with PIO data phase. |
338 | */ | 339 | */ |
339 | static ide_startstop_t task_in_intr(ide_drive_t *drive) | 340 | static ide_startstop_t task_pio_intr(ide_drive_t *drive) |
340 | { | 341 | { |
341 | ide_hwif_t *hwif = drive->hwif; | 342 | ide_hwif_t *hwif = drive->hwif; |
342 | struct ide_cmd *cmd = &drive->hwif->cmd; | 343 | struct ide_cmd *cmd = &drive->hwif->cmd; |
343 | u8 stat = hwif->tp_ops->read_status(hwif); | 344 | u8 stat = hwif->tp_ops->read_status(hwif); |
345 | u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); | ||
344 | 346 | ||
345 | /* Error? */ | 347 | if (write == 0) { |
346 | if (stat & ATA_ERR) | 348 | /* Error? */ |
347 | return task_error(drive, cmd, __func__, stat); | 349 | if (stat & ATA_ERR) |
348 | 350 | return task_error(drive, cmd, __func__, stat); | |
349 | /* Didn't want any data? Odd. */ | ||
350 | if ((stat & ATA_DRQ) == 0) | ||
351 | return task_in_unexpected(drive, cmd, stat); | ||
352 | 351 | ||
353 | ide_pio_datablock(drive, cmd, 0); | 352 | /* Didn't want any data? Odd. */ |
353 | if ((stat & ATA_DRQ) == 0) | ||
354 | return task_in_unexpected(drive, cmd, stat); | ||
355 | } else { | ||
356 | if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) | ||
357 | return task_error(drive, cmd, __func__, stat); | ||
354 | 358 | ||
355 | /* Are we done? Check status and finish transfer. */ | 359 | /* Deal with unexpected ATA data phase. */ |
356 | if (cmd->nleft == 0) { | 360 | if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0)) |
357 | stat = wait_drive_not_busy(drive); | ||
358 | if (!OK_STAT(stat, 0, BAD_STAT)) | ||
359 | return task_error(drive, cmd, __func__, stat); | 361 | return task_error(drive, cmd, __func__, stat); |
362 | } | ||
363 | |||
364 | if (write && cmd->nleft == 0) { | ||
360 | ide_finish_cmd(drive, cmd, stat); | 365 | ide_finish_cmd(drive, cmd, stat); |
361 | return ide_stopped; | 366 | return ide_stopped; |
362 | } | 367 | } |
363 | 368 | ||
364 | /* Still data left to transfer. */ | 369 | /* Still data left to transfer. */ |
365 | ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); | 370 | ide_pio_datablock(drive, cmd, write); |
366 | |||
367 | return ide_started; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Handler for command with PIO data-out phase (Write/Write Multiple). | ||
372 | */ | ||
373 | static ide_startstop_t task_out_intr (ide_drive_t *drive) | ||
374 | { | ||
375 | ide_hwif_t *hwif = drive->hwif; | ||
376 | struct ide_cmd *cmd = &drive->hwif->cmd; | ||
377 | u8 stat = hwif->tp_ops->read_status(hwif); | ||
378 | |||
379 | if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) | ||
380 | return task_error(drive, cmd, __func__, stat); | ||
381 | 371 | ||
382 | /* Deal with unexpected ATA data phase. */ | 372 | /* Are we done? Check status and finish transfer. */ |
383 | if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0)) | 373 | if (write == 0 && cmd->nleft == 0) { |
384 | return task_error(drive, cmd, __func__, stat); | 374 | stat = wait_drive_not_busy(drive); |
385 | 375 | if (!OK_STAT(stat, 0, BAD_STAT)) | |
386 | if (cmd->nleft == 0) { | 376 | return task_error(drive, cmd, __func__, stat); |
387 | ide_finish_cmd(drive, cmd, stat); | 377 | ide_finish_cmd(drive, cmd, stat); |
388 | return ide_stopped; | 378 | return ide_stopped; |
389 | } | 379 | } |
390 | 380 | ||
391 | /* Still data left to transfer. */ | 381 | /* Still data left to transfer. */ |
392 | ide_pio_datablock(drive, cmd, 1); | 382 | ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE, NULL); |
393 | ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); | ||
394 | 383 | ||
395 | return ide_started; | 384 | return ide_started; |
396 | } | 385 | } |
@@ -412,7 +401,8 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, | |||
412 | if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0) | 401 | if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0) |
413 | local_irq_disable(); | 402 | local_irq_disable(); |
414 | 403 | ||
415 | ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); | 404 | ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE, NULL); |
405 | |||
416 | ide_pio_datablock(drive, cmd, 1); | 406 | ide_pio_datablock(drive, cmd, 1); |
417 | 407 | ||
418 | return ide_started; | 408 | return ide_started; |