aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-11-04 03:08:40 -0500
committerJeff Garzik <jgarzik@redhat.com>2008-11-11 03:01:21 -0500
commit19b723218bde79c60a394a3caee9eb156ac2d356 (patch)
tree5ea111eb99068ae04ec5bc5ab2089a288362b5c1 /drivers/ata
parent44901a96847b9967c057832b185e2f34ee6a14e5 (diff)
libata: fix last_reset timestamp handling
ehc->last_reset is used to ensure that resets are not issued too close to each other. It's initialized to jiffies minus one minute on EH entry. However, when new links are initialized after PMP is probed, new links have zero for this timestamp resulting in long wait depending on the current jiffies. This patch makes last_set considered iff ATA_EHI_DID_RESET is set, in which case last_reset is always initialized. As an added precaution, WARN_ON() is added so that warning is printed if last_reset is in future. This problem is spotted and debugged by Shane Huang. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Shane Huang <Shane.Huang@amd.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-eh.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 8077bdf5d30d..32da9a93ce44 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -610,9 +610,6 @@ void ata_scsi_error(struct Scsi_Host *host)
610 if (ata_ncq_enabled(dev)) 610 if (ata_ncq_enabled(dev))
611 ehc->saved_ncq_enabled |= 1 << devno; 611 ehc->saved_ncq_enabled |= 1 << devno;
612 } 612 }
613
614 /* set last reset timestamp to some time in the past */
615 ehc->last_reset = jiffies - 60 * HZ;
616 } 613 }
617 614
618 ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; 615 ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
@@ -2281,17 +2278,21 @@ int ata_eh_reset(struct ata_link *link, int classify,
2281 if (link->flags & ATA_LFLAG_NO_SRST) 2278 if (link->flags & ATA_LFLAG_NO_SRST)
2282 softreset = NULL; 2279 softreset = NULL;
2283 2280
2284 now = jiffies; 2281 /* make sure each reset attemp is at least COOL_DOWN apart */
2285 deadline = ata_deadline(ehc->last_reset, ATA_EH_RESET_COOL_DOWN); 2282 if (ehc->i.flags & ATA_EHI_DID_RESET) {
2286 if (time_before(now, deadline)) 2283 now = jiffies;
2287 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 }
2288 2290
2289 spin_lock_irqsave(ap->lock, flags); 2291 spin_lock_irqsave(ap->lock, flags);
2290 ap->pflags |= ATA_PFLAG_RESETTING; 2292 ap->pflags |= ATA_PFLAG_RESETTING;
2291 spin_unlock_irqrestore(ap->lock, flags); 2293 spin_unlock_irqrestore(ap->lock, flags);
2292 2294
2293 ata_eh_about_to_do(link, NULL, ATA_EH_RESET); 2295 ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
2294 ehc->last_reset = jiffies;
2295 2296
2296 ata_link_for_each_dev(dev, link) { 2297 ata_link_for_each_dev(dev, link) {
2297 /* If we issue an SRST then an ATA drive (not ATAPI) 2298 /* If we issue an SRST then an ATA drive (not ATAPI)
@@ -2379,7 +2380,6 @@ int ata_eh_reset(struct ata_link *link, int classify,
2379 /* 2380 /*
2380 * Perform reset 2381 * Perform reset
2381 */ 2382 */
2382 ehc->last_reset = jiffies;
2383 if (ata_is_host_link(link)) 2383 if (ata_is_host_link(link))
2384 ata_eh_freeze_port(ap); 2384 ata_eh_freeze_port(ap);
2385 2385
@@ -2391,6 +2391,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
2391 reset == softreset ? "soft" : "hard"); 2391 reset == softreset ? "soft" : "hard");
2392 2392
2393 /* mark that this EH session started with reset */ 2393 /* mark that this EH session started with reset */
2394 ehc->last_reset = jiffies;
2394 if (reset == hardreset) 2395 if (reset == hardreset)
2395 ehc->i.flags |= ATA_EHI_DID_HARDRESET; 2396 ehc->i.flags |= ATA_EHI_DID_HARDRESET;
2396 else 2397 else
@@ -2535,7 +2536,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
2535 ata_eh_done(link, NULL, ATA_EH_RESET); 2536 ata_eh_done(link, NULL, ATA_EH_RESET);
2536 if (slave) 2537 if (slave)
2537 ata_eh_done(slave, NULL, ATA_EH_RESET); 2538 ata_eh_done(slave, NULL, ATA_EH_RESET);
2538 ehc->last_reset = jiffies; 2539 ehc->last_reset = jiffies; /* update to completion time */
2539 ehc->i.action |= ATA_EH_REVALIDATE; 2540 ehc->i.action |= ATA_EH_REVALIDATE;
2540 2541
2541 rc = 0; 2542 rc = 0;