summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/isci/remote_device.c49
-rw-r--r--drivers/scsi/isci/remote_device.h2
-rw-r--r--drivers/scsi/isci/request.c3
3 files changed, 34 insertions, 20 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 68ab4fb9032e..48765aa84328 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -72,8 +72,8 @@ const char *dev_state_name(enum sci_remote_device_states state)
}
#undef C
-static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
- enum sci_remote_node_suspension_reasons reason)
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+ enum sci_remote_node_suspension_reasons reason)
{
return sci_remote_node_context_suspend(&idev->rnc, reason,
SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
@@ -565,6 +565,8 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
u32 event_code)
{
enum sci_status status;
+ struct sci_base_state_machine *sm = &idev->sm;
+ enum sci_remote_device_states state = sm->current_state_id;
switch (scu_get_event_type(event_code)) {
case SCU_EVENT_TYPE_RNC_OPS_MISC:
@@ -603,6 +605,30 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
if (status != SCI_SUCCESS)
return status;
+ /* Decode device-specific states that may require an RNC resume during
+ * normal operation. When the abort path is active, these resumes are
+ * managed when the abort path exits.
+ */
+ 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;
}
@@ -1137,21 +1163,6 @@ 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);
@@ -1202,9 +1213,7 @@ 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] = {
- .enter_state = sci_stp_remote_device_atapi_error_substate_enter,
- },
+ [SCI_STP_DEV_ATAPI_ERROR] = { },
[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 ff34c4e8c1b1..7674caae1d88 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -382,4 +382,6 @@ enum sci_status isci_remote_device_terminate_requests(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+ enum sci_remote_node_suspension_reasons reason);
#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 415d5f55d1c6..6c530e4275e2 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2118,6 +2118,9 @@ 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,
+ SCI_SW_SUSPEND_NORMAL);
+
ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);