]> Pileus Git - ~andy/linux/commitdiff
isci: Redesign device suspension, abort, cleanup.
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>
Fri, 9 Mar 2012 06:41:54 +0000 (22:41 -0800)
committerDan Williams <dan.j.williams@intel.com>
Thu, 17 May 2012 21:33:38 +0000 (14:33 -0700)
This commit changes the means by which outstanding I/Os are handled
for cleanup.
The likelihood is that this commit will be broken into smaller pieces,
however that will be a later revision.  Among the changes:

- All completion structures have been removed from the tmf and
abort paths.
- Now using one completed I/O list, with the I/O completed in host bit being
used to select error or normal callback paths.

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

index d241b5722eb3a74c0fd01b4718bffbfac291a34e..25d537e2f5c43408db740345d6344ab8dc8363ac 100644 (file)
@@ -1089,33 +1089,25 @@ void isci_host_completion_routine(unsigned long data)
 {
        struct isci_host *ihost = (struct isci_host *)data;
        struct list_head    completed_request_list;
-       struct list_head    errored_request_list;
        struct list_head    *current_position;
        struct list_head    *next_position;
        struct isci_request *request;
-       struct isci_request *next_request;
        struct sas_task     *task;
        u16 active;
 
        INIT_LIST_HEAD(&completed_request_list);
-       INIT_LIST_HEAD(&errored_request_list);
 
        spin_lock_irq(&ihost->scic_lock);
 
        sci_controller_completion_handler(ihost);
 
        /* Take the lists of completed I/Os from the host. */
-
        list_splice_init(&ihost->requests_to_complete,
                         &completed_request_list);
 
-       /* Take the list of errored I/Os from the host. */
-       list_splice_init(&ihost->requests_to_errorback,
-                        &errored_request_list);
-
        spin_unlock_irq(&ihost->scic_lock);
 
-       /* Process any completions in the lists. */
+       /* Process any completions in the list. */
        list_for_each_safe(current_position, next_position,
                           &completed_request_list) {
 
@@ -1123,23 +1115,30 @@ void isci_host_completion_routine(unsigned long data)
                                     completed_node);
                task = isci_request_access_task(request);
 
-               /* Normal notification (task_done) */
-               dev_dbg(&ihost->pdev->dev,
-                       "%s: Normal - request/task = %p/%p\n",
-                       __func__,
-                       request,
-                       task);
 
                /* Return the task to libsas */
                if (task != NULL) {
 
                        task->lldd_task = NULL;
-                       if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-
-                               /* If the task is already in the abort path,
-                               * the task_done callback cannot be called.
-                               */
-                               task->task_done(task);
+                       if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags) &&
+                           !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+                               if (test_bit(IREQ_COMPLETE_IN_TARGET,
+                                            &request->flags)) {
+
+                                       /* Normal notification (task_done) */
+                                       dev_dbg(&ihost->pdev->dev, "%s: Normal"
+                                               " - request/task = %p/%p\n",
+                                               __func__, request, task);
+
+                                       task->task_done(task);
+                               } else {
+                                       dev_warn(&ihost->pdev->dev,
+                                                "%s: Error - request/task"
+                                                " = %p/%p\n",
+                                                __func__, request, task);
+
+                                       sas_task_abort(task);
+                               }
                        }
                }
 
@@ -1147,44 +1146,6 @@ void isci_host_completion_routine(unsigned long data)
                isci_free_tag(ihost, request->io_tag);
                spin_unlock_irq(&ihost->scic_lock);
        }
-       list_for_each_entry_safe(request, next_request, &errored_request_list,
-                                completed_node) {
-
-               task = isci_request_access_task(request);
-
-               /* Use sas_task_abort */
-               dev_warn(&ihost->pdev->dev,
-                        "%s: Error - request/task = %p/%p\n",
-                        __func__,
-                        request,
-                        task);
-
-               if (task != NULL) {
-
-                       /* Put the task into the abort path if it's not there
-                        * already.
-                        */
-                       if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED))
-                               sas_task_abort(task);
-
-               } else {
-                       /* This is a case where the request has completed with a
-                        * status such that it needed further target servicing,
-                        * but the sas_task reference has already been removed
-                        * from the request.  Since it was errored, it was not
-                        * being aborted, so there is nothing to do except free
-                        * it.
-                        */
-
-                       spin_lock_irq(&ihost->scic_lock);
-                       /* Remove the request from the remote device's list
-                       * of pending requests.
-                       */
-                       list_del_init(&request->dev_node);
-                       isci_free_tag(ihost, request->io_tag);
-                       spin_unlock_irq(&ihost->scic_lock);
-               }
-       }
 
        /* the coalesence timeout doubles at each encoding step, so
         * update it based on the ilog2 value of the outstanding requests
@@ -2345,7 +2306,6 @@ static int sci_controller_dma_alloc(struct isci_host *ihost)
 
                ireq->tc = &ihost->task_context_table[i];
                ireq->owning_controller = ihost;
-               spin_lock_init(&ireq->state_lock);
                ireq->request_daddr = dma;
                ireq->isci_host = ihost;
                ihost->reqs[i] = ireq;
@@ -2697,6 +2657,10 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
                return SCI_FAILURE_INVALID_STATE;
        }
        status = sci_io_request_terminate(ireq);
+
+       dev_dbg(&ihost->pdev->dev, "%s: status=%d; ireq=%p; flags=%lx\n",
+               __func__, status, ireq, ireq->flags);
+
        if ((status == SCI_SUCCESS) &&
            !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
            !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
@@ -2739,6 +2703,8 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost,
 
                index = ISCI_TAG_TCI(ireq->io_tag);
                clear_bit(IREQ_ACTIVE, &ireq->flags);
+               if (test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+                       wake_up_all(&ihost->eventq);
                return SCI_SUCCESS;
        default:
                dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
index 7272a0a375f28e946125c93ca30ccf41dce62d8d..eaa13c0be09aeef0ccd0ffc0a4cae0c064347791 100644 (file)
@@ -205,7 +205,6 @@ struct isci_host {
        wait_queue_head_t eventq;
        struct tasklet_struct completion_tasklet;
        struct list_head requests_to_complete;
-       struct list_head requests_to_errorback;
        spinlock_t scic_lock;
        struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
        struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
index 9e1c83e425edd30de0f8ee3b2c9a55743fc976be..39f12703b8937db22abf0c39005fc5873e72e08e 100644 (file)
@@ -556,7 +556,6 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
        }
 
        INIT_LIST_HEAD(&ihost->requests_to_complete);
-       INIT_LIST_HEAD(&ihost->requests_to_errorback);
        for (i = 0; i < SCI_MAX_PORTS; i++) {
                struct isci_port *iport = &ihost->ports[i];
 
index 3048e02aeb7b1bc155c46505658005e4d13f384e..c47304cea45d7f4349485a962843da86ff041a84 100644 (file)
@@ -80,49 +80,6 @@ static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev
                                               NULL, NULL);
 }
 
-/**
- * isci_remote_device_not_ready() - This function is called by the ihost when
- *    the remote device is not ready. We mark the isci device as ready (not
- *    "ready_for_io") and signal the waiting proccess.
- * @isci_host: This parameter specifies the isci host object.
- * @isci_device: This parameter specifies the remote device
- *
- * sci_lock is held on entrance to this function.
- */
-static void isci_remote_device_not_ready(struct isci_host *ihost,
-                                 struct isci_remote_device *idev, u32 reason)
-{
-       struct isci_request *ireq;
-
-       dev_dbg(&ihost->pdev->dev,
-               "%s: isci_device = %p\n", __func__, idev);
-
-       switch (reason) {
-       case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
-               set_bit(IDEV_GONE, &idev->flags);
-               break;
-       case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
-               set_bit(IDEV_IO_NCQERROR, &idev->flags);
-
-               /* Suspend the remote device so the I/O can be terminated. */
-               sci_remote_device_suspend(idev);
-
-               /* Kill all outstanding requests for the device. */
-               list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) {
-
-                       dev_dbg(&ihost->pdev->dev,
-                               "%s: isci_device = %p request = %p\n",
-                               __func__, idev, ireq);
-
-                       sci_controller_terminate_request(ihost, idev, ireq);
-               }
-               /* Fall through into the default case... */
-       default:
-               clear_bit(IDEV_IO_READY, &idev->flags);
-               break;
-       }
-}
-
 /**
  * isci_remote_device_ready() - This function is called by the ihost when the
  *    remote device is ready. We mark the isci device as ready and signal the
@@ -142,49 +99,121 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
                wake_up(&ihost->eventq);
 }
 
-static int isci_remote_device_suspendcheck(struct isci_remote_device *idev)
+static enum sci_status sci_remote_device_terminate_req(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       int check_abort,
+       struct isci_request *ireq)
+{
+       dev_dbg(&ihost->pdev->dev,
+               "%s: idev=%p; flags=%lx; req=%p; req target=%p\n",
+               __func__, idev, idev->flags, ireq, ireq->target_device);
+
+       if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
+           (ireq->target_device != idev) ||
+           (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags)))
+               return SCI_SUCCESS;
+
+       set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
+
+       return sci_controller_terminate_request(ihost, idev, ireq);
+}
+
+static enum sci_status sci_remote_device_terminate_reqs_checkabort(
+       struct isci_remote_device *idev,
+       int chk)
 {
-       return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-           || !test_bit(IDEV_ALLOCATED, &idev->flags);
+       struct isci_host *ihost = idev->owning_port->owning_controller;
+       enum sci_status status  = SCI_SUCCESS;
+       u32 i;
+
+       for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
+               struct isci_request *ireq = ihost->reqs[i];
+               enum sci_status s;
+
+               s = sci_remote_device_terminate_req(ihost, idev, chk, ireq);
+               if (s != SCI_SUCCESS)
+                       status = s;
+       }
+       return status;
 }
 
-enum sci_status isci_remote_device_suspend(
+enum sci_status isci_remote_device_terminate_requests(
        struct isci_host *ihost,
-       struct isci_remote_device *idev)
+       struct isci_remote_device *idev,
+       struct isci_request *ireq)
 {
-       enum sci_status status;
+       enum sci_status status = SCI_SUCCESS;
        unsigned long flags;
 
        spin_lock_irqsave(&ihost->scic_lock, flags);
-       if (isci_get_device(idev->domain_dev) == NULL) {
+       if (isci_get_device(idev) == NULL) {
+               dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n",
+                       __func__, idev);
                spin_unlock_irqrestore(&ihost->scic_lock, flags);
                status = SCI_FAILURE;
        } else {
-               status = sci_remote_device_suspend(idev);
-               spin_unlock_irqrestore(&ihost->scic_lock, flags);
-               if (status == SCI_SUCCESS) {
-                       dev_dbg(&ihost->pdev->dev,
-                               "%s: idev=%p, about to wait\n",
-                               __func__, idev);
-                       wait_event(ihost->eventq,
-                                  isci_remote_device_suspendcheck(idev));
-                       status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-                                       ? SCI_SUCCESS : SCI_FAILURE;
-                       dev_dbg(&ihost->pdev->dev,
-                               "%s: idev=%p, wait done, device is %s\n",
-                               __func__, idev,
-                               test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-                                       ? "<suspended>" : "<deallocated!>");
+               dev_dbg(&ihost->pdev->dev,
+                       "%s: idev=%p, ireq=%p; started_request_count=%d, "
+                               "about to wait\n",
+                       __func__, idev, ireq, idev->started_request_count);
+               if (ireq) {
+                       /* Terminate a specific TC. */
+                       sci_remote_device_terminate_req(ihost, idev, 0, ireq);
+                       spin_unlock_irqrestore(&ihost->scic_lock, flags);
+                       wait_event(ihost->eventq, !test_bit(IREQ_ACTIVE,
+                                                           &ireq->flags));
 
