isci: Errors in the submit path for SATA devices manage the ap lock.
authorDan Williams <dan.j.williams@intel.com>
Thu, 10 Mar 2011 05:27:46 +0000 (21:27 -0800)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 10:55:30 +0000 (03:55 -0700)
Since libsas takes the domain device sata_dev.ap->lock before submitting
a task, error completions in the submit path for SATA devices must
unlock/relock when completing the sas_task back to libsas.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/scsi/isci/task.c
drivers/scsi/isci/task.h

index a1234e42937e210f30e073e5be64392ca74a185f..d00b4c97b85b14a824930949c2a6ef1e72c17199 100644 (file)
@@ -54,6 +54,8 @@
  */
 
 #include <linux/completion.h>
+#include <linux/irqflags.h>
+#include <scsi/sas_ata.h>
 #include "scic_task_request.h"
 #include "scic_remote_device.h"
 #include "scic_io_request.h"
 #include "sata.h"
 #include "task.h"
 
+/**
+* isci_task_complete_for_upper_layer() - This function completes the request
+*    to the upper layer driver in the case where an I/O needs to be completed
+*    back in the submit path.
+* @host: This parameter is a pointer to the host on which the the request
+*    should be queued (either as an error or success).
+* @task: This parameter is the completed request.
+* @response: This parameter is the response code for the completed task.
+* @status: This parameter is the status code for the completed task.
+*
+* none.
+*/
+static void isci_task_complete_for_upper_layer(struct sas_task *task,
+                                              enum service_response response,
+                                              enum exec_status status,
+                                              enum isci_completion_selection task_notification_selection)
+{
+       unsigned long    flags = 0;
+       struct Scsi_Host *host = NULL;
+
+       task_notification_selection
+               = isci_task_set_completion_status(task, response, status,
+                                                 task_notification_selection);
+
+       /* Tasks aborted specifically by a call to the lldd_abort_task
+       * function should not be completed to the host in the regular path.
+       */
+       switch (task_notification_selection) {
+               case isci_perform_normal_io_completion:
+                       /* Normal notification (task_done) */
+                       dev_dbg(task->dev->port->ha->dev,
+                               "%s: Normal - task = %p, response=%d, status=%d\n",
+                               __func__, task, response, status);
+
+                       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 call back and report the I/O
+                               * submission error.
+                               */
+                               if (task->dev
+                                   && task->dev->port
+                                   && task->dev->port->ha) {
+
+                                       host = task->dev->port->ha->core.shost;
+                                       raw_local_irq_save(flags);
+                                       spin_unlock(host->host_lock);
+                               }
+                               task->task_done(task);
+                               if (host) {
+                                       spin_lock(host->host_lock);
+                                       raw_local_irq_restore(flags);
+                               }
+                       } else
+                               task->task_done(task);
+
+                       task->lldd_task = NULL;
+                       break;
+
+               case isci_perform_aborted_io_completion:
+                       /* No notification because this request is already in the
+                       * abort path.
+                       */
+                       dev_warn(task->dev->port->ha->dev,
+                                "%s: Aborted - task = %p, response=%d, status=%d\n",
+                                __func__, task, response, status);
+                       break;
+
+               case isci_perform_error_io_completion:
+                       /* Use sas_task_abort */
+                       dev_warn(task->dev->port->ha->dev,
+                                "%s: Error - task = %p, response=%d, status=%d\n",
+                                __func__, task, response, status);
+                       sas_task_abort(task);
+                       break;
+
+               default:
+                       dev_warn(task->dev->port->ha->dev,
+                                "%s: isci task notification default case!",
+                                __func__);
+                       sas_task_abort(task);
+                       break;
+       }
+}
 
 /**
  * isci_task_execute_task() - This function is one of the SAS Domain Template
index 4c2a27eede4975b8a02bd1f57185122218f341f7..e1c9c8f04050d9fcecdeb4bcae77668058fbc54a 100644 (file)
@@ -341,64 +341,5 @@ isci_task_set_completion_status(
        return task_notification_selection;
 
 }
-/**
- * isci_task_complete_for_upper_layer() - This function completes the request
- *    to the upper layer driver.
- * @host: This parameter is a pointer to the host on which the the request
- *    should be queued (either as an error or success).
- * @request: This parameter is the completed request.
- * @response: This parameter is the response code for the completed task.
- * @status: This parameter is the status code for the completed task.
- *
- * none.
- */
-static inline void isci_task_complete_for_upper_layer(
-       struct sas_task *task,
-       enum service_response response,
-       enum exec_status status,
-       enum isci_completion_selection task_notification_selection)
-{
-       task_notification_selection
-               = isci_task_set_completion_status(task, response, status,
-                                                 task_notification_selection);
-
-       /* Tasks aborted specifically by a call to the lldd_abort_task
-        * function should not be completed to the host in the regular path.
-        */
-       switch (task_notification_selection) {
-       case isci_perform_normal_io_completion:
-               /* Normal notification (task_done) */
-               dev_dbg(task->dev->port->ha->dev,
-                       "%s: Normal - task = %p, response=%d, status=%d\n",
-                       __func__, task, response, status);
-               task->task_done(task);
-               task->lldd_task = NULL;
-               break;
-
-       case isci_perform_aborted_io_completion:
-               /* No notification because this request is already in the
-                * abort path.
-                */
-               dev_warn(task->dev->port->ha->dev,
-                        "%s: Aborted - task = %p, response=%d, status=%d\n",
-                        __func__, task, response, status);
-               break;
-
-       case isci_perform_error_io_completion:
-               /* Use sas_task_abort */
-               dev_warn(task->dev->port->ha->dev,
-                        "%s: Error - task = %p, response=%d, status=%d\n",
-                        __func__, task, response, status);
-               sas_task_abort(task);
-               break;
-
-       default:
-               dev_warn(task->dev->port->ha->dev,
-                        "%s: isci task notification default case!",
-                        __func__);
-               sas_task_abort(task);
-               break;
-       }
-}
 
 #endif /* !defined(_SCI_TASK_H_) */