linux-scsi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dan Williams <dan.j.williams@intel.com>
To: linux-scsi@vger.kernel.org
Cc: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Subject: [isci-rnc PATCH v1 03/37] isci: Handle all suspending TC completions
Date: Thu, 22 Mar 2012 17:28:04 -0700	[thread overview]
Message-ID: <20120323002804.18065.27045.stgit@dwillia2-linux.jf.intel.com> (raw)
In-Reply-To: <20120323002504.18065.45709.stgit@dwillia2-linux.jf.intel.com>

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

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        |   86 ++++++++---------
 drivers/scsi/isci/remote_device.h        |    4 -
 drivers/scsi/isci/remote_node_context.c  |   74 ++++++++++-----
 drivers/scsi/isci/remote_node_context.h  |   13 ++-
 drivers/scsi/isci/request.c              |  149 ++++++++++++++++++++++++++++--
 drivers/scsi/isci/request.h              |    1 
 drivers/scsi/isci/scu_completion_codes.h |    2 
 7 files changed, 242 insertions(+), 87 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 71f5090..b1a8000 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -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,
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 4850b58..3915905 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -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);
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 3e84975..f180c72 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -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;
 }
 
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index a241e0f..276fc49 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -75,8 +75,12 @@
  */
 #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,
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 3384ead..847d971 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -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);
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 4961f9f..e845a31 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -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_) */
diff --git a/drivers/scsi/isci/scu_completion_codes.h b/drivers/scsi/isci/scu_completion_codes.h
index c8b329c..071cb74 100644
--- a/drivers/scsi/isci/scu_completion_codes.h
+++ b/drivers/scsi/isci/scu_completion_codes.h
@@ -224,6 +224,7 @@
  * 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)
@@ -237,6 +238,7 @@
 #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)


  parent reply	other threads:[~2012-03-23  0:12 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
2012-03-23  0:27 ` [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions Dan Williams
2012-03-23  0:27 ` [isci-rnc PATCH v1 02/37] isci: Fixed bug in resumption from RNC Tx/Rx suspend state Dan Williams
2012-03-23  0:28 ` Dan Williams [this message]
2012-03-23  0:28 ` [isci-rnc PATCH v1 04/37] isci: Terminate outstanding TCs on TX/RX RNC suspensions Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 05/37] isci: Manage device suspensions during TC terminations Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 06/37] isci: Remote device must be suspended for NCQ cleanup Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 07/37] isci: Remote device stop also suspends the RNC and terminates I/O Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 08/37] isci: Escalate to I_T_Nexus_Reset when the device is gone Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 09/37] isci: Redesign device suspension, abort, cleanup Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 10/37] isci: Add suspension cases for RNC INVALIDATING, POSTING states Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 11/37] isci: Device access in the error path does not depend on IDEV_GONE Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 12/37] isci: All pending TCs are terminated when the RNC is invalidated Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 13/37] isci: Only set IDEV_GONE in the device stop path Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 14/37] isci: Remove isci_device reqs_in_process and dev_node from isci_device Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 15/37] isci: Distinguish between remote device suspension cases Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 16/37] isci: Fix the terminated I/O to not call sas_task_abort() Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 17/37] isci: Save the suspension hint for upcoming suspensions Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 18/37] isci: Manage the LLHANG timer enable/disable per-device Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 19/37] isci: Make sure all TCs are terminated and cleaned in LUN reset Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 20/37] isci: Implement waiting for suspend in the abort path Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 21/37] isci: When in the abort path, defeat other resume calls until done Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 22/37] isci: Callbacks to libsas occur under scic_lock and are synchronized Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 23/37] isci: Manage tag releases differently when aborting tasks Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 24/37] isci: Fix RNC suspend call for SCI_RESUMING state Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 25/37] isci: Wait for RNC resumption before leaving the abort path Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 26/37] isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 27/37] isci: Add protocol indicator for TMF requests Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 28/37] isci: Added timeouts to RNC suspensions in the abort path Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 29/37] isci: Change the phy control and link reset interface for HW reasons Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 30/37] isci: Don't wait for an RNC suspend if it's being destroyed Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 31/37] isci: Restore the ATAPI device RNC management code Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 32/37] isci: Check IDEV_GONE before performing abort path operations Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 33/37] isci: Remove obviated host callback list Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 34/37] isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 35/37] isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 36/37] isci: Fixed RNC bug that lost the suspension or resumption during destroy Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 37/37] isci: End the RNC resumption wait when the RNC is destroyed Dan Williams

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120323002804.18065.27045.stgit@dwillia2-linux.jf.intel.com \
    --to=dan.j.williams@intel.com \
    --cc=jeffrey.d.skirvin@intel.com \
    --cc=linux-scsi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).