Skip to content

Commit

Permalink
isci: Handle all suspending TC completions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jeff Skirvin authored and Dan Williams committed May 17, 2012
1 parent 56d7c01 commit ac78ed0
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 87 deletions.
86 changes: 42 additions & 44 deletions drivers/scsi/isci/remote_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)) {
Expand All @@ -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",
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 0 additions & 4 deletions drivers/scsi/isci/remote_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
74 changes: 51 additions & 23 deletions drivers/scsi/isci/remote_node_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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)),
Expand Down Expand Up @@ -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;
}

Expand Down
13 changes: 9 additions & 4 deletions drivers/scsi/isci/remote_node_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit ac78ed0

Please sign in to comment.