ahci: Add Marvell 88se91a2 device id
[pandora-kernel.git] / drivers / ata / ahci.c
index cf26222..e3c276a 100644 (file)
 #define DRV_VERSION    "3.0"
 
 enum {
-       AHCI_PCI_BAR            = 5,
+       AHCI_PCI_BAR_STA2X11    = 0,
+       AHCI_PCI_BAR_ENMOTUS    = 2,
+       AHCI_PCI_BAR_STANDARD   = 5,
 };
 
 enum board_ids {
        /* board IDs by feature in alphabetical order */
        board_ahci,
        board_ahci_ign_iferr,
+       board_ahci_nomsi,
+       board_ahci_noncq,
        board_ahci_nosntf,
        board_ahci_yes_fbs,
 
        /* board IDs for specific chipsets in alphabetical order */
+       board_ahci_avn,
        board_ahci_mcp65,
        board_ahci_mcp77,
        board_ahci_mcp89,
@@ -81,6 +86,8 @@ enum board_ids {
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
                                 unsigned long deadline);
+static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
+                             unsigned long deadline);
 static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
                                unsigned long deadline);
 #ifdef CONFIG_PM
@@ -104,6 +111,11 @@ static struct ata_port_operations ahci_p5wdh_ops = {
 
 #define AHCI_HFLAGS(flags)     .private_data   = (void *)(flags)
 
+static struct ata_port_operations ahci_avn_ops = {
+       .inherits               = &ahci_ops,
+       .hardreset              = ahci_avn_hardreset,
+};
+
 static const struct ata_port_info ahci_port_info[] = {
        /* by features */
        [board_ahci] =
@@ -121,6 +133,20 @@ static const struct ata_port_info ahci_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
+       [board_ahci_nomsi] = {
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_MSI),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
+       [board_ahci_noncq] = {
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
        [board_ahci_nosntf] =
        {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_SNTF),
@@ -138,6 +164,12 @@ static const struct ata_port_info ahci_port_info[] = {
                .port_ops       = &ahci_ops,
        },
        /* by chipsets */
+       [board_ahci_avn] = {
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_avn_ops,
+       },
        [board_ahci_mcp65] =
        {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
@@ -260,10 +292,75 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
        { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
        { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
+       { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
+       { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
+       { PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
+       { PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
+       { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
+       { PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
+       { PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
+       { PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
+       { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
+       { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
+       { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
+       /* JMicron 362B and 362C have an AHCI function with IDE class code */
+       { PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
+       { PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
 
        /* ATI */
        { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
@@ -276,6 +373,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 
        /* AMD */
        { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
+       { PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
        /* AMD is using RAID class only for ahci controllers */
        { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
@@ -375,23 +473,59 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(SI, 0x1185), board_ahci },                /* SiS 968 */
        { PCI_VDEVICE(SI, 0x0186), board_ahci },                /* SiS 968 */
 
+       /* ST Microelectronics */
+       { PCI_VDEVICE(STMICRO, 0xCC06), board_ahci },           /* ST ConneXt */
+
        /* Marvell */
        { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },        /* 6145 */
        { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },        /* 6121 */
-       { PCI_DEVICE(0x1b4b, 0x9123),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
          .class = PCI_CLASS_STORAGE_SATA_AHCI,
          .class_mask = 0xffffff,
          .driver_data = board_ahci_yes_fbs },                  /* 88se9128 */
-       { PCI_DEVICE(0x1b4b, 0x9125),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9125 */
-       { PCI_DEVICE(0x1b4b, 0x91a3),
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
+                        PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9170 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9172 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9182 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9172 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9172 on some Gigabyte */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
+         .driver_data = board_ahci_yes_fbs },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a2),        /* 88se91a2 */
+         .driver_data = board_ahci_yes_fbs },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
+         .driver_data = board_ahci_yes_fbs },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
+         .driver_data = board_ahci_yes_fbs },
+       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
          .driver_data = board_ahci_yes_fbs },
 
        /* Promise */
        { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },   /* PDC42819 */
+       { PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
 
        /* Asmedia */
-       { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1061 */
+       { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },   /* ASM1060 */
+       { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci },   /* ASM1060 */
+       { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },   /* ASM1061 */
+       { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1062 */
+
+       /*
+        * Samsung SSDs found on some macbooks.  NCQ times out if MSI is
+        * enabled.  https://bugzilla.kernel.org/show_bug.cgi?id=60731
+        */
+       { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
+       { PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
+
+       /* Enmotus */
+       { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
 
        /* Generic, PCI class code for AHCI */
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -566,6 +700,78 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
        return rc;
 }
 
+/*
+ * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
+ *
+ * It has been observed with some SSDs that the timing of events in the
+ * link synchronization phase can leave the port in a state that can not
+ * be recovered by a SATA-hard-reset alone.  The failing signature is
+ * SStatus.DET stuck at 1 ("Device presence detected but Phy
+ * communication not established").  It was found that unloading and
+ * reloading the driver when this problem occurs allows the drive
+ * connection to be recovered (DET advanced to 0x3).  The critical
+ * component of reloading the driver is that the port state machines are
+ * reset by bouncing "port enable" in the AHCI PCS configuration
+ * register.  So, reproduce that effect by bouncing a port whenever we
+ * see DET==1 after a reset.
+ */
+static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
+                             unsigned long deadline)
+{
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       struct ata_port *ap = link->ap;
+       struct ahci_port_priv *pp = ap->private_data;
+       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+       unsigned long tmo = deadline - jiffies;
+       struct ata_taskfile tf;
+       bool online;
+       int rc, i;
+
+       DPRINTK("ENTER\n");
+
+       ahci_stop_engine(ap);
+
+       for (i = 0; i < 2; i++) {
+               u16 val;
+               u32 sstatus;
+               int port = ap->port_no;
+               struct ata_host *host = ap->host;
+               struct pci_dev *pdev = to_pci_dev(host->dev);
+
+               /* clear D2H reception area to properly wait for D2H FIS */
+               ata_tf_init(link->device, &tf);
+               tf.command = ATA_BUSY;
+               ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
+               rc = sata_link_hardreset(link, timing, deadline, &online,
+                               ahci_check_ready);
+
+               if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
+                               (sstatus & 0xf) != 1)
+                       break;
+
+               ata_link_printk(link, KERN_INFO, "avn bounce port%d\n",
+                               port);
+
+               pci_read_config_word(pdev, 0x92, &val);
+               val &= ~(1 << port);
+               pci_write_config_word(pdev, 0x92, val);
+               ata_msleep(ap, 1000);
+               val |= 1 << port;
+               pci_write_config_word(pdev, 0x92, val);
+               deadline += tmo;
+       }
+
+       ahci_start_engine(ap);
+
+       if (online)
+               *class = ahci_dev_classify(ap);
+
+       DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+       return rc;
+}
+
+
 #ifdef CONFIG_PM
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
@@ -622,6 +828,13 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
 {
        int rc;
 
+       /*
+        * If the device fixup already set the dma_mask to some non-standard
+        * value, don't extend it here. This happens on STA2X11, for example.
+        */
+       if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
+               return 0;
+
        if (using_dac &&
            !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
                rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -1026,6 +1239,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct ahci_host_priv *hpriv;
        struct ata_host *host;
        int n_ports, i, rc;
+       int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
        VPRINTK("ENTER\n");
 
@@ -1057,6 +1271,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_info(&pdev->dev,
                         "PDC42819 can only drive SATA devices with this driver\n");
 
+       /* Both Connext and Enmotus devices use non-standard BARs */
+       if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
+               ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
+       else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
+               ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
+
        /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
@@ -1065,7 +1285,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* AHCI controllers often implement SFF compatible interface.
         * Grab all PCI BARs just in case.
         */
-       rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+       rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
        if (rc == -EBUSY)
                pcim_pin_device(pdev);
        if (rc)
@@ -1108,7 +1328,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
                pci_intx(pdev, 1);
 
-       hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+       hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
        /* save initial config */
        ahci_pci_save_initial_config(pdev, hpriv);
@@ -1172,8 +1392,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
-               ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
-               ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+               ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
+               ata_port_pbar_desc(ap, ahci_pci_bar,
                                   0x100 + ap->port_no * 0x80, "port");
 
                /* set enclosure management message type */