-               } else
-                       dev_dbg(scirdev_to_dev(idev),
-                                "%s: sci_remote_device_suspend failed, "
-                                "status = %d\n", __func__, status);
+               } else {
+                       /* Terminate all TCs. */
+                       sci_remote_device_terminate_requests(idev);
+                       spin_unlock_irqrestore(&ihost->scic_lock, flags);
+                       wait_event(ihost->eventq,
+                                  idev->started_request_count == 0);
+               }
+               dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
+                       __func__, idev);
                isci_put_device(idev);
        }
        return status;
 }
 
+/**
+* isci_remote_device_not_ready() - This function is called by the ihost when
+*    the remote device is not ready. We mark the isci device as ready (not
+*    "ready_for_io") and signal the waiting proccess.
+* @isci_host: This parameter specifies the isci host object.
+* @isci_device: This parameter specifies the remote device
+*
+* sci_lock is held on entrance to this function.
+*/
+static void isci_remote_device_not_ready(struct isci_host *ihost,
+                                        struct isci_remote_device *idev,
+                                        u32 reason)
+{
+       dev_dbg(&ihost->pdev->dev,
+               "%s: isci_device = %p\n", __func__, idev);
+
+       switch (reason) {
+       case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
+               set_bit(IDEV_GONE, &idev->flags);
+               break;
+       case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
+               set_bit(IDEV_IO_NCQERROR, &idev->flags);
+
+               /* Suspend the remote device so the I/O can be terminated. */
+               sci_remote_device_suspend(idev);
+
+               /* Kill all outstanding requests for the device. */
+               sci_remote_device_terminate_requests(idev);
+
+               /* Fall through into the default case... */
+       default:
+               clear_bit(IDEV_IO_READY, &idev->flags);
+               break;
+       }
+}
+
 /* called once the remote node context is ready to be freed.
  * The remote device can now report that its stop operation is complete. none
  */
@@ -196,36 +225,10 @@ static void rnc_destruct_done(void *_dev)
        sci_change_state(&idev->sm, SCI_DEV_STOPPED);
 }
 
-static enum sci_status sci_remote_device_terminate_requests_checkabort(
-       struct isci_remote_device *idev,
-       int check_abort_pending)
-{
-       struct isci_host *ihost = idev->owning_port->owning_controller;
-       enum sci_status status  = SCI_SUCCESS;
-       u32 i;
-
-       for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
-               struct isci_request *ireq = ihost->reqs[i];
-               enum sci_status s;
-
-               if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
-                   (ireq->target_device != idev) ||
-                   (check_abort_pending && !test_bit(IREQ_PENDING_ABORT,
-                                                     &ireq->flags)))
-                       continue;
-
-               s = sci_controller_terminate_request(ihost, idev, ireq);
-               if (s != SCI_SUCCESS)
-                       status = s;
-       }
-
-       return status;
-}
-
 enum sci_status sci_remote_device_terminate_requests(
        struct isci_remote_device *idev)
 {
-       return sci_remote_device_terminate_requests_checkabort(idev, 0);
+       return sci_remote_device_terminate_reqs_checkabort(idev, 0);
 }
 
 enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
@@ -771,10 +774,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
                if (status != SCI_SUCCESS)
                        return status;
 
-               status = sci_remote_node_context_start_task(&idev->rnc, ireq);
-               if (status != SCI_SUCCESS)
-                       goto out;
-
                status = sci_request_start(ireq);
                if (status != SCI_SUCCESS)
                        goto out;
@@ -796,8 +795,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
                sci_remote_node_context_suspend(
                        &idev->rnc, SCI_SOFTWARE_SUSPENSION,
                        SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
-               sci_remote_node_context_resume(
-                       &idev->rnc, sci_remote_device_continue_request, idev);
+
+               status = sci_remote_node_context_start_task(&idev->rnc, ireq,
+                               sci_remote_device_continue_request, idev);
 
        out:
                sci_remote_device_start_request(idev, ireq, status);
@@ -811,7 +811,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
                if (status != SCI_SUCCESS)
                        return status;
 
-               status = sci_remote_node_context_start_task(&idev->rnc, ireq);
+               /* Resume the RNC as needed: */
+               status = sci_remote_node_context_start_task(&idev->rnc, ireq,
+                                                           NULL, NULL);
                if (status != SCI_SUCCESS)
                        break;
 
@@ -1322,20 +1324,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
        return status;
 }
 
-void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev)
-{
-       DECLARE_COMPLETION_ONSTACK(aborted_task_completion);
-
-       dev_dbg(&ihost->pdev->dev,
-               "%s: idev = %p\n", __func__, idev);
-
-       /* Cleanup all requests pending for this device. */
-       isci_terminate_pending_requests(ihost, idev);
-
-       dev_dbg(&ihost->pdev->dev,
-               "%s: idev = %p, done\n", __func__, idev);
-}
-
 /**
  * This function builds the isci_remote_device when a libsas dev_found message
  *    is received.
@@ -1495,32 +1483,28 @@ int isci_remote_device_found(struct domain_device *dev)
        return status == SCI_SUCCESS ? 0 : -ENODEV;
 }
 
-enum sci_status isci_remote_device_reset(
+enum sci_status isci_remote_device_suspend_terminate(
        struct isci_host *ihost,
-       struct isci_remote_device *idev)
+       struct isci_remote_device *idev,
+       struct isci_request *ireq)
 {
        unsigned long flags;
        enum sci_status status;
 
-       /* Put the device into a reset state so the suspension will not
-        * automatically resume.
-        */
+       /* Put the device into suspension. */
        spin_lock_irqsave(&ihost->scic_lock, flags);
-       status = sci_remote_device_reset(idev);
+       sci_remote_device_suspend(idev);
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
-       if (status != SCI_SUCCESS) {
-               dev_dbg(&ihost->pdev->dev,
-                       "%s: sci_remote_device_reset(%p) returned %d!\n",
-                       __func__, idev, status);
-               return status;
-       }
-       /* Wait for the device suspend. */
-       status = isci_remote_device_suspend(ihost, idev);
-       if (status != SCI_SUCCESS) {
+
+       /* Terminate and wait for the completions. */
+       status = isci_remote_device_terminate_requests(ihost, idev, ireq);
+       if (status != SCI_SUCCESS)
                dev_dbg(&ihost->pdev->dev,
-                       "%s: isci_remote_device_suspend(%p) returned %d!\n",
+                       "%s: isci_remote_device_terminate_requests(%p) "
+                               "returned %d!\n",
                        __func__, idev, status);
-       }
+
+       /* NOTE: RNC resumption is left to the caller! */
        return status;
 }
 
