/**
 * @brief This method provides STOPPING state specific handling for
 *        when the core remote device object issues a stop completion
 *        notification.
 *
 * @note There is no need to ensure all IO/Task requests are complete
 *       before transitioning to the STOPPED state.  The SCI Core will
 *       ensure this is accomplished.
 *
 * @param[in]  remote_device This parameter specifies the remote device
 *             object for which the completion occurred.
 * @param[in]  completion_status This parameter specifies the status
 *             of the completion operation.
 *
 * @return none.
 */
static
void scif_sas_remote_device_stopping_stop_complete_handler(
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   SCI_STATUS                 completion_status
)
{
   // Transition directly to the STOPPED state since the core ensures
   // all IO/Tasks are complete.
   sci_base_state_machine_change_state(
      &fw_device->parent.state_machine,
      SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
   );

   if (completion_status != SCI_SUCCESS)
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_device),
         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
         "Device:0x%x Status:0x%x failed to stop core device\n",
         fw_device, completion_status
      ));

      // Something is seriously wrong.  Stopping the core remote device
      // shouldn't fail in anyway.
      scif_cb_controller_error(fw_device->domain->controller,
              SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
   }
}
/**
 * @brief This method implements the actions taken when entering the
 *        FAILED state.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_CONTROLLER object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_controller_failed_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;

   SCIF_LOG_ERROR((
      sci_base_object_get_logger(fw_controller),
      SCIF_LOG_OBJECT_CONTROLLER,
      "Controller: entered FAILED state.\n"
   ));

   SET_STATE_HANDLER(
      fw_controller,
      scif_sas_controller_state_handler_table,
      SCI_BASE_CONTROLLER_STATE_FAILED
   );

   if (fw_controller->parent.error != SCI_CONTROLLER_FATAL_MEMORY_ERROR)
   {
       //clean timers to avoid timer leak.
       scif_sas_controller_release_resource(fw_controller);

       //notify user.
       scif_cb_controller_error(fw_controller, fw_controller->parent.error);
   }
}
Example #3
0
/**
 * @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;
   }
}
Example #4
0
/**
 * @brief This method provides DEFAULT handling for when the user
 *        attempts to destruct the supplied IO request.
 *
 * @param[in] io_request This parameter specifies the IO request object
 *            to be destructed.
 *
 * @return This method returns an indication that destruct operation is
 *         not allowed.
 * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
 */
SCI_STATUS scif_sas_io_request_default_destruct_handler(
   SCI_BASE_REQUEST_T * io_request
)
{
   SCIF_LOG_ERROR((
      sci_base_object_get_logger((SCIF_SAS_IO_REQUEST_T *) io_request),
      SCIF_LOG_OBJECT_IO_REQUEST,
      "IoRequest:0x%x State:0x%x invalid state to destruct.\n",
      io_request,
      sci_base_state_machine_get_state(
         &((SCIF_SAS_IO_REQUEST_T *) io_request)->parent.parent.state_machine)
   ));

   return SCI_FAILURE_INVALID_STATE;
}
Example #5
0
/**
 * @brief This method provides DEFAULT handling for when the user
 *        attempts to destruct the supplied task request.
 *
 * @param[in] task_request This parameter specifies the task request object
 *            to be destructed.
 *
 * @return This method returns an indication that destruct operation is
 *         not allowed.
 * @retval SCI_FAILURE_INVALID_STATE This value is always returned.
 */
static
SCI_STATUS scif_sas_task_request_default_destruct_handler(
   SCI_BASE_REQUEST_T * task_request
)
{
   SCIF_LOG_ERROR((
      sci_base_object_get_logger((SCIF_SAS_TASK_REQUEST_T *) task_request),
      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
      "TaskRequest:0x%x State:0x%x invalid state to destruct.\n",
      task_request,
      sci_base_state_machine_get_state(
         &((SCIF_SAS_TASK_REQUEST_T *) task_request)->parent.parent.state_machine)
   ));

   return SCI_FAILURE_INVALID_STATE;
}
/**
 * @file
 *
 * @brief This file contains the method implementations for the
 *        SCIF_SAS_STP_TASK_REQUEST object.  The contents will implement
 *        SATA/STP specific functionality.
 */
