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 scis_sds_remote_node_context_states state; state = sci_rnc->sm.current_state_id; if (state != SCI_RNC_READY) { 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) { sci_remote_device_post_request(rnc_to_dev(sci_rnc), SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX); } sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); return SCI_SUCCESS; }
static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) { union scu_remote_node_context *rnc_buffer; struct isci_remote_device *idev = rnc_to_dev(sci_rnc); struct domain_device *dev = idev->domain_dev; struct isci_host *ihost = idev->owning_port->owning_controller; rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index); rnc_buffer->ssp.is_valid = true; if (dev_is_sata(dev) && dev->parent) { sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96); } else { sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32); if (!dev->parent) sci_port_setup_transports(idev->owning_port, sci_rnc->remote_node_index); } }
static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_node_context *sci_rnc) { union scu_remote_node_context *rnc_buffer; struct isci_remote_device *idev = rnc_to_dev(sci_rnc); struct isci_host *ihost = idev->owning_port->owning_controller; rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index); rnc_buffer->ssp.is_valid = false; sci_remote_device_post_request(rnc_to_dev(sci_rnc), SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE); }
static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) { union scu_remote_node_context *rnc_buffer; struct isci_remote_device *idev = rnc_to_dev(sci_rnc); struct domain_device *dev = idev->domain_dev; struct isci_host *ihost = idev->owning_port->owning_controller; rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index); rnc_buffer->ssp.is_valid = true; if (!idev->is_direct_attached && (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) { sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96); } else { sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32); if (idev->is_direct_attached) sci_port_setup_transports(idev->owning_port, sci_rnc->remote_node_index); } }
static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_machine *sm) { struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); struct isci_remote_device *idev; struct domain_device *dev; idev = rnc_to_dev(rnc); dev = idev->domain_dev; if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) && idev->is_direct_attached) sci_port_setup_transports(idev->owning_port, rnc->remote_node_index); sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME); }
static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_machine *sm) { struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); struct isci_remote_device *idev; struct domain_device *dev; idev = rnc_to_dev(rnc); dev = idev->domain_dev; /* * For direct attached SATA devices we need to clear the TLCR * NCQ to TCi tag mapping on the phy and in cases where we * resume because of a target reset we also need to update * the STPTLDARNI register with the RNi of the device */ if (dev_is_sata(dev) && !dev->parent) sci_port_setup_transports(idev->owning_port, rnc->remote_node_index); sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME); }
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) { 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; enum sci_remote_node_context_destination_state dest_param = RNC_DEST_UNSPECIFIED; dev_dbg(scirdev_to_dev(idev), "%s: current state %s, current suspend_type %x dest state %d," " arg suspend_reason %d, arg suspend_type %x", __func__, rnc_state_name(state), sci_rnc->suspend_type, sci_rnc->destination_state, suspend_reason, suspend_type); /* Disable automatic state continuations if explicitly suspending. */ if ((suspend_reason == SCI_HW_SUSPEND) || (sci_rnc->destination_state == RNC_DEST_FINAL)) dest_param = sci_rnc->destination_state; switch (state) { case SCI_RNC_READY: break; case SCI_RNC_INVALIDATING: if (sci_rnc->destination_state == RNC_DEST_FINAL) { dev_warn(scirdev_to_dev(idev), "%s: already destroying %p\n", __func__, sci_rnc); return SCI_FAILURE_INVALID_STATE; } /* Fall through and handle like SCI_RNC_POSTING */ case SCI_RNC_RESUMING: /* Fall through and handle like SCI_RNC_POSTING */ case SCI_RNC_POSTING: /* Set the destination state to AWAIT - this signals the * entry into the SCI_RNC_READY state that a suspension * needs to be done immediately. */ if (sci_rnc->destination_state != RNC_DEST_FINAL) sci_rnc->destination_state = RNC_DEST_SUSPENDED; sci_rnc->suspend_type = suspend_type; sci_rnc->suspend_reason = suspend_reason; return SCI_SUCCESS; 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->destination_state = dest_param; sci_rnc->suspend_type = suspend_type; sci_rnc->suspend_reason = suspend_reason; if (status == SCI_SUCCESS) { /* Already in the destination state? */ struct isci_host *ihost = idev->owning_port->owning_controller; wake_up_all(&ihost->eventq); /* Let observers look. */ return SCI_SUCCESS; } if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) || (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) { if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT) 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); return SCI_SUCCESS; }