@@ -1533,7 +1517,7 @@ int isci_remote_device_is_safe_to_abort(
 enum sci_status sci_remote_device_abort_requests_pending_abort(
        struct isci_remote_device *idev)
 {
-       return sci_remote_device_terminate_requests_checkabort(idev, 1);
+       return sci_remote_device_terminate_reqs_checkabort(idev, 1);
 }
 
 enum sci_status isci_remote_device_reset_complete(
@@ -1545,7 +1529,6 @@ enum sci_status isci_remote_device_reset_complete(
 
        spin_lock_irqsave(&ihost->scic_lock, flags);
        status = sci_remote_device_reset_complete(idev);
-       sci_remote_device_resume(idev, NULL, NULL);
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
        return status;
index a6a376e200ef925abcb95db206a3b4e012393ecd..da43698e9ebada5d5cf04efdc74367c7f31ba800 100644 (file)
@@ -85,7 +85,6 @@ struct isci_remote_device {
        #define IDEV_GONE 3
        #define IDEV_IO_READY 4
        #define IDEV_IO_NCQERROR 5
-       #define IDEV_TXRX_SUSPENDED 6
        unsigned long flags;
        struct kref kref;
        struct isci_port *isci_port;
@@ -107,10 +106,8 @@ struct isci_remote_device {
 
 /* device reference routines must be called under sci_lock */
 static inline struct isci_remote_device *isci_get_device(
-       struct domain_device *dev)
+       struct isci_remote_device *idev)
 {
-       struct isci_remote_device *idev = dev->lldd_dev;
-
        if (idev)
                kref_get(&idev->kref);
        return idev;
@@ -378,4 +375,14 @@ enum sci_status isci_remote_device_reset(
 enum sci_status isci_remote_device_reset_complete(
        struct isci_host *ihost,
        struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_suspend_terminate(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       struct isci_request *ireq);
+
+enum sci_status isci_remote_device_terminate_requests(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       struct isci_request *ireq);
 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
index 7a8347e517671ec795ffc5a5adc6f4b47ce84c47..feeca17f0f13a290e92cf39f734518f473280932 100644 (file)
@@ -317,8 +317,6 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
        struct isci_remote_device *idev = rnc_to_dev(rnc);
        struct isci_host *ihost = idev->owning_port->owning_controller;
 
-       set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
-
        /* Terminate outstanding requests pending abort. */
        sci_remote_device_abort_requests_pending_abort(idev);
 
@@ -326,16 +324,6 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
        sci_remote_node_context_continue_state_transitions(rnc);
 }
 
-static void sci_remote_node_context_tx_rx_suspended_state_exit(
-       struct sci_base_state_machine *sm)
-{
-       struct sci_remote_node_context *rnc
-               = container_of(sm, typeof(*rnc), sm);
-       struct isci_remote_device *idev = rnc_to_dev(rnc);
-
-       clear_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
-}
-
 static void sci_remote_node_context_await_suspend_state_exit(
        struct sci_base_state_machine *sm)
 {
@@ -366,8 +354,6 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
        },
        [SCI_RNC_TX_RX_SUSPENDED] = {
                .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
-               .exit_state
-                       = sci_remote_node_context_tx_rx_suspended_state_exit,
        },
        [SCI_RNC_AWAIT_SUSPENSION] = {
                .exit_state = sci_remote_node_context_await_suspend_state_exit,
@@ -671,8 +657,11 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context
        }
 }
 
-enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
-                                                       struct isci_request *ireq)
+enum sci_status sci_remote_node_context_start_task(
+       struct sci_remote_node_context *sci_rnc,
+       struct isci_request *ireq,
+       scics_sds_remote_node_context_callback cb_fn,
+       void *cb_p)
 {
        enum scis_sds_remote_node_context_states state;
 
@@ -684,7 +673,7 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
                return SCI_SUCCESS;
        case SCI_RNC_TX_SUSPENDED:
        case SCI_RNC_TX_RX_SUSPENDED:
-               sci_remote_node_context_resume(sci_rnc, NULL, NULL);
+               sci_remote_node_context_resume(sci_rnc, cb_fn, cb_p);
                return SCI_SUCCESS;
        default:
                dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
index 5ddf88b53133e571c508ab4507668b66585100b9..2870af14edab2279dd8b0e6dbed856f1d61aab68 100644 (file)
@@ -211,7 +211,9 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
                                                    scics_sds_remote_node_context_callback cb_fn,
                                                    void *cb_p);
 enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
-                                                       struct isci_request *ireq);
+                                                  struct isci_request *ireq,
+                                                  scics_sds_remote_node_context_callback cb_fn,
+                                                  void *cb_p);
 enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
                                                      struct isci_request *ireq);
 int sci_remote_node_context_is_safe_to_abort(
index 1f314d0d71d58c481c559f2c787ce277a93bd72e..f4e80f31423cac59ffb2be2c7559e078ddd8b571 100644 (file)
@@ -2491,9 +2491,6 @@ static void isci_request_process_response_iu(
  * @request: This parameter is the completed isci_request object.
  * @response_ptr: This parameter specifies the service response for the I/O.
  * @status_ptr: This parameter specifies the exec status for the I/O.
- * @complete_to_host_ptr: This parameter specifies the action to be taken by
- *    the LLDD with respect to completing this request or forcing an abort
- *    condition on the I/O.
  * @open_rej_reason: This parameter specifies the encoded reason for the
  *    abandon-class reject.
  *
@@ -2504,14 +2501,12 @@ static void isci_request_set_open_reject_status(
        struct sas_task *task,
        enum service_response *response_ptr,
        enum exec_status *status_ptr,
-       enum isci_completion_selection *complete_to_host_ptr,
        enum sas_open_rej_reason open_rej_reason)
 {
        /* Task in the target is done. */
        set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
        *response_ptr                     = SAS_TASK_UNDELIVERED;
        *status_ptr                       = SAS_OPEN_REJECT;
-       *complete_to_host_ptr             = isci_perform_normal_io_completion;
        task->task_status.open_rej_reason = open_rej_reason;
 }
 
@@ -2521,9 +2516,6 @@ static void isci_request_set_open_reject_status(
  * @request: This parameter is the completed isci_request object.
  * @response_ptr: This parameter specifies the service response for the I/O.
  * @status_ptr: This parameter specifies the exec status for the I/O.
- * @complete_to_host_ptr: This parameter specifies the action to be taken by
- *    the LLDD with respect to completing this request or forcing an abort
- *    condition on the I/O.
  *
  * none.
  */
@@ -2532,8 +2524,7 @@ static void isci_request_handle_controller_specific_errors(
        struct isci_request *request,
        struct sas_task *task,
        enum service_response *response_ptr,
-       enum exec_status *status_ptr,
-       enum isci_completion_selection *complete_to_host_ptr)
+       enum exec_status *status_ptr)
 {
        unsigned int cstatus;
 
@@ -2574,9 +2565,6 @@ static void isci_request_handle_controller_specific_errors(
                                *status_ptr = SAS_ABORTED_TASK;
 
                        set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-                       *complete_to_host_ptr =
-                               isci_perform_normal_io_completion;
                } else {
                        /* Task in the target is not done. */
                        *response_ptr = SAS_TASK_UNDELIVERED;
@@ -2587,9 +2575,6 @@ static void isci_request_handle_controller_specific_errors(
                                *status_ptr = SAM_STAT_TASK_ABORTED;
 
                        clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-                       *complete_to_host_ptr =
-                               isci_perform_error_io_completion;
                }
 
                break;
@@ -2618,8 +2603,6 @@ static void isci_request_handle_controller_specific_errors(
                        *status_ptr = SAS_ABORTED_TASK;
 
                set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-               *complete_to_host_ptr = isci_perform_normal_io_completion;
                break;
 
 
@@ -2630,7 +2613,7 @@ static void isci_request_handle_controller_specific_errors(
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_WRONG_DEST);
+                       SAS_OREJ_WRONG_DEST);
                break;
 
        case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
@@ -2640,56 +2623,56 @@ static void isci_request_handle_controller_specific_errors(
                 */
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_RESV_AB0);
+                       SAS_OREJ_RESV_AB0);
                break;
 
        case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_RESV_AB1);
+                       SAS_OREJ_RESV_AB1);
                break;
 
        case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_RESV_AB2);
+                       SAS_OREJ_RESV_AB2);
                break;
 
        case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_RESV_AB3);
+                       SAS_OREJ_RESV_AB3);
                break;
 
        case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_BAD_DEST);
+                       SAS_OREJ_BAD_DEST);
                break;
 
        case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_STP_NORES);
+                       SAS_OREJ_STP_NORES);
                break;
 
        case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_EPROTO);
+                       SAS_OREJ_EPROTO);
                break;
 
        case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
 
                isci_request_set_open_reject_status(
                        request, task, response_ptr, status_ptr,
-                       complete_to_host_ptr, SAS_OREJ_CONN_RATE);
+                       SAS_OREJ_CONN_RATE);
                break;
 
        case SCU_TASK_DONE_LL_R_ERR:
@@ -2721,95 +2704,12 @@ static void isci_request_handle_controller_specific_errors(
                *response_ptr = SAS_TASK_UNDELIVERED;
                *status_ptr = SAM_STAT_TASK_ABORTED;
 
-               if (task->task_proto == SAS_PROTOCOL_SMP) {
+               if (task->task_proto == SAS_PROTOCOL_SMP)
                        set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-                       *complete_to_host_ptr = isci_perform_normal_io_completion;
-               } else {
+               else
                        clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-                       *complete_to_host_ptr = isci_perform_error_io_completion;
-               }
-               break;
-       }
-}
-
-/**
- * isci_task_save_for_upper_layer_completion() - This function saves the
- *    request for later completion 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 void isci_task_save_for_upper_layer_completion(
-       struct isci_host *host,
-       struct isci_request *request,
-       enum service_response response,
-       enum exec_status status,
-       enum isci_completion_selection task_notification_selection)
-{
-       struct sas_task *task = isci_request_access_task(request);
-
-       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) */
-
-               /* Add to the completed list. */
-               list_add(&request->completed_node,
-                        &host->requests_to_complete);
-
-               /* Take the request off the device's pending request list. */
-               list_del_init(&request->dev_node);
-               break;
-
-       case isci_perform_aborted_io_completion:
-               /* No notification to libsas because this request is
-                * already in the abort path.
-                */
-               /* Wake up whatever process was waiting for this
-                * request to complete.
-                */
-               WARN_ON(request->io_request_completion == NULL);
-
-               if (request->io_request_completion != NULL) {
-
-                       /* Signal whoever is waiting that this
-                       * request is complete.
-                       */
-                       complete(request->io_request_completion);
-               }
-               break;
-
-       case isci_perform_error_io_completion:
-               /* Use sas_task_abort */
-               /* Add to the aborted list. */
-               list_add(&request->completed_node,
-                        &host->requests_to_errorback);
-               break;
-
-       default:
-               /* Add to the error to libsas list. */
-               list_add(&request->completed_node,
-                        &host->requests_to_errorback);
                break;
        }
-       dev_dbg(&host->pdev->dev,
-               "%s: %d - task = %p, response=%d (%d), status=%d (%d)\n",
-               __func__, task_notification_selection, task,
-               (task) ? task->task_status.resp : 0, response,
-               (task) ? task->task_status.stat : 0, status);
 }
 
 static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
@@ -2844,9 +2744,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
        struct isci_remote_device *idev = request->target_device;
        enum service_response response = SAS_TASK_UNDELIVERED;
        enum exec_status status = SAS_ABORTED_TASK;
-       enum isci_request_status request_status;
-       enum isci_completion_selection complete_to_host
-               = isci_perform_normal_io_completion;
 
        dev_dbg(&ihost->pdev->dev,
                "%s: request = %p, task = %p,\n"
@@ -2857,282 +2754,158 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
                task->data_dir,
                completion_status);
 