SCI_STATUS scif_sas_stp_task_request_construct(
   SCIF_SAS_TASK_REQUEST_T * fw_task
)
{
   SCI_STATUS                 sci_status = SCI_FAILURE;

#if !defined(DISABLE_SATI_TASK_MANAGEMENT)
   SATI_STATUS                sati_status;
   SCIF_SAS_REMOTE_DEVICE_T * fw_device  = fw_task->parent.device;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_task),
      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
      "scif_sas_stp_task_request_construct(0x%x) enter\n",
      fw_task
   ));

   // The translator will indirectly invoke core methods to set the fields
   // of the ATA register FIS inside of this method.
   sati_status = sati_translate_task_management(
                    &fw_task->parent.stp.sequence,
                    &fw_device->protocol_device.stp_device.sati_device,
                    fw_task,
                    fw_task
                 );

   if (sati_status == SATI_SUCCESS)
   {
      sci_status = scic_task_request_construct_sata(fw_task->parent.core_object);
      //fw_task->parent.state_handlers = &stp_io_request_constructed_handlers;
      fw_task->parent.protocol_complete_handler =
         scif_sas_stp_core_cb_task_request_complete_handler;
   }
   else
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_task),
         SCIF_LOG_OBJECT_TASK_MANAGEMENT,
         "Task 0x%x received unexpected SAT translation failure 0x%x\n",
         fw_task, sati_status
      ));
   }
#endif // !defined(DISABLE_SATI_TASK_MANAGEMENT)

   return sci_status;
}
/**
 * @brief This method will construct the STP PACKET protocol specific IO
 *        request object.
 *
 * @pre The scif_sas_request_construct() method should be invoked before
 *      calling this method.
 *
 * @param[in,out] fw_io This parameter specifies the stp packet io request
 *                to be constructed.
 *
 * @return Indicate if the construction was successful.
 * @return SCI_SUCCESS_IO_COMPLETE_BEFORE_START
 * @return SCI_FAILURE_IO_RESPONSE_VALID
 * @return SCI_FAILURE This return value indicates a change in the translator
 *         where a new return code has been given, but is not yet understood
 *         by this routine.
 */
SCI_STATUS scif_sas_stp_packet_io_request_construct(
   SCIF_SAS_IO_REQUEST_T * fw_io
)
{
   SATI_STATUS                sati_status;
   SCI_STATUS                 sci_status = SCI_FAILURE;
   SCIF_SAS_REMOTE_DEVICE_T * fw_device  = fw_io->parent.device;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_io),
      SCIF_LOG_OBJECT_IO_REQUEST,
      "scif_sas_stp_packet_io_request_construct(0x%x) enter\n",
      fw_io
   ));

   sati_status = sati_atapi_translate_command(
                    &fw_io->parent.stp.sequence,
                    &fw_device->protocol_device.stp_device.sati_device,
                    fw_io,
                    fw_io
                 );

   if (sati_status == SATI_SUCCESS)
   {
      // Allow the core to finish construction of the IO request.
      sci_status = scic_io_request_construct_basic_sata(fw_io->parent.core_object);

      fw_io->parent.protocol_complete_handler
         = scif_sas_stp_core_cb_packet_io_request_complete_handler;
   }
   else if (sati_status == SATI_COMPLETE)
      sci_status = SCI_SUCCESS_IO_COMPLETE_BEFORE_START;
   else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
      sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
   else
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_io),
         SCIF_LOG_OBJECT_IO_REQUEST,
         "Unexpected SAT ATAPI translation failure 0x%x\n",
         fw_io
      ));
   }

   return sci_status;
}
/**
 * @brief This method will attempt to handle an operation timeout (i.e.
 *        discovery or reset).
 *
 * @param[in]  cookie This parameter specifies the domain in which the
 *             timeout occurred.
 *
 * @return none
 */
