/**
 * @brief construct a smp REPORT PHY SATA command to the fw_device.
 * @param[in] fw_controller The framework controller object.
 * @param[in] fw_device the framework smp device that DISCOVER command targets
 *       to.
 * @param[in] phy_identifier The phy index the DISCOVER command targets to.
 *
 * @return void * address to the built scif sas smp request.
 */
void * scif_sas_smp_request_construct_report_phy_sata(
   SCIF_SAS_CONTROLLER_T    * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   U8                         phy_identifier
)
{
   SMP_REQUEST_T report_phy_sata;

   scif_sas_smp_protocol_request_construct(
      &report_phy_sata,
      SMP_FUNCTION_REPORT_PHY_SATA,
      sizeof(SMP_RESPONSE_REPORT_PHY_SATA_T) / sizeof(U32),
      sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
   );

   report_phy_sata.request.report_phy_sata.phy_identifier = phy_identifier;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "SMP REPORT PHY SATA - Device:0x%x PhyId:0x%x\n",
      fw_device, phy_identifier
   ));

   return scif_sas_smp_request_build(
             fw_controller, fw_device, &report_phy_sata, NULL, NULL);
}
/**
 * @brief This method implements the actions taken when entering the
 *        FAILED state.  This includes setting the state handler methods
 *        and issuing a scif_cb_remote_device_failed() notification to
 *        the user.
 *
 * @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_failed_state_enter(
   SCI_BASE_OBJECT_T *object
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;

   SET_STATE_HANDLER(
      fw_device,
      scif_sas_remote_device_state_handler_table,
      SCI_BASE_REMOTE_DEVICE_STATE_FAILED
   );

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
      "Domain:0x%x Device:0x%x Status:0x%x device failed\n",
      fw_device->domain, fw_device, fw_device->operation_status
   ));

   // Notify the user that the device has failed.
   scif_cb_remote_device_failed(
      fw_device->domain->controller,
      fw_device->domain,
      fw_device,
      fw_device->operation_status
   );

   // Only call start_complete for the remote device if the device failed
   // from the STARTING state.
   if (fw_device->parent.state_machine.previous_state_id
       == SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
      scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
}
/**
 * @brief construct a smp Discover command to the fw_device.
 * @param[in] fw_controller The framework controller object.
 * @param[in] fw_device the framework smp device that DISCOVER command targets
 *       to.
 * @param[in] phy_identifier The phy index the DISCOVER command targets to.
 *
 * @return void * address to the built scif sas smp request.
 */
void * scif_sas_smp_request_construct_discover(
   SCIF_SAS_CONTROLLER_T    * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   U8                         phy_identifier,
   void                     * external_request_object,
   void                     * external_memory
)
{
   SMP_REQUEST_T smp_discover;

   scif_sas_smp_protocol_request_construct(
      &smp_discover,
      SMP_FUNCTION_DISCOVER,
      sizeof(SMP_RESPONSE_DISCOVER_T) / sizeof(U32),
      sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32)
   );

   smp_discover.request.discover.phy_identifier = phy_identifier;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "SMP DISCOVER - Device:0x%x PhyId:0x%x\n",
      fw_device, phy_identifier
   ));

   return scif_sas_smp_request_build(
             fw_controller, fw_device, &smp_discover,
             external_request_object, external_memory
          );
}
/**
 * @brief construct a SMP Report Manufacturer Info request to the fw_device.
 *
 * @param[in] fw_controller The framework controller object.
 * @param[in] fw_device the framework device that the REPORT MANUFACTURER
 *            INFO targets to.
 *
 * @return void * address to the built scif sas smp request.
 */
void * scif_sas_smp_request_construct_report_manufacturer_info(
   SCIF_SAS_CONTROLLER_T    * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
   SMP_REQUEST_T smp_report_manufacturer_info;

   scif_sas_smp_protocol_request_construct(
      &smp_report_manufacturer_info,
      SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION,
      sizeof(SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T) / sizeof(U32),
      0
   );

   smp_report_manufacturer_info.request.report_general.crc = 0;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "SMP REPORT MANUFACTURER_INFO -  Device:0x%x\n",
      fw_device
   ));

   return scif_sas_smp_request_build(
             fw_controller, fw_device, &smp_report_manufacturer_info, NULL, NULL
          );
}
/**
 * @brief construct a smp Report Genernal command to the fw_device.
 *
 * @param[in] fw_controller The framework controller object.
 * @param[in] fw_device the framework device that the REPORT GENERAL command
 *       targets to.
 *
 * @return void * address to the built scif sas smp request.
 */