-       spin_lock(&request->state_lock);
-       request_status = request->status;
-
-       /* Decode the request status.  Note that if the request has been
-        * aborted by a task management function, we don't care
-        * what the status is.
-        */
-       switch (request_status) {
-
-       case aborted:
-               /* "aborted" indicates that the request was aborted by a task
-                * management function, since once a task management request is
-                * perfomed by the device, the request only completes because
-                * of the subsequent driver terminate.
-                *
-                * Aborted also means an external thread is explicitly managing
-                * this request, so that we do not complete it up the stack.
-                *
-                * The target is still there (since the TMF was successful).
-                */
-               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-               response = SAS_TASK_COMPLETE;
+       /* The request is done from an SCU HW perspective. */
 
-               /* See if the device has been/is being stopped. Note
-                * that we ignore the quiesce state, since we are
-                * concerned about the actual device state.
-                */
-               if (!idev)
-                       status = SAS_DEVICE_UNKNOWN;
-               else
-                       status = SAS_ABORTED_TASK;
+       /* This is an active request being completed from the core. */
+       switch (completion_status) {
 
-               complete_to_host = isci_perform_aborted_io_completion;
-               /* This was an aborted request. */
+       case SCI_IO_FAILURE_RESPONSE_VALID:
+               dev_dbg(&ihost->pdev->dev,
+                       "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
+                       __func__, request, task);
 
-               spin_unlock(&request->state_lock);
-               break;
+               if (sas_protocol_ata(task->task_proto)) {
+                       isci_process_stp_response(task, &request->stp.rsp);
+               } else if (SAS_PROTOCOL_SSP == task->task_proto) {
 
-       case aborting:
-               /* aborting means that the task management function tried and
-                * failed to abort the request. We need to note the request
-                * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the
-                * target as down.
-                *
-                * Aborting also means an external thread is explicitly managing
-                * this request, so that we do not complete it up the stack.
-                */
-               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-               response = SAS_TASK_UNDELIVERED;
+                       /* crack the iu response buffer. */
+                       resp_iu = &request->ssp.rsp;
+                       isci_request_process_response_iu(task, resp_iu,
+                                                        &ihost->pdev->dev);
 
-               if (!idev)
-                       /* The device has been /is being stopped. Note that
-                        * we ignore the quiesce state, since we are
-                        * concerned about the actual device state.
-                        */
-                       status = SAS_DEVICE_UNKNOWN;
-               else
-                       status = SAS_PHY_DOWN;
+               } else if (SAS_PROTOCOL_SMP == task->task_proto) {
 
-               complete_to_host = isci_perform_aborted_io_completion;
+                       dev_err(&ihost->pdev->dev,
+                               "%s: SCI_IO_FAILURE_RESPONSE_VALID: "
+                                       "SAS_PROTOCOL_SMP protocol\n",
+                               __func__);
 
-               /* This was an aborted request. */
+               } else
+                       dev_err(&ihost->pdev->dev,
+                               "%s: unknown protocol\n", __func__);
 
-               spin_unlock(&request->state_lock);
+               /* use the task status set in the task struct by the
+               * isci_request_process_response_iu call.
+               */
+               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+               response = task->task_status.resp;
+               status = task->task_status.stat;
                break;
 
-       case terminating:
+       case SCI_IO_SUCCESS:
+       case SCI_IO_SUCCESS_IO_DONE_EARLY:
 
-               /* This was an terminated request.  This happens when
-                * the I/O is being terminated because of an action on
-                * the device (reset, tear down, etc.), and the I/O needs
-                * to be completed up the stack.
-                */
+               response = SAS_TASK_COMPLETE;
+               status   = SAM_STAT_GOOD;
                set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-               response = SAS_TASK_UNDELIVERED;
 
-               /* See if the device has been/is being stopped. Note
-                * that we ignore the quiesce state, since we are
-                * concerned about the actual device state.
-                */
-               if (!idev)
-                       status = SAS_DEVICE_UNKNOWN;
-               else
-                       status = SAS_ABORTED_TASK;
-
-               complete_to_host = isci_perform_aborted_io_completion;
-
-               /* This was a terminated request. */
-
-               spin_unlock(&request->state_lock);
-               break;
+               if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
 
-       case dead:
-               /* This was a terminated request that timed-out during the
-                * termination process.  There is no task to complete to
-                * libsas.
-                */
-               complete_to_host = isci_perform_normal_io_completion;
-               spin_unlock(&request->state_lock);
-               break;
-
-       default:
-
-               /* The request is done from an SCU HW perspective. */
-               request->status = completed;
+                       /* This was an SSP / STP / SATA transfer.
+                       * There is a possibility that less data than
+                       * the maximum was transferred.
+                       */
+                       u32 transferred_length = sci_req_tx_bytes(request);
 
-               spin_unlock(&request->state_lock);
+                       task->task_status.residual
+                               = task->total_xfer_len - transferred_length;
 
-               /* This is an active request being completed from the core. */
-               switch (completion_status) {
+                       /* If there were residual bytes, call this an
+                       * underrun.
+                       */
+                       if (task->task_status.residual != 0)
+                               status = SAS_DATA_UNDERRUN;
 
-               case SCI_IO_FAILURE_RESPONSE_VALID:
                        dev_dbg(&ihost->pdev->dev,
-                               "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
-                               __func__,
-                               request,
-                               task);
-
-                       if (sas_protocol_ata(task->task_proto)) {
-                               isci_process_stp_response(task, &request->stp.rsp);
-                       } else if (SAS_PROTOCOL_SSP == task->task_proto) {
-
-                               /* crack the iu response buffer. */
-                               resp_iu = &request->ssp.rsp;
-                               isci_request_process_response_iu(task, resp_iu,
-                                                                &ihost->pdev->dev);
-
-                       } else if (SAS_PROTOCOL_SMP == task->task_proto) {
+                               "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
+                               __func__, status);
 
-                               dev_err(&ihost->pdev->dev,
-                                       "%s: SCI_IO_FAILURE_RESPONSE_VALID: "
-                                       "SAS_PROTOCOL_SMP protocol\n",
-                                       __func__);
-
-                       } else
-                               dev_err(&ihost->pdev->dev,
-                                       "%s: unknown protocol\n", __func__);
-
-                       /* use the task status set in the task struct by the
-                        * isci_request_process_response_iu call.
-                        */
-                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-                       response = task->task_status.resp;
-                       status = task->task_status.stat;
-                       break;
-
-               case SCI_IO_SUCCESS:
-               case SCI_IO_SUCCESS_IO_DONE_EARLY:
-
-                       response = SAS_TASK_COMPLETE;
-                       status   = SAM_STAT_GOOD;
-                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-                       if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
-
-                               /* This was an SSP / STP / SATA transfer.
-                                * There is a possibility that less data than
-                                * the maximum was transferred.
-                                */
-                               u32 transferred_length = sci_req_tx_bytes(request);
-
-                               task->task_status.residual
-                                       = task->total_xfer_len - transferred_length;
+               } else
+                       dev_dbg(&ihost->pdev->dev, "%s: SCI_IO_SUCCESS\n",
+                               __func__);
+               break;
 
-                               /* If there were residual bytes, call this an
-                                * underrun.
-                                */
-                               if (task->task_status.residual != 0)
-                                       status = SAS_DATA_UNDERRUN;
+       case SCI_IO_FAILURE_TERMINATED:
 
-                               dev_dbg(&ihost->pdev->dev,
-                                       "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
-                                       __func__,
-                                       status);
+               dev_dbg(&ihost->pdev->dev,
+                       "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
+                       __func__, request, task);
 
-                       } else
-                               dev_dbg(&ihost->pdev->dev,
-                                       "%s: SCI_IO_SUCCESS\n",
-                                       __func__);
+               /* The request was terminated explicitly. */
+               clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+               response = SAS_TASK_UNDELIVERED;
 
-                       break;
+               /* See if the device has been/is being stopped. Note
+               * that we ignore the quiesce state, since we are
+               * concerned about the actual device state.
+               */
+               if (!idev)
+                       status = SAS_DEVICE_UNKNOWN;
+               else
+                       status = SAS_ABORTED_TASK;
+               break;
 
-               case SCI_IO_FAILURE_TERMINATED:
-                       dev_dbg(&ihost->pdev->dev,
-                               "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
-                               __func__,
-                               request,
-                               task);
+       case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
 
-                       /* The request was terminated explicitly.  No handling
-                        * is needed in the SCSI error handler path.
-                        */
-                       set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-                       response = SAS_TASK_UNDELIVERED;
+               isci_request_handle_controller_specific_errors(idev, request,
+                                                              task, &response,
+                                                              &status);
+               break;
 
-                       /* See if the device has been/is being stopped. Note
-                        * that we ignore the quiesce state, since we are
-                        * concerned about the actual device state.
-                        */
-                       if (!idev)
-                               status = SAS_DEVICE_UNKNOWN;
-                       else
-                               status = SAS_ABORTED_TASK;
+       case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
+               /* This is a special case, in that the I/O completion
+               * is telling us that the device needs a reset.
+               * In order for the device reset condition to be
+               * noticed, the I/O has to be handled in the error
+               * handler.  Set the reset flag and cause the
+               * SCSI error thread to be scheduled.
+               */
+               spin_lock_irqsave(&task->task_state_lock, task_flags);
+               task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+               spin_unlock_irqrestore(&task->task_state_lock, task_flags);
 
-                       complete_to_host = isci_perform_normal_io_completion;
-                       break;
+               /* Fail the I/O. */
+               response = SAS_TASK_UNDELIVERED;
+               status = SAM_STAT_TASK_ABORTED;
 
-               case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
+               clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+               break;
 
-                       isci_request_handle_controller_specific_errors(
-                               idev, request, task, &response, &status,
-                               &complete_to_host);
+       case SCI_FAILURE_RETRY_REQUIRED:
 
-                       break;
+               /* Fail the I/O so it can be retried. */
+               response = SAS_TASK_UNDELIVERED;
+               if (!idev)
+                       status = SAS_DEVICE_UNKNOWN;
+               else
+                       status = SAS_ABORTED_TASK;
 
-               case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
-                       /* This is a special case, in that the I/O completion
-                        * is telling us that the device needs a reset.
-                        * In order for the device reset condition to be
-                        * noticed, the I/O has to be handled in the error
-                        * handler.  Set the reset flag and cause the
-                        * SCSI error thread to be scheduled.
-                        */
-                       spin_lock_irqsave(&task->task_state_lock, task_flags);
-                       task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
-                       spin_unlock_irqrestore(&task->task_state_lock, task_flags);
+               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+               break;
 
-                       /* Fail the I/O. */
-                       response = SAS_TASK_UNDELIVERED;
-                       status = SAM_STAT_TASK_ABORTED;
 
-                       complete_to_host = isci_perform_error_io_completion;
-                       clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-                       break;
+       default:
+               /* Catch any otherwise unhandled error codes here. */
+               dev_dbg(&ihost->pdev->dev,
+                       "%s: invalid completion code: 0x%x - "
+                               "isci_request = %p\n",
+                       __func__, completion_status, request);
 
-               case SCI_FAILURE_RETRY_REQUIRED:
+               response = SAS_TASK_UNDELIVERED;
 
-                       /* Fail the I/O so it can be retried. */
-                       response = SAS_TASK_UNDELIVERED;
-                       if (!idev)
-                               status = SAS_DEVICE_UNKNOWN;
-                       else
-                               status = SAS_ABORTED_TASK;
+               /* See if the device has been/is being stopped. Note
+               * that we ignore the quiesce state, since we are
+               * concerned about the actual device state.
+               */
+               if (!idev)
+                       status = SAS_DEVICE_UNKNOWN;
+               else
+                       status = SAS_ABORTED_TASK;
 
-                       complete_to_host = isci_perform_normal_io_completion;
+               if (SAS_PROTOCOL_SMP == task->task_proto)
                        set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-                       break;
-
-
-               default:
-                       /* Catch any otherwise unhandled error codes here. */
-                       dev_dbg(&ihost->pdev->dev,
-                                "%s: invalid completion code: 0x%x - "
-                                "isci_request = %p\n",
-                                __func__, completion_status, request);
-
-                       response = SAS_TASK_UNDELIVERED;
-
-                       /* See if the device has been/is being stopped. Note
-                        * that we ignore the quiesce state, since we are
-                        * concerned about the actual device state.
-                        */
-                       if (!idev)
-                               status = SAS_DEVICE_UNKNOWN;
-                       else
-                               status = SAS_ABORTED_TASK;
-
-                       if (SAS_PROTOCOL_SMP == task->task_proto) {
-                               set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-                               complete_to_host = isci_perform_normal_io_completion;
-                       } else {
-                               clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-                               complete_to_host = isci_perform_error_io_completion;
-                       }
-                       break;
-               }
+               else
+                       clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
                break;
        }
 
@@ -3167,10 +2940,24 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
                break;
        }
 
