diff -durbB linux-2.4.20-p1/drivers/ide/ide-cd.c linux-2.4.20-p2/drivers/ide/ide-cd.c --- linux-2.4.20-p1/drivers/ide/ide-cd.c Wed Jan 8 16:25:04 2003 +++ linux-2.4.20-p2/drivers/ide/ide-cd.c Thu Jan 9 11:38:22 2003 @@ -644,7 +644,11 @@ } if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { /* force an abort */ - HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + /* This violates the ATA Spec and causes trouble for + many modern hard drives. I'm not sure if it is necessary + for older devices or even modern cd-roms. -- RAB + HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); */ + rq->errors |= ERROR_RESET; } if (rq->errors >= ERROR_MAX) { DRIVER(drive)->end_request(drive, 0); diff -durbB linux-2.4.20-p1/drivers/ide/ide-disk.c linux-2.4.20-p2/drivers/ide/ide-disk.c --- linux-2.4.20-p1/drivers/ide/ide-disk.c Wed Jan 8 16:25:17 2003 +++ linux-2.4.20-p2/drivers/ide/ide-disk.c Thu Jan 9 11:40:20 2003 @@ -943,7 +943,11 @@ } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + /* This violates the ATA Spec and causes trouble for + many modern hard drives. I'm not sure if it is necessary + for older devices or even other modern devices. -- RAB + hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); */ + rq->errors |= ERROR_RESET; } if (rq->errors >= ERROR_MAX) DRIVER(drive)->end_request(drive, 0); diff -durbB linux-2.4.20-p1/drivers/ide/ide-io.c linux-2.4.20-p2/drivers/ide/ide-io.c --- linux-2.4.20-p1/drivers/ide/ide-io.c Wed Jan 8 16:25:37 2003 +++ linux-2.4.20-p2/drivers/ide/ide-io.c Mon Jan 13 18:01:52 2003 @@ -328,7 +328,12 @@ } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { /* force an abort */ + /* This violates the ATA Spec and causes trouble for + many modern hard drives. I'm not sure if it is necessary + for older devices or even other modern ata devices -- RAB hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + */ + rq->errors |= ERROR_RESET; } if (rq->errors >= ERROR_MAX) { if (drive->driver != NULL) @@ -397,18 +402,63 @@ struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); u8 *args = (u8 *) rq->buffer; - u8 stat = hwif->INB(IDE_STATUS_REG); + u8 stat; int retries = 10; + /* The ATA-6 spec requires a 400ns wait when entering the + HPIOI1: Check_status State from the HI4 state. We should + only get here coming from the HPIOI0 INTRQ_wait state, but + better safe than sorry. The spec also says a read of the + alt status register accomplishes this wait. */ + if (IDE_CONTROL_REG) + (void)hwif->INB(IDE_ALTSTATUS_REG); + else + ide_delay_400ns(); + + /* The ATA-6 spec says that the should enter the check status + state when it get's an interrupt for a drive command, so + technically, the device can send an interrupt before it has + finished. I would consider any device that does this to be + broken, but the spec allows it. --RAB 1/10/03 */ + stat = hwif->INB(IDE_STATUS_REG); + if (stat & BUSY_STAT) { + /* We are just supposed to poll from here on out. */ + if (HWGROUP(drive)->poll_timeout == 0) { + HWGROUP(drive)->poll_timeout=WAIT_CMD/CMD_POLL_TICKS; + } else if (--HWGROUP(drive)->poll_timeout == 0) { + return DRIVER(drive)->error(drive, + "drive_cmd timeout", + stat); + } + ide_set_handler(drive, drive_cmd_intr, CMD_POLL_TICKS, NULL); + return ide_started; + } + local_irq_enable(); - if ((stat & DRQ_STAT) && args && args[3]) { + + /* We want to make sure that the device and the command + both agree on wether or not data is returned by the command + that was just issued. If they do not, it is an error. */ + if (args && args[3]) { u8 io_32bit = drive->io_32bit; + /* The software expects some data back. If the drive does + not, then it is an error. */ + if (!(stat & DRQ_STAT)) { + return DRIVER(drive)->error(drive, "drive_cmd no data", stat); + } drive->io_32bit = 0; hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) udelay(100); + } else { + /* The software does not expect data, so if the drive + returns some, then it's an error. */ + if (stat & DRQ_STAT) { + return DRIVER(drive)->error(drive, "drive_cmd unexpected data", stat); + } } + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return DRIVER(drive)->error(drive, "drive_cmd", stat); diff -durbB linux-2.4.20-p1/drivers/ide/ide-taskfile.c linux-2.4.20-p2/drivers/ide/ide-taskfile.c --- linux-2.4.20-p1/drivers/ide/ide-taskfile.c Wed Jan 8 16:25:43 2003 +++ linux-2.4.20-p2/drivers/ide/ide-taskfile.c Fri Jan 10 11:19:07 2003 @@ -485,7 +485,13 @@ } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); + /* This violates the ATA Spec and causes trouble for + many modern hard drives. I'm not sure if it is necessary + for older devices or even other modern ata devices -- RAB + hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + */ + rq->errors |= ERROR_RESET; + } if (rq->errors >= ERROR_MAX) { DRIVER(drive)->end_request(drive, 0); diff -durbB linux-2.4.20-p1/include/linux/ide.h linux-2.4.20-p2/include/linux/ide.h --- linux-2.4.20-p1/include/linux/ide.h Thu Jan 9 15:37:22 2003 +++ linux-2.4.20-p2/include/linux/ide.h Mon Jan 13 18:04:47 2003 @@ -271,6 +271,10 @@ #define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ +#define CMD_POLL_TICKS (1) /* How long to wait in ticks between + status checks for a drive cmd + that set it's interrupt before it + was complete. */ #define HOST(hwif,chipset) \ { \