ahci: add "em_buffer" attribute for AHCI hosts
[safe/jmp/linux-2.6] / drivers / ata / libata-pmp.c
index b65db30..224faab 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/libata.h>
+#include <linux/slab.h>
 #include "libata.h"
 
 const struct ata_port_operations sata_pmp_port_ops = {
@@ -221,6 +222,8 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr)
 {
        u32 rev = gscr[SATA_PMP_GSCR_REV];
 
+       if (rev & (1 << 3))
+               return "1.2";
        if (rev & (1 << 2))
                return "1.1";
        if (rev & (1 << 1))
@@ -228,10 +231,14 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr)
        return "<unknown>";
 }
 
+#define PMP_GSCR_SII_POL 129
+
 static int sata_pmp_configure(struct ata_device *dev, int print_info)
 {
        struct ata_port *ap = dev->link->ap;
        u32 *gscr = dev->gscr;
+       u16 vendor = sata_pmp_gscr_vendor(gscr);
+       u16 devid = sata_pmp_gscr_devid(gscr);
        unsigned int err_mask = 0;
        const char *reason;
        int nr_ports, rc;
@@ -257,12 +264,34 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
                goto fail;
        }
 
+       /* Disable sending Early R_OK.
+        * With "cached read" HDD testing and multiple ports busy on a SATA
+        * host controller, 3726 PMP will very rarely drop a deferred
+        * R_OK that was intended for the host. Symptom will be all
+        * 5 drives under test will timeout, get reset, and recover.
+        */
+       if (vendor == 0x1095 && devid == 0x3726) {
+               u32 reg;
+
+               err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, &reg);
+               if (err_mask) {
+                       rc = -EIO;
+                       reason = "failed to read Sil3726 Private Register";
+                       goto fail;
+               }
+               reg &= ~0x1;
+               err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
+               if (err_mask) {
+                       rc = -EIO;
+                       reason = "failed to write Sil3726 Private Register";
+                       goto fail;
+               }
+       }
+
        if (print_info) {
                ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
                               "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
-                              sata_pmp_spec_rev_str(gscr),
-                              sata_pmp_gscr_vendor(gscr),
-                              sata_pmp_gscr_devid(gscr),
+                              sata_pmp_spec_rev_str(gscr), vendor, devid,
                               sata_pmp_gscr_rev(gscr),
                               nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
                               gscr[SATA_PMP_GSCR_FEAT]);
@@ -321,7 +350,7 @@ static void sata_pmp_quirks(struct ata_port *ap)
 
        if (vendor == 0x1095 && devid == 0x3726) {
                /* sil3726 quirks */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        /* Class code report is unreliable and SRST
                         * times out under certain configurations.
                         */
@@ -336,7 +365,7 @@ static void sata_pmp_quirks(struct ata_port *ap)
                }
        } else if (vendor == 0x1095 && devid == 0x4723) {
                /* sil4723 quirks */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        /* class code report is unreliable */
                        if (link->pmp < 2)
                                link->flags |= ATA_LFLAG_ASSUME_ATA;
@@ -348,7 +377,7 @@ static void sata_pmp_quirks(struct ata_port *ap)
                }
        } else if (vendor == 0x1095 && devid == 0x4726) {
                /* sil4726 quirks */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        /* Class code report is unreliable and SRST
                         * times out under certain configurations.
                         * Config device can be at port 0 or 5 and
@@ -450,7 +479,7 @@ int sata_pmp_attach(struct ata_device *dev)
        if (ap->ops->pmp_attach)
                ap->ops->pmp_attach(ap);
 
-       ata_port_for_each_link(tlink, ap)
+       ata_for_each_link(tlink, ap, EDGE)
                sata_link_init_spd(tlink);
 
        ata_acpi_associate_sata_port(ap);
@@ -487,7 +516,7 @@ static void sata_pmp_detach(struct ata_device *dev)
        if (ap->ops->pmp_detach)
                ap->ops->pmp_detach(ap);
 
-       ata_port_for_each_link(tlink, ap)
+       ata_for_each_link(tlink, ap, EDGE)
                ata_eh_detach_dev(tlink->device);
 
        spin_lock_irqsave(ap->lock, flags);
@@ -700,7 +729,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
                }
 
                /* PMP is reset, SErrors cannot be trusted, scan all */
-               ata_port_for_each_link(tlink, ap) {
+               ata_for_each_link(tlink, ap, EDGE) {
                        struct ata_eh_context *ehc = &tlink->eh_context;
 
                        ehc->i.probe_mask |= ATA_ALL_DEVICES;
@@ -729,7 +758,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
                if (tries) {
                        /* consecutive revalidation failures? speed down */
                        if (reval_failed)
-                               sata_down_spd_limit(link);
+                               sata_down_spd_limit(link, 0);
                        else
                                reval_failed = 1;
 
@@ -768,7 +797,7 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
 
        spin_lock_irqsave(ap->lock, flags);
 
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                if (!(link->flags & ATA_LFLAG_DISABLED))
                        continue;
 
@@ -852,7 +881,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        int cnt, rc;
 
        pmp_tries = ATA_EH_PMP_TRIES;
-       ata_port_for_each_link(link, ap)
+       ata_for_each_link(link, ap, EDGE)
                link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
 
  retry:
@@ -861,7 +890,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
                rc = ata_eh_recover(ap, ops->prereset, ops->softreset,
                                    ops->hardreset, ops->postreset, NULL);
                if (rc) {
-                       ata_link_for_each_dev(dev, &ap->link)
+                       ata_for_each_dev(dev, &ap->link, ALL)
                                ata_dev_disable(dev);
                        return rc;
                }
@@ -870,7 +899,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
                        return 0;
 
                /* new PMP online */
-               ata_port_for_each_link(link, ap)
+               ata_for_each_link(link, ap, EDGE)
                        link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
 
                /* fall through */
@@ -942,7 +971,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        }
 
        cnt = 0;
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                if (!(gscr_error & (1 << link->pmp)))
                        continue;