Skip to content

Commit

Permalink
[SCSI] aic94xx: asd_clear_nexus should fail if the cleared task does …
Browse files Browse the repository at this point in the history
…not complete

Every so often, the driver will call asd_clear_nexus to clean out a task.
It is supposed to be the case that the CLEAR NEXUS does not go on the done
list until after the task itself has been put on the done list, but for
some reason this doesn't always happen.  Thus, the
wait_for_completion_timeout call times out, and we return success.  This
makes libsas free the task even though the task hasn't completed, leading
to a BUG_ON message from aic94xx_hwi.c around line 341.  We should return
failure from asd_clear_nexus so that libsas tries again; at a bare minimum
it shouldn't be freeing active tasks.  I _think_ this will fix one of
the SCB timeout crash problems (though I've not been able to reproduce
it lately...)

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
Darrick J. Wong authored and James Bottomley committed May 22, 2007
1 parent f45ffae commit 8fdcf86
Showing 1 changed file with 10 additions and 4 deletions.
14 changes: 10 additions & 4 deletions drivers/scsi/aic94xx/aic94xx_tmf.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
static inline int asd_clear_nexus(struct sas_task *task)
{
int res = TMF_RESP_FUNC_FAILED;
int leftover;
struct asd_ascb *tascb = task->lldd_task;
unsigned long flags;

Expand All @@ -298,10 +299,12 @@ static inline int asd_clear_nexus(struct sas_task *task)
res = asd_clear_nexus_tag(task);
else
res = asd_clear_nexus_index(task);
wait_for_completion_timeout(&tascb->completion,
AIC94XX_SCB_TIMEOUT);
leftover = wait_for_completion_timeout(&tascb->completion,
AIC94XX_SCB_TIMEOUT);
ASD_DPRINTK("came back from clear nexus\n");
spin_lock_irqsave(&task->task_state_lock, flags);
if (leftover < 1)
res = TMF_RESP_FUNC_FAILED;
if (task->task_state_flags & SAS_TASK_STATE_DONE)
res = TMF_RESP_FUNC_COMPLETE;
spin_unlock_irqrestore(&task->task_state_lock, flags);
Expand Down Expand Up @@ -350,6 +353,7 @@ int asd_abort_task(struct sas_task *task)
unsigned long flags;
struct asd_ascb *ascb = NULL;
struct scb *scb;
int leftover;

spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
Expand Down Expand Up @@ -455,9 +459,11 @@ int asd_abort_task(struct sas_task *task)
break;
case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */
res = TMF_RESP_FUNC_FAILED;
wait_for_completion_timeout(&tascb->completion,
AIC94XX_SCB_TIMEOUT);
leftover = wait_for_completion_timeout(&tascb->completion,
AIC94XX_SCB_TIMEOUT);
spin_lock_irqsave(&task->task_state_lock, flags);
if (leftover < 1)
res = TMF_RESP_FUNC_FAILED;
if (task->task_state_flags & SAS_TASK_STATE_DONE)
res = TMF_RESP_FUNC_COMPLETE;
spin_unlock_irqrestore(&task->task_state_lock, flags);
Expand Down

0 comments on commit 8fdcf86

Please sign in to comment.