-       /* Put the completed request on the correct list */
-       isci_task_save_for_upper_layer_completion(ihost, request, response,
-                                                 status, complete_to_host
-                                                 );
+       spin_lock_irqsave(&task->task_state_lock, task_flags);
+
+       task->task_status.resp = response;
+       task->task_status.stat = status;
+
+       if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) {
+               /* Normal notification (task_done) */
+               task->task_state_flags |= SAS_TASK_STATE_DONE;
+               task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+                                           SAS_TASK_STATE_PENDING);
+       }
+       spin_unlock_irqrestore(&task->task_state_lock, task_flags);
+
+       /* Add to the completed list. */
+       list_add(&request->completed_node, &ihost->requests_to_complete);
+
+       /* Take the request off the device's pending request list. */
+       list_del_init(&request->dev_node);
 
        /* complete the io request to the core. */
        sci_controller_complete_io(ihost, request->target_device, request);
@@ -3626,7 +3413,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t
        ireq->num_sg_entries = 0;
        INIT_LIST_HEAD(&ireq->completed_node);
        INIT_LIST_HEAD(&ireq->dev_node);
-       isci_request_change_state(ireq, allocated);
 
        return ireq;
 }
@@ -3721,15 +3507,12 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
         */
        list_add(&ireq->dev_node, &idev->reqs_in_process);
 
-       if (status == SCI_SUCCESS) {
-               isci_request_change_state(ireq, started);
-       } else {
+       if (status != SCI_SUCCESS) {
                /* The request did not really start in the
                 * hardware, so clear the request handle
                 * here so no terminations will be done.
                 */
                set_bit(IREQ_TERMINATED, &ireq->flags);
-               isci_request_change_state(ireq, completed);
        }
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
index 8d55f78010aa869798ffb7aec718e661c09706be..f3116a51235faf74ad29f4a8c17a9c575b6101bb 100644 (file)
 #include "host.h"
 #include "scu_task_context.h"
 
-/**
- * struct isci_request_status - This enum defines the possible states of an I/O
- *    request.
- *
- *
- */
-enum isci_request_status {
-       unallocated = 0x00,
-       allocated   = 0x01,
-       started     = 0x02,
-       completed   = 0x03,
-       aborting    = 0x04,
-       aborted     = 0x05,
-       terminating = 0x06,
-       dead        = 0x07
-};
-
 /**
  * isci_stp_request - extra request infrastructure to handle pio/atapi protocol
  * @pio_len - number of bytes requested at PIO setup
@@ -97,13 +80,13 @@ struct isci_stp_request {
 };
 
 struct isci_request {
-       enum isci_request_status status;
        #define IREQ_COMPLETE_IN_TARGET 0
        #define IREQ_TERMINATED 1
        #define IREQ_TMF 2
        #define IREQ_ACTIVE 3
        #define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
        #define IREQ_TC_ABORT_POSTED 5
+       #define IREQ_ABORT_PATH_ACTIVE 6
        unsigned long flags;
        /* XXX kill ttype and ttype_ptr, allocate full sas_task */
        union ttype_ptr_union {
@@ -115,7 +98,6 @@ struct isci_request {
        struct list_head completed_node;
        /* For use in the reqs_in_process list: */
        struct list_head dev_node;
-       spinlock_t state_lock;
        dma_addr_t request_daddr;
        dma_addr_t zero_scatter_daddr;
        unsigned int num_sg_entries;
@@ -304,92 +286,6 @@ sci_io_request_get_dma_addr(struct isci_request *ireq, void *virt_addr)
        return ireq->request_daddr + (requested_addr - base_addr);
 }
 
-/**
- * isci_request_change_state() - This function sets the status of the request
- *    object.
- * @request: This parameter points to the isci_request object
- * @status: This Parameter is the new status of the object
- *
- */
-static inline enum isci_request_status
-isci_request_change_state(struct isci_request *isci_request,
-                         enum isci_request_status status)
-{
-       enum isci_request_status old_state;
-       unsigned long flags;
-
-       dev_dbg(&isci_request->isci_host->pdev->dev,
-               "%s: isci_request = %p, state = 0x%x\n",
-               __func__,
-               isci_request,
-               status);
-
-       BUG_ON(isci_request == NULL);
-
-       spin_lock_irqsave(&isci_request->state_lock, flags);
-       old_state = isci_request->status;
-       isci_request->status = status;
-       spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
-       return old_state;
-}
-
-/**
- * isci_request_change_started_to_newstate() - This function sets the status of
- *    the request object.
- * @request: This parameter points to the isci_request object
- * @status: This Parameter is the new status of the object
- *
- * state previous to any change.
- */
-static inline enum isci_request_status
-isci_request_change_started_to_newstate(struct isci_request *isci_request,
-                                       struct completion *completion_ptr,
-                                       enum isci_request_status newstate)
-{
-       enum isci_request_status old_state;
-       unsigned long flags;
-
-       spin_lock_irqsave(&isci_request->state_lock, flags);
-
-       old_state = isci_request->status;
-
-       if (old_state == started || old_state == aborting) {
-               BUG_ON(isci_request->io_request_completion != NULL);
-
-               isci_request->io_request_completion = completion_ptr;
-               isci_request->status = newstate;
-       }
-
-       spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
-       dev_dbg(&isci_request->isci_host->pdev->dev,
-               "%s: isci_request = %p, old_state = 0x%x\n",
-               __func__,
-               isci_request,
-               old_state);
-
-       return old_state;
-}
-
-/**
- * isci_request_change_started_to_aborted() - This function sets the status of
- *    the request object.
- * @request: This parameter points to the isci_request object
- * @completion_ptr: This parameter is saved as the kernel completion structure
- *    signalled when the old request completes.
- *
- * state previous to any change.
- */
-static inline enum isci_request_status
-isci_request_change_started_to_aborted(struct isci_request *isci_request,
-                                      struct completion *completion_ptr)
-{
-       return isci_request_change_started_to_newstate(isci_request,
-                                                      completion_ptr,
-                                                      aborted);
-}
-
 #define isci_request_access_task(req) ((req)->ttype_ptr.io_task_ptr)
 
 #define isci_request_access_tmf(req) ((req)->ttype_ptr.tmf_task_ptr)
@@ -399,8 +295,6 @@ struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost,
                                               u16 tag);
 int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
                         struct sas_task *task, u16 tag);
-void isci_terminate_pending_requests(struct isci_host *ihost,
-                                    struct isci_remote_device *idev);
 enum sci_status
 sci_task_request_construct(struct isci_host *ihost,
                            struct isci_remote_device *idev,
index 26de06ef688e3217ebd0a0a469f9430681a79bbf..29ce8815e799de2930087f75ca10f64013d9e524 100644 (file)
@@ -78,54 +78,25 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
                             enum exec_status status)
 
 {
-       enum isci_completion_selection disposition;
+       unsigned long flags;
 
-       disposition = isci_perform_normal_io_completion;
-       disposition = isci_task_set_completion_status(task, response, status,
-                                                     disposition);
+       /* Normal notification (task_done) */
+       dev_dbg(&ihost->pdev->dev, "%s: task = %p, response=%d, status=%d\n",
+               __func__, task, response, status);
 
-       /* Tasks aborted specifically by a call to the lldd_abort_task
-        * 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(&ihost->pdev->dev,
-                       "%s: Normal - task = %p, response=%d, "
-                       "status=%d\n",
-                       __func__, task, response, status);
-
-               task->lldd_task = NULL;
-               task->task_done(task);
-               break;
-
-       case isci_perform_aborted_io_completion:
-               /*
-                * No notification because this request is already in the
-                * abort path.
-                */
-               dev_dbg(&ihost->pdev->dev,
-                       "%s: Aborted - task = %p, response=%d, "
-                       "status=%d\n",
-                       __func__, task, response, status);
-               break;
+       spin_lock_irqsave(&task->task_state_lock, flags);
 
-       case isci_perform_error_io_completion:
-               /* Use sas_task_abort */
-               dev_dbg(&ihost->pdev->dev,
-                       "%s: Error - task = %p, response=%d, "
-                       "status=%d\n",
-                       __func__, task, response, status);
-               sas_task_abort(task);
-               break;
+       task->task_status.resp = response;
+       task->task_status.stat = status;
 
-       default:
-               dev_dbg(&ihost->pdev->dev,
-                       "%s: isci task notification default case!",
-                       __func__);
-               sas_task_abort(task);
-               break;
-       }
+       /* Normal notification (task_done) */
+       task->task_state_flags |= SAS_TASK_STATE_DONE;
+       task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+                                   SAS_TASK_STATE_PENDING);
+       task->lldd_task = NULL;
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+       task->task_done(task);
 }
 
 #define for_each_sas_task(num, task) \
@@ -289,60 +260,6 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost,
        return ireq;
 }
 
-/**
-* isci_request_mark_zombie() - This function must be called with scic_lock held.
-*/
-static void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq)
-{
-       struct completion *tmf_completion = NULL;
-       struct completion *req_completion;
-
-       /* Set the request state to "dead". */
-       ireq->status = dead;
-
-       req_completion = ireq->io_request_completion;
-       ireq->io_request_completion = NULL;
-
-       if (test_bit(IREQ_TMF, &ireq->flags)) {
-               /* Break links with the TMF request. */
-               struct isci_tmf *tmf = isci_request_access_tmf(ireq);
-
-               /* In the case where a task request is dying,
-                * the thread waiting on the complete will sit and
-                * timeout unless we wake it now.  Since the TMF
-                * has a default error status, complete it here
-                * to wake the waiting thread.
-                */
-               if (tmf) {
-                       tmf_completion = tmf->complete;
-                       tmf->complete = NULL;
-               }
-               ireq->ttype_ptr.tmf_task_ptr = NULL;
-               dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n",
-                       __func__, tmf->tmf_code, tmf->io_tag);
-       } else {
-               /* Break links with the sas_task - the callback is done
-                * elsewhere.
-                */
-               struct sas_task *task = isci_request_access_task(ireq);
-
-               if (task)
-                       task->lldd_task = NULL;
-
-               ireq->ttype_ptr.io_task_ptr = NULL;
-       }
-
-       dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n",
-                ireq->io_tag);
-
-       /* Don't force waiting threads to timeout. */
-       if (req_completion)
-               complete(req_completion);
-
-       if (tmf_completion != NULL)
-               complete(tmf_completion);
-}
-
 static int isci_task_execute_tmf(struct isci_host *ihost,
                                 struct isci_remote_device *idev,
                                 struct isci_tmf *tmf, unsigned long timeout_ms)
@@ -400,15 +317,12 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
                spin_unlock_irqrestore(&ihost->scic_lock, flags);
                goto err_tci;
        }
-
-       if (tmf->cb_state_func != NULL)
-               tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data);
-
-       isci_request_change_state(ireq, started);
-
        /* add the request to the remote device request list. */
        list_add(&ireq->dev_node, &idev->reqs_in_process);
 
