diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 58 |
1 files changed, 41 insertions, 17 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index b3f7d3c8ae60..8256655ce7d9 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -50,6 +50,28 @@ enum { | |||
50 | ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), | 50 | ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* Waiting in ->prereset can never be reliable. It's sometimes nice | ||
54 | * to wait there but it can't be depended upon; otherwise, we wouldn't | ||
55 | * be resetting. Just give it enough time for most drives to spin up. | ||
56 | */ | ||
57 | enum { | ||
58 | ATA_EH_PRERESET_TIMEOUT = 10 * HZ, | ||
59 | }; | ||
60 | |||
61 | /* The following table determines how we sequence resets. Each entry | ||
62 | * represents timeout for that try. The first try can be soft or | ||
63 | * hardreset. All others are hardreset if available. In most cases | ||
64 | * the first reset w/ 10sec timeout should succeed. Following entries | ||
65 | * are mostly for error handling, hotplug and retarded devices. | ||
66 | */ | ||
67 | static const unsigned long ata_eh_reset_timeouts[] = { | ||
68 | 10 * HZ, /* most drives spin up by 10sec */ | ||
69 | 10 * HZ, /* > 99% working drives spin up before 20sec */ | ||
70 | 35 * HZ, /* give > 30 secs of idleness for retarded devices */ | ||
71 | 5 * HZ, /* and sweet one last chance */ | ||
72 | /* > 1 min has elapsed, give up */ | ||
73 | }; | ||
74 | |||
53 | static void __ata_port_freeze(struct ata_port *ap); | 75 | static void __ata_port_freeze(struct ata_port *ap); |
54 | static void ata_eh_finish(struct ata_port *ap); | 76 | static void ata_eh_finish(struct ata_port *ap); |
55 | #ifdef CONFIG_PM | 77 | #ifdef CONFIG_PM |
@@ -1603,8 +1625,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1603 | { | 1625 | { |
1604 | struct ata_eh_context *ehc = &ap->eh_context; | 1626 | struct ata_eh_context *ehc = &ap->eh_context; |
1605 | unsigned int *classes = ehc->classes; | 1627 | unsigned int *classes = ehc->classes; |
1606 | int tries = ATA_EH_RESET_TRIES; | ||
1607 | int verbose = !(ehc->i.flags & ATA_EHI_QUIET); | 1628 | int verbose = !(ehc->i.flags & ATA_EHI_QUIET); |
1629 | int try = 0; | ||
1630 | unsigned long deadline; | ||
1608 | unsigned int action; | 1631 | unsigned int action; |
1609 | ata_reset_fn_t reset; | 1632 | ata_reset_fn_t reset; |
1610 | int i, did_followup_srst, rc; | 1633 | int i, did_followup_srst, rc; |
@@ -1624,7 +1647,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1624 | ehc->i.action |= ATA_EH_HARDRESET; | 1647 | ehc->i.action |= ATA_EH_HARDRESET; |
1625 | 1648 | ||
1626 | if (prereset) { | 1649 | if (prereset) { |
1627 | rc = prereset(ap, jiffies + 40 * HZ); | 1650 | rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT); |
1628 | if (rc) { | 1651 | if (rc) { |
1629 | if (rc == -ENOENT) { | 1652 | if (rc == -ENOENT) { |
1630 | ata_port_printk(ap, KERN_DEBUG, | 1653 | ata_port_printk(ap, KERN_DEBUG, |
@@ -1665,6 +1688,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1665 | } | 1688 | } |
1666 | 1689 | ||
1667 | retry: | 1690 | retry: |
1691 | deadline = jiffies + ata_eh_reset_timeouts[try++]; | ||
1692 | |||
1668 | /* shut up during boot probing */ | 1693 | /* shut up during boot probing */ |
1669 | if (verbose) | 1694 | if (verbose) |
1670 | ata_port_printk(ap, KERN_INFO, "%s resetting port\n", | 1695 | ata_port_printk(ap, KERN_INFO, "%s resetting port\n", |
@@ -1676,7 +1701,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1676 | else | 1701 | else |
1677 | ehc->i.flags |= ATA_EHI_DID_SOFTRESET; | 1702 | ehc->i.flags |= ATA_EHI_DID_SOFTRESET; |
1678 | 1703 | ||
1679 | rc = ata_do_reset(ap, reset, classes, jiffies + 40 * HZ); | 1704 | rc = ata_do_reset(ap, reset, classes, deadline); |
1680 | 1705 | ||
1681 | did_followup_srst = 0; | 1706 | did_followup_srst = 0; |
1682 | if (reset == hardreset && | 1707 | if (reset == hardreset && |
@@ -1693,7 +1718,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1693 | } | 1718 | } |
1694 | 1719 | ||
1695 | ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); | 1720 | ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); |
1696 | rc = ata_do_reset(ap, reset, classes, jiffies + 40 * HZ); | 1721 | rc = ata_do_reset(ap, reset, classes, deadline); |
1697 | 1722 | ||
1698 | if (rc == 0 && classify && | 1723 | if (rc == 0 && classify && |
1699 | classes[0] == ATA_DEV_UNKNOWN) { | 1724 | classes[0] == ATA_DEV_UNKNOWN) { |
@@ -1703,22 +1728,21 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1703 | } | 1728 | } |
1704 | } | 1729 | } |
1705 | 1730 | ||
1706 | if (rc && --tries) { | 1731 | if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { |
1707 | const char *type; | 1732 | unsigned long now = jiffies; |
1708 | 1733 | ||
1709 | if (reset == softreset) { | 1734 | if (time_before(now, deadline)) { |
1710 | if (did_followup_srst) | 1735 | unsigned long delta = deadline - jiffies; |
1711 | type = "follow-up soft"; | ||
1712 | else | ||
1713 | type = "soft"; | ||
1714 | } else | ||
1715 | type = "hard"; | ||
1716 | 1736 | ||
1717 | ata_port_printk(ap, KERN_WARNING, | 1737 | ata_port_printk(ap, KERN_WARNING, "reset failed " |
1718 | "%sreset failed, retrying in 5 secs\n", type); | 1738 | "(errno=%d), retrying in %u secs\n", |
1719 | ssleep(5); | 1739 | rc, (jiffies_to_msecs(delta) + 999) / 1000); |
1740 | |||
1741 | schedule_timeout_uninterruptible(delta); | ||
1742 | } | ||
1720 | 1743 | ||
1721 | if (reset == hardreset) | 1744 | if (reset == hardreset && |
1745 | try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1) | ||
1722 | sata_down_spd_limit(ap); | 1746 | sata_down_spd_limit(ap); |
1723 | if (hardreset) | 1747 | if (hardreset) |
1724 | reset = hardreset; | 1748 | reset = hardreset; |