ATA_ECAT_DUBIOUS_TOUT_HSM = 6,
ATA_ECAT_DUBIOUS_UNK_DEV = 7,
ATA_ECAT_NR = 8,
-};
-/* Waiting in ->prereset can never be reliable. It's sometimes nice
- * to wait there but it can't be depended upon; otherwise, we wouldn't
- * be resetting. Just give it enough time for most drives to spin up.
- */
-enum {
- ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
- ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
+ /* always put at least this amount of time between resets */
+ ATA_EH_RESET_COOL_DOWN = 5000,
+
+ /* Waiting in ->prereset can never be reliable. It's
+ * sometimes nice to wait there but it can't be depended upon;
+ * otherwise, we wouldn't be resetting. Just give it enough
+ * time for most drives to spin up.
+ */
+ ATA_EH_PRERESET_TIMEOUT = 10000,
+ ATA_EH_FASTDRAIN_INTERVAL = 3000,
};
/* The following table determines how we sequence resets. Each entry
* are mostly for error handling, hotplug and retarded devices.
*/
static const unsigned long ata_eh_reset_timeouts[] = {
- 10 * HZ, /* most drives spin up by 10sec */
- 10 * HZ, /* > 99% working drives spin up before 20sec */
- 35 * HZ, /* give > 30 secs of idleness for retarded devices */
- 5 * HZ, /* and sweet one last chance */
+ 10000, /* most drives spin up by 10sec */
+ 10000, /* > 99% working drives spin up before 20sec */
+ 35000, /* give > 30 secs of idleness for retarded devices */
+ 5000, /* and sweet one last chance */
/* > 1 min has elapsed, give up */
};
if (ata_ncq_enabled(dev))
ehc->saved_ncq_enabled |= 1 << devno;
}
+
+ /* set last reset timestamp to some time in the past */
+ ehc->last_reset = jiffies - 60 * HZ;
}
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
/* some qcs have finished, give it another chance */
ap->fastdrain_cnt = cnt;
ap->fastdrain_timer.expires =
- jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL);
add_timer(&ap->fastdrain_timer);
}
/* activate fast drain */
ap->fastdrain_cnt = cnt;
- ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ ap->fastdrain_timer.expires =
+ ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL);
add_timer(&ap->fastdrain_timer);
}
/*
* Prepare to reset
*/
+ now = jiffies;
+ deadline = ata_deadline(ehc->last_reset, ATA_EH_RESET_COOL_DOWN);
+ if (time_before(now, deadline))
+ schedule_timeout_uninterruptible(deadline - now);
+
spin_lock_irqsave(ap->lock, flags);
ap->pflags |= ATA_PFLAG_RESETTING;
spin_unlock_irqrestore(ap->lock, flags);
ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
+ ehc->last_reset = jiffies;
ata_link_for_each_dev(dev, link) {
/* If we issue an SRST then an ATA drive (not ATAPI)
}
if (prereset) {
- rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
+ rc = prereset(link,
+ ata_deadline(jiffies, ATA_EH_PRERESET_TIMEOUT));
if (rc) {
if (rc == -ENOENT) {
ata_link_printk(link, KERN_DEBUG,
/*
* Perform reset
*/
+ ehc->last_reset = jiffies;
if (ata_is_host_link(link))
ata_eh_freeze_port(ap);
- deadline = jiffies + ata_eh_reset_timeouts[try++];
+ deadline = ata_deadline(jiffies, ata_eh_reset_timeouts[try++]);
if (reset) {
if (verbose)
/* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET);
+ ehc->last_reset = jiffies;
ehc->i.action |= ATA_EH_REVALIDATE;
rc = 0;
if (time_before(now, deadline)) {
unsigned long delta = deadline - now;
- ata_link_printk(link, KERN_WARNING, "reset failed "
- "(errno=%d), retrying in %u secs\n",
- rc, (jiffies_to_msecs(delta) + 999) / 1000);
+ ata_link_printk(link, KERN_WARNING,
+ "reset failed (errno=%d), retrying in %u secs\n",
+ rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
while (delta)
delta = schedule_timeout_uninterruptible(delta);
{
struct ata_link *link;
struct ata_device *dev;
- int nr_failed_devs, nr_disabled_devs;
+ int nr_failed_devs;
int rc;
unsigned long flags;
retry:
rc = 0;
nr_failed_devs = 0;
- nr_disabled_devs = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
dev_fail:
nr_failed_devs++;
- if (ata_eh_handle_dev_fail(dev, rc))
- nr_disabled_devs++;
+ ata_eh_handle_dev_fail(dev, rc);
if (ap->pflags & ATA_PFLAG_FROZEN) {
/* PMP reset requires working host port.
}
}
- if (nr_failed_devs) {
- if (nr_failed_devs != nr_disabled_devs) {
- ata_port_printk(ap, KERN_WARNING, "failed to recover "
- "some devices, retrying in 5 secs\n");
- ssleep(5);
- } else {
- /* no device left to recover, repeat fast */
- msleep(500);
- }
-
+ if (nr_failed_devs)
goto retry;
- }
out:
if (rc && r_failed_link)