+       /* The RNC must be unsuspended before the TMF can get a response. */
+       sci_remote_device_resume(idev, NULL, NULL);
+
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
        /* Wait for the TMF to complete, or a timeout. */
@@ -419,32 +333,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
                /* The TMF did not complete - this could be because
                 * of an unplug.  Terminate the TMF request now.
                 */
-               spin_lock_irqsave(&ihost->scic_lock, flags);
-
-               if (tmf->cb_state_func != NULL)
-                       tmf->cb_state_func(isci_tmf_timed_out, tmf,
-                                          tmf->cb_data);
-
-               sci_controller_terminate_request(ihost, idev, ireq);
-
-               spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-               timeleft = wait_for_completion_timeout(
-                       &completion,
-                       msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
-
-               if (!timeleft) {
-                       /* Strange condition - the termination of the TMF
-                        * request timed-out.
-                        */
-                       spin_lock_irqsave(&ihost->scic_lock, flags);
-
-                       /* If the TMF status has not changed, kill it. */
-                       if (tmf->status == SCI_FAILURE_TIMEOUT)
-                               isci_request_mark_zombie(ihost, ireq);
-
-                       spin_unlock_irqrestore(&ihost->scic_lock, flags);
-               }
+               isci_remote_device_suspend_terminate(ihost, idev, ireq);
        }
 
        isci_print_tmf(ihost, tmf);
@@ -476,316 +365,20 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
 }
 
 static void isci_task_build_tmf(struct isci_tmf *tmf,
-                               enum isci_tmf_function_codes code,
-                               void (*tmf_sent_cb)(enum isci_tmf_cb_state,
-                                                   struct isci_tmf *,
-                                                   void *),
-                               void *cb_data)
+                               enum isci_tmf_function_codes code)
 {
        memset(tmf, 0, sizeof(*tmf));
-
-       tmf->tmf_code      = code;
-       tmf->cb_state_func = tmf_sent_cb;
-       tmf->cb_data       = cb_data;
+       tmf->tmf_code = code;
 }
 
 static void isci_task_build_abort_task_tmf(struct isci_tmf *tmf,
                                           enum isci_tmf_function_codes code,
-                                          void (*tmf_sent_cb)(enum isci_tmf_cb_state,
-                                                              struct isci_tmf *,
-                                                              void *),
                                           struct isci_request *old_request)
 {
-       isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request);
+       isci_task_build_tmf(tmf, code);
        tmf->io_tag = old_request->io_tag;
 }
 
-/**
- * isci_task_validate_request_to_abort() - This function checks the given I/O
- *    against the "started" state.  If the request is still "started", it's
- *    state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD
- *    BEFORE CALLING THIS FUNCTION.
- * @isci_request: This parameter specifies the request object to control.
- * @isci_host: This parameter specifies the ISCI host object
- * @isci_device: This is the device to which the request is pending.
- * @aborted_io_completion: This is a completion structure that will be added to
- *    the request in case it is changed to aborting; this completion is
- *    triggered when the request is fully completed.
- *
- * Either "started" on successful change of the task status to "aborted", or
- * "unallocated" if the task cannot be controlled.
- */
-static enum isci_request_status isci_task_validate_request_to_abort(
-       struct isci_request *isci_request,
-       struct isci_host *isci_host,
-       struct isci_remote_device *isci_device,
-       struct completion *aborted_io_completion)
-{
-       enum isci_request_status old_state = unallocated;
-
-       /* Only abort the task if it's in the
-        *  device's request_in_process list
-        */
-       if (isci_request && !list_empty(&isci_request->dev_node)) {
-               old_state = isci_request_change_started_to_aborted(
-                       isci_request, aborted_io_completion);
-
-       }
-
-       return old_state;
-}
-
-static int isci_request_is_dealloc_managed(enum isci_request_status stat)
-{
-       switch (stat) {
-       case aborted:
-       case aborting:
-       case terminating:
-       case completed:
-       case dead:
-               return true;
-       default:
-               return false;
-       }
-}
-
-/**
- * isci_terminate_request_core() - This function will terminate the given
- *    request, and wait for it to complete.  This function must only be called
- *    from a thread that can wait.  Note that the request is terminated and
- *    completed (back to the host, if started there).
- * @ihost: This SCU.
- * @idev: The target.
- * @isci_request: The I/O request to be terminated.
- *
- */
-static void isci_terminate_request_core(struct isci_host *ihost,
-                                       struct isci_remote_device *idev,
-                                       struct isci_request *isci_request)
-{
-       enum sci_status status      = SCI_SUCCESS;
-       bool was_terminated         = false;
-       bool needs_cleanup_handling = false;
-       unsigned long     flags;
-       unsigned long     termination_completed = 1;
-       struct completion *io_request_completion;
-
-       dev_dbg(&ihost->pdev->dev,
-               "%s: device = %p; request = %p\n",
-               __func__, idev, isci_request);
-
-       spin_lock_irqsave(&ihost->scic_lock, flags);
-
-       io_request_completion = isci_request->io_request_completion;
-
-       /* Note that we are not going to control
-        * 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 (!test_bit(IREQ_TERMINATED, &isci_request->flags)) {
-               was_terminated = true;
-               needs_cleanup_handling = true;
-               status = sci_controller_terminate_request(ihost,
-                                                          idev,
-                                                          isci_request);
-       }
-       spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-       /*
-        * The only time the request to terminate will
-        * fail is when the io request is completed and
-        * being aborted.
-        */
-       if (status != SCI_SUCCESS) {
-               dev_dbg(&ihost->pdev->dev,
-                       "%s: sci_controller_terminate_request"
-                       " returned = 0x%x\n",
-                       __func__, status);
-
-               isci_request->io_request_completion = NULL;
-
-       } else {
-               if (was_terminated) {
-                       dev_dbg(&ihost->pdev->dev,
-                               "%s: before completion wait (%p/%p)\n",
-                               __func__, isci_request, io_request_completion);
-
-                       /* Wait here for the request to complete. */
-                       termination_completed
-                               = wait_for_completion_timeout(
-                                  io_request_completion,
-                                  msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
-
-                       if (!termination_completed) {
-
-                               /* The request to terminate has timed out.  */
-                               spin_lock_irqsave(&ihost->scic_lock, flags);
-
-                               /* Check for state changes. */
-                               if (!test_bit(IREQ_TERMINATED,
-                                             &isci_request->flags)) {
-
-                                       /* The best we can do is to have the
-                                        * request die a silent death if it
-                                        * ever really completes.
-                                        */
-                                       isci_request_mark_zombie(ihost,
-                                                                isci_request);
-                                       needs_cleanup_handling = true;
-                               } else
-                                       termination_completed = 1;
-
-                               spin_unlock_irqrestore(&ihost->scic_lock,
-                                                      flags);
-
-                               if (!termination_completed) {
-
-                                       dev_dbg(&ihost->pdev->dev,
-                                               "%s: *** Timeout waiting for "
-                                               "termination(%p/%p)\n",
-                                               __func__, io_request_completion,
-                                               isci_request);
-
-                                       /* The request can no longer be referenced
-                                        * safely since it may go away if the
-                                        * termination every really does complete.
-                                        */
-                                       isci_request = NULL;
-                               }
-                       }
-                       if (termination_completed)
-                               dev_dbg(&ihost->pdev->dev,
-                                       "%s: after completion wait (%p/%p)\n",
-                                       __func__, isci_request, io_request_completion);
-               }
-
-               if (termination_completed) {
-
-                       isci_request->io_request_completion = NULL;
-
-                       /* Peek at the status of the request.  This will tell
-                        * us if there was special handling on the request such that it
-                        * needs to be detached and freed here.
-                        */
-                       spin_lock_irqsave(&isci_request->state_lock, flags);
-
-                       needs_cleanup_handling
-                               = isci_request_is_dealloc_managed(
-                                       isci_request->status);
-
-                       spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
-               }
-               if (needs_cleanup_handling) {
-
-                       dev_dbg(&ihost->pdev->dev,
-                               "%s: cleanup isci_device=%p, request=%p\n",
-                               __func__, idev, isci_request);
-
-                       if (isci_request != NULL) {
-                               spin_lock_irqsave(&ihost->scic_lock, flags);
-                               isci_free_tag(ihost, isci_request->io_tag);
-                               isci_request_change_state(isci_request, unallocated);
-                               list_del_init(&isci_request->dev_node);
-                               spin_unlock_irqrestore(&ihost->scic_lock, flags);
-                       }
-               }
-       }
-}
-
-/**
- * isci_terminate_pending_requests() - This function will change the all of the
- *    requests on the given device's state to "aborting", will terminate the
- *    requests, and wait for them to complete.  This function must only be
- *    called from a thread that can wait.  Note that the requests are all
- *    terminated and completed (back to the host, if started there).
- * @isci_host: This parameter specifies SCU.
- * @idev: This parameter specifies the target.
- *
- */
-void isci_terminate_pending_requests(struct isci_host *ihost,
-                                    struct isci_remote_device *idev)
-{
-       struct completion request_completion;
-       enum isci_request_status old_state;
-       unsigned long flags;
-       LIST_HEAD(list);
-
-       isci_remote_device_suspend(ihost, idev);
-
-       spin_lock_irqsave(&ihost->scic_lock, flags);
-       list_splice_init(&idev->reqs_in_process, &list);
-
-       /* assumes that isci_terminate_request_core deletes from the list */
-       while (!list_empty(&list)) {
-               struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node);
-
-               /* Change state to "terminating" if it is currently
-                * "started".
-                */
-               old_state = isci_request_change_started_to_newstate(ireq,
-                                                                   &request_completion,
-                                                                   terminating);
-               switch (old_state) {
-               case started:
-               case completed:
-               case aborting:
-                       break;
-               default:
-                       /* termination in progress, or otherwise dispositioned.
-                        * We know the request was on 'list' so should be safe
-                        * to move it back to reqs_in_process
-                        */
-                       list_move(&ireq->dev_node, &idev->reqs_in_process);
-                       ireq = NULL;
-                       break;
-               }
-
-               if (!ireq)
-                       continue;
-               spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-               init_completion(&request_completion);
-
-               dev_dbg(&ihost->pdev->dev,
-                        "%s: idev=%p request=%p; task=%p old_state=%d\n",
-                        __func__, idev, ireq,
-                       (!test_bit(IREQ_TMF, &ireq->flags)
-                               ? isci_request_access_task(ireq)
-                               : NULL),
-                       old_state);
-
-               /* If the old_state is started:
-                * This request was not already being aborted. If it had been,
-                * then the aborting I/O (ie. the TMF request) would not be in
-                * the aborting state, and thus would be terminated here.  Note
-                * that since the TMF completion's call to the kernel function
-                * "complete()" does not happen until the pending I/O request
-                * terminate fully completes, we do not have to implement a
-                * special wait here for already aborting requests - the
-                * termination of the TMF request will force the request
-                * to finish it's already started terminate.
-                *
-                * If old_state == completed:
-                * This request completed from the SCU hardware perspective
-                * and now just needs cleaning up in terms of freeing the
-                * request and potentially calling up to libsas.
-                *
-                * If old_state == aborting:
-                * This request has already gone through a TMF timeout, but may
-                * not have been terminated; needs cleaning up at least.
-                */
-               isci_terminate_request_core(ihost, idev, ireq);
-               spin_lock_irqsave(&ihost->scic_lock, flags);
-       }
-       spin_unlock_irqrestore(&ihost->scic_lock, flags);
-}
-
 /**
  * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain
  *    Template functions.
@@ -809,7 +402,7 @@ static int isci_task_send_lu_reset_sas(
         * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or
         * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED").
         */