static
void scif_sas_domain_operation_timeout_handler(
   void * cookie
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
   U32                 state;

   state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);

   // Based upon the state of the domain, we know whether we were in the
   // process of performing discovery or a reset.
   if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
   {
      SCIF_LOG_WARNING((
         sci_base_object_get_logger(fw_domain),
         SCIF_LOG_OBJECT_DOMAIN,
         "Domain:0x%x State:0x%x DISCOVER timeout!\n",
         fw_domain, state
      ));

      fw_domain->operation.status = SCI_FAILURE_TIMEOUT;

      //search all the smp devices in the domain and cancel their activities
      //if there is any outstanding activity remained. The smp devices will terminate
      //all the started internal IOs.
      scif_sas_domain_cancel_smp_activities(fw_domain);

      scif_sas_domain_continue_discover(fw_domain);
   }
   else
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_domain),
         SCIF_LOG_OBJECT_DOMAIN,
         "Domain:0x%x State:0x%x operation timeout in invalid state\n",
         fw_domain, state
      ));
   }
}
/**
 * @brief This method implements the actions taken when entering the
 *        RESETTING state.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_CONTROLLER object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_controller_resetting_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)object;

   SET_STATE_HANDLER(
      fw_controller,
      scif_sas_controller_state_handler_table,
      SCI_BASE_CONTROLLER_STATE_RESETTING
   );

   // Attempt to reset the core controller.
   fw_controller->operation_status = scic_controller_reset(
                                        fw_controller->core_object
                                     );
   if (fw_controller->operation_status == SCI_SUCCESS)
   {
      // Reset the framework controller.
      sci_base_state_machine_change_state(
         &fw_controller->parent.state_machine,
         SCI_BASE_CONTROLLER_STATE_RESET
      );
   }
   else
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_controller),
         SCIF_LOG_OBJECT_CONTROLLER,
         "Controller: unable to successfully reset controller.\n"
      ));

      sci_base_state_machine_change_state(
         &fw_controller->parent.state_machine,
         SCI_BASE_CONTROLLER_STATE_FAILED
      );
   }
}
/**
 * @brief This method provides STOPPED state specific handling for
 *        when the user attempts to destruct the remote device.
 *
 * @param[in]  remote_device This parameter specifies the remote device
 *             object for which the framework is attempting to start.
 *
 * @return This method returns an indication as to whether the destruct
 *         operation completed successfully.
 */
static
SCI_STATUS scif_sas_remote_device_stopped_destruct_handler(
   SCI_BASE_REMOTE_DEVICE_T * remote_device
)
{
   SCI_STATUS                 status;
   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                                          remote_device;

   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
   scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);

   //For smp device, need to clear its smp phy list first.
   if(dev_protocols.u.bits.attached_smp_target)
      scif_sas_smp_remote_device_removed(fw_device);

   status = scic_remote_device_destruct(fw_device->core_object);
   if (status == SCI_SUCCESS)
   {
      sci_base_state_machine_change_state(
         &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_FINAL
      );

      scif_sas_remote_device_deinitialize_state_logging(fw_device);
   }
   else
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_device),
         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
         "Device:0x%x Status:0x%x failed to destruct core device\n",
         fw_device
      ));
   }

   return status;
}
/**
 * @brief This method constructs an internal smp request.
 *
 * @param[in] fw_controller The framework controller
 * @param[in] fw_device The smp device that the internal io targets to.
 * @param[in] internal_io_memory The memory space for the internal io.
 * @param[in] io_tag The io tag for the internl io to be constructed.
 * @param[in] smp_command A pointer to the smp request data structure according
 *       to SAS protocol.
 *
 * @return Indicate if the internal io was successfully constructed.
 * @retval SCI_SUCCESS This value is returned if the internal io was
 *         successfully constructed.
 * @retval SCI_FAILURE This value is returned if the internal io was failed to
 *         be constructed.
 */
