diff options
-rw-r--r-- | drivers/ata/libata-core.c | 21 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 52 |
2 files changed, 50 insertions, 23 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c6c316fc8379..ffc689d9e972 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -3490,22 +3490,11 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, | |||
3490 | if ((rc = sata_link_debounce(link, params, deadline))) | 3490 | if ((rc = sata_link_debounce(link, params, deadline))) |
3491 | return rc; | 3491 | return rc; |
3492 | 3492 | ||
3493 | /* Clear SError. PMP and some host PHYs require this to | 3493 | /* clear SError, some PHYs require this even for SRST to work */ |
3494 | * operate and clearing should be done before checking PHY | ||
3495 | * online status to avoid race condition (hotplugging between | ||
3496 | * link resume and status check). | ||
3497 | */ | ||
3498 | if (!(rc = sata_scr_read(link, SCR_ERROR, &serror))) | 3494 | if (!(rc = sata_scr_read(link, SCR_ERROR, &serror))) |
3499 | rc = sata_scr_write(link, SCR_ERROR, serror); | 3495 | rc = sata_scr_write(link, SCR_ERROR, serror); |
3500 | if (rc == 0 || rc == -EINVAL) { | ||
3501 | unsigned long flags; | ||
3502 | 3496 | ||
3503 | spin_lock_irqsave(link->ap->lock, flags); | 3497 | return rc != -EINVAL ? rc : 0; |
3504 | link->eh_info.serror = 0; | ||
3505 | spin_unlock_irqrestore(link->ap->lock, flags); | ||
3506 | rc = 0; | ||
3507 | } | ||
3508 | return rc; | ||
3509 | } | 3498 | } |
3510 | 3499 | ||
3511 | /** | 3500 | /** |
@@ -3704,8 +3693,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, | |||
3704 | */ | 3693 | */ |
3705 | void ata_std_postreset(struct ata_link *link, unsigned int *classes) | 3694 | void ata_std_postreset(struct ata_link *link, unsigned int *classes) |
3706 | { | 3695 | { |
3696 | u32 serror; | ||
3697 | |||
3707 | DPRINTK("ENTER\n"); | 3698 | DPRINTK("ENTER\n"); |
3708 | 3699 | ||
3700 | /* reset complete, clear SError */ | ||
3701 | if (!sata_scr_read(link, SCR_ERROR, &serror)) | ||
3702 | sata_scr_write(link, SCR_ERROR, serror); | ||
3703 | |||
3709 | /* print link status */ | 3704 | /* print link status */ |
3710 | sata_print_link_status(link); | 3705 | sata_print_link_status(link); |
3711 | 3706 | ||
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 | ||
2065 | static int ata_eh_followup_srst_needed(struct ata_link *link, | 2057 | static 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; |