/** * @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); } }
/** * @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 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; }
/** * @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; }