summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo2006-05-15 13:58:14 +0200
committerTejun Heo2006-05-15 13:58:14 +0200
commitd95a717f579e81061830a308125c89f5858f740a (patch)
treeefa4b35ffcd1f8f3eabe5cb27ffc128313378064 /drivers/scsi/libata-core.c
parent[PATCH] libata-eh-fw: update ata_scsi_error() for new EH (diff)
downloadkernel-qcow2-linux-d95a717f579e81061830a308125c89f5858f740a.tar.gz
kernel-qcow2-linux-d95a717f579e81061830a308125c89f5858f740a.tar.xz
kernel-qcow2-linux-d95a717f579e81061830a308125c89f5858f740a.zip
[PATCH] libata-eh-fw: update ata_exec_internal() for new EH
Update ata_exec_internal() such that it uses new EH framework. ->post_internal_cmd() is always invoked regardless of completion status. Also, when ata_exec_internal() detects a timeout condition and new EH is in place, it freezes the port as timeout for normal commands would do. Note that ata_port_flush_task() is called regardless of wait_for_completion status. This is necessary as exceptions unrelated to the qc can abort the qc, in which case PIO task could still be running after the wait for completion returns. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r--drivers/scsi/libata-core.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 35ae5b41f662..4def48ed6f46 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -984,6 +984,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
DECLARE_COMPLETION(wait);
unsigned long flags;
unsigned int err_mask;
+ int rc;
spin_lock_irqsave(&ap->host_set->lock, flags);
@@ -1036,20 +1037,25 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_unlock_irqrestore(&ap->host_set->lock, flags);
- if (!wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL)) {
- ata_port_flush_task(ap);
+ rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
+
+ ata_port_flush_task(ap);
+ if (!rc) {
spin_lock_irqsave(&ap->host_set->lock, flags);
/* We're racing with irq here. If we lose, the
* following test prevents us from completing the qc
- * again. If completion irq occurs after here but
- * before the caller cleans up, it will result in a
- * spurious interrupt. We can live with that.
+ * twice. If we win, the port is frozen and will be
+ * cleaned up by ->post_internal_cmd().
*/
if (qc->flags & ATA_QCFLAG_ACTIVE) {
- qc->err_mask = AC_ERR_TIMEOUT;
- ata_qc_complete(qc);
+ qc->err_mask |= AC_ERR_TIMEOUT;
+
+ if (ap->ops->error_handler)
+ ata_port_freeze(ap);
+ else
+ ata_qc_complete(qc);
ata_dev_printk(dev, KERN_WARNING,
"qc timeout (cmd 0x%x)\n", command);
@@ -1058,6 +1064,16 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_unlock_irqrestore(&ap->host_set->lock, flags);
}
+ /* do post_internal_cmd */
+ if (ap->ops->post_internal_cmd)
+ ap->ops->post_internal_cmd(qc);
+
+ if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "zero err_mask for failed "
+ "internal command, assuming AC_ERR_OTHER\n");
+ qc->err_mask |= AC_ERR_OTHER;
+ }
+
/* finish up */
spin_lock_irqsave(&ap->host_set->lock, flags);