]> Pileus Git - ~andy/linux/commitdiff
isci: Handle all suspending TC completions
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>
Fri, 9 Mar 2012 06:41:50 +0000 (22:41 -0800)
committerDan Williams <dan.j.williams@intel.com>
Thu, 17 May 2012 21:33:37 +0000 (14:33 -0700)
Add comprehensive decode for all TC completions that generate RNC
suspensions.

Note that this commit also removes unconditional resumptions of ATAPI
devices when in the SCI_STP_DEV_ATAPI_ERROR state, and STP devices
when in the SCI_STP_DEV_IDLE state. This is because the SCI_STP_DEV_IDLE
and SCI_STP_DEV_ATAPI state entry functions manage the RNC resumption.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
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/scu_completion_codes.h

index 71f5090647379e51a85a9aa1b5437f2672ba640e..b1a8000a5ef86f87467de71ed89878c917ee7ade 100644 (file)
@@ -265,20 +265,12 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
        return SCI_SUCCESS;
 }
 
-enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
-                                              u32 suspend_type)
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
 {
-       struct sci_base_state_machine *sm = &idev->sm;
-       enum sci_remote_device_states state = sm->current_state_id;
-
-       if (state != SCI_STP_DEV_CMD) {
-               dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
-                        __func__, dev_state_name(state));
-               return SCI_FAILURE_INVALID_STATE;
-       }
-
        return sci_remote_node_context_suspend(&idev->rnc,
-                                                   suspend_type, NULL, NULL);
+                                              SCI_SOFTWARE_SUSPENSION,
+                                              SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
+                                              NULL, NULL);
 }
 
 enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
@@ -412,8 +404,6 @@ static void atapi_remote_device_resume_done(void *_dev)
 enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
                                                     u32 event_code)
 {
-       struct sci_base_state_machine *sm = &idev->sm;
-       enum sci_remote_device_states state = sm->current_state_id;
        enum sci_status status;
 
        switch (scu_get_event_type(event_code)) {
@@ -427,9 +417,11 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
                        status = SCI_SUCCESS;
 
                        /* Suspend the associated RNC */
-                       sci_remote_node_context_suspend(&idev->rnc,
-                                                             SCI_SOFTWARE_SUSPENSION,
-                                                             NULL, NULL);
+                       sci_remote_node_context_suspend(
+                               &idev->rnc,
+                               SCI_SOFTWARE_SUSPENSION,
+                               SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
+                               NULL, NULL);
 
                        dev_dbg(scirdev_to_dev(idev),
                                "%s: device: %p event code: %x: %s\n",
@@ -455,26 +447,6 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
        if (status != SCI_SUCCESS)
                return status;
 
-       if (state == SCI_STP_DEV_ATAPI_ERROR) {
-               /* For ATAPI error state resume the RNC right away. */
-               if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
-                   scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) {
-                       return sci_remote_node_context_resume(&idev->rnc,
-                                                             atapi_remote_device_resume_done,
-                                                             idev);
-               }
-       }
-
-       if (state == SCI_STP_DEV_IDLE) {
-
-               /* We pick up suspension events to handle specifically to this
-                * state. We resume the RNC right away.
-                */
-               if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
-                   scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX)
-                       status = sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
-       }
-
        return status;
 }
 
@@ -765,11 +737,11 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
                 * the correct action when the remote node context is suspended
                 * and later resumed.
                 */
-               sci_remote_node_context_suspend(&idev->rnc,
-                               SCI_SOFTWARE_SUSPENSION, NULL, NULL);
-               sci_remote_node_context_resume(&idev->rnc,
-                               sci_remote_device_continue_request,
-                                                   idev);
+               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);
 
        out:
                sci_remote_device_start_request(idev, ireq, status);
