/** * @brief This method remove an expander device and its child devices, in order to * deal with a detected illeagal phy connection. * * @param[in] fw_domain The domain that a expander belongs to. * @param[in] fw_device The expander device to be removed. * * @return none. */ void scif_sas_domain_remove_expander_device( SCIF_SAS_DOMAIN_T * fw_domain, SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device; SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL; while (element != NULL) { curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); element = sci_fast_list_get_next(element); if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED && curr_smp_phy->u.end_device != NULL ) { if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY) current_device = curr_smp_phy->u.end_device; else current_device = curr_smp_phy->u.attached_phy->owning_device; scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device); } } //remove device itself scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device); }
/** * @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 ); }
void isci_task_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status) { struct ISCI_TASK_REQUEST *isci_task_request = (struct ISCI_TASK_REQUEST *)sci_object_get_association(task_request); struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller); struct ISCI_REMOTE_DEVICE *isci_remote_device = (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device); struct ISCI_REMOTE_DEVICE *pending_remote_device; BOOL retry_task = FALSE; union ccb *ccb = isci_task_request->ccb; isci_remote_device->is_resetting = FALSE; switch ((int)completion_status) { case SCI_TASK_SUCCESS: case SCI_TASK_FAILURE_RESPONSE_VALID: break; case SCI_TASK_FAILURE_INVALID_STATE: retry_task = TRUE; isci_log_message(0, "ISCI", "task failure (invalid state) - retrying\n"); break; case SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES: retry_task = TRUE; isci_log_message(0, "ISCI", "task failure (insufficient resources) - retrying\n"); break; case SCI_FAILURE_TIMEOUT: if (isci_controller->fail_on_task_timeout) { retry_task = FALSE; isci_log_message(0, "ISCI", "task timeout - not retrying\n"); scif_cb_domain_device_removed(isci_controller, isci_remote_device->domain, isci_remote_device); } else { retry_task = TRUE; isci_log_message(0, "ISCI", "task timeout - retrying\n"); } break; case SCI_TASK_FAILURE: case SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL: case SCI_TASK_FAILURE_INVALID_TAG: case SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR: case SCI_TASK_FAILURE_TERMINATED: case SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE: isci_log_message(0, "ISCI", "unhandled task completion code 0x%x\n", completion_status); break; default: isci_log_message(0, "ISCI", "unhandled task completion code 0x%x\n", completion_status); break; } if (isci_controller->is_frozen == TRUE) { isci_controller->is_frozen = FALSE; xpt_release_simq(isci_controller->sim, TRUE); } sci_pool_put(isci_controller->request_pool, (struct ISCI_REQUEST *)isci_task_request); /* Make sure we release the device queue, since it may have been frozen * if someone tried to start an I/O while the task was in progress. */ isci_remote_device_release_device_queue(isci_remote_device); if (retry_task == TRUE) isci_remote_device_reset(isci_remote_device, ccb); else { pending_remote_device = sci_fast_list_remove_head( &isci_controller->pending_device_reset_list); if (pending_remote_device != NULL) { /* Any resets that were triggered from an XPT_RESET_DEV * CCB are never put in the pending list if the request * pool is empty - they are given back to CAM to be * requeued. So we will alawys pass NULL here, * denoting that there is no CCB associated with the * device reset. */ isci_remote_device_reset(pending_remote_device, NULL); } else if (ccb != NULL) { /* There was a CCB associated with this reset, so mark * it complete and return it to CAM. */ ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_CMP; xpt_done(ccb); } } }
/** * @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 ); } }