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.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 06a92c58a49d..751dad0138ae 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2047,19 +2047,11 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
2047 unsigned int *classes, unsigned long deadline) 2047 unsigned int *classes, unsigned long deadline)
2048{ 2048{
2049 struct ata_device *dev; 2049 struct ata_device *dev;
2050 int rc;
2051 2050
2052 ata_link_for_each_dev(dev, link) 2051 ata_link_for_each_dev(dev, link)
2053 classes[dev->devno] = ATA_DEV_UNKNOWN; 2052 classes[dev->devno] = ATA_DEV_UNKNOWN;
2054 2053
2055 rc = reset(link, classes, deadline); 2054 return reset(link, classes, deadline);
2056
2057 /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
2058 ata_link_for_each_dev(dev, link)
2059 if (classes[dev->devno] == ATA_DEV_UNKNOWN)
2060 classes[dev->devno] = ATA_DEV_NONE;
2061
2062 return rc;
2063} 2055}
2064 2056
2065static int ata_eh_followup_srst_needed(struct ata_link *link, 2057static int ata_eh_followup_srst_needed(struct ata_link *link,
@@ -2096,7 +2088,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
2096 ata_reset_fn_t reset; 2088 ata_reset_fn_t reset;
2097 unsigned long flags; 2089 unsigned long flags;
2098 u32 sstatus; 2090 u32 sstatus;
2099 int rc; 2091 int nr_known, rc;
2100 2092
2101 /* 2093 /*
2102 * Prepare to reset 2094 * Prepare to reset
@@ -2245,9 +2237,49 @@ int ata_eh_reset(struct ata_link *link, int classify,
2245 if (ata_is_host_link(link)) 2237 if (ata_is_host_link(link))
2246 ata_eh_thaw_port(ap); 2238 ata_eh_thaw_port(ap);
2247 2239
2240 /* postreset() should clear hardware SError. Although SError
2241 * is cleared during link resume, clearing SError here is
2242 * necessary as some PHYs raise hotplug events after SRST.
2243 * This introduces race condition where hotplug occurs between
2244 * reset and here. This race is mediated by cross checking
2245 * link onlineness and classification result later.
2246 */
2248 if (postreset) 2247 if (postreset)
2249 postreset(link, classes); 2248 postreset(link, classes);
2250 2249
2250 /* clear cached SError */
2251 spin_lock_irqsave(link->ap->lock, flags);
2252 link->eh_info.serror = 0;
2253 spin_unlock_irqrestore(link->ap->lock, flags);
2254
2255 /* Make sure onlineness and classification result correspond.
2256 * Hotplug could have happened during reset and some
2257 * controllers fail to wait while a drive is spinning up after
2258 * being hotplugged causing misdetection. By cross checking
2259 * link onlineness and classification result, those conditions
2260 * can be reliably detected and retried.
2261 */
2262 nr_known = 0;
2263 ata_link_for_each_dev(dev, link) {
2264 /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
2265 if (classes[dev->devno] == ATA_DEV_UNKNOWN)
2266 classes[dev->devno] = ATA_DEV_NONE;
2267 else
2268 nr_known++;
2269 }
2270
2271 if (classify && !nr_known && ata_link_online(link)) {
2272 if (try < max_tries) {
2273 ata_link_printk(link, KERN_WARNING, "link online but "
2274 "device misclassified, retrying\n");
2275 rc = -EAGAIN;
2276 goto fail;
2277 }
2278 ata_link_printk(link, KERN_WARNING,
2279 "link online but device misclassified, "
2280 "device detection might fail\n");
2281 }
2282
2251 /* reset successful, schedule revalidation */ 2283 /* reset successful, schedule revalidation */
2252 ata_eh_done(link, NULL, ATA_EH_RESET); 2284 ata_eh_done(link, NULL, ATA_EH_RESET);
2253 ehc->i.action |= ATA_EH_REVALIDATE; 2285 ehc->i.action |= ATA_EH_REVALIDATE;