board_ahci_sb700,       /* for SB700 and SB800 */
        board_ahci_vt8251,
 
+       /*
+        * board IDs for Intel chipsets that support more than 6 ports
+        * *and* end up needing the PCS quirk.
+        */
+       board_ahci_pcs7,
+
        /* aliases */
        board_ahci_mcp_linux    = board_ahci_mcp65,
        board_ahci_mcp67        = board_ahci_mcp65,
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_vt8251_ops,
        },
+       [board_ahci_pcs7] = {
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
 };
 
 static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_mobile }, /* PCH M RAID */
        { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
-       { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b0), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b1), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b2), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b3), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b4), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b5), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b6), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b7), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19bE), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19bF), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c0), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c1), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c2), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c3), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c4), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c5), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c6), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c7), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19cE), board_ahci_pcs7 }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19cF), board_ahci_pcs7 }, /* DNV AHCI */
        { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
        { PCI_VDEVICE(INTEL, 0x1c03), board_ahci_mobile }, /* CPT M AHCI */
        { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
        ahci_save_initial_config(&pdev->dev, hpriv);
 }
 
-static int ahci_pci_reset_controller(struct ata_host *host)
-{
-       struct pci_dev *pdev = to_pci_dev(host->dev);
-       int rc;
-
-       rc = ahci_reset_controller(host);
-       if (rc)
-               return rc;
-
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
-               struct ahci_host_priv *hpriv = host->private_data;
-               u16 tmp16;
-
-               /* configure PCS */
-               pci_read_config_word(pdev, 0x92, &tmp16);
-               if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
-                       tmp16 |= hpriv->port_map;
-                       pci_write_config_word(pdev, 0x92, tmp16);
-               }
-       }
-
-       return 0;
-}
-
 static void ahci_pci_init_controller(struct ata_host *host)
 {
        struct ahci_host_priv *hpriv = host->private_data;
        struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
-       rc = ahci_pci_reset_controller(host);
+       rc = ahci_reset_controller(host);
        if (rc)
                return rc;
        ahci_pci_init_controller(host);
                ahci_mcp89_apple_enable(pdev);
 
        if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-               rc = ahci_pci_reset_controller(host);
+               rc = ahci_reset_controller(host);
                if (rc)
                        return rc;
 
                ap->target_lpm_policy = policy;
 }
 
+static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+       const struct pci_device_id *id = pci_match_id(ahci_pci_tbl, pdev);
+       u16 tmp16;
+
+       /*
+        * Only apply the 6-port PCS quirk for known legacy platforms.
+        */
+       if (!id || id->vendor != PCI_VENDOR_ID_INTEL)
+               return;
+       if (((enum board_ids) id->driver_data) < board_ahci_pcs7)
+               return;
+
+       /*
+        * port_map is determined from PORTS_IMPL PCI register which is
+        * implemented as write or write-once register.  If the register
+        * isn't programmed, ahci automatically generates it from number
+        * of ports, which is good enough for PCS programming. It is
+        * otherwise expected that platform firmware enables the ports
+        * before the OS boots.
+        */
+       pci_read_config_word(pdev, PCS_6, &tmp16);
+       if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
+               tmp16 |= hpriv->port_map;
+               pci_write_config_word(pdev, PCS_6, tmp16);
+       }
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned int board_id = ent->driver_data;
        /* save initial config */
        ahci_pci_save_initial_config(pdev, hpriv);
 
+       /*
+        * If platform firmware failed to enable ports, try to enable
+        * them here.
+        */
+       ahci_intel_pcs_quirk(pdev, hpriv);
+
        /* prepare host */
        if (hpriv->cap & HOST_CAP_NCQ) {
                pi.flags |= ATA_FLAG_NCQ;
        if (rc)
                return rc;
 
-       rc = ahci_pci_reset_controller(host);
+       rc = ahci_reset_controller(host);
        if (rc)
                return rc;