From b218a0d8e250e0ae8fd4d4e45bd66a588b380752 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 11 Jan 2007 14:14:55 -0800 Subject: [SCSI] libsas: Don't give scsi_cmnds to the EH if they never made it to the SAS LLDD or have already returned On a system with many SAS targets, it appears possible that a scsi_cmnd can time out without ever making it to the SAS LLDD or at the same time that a completion is occurring. In both of these cases, telling the LLDD to abort the sas_task makes no sense because the LLDD won't know about the sas_task; what we really want to do is to increase the timer. Note that this involves creating another sas_task bit to indicate whether or not the task has been sent to the LLDD; I could have implemented this by slightly redefining SAS_TASK_STATE_PENDING, but this way seems cleaner. This second version amends the aic94xx portion to set the TASK_AT_INITIATOR flag for all sas_tasks that were passed to lldd_execute_task. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/aic94xx_task.c | 9 +++++++++ drivers/scsi/libsas/sas_scsi_host.c | 7 +++++++ 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index d202ed5a670..e2ad5bed940 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -349,6 +349,7 @@ Again: spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags &= ~SAS_TASK_STATE_PENDING; + 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))) { spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -557,6 +558,7 @@ int asd_execute_task(struct sas_task *task, const int num, struct sas_task *t = task; struct asd_ascb *ascb = NULL, *a; struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; + unsigned long flags; res = asd_can_queue(asd_ha, num); if (res) @@ -599,6 +601,10 @@ int asd_execute_task(struct sas_task *task, const int num, } if (res) goto out_err_unmap; + + spin_lock_irqsave(&t->task_state_lock, flags); + t->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&t->task_state_lock, flags); } list_del_init(&alist); @@ -617,6 +623,9 @@ out_err_unmap: if (a == b) break; t = a->uldd_task; + spin_lock_irqsave(&t->task_state_lock, flags); + t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&t->task_state_lock, flags); switch (t->task_proto) { case SATA_PROTO: case SAS_PROTO_STP: diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 22672d54aa2..21bd2477598 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -542,6 +542,13 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) cmd, task); return EH_HANDLED; } + if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " + "EH_RESET_TIMER\n", + cmd, task); + return EH_RESET_TIMER; + } task->task_state_flags |= SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); -- cgit v1.2.3