aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-11 17:15:20 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-13 17:18:06 -0500
commit396819fba821ad56f1b90090d256f0ab726c89c5 (patch)
tree085d65ae13854d42fdf34fdb430aae76e696dbc4 /drivers
parent3ebf6922b0833807e54c73f4794c74baf9945fc8 (diff)
[SCSI] libsas: Delay issuing ABORT TASK TMF until the error handler
sas_task_abort() should simply abort the upper-level SCSI command and wait until the error handler to send the actual ABORT TASK command. By deferring things to the EH we simplify the concurrency coordination and eliminate some race conditions. Note that sas_task_abort has a few hooks to handle libsas internal commands properly too. Also rename do_sas_task_abort to __sas_task_abort just in case we really want to abort the task *right now* and we don't have a scsi_cmnd attached to the command. This is a hook for libata internal commands to abort. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c51
1 files changed, 29 insertions, 22 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index d0c04ebeb8b0..f867455dd339 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -560,6 +560,7 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
560 } 560 }
561 561
562 spin_lock_irqsave(&task->task_state_lock, flags); 562 spin_lock_irqsave(&task->task_state_lock, flags);
563 BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
563 if (task->task_state_flags & SAS_TASK_STATE_DONE) { 564 if (task->task_state_flags & SAS_TASK_STATE_DONE) {
564 spin_unlock_irqrestore(&task->task_state_lock, flags); 565 spin_unlock_irqrestore(&task->task_state_lock, flags);
565 SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", 566 SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
@@ -830,44 +831,42 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
830 spin_unlock_irqrestore(&core->task_queue_lock, flags); 831 spin_unlock_irqrestore(&core->task_queue_lock, flags);
831} 832}
832 833
833static int do_sas_task_abort(struct sas_task *task) 834/*
835 * Call the LLDD task abort routine directly. This function is intended for
836 * use by upper layers that need to tell the LLDD to abort a task.
837 */
838int __sas_task_abort(struct sas_task *task)
834{ 839{
835 struct scsi_cmnd *sc = task->uldd_task;
836 struct sas_internal *si = 840 struct sas_internal *si =
837 to_sas_internal(task->dev->port->ha->core.shost->transportt); 841 to_sas_internal(task->dev->port->ha->core.shost->transportt);
838 unsigned long flags; 842 unsigned long flags;
839 int res; 843 int res;
840 844
841 spin_lock_irqsave(&task->task_state_lock, flags); 845 spin_lock_irqsave(&task->task_state_lock, flags);
842 if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { 846 if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
847 task->task_state_flags & SAS_TASK_STATE_DONE) {
843 spin_unlock_irqrestore(&task->task_state_lock, flags); 848 spin_unlock_irqrestore(&task->task_state_lock, flags);
844 SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, 849 SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
845 task); 850 task);
846 return 0; 851 return 0;
847 } 852 }
848 853 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
849 if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
850 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
851 spin_unlock_irqrestore(&task->task_state_lock, flags); 854 spin_unlock_irqrestore(&task->task_state_lock, flags);
852 855
853 if (!si->dft->lldd_abort_task) 856 if (!si->dft->lldd_abort_task)
854 return -ENODEV; 857 return -ENODEV;
855 858
856 res = si->dft->lldd_abort_task(task); 859 res = si->dft->lldd_abort_task(task);
860
861 spin_lock_irqsave(&task->task_state_lock, flags);
857 if ((task->task_state_flags & SAS_TASK_STATE_DONE) || 862 if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
858 (res == TMF_RESP_FUNC_COMPLETE)) 863 (res == TMF_RESP_FUNC_COMPLETE))
859 { 864 {
860 /* SMP commands don't have scsi_cmds(?) */ 865 spin_unlock_irqrestore(&task->task_state_lock, flags);
861 if (!sc) { 866 task->task_done(task);
862 task->task_done(task);
863 return 0;
864 }
865 scsi_req_abort_cmd(sc);
866 scsi_schedule_eh(sc->device->host);
867 return 0; 867 return 0;
868 } 868 }
869 869
870 spin_lock_irqsave(&task->task_state_lock, flags);
871 if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) 870 if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
872 task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; 871 task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
873 spin_unlock_irqrestore(&task->task_state_lock, flags); 872 spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -875,17 +874,24 @@ static int do_sas_task_abort(struct sas_task *task)
875 return -EAGAIN; 874 return -EAGAIN;
876} 875}
877 876
878void sas_task_abort(struct work_struct *work) 877/*
878 * Tell an upper layer that it needs to initiate an abort for a given task.
879 * This should only ever be called by an LLDD.
880 */
881void sas_task_abort(struct sas_task *task)
879{ 882{
880 struct sas_task *task = 883 struct scsi_cmnd *sc = task->uldd_task;
881 container_of(work, struct sas_task, abort_work);
882 int i;
883 884
884 for (i = 0; i < 5; i++) 885 /* Escape for libsas internal commands */
885 if (!do_sas_task_abort(task)) 886 if (!sc) {
887 if (!del_timer(&task->timer))
886 return; 888 return;
889 task->timer.function(task->timer.data);
890 return;
891 }
887 892
888 SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); 893 scsi_req_abort_cmd(sc);
894 scsi_schedule_eh(sc->device->host);
889} 895}
890 896
891EXPORT_SYMBOL_GPL(sas_queuecommand); 897EXPORT_SYMBOL_GPL(sas_queuecommand);
@@ -895,6 +901,7 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy);
895EXPORT_SYMBOL_GPL(sas_change_queue_depth); 901EXPORT_SYMBOL_GPL(sas_change_queue_depth);
896EXPORT_SYMBOL_GPL(sas_change_queue_type); 902EXPORT_SYMBOL_GPL(sas_change_queue_type);
897EXPORT_SYMBOL_GPL(sas_bios_param); 903EXPORT_SYMBOL_GPL(sas_bios_param);
904EXPORT_SYMBOL_GPL(__sas_task_abort);
898EXPORT_SYMBOL_GPL(sas_task_abort); 905EXPORT_SYMBOL_GPL(sas_task_abort);
899EXPORT_SYMBOL_GPL(sas_phy_reset); 906EXPORT_SYMBOL_GPL(sas_phy_reset);
900EXPORT_SYMBOL_GPL(sas_phy_enable); 907EXPORT_SYMBOL_GPL(sas_phy_enable);