isci: combine request flags
[profile/ivi/kernel-adaptation-intel-automotive.git] / drivers / scsi / isci / task.c
index c313bc1..d1a4671 100644 (file)
@@ -63,6 +63,7 @@
 #include "request.h"
 #include "sata.h"
 #include "task.h"
+#include "host.h"
 
 /**
 * isci_task_refuse() - complete the request to the upper layer driver in
@@ -133,6 +134,15 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
        for (; num > 0; num--,\
             task = list_entry(task->list.next, struct sas_task, list))
 
+
+static inline int isci_device_io_ready(struct isci_remote_device *idev,
+                                      struct sas_task *task)
+{
+       return idev ? test_bit(IDEV_IO_READY, &idev->flags) ||
+                     (test_bit(IDEV_IO_NCQERROR, &idev->flags) &&
+                      isci_task_is_ncq_recovery(task))
+                   : 0;
+}
 /**
  * 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
@@ -147,25 +157,19 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
 {
        struct isci_host *ihost = dev_to_ihost(task->dev);
        struct isci_remote_device *idev;
-       enum sci_status status;
        unsigned long flags;
        bool io_ready;
-       int ret;
+       u16 tag;
 
        dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num);
 
-       /* Check if we have room for more tasks */
-       ret = isci_host_can_queue(ihost, num);
-
-       if (ret) {
-               dev_warn(&ihost->pdev->dev, "%s: queue full\n", __func__);
-               return ret;
-       }
-
        for_each_sas_task(num, task) {
+               enum sci_status status = SCI_FAILURE;
+
                spin_lock_irqsave(&ihost->scic_lock, flags);
                idev = isci_lookup_device(task->dev);
-               io_ready = idev ? test_bit(IDEV_IO_READY, &idev->flags) : 0;
+               io_ready = isci_device_io_ready(idev, task);
+               tag = isci_alloc_tag(ihost);
                spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
                dev_dbg(&ihost->pdev->dev,
@@ -176,14 +180,12 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                if (!idev) {
                        isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED,
                                         SAS_DEVICE_UNKNOWN);
-                       isci_host_can_dequeue(ihost, 1);
-               } else if (!io_ready) {
+               } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) {
                        /* Indicate QUEUE_FULL so that the scsi midlayer
                         * retries.
                          */
                        isci_task_refuse(ihost, task, SAS_TASK_COMPLETE,
                                         SAS_QUEUE_FULL);
-                       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);
@@ -196,13 +198,12 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                                isci_task_refuse(ihost, task,
                                                 SAS_TASK_UNDELIVERED,
                                                 SAM_STAT_TASK_ABORTED);
-                               isci_host_can_dequeue(ihost, 1);
                        } else {
                                task->task_state_flags |= SAS_TASK_AT_INITIATOR;
                                spin_unlock_irqrestore(&task->task_state_lock, flags);
 
                                /* build and send the request. */
-                               status = isci_request_execute(ihost, idev, task, gfp_flags);
+                               status = isci_request_execute(ihost, idev, task, tag, gfp_flags);
 
                                if (status != SCI_SUCCESS) {
 
@@ -221,10 +222,17 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
                                        isci_task_refuse(ihost, task,
                                                         SAS_TASK_COMPLETE,
                                                         SAS_QUEUE_FULL);
-                                       isci_host_can_dequeue(ihost, 1);
                                }
                        }
                }
+               if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) {
+                       spin_lock_irqsave(&ihost->scic_lock, flags);
+                       /* command never hit the device, so just free
+                        * the tci and skip the sequence increment
+                        */
+                       isci_tci_free(ihost, ISCI_TAG_TCI(tag));
+                       spin_unlock_irqrestore(&ihost->scic_lock, flags);
+               }
                isci_put_device(idev);
        }
        return 0;
