/**
 *
 * @param[in] device This is the SCI base object which is cast into a
 *       SCIC_SDS_REMOTE_DEVICE object.
 *
 * @return none
 */
static
void scic_sds_stp_remote_device_ready_idle_substate_enter(
   SCI_BASE_OBJECT_T * device
)
{
   SCIC_SDS_REMOTE_DEVICE_T * this_device;

   this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device;

   SET_STATE_HANDLER(
      this_device,
      scic_sds_stp_remote_device_ready_substate_handler_table,
      SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE
   );

   this_device->working_request = NULL;

   if (scic_sds_remote_node_context_is_ready(this_device->rnc))
   {
      // Since the RNC is ready, it's alright to finish completion
      // processing (e.g. signal the remote device is ready).
      scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler(
         this_device
      );
   }
   else
   {
      scic_sds_remote_node_context_resume(
         this_device->rnc,
         scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler,
         this_device
      );
   }
}
/**
 * This method will handle the event for a ATAPI device that is in
 * the ATAPI ERROR state. We pick up suspension events to handle specifically
 * to this state. We resume the RNC right away. We then complete the outstanding
 * IO to this device.
 *
 * @param [in] device The device received event.
 * @param [in] event_code The event code.
 *
 * @return SCI_STATUS
 */
static
SCI_STATUS scic_sds_stp_remote_device_ready_atapi_error_substate_event_handler(
   SCIC_SDS_REMOTE_DEVICE_T * this_device,
   U32                        event_code
)
{
   SCI_STATUS status;

   status = scic_sds_remote_device_general_event_handler(this_device, event_code);

   if (status == SCI_SUCCESS)
   {
      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 = scic_sds_remote_node_context_resume(
                     this_device->rnc,
                     (SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK)
                        this_device->working_request->state_handlers->parent.complete_handler,
                     (void *)this_device->working_request
                  );
      }
   }

   return status;
}
/**
* This method will report a success or failure attempt to start a new task
* request to the hardware.  Since all task requests are sent on the high
* priority queue they can be sent when the RCN is in a TX suspend state.
*
* @param[in] this_rnc The remote node context which is to receive the task
*       request.
* @param[in] the_request The task request to be transmitted to to the remote
*       target device.
*
* @return SCI_STATUS
* @retval SCI_SUCCESS
*/
static
SCI_STATUS scic_sds_remote_node_context_suspended_start_task_handler(
   struct SCIC_SDS_REMOTE_NODE_CONTEXT * this_rnc,
   struct SCIC_SDS_REQUEST             * the_request
)
{
   scic_sds_remote_node_context_resume(this_rnc, NULL, NULL);

   return SCI_SUCCESS;
}
/**
 * This method will handle the event for a sata device that is in
 * the idle state. We pick up suspension events to handle specifically
 * to this state. We resume the RNC right away.
 *
 * @param [in] device The device received event.
 * @param [in] event_code The event code.
 *
 * @return SCI_STATUS
 */
static
SCI_STATUS scic_sds_stp_remote_device_ready_idle_substate_event_handler(
   SCIC_SDS_REMOTE_DEVICE_T * this_device,
   U32                        event_code
)
{
   SCI_STATUS status;

   status = scic_sds_remote_device_general_event_handler(this_device, event_code);

   if (status == SCI_SUCCESS)
   {
      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)
          && (this_device->rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY))
      {
         status = scic_sds_remote_node_context_resume(
                  this_device->rnc, NULL, NULL);
      }
   }

   return status;
}
/**
 * This is the READY NCQ substate handler to start task management request. In this
 * routine, we suspend and resume the RNC.
 *
 * @param[in] device The target device a task management request towards to.
 * @param[in] request The task request.
 *
 * @return SCI_STATUS Always return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS status
 *     to let controller_start_task_handler know that the controller can't post TC for
 *     task request yet, instead, when RNC gets resumed, a controller_continue_task
 *     callback will be called.
 */
static
SCI_STATUS scic_sds_stp_remote_device_ready_substate_start_request_handler(
   SCI_BASE_REMOTE_DEVICE_T * device,
   SCI_BASE_REQUEST_T       * request
)
{
   SCI_STATUS status;
   SCIC_SDS_REMOTE_DEVICE_T * this_device  = (SCIC_SDS_REMOTE_DEVICE_T *)device;
   SCIC_SDS_REQUEST_T       * this_request = (SCIC_SDS_REQUEST_T       *)request;

   // Will the port allow the io request to start?
   status = this_device->owning_port->state_handlers->start_io_handler(
      this_device->owning_port,
      this_device,
      this_request
   );

   if (SCI_SUCCESS == status)
   {
      status =
         scic_sds_remote_node_context_start_task(this_device->rnc, this_request);

      if (SCI_SUCCESS == status)
      {
         status = this_request->state_handlers->parent.start_handler(request);
      }

      if (status == SCI_SUCCESS)
      {
         /// @note If the remote device state is not IDLE this will replace
         ///       the request that probably resulted in the task management
         ///       request.
         this_device->working_request = this_request;

         sci_base_state_machine_change_state(
            &this_device->ready_substate_machine,
            SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD
         );

         //The remote node context must cleanup the TCi to NCQ mapping table.
         //The only way to do this correctly is to either write to the TLCR
         //register or to invalidate and repost the RNC. In either case the
         //remote node context state machine will take the correct action when
         //the remote node context is suspended and later resumed.
         scic_sds_remote_node_context_suspend(
            this_device->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL);

         scic_sds_remote_node_context_resume(
            this_device->rnc,
            (SCIC_SDS_REMOTE_NODE_CONTEXT_CALLBACK)
                scic_sds_remote_device_continue_request,
            this_device);
      }

      scic_sds_remote_device_start_request(this_device,this_request,status);

      //We need to let the controller start request handler know that it can't
      //post TC yet. We will provide a callback function to post TC when RNC gets
      //resumed.
      return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS;
   }

   return status;
}