/**
 * @brief This method will allocate the internal IO request object and
 *        construct its contents based upon the supplied SMP request.
 *
 * @param[in] fw_controller This parameter specifies the controller object
 *            from which to allocate the internal IO request.
 * @param[in] fw_device This parameter specifies the remote device for
 *            which the internal IO request is destined.
 * @param[in] smp_request This parameter specifies the SMP request contents
 *            to be sent to the SMP target.
 *
 * @return void * The address of built scif sas smp request.
 */
static
void * scif_sas_smp_request_build(
   SCIF_SAS_CONTROLLER_T    * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   SMP_REQUEST_T            * smp_request,
   void                     * external_request_object,
   void                     * external_memory
)
{
   if (external_memory != NULL && external_request_object != NULL)
   {
      scif_sas_io_request_construct_smp(
         fw_controller,
         fw_device,
         external_memory,
         (char *)external_memory + sizeof(SCIF_SAS_IO_REQUEST_T),
         SCI_CONTROLLER_INVALID_IO_TAG,
         smp_request,
         external_request_object
      );

      return external_memory;
   }
   else
   {
      void * internal_io_memory;
      internal_io_memory = scif_sas_controller_allocate_internal_request(fw_controller);
      ASSERT(internal_io_memory != NULL);

      if (internal_io_memory != NULL)
      {
         //construct, only when we got valid io memory.
         scif_sas_internal_io_request_construct_smp(
            fw_controller,
            fw_device,
            internal_io_memory,
            SCI_CONTROLLER_INVALID_IO_TAG,
            smp_request
         );
      }
      else
      {
         SCIF_LOG_ERROR((
            sci_base_object_get_logger(fw_controller),
            SCIF_LOG_OBJECT_IO_REQUEST,
            "scif_sas_smp_request_build, no memory available!\n"
         ));
      }

      return internal_io_memory;
   }
}
/**
* @brief This method implements the actions taken when entering the
*        READY NCQ ERROR substate.  This includes setting the state
*        handler methods.
*
* @param[in]  object This parameter specifies the base object for which
*             the state transition is occurring.  This is cast into a
*             SCIF_SAS_REMOTE_DEVICE object in the method implementation.
*
* @return none
*/
static
void scif_sas_remote_device_ready_ncq_error_substate_enter(
   SCI_BASE_OBJECT_T *object
)
{
   SCIF_SAS_REMOTE_DEVICE_T         * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
   SCI_STATUS                         status = SCI_SUCCESS;
   SCI_TASK_REQUEST_HANDLE_T          handle;
   SCIF_SAS_CONTROLLER_T            * fw_controller = fw_device->domain->controller;
   SCIF_SAS_TASK_REQUEST_T          * fw_task_request;
   SCIF_SAS_REQUEST_T               * fw_request;
   void                             * internal_task_memory;
   SCIF_SAS_DOMAIN_T                * fw_domain = fw_device->domain;
   SCI_FAST_LIST_ELEMENT_T          * pending_request_element;
   SCIF_SAS_REQUEST_T               * pending_request = NULL;

   SET_STATE_HANDLER(
      fw_device,
      scif_sas_remote_device_ready_substate_handler_table,
      SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR
   );

   internal_task_memory = scif_sas_controller_allocate_internal_request(fw_controller);
   ASSERT(internal_task_memory != NULL);

   fw_task_request = (SCIF_SAS_TASK_REQUEST_T*)internal_task_memory;

   fw_request = &fw_task_request->parent;

   //construct the scif io request
   status = scif_sas_internal_task_request_construct(
      fw_controller,
      fw_device,
      SCI_CONTROLLER_INVALID_IO_TAG,
      (void *)fw_task_request,
      &handle,
      SCI_SAS_ABORT_TASK_SET
   );

   pending_request_element = fw_domain->request_list.list_head;

   // Cycle through the fast list of IO requests.  Mark each request
   //  pending to this remote device so that they are not completed
   //  to the operating system when the request is terminated, but
   //  rather when the abort task set completes.
   while (pending_request_element != NULL)
   {
      pending_request =
         (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(pending_request_element);

      // The current element may be deleted from the list because of
      // IO completion so advance to the next element early
      pending_request_element = sci_fast_list_get_next(pending_request_element);

      if (pending_request->device == fw_device)
      {
         pending_request->is_waiting_for_abort_task_set = TRUE;
      }
   }

   scif_controller_start_task(
      fw_controller,
      fw_device,
      fw_request,
      SCI_CONTROLLER_INVALID_IO_TAG
   );
}