void * scif_sas_smp_request_construct_report_general(
   SCIF_SAS_CONTROLLER_T    * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
   SMP_REQUEST_T smp_report_general;

   // Build the REPORT GENERAL request.
   scif_sas_smp_protocol_request_construct(
      &smp_report_general,
      SMP_FUNCTION_REPORT_GENERAL,
      sizeof(SMP_RESPONSE_REPORT_GENERAL_T) / sizeof(U32),
      0
   );

   smp_report_general.request.report_general.crc = 0;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "SMP REPORT GENERAL -  Device:0x%x\n",
      fw_device
   ));

   return scif_sas_smp_request_build(
             fw_controller, fw_device, &smp_report_general, NULL, NULL);
}
Exemple #6
0
/**
 * @brief This method will attempt to transition to the stopped state.
 *        The transition will only occur if the criteria for transition is
 *        met (i.e. all IOs are complete and all devices are stopped).
 *
 * @param[in]  fw_domain This parameter specifies the domain in which to
 *             to attempt to perform the transition.
 *
 * @return none
 */
void scif_sas_domain_transition_to_stopped_state(
   SCIF_SAS_DOMAIN_T * fw_domain
)
{
   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_transition_to_stopped_state(0x%x) enter\n",
      fw_domain
   ));

   // If IOs are quiesced, and all remote devices are stopped,
   // then transition directly to the STOPPED state.
   if (  (fw_domain->request_list.element_count == 0)
      && (fw_domain->device_start_count == 0) )
   {
      SCIF_LOG_INFO((
         sci_base_object_get_logger(fw_domain),
         SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
         "Domain:0x%x immediate transition to STOPPED\n",
         fw_domain
      ));

      sci_base_state_machine_change_state(
         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPED
      );
   }
}
/**
 * @brief This method implements the actions taken when entering the
 *        READY OPERATIONAL substate.  This includes setting the state
 *        handler methods and issuing a scif_cb_remote_device_ready()
 *        notification to the user.
 *
 * @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_operational_substate_enter(
   SCI_BASE_OBJECT_T *object
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;

   SET_STATE_HANDLER(
      fw_device,
      scif_sas_remote_device_ready_substate_handler_table,
      SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL
   );

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
      "Domain:0x%x Device:0x%x device ready\n",
      fw_device->domain, fw_device
   ));

   // Notify the user that the device has become ready.
   scif_cb_remote_device_ready(
      fw_device->domain->controller, fw_device->domain, fw_device
   );
}
/**
 * @brief This method attempts to allocate a valid NCQ tag from the list
 *        of available tags in the remote device.
 *
 * @todo Attempt to find a CLZ like instruction to optimize this routine
 *       down into a few instructions.  I know there is one like it for IA.
 *
 * @param[in] fw_device This parameter specifies the remote device
 *            for which to allocate an available NCQ tag.
 *
 * @return Return an available NCQ tag.
 * @retval 0-31 These values indicate an available tag was successfully
 *         allocated.
 * @return SCIF_SAS_STP_INVALID_NCQ_TAG This value indicates that there are
 *         no available NCQ tags.
 */
U8 scif_sas_stp_remote_device_allocate_ncq_tag(
   SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
   U8  ncq_tag  = 0;
   U32 tag_mask = 1;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
      "scif_sas_stp_remote_device_allocate_ncq_tag(0x%x)\n",
      fw_device
   ));

   // Try to find an unused NCQ tag.
   while (  (fw_device->protocol_device.stp_device.s_active & tag_mask)
         && (ncq_tag < fw_device->protocol_device.stp_device.sati_device.ncq_depth) )
   {
      tag_mask <<= 1;
      ncq_tag++;
   }

   // Check to see if we were able to find an available NCQ tag.
   if (ncq_tag < fw_device->protocol_device.stp_device.sati_device.ncq_depth)
   {
      SCIF_LOG_INFO((
         sci_base_object_get_logger(fw_device),
         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
         "RemoteDevice:0x%x NcqTag:0x%x successful NCQ TAG allocation\n",
         fw_device, ncq_tag
      ));

      fw_device->protocol_device.stp_device.s_active |= tag_mask;
      return ncq_tag;
   }

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
      "RemoteDevice:0x%x unable to allocate NCQ TAG\n",
      fw_device
   ));

   // All NCQ tags are in use.
   return SCIF_SAS_INVALID_NCQ_TAG;
}
/**
 * @brief This method removes the specified tag from the list of
 *        outstanding tags.  It doesn't return any values.
 *
 * @param[in] fw_device This parameter specifies the remote device for
 *            which to free an NCQ tag.
 * @param[in] ncq_tag This parameter specifies the NCQ tag that is
 *            to be freed.
 *
 * @return none
 */
