Merge branch 'linus' into x86/i8259
[sfrench/cifs-2.6.git] / drivers / ata / libata-pmp.c
index ff1822a7da38941b4c4cc2051f2bdd4ec80e37a2..7daf4c0f62167af1735c7f5885903774312cb8ba 100644 (file)
@@ -48,7 +48,7 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
        tf.device = link->pmp;
 
        err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
-                                    SATA_PMP_SCR_TIMEOUT);
+                                    SATA_PMP_RW_TIMEOUT);
        if (err_mask)
                return err_mask;
 
@@ -88,7 +88,7 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
        tf.lbah = (val >> 24) & 0xff;
 
        return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
-                                SATA_PMP_SCR_TIMEOUT);
+                                SATA_PMP_RW_TIMEOUT);
 }
 
 /**
@@ -257,19 +257,6 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
                goto fail;
        }
 
-       /* turn off notification till fan-out ports are reset and configured */
-       if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
-               gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
-
-               err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
-                                         gscr[SATA_PMP_GSCR_FEAT_EN]);
-               if (err_mask) {
-                       rc = -EIO;
-                       reason = "failed to write GSCR_FEAT_EN";
-                       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",
@@ -335,9 +322,12 @@ static void sata_pmp_quirks(struct ata_port *ap)
        if (vendor == 0x1095 && devid == 0x3726) {
                /* sil3726 quirks */
                ata_port_for_each_link(link, ap) {
-                       /* class code report is unreliable */
+                       /* Class code report is unreliable and SRST
+                        * times out under certain configurations.
+                        */
                        if (link->pmp < 5)
-                               link->flags |= ATA_LFLAG_ASSUME_ATA;
+                               link->flags |= ATA_LFLAG_NO_SRST |
+                                              ATA_LFLAG_ASSUME_ATA;
 
                        /* port 5 is for SEMB device and it doesn't like SRST */
                        if (link->pmp == 5)
@@ -700,8 +690,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
        if (ehc->i.action & ATA_EH_RESET) {
                struct ata_link *tlink;
 
-               ata_eh_freeze_port(ap);
-
                /* reset */
                rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
                                  postreset);
@@ -711,8 +699,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
                        goto fail;
                }
 
-               ata_eh_thaw_port(ap);
-
                /* PMP is reset, SErrors cannot be trusted, scan all */
                ata_port_for_each_link(tlink, ap) {
                        struct ata_eh_context *ehc = &tlink->eh_context;
@@ -864,6 +850,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        struct ata_link *pmp_link = &ap->link;
        struct ata_device *pmp_dev = pmp_link->device;
        struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+       u32 *gscr = pmp_dev->gscr;
        struct ata_link *link;
        struct ata_device *dev;
        unsigned int err_mask;
@@ -901,6 +888,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        if (rc)
                goto pmp_fail;
 
+       /* PHY event notification can disturb reset and other recovery
+        * operations.  Turn it off.
+        */
+       if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+               gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+               err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+                                         gscr[SATA_PMP_GSCR_FEAT_EN]);
+               if (err_mask) {
+                       ata_link_printk(pmp_link, KERN_WARNING,
+                               "failed to disable NOTIFY (err_mask=0x%x)\n",
+                               err_mask);
+                       goto pmp_fail;
+               }
+       }
+
        /* handle disabled links */
        rc = sata_pmp_eh_handle_disabled_links(ap);
        if (rc)
@@ -923,10 +926,10 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
 
        /* enable notification */
        if (pmp_dev->flags & ATA_DFLAG_AN) {
-               pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+               gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
 
-               err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
-                                         pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+               err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+                                         gscr[SATA_PMP_GSCR_FEAT_EN]);
                if (err_mask) {
                        ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
                                       "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);