@@ -954,14 +926,23 @@ static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm
 static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm)
 {
        struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+       struct isci_host *ihost = idev->owning_port->owning_controller;
+
+       dev_dbg(&ihost->pdev->dev,
+               "%s: isci_device = %p\n", __func__, idev);
 
        sci_remote_node_context_suspend(
-               &idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL);
+               &idev->rnc, SCI_SOFTWARE_SUSPENSION,
+               SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
 }
 
 static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm)
 {
        struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+       struct isci_host *ihost = idev->owning_port->owning_controller;
+
+       dev_dbg(&ihost->pdev->dev,
+               "%s: isci_device = %p\n", __func__, idev);
 
        sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
 }
@@ -1004,6 +985,21 @@ static void sci_stp_remote_device_ready_ncq_error_substate_enter(struct sci_base
                                             idev->not_ready_reason);
 }
 
+static void sci_stp_remote_device_atapi_error_substate_enter(
+       struct sci_base_state_machine *sm)
+{
+       struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+
+       /* This state is entered when an I/O is decoded with an error
+        * condition.  By this point the RNC expected suspension state is set.
+        * The error conditions suspend the device, so unsuspend here if
+        * possible.
+        */
+       sci_remote_node_context_resume(&idev->rnc,
+                                      atapi_remote_device_resume_done,
+                                      idev);
+}
+
 static void sci_smp_remote_device_ready_idle_substate_enter(struct sci_base_state_machine *sm)
 {
        struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
@@ -1054,7 +1050,9 @@ static const struct sci_base_state sci_remote_device_state_table[] = {
        [SCI_STP_DEV_NCQ_ERROR] = {
                .enter_state = sci_stp_remote_device_ready_ncq_error_substate_enter,
        },
-       [SCI_STP_DEV_ATAPI_ERROR] = { },
+       [SCI_STP_DEV_ATAPI_ERROR] = {
+               .enter_state = sci_stp_remote_device_atapi_error_substate_enter,
+       },
        [SCI_STP_DEV_AWAIT_RESET] = { },
        [SCI_SMP_DEV_IDLE] = {
                .enter_state = sci_smp_remote_device_ready_idle_substate_enter,
index 4850b58edbe69cf06a44aa6b7c65796bbfe8f26a..39159053b7ff80e9d46ef1bd2410e5eaaa4dfc89 100644 (file)
@@ -331,10 +331,6 @@ enum sci_status sci_remote_device_complete_io(
        struct isci_remote_device *idev,
        struct isci_request *ireq);
 
-enum sci_status sci_remote_device_suspend(
-       struct isci_remote_device *idev,
-       u32 suspend_type);
-
 void sci_remote_device_post_request(
        struct isci_remote_device *idev,
        u32 request);
index 3e849752bffa225c6a482ea852ae503616ac63ac..f180c726c5bb1aaac1c908bc3846cad77dc6561d 100644 (file)
@@ -367,6 +367,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
                                                           u32 event_code)
 {
        enum scis_sds_remote_node_context_states state;
+       u32 next_state;
 
        state = sci_rnc->sm.current_state_id;
        switch (state) {
@@ -425,11 +426,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
                switch (scu_get_event_type(event_code)) {
                case SCU_EVENT_TL_RNC_SUSPEND_TX:
                        sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
-                       sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+                       sci_rnc->suspend_type = scu_get_event_type(event_code);
                        break;
                case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
                        sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
-                       sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+                       sci_rnc->suspend_type = scu_get_event_type(event_code);
                        break;
                default:
                        goto out;
@@ -438,16 +439,16 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
        case SCI_RNC_AWAIT_SUSPENSION:
                switch (scu_get_event_type(event_code)) {
                case SCU_EVENT_TL_RNC_SUSPEND_TX:
-                       sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
-                       sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+                       next_state = SCI_RNC_TX_SUSPENDED;
                        break;
                case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
-                       sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
-                       sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+                       next_state = SCI_RNC_TX_RX_SUSPENDED;
                        break;
                default:
                        goto out;
                }
+               if (sci_rnc->suspend_type == scu_get_event_type(event_code))
+                       sci_change_state(&sci_rnc->sm, next_state);
                break;
        default:
                dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
@@ -502,33 +503,60 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
        }
 }
 
-enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
-                                                    u32 suspend_type,
-                                                    scics_sds_remote_node_context_callback cb_fn,
-                                                    void *cb_p)
+enum sci_status sci_remote_node_context_suspend(
+                       struct sci_remote_node_context *sci_rnc,
+                       enum sci_remote_node_suspension_reasons suspend_reason,
+                       u32 suspend_type,
+                       scics_sds_remote_node_context_callback cb_fn,
+                       void *cb_p)
 {
-       enum scis_sds_remote_node_context_states state;
+       enum scis_sds_remote_node_context_states state
+               = sci_rnc->sm.current_state_id;
+       struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
+       enum sci_status status = SCI_FAILURE_INVALID_STATE;
 
-       state = sci_rnc->sm.current_state_id;
-       if (state != SCI_RNC_READY) {
+       /* Disable automatic state continuations if explicitly suspending. */
+       if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
+               sci_rnc->destination_state
+                       = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+       switch (state) {
+       case SCI_RNC_READY:
+               break;
+       case SCI_RNC_TX_SUSPENDED:
+               if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX)
+                       status = SCI_SUCCESS;
+               break;
+       case SCI_RNC_TX_RX_SUSPENDED:
+               if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
+                       status = SCI_SUCCESS;
+               break;
+       case SCI_RNC_AWAIT_SUSPENSION:
+               if ((sci_rnc->suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
+                   || (suspend_type == sci_rnc->suspend_type))
+                       return SCI_SUCCESS;
+               break;
+       default:
                dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
                         "%s: invalid state %s\n", __func__,
                         rnc_state_name(state));
                return SCI_FAILURE_INVALID_STATE;
        }
+       sci_rnc->user_callback = cb_fn;
+       sci_rnc->user_cookie   = cb_p;
+       sci_rnc->suspend_type  = suspend_type;
 
-       sci_rnc->user_callback   = cb_fn;
-       sci_rnc->user_cookie     = cb_p;
-       sci_rnc->suspension_code = suspend_type;
-
-       if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
-               sci_remote_device_post_request(rnc_to_dev(sci_rnc),
-                                                   SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
-               isci_dev_set_hang_detection_timeout(rnc_to_dev(sci_rnc),
-                                                   0x00000001);
+       if (status == SCI_SUCCESS) { /* Already in the destination state? */
+               sci_remote_node_context_notify_user(sci_rnc);
+               return SCI_SUCCESS;
+       }
+       if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
+               isci_dev_set_hang_detection_timeout(idev, 0x00000001);
+               sci_remote_device_post_request(
+                       idev, SCI_SOFTWARE_SUSPEND_CMD);
        }
+       if (state != SCI_RNC_AWAIT_SUSPENSION)
+               sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
 
-       sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
        return SCI_SUCCESS;
 }
 
index a241e0f4c865246406c8cb741b026962748aff32..276fc491e8f9c587eaf786c7d8d208bc3a1605a2 100644 (file)
  */
 #define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX    0x0FFF
 
-#define SCU_HARDWARE_SUSPENSION  (0)
-#define SCI_SOFTWARE_SUSPENSION  (1)
+enum sci_remote_node_suspension_reasons {
+       SCU_HARDWARE_SUSPENSION,
+       SCI_SOFTWARE_SUSPENSION
+};
+#define SCI_SOFTWARE_SUSPEND_CMD SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX
+#define SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT SCU_EVENT_TL_RNC_SUSPEND_TX_RX
 
 struct isci_request;
 struct isci_remote_device;
@@ -156,10 +160,10 @@ struct sci_remote_node_context {
        u16 remote_node_index;
 
        /**
-        * This field is the recored suspension code or the reason for the remote node
+        * This field is the recored suspension type of the remote node
         * context suspension.
         */
-       u32 suspension_code;
+       u32 suspend_type;
 
        /**
         * This field is true if the remote node context is resuming from its current
@@ -200,6 +204,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
                                                      void *callback_parameter);
 enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
                                                     u32 suspend_type,
+                                                    u32 suspension_code,
                                                     scics_sds_remote_node_context_callback cb_fn,
                                                     void *cb_p);
 enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,
index dcd26eadf867339ec9e3c22ba9f1df14c77cbecc..605dc68cbf7926764eff08eb27ddee20b381d6c0 100644 (file)
@@ -2116,9 +2116,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
                 * completion.
                 */
                if (ireq->stp.rsp.fis_type == FIS_REGD2H) {
-                       sci_remote_device_suspend(ireq->target_device,
-                               SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code)));
-
                        ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
                        ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
                        sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
@@ -2138,13 +2135,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
        /* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR
         * - this comes only for B0
         */
-       case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN):
-       case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR):
-       case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR):
-       case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR):
-               sci_remote_device_suspend(ireq->target_device,
-                       SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code)));
-               /* Fall through to the default case */
        default:
                /* All other completion status cause the IO to be complete. */
                ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
