Some devices raise irq early before clearing the BSY. This patch adds blacklist and waits up to 10 microseconds to workaround the early irq problem. Signed-off-by: Albert Lee <albertcc@xxxxxxxxxx> --- Ok, we should not affect the good devices. Patch revised for your review. (against the libata-dev tree 6b78c0d20ffbc89acc3c2790f8d7eded05606813). diff -Nrup 000_libata_dev/drivers/ata/libata-core.c 001_early_irq/drivers/ata/libata-core.c --- 000_libata_dev/drivers/ata/libata-core.c 2006-11-30 15:53:08.000000000 +0800 +++ 001_early_irq/drivers/ata/libata-core.c 2006-11-30 16:41:23.000000000 +0800 @@ -1610,6 +1610,9 @@ int ata_dev_configure(struct ata_device if (dev->flags & ATA_DFLAG_LBA48) dev->max_sectors = ATA_MAX_SECTORS_LBA48; + if (ata_device_blacklisted(dev) & ATA_HORKAGE_EARLY_IRQ) + dev->horkage |= ATA_HORKAGE_EARLY_IRQ; + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { /* Let the user know. We don't want to disallow opens for rescue purposes, or in case the vendor is just a blithering @@ -3184,6 +3187,9 @@ static const struct ata_blacklist_entry /* Devices with NCQ limits */ + /* Devices with early IRQ */ + { "CD-ROM 36X/AKW", NULL, ATA_HORKAGE_EARLY_IRQ }, + /* End Marker */ { } }; @@ -4989,6 +4995,11 @@ inline unsigned int ata_host_intr (struc goto idle_irq; } + /* some drives raise INTRQ early before clearing BSY */ + if (unlikely(qc->dev->horkage & ATA_HORKAGE_EARLY_IRQ)) + /* wait up to 10 microseconds for BSY to clear */ + ata_busy_wait_alt(ap, ATA_BUSY, ATA_EARLY_IRQ_WAIT); + /* check altstatus */ status = ata_altstatus(ap); if (status & ATA_BUSY) diff -Nrup 000_libata_dev/include/linux/libata.h 001_early_irq/include/linux/libata.h --- 000_libata_dev/include/linux/libata.h 2006-11-30 15:53:26.000000000 +0800 +++ 001_early_irq/include/linux/libata.h 2006-11-30 17:04:37.000000000 +0800 @@ -309,6 +309,9 @@ enum { * most devices. */ ATA_SPINUP_WAIT = 8000, + + /* early irq max wait time (for BSY to clear) in usecs */ + ATA_EARLY_IRQ_WAIT = 10, /* Horkage types. May be set by libata or controller on drives (some horkage may be drive/controller pair dependant */ @@ -316,6 +319,7 @@ enum { ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ + ATA_HORKAGE_EARLY_IRQ = (1 << 3), /* Early IRQ */ }; enum hsm_task_states { @@ -1056,6 +1060,30 @@ static inline void ata_pause(struct ata_ ndelay(400); } +/** + * ata_busy_wait_alt - Wait for a port alt status register + * @ap: Port to wait for. + * + * Waits up to max microseconds for the selected bits in the port's + * alt status register to be cleared. + * Returns final value of alt status register. + * + * LOCKING: + * Inherited from caller. + */ +static inline u8 ata_busy_wait_alt(struct ata_port *ap, unsigned int bits, + unsigned int max) +{ + u8 status = ata_altstatus(ap); + + while ((status & bits) && (max > 0)) { + udelay(1); + status = ata_altstatus(ap); + max--; + }; + + return status; +} /** * ata_busy_wait - Wait for a port status register - To unsubscribe from this list: send the line "unsubscribe linux-ide" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html