diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-eh.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 6432e0489dfb..1b82283f4b49 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -151,6 +151,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = { #undef CMDS static void __ata_port_freeze(struct ata_port *ap); +static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, + struct ata_device **r_failed_dev); #ifdef CONFIG_PM static void ata_eh_handle_port_suspend(struct ata_port *ap); static void ata_eh_handle_port_resume(struct ata_port *ap); @@ -2934,6 +2936,23 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { WARN_ON(dev->class == ATA_DEV_PMP); + /* + * The link may be in a deep sleep, wake it up. + * + * If the link is in deep sleep, ata_phys_link_offline() + * will return true, causing the revalidation to fail, + * which leads to a (potentially) needless hard reset. + * + * ata_eh_recover() will later restore the link policy + * to ap->target_lpm_policy after revalidation is done. + */ + if (link->lpm_policy > ATA_LPM_MAX_POWER) { + rc = ata_eh_set_lpm(link, ATA_LPM_MAX_POWER, + r_failed_dev); + if (rc) + goto err; + } + if (ata_phys_link_offline(ata_dev_phys_link(dev))) { rc = -EIO; goto err; |