]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ata/libata-eh.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux-2.6-omap-h63xx.git] / drivers / ata / libata-eh.c
index c0e9a42e6ae700a1cbc27684a87d7ac80f19734e..2eaa39fc65d031d5f44519e3ec43e9a80d3cb34b 100644 (file)
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -2063,6 +2064,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
                 ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
                 ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
+       struct ata_port *ap = link->ap;
        struct ata_eh_context *ehc = &link->eh_context;
        unsigned int *classes = ehc->classes;
        int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
@@ -2071,9 +2073,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
        unsigned long deadline;
        unsigned int action;
        ata_reset_fn_t reset;
+       unsigned long flags;
        int rc;
 
        /* about to reset */
+       spin_lock_irqsave(ap->lock, flags);
+       ap->pflags |= ATA_PFLAG_RESETTING;
+       spin_unlock_irqrestore(ap->lock, flags);
+
        ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
 
        /* Determine which reset to use and record in ehc->i.action.
@@ -2231,6 +2238,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
  out:
        /* clear hotplug flag */
        ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+
+       spin_lock_irqsave(ap->lock, flags);
+       ap->pflags &= ~ATA_PFLAG_RESETTING;
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return rc;
 }
 
@@ -2546,7 +2558,11 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 
        /* reset */
        if (reset) {
-               ata_eh_freeze_port(ap);
+               /* if PMP is attached, this function only deals with
+                * downstream links, port should stay thawed.
+                */
+               if (!ap->nr_pmp_links)
+                       ata_eh_freeze_port(ap);
 
                ata_port_for_each_link(link, ap) {
                        struct ata_eh_context *ehc = &link->eh_context;
@@ -2564,7 +2580,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                        }
                }
 
-               ata_eh_thaw_port(ap);
+               if (!ap->nr_pmp_links)
+                       ata_eh_thaw_port(ap);
        }
 
        /* the rest */
@@ -2599,8 +2616,14 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                if (ata_eh_handle_dev_fail(dev, rc))
                        nr_disabled_devs++;
 
-               if (ap->pflags & ATA_PFLAG_FROZEN)
+               if (ap->pflags & ATA_PFLAG_FROZEN) {
+                       /* PMP reset requires working host port.
+                        * Can't retry if it's frozen.
+                        */
+                       if (ap->nr_pmp_links)
+                               goto out;
                        break;
+               }
        }
 
        if (nr_failed_devs) {