isci: Free host lock for SATA/STP abort escalation at submission time.
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>
Thu, 31 Mar 2011 20:10:36 +0000 (13:10 -0700)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 11:00:36 +0000 (04:00 -0700)
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>
drivers/scsi/isci/request.c

index c6ce9d0c50c2407a4776c29a0ae0316882fa544f..946caaeb66c6a18f3d13faddc21252a49cca42ce 100644 (file)
@@ -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"
@@ -355,33 +356,6 @@ int isci_request_alloc_tmf(
        return retval;
 }
 
-/**
- * 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.
@@ -453,11 +427,18 @@ int isci_request_execute(
                                /* 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 @@ int isci_request_execute(
                        * 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