aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2008-05-18 12:15:08 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-05-19 17:51:47 -0400
commitf046519fc85a8fdf6a058b4ac9d897cdee6f3e52 (patch)
treef4ee1fc8edaeaa2fb0245b82925ef40243a9f26f /drivers/ata/libata-core.c
parentdc98c32cbe80750ae2d9d9fbdae305d38f005de7 (diff)
libata: kill hotplug related race condition
Originally, whole reset processing was done while the port is frozen and SError was cleared during @postreset(). This had two race conditions. 1: hotplug could occur after reset but before SError is cleared and libata won't know about it. 2: hotplug could occur after all the reset is complete but before the port is thawed. As all events are cleared on thaw, the hotplug event would be lost. Commit ac371987a81c61c2efbd6931245cdcaf43baad89 kills the first race by clearing SError during link resume but before link onlineness test. However, this doesn't fix race #2 and in some cases clearing SError after SRST is a good idea. This patch solves this problem by cross checking link onlineness with classification result after SError is cleared and port is thawed. Reset is retried if link is online but all devices attached to the link are unknown. As all devices will be revalidated, this one-way check is enough to ensure that all devices are detected and revalidated reliably. This, luckily, also fixes the cases where host controller returns bogus status while harddrive is spinning up after hotplug making classification run before the device sends the first FIS and thus causes misdetection. Low level drivers can bypass the logic by setting class explicitly to ATA_DEV_NONE if ever necessary (currently none requires this). Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c21
1 files changed, 8 insertions, 13 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 */
3705void ata_std_postreset(struct ata_link *link, unsigned int *classes) 3694void 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