SCI_STATUS scif_sas_internal_io_request_construct_smp(
   SCIF_SAS_CONTROLLER_T       * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T    * fw_device,
   void                        * internal_io_memory,
   U16                           io_tag,
   SMP_REQUEST_T               * smp_command
)
{
   SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io  =
     (SCIF_SAS_INTERNAL_IO_REQUEST_T*)internal_io_memory;

   SCIF_SAS_IO_REQUEST_T * fw_io =
     (SCIF_SAS_IO_REQUEST_T*)internal_io_memory;

   SCI_STATUS status;

   //call common smp request construct routine.
   status = scif_sas_io_request_construct_smp(
               fw_controller,
               fw_device,
               internal_io_memory,
               (char *)internal_io_memory + sizeof(SCIF_SAS_INTERNAL_IO_REQUEST_T),
               SCI_CONTROLLER_INVALID_IO_TAG,
               smp_command,
               NULL //there is no associated user io object.
            );

   //Codes below are all internal io related.
   if (status == SCI_SUCCESS)
   {
      //set the is_internal flag
      fw_io->parent.is_internal = TRUE;

      if (fw_internal_io->internal_io_timer == NULL)
      {
         //create the timer for this internal request.
         fw_internal_io->internal_io_timer =
            scif_cb_timer_create(
               (SCI_CONTROLLER_HANDLE_T *)fw_controller,
               scif_sas_internal_io_request_timeout_handler,
               (void*)fw_io
            );
      }
      else
      {
         ASSERT (0);
      }

      //insert into high priority queue
      if ( !sci_pool_full(fw_controller->hprq.pool) )
      {
         sci_pool_put(
            fw_controller->hprq.pool, (POINTER_UINT) internal_io_memory
         );
      }
      else
      {
         SCIF_LOG_ERROR((
            sci_base_object_get_logger(fw_controller),
            SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_REMOTE_DEVICE,
            "scif_sas_internal_io_request_construct_smp, high priority queue full!\n"
         ));

         scif_sas_internal_io_request_destruct(fw_controller, fw_internal_io);

         //return failure status.
         return SCI_FAILURE_INSUFFICIENT_RESOURCES;
      }
   }

   return status;
}
/**
 * @brief This method provides OPERATIONAL sub-state specific handling for
 *        when a user attempts to start a task management request on
 *        a remote device.  This includes terminating all of the affected
 *        ongoing IO requests (i.e. aborting them in the silicon) and then
 *        issuing the task management request to the silicon.
 *
 * @param[in]  remote_device This parameter specifies the remote device
 *             object on which the user is attempting to perform a start
 *             task operation.
 * @param[in]  task_request This parameter specifies the task management
 *             request to be started.
 *
 * @return This method returns an indication as to whether the task
 *         management request started successfully.
 */
static
SCI_STATUS scif_sas_remote_device_ready_operational_start_task_handler(
   SCI_BASE_REMOTE_DEVICE_T * remote_device,
   SCI_BASE_REQUEST_T       * task_request
)
{
   SCI_STATUS                 status     = SCI_FAILURE;
   SCIF_SAS_REMOTE_DEVICE_T * fw_device  = (SCIF_SAS_REMOTE_DEVICE_T*)
                                           remote_device;
   SCIF_SAS_TASK_REQUEST_T  * fw_task    = (SCIF_SAS_TASK_REQUEST_T*)
                                           task_request;
   U8 task_function =
         scif_sas_task_request_get_function(fw_task);

   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;

   scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
   if (   dev_protocols.u.bits.attached_ssp_target
       || dev_protocols.u.bits.attached_stp_target)
   {
      // //NOTE: For STP/SATA targets we currently terminate all requests for
      //       any type of task management.
      if (  (task_function == SCI_SAS_ABORT_TASK_SET)
         || (task_function == SCI_SAS_CLEAR_TASK_SET)
         || (task_function == SCI_SAS_LOGICAL_UNIT_RESET)
         || (task_function == SCI_SAS_I_T_NEXUS_RESET)
         || (task_function == SCI_SAS_HARD_RESET) )
      {
         // Terminate all of the requests in the silicon for this device.
         scif_sas_domain_terminate_requests(
            fw_device->domain, fw_device, NULL, fw_task
         );

         status = scif_sas_remote_device_start_task_request(fw_device, fw_task);
      }
      else if (  (task_function == SCI_SAS_CLEAR_ACA)
              || (task_function == SCI_SAS_QUERY_TASK)
              || (task_function == SCI_SAS_QUERY_TASK_SET)
              || (task_function == SCI_SAS_QUERY_ASYNCHRONOUS_EVENT) )
      {
       ASSERT(!dev_protocols.u.bits.attached_stp_target);
         status = scif_sas_remote_device_start_task_request(fw_device, fw_task);
      }
      else if (task_function == SCI_SAS_ABORT_TASK)
      {
         SCIF_SAS_REQUEST_T * fw_request
            = scif_sas_domain_get_request_by_io_tag(
                 fw_device->domain, fw_task->io_tag_to_manage
              );

         // Determine if the request being aborted was found.
         if (fw_request != NULL)
         {
            scif_sas_domain_terminate_requests(
               fw_device->domain, fw_device, fw_request, fw_task
            );

            status = scif_sas_remote_device_start_task_request(
                        fw_device, fw_task
                     );
         }
         else
            status = SCI_FAILURE_INVALID_IO_TAG;
      }
   }
   else
      status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;

   if (status != SCI_SUCCESS)
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_device),
         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
         "Controller:0x%x TaskRequest:0x%x Status:0x%x start task failure\n",
         fw_device, fw_task, status
      ));
   }

   return status;
}
/**
 * @brief This method will construct the SATA/STP specific IO request
 *        object utilizing the SATI.
 *
 * @pre The scif_sas_request_construct() method should be invoked before
 *      calling this method.
 *
 * @param[in,out] stp_io_request This parameter specifies the stp_io_request
 *                to be constructed.
 *
 * @return Indicate if the construction was successful.
 * @return SCI_FAILURE_NO_NCQ_TAG_AVAILABLE
 * @return SCI_SUCCESS_IO_COMPLETE_BEFORE_START
 * @return SCI_FAILURE_IO_RESPONSE_VALID
 * @return SCI_FAILURE This return value indicates a change in the translator
 *         where a new return code has been given, but is not yet understood
 *         by this routine.
 */
