Problem:
  Kernel got "irq 5: nobody cared" when using
  libata + polling IDENTIFY + Promise 20275 adapter + Benq DW1620 drive.

  Detail message available in bug 8441 
(http://bugzilla.kernel.org/show_bug.cgi?id=8441).

Cause:
 The Benq DW1620 drive raises INTRQ during polling IDENTIFY PACKET DEVICE,
 even if nIEN = 1.

Proposed fix:
  disable_irq() during polling IDENTIFY to work around, the same as what IDE 
subsystem does.

Signed-off-by: Albert Lee <[EMAIL PROTECTED]>
---
Some controller like Intel ICH4 is immune from the problem, with the same kernel
and the same Benq DW1620 drive. So, adding the ATA_FLAG_IDENT_IRQ_OFF flag for
those adapters that needs the workaround. Patch against 2.6.21.1 for your 
review, thanks.

diff -Nrup linux-2.6.21.1-ori/drivers/ata/libata-core.c 
linux-2.6.21.1-mod2/drivers/ata/libata-core.c
--- linux-2.6.21.1-ori/drivers/ata/libata-core.c        2007-05-04 
11:22:23.000000000 +0800
+++ linux-2.6.21.1-mod2/drivers/ata/libata-core.c       2007-05-07 
11:00:02.000000000 +0800
@@ -1427,6 +1427,7 @@ int ata_dev_read_id(struct ata_device *d
                    unsigned int flags, u16 *id)
 {
        struct ata_port *ap = dev->ap;
+       struct ata_host *host = ap->host;
        unsigned int class = *p_class;
        struct ata_taskfile tf;
        unsigned int err_mask = 0;
@@ -1466,8 +1467,29 @@ int ata_dev_read_id(struct ata_device *d
         */
        tf.flags |= ATA_TFLAG_POLLING;
 
+       /* Disable IRQ since some devices like Benq DW1620 raises INTRQ
+        * when IDENTIFY PACKET DEVICE, even with polling IDENTIFY.
+        */
+       if (ap->flags & ATA_FLAG_IDENT_IRQ_OFF) {
+               if (host->irq)
+                       disable_irq(host->irq);
+
+               if (host->irq2)
+                       disable_irq(host->irq2);
+       }
+
        err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
                                     id, sizeof(id[0]) * ATA_ID_WORDS);
+
+       /* Re-enable IRQ */
+       if (ap->flags & ATA_FLAG_IDENT_IRQ_OFF) {
+               if (host->irq)
+                       enable_irq(host->irq);
+
+               if (host->irq2)
+                       enable_irq(host->irq2);
+       }
+
        if (err_mask) {
                if (err_mask & AC_ERR_NODEV_HINT) {
                        DPRINTK("ata%u.%d: NODEV after polling detection\n",
diff -Nrup linux-2.6.21.1-ori/drivers/ata/pata_pdc2027x.c 
linux-2.6.21.1-mod2/drivers/ata/pata_pdc2027x.c
--- linux-2.6.21.1-ori/drivers/ata/pata_pdc2027x.c      2007-04-28 
05:49:26.000000000 +0800
+++ linux-2.6.21.1-mod2/drivers/ata/pata_pdc2027x.c     2007-05-07 
10:44:33.000000000 +0800
@@ -214,7 +214,7 @@ static struct ata_port_info pdc2027x_por
        {
                .sht            = &pdc2027x_sht,
                .flags          = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
-                                 ATA_FLAG_MMIO,
+                                 ATA_FLAG_MMIO | ATA_FLAG_IDENT_IRQ_OFF,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA5, /* udma0-5 */
@@ -224,7 +224,7 @@ static struct ata_port_info pdc2027x_por
        {
                .sht            = &pdc2027x_sht,
                .flags          = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
-                                 ATA_FLAG_MMIO,
+                                 ATA_FLAG_MMIO | ATA_FLAG_IDENT_IRQ_OFF,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = ATA_UDMA6, /* udma0-6 */
diff -Nrup linux-2.6.21.1-ori/include/linux/libata.h 
linux-2.6.21.1-mod2/include/linux/libata.h
--- linux-2.6.21.1-ori/include/linux/libata.h   2007-04-28 05:49:26.000000000 
+0800
+++ linux-2.6.21.1-mod2/include/linux/libata.h  2007-05-07 12:25:05.000000000 
+0800
@@ -174,6 +174,7 @@ enum {
        ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */
        ATA_FLAG_IGN_SIMPLEX    = (1 << 15), /* ignore SIMPLEX */
        ATA_FLAG_NO_IORDY       = (1 << 16), /* controller lacks iordy */
+       ATA_FLAG_IDENT_IRQ_OFF  = (1 << 17), /* disable irq when IDENTIFY */
 
        /* The following flag belongs to ap->pflags but is kept in
         * ap->flags because it's referenced in many LLDs and will be


-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to