/** * @brief this routine is called by OS' DPC to start io requests from internal * high priority request queue * @param[in] fw_controller The framework controller. * * @return none */ void scif_sas_controller_start_high_priority_io( SCIF_SAS_CONTROLLER_T * fw_controller ) { POINTER_UINT io_address; SCIF_SAS_IO_REQUEST_T * fw_io; SCI_STATUS status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_controller_start_high_priority_io(0x%x) enter\n", fw_controller )); while ( !sci_pool_empty(fw_controller->hprq.pool) ) { sci_pool_get(fw_controller->hprq.pool, io_address); fw_io = (SCIF_SAS_IO_REQUEST_T *)io_address; status = fw_controller->state_handlers->start_high_priority_io_handler( (SCI_BASE_CONTROLLER_T*) fw_controller, (SCI_BASE_REMOTE_DEVICE_T*) fw_io->parent.device, (SCI_BASE_REQUEST_T*) fw_io, SCI_CONTROLLER_INVALID_IO_TAG ); } }
/** * @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); }
void scic_cb_controller_stop_complete( SCI_CONTROLLER_HANDLE_T controller, SCI_STATUS completion_status ) { SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*) sci_object_get_association(controller); SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN, "scic_cb_controller_stop_complete(0x%x, 0x%x) enter\n", controller, completion_status )); if (completion_status == SCI_SUCCESS) { sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_STOPPED ); } else { sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_FAILED ); } scif_cb_controller_stop_complete(fw_controller, completion_status); }
/** * @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); } }
void scic_cb_controller_start_complete( SCI_CONTROLLER_HANDLE_T controller, SCI_STATUS completion_status ) { SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*) sci_object_get_association(controller); SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "scic_cb_controller_start_complete(0x%x, 0x%x) enter\n", controller, completion_status )); if (completion_status == SCI_SUCCESS || completion_status == SCI_FAILURE_TIMEOUT) { // Even the initialization of the core controller timed out, framework // controller should still transit to READY state. sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_READY ); } scif_cb_controller_start_complete(fw_controller, completion_status); }
SCI_STATUS scif_controller_complete_task( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T task_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if ( (controller == SCI_INVALID_HANDLE) || (remote_device == SCI_INVALID_HANDLE) || (task_request == SCI_INVALID_HANDLE) ) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT, "scif_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, task_request )); return fw_controller->state_handlers->complete_task_handler( (SCI_BASE_CONTROLLER_T*) controller, (SCI_BASE_REMOTE_DEVICE_T*) remote_device, (SCI_BASE_REQUEST_T*) task_request ); }
SCI_IO_STATUS scif_controller_start_io( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T io_request, U16 io_tag ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; SCI_STATUS status; SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request, io_tag )); if ( sci_pool_empty(fw_controller->hprq.pool) || scif_sas_controller_sufficient_resource(controller) ) { status = fw_controller->state_handlers->start_io_handler( (SCI_BASE_CONTROLLER_T*) controller, (SCI_BASE_REMOTE_DEVICE_T*) remote_device, (SCI_BASE_REQUEST_T*) io_request, io_tag ); } else status = SCI_FAILURE_INSUFFICIENT_RESOURCES; return (SCI_IO_STATUS)status; }
/** * @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 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 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 This method provides SATA/STP CONSTRUCTED state specific handling * for when the user attempts to complete the supplied IO request. * This method will be invoked in the event the call to start the * core IO request fails for some reason. In this situation, the * NCQ tag will be freed. * * @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 started or not. * @retval SCI_SUCCESS This return value indicates successful starting * of the IO request. */ static SCI_STATUS scif_sas_stp_io_request_constructed_complete_handler( SCI_BASE_REQUEST_T * io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *) io_request; SCIF_LOG_TRACE(( sci_base_object_get_logger(io_request), SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_stp_io_request_constructed_complete_handler(0x%x) enter\n", io_request )); if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_FPDMA) { // For NCQ, we need to return the tag back to the free pool. if (fw_io->parent.stp.ncq_tag != SCIF_SAS_INVALID_NCQ_TAG) scif_sas_stp_remote_device_free_ncq_tag( fw_io->parent.device, fw_io->parent.stp.ncq_tag ); } return SCI_SUCCESS; }
/** * @brief This method implements the actions taken when entering the * STOPPED state. * * @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_stopped_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_STOPPED ); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_domain_stopped_state_enter(0x%x) enter\n", fw_domain )); // A hot unplug of the direct attached device has occurred. Thus, // notify the user. Note, if the controller is not in READY state, // mostly likely the controller is in STOPPING or STOPPED state, // meaning the controller is in the process of stopping, we should // not call back to user in the middle of controller stopping. if(fw_domain->controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_READY) scif_cb_domain_change_notification(fw_domain->controller, fw_domain); }
/** * This method will perform the STP request (both io or task) completion * processing for await reset state. * * @param[in] device This parameter specifies the device for which the * request is being completed. * @param[in] request This parameter specifies the request being completed. * * @return This method returns an indication as to whether the request * processing completed successfully. */ static SCI_STATUS scic_sds_stp_remote_device_ready_await_reset_substate_complete_request_handler( SCI_BASE_REMOTE_DEVICE_T * device, SCI_BASE_REQUEST_T * request ) { SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device; SCIC_SDS_REQUEST_T * the_request = (SCIC_SDS_REQUEST_T *)request; SCI_STATUS status; status = scic_sds_io_request_complete(the_request); if (status == SCI_SUCCESS) { status = scic_sds_port_complete_io( this_device->owning_port, this_device, the_request ); if (status == SCI_SUCCESS) scic_sds_remote_device_decrement_request_count(this_device); } if (status != SCI_SUCCESS) { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_device), SCIC_LOG_OBJECT_STP_REMOTE_TARGET, "Port:0x%x Device:0x%x Request:0x%x Status:0x%x could not complete\n", this_device->owning_port, this_device, the_request, status )); } return status; }
/** * @brief This routine is to allocate the memory for creating a smp phy object. * * @param[in] scif_controller handle to frame controller * * @return SCIF_SAS_SMP_PHY_T * An allocated space for smp phy. If failed to allocate, * return NULL. */ SCIF_SAS_SMP_PHY_T * scif_sas_controller_allocate_smp_phy( SCIF_SAS_CONTROLLER_T * fw_controller ) { SCIF_SAS_SMP_PHY_T * smp_phy; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "scif_controller_allocate_smp_phy(0x%x) enter\n", fw_controller )); if( !sci_fast_list_is_empty(&fw_controller->smp_phy_memory_list) ) { smp_phy = (SCIF_SAS_SMP_PHY_T *) sci_fast_list_remove_head(&fw_controller->smp_phy_memory_list); //clean the memory. memset((char*)smp_phy, 0, sizeof(SCIF_SAS_SMP_PHY_T) ); return smp_phy; } else return NULL; }
/** * @brief This handler is currently solely used by smp remote device for * discovering. * * @param[in] remote_device This parameter specifies the remote device * object on which the user is attempting to perform a complete high * priority IO operation. * @param[in] io_request This parameter specifies the high priority IO request * to be completed. * * @return SCI_STATUS indicate whether the io complete successfully. */ SCI_STATUS scif_sas_remote_device_ready_task_management_complete_high_priority_io_handler( SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, void * response_data, SCI_IO_STATUS completion_status ) { SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) remote_device; SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) io_request; SCI_STATUS status = SCI_SUCCESS; SCIC_TRANSPORT_PROTOCOL protocol; SCIF_LOG_TRACE(( sci_base_object_get_logger(remote_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_remote_device_ready_task_management_complete_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n", remote_device, io_request, response_data, completion_status )); fw_device->request_count--; // we are back to ready operational sub state here. sci_base_state_machine_change_state( &fw_device->ready_substate_machine, SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL ); protocol = scic_io_request_get_protocol(fw_request->core_object); // If this request was an SMP initiator request we created, then // decode the response. if (protocol == SCIC_SMP_PROTOCOL) { if (completion_status != SCI_IO_FAILURE_TERMINATED) { status = scif_sas_smp_remote_device_decode_smp_response( fw_device, fw_request, response_data, completion_status ); } else scif_sas_smp_remote_device_terminated_request_handler(fw_device, fw_request); } else { // Currently, there are only internal SMP requests. So, default work // is simply to clean up the internal request. if (fw_request->is_internal == TRUE) { scif_sas_internal_io_request_complete( fw_device->domain->controller, (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request, SCI_SUCCESS ); } } return status; }
/** * @brief This method implements the actions taken when entering the * STARTING state. This includes setting the state handlers and * checking to see if the core port has already become READY. * * @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_starting_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_STARTING ); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_domain_starting_state_enter(0x%x) enter\n", fw_domain )); scif_sas_domain_transition_from_discovering_state(fw_domain); // If we entered the STARTING state and the core port is actually ready, // then directly transition into the READY state. This can occur // if we were in the middle of discovery when the port failed // (causing a transition to STOPPING), then before reaching STOPPED // the port becomes ready again. if (fw_domain->is_port_ready == TRUE) { sci_base_state_machine_change_state( &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY ); } }
/** * @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 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 is called by the SCI user to build an SMP pass-through * IO request. * * @pre * - The user must have previously called scic_io_request_construct() * on the supplied IO request. * * @param[in] scic_smp_request This parameter specifies the handle to the * io request object to be built. * * @param[in] passthru_cb This parameter specifies the pointer to the callback * structure that contains the function pointers * * @return Indicate if the controller successfully built the IO request. */ SCI_STATUS scic_io_request_construct_smp_pass_through( SCI_IO_REQUEST_HANDLE_T scic_smp_request, SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb ) { SMP_REQUEST_T smp_request; U8 * request_buffer; U32 request_buffer_length_in_bytes; SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request; SCIC_LOG_TRACE(( sci_base_object_get_logger(this_request), SCIC_LOG_OBJECT_SMP_IO_REQUEST, "scic_io_request_construct_smp_pass_through(0x%x) enter\n", this_request )); this_request->protocol = SCIC_SMP_PROTOCOL; this_request->has_started_substate_machine = TRUE; // Call the callback function to retrieve the SMP passthrough request request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request ( (void *)this_request, &request_buffer ); //copy the request to smp request memcpy((char *)&smp_request.request.vendor_specific_request, request_buffer, request_buffer_length_in_bytes); //the header length in smp_request is in dwords - the sas spec has similar way, //but the csmi header contains the number of bytes, so we need to convert the //number of bytes to number of dwords smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32)); //Grab the other needed fields from the smp request using callbacks smp_request.header.smp_frame_type = passthru_cb->scic_cb_smp_passthru_get_frame_type ((void *)this_request); smp_request.header.function = passthru_cb->scic_cb_smp_passthru_get_function ((void *)this_request); smp_request.header.allocated_response_length = passthru_cb->scic_cb_smp_passthru_get_allocated_response_length((void *)this_request); // Construct the started sub-state machine. sci_base_state_machine_construct( &this_request->started_substate_machine, &this_request->parent.parent, scic_sds_smp_request_started_substate_table, SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE ); // Construct the SMP SCU Task Context scu_smp_request_construct_task_context (this_request, &smp_request); sci_base_state_machine_change_state( &this_request->parent.state_machine, SCI_BASE_REQUEST_STATE_CONSTRUCTED ); return SCI_SUCCESS; }
/** * @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; }
/** * @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 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 constructs the framework's SAS domain object. During * the construction process a linkage to the corresponding core port * object. * * @param[in] domain This parameter specifies the domain object to be * constructed. * @param[in] domain_id This parameter specifies the ID for the domain * object. * @param[in] fw_controller This parameter specifies the controller managing * the domain being constructed. * * @return none */ void scif_sas_domain_construct( SCIF_SAS_DOMAIN_T * fw_domain, U8 domain_id, SCIF_SAS_CONTROLLER_T * fw_controller ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION, "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n", fw_domain, domain_id, fw_controller )); sci_base_domain_construct( &fw_domain->parent, sci_base_object_get_logger(fw_controller), scif_sas_domain_state_table ); scif_sas_domain_initialize_state_logging(fw_domain); sci_abstract_list_construct( &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool ); // Retrieve the core's port object that directly corresponds to this // domain. scic_controller_get_port_handle( fw_controller->core_object, domain_id, &fw_domain->core_object ); // Set the association in the core port to this framework domain object. sci_object_set_association( (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain ); sci_fast_list_init(&fw_domain->request_list); fw_domain->operation.timer = NULL; fw_domain->is_port_ready = FALSE; fw_domain->device_start_count = 0; fw_domain->controller = fw_controller; fw_domain->operation.status = SCI_SUCCESS; fw_domain->is_config_route_table_needed = FALSE; }
/** * @brief This method will terminate the requests outstanding in the core * based on the supplied criteria. * - if the all three parameters are specified then only the single * SCIF_SAS_REQUEST object is terminated. * - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are * specified, then all SCIF_SAS_REQUEST objects outstanding at * the device are terminated. The one exclusion to this rule is * that the fw_requestor is not terminated. * - if only the SCIF_SAS_DOMAIN object is specified, then all * SCIF_SAS_REQUEST objects outstanding in the domain are * terminated. * * @param[in] fw_domain This parameter specifies the domain in which to * terminate requests. * @param[in] fw_device This parameter specifies the remote device in * which to terminate requests. This parameter can be NULL * as long as the fw_request parameter is NULL. It is a * required parameter if the fw_request parameter is not NULL. * @param[in] fw_request This parameter specifies the request object to * be terminated. This parameter can be NULL. * @param[in] fw_requestor This parameter specifies the task management * request that is responsible for the termination of requests. * * @return none */ void scif_sas_domain_terminate_requests( SCIF_SAS_DOMAIN_T * fw_domain, SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request, SCIF_SAS_TASK_REQUEST_T * fw_requestor ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT, "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n", fw_domain, fw_device, fw_request, fw_requestor )); if (fw_request != NULL) { fw_request->terminate_requestor = fw_requestor; fw_request->state_handlers->abort_handler(&fw_request->parent); } else { SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head; SCIF_SAS_REQUEST_T * request = NULL; // Cycle through the fast list of IO requests. Terminate each // outstanding requests that matches the criteria supplied by the // caller. while (element != NULL) { request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element); // The current element may be deleted from the list becasue of // IO completion so advance to the next element early element = sci_fast_list_get_next(element); // Ensure we pass the supplied criteria before terminating the // request. if ( (fw_device == NULL) || ( (request->device == fw_device) && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request) ) ) { if ( (request->is_waiting_for_abort_task_set == FALSE) || (request->terminate_requestor == NULL) ) { request->terminate_requestor = fw_requestor; request->state_handlers->abort_handler(&request->parent); } } } } }
/** * @brief This method provides STP PACKET io request STARTED state specific handling for * when the user attempts to complete the supplied IO request. * It will perform data/response translation. * * @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_packet_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; SATI_STATUS sati_status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_stp_packet_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 (*completion_status == SCI_FAILURE_IO_RESPONSE_VALID) { sati_status = sati_atapi_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 REQUEST SENSE command is // necessary to finish the original SCSI request. As a result, // do not complete the IO and begin the next stage of the IO. return SCI_WARNING_SEQUENCE_INCOMPLETE; } else { // Something unexpected occurred during translation. Fail the // IO request to the user. *completion_status = SCI_FAILURE; } } else if (*completion_status == SCI_SUCCESS && fw_request->stp.sequence.state == SATI_SEQUENCE_STATE_INCOMPLETE) { //The internal Request Sense command is completed successfully. sati_atapi_translate_request_sense_response( &fw_io->parent.stp.sequence, fw_io, fw_io ); *completion_status = SCI_FAILURE_IO_RESPONSE_VALID; } return SCI_SUCCESS; }
BOOL scic_cb_io_request_do_copy_rx_frames( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_io), SCIF_LOG_OBJECT_IO_REQUEST, "scic_cb_io_request_do_copy_rx_frames(0x%x) enter\n", fw_io )); // If the translation was a PIO DATA IN (i.e. read) and the request // was actually a READ payload operation, then copy the data, since // there will be SGL space allocated for the transfer. if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_PIO_DATA_IN) { if ( (fw_io->parent.stp.sequence.type == SATI_SEQUENCE_ATA_PASSTHROUGH_12) || (fw_io->parent.stp.sequence.type == SATI_SEQUENCE_ATA_PASSTHROUGH_16) || ( (fw_io->parent.stp.sequence.type >= SATI_SEQUENCE_TYPE_READ_MIN) && (fw_io->parent.stp.sequence.type <= SATI_SEQUENCE_TYPE_READ_MAX) ) ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_io), SCIF_LOG_OBJECT_IO_REQUEST, "scic_cb_io_request_do_copy_rx_frames(0x%x) TRUE\n", fw_io )); return TRUE; } } // For all other requests we leave the data in the core buffers. // This allows the translation to translate without having to have // separate space allocated into which to copy the data. return FALSE; }
/** * This method will perform the STP request completion processing common * to IO requests and task requests of all types * * @param[in] device This parameter specifies the device for which the * request is being completed. * @param[in] request This parameter specifies the request being completed. * * @return This method returns an indication as to whether the request * processing completed successfully. */ static SCI_STATUS scic_sds_stp_remote_device_complete_request( SCI_BASE_REMOTE_DEVICE_T * device, SCI_BASE_REQUEST_T * request ) { SCIC_SDS_REMOTE_DEVICE_T * this_device = (SCIC_SDS_REMOTE_DEVICE_T *)device; SCIC_SDS_REQUEST_T * the_request = (SCIC_SDS_REQUEST_T *)request; SCI_STATUS status; status = scic_sds_io_request_complete(the_request); if (status == SCI_SUCCESS) { status = scic_sds_port_complete_io( this_device->owning_port, this_device, the_request ); if (status == SCI_SUCCESS) { scic_sds_remote_device_decrement_request_count(this_device); if (the_request->sci_status == SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { //This request causes hardware error, device needs to be Lun Reset. //So here we force the state machine to IDLE state so the rest IOs //can reach RNC state handler, these IOs will be completed by RNC with //status of "DEVICE_RESET_REQUIRED", instead of "INVALID STATE". sci_base_state_machine_change_state( &this_device->ready_substate_machine, SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET ); } else if (scic_sds_remote_device_get_request_count(this_device) == 0) { sci_base_state_machine_change_state( &this_device->ready_substate_machine, SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE ); } } } if (status != SCI_SUCCESS) { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_device), SCIC_LOG_OBJECT_STP_REMOTE_TARGET, "Port:0x%x Device:0x%x Request:0x%x Status:0x%x could not complete\n", this_device->owning_port, this_device, the_request, status )); } return status; }
/** * @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 will attempt to destruct a framework controller. * This includes free any resources retreived from the user (e.g. * timers). * * @param[in] fw_controller This parameter specifies the framework * controller to destructed. * * @return none */ void scif_sas_controller_destruct( SCIF_SAS_CONTROLLER_T * fw_controller ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN, "scif_sas_controller_destruct(0x%x) enter\n", fw_controller )); }
/** * @brief This method provides default handling (i.e. returns an error); * for when the core issues a ready notification and such a * notification isn't supported. * * @param[in] remote_device This parameter specifies the remote device object * for which the notification has occured. * * @return none. */ void scif_sas_remote_device_default_ready_handler( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE, "RemoteDevice:0x%x State:0x%x invalid state to handle ready\n", fw_device, sci_base_state_machine_get_state(&fw_device->parent.state_machine) )); }