SCI_STATUS scif_sas_stp_io_request_construct(
   SCIF_SAS_IO_REQUEST_T * fw_io
)
{
   SATI_STATUS                sati_status;
   SCI_STATUS                 sci_status = SCI_FAILURE;
   SCIF_SAS_REMOTE_DEVICE_T * fw_device  = fw_io->parent.device;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_io),
      SCIF_LOG_OBJECT_IO_REQUEST,
      "scif_sas_stp_io_request_construct(0x%x) enter\n",
      fw_io
   ));

   // The translator will indirectly invoke core methods to set the fields
   // of the ATA register FIS inside of this method.
   sati_status = sati_translate_command(
                    &fw_io->parent.stp.sequence,
                    &fw_device->protocol_device.stp_device.sati_device,
                    fw_io,
                    fw_io
                 );

   if (sati_status == SATI_SUCCESS)
   {
      // Allow the core to finish construction of the IO request.
      sci_status = scic_io_request_construct_basic_sata(fw_io->parent.core_object);
      fw_io->parent.state_handlers = &stp_io_request_constructed_handlers;
      fw_io->parent.protocol_complete_handler
         = scif_sas_stp_core_cb_io_request_complete_handler;
   }
   else if (sati_status == SATI_SUCCESS_SGL_TRANSLATED)
   {
      SCIC_IO_SATA_PARAMETERS_T parms;
      parms.do_translate_sgl = FALSE;

      // The translation actually already caused translation of the
      // scatter gather list.  So, call into the core through an API
      // that will not attempt to translate the SGL.
      scic_io_request_construct_advanced_sata(
                      fw_io->parent.core_object, &parms
                   );
      fw_io->parent.state_handlers = &stp_io_request_constructed_handlers;
      fw_io->parent.protocol_complete_handler
         = scif_sas_stp_core_cb_io_request_complete_handler;
      // Done with translation
      sci_status = SCI_SUCCESS;
   }
   else if (sati_status == SATI_COMPLETE)
      sci_status = SCI_SUCCESS_IO_COMPLETE_BEFORE_START;
   else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
      sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
   else
   {
      SCIF_LOG_ERROR((
         sci_base_object_get_logger(fw_io),
         SCIF_LOG_OBJECT_IO_REQUEST,
         "Unexpected SAT translation failure 0x%x\n",
         fw_io
      ));
   }

   return sci_status;
}