Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
[safe/jmp/linux-2.6] / drivers / ata / ata_piix.c
index 7865954..1aeb708 100644 (file)
@@ -72,6 +72,7 @@
  *     ICH2    spec c #20      - IDE PRD must not cross a 64K boundary
  *                               and must be dword aligned
  *     ICH2    spec c #24      - UDMA mode 4,5 t85/86 should be 6ns not 3.3
+ *     ICH7    errata #16      - MWDMA1 timings are incorrect
  *
  * Should have been BIOS fixed:
  *     450NX:  errata #19      - DMA hangs on old 450NX
@@ -94,7 +95,7 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME       "ata_piix"
-#define DRV_VERSION    "2.12"
+#define DRV_VERSION    "2.13"
 
 enum {
        PIIX_IOCFG              = 0x54, /* IDE I/O configuration register */
@@ -136,6 +137,7 @@ enum piix_controller_ids {
        ich_pata_33,            /* ICH up to UDMA 33 only */
        ich_pata_66,            /* ICH up to 66 Mhz */
        ich_pata_100,           /* ICH up to UDMA 100 */
+       ich_pata_100_nomwdma1,  /* ICH up to UDMA 100 but with no MWDMA1*/
        ich5_sata,
        ich6_sata,
        ich6m_sata,
@@ -216,8 +218,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
        /* ICH6 (and 6) (i915) UDMA 100 */
        { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* ICH7/7-R (i945, i975) UDMA 100*/
-       { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-       { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+       { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
+       { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
        /* ICH8 Mobile PATA Controller */
        { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 
@@ -310,7 +312,7 @@ static struct scsi_host_template piix_sht = {
 };
 
 static struct ata_port_operations piix_pata_ops = {
-       .inherits               = &ata_bmdma_port_ops,
+       .inherits               = &ata_bmdma32_port_ops,
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = piix_set_piomode,
        .set_dmamode            = piix_set_dmamode,
@@ -446,34 +448,34 @@ static struct ata_port_info piix_port_info[] = {
        [piix_pata_mwdma] =     /* PIIX3 MWDMA only */
        {
                .flags          = PIIX_PATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
                .port_ops       = &piix_pata_ops,
        },
 
        [piix_pata_33] =        /* PIIX4 at 33MHz */
        {
                .flags          = PIIX_PATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
-               .udma_mask      = ATA_UDMA_MASK_40C,
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+               .udma_mask      = ATA_UDMA2,
                .port_ops       = &piix_pata_ops,
        },
 
        [ich_pata_33] =         /* ICH0 - ICH at 33Mhz*/
        {
                .flags          = PIIX_PATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio 0-4 */
-               .mwdma_mask     = 0x06, /* Check: maybe 0x07  */
-               .udma_mask      = ATA_UDMA2, /* UDMA33 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA12_ONLY, /* Check: maybe MWDMA0 is ok  */
+               .udma_mask      = ATA_UDMA2,
                .port_ops       = &ich_pata_ops,
        },
 
        [ich_pata_66] =         /* ICH controllers up to 66MHz */
        {
                .flags          = PIIX_PATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio 0-4 */
-               .mwdma_mask     = 0x06, /* MWDMA0 is broken on chip */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA12_ONLY, /* MWDMA0 is broken on chip */
                .udma_mask      = ATA_UDMA4,
                .port_ops       = &ich_pata_ops,
        },
@@ -481,17 +483,26 @@ static struct ata_port_info piix_port_info[] = {
        [ich_pata_100] =
        {
                .flags          = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x06, /* mwdma1-2 */
-               .udma_mask      = ATA_UDMA5, /* udma0-5 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA12_ONLY,
+               .udma_mask      = ATA_UDMA5,
+               .port_ops       = &ich_pata_ops,
+       },
+
+       [ich_pata_100_nomwdma1] =
+       {
+               .flags          = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2_ONLY,
+               .udma_mask      = ATA_UDMA5,
                .port_ops       = &ich_pata_ops,
        },
 
        [ich5_sata] =
        {
                .flags          = PIIX_SATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -499,8 +510,8 @@ static struct ata_port_info piix_port_info[] = {
        [ich6_sata] =
        {
                .flags          = PIIX_SATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -508,8 +519,8 @@ static struct ata_port_info piix_port_info[] = {
        [ich6m_sata] =
        {
                .flags          = PIIX_SATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -517,8 +528,8 @@ static struct ata_port_info piix_port_info[] = {
        [ich8_sata] =
        {
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -526,8 +537,8 @@ static struct ata_port_info piix_port_info[] = {
        [ich8_2port_sata] =
        {
                .flags          = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -535,8 +546,8 @@ static struct ata_port_info piix_port_info[] = {
        [tolapai_sata] =
        {
                .flags          = PIIX_SATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -544,8 +555,8 @@ static struct ata_port_info piix_port_info[] = {
        [ich8m_apple_sata] =
        {
                .flags          = PIIX_SATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &piix_sata_ops,
        },
@@ -553,9 +564,9 @@ static struct ata_port_info piix_port_info[] = {
        [piix_pata_vmw] =
        {
                .flags          = PIIX_PATA_FLAGS,
-               .pio_mask       = 0x1f, /* pio0-4 */
-               .mwdma_mask     = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
-               .udma_mask      = ATA_UDMA_MASK_40C,
+               .pio_mask       = ATA_PIO4,
+               .mwdma_mask     = ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+               .udma_mask      = ATA_UDMA2,
                .port_ops       = &piix_vmw_ops,
        },
 
@@ -594,6 +605,7 @@ static const struct ich_laptop ich_laptop[] = {
        { 0x24CA, 0x1025, 0x003d },     /* ICH4 on ACER TM290 */
        { 0x266F, 0x1025, 0x0066 },     /* ICH6 on ACER Aspire 1694WLMi */
        { 0x2653, 0x1043, 0x82D8 },     /* ICH6M on Asus Eee 701 */
+       { 0x27df, 0x104d, 0x900e },     /* ICH7 on Sony TZ-90 */
        /* end marker */
        { 0, }
 };
@@ -1053,6 +1065,13 @@ static int piix_broken_suspend(void)
                                DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),
                        },
                },
+               {
+                       .ident = "VGN-BX297XP",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-BX297XP"),
+                       },
+               },
 
                { }     /* terminate list */
        };
@@ -1289,6 +1308,39 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
        return map;
 }
 
+static bool piix_no_sidpr(struct ata_host *host)
+{
+       struct pci_dev *pdev = to_pci_dev(host->dev);
+
+       /*
+        * Samsung DB-P70 only has three ATA ports exposed and
+        * curiously the unconnected first port reports link online
+        * while not responding to SRST protocol causing excessive
+        * detection delay.
+        *
+        * Unfortunately, the system doesn't carry enough DMI
+        * information to identify the machine but does have subsystem
+        * vendor and device set.  As it's unclear whether the
+        * subsystem vendor/device is used only for this specific
+        * board, the port can't be disabled solely with the
+        * information; however, turning off SIDPR access works around
+        * the problem.  Turn it off.
+        *
+        * This problem is reported in bnc#441240.
+        *
+        * https://bugzilla.novell.com/show_bug.cgi?id=441420
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2920 &&
+           pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG &&
+           pdev->subsystem_device == 0xb049) {
+               dev_printk(KERN_WARNING, host->dev,
+                          "Samsung DB-P70 detected, disabling SIDPR\n");
+               return true;
+       }
+
+       return false;
+}
+
 static int __devinit piix_init_sidpr(struct ata_host *host)
 {
        struct pci_dev *pdev = to_pci_dev(host->dev);
@@ -1302,6 +1354,10 @@ static int __devinit piix_init_sidpr(struct ata_host *host)
                if (hpriv->map[i] == IDE)
                        return 0;
 
+       /* is it blacklisted? */
+       if (piix_no_sidpr(host))
+               return 0;
+
        if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
                return 0;
 
@@ -1387,6 +1443,41 @@ static void piix_iocfg_bit18_quirk(struct ata_host *host)
        }
 }
 
+static bool piix_broken_system_poweroff(struct pci_dev *pdev)
+{
+       static const struct dmi_system_id broken_systems[] = {
+               {
+                       .ident = "HP Compaq 2510p",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 2510p"),
+                       },
+                       /* PCI slot number of the controller */
+                       .driver_data = (void *)0x1FUL,
+               },
+               {
+                       .ident = "HP Compaq nc6000",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nc6000"),
+                       },
+                       /* PCI slot number of the controller */
+                       .driver_data = (void *)0x1FUL,
+               },
+
+               { }     /* 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;
+}
+
 /**
  *     piix_init_one - Register PIIX ATA PCI device with kernel services
  *     @pdev: PCI device to register
@@ -1422,6 +1513,14 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        if (!in_module_init)
                return -ENODEV;
 
+       if (piix_broken_system_poweroff(pdev)) {
+               piix_port_info[ent->driver_data].flags |=
+                               ATA_FLAG_NO_POWEROFF_SPINDOWN |
+                                       ATA_FLAG_NO_HIBERNATE_SPINDOWN;
+               dev_info(&pdev->dev, "quirky BIOS, skipping spindown "
+                               "on poweroff and hibernation\n");
+       }
+
        port_info[0] = piix_port_info[ent->driver_data];
        port_info[1] = piix_port_info[ent->driver_data];