summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libata-core.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index bb604dfbdef..665ae79e1fd 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1046,6 +1046,30 @@ static unsigned int ata_pio_modes(const struct ata_device *adev)
return modes;
}
+static int ata_qc_wait_err(struct ata_queued_cmd *qc,
+ struct completion *wait)
+{
+ int rc = 0;
+
+ if (wait_for_completion_timeout(wait, 30 * HZ) < 1) {
+ /* timeout handling */
+ unsigned int err_mask = ac_err_mask(ata_chk_status(qc->ap));
+
+ if (!err_mask) {
+ printk(KERN_WARNING "ata%u: slow completion (cmd %x)\n",
+ qc->ap->id, qc->tf.command);
+ } else {
+ printk(KERN_WARNING "ata%u: qc timeout (cmd %x)\n",
+ qc->ap->id, qc->tf.command);
+ rc = -EIO;
+ }
+
+ ata_qc_complete(qc, err_mask);
+ }
+
+ return rc;
+}
+
/**
* ata_dev_identify - obtain IDENTIFY x DEVICE page
* @ap: port on which device we wish to probe resides
@@ -1125,7 +1149,7 @@ retry:
if (rc)
goto err_out;
else
- wait_for_completion(&wait);
+ ata_qc_wait_err(qc, &wait);
spin_lock_irqsave(&ap->host_set->lock, flags);
ap->ops->tf_read(ap, &qc->tf);
@@ -2269,7 +2293,7 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
if (rc)
ata_port_disable(ap);
else
- wait_for_completion(&wait);
+ ata_qc_wait_err(qc, &wait);
DPRINTK("EXIT\n");
}
@@ -2317,7 +2341,7 @@ static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev)
if (rc)
goto err_out;
- wait_for_completion(&wait);
+ ata_qc_wait_err(qc, &wait);
swap_buf_le16(dev->id, ATA_ID_WORDS);
@@ -2373,7 +2397,7 @@ static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
if (rc)
ata_port_disable(ap);
else
- wait_for_completion(&wait);
+ ata_qc_wait_err(qc, &wait);
DPRINTK("EXIT\n");
}