[libata] add timeout to commands for which we call wait_completion()
authorJeff Garzik <jgarzik@pobox.com>
Thu, 17 Nov 2005 15:50:01 +0000 (10:50 -0500)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 17 Nov 2005 15:50:01 +0000 (10:50 -0500)
drivers/scsi/libata-core.c

index bb604df..665ae79 100644 (file)
@@ -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");
 }