[PATCH] sata_sil: disable hotplug interrupts on two ATI IXPs
authorTejun Heo <htejun@gmail.com>
Mon, 26 Jun 2006 12:23:52 +0000 (21:23 +0900)
committerJeff Garzik <jeff@garzik.org>
Tue, 27 Jun 2006 01:02:36 +0000 (21:02 -0400)
Some SATA controllers embedded in ATI IXPs seem to have broken
SATA_IRQ bit in their bmdma2 registers which is always stuck at 1.
This makes the driver believe that there has been a hotplug event and
freeze the port whenever there's an interrupt thus failing all
commands.

This patch disables SATA_IRQ for those controllers.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/scsi/sata_sil.c

index 662ad10de288e64cb7d0bff81aa13bac01cf7a8c..51d86d750e84f6892b05c98beaa9ac7f82e09fcb 100644 (file)
@@ -52,6 +52,7 @@ enum {
        /*
         * host flags
         */
+       SIL_FLAG_NO_SATA_IRQ    = (1 << 28),
        SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
        SIL_FLAG_MOD15WRITE     = (1 << 30),
 
@@ -62,8 +63,9 @@ enum {
         * Controller IDs
         */
        sil_3112                = 0,
-       sil_3512                = 1,
-       sil_3114                = 2,
+       sil_3112_no_sata_irq    = 1,
+       sil_3512                = 2,
+       sil_3114                = 3,
 
        /*
         * Register offsets
@@ -123,8 +125,8 @@ static const struct pci_device_id sil_pci_tbl[] = {
        { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
        { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
        { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
        { }     /* terminate list */
 };
 
@@ -217,6 +219,16 @@ static const struct ata_port_info sil_port_info[] = {
                .udma_mask      = 0x3f,                 /* udma0-5 */
                .port_ops       = &sil_ops,
        },
+       /* sil_3112_no_sata_irq */
+       {
+               .sht            = &sil_sht,
+               .host_flags     = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE |
+                                 SIL_FLAG_NO_SATA_IRQ,
+               .pio_mask       = 0x1f,                 /* pio0-4 */
+               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .udma_mask      = 0x3f,                 /* udma0-5 */
+               .port_ops       = &sil_ops,
+       },
        /* sil_3512 */
        {
                .sht            = &sil_sht,
@@ -437,6 +449,10 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance,
                if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
                        continue;
 
+               /* turn off SATA_IRQ if not supported */
+               if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+                       bmdma2 &= ~SIL_DMA_SATA_IRQ;
+
                if (bmdma2 == 0xffffffff ||
                    !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
                        continue;
@@ -474,8 +490,9 @@ static void sil_thaw(struct ata_port *ap)
        ata_chk_status(ap);
        ata_bmdma_irq_clear(ap);
 
-       /* turn on SATA IRQ */
-       writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+       /* turn on SATA IRQ if supported */
+       if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+               writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
 
        /* turn on IRQ */
        tmp = readl(mmio_base + SIL_SYSCFG);