void scif_sas_stp_remote_device_free_ncq_tag(
   struct SCIF_SAS_REMOTE_DEVICE * fw_device,
   U8                              ncq_tag
)
{
   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST,
      "RemoteDevice:0x%x NcqTag:0x%x freeing NCQ TAG\n",
      fw_device, ncq_tag
   ));

   fw_device->protocol_device.stp_device.s_active &= ~(1 << ncq_tag);
}
/**
 * @brief This method provides handling of device start complete duing
 *        UPDATING_PORT_WIDTH state.
 *
 * @param[in]  remote_device This parameter specifies the remote device object
 *             which is start complete.
 *
 * @return none.
 */
static
void scif_sas_remote_device_updating_port_width_state_start_complete_handler(
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   SCI_STATUS                 completion_status
)
{
   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE,
      "RemoteDevice:0x%x updating port width state start complete handler\n",
      fw_device,
      sci_base_state_machine_get_state(&fw_device->parent.state_machine)
   ));

   if ( fw_device->destination_state
           == SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING )
   {
      //if the destination state of this device change to STOPPING, no matter
      //whether we need to update the port width again, just make the device
      //go to the STOPPING state.
      sci_base_state_machine_change_state(
         &fw_device->parent.state_machine,
         SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
      );
   }
   else if ( scic_remote_device_get_port_width(fw_device->core_object)
                != fw_device->device_port_width
            && fw_device->device_port_width != 0)
   {
      scic_remote_device_stop(
         fw_device->core_object,
         SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
      );
   }
   else
   {
      //Port width updating succeeds. Transfer to destination state.
      sci_base_state_machine_change_state(
         &fw_device->parent.state_machine,
         SCI_BASE_REMOTE_DEVICE_STATE_READY
      );
   }
}
/**
 * @brief This method performs functionality required after a task management
 *        operation (either a task management request or a silicon task
 *        termination) has finished.
 *
 * @param[in]  fw_task This parameter specifies the request that has
 *             the operation completing.
 *
 * @return none
 */
void scif_sas_task_request_operation_complete(
   SCIF_SAS_TASK_REQUEST_T * fw_task
)
{
   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_task),
      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
      "scif_sas_task_request_operation_complete(0x%x) enter\n",
      fw_task
   ));

   fw_task->affected_request_count--;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_task),
      SCIF_LOG_OBJECT_TASK_MANAGEMENT,
      "TaskRequest:0x%x current affected request count:0x%x\n",
      fw_task, fw_task->affected_request_count
   ));
}
/**
 * @brief This method provides handling of device stop complete duing
 *        UPDATING_PORT_WIDTH state.
 *
 * @param[in]  remote_device This parameter specifies the remote device object
 *             which is stop complete.
 *
 * @return none.
 */
static
void scif_sas_remote_device_updating_port_width_state_stop_complete_handler(
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   SCI_STATUS                 completion_status
)
{
   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE,
      "RemoteDevice:0x%x updating port width state stop complete handler\n",
      fw_device,
      sci_base_state_machine_get_state(&fw_device->parent.state_machine)
   ));

   if ( fw_device->destination_state
           == SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING )
   {
      //Device directly transits to STOPPED STATE from UPDATING_PORT_WIDTH state,
      fw_device->domain->device_start_count--;

      //if the destination state of this device change to STOPPING, no matter
      //whether we need to update the port width again, just make the device
      //go to the STOPPED state.
      sci_base_state_machine_change_state(
         &fw_device->parent.state_machine,
         SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
      );
   }
   else
   {
      scic_remote_device_set_port_width(
         fw_device->core_object,
         fw_device->device_port_width
      );

      //Device stop complete, means the RNC has been destructed. Now we need to
      //start core device so the RNC with updated port width will be posted.
      scic_remote_device_start(
         fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT);
   }
}
/**
 * @brief This method implements the actions taken when entering the
 *        STARTING state.  This method will attempt to start the core
 *        remote device and will kick-start the starting sub-state machine
 *        if no errors are encountered.
 *
 * @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_starting_state_enter(
   SCI_BASE_OBJECT_T *object
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;

   SET_STATE_HANDLER(
      fw_device,
      scif_sas_remote_device_state_handler_table,
      SCI_BASE_REMOTE_DEVICE_STATE_STARTING
   );

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
      "RemoteDevice:0x%x starting/configuring\n",
      fw_device
   ));

   fw_device->destination_state =
      SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;

   sci_base_state_machine_start(&fw_device->starting_substate_machine);

   fw_device->operation_status = scic_remote_device_start(
                                    fw_device->core_object,
                                    SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
                                 );

   if (fw_device->operation_status != SCI_SUCCESS)
   {
      fw_device->state_handlers->parent.fail_handler(&fw_device->parent);

      // Something is seriously wrong.  Starting the core remote device
      // shouldn't fail in anyway in this state.
      scif_cb_controller_error(fw_device->domain->controller,
              SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
   }
}
/**
 * @brief This method provides handling (i.e. returns an error);
 *        when a user attempts to stop a remote device during the updating
 *        port width state, it will record the destination state for this
 *        device to be STOPPING, instead of usually READY state.
 *
 * @param[in]  remote_device This parameter specifies the remote device object
 *             on which the user is attempting to perform a stop operation.
 *
 * @return This method always return SCI_SUCCESS.
 */