@@ -2262,15 +2252,152 @@ static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ire
        return status;
 }
 
+static int sci_request_smp_completion_status_is_tx_suspend(
+       unsigned int completion_status)
+{
+       switch (completion_status) {
+       case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+       case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+       case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+               return 1;
+       }
+       return 0;
+}
+
+static int sci_request_smp_completion_status_is_tx_rx_suspend(
+       unsigned int completion_status)
+{
+       return 0; /* There are no Tx/Rx SMP suspend conditions. */
+}
+
+static int sci_request_ssp_completion_status_is_tx_suspend(
+       unsigned int completion_status)
+{
+       switch (completion_status) {
+       case SCU_TASK_DONE_TX_RAW_CMD_ERR:
+       case SCU_TASK_DONE_LF_ERR:
+       case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+       case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+       case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+       case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+       case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+       case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+               return 1;
+       }
+       return 0;
+}
+
+static int sci_request_ssp_completion_status_is_tx_rx_suspend(
+       unsigned int completion_status)
+{
+       return 0; /* There are no Tx/Rx SSP suspend conditions. */
+}
+
+static int sci_request_stpsata_completion_status_is_tx_suspend(
+       unsigned int completion_status)
+{
+       switch (completion_status) {
+       case SCU_TASK_DONE_TX_RAW_CMD_ERR:
+       case SCU_TASK_DONE_LL_R_ERR:
+       case SCU_TASK_DONE_LL_PERR:
+       case SCU_TASK_DONE_REG_ERR:
+       case SCU_TASK_DONE_SDB_ERR:
+       case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+       case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+       case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+       case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+       case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+       case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+       case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+               return 1;
+       }
+       return 0;
+}
+
+
+static int sci_request_stpsata_completion_status_is_tx_rx_suspend(
+       unsigned int completion_status)
+{
+       switch (completion_status) {
+       case SCU_TASK_DONE_LF_ERR:
+       case SCU_TASK_DONE_LL_SY_TERM:
+       case SCU_TASK_DONE_LL_LF_TERM:
+       case SCU_TASK_DONE_BREAK_RCVD:
+       case SCU_TASK_DONE_INV_FIS_LEN:
+       case SCU_TASK_DONE_UNEXP_FIS:
+       case SCU_TASK_DONE_UNEXP_SDBFIS:
+       case SCU_TASK_DONE_MAX_PLD_ERR:
+               return 1;
+       }
+       return 0;
+}
+
+static void sci_request_handle_suspending_completions(
+       struct isci_request *ireq,
+       u32 completion_code)
+{
+       int is_tx = 0;
+       int is_tx_rx = 0;
+
+       switch (ireq->protocol) {
+       case SAS_PROTOCOL_SMP:
+               is_tx = sci_request_smp_completion_status_is_tx_suspend(
+                       completion_code);
+               is_tx_rx = sci_request_smp_completion_status_is_tx_rx_suspend(
+                       completion_code);
+               break;
+       case SAS_PROTOCOL_SSP:
+               is_tx = sci_request_ssp_completion_status_is_tx_suspend(
+                       completion_code);
+               is_tx_rx = sci_request_ssp_completion_status_is_tx_rx_suspend(
+                       completion_code);
+               break;
+       case SAS_PROTOCOL_STP:
+               is_tx = sci_request_stpsata_completion_status_is_tx_suspend(
+                       completion_code);
+               is_tx_rx =
+                       sci_request_stpsata_completion_status_is_tx_rx_suspend(
+                               completion_code);
+               break;
+       default:
+               dev_warn(&ireq->isci_host->pdev->dev,
+                        "%s: request %p has no valid protocol\n",
+                        __func__, ireq);
+               break;
+       }
+       if (is_tx || is_tx_rx) {
+               BUG_ON(is_tx && is_tx_rx);
+
+               sci_remote_node_context_suspend(
+                       &ireq->target_device->rnc,
+                       SCU_HARDWARE_SUSPENSION,
+                       (is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX
+                                  : SCU_EVENT_TL_RNC_SUSPEND_TX,
+                       NULL, NULL);
+       }
+}
+
 enum sci_status
 sci_io_request_tc_completion(struct isci_request *ireq,
-                                 u32 completion_code)
+                            u32 completion_code)
 {
        enum sci_base_request_states state;
        struct isci_host *ihost = ireq->owning_controller;
 
        state = ireq->sm.current_state_id;
 
+       /* Decode those completions that signal upcoming suspension events. */
+       sci_request_handle_suspending_completions(
+               ireq, SCU_GET_COMPLETION_TL_STATUS(completion_code));
+
        switch (state) {
        case SCI_REQ_STARTED:
                return request_started_state_tc_event(ireq, completion_code);
index 4961f9fbf70fec8ea706d6a464b6da356170bba5..e845a31ecebbfcd73e945ebad05c917a273d44f5 100644 (file)
@@ -414,5 +414,4 @@ static inline int isci_task_is_ncq_recovery(struct sas_task *task)
                task->ata_task.fis.lbal == ATA_LOG_SATA_NCQ);
 
 }
