diff options
author | Tejun Heo <htejun@gmail.com> | 2007-08-06 05:36:24 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:32 -0400 |
commit | 9b1e2658faf3f3095a96558c333b333c0e29dbc0 (patch) | |
tree | 38553202d35e9a82b2e943df525d482892fef505 /drivers/ata | |
parent | cf1b86c8ab41fe2b2a2eb59c9a2ea9a7e463653a (diff) |
libata-link: update EH to deal with PMP links
Update ata_eh_autopsy(), ata_eh_report(),
ata_eh_revalidate_and_attach() and ata_eh_recover() to deal with PMP
links. ata_eh_autopsy() and ata_eh_report() updates are
straightforward. They just repeat the same operation over all
configured links. The only change to ata_eh_revalidate_and_attach()
is avoiding calling ->cable_select() on non-host ports.
ata_eh_recover() update is more complex as it first processes all
resets and then performs the rest. This is necessary as thawing with
some links in unknown state can be dangerous. ehi->action is cleared
on successful recovery of a link to avoid repeating recovery due to
failures in other links.
ata_eh_recover() iterates over only PMP links if PMP is attached, and,
on failure, the failing link is returned in @failed_link instead of
disabling devices directly. These are to integrate ata_eh_recover()
into PMP EH later.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-eh.c | 228 |
1 files changed, 158 insertions, 70 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 45eb932c3935..2ddc2ed9c29d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -1578,8 +1578,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, | |||
1578 | } | 1578 | } |
1579 | 1579 | ||
1580 | /** | 1580 | /** |
1581 | * ata_eh_autopsy - analyze error and determine recovery action | 1581 | * ata_eh_link_autopsy - analyze error and determine recovery action |
1582 | * @link: ATA link to perform autopsy on | 1582 | * @link: host link to perform autopsy on |
1583 | * | 1583 | * |
1584 | * Analyze why @link failed and determine which recovery actions | 1584 | * Analyze why @link failed and determine which recovery actions |
1585 | * are needed. This function also sets more detailed AC_ERR_* | 1585 | * are needed. This function also sets more detailed AC_ERR_* |
@@ -1588,7 +1588,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, | |||
1588 | * LOCKING: | 1588 | * LOCKING: |
1589 | * Kernel thread context (may sleep). | 1589 | * Kernel thread context (may sleep). |
1590 | */ | 1590 | */ |
1591 | static void ata_eh_autopsy(struct ata_link *link) | 1591 | static void ata_eh_link_autopsy(struct ata_link *link) |
1592 | { | 1592 | { |
1593 | struct ata_port *ap = link->ap; | 1593 | struct ata_port *ap = link->ap; |
1594 | struct ata_eh_context *ehc = &link->eh_context; | 1594 | struct ata_eh_context *ehc = &link->eh_context; |
@@ -1680,7 +1680,25 @@ static void ata_eh_autopsy(struct ata_link *link) | |||
1680 | } | 1680 | } |
1681 | 1681 | ||
1682 | /** | 1682 | /** |
1683 | * ata_eh_report - report error handling to user | 1683 | * ata_eh_autopsy - analyze error and determine recovery action |
1684 | * @ap: host port to perform autopsy on | ||
1685 | * | ||
1686 | * Analyze all links of @ap and determine why they failed and | ||
1687 | * which recovery actions are needed. | ||
1688 | * | ||
1689 | * LOCKING: | ||
1690 | * Kernel thread context (may sleep). | ||
1691 | */ | ||
1692 | static void ata_eh_autopsy(struct ata_port *ap) | ||
1693 | { | ||
1694 | struct ata_link *link; | ||
1695 | |||
1696 | __ata_port_for_each_link(link, ap) | ||
1697 | ata_eh_link_autopsy(link); | ||
1698 | } | ||
1699 | |||
1700 | /** | ||
1701 | * ata_eh_link_report - report error handling to user | ||
1684 | * @link: ATA link EH is going on | 1702 | * @link: ATA link EH is going on |
1685 | * | 1703 | * |
1686 | * Report EH to user. | 1704 | * Report EH to user. |
@@ -1688,7 +1706,7 @@ static void ata_eh_autopsy(struct ata_link *link) | |||
1688 | * LOCKING: | 1706 | * LOCKING: |
1689 | * None. | 1707 | * None. |
1690 | */ | 1708 | */ |
1691 | static void ata_eh_report(struct ata_link *link) | 1709 | static void ata_eh_link_report(struct ata_link *link) |
1692 | { | 1710 | { |
1693 | struct ata_port *ap = link->ap; | 1711 | struct ata_port *ap = link->ap; |
1694 | struct ata_eh_context *ehc = &link->eh_context; | 1712 | struct ata_eh_context *ehc = &link->eh_context; |
@@ -1767,6 +1785,23 @@ static void ata_eh_report(struct ata_link *link) | |||
1767 | } | 1785 | } |
1768 | } | 1786 | } |
1769 | 1787 | ||
1788 | /** | ||
1789 | * ata_eh_report - report error handling to user | ||
1790 | * @ap: ATA port to report EH about | ||
1791 | * | ||
1792 | * Report EH to user. | ||
1793 | * | ||
1794 | * LOCKING: | ||
1795 | * None. | ||
1796 | */ | ||
1797 | static void ata_eh_report(struct ata_port *ap) | ||
1798 | { | ||
1799 | struct ata_link *link; | ||
1800 | |||
1801 | __ata_port_for_each_link(link, ap) | ||
1802 | ata_eh_link_report(link); | ||
1803 | } | ||
1804 | |||
1770 | static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, | 1805 | static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, |
1771 | unsigned int *classes, unsigned long deadline) | 1806 | unsigned int *classes, unsigned long deadline) |
1772 | { | 1807 | { |
@@ -2036,7 +2071,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, | |||
2036 | } | 2071 | } |
2037 | 2072 | ||
2038 | /* PDIAG- should have been released, ask cable type if post-reset */ | 2073 | /* PDIAG- should have been released, ask cable type if post-reset */ |
2039 | if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect) | 2074 | if (ata_is_host_link(link) && ap->ops->cable_detect && |
2075 | (ehc->i.flags & ATA_EHI_DID_RESET)) | ||
2040 | ap->cbl = ap->ops->cable_detect(ap); | 2076 | ap->cbl = ap->ops->cable_detect(ap); |
2041 | 2077 | ||
2042 | /* Configure new devices forward such that user doesn't see | 2078 | /* Configure new devices forward such that user doesn't see |
@@ -2110,7 +2146,7 @@ static int ata_eh_skip_recovery(struct ata_link *link) | |||
2110 | return 1; | 2146 | return 1; |
2111 | } | 2147 | } |
2112 | 2148 | ||
2113 | static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) | 2149 | static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) |
2114 | { | 2150 | { |
2115 | struct ata_eh_context *ehc = &dev->link->eh_context; | 2151 | struct ata_eh_context *ehc = &dev->link->eh_context; |
2116 | 2152 | ||
@@ -2151,12 +2187,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) | |||
2151 | ehc->did_probe_mask |= (1 << dev->devno); | 2187 | ehc->did_probe_mask |= (1 << dev->devno); |
2152 | ehc->i.action |= ATA_EH_SOFTRESET; | 2188 | ehc->i.action |= ATA_EH_SOFTRESET; |
2153 | } | 2189 | } |
2190 | |||
2191 | return 1; | ||
2154 | } else { | 2192 | } else { |
2155 | /* soft didn't work? be haaaaard */ | 2193 | /* soft didn't work? be haaaaard */ |
2156 | if (ehc->i.flags & ATA_EHI_DID_RESET) | 2194 | if (ehc->i.flags & ATA_EHI_DID_RESET) |
2157 | ehc->i.action |= ATA_EH_HARDRESET; | 2195 | ehc->i.action |= ATA_EH_HARDRESET; |
2158 | else | 2196 | else |
2159 | ehc->i.action |= ATA_EH_SOFTRESET; | 2197 | ehc->i.action |= ATA_EH_SOFTRESET; |
2198 | |||
2199 | return 0; | ||
2160 | } | 2200 | } |
2161 | } | 2201 | } |
2162 | 2202 | ||
@@ -2167,12 +2207,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) | |||
2167 | * @softreset: softreset method (can be NULL) | 2207 | * @softreset: softreset method (can be NULL) |
2168 | * @hardreset: hardreset method (can be NULL) | 2208 | * @hardreset: hardreset method (can be NULL) |
2169 | * @postreset: postreset method (can be NULL) | 2209 | * @postreset: postreset method (can be NULL) |
2210 | * @r_failed_link: out parameter for failed link | ||
2170 | * | 2211 | * |
2171 | * This is the alpha and omega, eum and yang, heart and soul of | 2212 | * This is the alpha and omega, eum and yang, heart and soul of |
2172 | * libata exception handling. On entry, actions required to | 2213 | * libata exception handling. On entry, actions required to |
2173 | * recover the port and hotplug requests are recorded in | 2214 | * recover each link and hotplug requests are recorded in the |
2174 | * eh_context. This function executes all the operations with | 2215 | * link's eh_context. This function executes all the operations |
2175 | * appropriate retrials and fallbacks to resurrect failed | 2216 | * with appropriate retrials and fallbacks to resurrect failed |
2176 | * devices, detach goners and greet newcomers. | 2217 | * devices, detach goners and greet newcomers. |
2177 | * | 2218 | * |
2178 | * LOCKING: | 2219 | * LOCKING: |
@@ -2183,102 +2224,139 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) | |||
2183 | */ | 2224 | */ |
2184 | static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | 2225 | static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, |
2185 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, | 2226 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, |
2186 | ata_postreset_fn_t postreset) | 2227 | ata_postreset_fn_t postreset, |
2228 | struct ata_link **r_failed_link) | ||
2187 | { | 2229 | { |
2188 | struct ata_link *link = &ap->link; | 2230 | struct ata_link *link; |
2189 | struct ata_eh_context *ehc = &link->eh_context; | ||
2190 | struct ata_device *dev; | 2231 | struct ata_device *dev; |
2191 | int rc; | 2232 | int nr_failed_devs, nr_disabled_devs; |
2233 | int reset, rc; | ||
2192 | 2234 | ||
2193 | DPRINTK("ENTER\n"); | 2235 | DPRINTK("ENTER\n"); |
2194 | 2236 | ||
2195 | /* prep for recovery */ | 2237 | /* prep for recovery */ |
2196 | ata_link_for_each_dev(dev, link) { | 2238 | ata_port_for_each_link(link, ap) { |
2197 | ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; | 2239 | struct ata_eh_context *ehc = &link->eh_context; |
2198 | 2240 | ||
2199 | /* collect port action mask recorded in dev actions */ | 2241 | ata_link_for_each_dev(dev, link) { |
2200 | ehc->i.action |= | 2242 | ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; |
2201 | ehc->i.dev_action[dev->devno] & ~ATA_EH_PERDEV_MASK; | ||
2202 | ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; | ||
2203 | |||
2204 | /* process hotplug request */ | ||
2205 | if (dev->flags & ATA_DFLAG_DETACH) | ||
2206 | ata_eh_detach_dev(dev); | ||
2207 | 2243 | ||
2208 | if (!ata_dev_enabled(dev) && | 2244 | /* collect port action mask recorded in dev actions */ |
2209 | ((ehc->i.probe_mask & (1 << dev->devno)) && | 2245 | ehc->i.action |= ehc->i.dev_action[dev->devno] & |
2210 | !(ehc->did_probe_mask & (1 << dev->devno)))) { | 2246 | ~ATA_EH_PERDEV_MASK; |
2211 | ata_eh_detach_dev(dev); | 2247 | ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; |
2212 | ata_dev_init(dev); | 2248 | |
2213 | ehc->did_probe_mask |= (1 << dev->devno); | 2249 | /* process hotplug request */ |
2214 | ehc->i.action |= ATA_EH_SOFTRESET; | 2250 | if (dev->flags & ATA_DFLAG_DETACH) |
2251 | ata_eh_detach_dev(dev); | ||
2252 | |||
2253 | if (!ata_dev_enabled(dev) && | ||
2254 | ((ehc->i.probe_mask & (1 << dev->devno)) && | ||
2255 | !(ehc->did_probe_mask & (1 << dev->devno)))) { | ||
2256 | ata_eh_detach_dev(dev); | ||
2257 | ata_dev_init(dev); | ||
2258 | ehc->did_probe_mask |= (1 << dev->devno); | ||
2259 | ehc->i.action |= ATA_EH_SOFTRESET; | ||
2260 | } | ||
2215 | } | 2261 | } |
2216 | } | 2262 | } |
2217 | 2263 | ||
2218 | retry: | 2264 | retry: |
2219 | rc = 0; | 2265 | rc = 0; |
2266 | nr_failed_devs = 0; | ||
2267 | nr_disabled_devs = 0; | ||
2268 | reset = 0; | ||
2220 | 2269 | ||
2221 | /* if UNLOADING, finish immediately */ | 2270 | /* if UNLOADING, finish immediately */ |
2222 | if (ap->pflags & ATA_PFLAG_UNLOADING) | 2271 | if (ap->pflags & ATA_PFLAG_UNLOADING) |
2223 | goto out; | 2272 | goto out; |
2224 | 2273 | ||
2225 | /* skip EH if possible. */ | 2274 | /* prep for EH */ |
2226 | if (ata_eh_skip_recovery(link)) | 2275 | ata_port_for_each_link(link, ap) { |
2227 | ehc->i.action = 0; | 2276 | struct ata_eh_context *ehc = &link->eh_context; |
2228 | 2277 | ||
2229 | ata_link_for_each_dev(dev, link) | 2278 | /* skip EH if possible. */ |
2230 | ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; | 2279 | if (ata_eh_skip_recovery(link)) |
2280 | ehc->i.action = 0; | ||
2281 | |||
2282 | /* do we need to reset? */ | ||
2283 | if (ehc->i.action & ATA_EH_RESET_MASK) | ||
2284 | reset = 1; | ||
2285 | |||
2286 | ata_link_for_each_dev(dev, link) | ||
2287 | ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; | ||
2288 | } | ||
2231 | 2289 | ||
2232 | /* reset */ | 2290 | /* reset */ |
2233 | if (ehc->i.action & ATA_EH_RESET_MASK) { | 2291 | if (reset) { |
2234 | ata_eh_freeze_port(ap); | 2292 | ata_eh_freeze_port(ap); |
2235 | 2293 | ||
2236 | rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, | 2294 | ata_port_for_each_link(link, ap) { |
2237 | softreset, hardreset, postreset); | 2295 | struct ata_eh_context *ehc = &link->eh_context; |
2238 | if (rc) { | 2296 | |
2239 | ata_link_printk(link, KERN_ERR, | 2297 | if (!(ehc->i.action & ATA_EH_RESET_MASK)) |
2240 | "reset failed, giving up\n"); | 2298 | continue; |
2241 | goto out; | 2299 | |
2300 | rc = ata_eh_reset(link, ata_link_nr_vacant(link), | ||
2301 | prereset, softreset, hardreset, | ||
2302 | postreset); | ||
2303 | if (rc) { | ||
2304 | ata_link_printk(link, KERN_ERR, | ||
2305 | "reset failed, giving up\n"); | ||
2306 | goto out; | ||
2307 | } | ||
2242 | } | 2308 | } |
2243 | 2309 | ||
2244 | ata_eh_thaw_port(ap); | 2310 | ata_eh_thaw_port(ap); |
2245 | } | 2311 | } |
2246 | 2312 | ||
2247 | /* revalidate existing devices and attach new ones */ | 2313 | /* the rest */ |
2248 | rc = ata_eh_revalidate_and_attach(link, &dev); | 2314 | ata_port_for_each_link(link, ap) { |
2249 | if (rc) | 2315 | struct ata_eh_context *ehc = &link->eh_context; |
2250 | goto dev_fail; | ||
2251 | 2316 | ||
2252 | /* configure transfer mode if necessary */ | 2317 | /* revalidate existing devices and attach new ones */ |
2253 | if (ehc->i.flags & ATA_EHI_SETMODE) { | 2318 | rc = ata_eh_revalidate_and_attach(link, &dev); |
2254 | rc = ata_set_mode(link, &dev); | ||
2255 | if (rc) | 2319 | if (rc) |
2256 | goto dev_fail; | 2320 | goto dev_fail; |
2257 | ehc->i.flags &= ~ATA_EHI_SETMODE; | ||
2258 | } | ||
2259 | 2321 | ||
2260 | goto out; | 2322 | /* configure transfer mode if necessary */ |
2323 | if (ehc->i.flags & ATA_EHI_SETMODE) { | ||
2324 | rc = ata_set_mode(link, &dev); | ||
2325 | if (rc) | ||
2326 | goto dev_fail; | ||
2327 | ehc->i.flags &= ~ATA_EHI_SETMODE; | ||
2328 | } | ||
2329 | |||
2330 | /* this link is okay now */ | ||
2331 | ehc->i.flags = 0; | ||
2332 | continue; | ||
2261 | 2333 | ||
2262 | dev_fail: | 2334 | dev_fail: |
2263 | ata_eh_handle_dev_fail(dev, rc); | 2335 | nr_failed_devs++; |
2336 | if (ata_eh_handle_dev_fail(dev, rc)) | ||
2337 | nr_disabled_devs++; | ||
2264 | 2338 | ||
2265 | if (ata_link_nr_enabled(link)) { | 2339 | if (ap->pflags & ATA_PFLAG_FROZEN) |
2266 | ata_link_printk(link, KERN_WARNING, "failed to recover some " | 2340 | break; |
2267 | "devices, retrying in 5 secs\n"); | ||
2268 | ssleep(5); | ||
2269 | } else { | ||
2270 | /* no device left, repeat fast */ | ||
2271 | msleep(500); | ||
2272 | } | 2341 | } |
2273 | 2342 | ||
2274 | goto retry; | 2343 | if (nr_failed_devs) { |
2344 | if (nr_failed_devs != nr_disabled_devs) { | ||
2345 | ata_port_printk(ap, KERN_WARNING, "failed to recover " | ||
2346 | "some devices, retrying in 5 secs\n"); | ||
2347 | ssleep(5); | ||
2348 | } else { | ||
2349 | /* no device left to recover, repeat fast */ | ||
2350 | msleep(500); | ||
2351 | } | ||
2275 | 2352 | ||
2276 | out: | 2353 | goto retry; |
2277 | if (rc) { | ||
2278 | ata_link_for_each_dev(dev, link); | ||
2279 | ata_dev_disable(dev); | ||
2280 | } | 2354 | } |
2281 | 2355 | ||
2356 | out: | ||
2357 | if (rc && r_failed_link) | ||
2358 | *r_failed_link = link; | ||
2359 | |||
2282 | DPRINTK("EXIT, rc=%d\n", rc); | 2360 | DPRINTK("EXIT, rc=%d\n", rc); |
2283 | return rc; | 2361 | return rc; |
2284 | } | 2362 | } |
@@ -2342,9 +2420,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2342 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, | 2420 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, |
2343 | ata_postreset_fn_t postreset) | 2421 | ata_postreset_fn_t postreset) |
2344 | { | 2422 | { |
2345 | ata_eh_autopsy(&ap->link); | 2423 | struct ata_device *dev; |
2346 | ata_eh_report(&ap->link); | 2424 | int rc; |
2347 | ata_eh_recover(ap, prereset, softreset, hardreset, postreset); | 2425 | |
2426 | ata_eh_autopsy(ap); | ||
2427 | ata_eh_report(ap); | ||
2428 | |||
2429 | rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset, | ||
2430 | NULL); | ||
2431 | if (rc) { | ||
2432 | ata_link_for_each_dev(dev, &ap->link) | ||
2433 | ata_dev_disable(dev); | ||
2434 | } | ||
2435 | |||
2348 | ata_eh_finish(ap); | 2436 | ata_eh_finish(ap); |
2349 | } | 2437 | } |
2350 | 2438 | ||