+
+enum sci_status scic_sds_remote_node_context_suspend(struct scic_sds_remote_node_context *sci_rnc,
+ u32 suspend_type,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p)
+{
+ enum scis_sds_remote_node_context_states state;
+
+ state = sci_rnc->state_machine.current_state_id;
+ if (state != SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE) {
+ dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+ "%s: invalid state %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+
+ sci_rnc->user_callback = cb_fn;
+ sci_rnc->user_cookie = cb_p;
+ sci_rnc->suspension_code = suspend_type;
+
+ if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
+ scic_sds_remote_device_post_request(rnc_to_dev(sci_rnc),
+ SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
+ }
+
+ sci_base_state_machine_change_state(&sci_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE);
+ return SCI_SUCCESS;
+}
+
+enum sci_status scic_sds_remote_node_context_resume(struct scic_sds_remote_node_context *sci_rnc,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p)
+{
+ enum scis_sds_remote_node_context_states state;
+
+ state = sci_rnc->state_machine.current_state_id;
+ switch (state) {
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE:
+ if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
+ return SCI_FAILURE_INVALID_STATE;
+
+ scic_sds_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+ scic_sds_remote_node_context_construct_buffer(sci_rnc);
+ sci_base_state_machine_change_state(&sci_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE);
+ return SCI_SUCCESS;
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE:
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE:
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE:
+ if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY)
+ return SCI_FAILURE_INVALID_STATE;
+
+ sci_rnc->user_callback = cb_fn;
+ sci_rnc->user_cookie = cb_p;
+ return SCI_SUCCESS;
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE: {
+ struct scic_sds_remote_device *sci_dev = rnc_to_dev(sci_rnc);
+ struct domain_device *dev = sci_dev_to_domain(sci_dev);
+
+ scic_sds_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+
+ /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */
+ if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev))
+ sci_base_state_machine_change_state(&sci_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE);
+ else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
+ if (sci_dev->is_direct_attached) {
+ /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */
+ sci_base_state_machine_change_state(&sci_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE);
+ } else {
+ sci_base_state_machine_change_state(&sci_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE);
+ }
+ } else
+ return SCI_FAILURE;
+ return SCI_SUCCESS;
+ }
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE:
+ scic_sds_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+ sci_base_state_machine_change_state(&sci_rnc->state_machine,
+ SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE);
+ return SCI_FAILURE_INVALID_STATE;
+ case SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE:
+ scic_sds_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+ return SCI_SUCCESS;
+ default:
+ dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+ "%s: invalid state %d\n", __func__, state);
+ return SCI_FAILURE_INVALID_STATE;
+ }
+}