aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/libata-eh.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 8f8ed4dfb17..fbbf7916390 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1308,6 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
struct ata_eh_context *ehc = &link->eh_context;
u32 serror = ehc->i.serror;
unsigned int err_mask = 0, action = 0;
+ u32 hotplug_mask;
if (serror & SERR_PERSISTENT) {
err_mask |= AC_ERR_ATA_BUS;
@@ -1326,7 +1327,20 @@ static void ata_eh_analyze_serror(struct ata_link *link)
err_mask |= AC_ERR_SYSTEM;
action |= ATA_EH_HARDRESET;
}
- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+ /* Determine whether a hotplug event has occurred. Both
+ * SError.N/X are considered hotplug events for enabled or
+ * host links. For disabled PMP links, only N bit is
+ * considered as X bit is left at 1 for link plugging.
+ */
+ hotplug_mask = 0;
+
+ if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+ hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+ else
+ hotplug_mask = SERR_PHYRDY_CHG;
+
+ if (serror & hotplug_mask)
ata_ehi_hotplugged(&ehc->i);
ehc->i.err_mask |= err_mask;
@@ -2227,6 +2241,10 @@ static int ata_eh_skip_recovery(struct ata_link *link)
struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev;
+ /* skip disabled links */
+ if (link->flags & ATA_LFLAG_DISABLED)
+ return 1;
+
/* thaw frozen port, resume link and recover failed devices */
if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
(ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
@@ -2327,6 +2345,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_device *dev;
int nr_failed_devs, nr_disabled_devs;
int reset, rc;
+ unsigned long flags;
DPRINTK("ENTER\n");
@@ -2334,6 +2353,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_port_for_each_link(link, ap) {
struct ata_eh_context *ehc = &link->eh_context;
+ /* re-enable link? */
+ if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+ ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags &= ~ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+ }
+
ata_link_for_each_dev(dev, link) {
if (link->flags & ATA_LFLAG_NO_RETRY)
ehc->tries[dev->devno] = 1;