Browse Source

isci: Errors in the submit path for SATA devices manage the ap lock.

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>
Dan Williams 14 years ago
parent
commit
50e7f9b5a9
2 changed files with 87 additions and 59 deletions
  1. 87 0
      drivers/scsi/isci/task.c
  2. 0 59
      drivers/scsi/isci/task.h

+ 87 - 0
drivers/scsi/isci/task.c

@@ -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"
@@ -64,6 +66,91 @@
 #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

+ 0 - 59
drivers/scsi/isci/task.h

@@ -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_) */