-       isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL);
+       isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset);
 
        #define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
        ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS);
@@ -829,48 +422,41 @@ static int isci_task_send_lu_reset_sas(
 int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 {
        struct isci_host *ihost = dev_to_ihost(dev);
-       struct isci_remote_device *isci_device;
+       struct isci_remote_device *idev;
        unsigned long flags;
        int ret;
 
        spin_lock_irqsave(&ihost->scic_lock, flags);
-       isci_device = isci_lookup_device(dev);
+       idev = isci_lookup_device(dev);
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
        dev_dbg(&ihost->pdev->dev,
                "%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
-               __func__, dev, ihost, isci_device);
+               __func__, dev, ihost, idev);
 
-       if (!isci_device) {
+       if (!idev) {
                /* If the device is gone, escalate to I_T_Nexus_Reset. */
                dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__);
 
                ret = TMF_RESP_FUNC_FAILED;
                goto out;
        }
-       if (isci_remote_device_suspend(ihost, isci_device) != SCI_SUCCESS) {
-               dev_dbg(&ihost->pdev->dev,
-                       "%s:  device = %p; failed to suspend\n",
-                       __func__, isci_device);
-               ret = TMF_RESP_FUNC_FAILED;
-               goto out;
-       }
 
-       /* Send the task management part of the reset. */
        if (dev_is_sata(dev)) {
                sas_ata_schedule_reset(dev);
                ret = TMF_RESP_FUNC_COMPLETE;
-       } else
-               ret = isci_task_send_lu_reset_sas(ihost, isci_device, lun);
-
-       /* If the LUN reset worked, all the I/O can now be terminated. */
-       if (ret == TMF_RESP_FUNC_COMPLETE) {
-               /* Terminate all I/O now. */
-               isci_terminate_pending_requests(ihost, isci_device);
-               isci_remote_device_resume(ihost, isci_device, NULL, NULL);
+       } else {
+               /* Suspend the RNC, kill all TCs */
+               if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+                   != SCI_SUCCESS) {
+                       ret = TMF_RESP_FUNC_FAILED;
+                       goto out;
+               }
+               /* Send the task management part of the reset. */
+               ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
        }
  out:
-       isci_put_device(isci_device);
+       isci_put_device(idev);
        return ret;
 }
 
@@ -890,63 +476,6 @@ int isci_task_clear_nexus_ha(struct sas_ha_struct *ha)
 
 /* Task Management Functions. Must be called from process context.      */
 
-/**
- * isci_abort_task_process_cb() - This is a helper function for the abort task
- *    TMF command.  It manages the request state with respect to the successful
- *    transmission / completion of the abort task request.
- * @cb_state: This parameter specifies when this function was called - after
- *    the TMF request has been started and after it has timed-out.
- * @tmf: This parameter specifies the TMF in progress.
- *
- *
- */
-static void isci_abort_task_process_cb(
-       enum isci_tmf_cb_state cb_state,
-       struct isci_tmf *tmf,
-       void *cb_data)
-{
-       struct isci_request *old_request;
-
-       old_request = (struct isci_request *)cb_data;
-
-       dev_dbg(&old_request->isci_host->pdev->dev,
-               "%s: tmf=%p, old_request=%p\n",
-               __func__, tmf, old_request);
-
-       switch (cb_state) {
-
-       case isci_tmf_started:
-               /* The TMF has been started.  Nothing to do here, since the
-                * request state was already set to "aborted" by the abort
-                * task function.
-                */
-               if ((old_request->status != aborted)
-                       && (old_request->status != completed))
-                       dev_dbg(&old_request->isci_host->pdev->dev,
-                               "%s: Bad request status (%d): tmf=%p, old_request=%p\n",
-                               __func__, old_request->status, tmf, old_request);
-               break;
-
-       case isci_tmf_timed_out:
-
-               /* Set the task's state to "aborting", since the abort task
-                * function thread set it to "aborted" (above) in anticipation
-                * of the task management request working correctly.  Since the
-                * timeout has now fired, the TMF request failed.  We set the
-                * state such that the request completion will indicate the
-                * device is no longer present.
-                */
-               isci_request_change_state(old_request, aborting);
-               break;
-
-       default:
-               dev_dbg(&old_request->isci_host->pdev->dev,
-                       "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n",
-                       __func__, cb_state, tmf, old_request);
-               break;
-       }
-}
-
 /**
  * isci_task_abort_task() - This function is one of the SAS Domain Template
  *    functions. This function is called by libsas to abort a specified task.
@@ -956,22 +485,20 @@ static void isci_abort_task_process_cb(
  */
 int isci_task_abort_task(struct sas_task *task)
 {
-       struct isci_host *isci_host = dev_to_ihost(task->dev);
+       struct isci_host *ihost = dev_to_ihost(task->dev);
        DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
        struct isci_request       *old_request = NULL;
-       enum isci_request_status  old_state;
-       struct isci_remote_device *isci_device = NULL;
+       struct isci_remote_device *idev = NULL;
        struct isci_tmf           tmf;
        int                       ret = TMF_RESP_FUNC_FAILED;
        unsigned long             flags;
-       int                       perform_termination = 0;
 
        /* Get the isci_request reference from the task.  Note that
         * this check does not depend on the pending request list
         * in the device, because tasks driving resets may land here
         * after completion in the core.
         */
-       spin_lock_irqsave(&isci_host->scic_lock, flags);
+       spin_lock_irqsave(&ihost->scic_lock, flags);
        spin_lock(&task->task_state_lock);
 
        old_request = task->lldd_task;
@@ -980,20 +507,20 @@ int isci_task_abort_task(struct sas_task *task)
        if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
            (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
            old_request)
-               isci_device = isci_lookup_device(task->dev);
+               idev = isci_lookup_device(task->dev);
 
        spin_unlock(&task->task_state_lock);
-       spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+       spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-       dev_warn(&isci_host->pdev->dev,
-               "%s: dev = %p, task = %p, old_request == %p\n",
-               __func__, isci_device, task, old_request);
+       dev_warn(&ihost->pdev->dev,
+                "%s: dev = %p, task = %p, old_request == %p\n",
+                __func__, idev, task, old_request);
 
        /* Device reset conditions signalled in task_state_flags are the
         * responsbility of libsas to observe at the start of the error
         * handler thread.
         */
-       if (!isci_device || !old_request) {
+       if (!idev || !old_request) {
                /* The request has already completed and there
                * is nothing to do here other than to set the task
                * done bit, and indicate that the task abort function
@@ -1007,126 +534,66 @@ int isci_task_abort_task(struct sas_task *task)
 
                ret = TMF_RESP_FUNC_COMPLETE;
 
-               dev_warn(&isci_host->pdev->dev,
-                       "%s: abort task not needed for %p\n",
-                       __func__, task);
+               dev_warn(&ihost->pdev->dev,
+                        "%s: abort task not needed for %p\n",
+                        __func__, task);
                goto out;
        }
-
-       spin_lock_irqsave(&isci_host->scic_lock, flags);
-
-       /* Check the request status and change to "aborted" if currently
-        * "starting"; if true then set the I/O kernel completion
-        * struct that will be triggered when the request completes.
-        */
-       old_state = isci_task_validate_request_to_abort(
-                               old_request, isci_host, isci_device,
-                               &aborted_io_completion);
-       if ((old_state != started) &&
-           (old_state != completed) &&
-           (old_state != aborting)) {
-
-               spin_unlock_irqrestore(&isci_host->scic_lock, flags);
-
-               /* The request was already being handled by someone else (because
-               * they got to set the state away from started).
-               */
-               dev_warn(&isci_host->pdev->dev,
-                       "%s:  device = %p; old_request %p already being aborted\n",
-                       __func__,
-                       isci_device, old_request);
-               ret = TMF_RESP_FUNC_COMPLETE;
+       /* Suspend the RNC, kill the TC */
+       if (isci_remote_device_suspend_terminate(ihost, idev, old_request)
+           != SCI_SUCCESS) {
+               dev_warn(&ihost->pdev->dev,
+                        "%s: isci_remote_device_reset_terminate(dev=%p, "
+                                "req=%p, task=%p) failed\n",
+                        __func__, idev, old_request, task);
+               ret = TMF_RESP_FUNC_FAILED;
                goto out;
        }
+       spin_lock_irqsave(&ihost->scic_lock, flags);
+
        if (task->task_proto == SAS_PROTOCOL_SMP ||
            sas_protocol_ata(task->task_proto) ||
            test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
 
-               spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+               /* No task to send, so explicitly resume the device here */
+               sci_remote_device_resume(idev, NULL, NULL);
 
-               dev_warn(&isci_host->pdev->dev,
-                       "%s: %s request"
-                       " or complete_in_target (%d), thus no TMF\n",
-                       __func__,
-                       ((task->task_proto == SAS_PROTOCOL_SMP)
-                               ? "SMP"
-                               : (sas_protocol_ata(task->task_proto)
-                                       ? "SATA/STP"
-                                       : "<other>")
-                        ),
-                       test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));
-
-               if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
-                       spin_lock_irqsave(&task->task_state_lock, flags);
-                       task->task_state_flags |= SAS_TASK_STATE_DONE;
-                       task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
-                                                   SAS_TASK_STATE_PENDING);
-                       spin_unlock_irqrestore(&task->task_state_lock, flags);
-                       ret = TMF_RESP_FUNC_COMPLETE;
-               } else {
-                       spin_lock_irqsave(&task->task_state_lock, flags);
-                       task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
-                                                   SAS_TASK_STATE_PENDING);
-                       spin_unlock_irqrestore(&task->task_state_lock, flags);
-               }
+               spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-               /* STP and SMP devices are not sent a TMF, but the
-                * outstanding I/O request is terminated below.  This is
-                * because SATA/STP and SMP discovery path timeouts directly
-                * call the abort task interface for cleanup.
-                */
-               perform_termination = 1;
-
-               if (isci_device && !test_bit(IDEV_GONE, &isci_device->flags) &&
-                   (isci_remote_device_suspend(isci_host, isci_device)
-                    != SCI_SUCCESS)) {
-                       dev_warn(&isci_host->pdev->dev,
-                               "%s:  device = %p; failed to suspend\n",
-                               __func__, isci_device);
-                       goto out;
-               }
+               dev_warn(&ihost->pdev->dev,
+                        "%s: %s request"
+                                " or complete_in_target (%d), thus no TMF\n",
+                        __func__,
+                        ((task->task_proto == SAS_PROTOCOL_SMP)
+                         ? "SMP"
+                         : (sas_protocol_ata(task->task_proto)
+                               ? "SATA/STP"
+                               : "<other>")
+                         ),
+                        test_bit(IREQ_COMPLETE_IN_TARGET,
+                                 &old_request->flags));
 
+               spin_lock_irqsave(&task->task_state_lock, flags);
+               task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+                                           SAS_TASK_STATE_PENDING);
+               task->task_state_flags |= SAS_TASK_STATE_DONE;
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+               ret = TMF_RESP_FUNC_COMPLETE;
        } else {
                /* Fill in the tmf stucture */
                isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
-                                              isci_abort_task_process_cb,
                                               old_request);
 
