isci: Free host lock for SATA/STP abort escalation at submission time.

In the case of I/O requests that fail at submit time because of a
pending reset condition, the host lock for SATA/STP devices must be
managed for any SCSI-initiated I/O before sas_task_abort is called.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index c6ce9d0c..946caae 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -53,6 +53,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <scsi/sas_ata.h>
 #include "isci.h"
 #include "scic_remote_device.h"
 #include "scic_io_request.h"
@@ -356,33 +357,6 @@
 }
 
 /**
- * isci_request_signal_device_reset() - This function will set the "device
- *    needs target reset" flag in the given sas_tasks' task_state_flags, and
- *    then cause the task to be added into the SCSI error handler queue which
- *    will eventually be escalated to a target reset.
- *
- *
- */
-static void isci_request_signal_device_reset(
-	struct isci_request *isci_request)
-{
-	unsigned long flags;
-	struct sas_task *task = isci_request_access_task(isci_request);
-
-	dev_dbg(&isci_request->isci_host->pdev->dev,
-		"%s: request=%p, task=%p\n", __func__, isci_request, task);
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	/* Cause this task to be scheduled in the SCSI error handler
-	 * thread.
-	 */
-	sas_task_abort(task);
-}
-
-/**
  * isci_request_execute() - This function allocates the isci_request object,
  *    all fills in some common fields.
  * @isci_host: This parameter specifies the ISCI host object
@@ -453,11 +427,18 @@
 				/* Save the tag for possible task mgmt later. */
 				request->io_tag = scic_io_request_get_io_tag(
 						     request->sci_request_handle);
+			} else {
+				/* The request did not really start in the
+				 * hardware, so clear the request handle
+				 * here so no terminations will be done.
+				 */
+				request->sci_request_handle = NULL;
 			}
+
 		} else
 			dev_warn(&isci_host->pdev->dev,
-				 "%s: failed request start\n",
-				 __func__);
+				 "%s: failed request start (0x%x)\n",
+				 __func__, status);
 
 		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
@@ -467,7 +448,26 @@
 			* handler thread to work on this I/O and that
 			* we want a device reset.
 			*/
-			isci_request_signal_device_reset(request);
+			spin_lock_irqsave(&task->task_state_lock, flags);
+			task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+			spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+			/* Cause this task to be scheduled in the SCSI error handler
+			* thread.
+			*/
+			if (dev_is_sata(task->dev)) {
+				/* Since we are still in the submit path, and since
+				* libsas takes the host lock on behalf of SATA
+				* devices before I/O starts, we need to unlock
+				* before we can put the task in the error path.
+				*/
+				raw_local_irq_save(flags);
+				spin_unlock(isci_host->shost->host_lock);
+				sas_task_abort(task);
+				spin_lock(isci_host->shost->host_lock);
+				raw_local_irq_restore(flags);
+			} else
+				sas_task_abort(task);
 
 			/* Change the status, since we are holding
 			* the I/O until it is managed by the SCSI