static
SCI_STATUS scif_sas_remote_device_updating_port_width_state_stop_handler(
   SCI_BASE_REMOTE_DEVICE_T * remote_device
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device =
      (SCIF_SAS_REMOTE_DEVICE_T *)remote_device;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE,
      "RemoteDevice:0x%x updating port width state stop handler\n",
      fw_device,
      sci_base_state_machine_get_state(&fw_device->parent.state_machine)
   ));

   //Can't stop the device right now. Remember the pending stopping request.
   //When exit the UPDATING_PORT_WIDTH state, we will check this variable
   //to decide which state to go.
   fw_device->destination_state =
      SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_STOPPING;

   return SCI_SUCCESS;
}
Exemple #15
0
/**
 * @brief This method provides startig sub-state specific handling for
 *        when the remote device is requested to stop.  This will occur
 *        when there is a link failure during the starting operation.
 *
 * @param[in]  remote_device This parameter specifies the remote device
 *             object for which the failure condition occurred.
 *
 * @return This method returns an indication as to whether the failure
 *         operation completed successfully.
 */
static
SCI_STATUS
scif_sas_remote_device_starting_state_general_stop_handler(
   SCI_BASE_REMOTE_DEVICE_T * remote_device
)
{
   SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                                          remote_device;

   SCIF_LOG_INFO((
      sci_base_object_get_logger(fw_device),
      SCIF_LOG_OBJECT_REMOTE_DEVICE,
      "RemoteDevice:0x%x starting device requested to stop\n",
      fw_device
   ));

   fw_device->domain->device_start_in_progress_count--;

   sci_base_state_machine_change_state(
      &fw_device->parent.state_machine, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
   );

   return SCI_SUCCESS;
}
/**
 * @brief This method provides SATA/STP STARTED state specific handling for
 *        when the user attempts to complete the supplied IO request.
 *        It will perform data/response translation and free NCQ tags
 *        if necessary.
 *
 * @param[in] io_request This parameter specifies the IO request object
 *            to be started.
 *
 * @return This method returns a value indicating if the IO request was
 *         successfully completed or not.
 */
static
SCI_STATUS scif_sas_stp_core_cb_io_request_complete_handler(
   SCIF_SAS_CONTROLLER_T    * fw_controller,
   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
   SCIF_SAS_REQUEST_T       * fw_request,
   SCI_STATUS               * completion_status
)
{
   SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *) fw_request;

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_controller),
      SCIF_LOG_OBJECT_IO_REQUEST,
      "scif_sas_stp_core_cb_io_request_complete_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
      fw_controller, fw_device, fw_request, *completion_status
   ));

   if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_FPDMA)
      scif_sas_stp_remote_device_free_ncq_tag(
         fw_request->device, fw_io->parent.stp.ncq_tag
      );

   // Translating the response is only necessary if:
   // - some sort of error occurred resulting in having the error bit
   //   set in the ATA status register and values to decode in the
   //   ATA error register.
   // - the command returns information in the register FIS itself,
   //   which requires translation.
   // - the request completed ok but the sequence requires a callback
   //   to possibly continue the translation
   if ((*completion_status == SCI_FAILURE_IO_RESPONSE_VALID) ||
       ((sati_cb_do_translate_response(fw_request)) &&
        (*completion_status != SCI_FAILURE_IO_TERMINATED)))
   {
      SATI_STATUS sati_status = sati_translate_command_response(
                                   &fw_io->parent.stp.sequence, fw_io, fw_io
                                );
      if (sati_status == SATI_COMPLETE)
         *completion_status = SCI_SUCCESS;
      else if (sati_status == SATI_FAILURE_CHECK_RESPONSE_DATA)
         *completion_status = SCI_FAILURE_IO_RESPONSE_VALID;
      else if (sati_status == SATI_SEQUENCE_INCOMPLETE)
      {
         // The translation indicates that additional SATA requests are
         // necessary to finish the original SCSI request.  As a result,
         // do not complete the IO and begin the next stage of the
         // translation.
         return SCI_WARNING_SEQUENCE_INCOMPLETE;
      }
      else if (sati_status == SATI_COMPLETE_IO_DONE_EARLY)
         *completion_status = SCI_SUCCESS_IO_DONE_EARLY;
      else
      {
         // Something unexpected occurred during translation.  Fail the
         // IO request to the user.
         *completion_status = SCI_FAILURE;
      }
   }
   else if (*completion_status != SCI_SUCCESS)
   {
      SCIF_LOG_INFO((
         sci_base_object_get_logger(fw_controller),
         SCIF_LOG_OBJECT_IO_REQUEST,
         "Sequence Terminated(0x%x, 0x%x, 0x%x)\n",
         fw_controller, fw_device, fw_request
      ));

      sati_sequence_terminate(&fw_io->parent.stp.sequence, fw_io, fw_io);
   }

   return SCI_SUCCESS;
}
Exemple #17
0
/**
 * @brief This method implements the actions taken when entering the
 *        DISCOVERING state.  This includes determining from which
 *        state we entered.  If we entered from stopping that some sort
 *        of hot-remove of the port occurred.  In the hot-remove case
 *        all devices should be in the STOPPED state already and, as
 *        a result, are removed from the domain with a notification sent
 *        to the framework user.
 *
 * @note This method currently only handles hot-insert/hot-remove of
 *       direct attached SSP devices.
 *
 * @param[in]  object This parameter specifies the base object for which
 *             the state transition is occurring.  This is cast into a
 *             SCIF_SAS_DOMAIN object in the method implementation.
 *
 * @return none
 */
