diff options
-rw-r--r-- | drivers/ata/libata-eh.c | 30 | ||||
-rw-r--r-- | include/linux/libata.h | 3 |
2 files changed, 32 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8f8ed4dfb171..fbbf79163900 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) | |||
1308 | struct ata_eh_context *ehc = &link->eh_context; | 1308 | struct ata_eh_context *ehc = &link->eh_context; |
1309 | u32 serror = ehc->i.serror; | 1309 | u32 serror = ehc->i.serror; |
1310 | unsigned int err_mask = 0, action = 0; | 1310 | unsigned int err_mask = 0, action = 0; |
1311 | u32 hotplug_mask; | ||
1311 | 1312 | ||
1312 | if (serror & SERR_PERSISTENT) { | 1313 | if (serror & SERR_PERSISTENT) { |
1313 | err_mask |= AC_ERR_ATA_BUS; | 1314 | err_mask |= AC_ERR_ATA_BUS; |
@@ -1326,7 +1327,20 @@ static void ata_eh_analyze_serror(struct ata_link *link) | |||
1326 | err_mask |= AC_ERR_SYSTEM; | 1327 | err_mask |= AC_ERR_SYSTEM; |
1327 | action |= ATA_EH_HARDRESET; | 1328 | action |= ATA_EH_HARDRESET; |
1328 | } | 1329 | } |
1329 | if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) | 1330 | |
1331 | /* Determine whether a hotplug event has occurred. Both | ||
1332 | * SError.N/X are considered hotplug events for enabled or | ||
1333 | * host links. For disabled PMP links, only N bit is | ||
1334 | * considered as X bit is left at 1 for link plugging. | ||
1335 | */ | ||
1336 | hotplug_mask = 0; | ||
1337 | |||
1338 | if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) | ||
1339 | hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; | ||
1340 | else | ||
1341 | hotplug_mask = SERR_PHYRDY_CHG; | ||
1342 | |||
1343 | if (serror & hotplug_mask) | ||
1330 | ata_ehi_hotplugged(&ehc->i); | 1344 | ata_ehi_hotplugged(&ehc->i); |
1331 | 1345 | ||
1332 | ehc->i.err_mask |= err_mask; | 1346 | ehc->i.err_mask |= err_mask; |
@@ -2227,6 +2241,10 @@ static int ata_eh_skip_recovery(struct ata_link *link) | |||
2227 | struct ata_eh_context *ehc = &link->eh_context; | 2241 | struct ata_eh_context *ehc = &link->eh_context; |
2228 | struct ata_device *dev; | 2242 | struct ata_device *dev; |
2229 | 2243 | ||
2244 | /* skip disabled links */ | ||
2245 | if (link->flags & ATA_LFLAG_DISABLED) | ||
2246 | return 1; | ||
2247 | |||
2230 | /* thaw frozen port, resume link and recover failed devices */ | 2248 | /* thaw frozen port, resume link and recover failed devices */ |
2231 | if ((link->ap->pflags & ATA_PFLAG_FROZEN) || | 2249 | if ((link->ap->pflags & ATA_PFLAG_FROZEN) || |
2232 | (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) | 2250 | (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, | |||
2327 | struct ata_device *dev; | 2345 | struct ata_device *dev; |
2328 | int nr_failed_devs, nr_disabled_devs; | 2346 | int nr_failed_devs, nr_disabled_devs; |
2329 | int reset, rc; | 2347 | int reset, rc; |
2348 | unsigned long flags; | ||
2330 | 2349 | ||
2331 | DPRINTK("ENTER\n"); | 2350 | DPRINTK("ENTER\n"); |
2332 | 2351 | ||
@@ -2334,6 +2353,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2334 | ata_port_for_each_link(link, ap) { | 2353 | ata_port_for_each_link(link, ap) { |
2335 | struct ata_eh_context *ehc = &link->eh_context; | 2354 | struct ata_eh_context *ehc = &link->eh_context; |
2336 | 2355 | ||
2356 | /* re-enable link? */ | ||
2357 | if (ehc->i.action & ATA_EH_ENABLE_LINK) { | ||
2358 | ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK); | ||
2359 | spin_lock_irqsave(ap->lock, flags); | ||
2360 | link->flags &= ~ATA_LFLAG_DISABLED; | ||
2361 | spin_unlock_irqrestore(ap->lock, flags); | ||
2362 | ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK); | ||
2363 | } | ||
2364 | |||
2337 | ata_link_for_each_dev(dev, link) { | 2365 | ata_link_for_each_dev(dev, link) { |
2338 | if (link->flags & ATA_LFLAG_NO_RETRY) | 2366 | if (link->flags & ATA_LFLAG_NO_RETRY) |
2339 | ehc->tries[dev->devno] = 1; | 2367 | ehc->tries[dev->devno] = 1; |
diff --git a/include/linux/libata.h b/include/linux/libata.h index adeee7397cdb..2bd1d26c9c8d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -170,6 +170,7 @@ enum { | |||
170 | ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ | 170 | ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ |
171 | ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, | 171 | ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, |
172 | ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ | 172 | ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ |
173 | ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ | ||
173 | 174 | ||
174 | /* struct ata_port flags */ | 175 | /* struct ata_port flags */ |
175 | ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ | 176 | ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ |
@@ -289,6 +290,7 @@ enum { | |||
289 | ATA_EH_REVALIDATE = (1 << 0), | 290 | ATA_EH_REVALIDATE = (1 << 0), |
290 | ATA_EH_SOFTRESET = (1 << 1), | 291 | ATA_EH_SOFTRESET = (1 << 1), |
291 | ATA_EH_HARDRESET = (1 << 2), | 292 | ATA_EH_HARDRESET = (1 << 2), |
293 | ATA_EH_ENABLE_LINK = (1 << 3), | ||
292 | 294 | ||
293 | ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, | 295 | ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, |
294 | ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, | 296 | ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, |
@@ -999,6 +1001,7 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) | |||
999 | { | 1001 | { |
1000 | ata_ehi_schedule_probe(ehi); | 1002 | ata_ehi_schedule_probe(ehi); |
1001 | ehi->flags |= ATA_EHI_HOTPLUGGED; | 1003 | ehi->flags |= ATA_EHI_HOTPLUGGED; |
1004 | ehi->action |= ATA_EH_ENABLE_LINK; | ||
1002 | ehi->err_mask |= AC_ERR_ATA_BUS; | 1005 | ehi->err_mask |= AC_ERR_ATA_BUS; |
1003 | } | 1006 | } |
1004 | 1007 | ||