+/*
+ * Call the LLDD task abort routine directly. This function is intended for
+ * use by upper layers that need to tell the LLDD to abort a task.
+ */
+int __sas_task_abort(struct sas_task *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 ||
+ task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
+ task);
+ return 0;
+ }
+ 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);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
+ (res == TMF_RESP_FUNC_COMPLETE))
+ {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ task->task_done(task);
+ return 0;
+ }
+
+ 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;
+}
+
+/*
+ * Tell an upper layer that it needs to initiate an abort for a given task.
+ * This should only ever be called by an LLDD.
+ */
+void sas_task_abort(struct sas_task *task)
+{
+ struct scsi_cmnd *sc = task->uldd_task;
+
+ /* Escape for libsas internal commands */
+ if (!sc) {
+ if (!del_timer(&task->timer))
+ return;
+ task->timer.function(task->timer.data);
+ return;
+ }
+
+ scsi_req_abort_cmd(sc);
+ scsi_schedule_eh(sc->device->host);
+}
+