@@ -232,7 +240,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
 
 static struct isci_request *isci_task_request_build(struct isci_host *ihost,
                                                    struct isci_remote_device *idev,
-                                                   struct isci_tmf *isci_tmf)
+                                                   u16 tag, struct isci_tmf *isci_tmf)
 {
        enum sci_status status = SCI_FAILURE;
        struct isci_request *ireq = NULL;
@@ -249,8 +257,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost,
                return NULL;
 
        /* let the core do it's construct. */
-       status = scic_task_request_construct(&ihost->sci, &idev->sci,
-                                            SCI_CONTROLLER_INVALID_IO_TAG,
+       status = scic_task_request_construct(&ihost->sci, &idev->sci, tag,
                                             &ireq->sci);
 
        if (status != SCI_SUCCESS) {
@@ -280,8 +287,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost,
        return ireq;
  errout:
        isci_request_free(ihost, ireq);
-       ireq = NULL;
-       return ireq;
+       return NULL;
 }
 
 int isci_task_execute_tmf(struct isci_host *ihost,
@@ -295,16 +301,26 @@ int isci_task_execute_tmf(struct isci_host *ihost,
        int ret = TMF_RESP_FUNC_FAILED;
        unsigned long flags;
        unsigned long timeleft;
+       u16 tag;
+
+       spin_lock_irqsave(&ihost->scic_lock, flags);
+       tag = isci_alloc_tag(ihost);
+       spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+       if (tag == SCI_CONTROLLER_INVALID_IO_TAG)
+               return ret;
 
        /* sanity check, return TMF_RESP_FUNC_FAILED
         * if the device is not there and ready.
         */
-       if (!isci_device || !test_bit(IDEV_IO_READY, &isci_device->flags)) {
+       if (!isci_device ||
+           (!test_bit(IDEV_IO_READY, &isci_device->flags) &&
+            !test_bit(IDEV_IO_NCQERROR, &isci_device->flags))) {
                dev_dbg(&ihost->pdev->dev,
                        "%s: isci_device = %p not ready (%#lx)\n",
                        __func__,
                        isci_device, isci_device ? isci_device->flags : 0);
-               return TMF_RESP_FUNC_FAILED;
+               goto err_tci;
        } else
                dev_dbg(&ihost->pdev->dev,
                        "%s: isci_device = %p\n",
@@ -315,22 +331,16 @@ int isci_task_execute_tmf(struct isci_host *ihost,
        /* Assign the pointer to the TMF's completion kernel wait structure. */
        tmf->complete = &completion;
 
-       ireq = isci_task_request_build(ihost, isci_device, tmf);
-       if (!ireq) {
-               dev_warn(&ihost->pdev->dev,
-                       "%s: isci_task_request_build failed\n",
-                       __func__);
-               return TMF_RESP_FUNC_FAILED;
-       }
+       ireq = isci_task_request_build(ihost, isci_device, tag, tmf);
+       if (!ireq)
+               goto err_tci;
 
        spin_lock_irqsave(&ihost->scic_lock, flags);
 
        /* start the TMF io. */
-       status = scic_controller_start_task(
-               &ihost->sci,
-               sci_device,
-               &ireq->sci,
-               SCI_CONTROLLER_INVALID_IO_TAG);
+       status = scic_controller_start_task(&ihost->sci,
+                                           sci_device,
+                                           &ireq->sci);
 
        if (status != SCI_TASK_SUCCESS) {
                dev_warn(&ihost->pdev->dev,
@@ -339,7 +349,7 @@ int isci_task_execute_tmf(struct isci_host *ihost,
                         status,
                         ireq);
                spin_unlock_irqrestore(&ihost->scic_lock, flags);
-               goto cleanup_request;
+               goto err_ireq;
        }
 
        if (tmf->cb_state_func != NULL)
@@ -354,7 +364,7 @@ int isci_task_execute_tmf(struct isci_host *ihost,
 
        /* Wait for the TMF to complete, or a timeout. */
        timeleft = wait_for_completion_timeout(&completion,
-                                      jiffies + msecs_to_jiffies(timeout_ms));
+                                              msecs_to_jiffies(timeout_ms));
 
        if (timeleft == 0) {
                spin_lock_irqsave(&ihost->scic_lock, flags);
@@ -362,11 +372,13 @@ int isci_task_execute_tmf(struct isci_host *ihost,
                if (tmf->cb_state_func != NULL)
                        tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data);
 
-               status = scic_controller_terminate_request(&ihost->sci,
-                                                          &isci_device->sci,
-                                                          &ireq->sci);
+               scic_controller_terminate_request(&ihost->sci,
+                                                 &isci_device->sci,
+                                                 &ireq->sci);
 
                spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+               wait_for_completion(tmf->complete);
        }
 
        isci_print_tmf(tmf);
@@ -387,13 +399,15 @@ int isci_task_execute_tmf(struct isci_host *ihost,
                __func__,
                ireq);
 
-       if (ireq->io_request_completion != NULL) {
-               /* A thread is waiting for this TMF to finish. */
-               complete(ireq->io_request_completion);
-       }
+       return ret;
 
cleanup_request:
err_ireq:
        isci_request_free(ihost, ireq);
+ err_tci:
+       spin_lock_irqsave(&ihost->scic_lock, flags);
+       isci_tci_free(ihost, ISCI_TAG_TCI(tag));
+       spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
        return ret;
 }
 
@@ -544,15 +558,15 @@ static void isci_terminate_request_core(
                : NULL;
 
        /* Note that we are not going to control
-       * the target to abort the request.
-       */
-       isci_request->complete_in_target = true;
+        * the target to abort the request.
+        */
+       set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->flags);
 
        /* Make sure the request wasn't just sitting around signalling
         * device condition (if the request handle is NULL, then the
         * request completed but needed additional handling here).
         */
-       if (!isci_request->terminated) {
+       if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) {
                was_terminated = true;
                needs_cleanup_handling = true;
                status = scic_controller_terminate_request(
@@ -595,7 +609,7 @@ static void isci_terminate_request_core(
                                                  flags);
 
                                /* Check for state changes. */
-                               if (!isci_request->terminated) {
+                               if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) {
 
                                        /* The best we can do is to have the
                                         * request die a silent death if it
@@ -1084,9 +1098,8 @@ int isci_task_abort_task(struct sas_task *task)
                ret = TMF_RESP_FUNC_COMPLETE;
                goto out;
        }
-       if ((task->task_proto == SAS_PROTOCOL_SMP)
-           || old_request->complete_in_target
-           ) {
+       if (task->task_proto == SAS_PROTOCOL_SMP ||
+           test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
 
                spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
@@ -1094,7 +1107,7 @@ int isci_task_abort_task(struct sas_task *task)
                        "%s: SMP request (%d)"
                        " or complete_in_target (%d), thus no TMF\n",
                        __func__, (task->task_proto == SAS_PROTOCOL_SMP),
-                       old_request->complete_in_target);
+                       test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));
 
                /* Set the state on the task. */
                isci_task_all_done(task);
@@ -1122,7 +1135,7 @@ int isci_task_abort_task(struct sas_task *task)
                                __func__);
        }
        if (ret == TMF_RESP_FUNC_COMPLETE) {
-               old_request->complete_in_target = true;
+               set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags);
 
                /* Clean up the request on our side, and wait for the aborted
                 * I/O to complete.
@@ -1238,7 +1251,7 @@ isci_task_request_complete(struct isci_host *ihost,
        isci_request_change_state(ireq, completed);
 
        tmf->status = completion_status;
-       ireq->complete_in_target = true;
+       set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags);
 
        if (tmf->proto == SAS_PROTOCOL_SSP) {
                memcpy(&tmf->resp.resp_iu,
@@ -1257,7 +1270,7 @@ isci_task_request_complete(struct isci_host *ihost,
        /* set the 'terminated' flag handle to make sure it cannot be terminated
         *  or completed again.
         */
-       ireq->terminated = true;;
+       set_bit(IREQ_TERMINATED, &ireq->flags);
 
        isci_request_change_state(ireq, unallocated);
        list_del_init(&ireq->dev_node);