aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 5d687d7cffae..32da9a93ce44 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -603,13 +603,13 @@ void ata_scsi_error(struct Scsi_Host *host)
603 ata_link_for_each_dev(dev, link) { 603 ata_link_for_each_dev(dev, link) {
604 int devno = dev->devno; 604 int devno = dev->devno;
605 605
606 if (!ata_dev_enabled(dev))
607 continue;
608
606 ehc->saved_xfer_mode[devno] = dev->xfer_mode; 609 ehc->saved_xfer_mode[devno] = dev->xfer_mode;
607 if (ata_ncq_enabled(dev)) 610 if (ata_ncq_enabled(dev))
608 ehc->saved_ncq_enabled |= 1 << devno; 611 ehc->saved_ncq_enabled |= 1 << devno;
609 } 612 }
610
611 /* set last reset timestamp to some time in the past */
612 ehc->last_reset = jiffies - 60 * HZ;
613 } 613 }
614 614
615 ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; 615 ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
@@ -1161,6 +1161,7 @@ void ata_eh_detach_dev(struct ata_device *dev)
1161{ 1161{
1162 struct ata_link *link = dev->link; 1162 struct ata_link *link = dev->link;
1163 struct ata_port *ap = link->ap; 1163 struct ata_port *ap = link->ap;
1164 struct ata_eh_context *ehc = &link->eh_context;
1164 unsigned long flags; 1165 unsigned long flags;
1165 1166
1166 ata_dev_disable(dev); 1167 ata_dev_disable(dev);
@@ -1174,9 +1175,11 @@ void ata_eh_detach_dev(struct ata_device *dev)
1174 ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; 1175 ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
1175 } 1176 }
1176 1177
1177 /* clear per-dev EH actions */ 1178 /* clear per-dev EH info */
1178 ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK); 1179 ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
1179 ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK); 1180 ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
1181 ehc->saved_xfer_mode[dev->devno] = 0;
1182 ehc->saved_ncq_enabled &= ~(1 << dev->devno);
1180 1183
1181 spin_unlock_irqrestore(ap->lock, flags); 1184 spin_unlock_irqrestore(ap->lock, flags);
1182} 1185}
@@ -2275,17 +2278,21 @@ int ata_eh_reset(struct ata_link *link, int classify,
2275 if (link->flags & ATA_LFLAG_NO_SRST) 2278 if (link->flags & ATA_LFLAG_NO_SRST)
2276 softreset = NULL; 2279 softreset = NULL;
2277 2280
2278 now = jiffies; 2281 /* make sure each reset attemp is at least COOL_DOWN apart */
2279 deadline = ata_deadline(ehc->last_reset, ATA_EH_RESET_COOL_DOWN); 2282 if (ehc->i.flags & ATA_EHI_DID_RESET) {
2280 if (time_before(now, deadline)) 2283 now = jiffies;
2281 schedule_timeout_uninterruptible(deadline - now); 2284 WARN_ON(time_after(ehc->last_reset, now));
2285 deadline = ata_deadline(ehc->last_reset,
2286 ATA_EH_RESET_COOL_DOWN);
2287 if (time_before(now, deadline))
2288 schedule_timeout_uninterruptible(deadline - now);
2289 }
2282 2290
2283 spin_lock_irqsave(ap->lock, flags); 2291 spin_lock_irqsave(ap->lock, flags);
2284 ap->pflags |= ATA_PFLAG_RESETTING; 2292 ap->pflags |= ATA_PFLAG_RESETTING;
2285 spin_unlock_irqrestore(ap->lock, flags); 2293 spin_unlock_irqrestore(ap->lock, flags);
2286 2294
2287 ata_eh_about_to_do(link, NULL, ATA_EH_RESET); 2295 ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
2288 ehc->last_reset = jiffies;
2289 2296
2290 ata_link_for_each_dev(dev, link) { 2297 ata_link_for_each_dev(dev, link) {
2291 /* If we issue an SRST then an ATA drive (not ATAPI) 2298 /* If we issue an SRST then an ATA drive (not ATAPI)
@@ -2373,7 +2380,6 @@ int ata_eh_reset(struct ata_link *link, int classify,
2373 /* 2380 /*
2374 * Perform reset 2381 * Perform reset
2375 */ 2382 */
2376 ehc->last_reset = jiffies;
2377 if (ata_is_host_link(link)) 2383 if (ata_is_host_link(link))
2378 ata_eh_freeze_port(ap); 2384 ata_eh_freeze_port(ap);
2379 2385
@@ -2385,6 +2391,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
2385 reset == softreset ? "soft" : "hard"); 2391 reset == softreset ? "soft" : "hard");
2386 2392
2387 /* mark that this EH session started with reset */ 2393 /* mark that this EH session started with reset */
2394 ehc->last_reset = jiffies;
2388 if (reset == hardreset) 2395 if (reset == hardreset)
2389 ehc->i.flags |= ATA_EHI_DID_HARDRESET; 2396 ehc->i.flags |= ATA_EHI_DID_HARDRESET;
2390 else 2397 else
@@ -2529,7 +2536,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
2529 ata_eh_done(link, NULL, ATA_EH_RESET); 2536 ata_eh_done(link, NULL, ATA_EH_RESET);
2530 if (slave) 2537 if (slave)
2531 ata_eh_done(slave, NULL, ATA_EH_RESET); 2538 ata_eh_done(slave, NULL, ATA_EH_RESET);
2532 ehc->last_reset = jiffies; 2539 ehc->last_reset = jiffies; /* update to completion time */
2533 ehc->i.action |= ATA_EH_REVALIDATE; 2540 ehc->i.action |= ATA_EH_REVALIDATE;
2534 2541
2535 rc = 0; 2542 rc = 0;
@@ -2787,6 +2794,9 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
2787 2794
2788 /* if data transfer is verified, clear DUBIOUS_XFER on ering top */ 2795 /* if data transfer is verified, clear DUBIOUS_XFER on ering top */
2789 ata_link_for_each_dev(dev, link) { 2796 ata_link_for_each_dev(dev, link) {
2797 if (!ata_dev_enabled(dev))
2798 continue;
2799
2790 if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) { 2800 if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) {
2791 struct ata_ering_entry *ent; 2801 struct ata_ering_entry *ent;
2792 2802
@@ -2808,6 +2818,9 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
2808 u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno]; 2818 u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno];
2809 u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno)); 2819 u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno));
2810 2820
2821 if (!ata_dev_enabled(dev))
2822 continue;
2823
2811 if (dev->xfer_mode != saved_xfer_mode || 2824 if (dev->xfer_mode != saved_xfer_mode ||
2812 ata_ncq_enabled(dev) != saved_ncq) 2825 ata_ncq_enabled(dev) != saved_ncq)
2813 dev->flags |= ATA_DFLAG_DUBIOUS_XFER; 2826 dev->flags |= ATA_DFLAG_DUBIOUS_XFER;