From: Darrick J. Wong Date: Mon, 30 Oct 2006 23:18:50 +0000 (-0800) Subject: [SCSI] libsas: add sas_abort_task X-Git-Tag: v2.6.20-rc1~34^2~20^2~41^2~69 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79a5eb609b74e7b3638861c41b98eafa74920a1f;p=linux-2.6 [SCSI] libsas: add sas_abort_task This patch adds an external function, sas_abort_task, to enable LLDDs to abort sas_tasks. It also adds a work_struct so that the actual work of aborting a task can be shifted from tasklet context (in the LLDD) onto the scsi_host's workqueue. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley --- diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 6a97b07849..c5fd375227 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -33,6 +33,7 @@ #include #include #include "../scsi_sas_internal.h" +#include "../scsi_transport_api.h" #include #include @@ -798,6 +799,64 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) spin_unlock_irqrestore(&core->task_queue_lock, flags); } +static int do_sas_task_abort(struct sas_task *task) +{ + struct scsi_cmnd *sc = task->uldd_task; + struct sas_internal *si = + to_sas_internal(task->dev->port->ha->core.shost->transportt); + unsigned long flags; + int res; + + spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, + task); + return 0; + } + + task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED; + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + if (!si->dft->lldd_abort_task) + return -ENODEV; + + res = si->dft->lldd_abort_task(task); + if ((task->task_state_flags & SAS_TASK_STATE_DONE) || + (res == TMF_RESP_FUNC_COMPLETE)) + { + /* SMP commands don't have scsi_cmds(?) */ + if (!sc) { + task->task_done(task); + return 0; + } + scsi_req_abort_cmd(sc); + scsi_schedule_eh(sc->device->host); + return 0; + } + + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED; + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + return -EAGAIN; +} + +void sas_task_abort(struct sas_task *task) +{ + int i; + + for (i = 0; i < 5; i++) + if (!do_sas_task_abort(task)) + return; + + SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); +} + EXPORT_SYMBOL_GPL(sas_queuecommand); EXPORT_SYMBOL_GPL(sas_target_alloc); EXPORT_SYMBOL_GPL(sas_slave_configure); @@ -805,3 +864,4 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); EXPORT_SYMBOL_GPL(sas_change_queue_depth); EXPORT_SYMBOL_GPL(sas_change_queue_type); EXPORT_SYMBOL_GPL(sas_bios_param); +EXPORT_SYMBOL_GPL(sas_task_abort); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 7bf2e8b990..a1fc20a47c 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -528,6 +528,8 @@ struct sas_task { void *lldd_task; /* for use by LLDDs */ void *uldd_task; + + struct work_struct abort_work; }; @@ -627,4 +629,6 @@ void sas_unregister_dev(struct domain_device *); void sas_init_dev(struct domain_device *); +void sas_task_abort(struct sas_task *task); + #endif /* _SASLIB_H_ */