/** * @brief This methods check each smp device in this domain. If there is at * least one smp device in discover or target reset activity, this * domain is considered in smp activity. Note this routine is not * called on fast IO path. * * @param[in] fw_domain The framework domain object * * @return BOOL value to indicate whether a domain is in SMP activity. */ BOOL scif_sas_domain_is_in_smp_activity( SCIF_SAS_DOMAIN_T * fw_domain ) { SCI_ABSTRACT_ELEMENT_T * current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); SCIF_SAS_REMOTE_DEVICE_T * current_device; while ( current_element != NULL ) { SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); scic_remote_device_get_protocols(current_device->core_object, &dev_protocols ); if (dev_protocols.u.bits.attached_smp_target && scif_sas_smp_remote_device_is_in_activity(current_device)) return TRUE; current_element = sci_abstract_list_get_next(current_element); } return FALSE; }
/** * @brief This methods finds the first device that has specific activity scheduled. * * @param[in] fw_domain The framework domain object * @param[in] smp_activity A specified smp activity. The valid range is [1,5]. * * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled. */ SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity( SCIF_SAS_DOMAIN_T * fw_domain, U8 smp_activity ) { SCI_ABSTRACT_ELEMENT_T * current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); SCIF_SAS_REMOTE_DEVICE_T * current_device; SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; //config route table activity has higher priority than discover activity. while ( current_element != NULL ) { current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); scic_remote_device_get_protocols(current_device->core_object, &dev_protocols); current_element = sci_abstract_list_get_next(current_element); if ( dev_protocols.u.bits.attached_smp_target && current_device->protocol_device.smp_device.scheduled_activity == smp_activity) { return current_device; } } return NULL; }
/** * @brief This methods finds a expander attached device by searching the domain's * device list using connected expander device and expander phy id. * * @param[in] fw_domain The framework domain object * @param[in] parent_device The expander device the target device attaches to. * @param[in] expander_phy_id The expander phy id that the target device owns. * * @return found remote device or a NULL value if no device found. */ SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device( SCIF_SAS_DOMAIN_T * fw_domain, SCIF_SAS_REMOTE_DEVICE_T * containing_device, U8 expander_phy_id ) { SCIF_SAS_REMOTE_DEVICE_T * fw_device; SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front( &fw_domain->remote_device_list ); //parent device must not be NULL. ASSERT(containing_device != NULL); // Search the abstract list to see if there is a remote device meets the // search condition. while (element != NULL) { fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) sci_abstract_list_get_object(element); // Check to see if this is the device for which we are searching. if ( (fw_device->containing_device == containing_device) && (fw_device->expander_phy_identifier == expander_phy_id) ) { return fw_device; } element = sci_abstract_list_get_next(element); } return SCI_INVALID_HANDLE; }
/** * @brief This method finds the a EA device that has target reset scheduled. * * @param[in] fw_domain The framework domain object * * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled. */ SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset( SCIF_SAS_DOMAIN_T * fw_domain ) { SCI_ABSTRACT_ELEMENT_T * current_element; SCIF_SAS_REMOTE_DEVICE_T * current_device; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN, "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n", fw_domain )); //search throught domain's device list to find the first sata device on spinup_hold current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); while (current_element != NULL ) { current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); current_element = sci_abstract_list_get_next(current_element); if ( current_device->ea_target_reset_request_scheduled != NULL ) { return current_device; } } return NULL; }
/** * @brief This method searches the whole domain and finds all the smp devices to * cancel their smp activities if there is any. * * @param[in] fw_domain The domain that its smp activities are to be canceled. * * @return none. */ void scif_sas_domain_cancel_smp_activities( SCIF_SAS_DOMAIN_T * fw_domain ) { SCI_ABSTRACT_ELEMENT_T * current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); SCIF_SAS_REMOTE_DEVICE_T * current_device; //purge all the outstanding internal IOs in HPQ. scif_sas_high_priority_request_queue_purge_domain( &fw_domain->controller->hprq, fw_domain ); while ( current_element != NULL ) { SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); scic_remote_device_get_protocols(current_device->core_object, &dev_protocols ); if (dev_protocols.u.bits.attached_smp_target) { scif_sas_smp_remote_device_cancel_smp_activity(current_device); } current_element = sci_abstract_list_get_next(current_element); } }
/** * @brief This method schedule clear affiliation activities for smp devices in * this domain. * * @param[in] fw_domain The domain that its smp devices are scheduled to clear * affiliation for all the EA SATA devices. * * @return none. */ void scif_sas_domain_schedule_clear_affiliation( SCIF_SAS_DOMAIN_T * fw_domain ) { SCI_ABSTRACT_ELEMENT_T * current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); SCIF_SAS_REMOTE_DEVICE_T * current_device; SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; //config route table activity has higher priority than discover activity. while ( current_element != NULL ) { current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); scic_remote_device_get_protocols(current_device->core_object, &dev_protocols); current_element = sci_abstract_list_get_next(current_element); if ( dev_protocols.u.bits.attached_smp_target ) { current_device->protocol_device.smp_device.scheduled_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION; } } }
/** * @brief This method starts domain's smp discover process from the top level expander. * * @param[in] fw_domain The framework domain that to start smp discover process. @ @param[in] top_expander The top level expander device to start smp discover process. * * @return None */ void scif_sas_domain_start_smp_discover( SCIF_SAS_DOMAIN_T * fw_domain, SCIF_SAS_REMOTE_DEVICE_T * top_expander ) { SCI_ABSTRACT_ELEMENT_T * current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); SCIF_SAS_REMOTE_DEVICE_T * current_device; // something changed behind expander // mark all the device behind expander to be NOT // is_currently_discovered. while ( current_element != NULL ) { current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); current_device->is_currently_discovered = FALSE; //reset all the devices' port witdh except the top expander. if (current_device->containing_device != NULL) current_device->device_port_width = 1; current_element = sci_abstract_list_get_next(current_element); } //expander device itself should be set to is_currently_discovered. top_expander->is_currently_discovered = TRUE; //kick off the smp discover process. scif_sas_smp_remote_device_start_discover(top_expander); }
/** * @brief This method implements the actions taken when entering the * STOPPING 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_stopping_state_enter( SCI_BASE_OBJECT_T * object ) { SCIF_SAS_REMOTE_DEVICE_T * fw_device; SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object; SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front( &fw_domain->remote_device_list ); SET_STATE_HANDLER( fw_domain, scif_sas_domain_state_handler_table, SCI_BASE_DOMAIN_STATE_STOPPING ); // This must be invoked after the state handlers are set to ensure // appropriate processing will occur if the user attempts to perform // additional actions. scif_sas_domain_transition_from_discovering_state(fw_domain); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_domain_stopping_state_enter(0x%x) enter\n", fw_domain )); scif_sas_high_priority_request_queue_purge_domain( &fw_domain->controller->hprq, fw_domain ); // Search the domain's list of devices and put them all in the STOPPING // state. while (element != NULL) { fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) sci_abstract_list_get_object(element); // This method will stop the core device. The core will terminate // all IO requests currently outstanding. fw_device->state_handlers->parent.stop_handler(&fw_device->parent); element = sci_abstract_list_get_next(element); } // Attempt to transition to the stopped state. scif_sas_domain_transition_to_stopped_state(fw_domain); }
/** * @brief Get the object currently pointed to by this iterator. * * @param[in] iterator_handle Handle to an iterator. * * @return void * : Object pointed to by this iterator. * @retval NULL If iterator is not currently pointing to a valid element. */ void * sci_iterator_get_current( SCI_ITERATOR_HANDLE_T iterator_handle ) { SCI_BASE_ITERATOR_T * iterator = (SCI_BASE_ITERATOR_T *)iterator_handle; void *current_object = NULL; if (iterator->current != NULL) { current_object = sci_abstract_list_get_object(iterator->current); } return current_object; }
SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address( SCI_DOMAIN_HANDLE_T domain, SCI_SAS_ADDRESS_T * sas_address ) { SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain; SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front( &fw_domain->remote_device_list ); SCIF_SAS_REMOTE_DEVICE_T * fw_device; SCI_SAS_ADDRESS_T fw_device_address; SCIF_LOG_TRACE(( sci_base_object_get_logger(domain), SCIF_LOG_OBJECT_DOMAIN, "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n", domain, sas_address )); // Search the abstract list to see if there is a remote device with the // same SAS address. while (element != NULL) { fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) sci_abstract_list_get_object(element); scic_remote_device_get_sas_address( fw_device->core_object, &fw_device_address ); // Check to see if this is the device for which we are searching. if ( (fw_device_address.low == sas_address->low) && (fw_device_address.high == sas_address->high) ) { return fw_device; } element = sci_abstract_list_get_next(element); } return SCI_INVALID_HANDLE; }
/** * @brief This method finishes domain's smp discover process and * update domain's remote device list. * * @param[in] fw_domain The framework domain that's to finish smp discover process. * * @return None */ void scif_sas_domain_finish_discover( SCIF_SAS_DOMAIN_T * fw_domain ) { SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL; SCI_ABSTRACT_ELEMENT_T * current_element = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_domain_finish_discover(0x%x) enter\n", fw_domain )); //need to scrub all the devices behind the expander. Check each //device's discover_status. if the is_currently_discovered is FALSE, means //the device is not been rediscovered. this device needs to be removed. current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); while (current_element != NULL ) { current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); //We must get the next element before we remove the current //device. Or else, we will get wrong next_element, since the erased //element has been put into free pool. current_element = sci_abstract_list_get_next(current_element); if ( current_device->is_currently_discovered == FALSE ) { // Notify the framework user of the device removal. scif_cb_domain_device_removed( fw_domain->controller, fw_domain, current_device ); } } sci_base_state_machine_change_state( &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY ); }
/** * @brief This methods finds the first device that is in STOPPED state and its * connection_rate is still in SPINUP_HOLD(value 3). * * @param[in] fw_domain The framework domain object * * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL. */ SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold( SCIF_SAS_DOMAIN_T * fw_domain ) { SCI_ABSTRACT_ELEMENT_T * current_element; SCIF_SAS_REMOTE_DEVICE_T * current_device; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_domain), SCIF_LOG_OBJECT_DOMAIN, "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n", fw_domain )); //search throught domain's device list to find the first sata device on spinup_hold current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); while (current_element != NULL ) { current_device = (SCIF_SAS_REMOTE_DEVICE_T *) sci_abstract_list_get_object(current_element); //We must get the next element before we remove the current //device. Or else, we will get wrong next_element, since the erased //element has been put into free pool. current_element = sci_abstract_list_get_next(current_element); if ( sci_base_state_machine_get_state(¤t_device->parent.state_machine) == SCI_BASE_REMOTE_DEVICE_STATE_STOPPED && scic_remote_device_get_connection_rate(current_device->core_object) == SCI_SATA_SPINUP_HOLD ) { return current_device; } } return NULL; }
/** * @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 ); } }