static
void scif_sas_domain_discovering_state_enter(
   SCI_BASE_OBJECT_T * object
)
{
   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;

   SET_STATE_HANDLER(
      fw_domain,
      scif_sas_domain_state_handler_table,
      SCI_BASE_DOMAIN_STATE_DISCOVERING
   );

   SCIF_LOG_TRACE((
      sci_base_object_get_logger(fw_domain),
      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
      "scif_sas_domain_discovering_state_enter(0x%x) enter\n",
      fw_domain
   ));

   fw_domain->broadcast_change_count = 0;

   // Did the domain just go through a port not ready action?  If it did,
   // then we will be entering from the STOPPED state.
   if (fw_domain->parent.state_machine.previous_state_id
       != SCI_BASE_DOMAIN_STATE_STOPPED)
   {
      SCIF_SAS_REMOTE_DEVICE_T * remote_device;
      SCIC_PORT_PROPERTIES_T     properties;

      scic_port_get_properties(fw_domain->core_object, &properties);

      // If the device has not yet been added to the domain, then
      // inform the user that the device is new.
      remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                      scif_domain_get_device_by_sas_address(
                         fw_domain, &properties.remote.sas_address
                      );
      if (remote_device == SCI_INVALID_HANDLE)
      {
         // simply notify the user of the new DA device and be done
         // with discovery.
         scif_cb_domain_da_device_added(
            fw_domain->controller,
            fw_domain,
            &properties.remote.sas_address,
            &properties.remote.protocols
         );
      }
      else
      {
         if(properties.remote.protocols.u.bits.smp_target)
            //kick off the smp discover process.
            scif_sas_domain_start_smp_discover(fw_domain, remote_device);
      }
   }
   else  //entered from STOPPED state.
   {
      SCI_ABSTRACT_ELEMENT_T * current_element =
             sci_abstract_list_get_front(&(fw_domain->remote_device_list) );

      SCIF_SAS_REMOTE_DEVICE_T * fw_device;

      while (current_element != NULL)
      {
         fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
                     sci_abstract_list_get_object(current_element);

         ASSERT(fw_device->parent.state_machine.current_state_id
                == SCI_BASE_REMOTE_DEVICE_STATE_STOPPED);

         current_element =
            sci_abstract_list_get_next(current_element);

         SCIF_LOG_INFO((
            sci_base_object_get_logger(fw_domain),
            SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
            "Controller:0x%x Domain:0x%x Device:0x%x removed\n",
            fw_domain->controller, fw_domain, fw_device
         ));

         // Notify the framework user of the device removal.
         scif_cb_domain_device_removed(
            fw_domain->controller, fw_domain, fw_device
         );
      }

      ASSERT(fw_domain->request_list.element_count == 0);
      ASSERT(sci_abstract_list_size(&fw_domain->remote_device_list) == 0);

      sci_base_state_machine_change_state(
         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STARTING
      );
   }
}