isci: fix incorrect assumptions about task->dev and task->dev->port being NULL
authorDan Williams <dan.j.williams@intel.com>
Fri, 11 Mar 2011 18:13:51 +0000 (10:13 -0800)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 10:55:30 +0000 (03:55 -0700)
A domain_device has the same lifetime as its related scsi_target.  The
scsi_target is reference counted based on outstanding commands,
therefore it is safe to assume that if we have a valid sas_task that the
->dev pointer is also valid.

The asd_sas_port of a domain_device has the same lifetime as the driver
so it can also never be NULL as long as the sas_task is valid and the
driver is loaded.

This also cleans up isci_task_complete_for_upper_layer(), renames it to
isci_task_refuse() and notices that the isci_completion_selection
parameter was set to isci_perform_normal_io_completion by all callers.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/scsi/isci/task.c

index d00b4c9..d483680 100644 (file)
 #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.
+* isci_task_refuse() - complete the request to the upper layer driver in
+*     the case where an I/O needs to be completed back in the submit path.
+* @ihost: host on which the the request was queued
+* @task: request to complete
+* @response: response code for the completed task.
+* @status: 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)
+static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
+                            enum service_response response,
+                            enum exec_status status)
+
 {
-       unsigned long    flags = 0;
-       struct Scsi_Host *host = NULL;
+       enum isci_completion_selection disposition;
 
-       task_notification_selection
-               = isci_task_set_completion_status(task, response, status,
-                                                 task_notification_selection);
+       disposition = isci_perform_normal_io_completion;
+       disposition = isci_task_set_completion_status(task, response, status,
+                                                     disposition);
 
        /* 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) {
+        * function should not be completed to the host in the regular path.
+        */
+       switch (disposition) {
                case isci_perform_normal_io_completion:
                        /* Normal notification (task_done) */
-                       dev_dbg(task->dev->port->ha->dev,
+                       dev_dbg(&ihost->pdev->dev,
                                "%s: Normal - task = %p, response=%d, status=%d\n",
                                __func__, task, response, status);
 
+                       task->lldd_task = NULL;
                        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
@@ -107,44 +104,36 @@ static void isci_task_complete_for_upper_layer(struct sas_task *task,
                                * before we can call back and report the I/O
                                * submission error.
                                */
-                               if (task->dev
-                                   && task->dev->port
-                                   && task->dev->port->ha) {
+                               unsigned long flags;
 
-                                       host = task->dev->port->ha->core.shost;
-                                       raw_local_irq_save(flags);
-                                       spin_unlock(host->host_lock);
-                               }
+                               raw_local_irq_save(flags);
+                               spin_unlock(ihost->shost->host_lock);
                                task->task_done(task);
-                               if (host) {
-                                       spin_lock(host->host_lock);
-                                       raw_local_irq_restore(flags);
-                               }
+                               spin_lock(ihost->shost->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,
+                       dev_warn(&ihost->pdev->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,
+                       dev_warn(&ihost->pdev->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,
+                       dev_warn(&ihost->pdev->dev,
                                 "%s: isci task notification default case!",
                                 __func__);
                        sas_task_abort(task);
@@ -152,6 +141,10 @@ static void isci_task_complete_for_upper_layer(struct sas_task *task,
        }
 }
 
+#define for_each_sas_task(num, task) \
+       for (; num > 0; num--,\
+            task = list_entry(task->list.next, struct sas_task, list))
+
 /**
  * isci_task_execute_task() - This function is one of the SAS Domain Template
  *    functions. This function is called by libsas to send a task down to
@@ -164,7 +157,7 @@ static void isci_task_complete_for_upper_layer(struct sas_task *task,
  */
 int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
 {
-       struct isci_host *isci_host;
+       struct isci_host *ihost = task->dev->port->ha->lldd_ha;
        struct isci_request *request = NULL;
        struct isci_remote_device *device;
        unsigned long flags;
@@ -172,60 +165,23 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
        enum sci_status status;
        enum isci_status device_status;
 
-       dev_dbg(task->dev->port->ha->dev, "%s: num=%d\n", __func__, num);
-
-       if ((task->dev == NULL) || (task->dev->port == NULL)) {
-
-               /* Indicate SAS_TASK_UNDELIVERED, so that the scsi midlayer
-                * removes the target.
-                */
-               isci_task_complete_for_upper_layer(
-                       task,
-                       SAS_TASK_UNDELIVERED,
-                       SAS_DEVICE_UNKNOWN,
-                       isci_perform_normal_io_completion
-                       );
-               return 0;  /* The I/O was accepted (and failed). */
-       }
-       isci_host = isci_host_from_sas_ha(task->dev->port->ha);
+       dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num);
 
        /* Check if we have room for more tasks */
-       ret = isci_host_can_queue(isci_host, num);
+       ret = isci_host_can_queue(ihost, num);
 
        if (ret) {
-               dev_warn(task->dev->port->ha->dev, "%s: queue full\n", __func__);
+               dev_warn(&ihost->pdev->dev, "%s: queue full\n", __func__);
                return ret;
        }
 
-       do {
-               dev_dbg(task->dev->port->ha->dev,
+       for_each_sas_task(num, task) {
+               dev_dbg(&ihost->pdev->dev,
                        "task = %p, num = %d; dev = %p; cmd = %p\n",
                            task, num, task->dev, task->uldd_task);
 
-               if ((task->dev == NULL) || (task->dev->port == NULL)) {
-                       dev_warn(task->dev->port->ha->dev,
-                                "%s: task %p's port or dev == NULL!\n",
-                                __func__, task);
-
-                       /* Indicate SAS_TASK_UNDELIVERED, so that the scsi
-                        * midlayer removes the target.
-                        */
-                       isci_task_complete_for_upper_layer(
-                               task,
-                               SAS_TASK_UNDELIVERED,
-                               SAS_DEVICE_UNKNOWN,
-                               isci_perform_normal_io_completion
-                               );
-                       /* We don't have a valid host reference, so we
-                        * can't control the host queueing condition.
-                        */
-                       goto next_task;
-               }
-
                device = isci_dev_from_domain_dev(task->dev);
 
-               isci_host = isci_host_from_sas_ha(task->dev->port->ha);
-
                if (device)
                        device_status = device->status;
                else
@@ -239,34 +195,28 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                if (device_status != isci_ready_for_io) {
 
                        /* Forces a retry from scsi mid layer. */
-                       dev_warn(task->dev->port->ha->dev,
+                       dev_warn(&ihost->pdev->dev,
                                 "%s: task %p: isci_host->status = %d, "
                                 "device = %p; device_status = 0x%x\n\n",
                                 __func__,
                                 task,
-                                isci_host_get_state(isci_host),
+                                isci_host_get_state(ihost),
                                 device, device_status);
 
                        if (device_status == isci_ready) {
                                /* Indicate QUEUE_FULL so that the scsi midlayer
                                * retries.
                                */
-                               isci_task_complete_for_upper_layer(
-                                       task,
-                                       SAS_TASK_COMPLETE,
-                                       SAS_QUEUE_FULL,
-                                       isci_perform_normal_io_completion
-                                       );
+                               isci_task_refuse(ihost, task,
+                                                SAS_TASK_COMPLETE,
+                                                SAS_QUEUE_FULL);
                        } else {
                                /* Else, the device is going down. */
-                               isci_task_complete_for_upper_layer(
-                                       task,
-                                       SAS_TASK_UNDELIVERED,
-                                       SAS_DEVICE_UNKNOWN,
-                                       isci_perform_normal_io_completion
-                                       );
+                               isci_task_refuse(ihost, task,
+                                                SAS_TASK_UNDELIVERED,
+                                                SAS_DEVICE_UNKNOWN);
                        }
-                       isci_host_can_dequeue(isci_host, 1);
+                       isci_host_can_dequeue(ihost, 1);
                } else {
                        /* There is a device and it's ready for I/O. */
                        spin_lock_irqsave(&task->task_state_lock, flags);
@@ -276,12 +226,9 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                                spin_unlock_irqrestore(&task->task_state_lock,
                                                       flags);
 
-                               isci_task_complete_for_upper_layer(
-                                       task,
-                                       SAS_TASK_UNDELIVERED,
-                                       SAM_STAT_TASK_ABORTED,
-                                       isci_perform_normal_io_completion
-                                       );
+                               isci_task_refuse(ihost, task,
+                                                SAS_TASK_UNDELIVERED,
+                                                SAM_STAT_TASK_ABORTED);
 
                                /* The I/O was aborted. */
 
@@ -290,7 +237,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                                spin_unlock_irqrestore(&task->task_state_lock, flags);
 
                                /* build and send the request. */
-                               status = isci_request_execute(isci_host, task, &request,
+                               status = isci_request_execute(ihost, task, &request,
                                                              gfp_flags);
 
                                if (status != SCI_SUCCESS) {
@@ -307,19 +254,14 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                                        * SAS_TASK_UNDELIVERED next time
                                        * through.
                                        */
-                                       isci_task_complete_for_upper_layer(
-                                               task,
-                                               SAS_TASK_COMPLETE,
-                                               SAS_QUEUE_FULL,
-                                               isci_perform_normal_io_completion
-                                               );
-                                       isci_host_can_dequeue(isci_host, 1);
+                                       isci_task_refuse(ihost, task,
+                                                        SAS_TASK_COMPLETE,
+                                                        SAS_QUEUE_FULL);
+                                       isci_host_can_dequeue(ihost, 1);
                                }
                        }
                }
-next_task:
-               task = list_entry(task->list.next, struct sas_task, list);
-       } while (--num > 0);
+       }
        return 0;
 }