diff options
author | Tejun Heo <htejun@gmail.com> | 2008-04-07 09:47:19 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-04-17 15:44:23 -0400 |
commit | ac371987a81c61c2efbd6931245cdcaf43baad89 (patch) | |
tree | f88970931b26d2ad344d7d67ddabc64d9b48181d /drivers/ata/libata-core.c | |
parent | 57c9efdfb3cee5d4564fcb5f70555e2edb1bc52a (diff) |
libata: clear SError after link resume
SError used to be cleared in ->postreset. This has small hotplug race
condition. If a device is plugged in after reset is complete but
postreset hasn't run yet, its hotplug event gets lost when SError is
cleared. This patch makes sata_link_resume() clear SError. This
kills the race condition and makes a lot of sense as some PMP and host
PHYs don't work properly without SError cleared.
This change makes sata_pmp_std_{pre|post}_reset()'s unnecessary as
they become identical to ata_std counterparts. It also simplifies
sata_pmp_hardreset() and ahci_vt8251_hardreset().
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c4fd4afbf349..e00b620f161a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -90,9 +90,9 @@ const struct ata_port_operations sata_port_ops = { | |||
90 | const struct ata_port_operations sata_pmp_port_ops = { | 90 | const struct ata_port_operations sata_pmp_port_ops = { |
91 | .inherits = &sata_port_ops, | 91 | .inherits = &sata_port_ops, |
92 | 92 | ||
93 | .pmp_prereset = sata_pmp_std_prereset, | 93 | .pmp_prereset = ata_std_prereset, |
94 | .pmp_hardreset = sata_pmp_std_hardreset, | 94 | .pmp_hardreset = sata_pmp_std_hardreset, |
95 | .pmp_postreset = sata_pmp_std_postreset, | 95 | .pmp_postreset = ata_std_postreset, |
96 | .error_handler = sata_pmp_error_handler, | 96 | .error_handler = sata_pmp_error_handler, |
97 | }; | 97 | }; |
98 | 98 | ||
@@ -3493,7 +3493,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, | |||
3493 | int sata_link_resume(struct ata_link *link, const unsigned long *params, | 3493 | int sata_link_resume(struct ata_link *link, const unsigned long *params, |
3494 | unsigned long deadline) | 3494 | unsigned long deadline) |
3495 | { | 3495 | { |
3496 | u32 scontrol; | 3496 | u32 scontrol, serror; |
3497 | int rc; | 3497 | int rc; |
3498 | 3498 | ||
3499 | if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) | 3499 | if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) |
@@ -3509,7 +3509,25 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, | |||
3509 | */ | 3509 | */ |
3510 | msleep(200); | 3510 | msleep(200); |
3511 | 3511 | ||
3512 | return sata_link_debounce(link, params, deadline); | 3512 | if ((rc = sata_link_debounce(link, params, deadline))) |
3513 | return rc; | ||
3514 | |||
3515 | /* Clear SError. PMP and some host PHYs require this to | ||
3516 | * operate and clearing should be done before checking PHY | ||
3517 | * online status to avoid race condition (hotplugging between | ||
3518 | * link resume and status check). | ||
3519 | */ | ||
3520 | if (!(rc = sata_scr_read(link, SCR_ERROR, &serror))) | ||
3521 | rc = sata_scr_write(link, SCR_ERROR, serror); | ||
3522 | if (rc == 0 || rc == -EINVAL) { | ||
3523 | unsigned long flags; | ||
3524 | |||
3525 | spin_lock_irqsave(link->ap->lock, flags); | ||
3526 | link->eh_info.serror = 0; | ||
3527 | spin_unlock_irqrestore(link->ap->lock, flags); | ||
3528 | rc = 0; | ||
3529 | } | ||
3530 | return rc; | ||
3513 | } | 3531 | } |
3514 | 3532 | ||
3515 | /** | 3533 | /** |
@@ -3701,18 +3719,11 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, | |||
3701 | */ | 3719 | */ |
3702 | void ata_std_postreset(struct ata_link *link, unsigned int *classes) | 3720 | void ata_std_postreset(struct ata_link *link, unsigned int *classes) |
3703 | { | 3721 | { |
3704 | u32 serror; | ||
3705 | |||
3706 | DPRINTK("ENTER\n"); | 3722 | DPRINTK("ENTER\n"); |
3707 | 3723 | ||
3708 | /* print link status */ | 3724 | /* print link status */ |
3709 | sata_print_link_status(link); | 3725 | sata_print_link_status(link); |
3710 | 3726 | ||
3711 | /* clear SError */ | ||
3712 | if (sata_scr_read(link, SCR_ERROR, &serror) == 0) | ||
3713 | sata_scr_write(link, SCR_ERROR, serror); | ||
3714 | link->eh_info.serror = 0; | ||
3715 | |||
3716 | DPRINTK("EXIT\n"); | 3727 | DPRINTK("EXIT\n"); |
3717 | } | 3728 | } |
3718 | 3729 | ||
@@ -6296,9 +6307,7 @@ EXPORT_SYMBOL_GPL(ata_pci_device_resume); | |||
6296 | #endif /* CONFIG_PCI */ | 6307 | #endif /* CONFIG_PCI */ |
6297 | 6308 | ||
6298 | EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); | 6309 | EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); |
6299 | EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); | ||
6300 | EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); | 6310 | EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); |
6301 | EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); | ||
6302 | EXPORT_SYMBOL_GPL(sata_pmp_error_handler); | 6311 | EXPORT_SYMBOL_GPL(sata_pmp_error_handler); |
6303 | 6312 | ||
6304 | EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); | 6313 | EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); |