summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c38
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;