Skip to content

Commit

Permalink
[PATCH] libata-eh-fw: update ata_exec_internal() for new EH
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tejun Heo committed May 15, 2006
1 parent ad9e276 commit d95a717
Showing 1 changed file with 23 additions and 7 deletions.
30 changes: 23 additions & 7 deletions drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down

0 comments on commit d95a717

Please sign in to comment.