can: make the number of echo skb's configurable
[safe/jmp/linux-2.6] / drivers / ata / sata_sil.c
index 564c142..3cb69d5 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/device.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
+#include <linux/dmi.h>
 
 #define DRV_NAME       "sata_sil"
 #define DRV_VERSION    "2.4"
@@ -182,7 +183,7 @@ static struct scsi_host_template sil_sht = {
 };
 
 static struct ata_port_operations sil_ops = {
-       .inherits               = &ata_bmdma_port_ops,
+       .inherits               = &ata_bmdma32_port_ops,
        .dev_config             = sil_dev_config,
        .set_mode               = sil_set_mode,
        .bmdma_setup            = sil_bmdma_setup,
@@ -199,8 +200,8 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3112 */
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
-               .pio_mask       = 0x1f,                 /* pio0-4 */
-               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
                .port_ops       = &sil_ops,
        },
@@ -208,24 +209,24 @@ static const struct ata_port_info sil_port_info[] = {
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
                                  SIL_FLAG_NO_SATA_IRQ,
-               .pio_mask       = 0x1f,                 /* pio0-4 */
-               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
                .port_ops       = &sil_ops,
        },
        /* sil_3512 */
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
-               .pio_mask       = 0x1f,                 /* pio0-4 */
-               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
                .port_ops       = &sil_ops,
        },
        /* sil_3114 */
        {
                .flags          = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
-               .pio_mask       = 0x1f,                 /* pio0-4 */
-               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA5,
                .port_ops       = &sil_ops,
        },
@@ -323,7 +324,7 @@ static void sil_fill_sg(struct ata_queued_cmd *qc)
 
                prd->addr = cpu_to_le32(addr);
                prd->flags_len = cpu_to_le32(sg_len);
-               VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, sg_len);
+               VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", si, addr, sg_len);
 
                last_prd = prd;
                prd++;
@@ -531,7 +532,7 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
                struct ata_port *ap = host->ports[i];
                u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
 
-               if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+               if (unlikely(ap->flags & ATA_FLAG_DISABLED))
                        continue;
 
                /* turn off SATA_IRQ if not supported */
@@ -564,6 +565,19 @@ static void sil_freeze(struct ata_port *ap)
        tmp |= SIL_MASK_IDE0_INT << ap->port_no;
        writel(tmp, mmio_base + SIL_SYSCFG);
        readl(mmio_base + SIL_SYSCFG);  /* flush */
+
+       /* Ensure DMA_ENABLE is off.
+        *
+        * This is because the controller will not give us access to the
+        * taskfile registers while a DMA is in progress
+        */
+       iowrite8(ioread8(ap->ioaddr.bmdma_addr) & ~SIL_DMA_ENABLE,
+                ap->ioaddr.bmdma_addr);
+
+       /* According to ata_bmdma_stop, an HDMA transition requires
+        * on PIO cycle. But we can't read a taskfile register.
+        */
+       ioread8(ap->ioaddr.bmdma_addr);
 }
 
 static void sil_thaw(struct ata_port *ap)
@@ -695,11 +709,38 @@ static void sil_init_controller(struct ata_host *host)
        }
 }
 
+static bool sil_broken_system_poweroff(struct pci_dev *pdev)
+{
+       static const struct dmi_system_id broken_systems[] = {
+               {
+                       .ident = "HP Compaq nx6325",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
+                       },
+                       /* PCI slot number of the controller */
+                       .driver_data = (void *)0x12UL,
+               },
+
+               { }     /* terminate list */
+       };
+       const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
+
+       if (dmi) {
+               unsigned long slot = (unsigned long)dmi->driver_data;
+               /* apply the quirk only to on-board controllers */
+               return slot == PCI_SLOT(pdev->devfn);
+       }
+
+       return false;
+}
+
 static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
        int board_id = ent->driver_data;
-       const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };
+       struct ata_port_info pi = sil_port_info[board_id];
+       const struct ata_port_info *ppi[] = { &pi, NULL };
        struct ata_host *host;
        void __iomem *mmio_base;
        int n_ports, rc;
@@ -713,6 +754,13 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (board_id == sil_3114)
                n_ports = 4;
 
+       if (sil_broken_system_poweroff(pdev)) {
+               pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN |
+                                       ATA_FLAG_NO_HIBERNATE_SPINDOWN;
+               dev_info(&pdev->dev, "quirky BIOS, skipping spindown "
+                               "on poweroff and hibernation\n");
+       }
+
        host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
        if (!host)
                return -ENOMEM;