diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7c128c89b454..08e11bc312c2 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); @@ -1086,14 +1088,11 @@ static void __ata_port_freeze(struct ata_port *ap) */ int ata_port_freeze(struct ata_port *ap) { - int nr_aborted; - WARN_ON(!ap->ops->error_handler); __ata_port_freeze(ap); - nr_aborted = ata_port_abort(ap); - return nr_aborted; + return ata_port_abort(ap); } EXPORT_SYMBOL_GPL(ata_port_freeze); @@ -1393,7 +1392,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) /** * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT * @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to - * @cmd: scsi command for which the sense code should be set * * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK * SENSE. This function is an EH helper. @@ -1401,9 +1399,9 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_request_sense(struct ata_queued_cmd *qc, - struct scsi_cmnd *cmd) +static void ata_eh_request_sense(struct ata_queued_cmd *qc) { + struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; struct ata_taskfile tf; unsigned int err_mask; @@ -1541,7 +1539,6 @@ static void ata_eh_analyze_serror(struct ata_link *link) /** * ata_eh_analyze_tf - analyze taskfile of a failed qc * @qc: qc to analyze - * @tf: Taskfile registers to analyze * * Analyze taskfile of @qc and further determine cause of * failure. This function also requests ATAPI sense data if @@ -1553,9 +1550,9 @@ static void ata_eh_analyze_serror(struct ata_link *link) * RETURNS: * Determined recovery action */ -static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, - const struct ata_taskfile *tf) +static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc) { + const struct ata_taskfile *tf = &qc->result_tf; unsigned int tmp, action = 0; u8 stat = tf->status, err = tf->error; @@ -1579,7 +1576,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, switch (qc->dev->class) { case ATA_DEV_ZAC: if (stat & ATA_SENSE) - ata_eh_request_sense(qc, qc->scsicmd); + ata_eh_request_sense(qc); fallthrough; case ATA_DEV_ATA: if (err & ATA_ICRC) @@ -1957,7 +1954,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) qc->err_mask |= ehc->i.err_mask; /* analyze TF */ - ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf); + ehc->i.action |= ata_eh_analyze_tf(qc); /* DEV errors are probably spurious in case of ATA_BUS error */ if (qc->err_mask & AC_ERR_ATA_BUS) @@ -2940,6 +2937,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; |