-
 #endif /* !defined(_ISCI_REQUEST_H_) */
index c8b329c695f9ca7487b6995947d70eb933d7dfc7..071cb74a211c80d87da83f36a356f784cdd186b1 100644 (file)
  * 32-bit value like we want, each immediate value must be cast to a u32.
  */
 #define SCU_TASK_DONE_GOOD                                  ((u32)0x00)
+#define SCU_TASK_DONE_TX_RAW_CMD_ERR                        ((u32)0x08)
 #define SCU_TASK_DONE_CRC_ERR                               ((u32)0x14)
 #define SCU_TASK_DONE_CHECK_RESPONSE                        ((u32)0x14)
 #define SCU_TASK_DONE_GEN_RESPONSE                          ((u32)0x15)
 #define SCU_TASK_DONE_LL_LF_TERM                            ((u32)0x1A)
 #define SCU_TASK_DONE_DATA_LEN_ERR                          ((u32)0x1A)
 #define SCU_TASK_DONE_LL_CL_TERM                            ((u32)0x1B)
+#define SCU_TASK_DONE_BREAK_RCVD                            ((u32)0x1B)
 #define SCU_TASK_DONE_LL_ABORT_ERR                          ((u32)0x1B)
 #define SCU_TASK_DONE_SEQ_INV_TYPE                          ((u32)0x1C)
 #define SCU_TASK_DONE_UNEXP_XR                              ((u32)0x1C)