-               spin_unlock_irqrestore(&isci_host->scic_lock, flags);
-
-               if (isci_remote_device_suspend(isci_host, isci_device)
-                   != SCI_SUCCESS) {
-                       dev_warn(&isci_host->pdev->dev,
-                               "%s:  device = %p; failed to suspend\n",
-                               __func__, isci_device);
-                       goto out;
-               }
+               spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
+               /* Send the task management request. */
                #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
-               ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
+               ret = isci_task_execute_tmf(ihost, idev, &tmf,
                                            ISCI_ABORT_TASK_TIMEOUT_MS);
-
-               if (ret == TMF_RESP_FUNC_COMPLETE)
-                       perform_termination = 1;
-               else
-                       dev_warn(&isci_host->pdev->dev,
-                               "%s: isci_task_send_tmf failed\n", __func__);
-       }
-       if (perform_termination) {
-               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.
-                */
-               isci_terminate_request_core(isci_host, isci_device,
-                                           old_request);
-               isci_remote_device_resume(isci_host, isci_device, NULL, NULL);
        }
-
-       /* Make sure we do not leave a reference to aborted_io_completion */
-       old_request->io_request_completion = NULL;
- out:
-       isci_put_device(isci_device);
+out:
+       isci_put_device(idev);
        return ret;
 }
 
@@ -1222,14 +689,11 @@ isci_task_request_complete(struct isci_host *ihost,
 {
        struct isci_tmf *tmf = isci_request_access_tmf(ireq);
        struct completion *tmf_complete = NULL;
-       struct completion *request_complete = ireq->io_request_completion;
 
        dev_dbg(&ihost->pdev->dev,
                "%s: request = %p, status=%d\n",
                __func__, ireq, completion_status);
 
-       isci_request_change_state(ireq, completed);
-
        set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags);
 
        if (tmf) {
@@ -1253,20 +717,8 @@ isci_task_request_complete(struct isci_host *ihost,
         */
        set_bit(IREQ_TERMINATED, &ireq->flags);
 
-       /* As soon as something is in the terminate path, deallocation is
-        * managed there.  Note that the final non-managed state of a task
-        * request is "completed".
-        */
-       if ((ireq->status == completed) ||
-           !isci_request_is_dealloc_managed(ireq->status)) {
-               isci_request_change_state(ireq, unallocated);
-               isci_free_tag(ihost, ireq->io_tag);
-               list_del_init(&ireq->dev_node);
-       }
-
-       /* "request_complete" is set if the task was being terminated. */
-       if (request_complete)
-               complete(request_complete);
+       isci_free_tag(ihost, ireq->io_tag);
+       list_del_init(&ireq->dev_node);
 
        /* The task management part completes last. */
        if (tmf_complete)
@@ -1277,37 +729,37 @@ static int isci_reset_device(struct isci_host *ihost,
                             struct domain_device *dev,
                             struct isci_remote_device *idev)
 {
-       int rc;
-       enum sci_status status;
+       int rc = TMF_RESP_FUNC_COMPLETE, reset_stat;
        struct sas_phy *phy = sas_get_local_phy(dev);
        struct isci_port *iport = dev->port->lldd_port;
 
        dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
 
-       if (isci_remote_device_reset(ihost, idev) != SCI_SUCCESS) {
+       /* Suspend the RNC, terminate all outstanding TCs. */
+       if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+           != SCI_SUCCESS) {
                rc = TMF_RESP_FUNC_FAILED;
                goto out;
        }
+       /* Note that since the termination for outstanding requests succeeded,
+        * this function will return success.  This is because the resets will
+        * only fail if the device has been removed (ie. hotplug), and the
+        * primary duty of this function is to cleanup tasks, so that is the
+        * relevant status.
+        */
 
        if (scsi_is_sas_phy_local(phy)) {
                struct isci_phy *iphy = &ihost->phys[phy->number];
 
-               rc = isci_port_perform_hard_reset(ihost, iport, iphy);
+               reset_stat = isci_port_perform_hard_reset(ihost, iport, iphy);
        } else
-               rc = sas_phy_reset(phy, !dev_is_sata(dev));
+               reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
 
-       /* Terminate in-progress I/O now. */
-       isci_remote_device_nuke_requests(ihost, idev);
-
-       /* Since all pending TCs have been cleaned, resume the RNC. */
-       status = isci_remote_device_reset_complete(ihost, idev);
-
-       if (status != SCI_SUCCESS)
-               dev_dbg(&ihost->pdev->dev,
-                        "%s: isci_remote_device_reset_complete(%p) "
-                        "returned %d!\n", __func__, idev, status);
+       /* Explicitly resume the RNC here, since there was no task sent. */
+       isci_remote_device_resume(ihost, idev, NULL, NULL);
 
-       dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
+       dev_dbg(&ihost->pdev->dev, "%s: idev %p complete, reset_stat=%d.\n",
+               __func__, idev, reset_stat);
  out:
        sas_put_local_phy(phy);
        return rc;
@@ -1321,7 +773,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
        int ret;
 
        spin_lock_irqsave(&ihost->scic_lock, flags);
-       idev = isci_get_device(dev);
+       idev = isci_get_device(dev->lldd_dev);
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
        if (!idev) {
index 7b6d0e32fd9bc75720da20df9f2a12c04034b59a..9c06cbad1d26cad25e99a3cc4a33969193379ca7 100644 (file)
 
 struct isci_request;
 
-/**
- * enum isci_tmf_cb_state - This enum defines the possible states in which the
- *    TMF callback function is invoked during the TMF execution process.
- *
- *
- */
-enum isci_tmf_cb_state {
-
-       isci_tmf_init_state = 0,
-       isci_tmf_started,
-       isci_tmf_timed_out
-};
-
 /**
  * enum isci_tmf_function_codes - This enum defines the possible preparations
  *    of task management requests.
@@ -87,6 +74,7 @@ enum isci_tmf_function_codes {
        isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
        isci_tmf_ssp_lun_reset  = TMF_LU_RESET,
 };
+
 /**
  * struct isci_tmf - This class represents the task management object which
  *    acts as an interface to libsas for processing task management requests
@@ -106,15 +94,6 @@ struct isci_tmf {
        u16 io_tag;
        enum isci_tmf_function_codes tmf_code;
        int status;
-
-       /* The optional callback function allows the user process to
-        * track the TMF transmit / timeout conditions.
-        */
-       void (*cb_state_func)(
-               enum isci_tmf_cb_state,
-               struct isci_tmf *, void *);
-       void *cb_data;
-
 };
 
 static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf)
@@ -208,113 +187,4 @@ int isci_queuecommand(
        struct scsi_cmnd *scsi_cmd,
        void (*donefunc)(struct scsi_cmnd *));
 
-/**
- * enum isci_completion_selection - This enum defines the possible actions to
- *    take with respect to a given request's notification back to libsas.
- *
- *
- */
-enum isci_completion_selection {
-
-       isci_perform_normal_io_completion,      /* Normal notify (task_done) */
-       isci_perform_aborted_io_completion,     /* No notification.   */
-       isci_perform_error_io_completion        /* Use sas_task_abort */
-};
-
-/**
- * isci_task_set_completion_status() - This function sets the completion status
- *    for the request.
- * @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.
- *
-* @return The new notification mode for the request.
-*/
-static inline enum isci_completion_selection
-isci_task_set_completion_status(
-       struct sas_task *task,
-       enum service_response response,
-       enum exec_status status,
-       enum isci_completion_selection task_notification_selection)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&task->task_state_lock, flags);
-
-       /* If a device reset is being indicated, make sure the I/O
-       * is in the error path.
-       */
-       if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
-               /* Fail the I/O to make sure it goes into the error path. */
-               response = SAS_TASK_UNDELIVERED;
-               status = SAM_STAT_TASK_ABORTED;
-
-               task_notification_selection = isci_perform_error_io_completion;
-       }
-       task->task_status.resp = response;
-       task->task_status.stat = status;
-
-       switch (task->task_proto) {
-
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-
-               if (task_notification_selection
-                   == isci_perform_error_io_completion) {
-                       /* SATA/STP I/O has it's own means of scheduling device
-                       * error handling on the normal path.
-                       */
-                       task_notification_selection
-                               = isci_perform_normal_io_completion;
-               }
-               break;
-       default:
-               break;
-       }
-
-       switch (task_notification_selection) {
-
-       case isci_perform_error_io_completion:
-
-               if (task->task_proto == SAS_PROTOCOL_SMP) {
-                       /* There is no error escalation in the SMP case.
-                        * Convert to a normal completion to avoid the
-                        * timeout in the discovery path and to let the
-                        * next action take place quickly.
-                        */
-                       task_notification_selection
-                               = isci_perform_normal_io_completion;
-
-                       /* Fall through to the normal case... */
-               } else {
-                       /* Use sas_task_abort */
-                       /* Leave SAS_TASK_STATE_DONE clear
-                        * Leave SAS_TASK_AT_INITIATOR set.
-                        */
-                       break;
-               }
-
-       case isci_perform_aborted_io_completion:
-               /* This path can occur with task-managed requests as well as
-                * requests terminated because of LUN or device resets.
-                */
-               /* Fall through to the normal case... */
-       case isci_perform_normal_io_completion:
-               /* Normal notification (task_done) */
-               task->task_state_flags |= SAS_TASK_STATE_DONE;
-               task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
-                                           SAS_TASK_STATE_PENDING);
-               break;
-       default:
-               WARN_ONCE(1, "unknown task_notification_selection: %d\n",
-                        task_notification_selection);
-               break;
-       }
-
-       spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-       return task_notification_selection;
-
-}
 #endif /* !defined(_SCI_TASK_H_) */