diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-02-24 06:44:19 +0100 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-02-24 07:40:57 +0100 |
commit | e2396f1e4ecd438a15fa653a028b93e95013caa3 (patch) | |
tree | 8cc11b28b64fbf3a7a22d1636467d35174092e27 /drivers/scsi/aic94xx/aic94xx_task.c | |
parent | [SCSI] libsas: misc fixes to the eh path (diff) | |
download | linux-e2396f1e4ecd438a15fa653a028b93e95013caa3.tar.xz linux-e2396f1e4ecd438a15fa653a028b93e95013caa3.zip |
[SCSI] aic94xx: fix TMF ascb handling to prevent sequencer panic
This is a particularly nasty bug. The problem is that if any internal
ascb times out, currently we free it even though it's pending at the
sequencer. This results in the sequencer getting terminally confused
and the error message:
BUG:sequencer:dl:no ascb
Being returned when it comes back. The way to fix this is to manage
freeing the ascb from the tasklet completion routine, so that we only
free it when the sequencer actually returns it. The code is also
altered to use on stack completions and transfer variables.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/aic94xx/aic94xx_task.c')
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_task.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 965d4bb999d9..008df9ab92a5 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -343,11 +343,13 @@ Again: task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; task->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { + struct completion *completion = ascb->completion; spin_unlock_irqrestore(&task->task_state_lock, flags); ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " "stat 0x%x but aborted by upper layer!\n", task, opcode, ts->resp, ts->stat); - complete(&ascb->completion); + if (completion) + complete(completion); } else { spin_unlock_irqrestore(&task->task_state_lock, flags); task->lldd_task = NULL; |