libata: remove WARN() for DMA or PIO command without data
[pandora-kernel.git] / drivers / ata / libahci.c
index 3c92dbd..fbfde71 100644 (file)
@@ -452,6 +452,7 @@ void ahci_save_initial_config(struct device *dev,
                dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
                         port_map, force_port_map);
                port_map = force_port_map;
+               hpriv->saved_port_map = port_map;
        }
 
        if (mask_port_map) {
@@ -480,8 +481,8 @@ void ahci_save_initial_config(struct device *dev,
                }
        }
 
-       /* fabricate port_map from cap.nr_ports */
-       if (!port_map) {
+       /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
+       if (!port_map && vers < 0x10300) {
                port_map = (1 << ahci_nr_ports(cap)) - 1;
                dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
 
@@ -1137,7 +1138,7 @@ static void ahci_dev_config(struct ata_device *dev)
        }
 }
 
-static unsigned int ahci_dev_classify(struct ata_port *ap)
+unsigned int ahci_dev_classify(struct ata_port *ap)
 {
        void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_taskfile tf;
@@ -1151,6 +1152,7 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
 
        return ata_dev_classify(&tf);
 }
+EXPORT_SYMBOL_GPL(ahci_dev_classify);
 
 void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
                        u32 opts)
@@ -1225,6 +1227,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
        ata_tf_to_fis(tf, pmp, is_cmd, fis);
        ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
 
+       /* set port value for softreset of Port Multiplier */
+       if (pp->fbs_enabled && pp->fbs_last_dev != pmp) {
+               tmp = readl(port_mmio + PORT_FBS);
+               tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+               tmp |= pmp << PORT_FBS_DEV_OFFSET;
+               writel(tmp, port_mmio + PORT_FBS);
+               pp->fbs_last_dev = pmp;
+       }
+
        /* issue & wait */
        writel(1, port_mmio + PORT_CMD_ISSUE);
 
@@ -1247,9 +1258,11 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
 {
        struct ata_port *ap = link->ap;
        struct ahci_host_priv *hpriv = ap->host->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
        const char *reason = NULL;
        unsigned long now, msecs;
        struct ata_taskfile tf;
+       bool fbs_disabled = false;
        int rc;
 
        DPRINTK("ENTER\n");
@@ -1259,6 +1272,16 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
        if (rc && rc != -EOPNOTSUPP)
                ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc);
 
+       /*
+        * According to AHCI-1.2 9.3.9: if FBS is enable, software shall
+        * clear PxFBS.EN to '0' prior to issuing software reset to devices
+        * that is attached to port multiplier.
+        */
+       if (!ata_is_host_link(link) && pp->fbs_enabled) {
+               ahci_disable_fbs(ap);
+               fbs_disabled = true;
+       }
+
        ata_tf_init(link->device, &tf);
 
        /* issue the first D2H Register FIS */
@@ -1299,6 +1322,10 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
        } else
                *class = ahci_dev_classify(ap);
 
+       /* re-enable FBS if disabled before */
+       if (fbs_disabled)
+               ahci_enable_fbs(ap);
+
        DPRINTK("EXIT, class=%u\n", *class);
        return 0;
 
@@ -1541,8 +1568,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
                u32 fbs = readl(port_mmio + PORT_FBS);
                int pmp = fbs >> PORT_FBS_DWE_OFFSET;
 
-               if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) &&
-                   ata_link_online(&ap->pmp_link[pmp])) {
+               if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {
                        link = &ap->pmp_link[pmp];
                        fbs_need_dec = true;
                }
@@ -1653,8 +1679,7 @@ static void ahci_port_intr(struct ata_port *ap)
        if (unlikely(resetting))
                status &= ~PORT_IRQ_BAD_PMP;
 
-       /* if LPM is enabled, PHYRDY doesn't mean anything */
-       if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
+       if (sata_lpm_ignore_phy_events(&ap->link)) {
                status &= ~PORT_IRQ_PHYRDY;
                ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
        }