Index: head/sys/dev/isci/isci.h =================================================================== --- head/sys/dev/isci/isci.h (revision 231295) +++ head/sys/dev/isci/isci.h (revision 231296) @@ -1,302 +1,301 @@ /*- * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE2SOFTC(dev) ((struct isci_softc *) device_get_softc(dev)) #define DEVICE_TIMEOUT 1000 #define SCI_MAX_TIMERS 32 #define ISCI_NUM_PCI_BARS 2 #define ISCI_MAX_LUN 8 MALLOC_DECLARE(M_ISCI); struct ISCI_TIMER { struct callout callout; SCI_TIMER_CALLBACK_T callback; void *cookie; BOOL is_started; }; struct ISCI_REMOTE_DEVICE { uint32_t index; struct ISCI_DOMAIN *domain; SCI_REMOTE_DEVICE_HANDLE_T sci_object; BOOL is_resetting; uint32_t frozen_lun_mask; SCI_FAST_LIST_ELEMENT_T pending_device_reset_element; }; struct ISCI_DOMAIN { struct ISCI_CONTROLLER *controller; SCI_DOMAIN_HANDLE_T sci_object; uint8_t index; }; struct ISCI_MEMORY { bus_addr_t physical_address; bus_dma_tag_t dma_tag; bus_dmamap_t dma_map; POINTER_UINT virtual_address; uint32_t size; int error; }; struct ISCI_INTERRUPT_INFO { SCIC_CONTROLLER_HANDLER_METHODS_T *handlers; void *interrupt_target_handle; struct resource *res; int rid; void *tag; }; struct ISCI_CONTROLLER { struct isci_softc *isci; uint8_t index; SCI_CONTROLLER_HANDLE_T scif_controller_handle; struct ISCI_DOMAIN domain[SCI_MAX_DOMAINS]; BOOL is_started; uint32_t initial_discovery_mask; BOOL is_frozen; uint8_t *remote_device_memory; struct ISCI_MEMORY cached_controller_memory; struct ISCI_MEMORY uncached_controller_memory; struct ISCI_MEMORY request_memory; bus_dma_tag_t buffer_dma_tag; struct mtx lock; struct cam_sim *sim; struct cam_path *path; struct ISCI_REMOTE_DEVICE *remote_device[SCI_MAX_REMOTE_DEVICES]; void *timer_memory; SCIC_OEM_PARAMETERS_T oem_parameters; uint32_t oem_parameters_version; uint32_t queue_depth; uint32_t sim_queue_depth; SCI_FAST_LIST_T pending_device_reset_list; SCI_MEMORY_DESCRIPTOR_LIST_HANDLE_T mdl; SCI_POOL_CREATE(remote_device_pool, struct ISCI_REMOTE_DEVICE *, SCI_MAX_REMOTE_DEVICES); SCI_POOL_CREATE(request_pool, struct ISCI_REQUEST *, SCI_MAX_IO_REQUESTS); SCI_POOL_CREATE(timer_pool, struct ISCI_TIMER *, SCI_MAX_TIMERS); }; struct ISCI_REQUEST { SCI_CONTROLLER_HANDLE_T controller_handle; SCI_REMOTE_DEVICE_HANDLE_T remote_device_handle; bus_dma_tag_t dma_tag; bus_dmamap_t dma_map; SCI_PHYSICAL_ADDRESS physical_address; struct callout timer; }; struct ISCI_IO_REQUEST { struct ISCI_REQUEST parent; - SCI_STATUS status; SCI_IO_REQUEST_HANDLE_T sci_object; union ccb *ccb; uint32_t num_segments; uint32_t current_sge_index; bus_dma_segment_t *sge; }; struct ISCI_TASK_REQUEST { struct ISCI_REQUEST parent; struct scsi_sense_data sense_data; SCI_TASK_REQUEST_HANDLE_T sci_object; union ccb *ccb; }; struct ISCI_PCI_BAR { bus_space_tag_t bus_tag; bus_space_handle_t bus_handle; int resource_id; struct resource *resource; }; /* * One of these per allocated PCI device. */ struct isci_softc { struct ISCI_PCI_BAR pci_bar[ISCI_NUM_PCI_BARS]; struct ISCI_CONTROLLER controllers[SCI_MAX_CONTROLLERS]; SCI_LIBRARY_HANDLE_T sci_library_handle; void * sci_library_memory; SCIC_CONTROLLER_HANDLER_METHODS_T handlers[4]; struct ISCI_INTERRUPT_INFO interrupt_info[4]; uint32_t controller_count; uint32_t num_interrupts; uint32_t coalesce_number; uint32_t coalesce_timeout; device_t device; SCI_PCI_COMMON_HEADER_T pci_common_header; BOOL oem_parameters_found; struct intr_config_hook config_hook; }; int isci_allocate_resources(device_t device); int isci_allocate_dma_buffer(device_t device, struct ISCI_MEMORY *memory); void isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device, union ccb *ccb); /** * Returns the negotiated link rate (in KB/s) for the associated * remote device. Used to fill out bitrate field for GET_TRANS_SETTINGS. * Will match the negotiated link rate for the lowest numbered local phy * in the port/domain containing this remote device. */ uint32_t isci_remote_device_get_bitrate( struct ISCI_REMOTE_DEVICE *remote_device); void isci_remote_device_freeze_lun_queue( struct ISCI_REMOTE_DEVICE *remote_device, lun_id_t lun); void isci_remote_device_release_lun_queue( struct ISCI_REMOTE_DEVICE *remote_device, lun_id_t lun); void isci_remote_device_release_device_queue( struct ISCI_REMOTE_DEVICE * remote_device); void isci_request_construct(struct ISCI_REQUEST *request, SCI_CONTROLLER_HANDLE_T scif_controller_handle, bus_dma_tag_t io_buffer_dma_tag, bus_addr_t physical_address); #define isci_io_request_get_max_io_size() \ ((SCI_MAX_SCATTER_GATHER_ELEMENTS - 1) * PAGE_SIZE) #define isci_task_request_get_object_size() \ (sizeof(struct ISCI_TASK_REQUEST) + scif_task_request_get_object_size()) #define isci_io_request_get_object_size() \ (sizeof(struct ISCI_IO_REQUEST) + scif_io_request_get_object_size()) #define isci_request_get_object_size() \ max( \ isci_task_request_get_object_size(), \ isci_io_request_get_object_size() \ ) void isci_io_request_execute_scsi_io(union ccb *ccb, struct ISCI_CONTROLLER *controller); #if __FreeBSD_version >= 900026 void isci_io_request_execute_smp_io( union ccb *ccb, struct ISCI_CONTROLLER *controller); #endif void isci_io_request_timeout(void *); void isci_get_oem_parameters(struct isci_softc *isci); void isci_io_request_complete( SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, struct ISCI_IO_REQUEST * isci_request, SCI_IO_STATUS completion_status); void isci_task_request_complete( SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T io_request, SCI_TASK_STATUS completion_status); void isci_sysctl_initialize(struct isci_softc *isci); void isci_controller_construct(struct ISCI_CONTROLLER *controller, struct isci_softc *isci); SCI_STATUS isci_controller_initialize(struct ISCI_CONTROLLER *controller); int isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller); void isci_controller_domain_discovery_complete( struct ISCI_CONTROLLER *isci_controller, struct ISCI_DOMAIN *isci_domain); int isci_controller_attach_to_cam(struct ISCI_CONTROLLER *controller); void isci_controller_start(void *controller); void isci_domain_construct(struct ISCI_DOMAIN *domain, uint32_t domain_index, struct ISCI_CONTROLLER *controller); void isci_interrupt_setup(struct isci_softc *isci); void isci_interrupt_poll_handler(struct ISCI_CONTROLLER *controller); void isci_log_message(uint32_t verbosity, char *log_message_prefix, char *log_message, ...); extern uint32_t g_isci_debug_level; Index: head/sys/dev/isci/isci_io_request.c =================================================================== --- head/sys/dev/isci/isci_io_request.c (revision 231295) +++ head/sys/dev/isci/isci_io_request.c (revision 231296) @@ -1,923 +1,923 @@ /*- * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include /** * @brief This user callback will inform the user that an IO request has * completed. * * @param[in] controller This parameter specifies the controller on * which the IO request is completing. * @param[in] remote_device This parameter specifies the remote device on * which this request is completing. * @param[in] io_request This parameter specifies the IO request that has * completed. * @param[in] completion_status This parameter specifies the results of * the IO request operation. SCI_IO_SUCCESS indicates * successful completion. * * @return none */ void scif_cb_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T io_request, SCI_IO_STATUS completion_status) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)sci_object_get_association(io_request); scif_controller_complete_io(scif_controller, remote_device, io_request); isci_io_request_complete(scif_controller, remote_device, isci_request, completion_status); } void isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, struct ISCI_IO_REQUEST *isci_request, SCI_IO_STATUS completion_status) { struct ISCI_CONTROLLER *isci_controller; struct ISCI_REMOTE_DEVICE *isci_remote_device; union ccb *ccb; isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller); isci_remote_device = (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device); ccb = isci_request->ccb; ccb->ccb_h.status &= ~CAM_STATUS_MASK; switch (completion_status) { case SCI_IO_SUCCESS: case SCI_IO_SUCCESS_COMPLETE_BEFORE_START: #if __FreeBSD_version >= 900026 if (ccb->ccb_h.func_code == XPT_SMP_IO) { void *smp_response = scif_io_request_get_response_iu_address( isci_request->sci_object); memcpy(ccb->smpio.smp_response, smp_response, ccb->smpio.smp_response_len); } #endif ccb->ccb_h.status |= CAM_REQ_CMP; break; case SCI_IO_SUCCESS_IO_DONE_EARLY: ccb->ccb_h.status |= CAM_REQ_CMP; ccb->csio.resid = ccb->csio.dxfer_len - scif_io_request_get_number_of_bytes_transferred( isci_request->sci_object); break; case SCI_IO_FAILURE_RESPONSE_VALID: { SCI_SSP_RESPONSE_IU_T * response_buffer; uint32_t sense_length; int error_code, sense_key, asc, ascq; struct ccb_scsiio *csio = &ccb->csio; response_buffer = (SCI_SSP_RESPONSE_IU_T *) scif_io_request_get_response_iu_address( isci_request->sci_object); sense_length = sci_ssp_get_sense_data_length( response_buffer->sense_data_length); sense_length = MIN(csio->sense_len, sense_length); memcpy(&csio->sense_data, response_buffer->data, sense_length); csio->sense_resid = csio->sense_len - sense_length; csio->scsi_status = response_buffer->status; ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; ccb->ccb_h.status |= CAM_AUTOSNS_VALID; scsi_extract_sense( &csio->sense_data, &error_code, &sense_key, &asc, &ascq ); isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], csio->scsi_status, sense_key, asc, ascq); break; } case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: isci_remote_device_reset(isci_remote_device, NULL); /* drop through */ case SCI_IO_FAILURE_TERMINATED: ccb->ccb_h.status |= CAM_REQ_TERMIO; isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]); break; case SCI_IO_FAILURE_INVALID_STATE: case SCI_IO_FAILURE_INSUFFICIENT_RESOURCES: ccb->ccb_h.status |= CAM_REQUEUE_REQ; isci_remote_device_freeze_lun_queue(isci_remote_device, ccb->ccb_h.target_lun); break; case SCI_IO_FAILURE_INVALID_REMOTE_DEVICE: ccb->ccb_h.status |= CAM_DEV_NOT_THERE; break; case SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE: { struct ccb_relsim ccb_relsim; struct cam_path *path; xpt_create_path(&path, NULL, cam_sim_path(isci_controller->sim), isci_remote_device->index, 0); xpt_setup_ccb(&ccb_relsim.ccb_h, path, 5); ccb_relsim.ccb_h.func_code = XPT_REL_SIMQ; ccb_relsim.ccb_h.flags = CAM_DEV_QFREEZE; ccb_relsim.release_flags = RELSIM_ADJUST_OPENINGS; ccb_relsim.openings = scif_remote_device_get_max_queue_depth(remote_device); xpt_action((union ccb *)&ccb_relsim); xpt_free_path(path); ccb->ccb_h.status |= CAM_REQUEUE_REQ; } break; case SCI_IO_FAILURE: case SCI_IO_FAILURE_REQUIRES_SCSI_ABORT: case SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL: case SCI_IO_FAILURE_PROTOCOL_VIOLATION: case SCI_IO_FAILURE_INVALID_PARAMETER_VALUE: case SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR: default: isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0], completion_status); ccb->ccb_h.status |= CAM_REQ_CMP_ERR; break; } if (ccb->ccb_h.status != CAM_REQ_CMP) { /* ccb will be completed with some type of non-success * status. So temporarily freeze the queue until the * upper layers can act on the status. The CAM_DEV_QFRZN * flag will then release the queue after the status is * acted upon. */ ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, 1); } callout_stop(&isci_request->parent.timer); bus_dmamap_sync(isci_request->parent.dma_tag, isci_request->parent.dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(isci_request->parent.dma_tag, isci_request->parent.dma_map); if (isci_remote_device->frozen_lun_mask != 0 && !(ccb->ccb_h.status & CAM_REQUEUE_REQ)) isci_remote_device_release_device_queue(isci_remote_device); xpt_done(ccb); isci_request->ccb = NULL; 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_request); } /** * @brief This callback method asks the user to provide the physical * address for the supplied virtual address when building an * io request object. * * @param[in] controller This parameter is the core controller object * handle. * @param[in] io_request This parameter is the io request object handle * for which the physical address is being requested. * @param[in] virtual_address This paramter is the virtual address which * is to be returned as a physical address. * @param[out] physical_address The physical address for the supplied virtual * address. * * @return None. */ void scic_cb_io_request_get_physical_address(SCI_CONTROLLER_HANDLE_T controller, SCI_IO_REQUEST_HANDLE_T io_request, void *virtual_address, SCI_PHYSICAL_ADDRESS *physical_address) { SCI_IO_REQUEST_HANDLE_T scif_request = sci_object_get_association(io_request); struct ISCI_REQUEST *isci_request = sci_object_get_association(scif_request); if(isci_request != NULL) { /* isci_request is not NULL, meaning this is a request initiated * by CAM or the isci layer (i.e. device reset for I/O * timeout). Therefore we can calculate the physical address * based on the address we stored in the struct ISCI_REQUEST * object. */ *physical_address = isci_request->physical_address + (uintptr_t)virtual_address - (uintptr_t)isci_request; } else { /* isci_request is NULL, meaning this is a request generated * internally by SCIL (i.e. for SMP requests or NCQ error * recovery). Therefore we calculate the physical address * based on the controller's uncached controller memory buffer, * since we know that this is what SCIL uses for internal * framework requests. */ SCI_CONTROLLER_HANDLE_T scif_controller = (SCI_CONTROLLER_HANDLE_T) sci_object_get_association(controller); struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller); U64 virt_addr_offset = (uintptr_t)virtual_address - (U64)isci_controller->uncached_controller_memory.virtual_address; *physical_address = isci_controller->uncached_controller_memory.physical_address + virt_addr_offset; } } /** * @brief This callback method asks the user to provide the address for * the command descriptor block (CDB) associated with this IO request. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the virtual address of the CDB. */ void * scif_cb_io_request_get_cdb_address(void * scif_user_io_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; return (isci_request->ccb->csio.cdb_io.cdb_bytes); } /** * @brief This callback method asks the user to provide the length of * the command descriptor block (CDB) associated with this IO request. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the length of the CDB. */ uint32_t scif_cb_io_request_get_cdb_length(void * scif_user_io_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; return (isci_request->ccb->csio.cdb_len); } /** * @brief This callback method asks the user to provide the Logical Unit (LUN) * associated with this IO request. * * @note The contents of the value returned from this callback are defined * by the protocol standard (e.g. T10 SAS specification). Please * refer to the transport command information unit description * in the associated standard. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the LUN associated with this request. */ uint32_t scif_cb_io_request_get_lun(void * scif_user_io_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; return (isci_request->ccb->ccb_h.target_lun); } /** * @brief This callback method asks the user to provide the task attribute * associated with this IO request. * * @note The contents of the value returned from this callback are defined * by the protocol standard (e.g. T10 SAS specification). Please * refer to the transport command information unit description * in the associated standard. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the task attribute associated with this * IO request. */ uint32_t scif_cb_io_request_get_task_attribute(void * scif_user_io_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; uint32_t task_attribute; if((isci_request->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) switch(isci_request->ccb->csio.tag_action) { case MSG_HEAD_OF_Q_TAG: task_attribute = SCI_SAS_HEAD_OF_QUEUE_ATTRIBUTE; break; case MSG_ORDERED_Q_TAG: task_attribute = SCI_SAS_ORDERED_ATTRIBUTE; break; case MSG_ACA_TASK: task_attribute = SCI_SAS_ACA_ATTRIBUTE; break; default: task_attribute = SCI_SAS_SIMPLE_ATTRIBUTE; break; } else task_attribute = SCI_SAS_SIMPLE_ATTRIBUTE; return (task_attribute); } /** * @brief This callback method asks the user to provide the command priority * associated with this IO request. * * @note The contents of the value returned from this callback are defined * by the protocol standard (e.g. T10 SAS specification). Please * refer to the transport command information unit description * in the associated standard. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the command priority associated with this * IO request. */ uint32_t scif_cb_io_request_get_command_priority(void * scif_user_io_request) { return (0); } /** * @brief This method simply returns the virtual address associated * with the scsi_io and byte_offset supplied parameters. * * @note This callback is not utilized in the fast path. The expectation * is that this method is utilized for items such as SCSI to ATA * translation for commands like INQUIRY, READ CAPACITY, etc. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * @param[in] byte_offset This parameter specifies the offset into the data * buffers pointed to by the SGL. The byte offset starts at 0 * and continues until the last byte pointed to be the last SGL * element. * * @return A virtual address pointer to the location specified by the * parameters. */ uint8_t * scif_cb_io_request_get_virtual_address_from_sgl(void * scif_user_io_request, uint32_t byte_offset) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; return (isci_request->ccb->csio.data_ptr + byte_offset); } /** * @brief This callback method asks the user to provide the number of * bytes to be transfered as part of this request. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the number of payload data bytes to be * transfered for this IO request. */ uint32_t scif_cb_io_request_get_transfer_length(void * scif_user_io_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; return (isci_request->ccb->csio.dxfer_len); } /** * @brief This callback method asks the user to provide the data direction * for this request. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * * @return This method returns the value of SCI_IO_REQUEST_DATA_OUT, * SCI_IO_REQUEST_DATA_IN, or SCI_IO_REQUEST_NO_DATA. */ SCI_IO_REQUEST_DATA_DIRECTION scif_cb_io_request_get_data_direction(void * scif_user_io_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; switch (isci_request->ccb->ccb_h.flags & CAM_DIR_MASK) { case CAM_DIR_IN: return (SCI_IO_REQUEST_DATA_IN); case CAM_DIR_OUT: return (SCI_IO_REQUEST_DATA_OUT); default: return (SCI_IO_REQUEST_NO_DATA); } } /** * @brief This callback method asks the user to provide the address * to where the next Scatter-Gather Element is located. * * Details regarding usage: * - Regarding the first SGE: the user should initialize an index, * or a pointer, prior to construction of the request that will * reference the very first scatter-gather element. This is * important since this method is called for every scatter-gather * element, including the first element. * - Regarding the last SGE: the user should return NULL from this * method when this method is called and the SGL has exhausted * all elements. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * @param[in] current_sge_address This parameter specifies the address for * the current SGE (i.e. the one that has just processed). * @param[out] next_sge An address specifying the location for the next scatter * gather element to be processed. * * @return None. */ void scif_cb_io_request_get_next_sge(void * scif_user_io_request, void * current_sge_address, void ** next_sge) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)scif_user_io_request; if (isci_request->current_sge_index == isci_request->num_segments) *next_sge = NULL; else { bus_dma_segment_t *sge = &isci_request->sge[isci_request->current_sge_index]; isci_request->current_sge_index++; *next_sge = sge; } } /** * @brief This callback method asks the user to provide the contents of the * "address" field in the Scatter-Gather Element. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * @param[in] sge_address This parameter specifies the address for the * SGE from which to retrieve the address field. * * @return A physical address specifying the contents of the SGE's address * field. */ SCI_PHYSICAL_ADDRESS scif_cb_sge_get_address_field(void *scif_user_io_request, void *sge_address) { bus_dma_segment_t *sge = (bus_dma_segment_t *)sge_address; return ((SCI_PHYSICAL_ADDRESS)sge->ds_addr); } /** * @brief This callback method asks the user to provide the contents of the * "length" field in the Scatter-Gather Element. * * @param[in] scif_user_io_request This parameter points to the user's * IO request object. It is a cookie that allows the user to * provide the necessary information for this callback. * @param[in] sge_address This parameter specifies the address for the * SGE from which to retrieve the address field. * * @return This method returns the length field specified inside the SGE * referenced by the sge_address parameter. */ uint32_t scif_cb_sge_get_length_field(void *scif_user_io_request, void *sge_address) { bus_dma_segment_t *sge = (bus_dma_segment_t *)sge_address; return ((uint32_t)sge->ds_len); } void isci_request_construct(struct ISCI_REQUEST *request, SCI_CONTROLLER_HANDLE_T scif_controller_handle, bus_dma_tag_t io_buffer_dma_tag, bus_addr_t physical_address) { request->controller_handle = scif_controller_handle; request->dma_tag = io_buffer_dma_tag; request->physical_address = physical_address; bus_dmamap_create(request->dma_tag, 0, &request->dma_map); callout_init(&request->timer, CALLOUT_MPSAFE); } static void isci_io_request_construct(void *arg, bus_dma_segment_t *seg, int nseg, int error) { union ccb *ccb; struct ISCI_IO_REQUEST *io_request = (struct ISCI_IO_REQUEST *)arg; SCI_REMOTE_DEVICE_HANDLE_T *device = io_request->parent.remote_device_handle; SCI_STATUS status; io_request->num_segments = nseg; io_request->sge = seg; ccb = io_request->ccb; /* XXX More cleanup is needed here */ if ((nseg == 0) || (error != 0)) { ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } - io_request->status = scif_io_request_construct( + status = scif_io_request_construct( io_request->parent.controller_handle, io_request->parent.remote_device_handle, SCI_CONTROLLER_INVALID_IO_TAG, (void *)io_request, (void *)((char*)io_request + sizeof(struct ISCI_IO_REQUEST)), &io_request->sci_object); - if (io_request->status != SCI_SUCCESS) { + if (status != SCI_SUCCESS) { isci_io_request_complete(io_request->parent.controller_handle, - device, io_request, io_request->status); + device, io_request, (SCI_IO_STATUS)status); return; } sci_object_set_association(io_request->sci_object, io_request); bus_dmamap_sync(io_request->parent.dma_tag, io_request->parent.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); status = (SCI_STATUS)scif_controller_start_io( io_request->parent.controller_handle, device, io_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG); if (status != SCI_SUCCESS) { isci_io_request_complete(io_request->parent.controller_handle, - device, io_request, status); + device, io_request, (SCI_IO_STATUS)status); return; } if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) callout_reset(&io_request->parent.timer, ccb->ccb_h.timeout, isci_io_request_timeout, io_request); } void isci_io_request_execute_scsi_io(union ccb *ccb, struct ISCI_CONTROLLER *controller) { struct ccb_scsiio *csio = &ccb->csio; target_id_t target_id = ccb->ccb_h.target_id; struct ISCI_REQUEST *request; struct ISCI_IO_REQUEST *io_request; struct ISCI_REMOTE_DEVICE *device = controller->remote_device[target_id]; int error; if (device == NULL) { ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_DEV_NOT_THERE; xpt_done(ccb); return; } if (sci_pool_empty(controller->request_pool)) { ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQUEUE_REQ; xpt_freeze_simq(controller->sim, 1); controller->is_frozen = TRUE; xpt_done(ccb); return; } ASSERT(device->is_resetting == FALSE); sci_pool_get(controller->request_pool, request); io_request = (struct ISCI_IO_REQUEST *)request; io_request->ccb = ccb; io_request->current_sge_index = 0; io_request->parent.remote_device_handle = device->sci_object; if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) != 0) panic("Unexpected CAM_SCATTER_VALID flag! flags = 0x%x\n", ccb->ccb_h.flags); if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0) panic("Unexpected CAM_DATA_PHYS flag! flags = 0x%x\n", ccb->ccb_h.flags); error = bus_dmamap_load(io_request->parent.dma_tag, io_request->parent.dma_map, csio->data_ptr, csio->dxfer_len, isci_io_request_construct, io_request, 0x0); /* A resource shortage from BUSDMA will be automatically * continued at a later point, pushing the CCB processing * forward, which will in turn unfreeze the simq. */ if (error == EINPROGRESS) { xpt_freeze_simq(controller->sim, 1); ccb->ccb_h.flags |= CAM_RELEASE_SIMQ; } } void isci_io_request_timeout(void *arg) { struct ISCI_IO_REQUEST *request = (struct ISCI_IO_REQUEST *)arg; struct ISCI_REMOTE_DEVICE *remote_device = (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(request->parent.remote_device_handle); struct ISCI_CONTROLLER *controller = remote_device->domain->controller; mtx_lock(&controller->lock); isci_remote_device_reset(remote_device, NULL); mtx_unlock(&controller->lock); } #if __FreeBSD_version >= 900026 /** * @brief This callback method gets the size of and pointer to the buffer * (if any) containing the request buffer for an SMP request. * * @param[in] core_request This parameter specifies the SCI core's request * object associated with the SMP request. * @param[out] smp_request_buffer This parameter returns a pointer to the * payload portion of the SMP request - i.e. everything after * the SMP request header. * * @return Size of the request buffer in bytes. This does *not* include * the size of the SMP request header. */ static uint32_t smp_io_request_cb_get_request_buffer(SCI_IO_REQUEST_HANDLE_T core_request, uint8_t ** smp_request_buffer) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *) sci_object_get_association(sci_object_get_association(core_request)); *smp_request_buffer = isci_request->ccb->smpio.smp_request + sizeof(SMP_REQUEST_HEADER_T); return (isci_request->ccb->smpio.smp_request_len - sizeof(SMP_REQUEST_HEADER_T)); } /** * @brief This callback method gets the SMP function for an SMP request. * * @param[in] core_request This parameter specifies the SCI core's request * object associated with the SMP request. * * @return SMP function for the SMP request. */ static uint8_t smp_io_request_cb_get_function(SCI_IO_REQUEST_HANDLE_T core_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *) sci_object_get_association(sci_object_get_association(core_request)); SMP_REQUEST_HEADER_T *header = (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request; return (header->function); } /** * @brief This callback method gets the SMP frame type for an SMP request. * * @param[in] core_request This parameter specifies the SCI core's request * object associated with the SMP request. * * @return SMP frame type for the SMP request. */ static uint8_t smp_io_request_cb_get_frame_type(SCI_IO_REQUEST_HANDLE_T core_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *) sci_object_get_association(sci_object_get_association(core_request)); SMP_REQUEST_HEADER_T *header = (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request; return (header->smp_frame_type); } /** * @brief This callback method gets the allocated response length for an SMP request. * * @param[in] core_request This parameter specifies the SCI core's request * object associated with the SMP request. * * @return Allocated response length for the SMP request. */ static uint8_t smp_io_request_cb_get_allocated_response_length( SCI_IO_REQUEST_HANDLE_T core_request) { struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *) sci_object_get_association(sci_object_get_association(core_request)); SMP_REQUEST_HEADER_T *header = (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request; return (header->allocated_response_length); } static SCI_STATUS isci_smp_request_construct(struct ISCI_IO_REQUEST *request) { SCI_STATUS status; SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T callbacks; status = scif_request_construct(request->parent.controller_handle, request->parent.remote_device_handle, SCI_CONTROLLER_INVALID_IO_TAG, (void *)request, (void *)((char*)request + sizeof(struct ISCI_IO_REQUEST)), &request->sci_object); if (status == SCI_SUCCESS) { callbacks.scic_cb_smp_passthru_get_request = &smp_io_request_cb_get_request_buffer; callbacks.scic_cb_smp_passthru_get_function = &smp_io_request_cb_get_function; callbacks.scic_cb_smp_passthru_get_frame_type = &smp_io_request_cb_get_frame_type; callbacks.scic_cb_smp_passthru_get_allocated_response_length = &smp_io_request_cb_get_allocated_response_length; /* create the smp passthrough part of the io request */ status = scic_io_request_construct_smp_pass_through( scif_io_request_get_scic_handle(request->sci_object), &callbacks); } return (status); } void isci_io_request_execute_smp_io(union ccb *ccb, struct ISCI_CONTROLLER *controller) { SCI_STATUS status; target_id_t target_id = ccb->ccb_h.target_id; struct ISCI_REQUEST *request; struct ISCI_IO_REQUEST *io_request; SCI_REMOTE_DEVICE_HANDLE_T smp_device_handle; struct ISCI_REMOTE_DEVICE *end_device = controller->remote_device[target_id]; /* SMP commands are sent to an end device, because SMP devices are not * exposed to the kernel. It is our responsibility to use this method * to get the SMP device that contains the specified end device. If * the device is direct-attached, the handle will come back NULL, and * we'll just fail the SMP_IO with DEV_NOT_THERE. */ scif_remote_device_get_containing_device(end_device->sci_object, &smp_device_handle); if (smp_device_handle == NULL) { ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_DEV_NOT_THERE; xpt_done(ccb); return; } if (sci_pool_empty(controller->request_pool)) { ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQUEUE_REQ; xpt_freeze_simq(controller->sim, 1); controller->is_frozen = TRUE; xpt_done(ccb); return; } ASSERT(device->is_resetting == FALSE); sci_pool_get(controller->request_pool, request); io_request = (struct ISCI_IO_REQUEST *)request; io_request->ccb = ccb; io_request->parent.remote_device_handle = smp_device_handle; status = isci_smp_request_construct(io_request); if (status != SCI_SUCCESS) { isci_io_request_complete(controller->scif_controller_handle, - smp_device_handle, io_request, status); + smp_device_handle, io_request, (SCI_IO_STATUS)status); return; } sci_object_set_association(io_request->sci_object, io_request); status = (SCI_STATUS) scif_controller_start_io( controller->scif_controller_handle, smp_device_handle, io_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG); if (status != SCI_SUCCESS) { isci_io_request_complete(controller->scif_controller_handle, - smp_device_handle, io_request, status); + smp_device_handle, io_request, (SCI_IO_STATUS)status); return; } if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) callout_reset(&io_request->parent.timer, ccb->ccb_h.timeout, isci_io_request_timeout, request); } #endif Index: head/sys/dev/isci/isci_remote_device.c =================================================================== --- head/sys/dev/isci/isci_remote_device.c (revision 231295) +++ head/sys/dev/isci/isci_remote_device.c (revision 231296) @@ -1,298 +1,298 @@ /*- * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include /** * @brief This callback method informs the framework user that the remote * device is ready and capable of processing IO requests. * * @param[in] controller This parameter specifies the controller object * with which this callback is associated. * @param[in] domain This parameter specifies the domain object with * which this callback is associated. * @param[in] remote_device This parameter specifies the device object with * which this callback is associated. * * @return none */ void scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller, SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) { struct ISCI_REMOTE_DEVICE *isci_remote_device = sci_object_get_association(remote_device); struct ISCI_CONTROLLER *isci_controller = sci_object_get_association(controller); uint32_t device_index = isci_remote_device->index; if (isci_controller->remote_device[device_index] == NULL) { /* This new device is now ready, so put it in the controller's * remote device list so it is visible to CAM. */ isci_controller->remote_device[device_index] = isci_remote_device; if (isci_controller->sim != NULL) { /* The sim object is not NULL, meaning we have attached * the controller to CAM already. In that case, create * a CCB to instruct CAM to rescan this device. * If the sim object is NULL, this device will get * scanned as part of the initial scan when the * controller is attached to CAM. */ union ccb *ccb = xpt_alloc_ccb_nowait(); xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(isci_controller->sim), isci_remote_device->index, CAM_LUN_WILDCARD); xpt_rescan(ccb); } } isci_remote_device_release_device_queue(isci_remote_device); } /** * @brief This callback method informs the framework user that the remote * device is not ready. Thus, it is incapable of processing IO * requests. * * @param[in] controller This parameter specifies the controller object * with which this callback is associated. * @param[in] domain This parameter specifies the domain object with * which this callback is associated. * @param[in] remote_device This parameter specifies the device object with * which this callback is associated. * * @return none */ void scif_cb_remote_device_not_ready(SCI_CONTROLLER_HANDLE_T controller, SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device) { } /** * @brief This callback method informs the framework user that the remote * device failed. This typically occurs shortly after the device * has been discovered, during the configuration phase for the device. * * @param[in] controller This parameter specifies the controller object * with which this callback is associated. * @param[in] domain This parameter specifies the domain object with * which this callback is associated. * @param[in] remote_device This parameter specifies the device object with * which this callback is associated. * @param[in] status This parameter specifies the specific failure condition * associated with this device failure. * * @return none */ void scif_cb_remote_device_failed(SCI_CONTROLLER_HANDLE_T controller, SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_STATUS status) { } void isci_remote_device_reset(struct ISCI_REMOTE_DEVICE *remote_device, union ccb *ccb) { struct ISCI_CONTROLLER *controller = remote_device->domain->controller; struct ISCI_REQUEST *request; struct ISCI_TASK_REQUEST *task_request; SCI_STATUS status; if (remote_device->is_resetting == TRUE) { /* device is already being reset, so return immediately */ return; } if (sci_pool_empty(controller->request_pool)) { /* No requests are available in our request pool. If this reset is tied * to a CCB, ask CAM to requeue it. Otherwise, we need to put it on our * pending device reset list, so that the reset will occur when a request * frees up. */ if (ccb == NULL) sci_fast_list_insert_tail( &controller->pending_device_reset_list, &remote_device->pending_device_reset_element); else { ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQUEUE_REQ; xpt_done(ccb); } return; } isci_log_message(0, "ISCI", "Sending reset to device on controller %d domain %d CAM index %d\n", controller->index, remote_device->domain->index, remote_device->index ); sci_pool_get(controller->request_pool, request); task_request = (struct ISCI_TASK_REQUEST *)request; task_request->parent.remote_device_handle = remote_device->sci_object; task_request->ccb = ccb; remote_device->is_resetting = TRUE; status = (SCI_STATUS) scif_task_request_construct( controller->scif_controller_handle, remote_device->sci_object, SCI_CONTROLLER_INVALID_IO_TAG, (void *)task_request, (void *)((char*)task_request + sizeof(struct ISCI_TASK_REQUEST)), &task_request->sci_object); if (status != SCI_SUCCESS) { isci_task_request_complete(controller->scif_controller_handle, remote_device->sci_object, task_request->sci_object, - status); + (SCI_TASK_STATUS)status); return; } status = (SCI_STATUS)scif_controller_start_task( controller->scif_controller_handle, remote_device->sci_object, task_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG); if (status != SCI_SUCCESS) { isci_task_request_complete( controller->scif_controller_handle, remote_device->sci_object, task_request->sci_object, - status); + (SCI_TASK_STATUS)status); return; } } uint32_t isci_remote_device_get_bitrate(struct ISCI_REMOTE_DEVICE *remote_device) { struct ISCI_DOMAIN *domain = remote_device->domain; struct ISCI_CONTROLLER *controller = domain->controller; SCI_PORT_HANDLE_T port_handle; SCIC_PORT_PROPERTIES_T port_properties; uint8_t phy_index; SCI_PHY_HANDLE_T phy_handle; SCIC_PHY_PROPERTIES_T phy_properties; /* get a handle to the port associated with this remote device's * domain */ port_handle = scif_domain_get_scic_port_handle(domain->sci_object); scic_port_get_properties(port_handle, &port_properties); /* get the lowest numbered phy in the port */ phy_index = 0; while ((port_properties.phy_mask != 0) && !(port_properties.phy_mask & 0x1)) { phy_index++; port_properties.phy_mask >>= 1; } /* get the properties for the lowest numbered phy */ scic_controller_get_phy_handle( scif_controller_get_scic_handle(controller->scif_controller_handle), phy_index, &phy_handle); scic_phy_get_properties(phy_handle, &phy_properties); switch (phy_properties.negotiated_link_rate) { case SCI_SAS_150_GB: return (150000); case SCI_SAS_300_GB: return (300000); case SCI_SAS_600_GB: return (600000); default: return (0); } } void isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, lun_id_t lun) { if (!(remote_device->frozen_lun_mask & (1 << lun))) { struct cam_path *path; xpt_create_path(&path, xpt_periph, cam_sim_path(remote_device->domain->controller->sim), remote_device->index, lun); xpt_freeze_devq(path, 1); xpt_free_path(path); remote_device->frozen_lun_mask |= (1 << lun); } } void isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, lun_id_t lun) { if (remote_device->frozen_lun_mask & (1 << lun)) { struct cam_path *path; xpt_create_path(&path, xpt_periph, cam_sim_path(remote_device->domain->controller->sim), remote_device->index, lun); xpt_release_devq(path, 1, TRUE); xpt_free_path(path); remote_device->frozen_lun_mask &= ~(1 << lun); } } void isci_remote_device_release_device_queue( struct ISCI_REMOTE_DEVICE *remote_device) { lun_id_t lun; for (lun = 0; lun < ISCI_MAX_LUN; lun++) isci_remote_device_release_lun_queue(remote_device, lun); } Index: head/sys/dev/isci/scil/sati_abort_task_set.c =================================================================== --- head/sys/dev/isci/scil/sati_abort_task_set.c (revision 231295) +++ head/sys/dev/isci/scil/sati_abort_task_set.c (revision 231296) @@ -1,177 +1,177 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the method implementations required to * translate the SCSI abort task set command. */ #if !defined(DISABLE_SATI_TASK_MANAGEMENT) #include #include #include #include #include #include #include //****************************************************************************** //* P U B L I C M E T H O D S //****************************************************************************** #if !defined(DISABLE_SATI_ABORT_TASK_SET) /** * @brief This method will translate the abort task set SCSI task request into an * ATA READ LOG EXT command. For more information on the parameters * passed to this method, please reference sati_translate_command(). * * @return Indicate if the command translation succeeded. * @retval SCI_SUCCESS This is returned if the command translation was * successful. */ SATI_STATUS sati_abort_task_set_translate_command( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * scsi_io, void * ata_io ) { U8 * register_fis; //ATA Read Log Ext with log address set to 0x10 sati_ata_read_log_ext_construct( ata_io, sequence, ATA_LOG_PAGE_NCQ_ERROR, sizeof(ATA_NCQ_COMMAND_ERROR_LOG_T) ); register_fis = sati_cb_get_h2d_register_fis_address(ata_io); sati_set_sata_command_flag(register_fis); sequence->type = SATI_SEQUENCE_ABORT_TASK_SET; sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE; return SATI_SUCCESS; } SATI_STATUS sati_abort_task_set_translate_data( SATI_TRANSLATOR_SEQUENCE_T * sequence, void * ata_input_data, void * scsi_task ) { ATA_NCQ_COMMAND_ERROR_LOG_T * log = (ATA_NCQ_COMMAND_ERROR_LOG_T *)ata_input_data; U8 tag_index; sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA; for (tag_index = 0; tag_index < 32; tag_index++) { - void * matching_command; - SCI_STATUS completion_status; + void * matching_command; + SCI_IO_STATUS completion_status; sati_cb_device_get_request_by_ncq_tag( scsi_task, tag_index, matching_command ); if (matching_command != NULL) { if ( (log->ncq_tag == tag_index) && (log->nq == 0) // nq==1 means a non-queued command // caused this failure ) { sati_translate_error(sequence, matching_command, log->error); - completion_status = SCI_FAILURE_IO_RESPONSE_VALID; + completion_status = SCI_IO_FAILURE_RESPONSE_VALID; if(sequence->state == SATI_SEQUENCE_STATE_READ_ERROR) { //Uncorrectable read error, return additional sense data sati_scsi_read_ncq_error_sense_construct( sequence, matching_command, ata_input_data, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_MEDIUM_ERROR, SCSI_ASC_UNRECOVERED_READ_ERROR, SCSI_ASCQ_UNRECOVERED_READ_ERROR ); } } else { - completion_status = SCI_FAILURE_IO_TERMINATED; + completion_status = SCI_IO_FAILURE_TERMINATED; } sati_cb_io_request_complete(matching_command, completion_status); } } sequence->state = SATI_SEQUENCE_STATE_FINAL; return SATI_COMPLETE; } #endif // !defined(DISABLE_SATI_ABORT_TASK_SET) #endif // !defined(DISABLE_SATI_TASK_MANAGEMENT) Index: head/sys/dev/isci/scil/scic_sds_controller.c =================================================================== --- head/sys/dev/isci/scil/scic_sds_controller.c (revision 231295) +++ head/sys/dev/isci/scil/scic_sds_controller.c (revision 231296) @@ -1,7042 +1,7042 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the implementation of the SCIC_SDS_CONTROLLER * public, protected, and private methods. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SCU_CONTEXT_RAM_INIT_STALL_TIME 200 #define SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT 3 #define SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT 3 #define SCU_MAX_ZPT_DWORD_INDEX 131 /** * The number of milliseconds to wait for a phy to start. */ #define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT 100 /** * The number of milliseconds to wait while a given phy is consuming * power before allowing another set of phys to consume power. * Ultimately, this will be specified by OEM parameter. */ #define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL 500 /** * This macro will return the cycle bit of the completion queue entry */ #define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000) /** * This macro will normalize the completion queue get pointer so its value * can be used as an index into an array */ #define NORMALIZE_GET_POINTER(x) \ ((x) & SMU_COMPLETION_QUEUE_GET_POINTER_MASK) /** * This macro will normalize the completion queue put pointer so its value * can be used as an array inde */ #define NORMALIZE_PUT_POINTER(x) \ ((x) & SMU_COMPLETION_QUEUE_PUT_POINTER_MASK) /** * This macro will normalize the completion queue cycle pointer so it * matches the completion queue cycle bit */ #define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \ (((U32)(SMU_CQGR_CYCLE_BIT & (x))) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT)) /** * This macro will normalize the completion queue event entry so its value * can be used as an index. */ #define NORMALIZE_EVENT_POINTER(x) \ ( \ ((U32)((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK)) \ >> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \ ) /** * This macro will increment the controllers completion queue index value * and possibly toggle the cycle bit if the completion queue index wraps * back to 0. */ #define INCREMENT_COMPLETION_QUEUE_GET(controller, index, cycle) \ INCREMENT_QUEUE_GET( \ (index), \ (cycle), \ (controller)->completion_queue_entries, \ SMU_CQGR_CYCLE_BIT \ ) /** * This macro will increment the controllers event queue index value and * possibly toggle the event cycle bit if the event queue index wraps back * to 0. */ #define INCREMENT_EVENT_QUEUE_GET(controller, index, cycle) \ INCREMENT_QUEUE_GET( \ (index), \ (cycle), \ (controller)->completion_event_entries, \ SMU_CQGR_EVENT_CYCLE_BIT \ ) //****************************************************************************- //* SCIC SDS Controller Initialization Methods //****************************************************************************- /** * @brief This timer is used to start another phy after we have given up on * the previous phy to transition to the ready state. * * @param[in] controller */ static void scic_sds_controller_phy_startup_timeout_handler( void *controller ) { SCI_STATUS status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; this_controller->phy_startup_timer_pending = FALSE; status = SCI_FAILURE; while (status != SCI_SUCCESS) { status = scic_sds_controller_start_next_phy(this_controller); } } /** * This method initializes the phy startup operations for controller start. * * @param this_controller */ static SCI_STATUS scic_sds_controller_initialize_phy_startup( SCIC_SDS_CONTROLLER_T *this_controller ) { this_controller->phy_startup_timer = scic_cb_timer_create( this_controller, scic_sds_controller_phy_startup_timeout_handler, this_controller ); if (this_controller->phy_startup_timer == NULL) { return SCI_FAILURE_INSUFFICIENT_RESOURCES; } else { this_controller->next_phy_to_start = 0; this_controller->phy_startup_timer_pending = FALSE; } return SCI_SUCCESS; } /** * This method initializes the power control operations for the controller * object. * * @param this_controller */ void scic_sds_controller_initialize_power_control( SCIC_SDS_CONTROLLER_T *this_controller ) { this_controller->power_control.timer = scic_cb_timer_create( this_controller, scic_sds_controller_power_control_timer_handler, this_controller ); memset( this_controller->power_control.requesters, 0, sizeof(this_controller->power_control.requesters) ); this_controller->power_control.phys_waiting = 0; this_controller->power_control.remote_devices_granted_power = 0; } // --------------------------------------------------------------------------- #define SCU_REMOTE_NODE_CONTEXT_ALIGNMENT (32) #define SCU_TASK_CONTEXT_ALIGNMENT (256) #define SCU_UNSOLICITED_FRAME_ADDRESS_ALIGNMENT (64) #define SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT (1024) #define SCU_UNSOLICITED_FRAME_HEADER_ALIGNMENT (64) // --------------------------------------------------------------------------- /** * @brief This method builds the memory descriptor table for this * controller. * * @param[in] this_controller This parameter specifies the controller * object for which to build the memory table. * * @return none */ void scic_sds_controller_build_memory_descriptor_table( SCIC_SDS_CONTROLLER_T *this_controller ) { sci_base_mde_construct( &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE], SCU_COMPLETION_RAM_ALIGNMENT, (sizeof(U32) * this_controller->completion_queue_entries), (SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS) ); sci_base_mde_construct( &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT], SCU_REMOTE_NODE_CONTEXT_ALIGNMENT, this_controller->remote_node_entries * sizeof(SCU_REMOTE_NODE_CONTEXT_T), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); sci_base_mde_construct( &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT], SCU_TASK_CONTEXT_ALIGNMENT, this_controller->task_context_entries * sizeof(SCU_TASK_CONTEXT_T), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); // The UF buffer address table size must be programmed to a power // of 2. Find the first power of 2 that is equal to or greater then // the number of unsolicited frame buffers to be utilized. scic_sds_unsolicited_frame_control_set_address_table_count( &this_controller->uf_control ); sci_base_mde_construct( &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER], SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT, scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); } /** * @brief This method validates the driver supplied memory descriptor * table. * * @param[in] this_controller * * @return SCI_STATUS */ SCI_STATUS scic_sds_controller_validate_memory_descriptor_table( SCIC_SDS_CONTROLLER_T *this_controller ) { BOOL mde_list_valid; mde_list_valid = sci_base_mde_is_valid( &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE], SCU_COMPLETION_RAM_ALIGNMENT, (sizeof(U32) * this_controller->completion_queue_entries), (SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS) ); if (mde_list_valid == FALSE) return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD; mde_list_valid = sci_base_mde_is_valid( &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT], SCU_REMOTE_NODE_CONTEXT_ALIGNMENT, this_controller->remote_node_entries * sizeof(SCU_REMOTE_NODE_CONTEXT_T), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); if (mde_list_valid == FALSE) return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD; mde_list_valid = sci_base_mde_is_valid( &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT], SCU_TASK_CONTEXT_ALIGNMENT, this_controller->task_context_entries * sizeof(SCU_TASK_CONTEXT_T), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); if (mde_list_valid == FALSE) return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD; mde_list_valid = sci_base_mde_is_valid( &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER], SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT, scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); if (mde_list_valid == FALSE) return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD; return SCI_SUCCESS; } /** * @brief This method initializes the controller with the physical memory * addresses that are used to communicate with the driver. * * @param[in] this_controller * * @return none */ void scic_sds_controller_ram_initialization( SCIC_SDS_CONTROLLER_T *this_controller ) { SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde; // The completion queue is actually placed in cacheable memory // Therefore it no longer comes out of memory in the MDL. mde = &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE]; this_controller->completion_queue = (U32*) mde->virtual_address; SMU_CQBAR_WRITE(this_controller, mde->physical_address); // Program the location of the Remote Node Context table // into the SCU. mde = &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT]; this_controller->remote_node_context_table = (SCU_REMOTE_NODE_CONTEXT_T *) mde->virtual_address; SMU_RNCBAR_WRITE(this_controller, mde->physical_address); // Program the location of the Task Context table into the SCU. mde = &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT]; this_controller->task_context_table = (SCU_TASK_CONTEXT_T *) mde->virtual_address; SMU_HTTBAR_WRITE(this_controller, mde->physical_address); mde = &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER]; scic_sds_unsolicited_frame_control_construct( &this_controller->uf_control, mde, this_controller ); // Inform the silicon as to the location of the UF headers and // address table. SCU_UFHBAR_WRITE( this_controller, this_controller->uf_control.headers.physical_address); SCU_PUFATHAR_WRITE( this_controller, this_controller->uf_control.address_table.physical_address); //enable the ECC correction and detection. SCU_SECR0_WRITE( this_controller, (SIGNLE_BIT_ERROR_CORRECTION_ENABLE | MULTI_BIT_ERROR_REPORTING_ENABLE | SINGLE_BIT_ERROR_REPORTING_ENABLE) ); SCU_SECR1_WRITE( this_controller, (SIGNLE_BIT_ERROR_CORRECTION_ENABLE | MULTI_BIT_ERROR_REPORTING_ENABLE | SINGLE_BIT_ERROR_REPORTING_ENABLE) ); } /** * @brief This method initializes the task context data for the controller. * * @param[in] this_controller * * @return none */ void scic_sds_controller_assign_task_entries( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 task_assignment; // Assign all the TCs to function 0 // TODO: Do we actually need to read this register to write it back? task_assignment = SMU_TCA_READ(this_controller, 0); task_assignment = ( task_assignment | (SMU_TCA_GEN_VAL(STARTING, 0)) | (SMU_TCA_GEN_VAL(ENDING, this_controller->task_context_entries - 1)) | (SMU_TCA_GEN_BIT(RANGE_CHECK_ENABLE)) ); SMU_TCA_WRITE(this_controller, 0, task_assignment); } /** * @brief This method initializes the hardware completion queue. * * @param[in] this_controller */ void scic_sds_controller_initialize_completion_queue( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 index; U32 completion_queue_control_value; U32 completion_queue_get_value; U32 completion_queue_put_value; this_controller->completion_queue_get = 0; completion_queue_control_value = ( SMU_CQC_QUEUE_LIMIT_SET(this_controller->completion_queue_entries - 1) | SMU_CQC_EVENT_LIMIT_SET(this_controller->completion_event_entries - 1) ); SMU_CQC_WRITE(this_controller, completion_queue_control_value); // Set the completion queue get pointer and enable the queue completion_queue_get_value = ( (SMU_CQGR_GEN_VAL(POINTER, 0)) | (SMU_CQGR_GEN_VAL(EVENT_POINTER, 0)) | (SMU_CQGR_GEN_BIT(ENABLE)) | (SMU_CQGR_GEN_BIT(EVENT_ENABLE)) ); SMU_CQGR_WRITE(this_controller, completion_queue_get_value); this_controller->completion_queue_get = completion_queue_get_value; // Set the completion queue put pointer completion_queue_put_value = ( (SMU_CQPR_GEN_VAL(POINTER, 0)) | (SMU_CQPR_GEN_VAL(EVENT_POINTER, 0)) ); SMU_CQPR_WRITE(this_controller, completion_queue_put_value); // Initialize the cycle bit of the completion queue entries for (index = 0; index < this_controller->completion_queue_entries; index++) { // If get.cycle_bit != completion_queue.cycle_bit // its not a valid completion queue entry // so at system start all entries are invalid this_controller->completion_queue[index] = 0x80000000; } } /** * @brief This method initializes the hardware unsolicited frame queue. * * @param[in] this_controller */ void scic_sds_controller_initialize_unsolicited_frame_queue( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 frame_queue_control_value; U32 frame_queue_get_value; U32 frame_queue_put_value; // Write the queue size frame_queue_control_value = SCU_UFQC_GEN_VAL(QUEUE_SIZE, this_controller->uf_control.address_table.count); SCU_UFQC_WRITE(this_controller, frame_queue_control_value); // Setup the get pointer for the unsolicited frame queue frame_queue_get_value = ( SCU_UFQGP_GEN_VAL(POINTER, 0) | SCU_UFQGP_GEN_BIT(ENABLE_BIT) ); SCU_UFQGP_WRITE(this_controller, frame_queue_get_value); // Setup the put pointer for the unsolicited frame queue frame_queue_put_value = SCU_UFQPP_GEN_VAL(POINTER, 0); SCU_UFQPP_WRITE(this_controller, frame_queue_put_value); } /** * @brief This method enables the hardware port task scheduler. * * @param[in] this_controller */ void scic_sds_controller_enable_port_task_scheduler( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 port_task_scheduler_value; port_task_scheduler_value = SCU_PTSGCR_READ(this_controller); port_task_scheduler_value |= (SCU_PTSGCR_GEN_BIT(ETM_ENABLE) | SCU_PTSGCR_GEN_BIT(PTSG_ENABLE)); SCU_PTSGCR_WRITE(this_controller, port_task_scheduler_value); } // --------------------------------------------------------------------------- #ifdef ARLINGTON_BUILD /** * This method will read from the lexington status register. This is required * as a read fence to the lexington register writes. * * @param this_controller */ void scic_sds_controller_lex_status_read_fence( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 lex_status; // Read Fence lex_status = lex_register_read( this_controller, this_controller->lex_registers + 0xC4); SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "Controller 0x%x lex_status = 0x%08x\n", this_controller, lex_status )); } /** * This method will initialize the arlington through the LEX_BAR. * * @param this_controller */ void scic_sds_controller_lex_atux_initialization( SCIC_SDS_CONTROLLER_T *this_controller ) { // 1. Reset all SCU PHY lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0020FFFF) ; // 2. Write to LEX_CTRL lex_register_write( this_controller, this_controller->lex_registers + 0xC0, 0x00000700); scic_sds_controller_lex_status_read_fence(this_controller); // 3. Enable PCI Master lex_register_write( this_controller, this_controller->lex_registers + 0x70, 0x00000002); // 4. Enable SCU Register Clock Domain lex_register_write( this_controller, this_controller->lex_registers + 0xC0, 0x00000300); scic_sds_controller_lex_status_read_fence(this_controller); // 5.1 Release PHY-A Reg Reset lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF); // 5.2 Initialize the AFE for PHY-A scic_sds_controller_afe_initialization(this_controller); scic_sds_controller_lex_status_read_fence(this_controller); #if 0 // 5.3 Release PHY Reg Reset lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF); #endif // 6.1 Release PHY-B Reg Reset lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ; // 6.2 Initialize the AFE for PHY-B scic_sds_controller_afe_initialization(this_controller); scic_sds_controller_lex_status_read_fence(this_controller); #if 0 // 6.3 Release PHY-B Reg Reset lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ; #endif // 7. Enable SCU clock domaion lex_register_write( this_controller, this_controller->lex_registers + 0xC0, 0x00000100); scic_sds_controller_lex_status_read_fence(this_controller); // 8. Release LEX SCU Reset lex_register_write( this_controller, this_controller->lex_registers + 0xC0, 0x00000000); scic_sds_controller_lex_status_read_fence(this_controller); #if !defined(DISABLE_INTERRUPTS) // 8a. Set legacy interrupts (SCU INTx to PCI-x INTA) lex_register_write( this_controller, this_controller->lex_registers + 0xC0, 0x00000800); scic_sds_controller_lex_status_read_fence(this_controller); #endif #if 0 // 9. Override TXOLVL //write to lex_ctrl lex_register_write( this_controller, this_controller->lex_registers + 0xC0, 0x27800000); #endif // 10. Release PHY-A & PHY-B Resets lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0000FF77); lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0000FF55); lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0000FF11); lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0000FF00); lex_register_write( this_controller, this_controller->lex_registers + 0x28, 0x0003FF00); } #endif // ARLINGTON_BUILD // --------------------------------------------------------------------------- #ifdef ARLINGTON_BUILD /** * This method enables chipwatch on the arlington board * * @param[in] this_controller */ void scic_sds_controller_enable_chipwatch( SCIC_SDS_CONTROLLER_T *this_controller ) { lex_register_write( this_controller, this_controller->lex_registers + 0x88, 0x09090909); lex_register_write( this_controller, this_controller->lex_registers + 0x8C, 0xcac9c862); } #endif /** * This macro is used to delay between writes to the AFE registers * during AFE initialization. */ #define AFE_REGISTER_WRITE_DELAY 10 /** * Initialize the AFE for this phy index. * * @todo We need to read the AFE setup from the OEM parameters * * @param[in] this_controller * * @return none */ #if defined(ARLINGTON_BUILD) void scic_sds_controller_afe_initialization( SCIC_SDS_CONTROLLER_T *this_controller ) { // 1. Establish Power // Hold Bias, PLL, and RX TX in reset and powerdown // pe_afe0_rst_n = 0 // pe_afe0_txpdn0,1,2,3 = 1 // pe_afe0_rxpdn0,1,2,3 = 1 // pe_afe0_txrst0,1,2,3_n = 0 // pe_afe0_rxrst0,1,2,3_n = 0 // wait 1us // pe_afe0_rst_n = 1 // wait 1us scu_afe_register_write( this_controller, afe_pll_control, 0x00247506); // 2. Write 0x00000000 to AFE XCVR Ctrl2 scu_afe_register_write( this_controller, afe_dfx_transceiver_status_clear, 0x00000000); // 3. afe0_override_en = 0 // afe0_pll_dis_override = 0 // afe0_tx_rst_override = 0 // afe0_pll_dis = 1 // pe_afe0_txrate = 01 // pe_afe0_rxrate = 01 // pe_afe0_txdis = 11 // pe_afe0_txoob = 1 // pe_afe0_txovlv = 9'b001110000 scu_afe_register_write( this_controller, afe_transceiver_control0[0], 0x0700141e); // 4. Configure PLL Unit // Write 0x00200506 to AFE PLL Ctrl Register 0 scu_afe_register_write(this_controller, afe_pll_control, 0x00200506); scu_afe_register_write(this_controller, afe_pll_dfx_control, 0x10000080); // 5. Configure Bias Unit scu_afe_register_write(this_controller, afe_bias_control[0], 0x00124814); scu_afe_register_write(this_controller, afe_bias_control[1], 0x24900000); // 6. Configure Transceiver Units scu_afe_register_write( this_controller, afe_transceiver_control0[0], 0x0702941e); scu_afe_register_write( this_controller, afe_transceiver_control1[0], 0x0000000a); // 7. Configure RX Units scu_afe_register_write( this_controller, afe_transceiver_equalization_control[0], 0x00ba2223); scu_afe_register_write( this_controller, reserved_0028_003c[2], 0x00000000); // 8. Configure TX Units scu_afe_register_write( this_controller, afe_dfx_transmit_control_register[0], 0x03815428); // 9. Transfer control to PE signals scu_afe_register_write( this_controller, afe_dfx_transceiver_status_clear, 0x00000010); // 10. Release PLL Powerdown scu_afe_register_write(this_controller, afe_pll_control, 0x00200504); // 11. Release PLL Reset scu_afe_register_write(this_controller, afe_pll_control, 0x00200505); // 12. Wait for PLL to Lock // (afe0_comm_sta [1:0] should go to 1'b11, and // [5:2] is 0x5, 0x6, 0x7, 0x8, or 0x9 scu_afe_register_write(this_controller, afe_pll_control, 0x00200501); while ((scu_afe_register_read(this_controller, afe_common_status) & 0x03) != 0x03) { // Give time for the PLLs to lock scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // 13. pe_afe0_rxpdn0 = 0 // pe_afe0_rxrst0 = 1 // pe_afe0_txrst0_n = 1 // pe_afe_txoob0_n = 0 scu_afe_register_write( this_controller, afe_transceiver_control0[0], 0x07028c11); } #elif defined(PLEASANT_RIDGE_BUILD) void scic_sds_controller_afe_initialization( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 afe_status; U32 phy_id; #if defined(SPREADSHEET_AFE_SETTINGS) // Clear DFX Status registers scu_afe_register_write( this_controller, afe_dfx_master_control0, 0x0000000f); // Configure bias currents to normal scu_afe_register_write( this_controller, afe_bias_control, 0x0000aa00); // Enable PLL scu_afe_register_write( this_controller, afe_pll_control0, 0x80000908); // Wait for the PLL to lock do { scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); afe_status = scu_afe_register_read( this_controller, afe_common_block_status); } while((afe_status & 0x00001000) == 0); for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { // Initialize transceiver channels scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000157); // Configure transceiver modes scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016d1a); // Configure receiver parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01501014); // Configure transmitter parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000); // Configure transmitter equalization scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e); // Configure transmitter SSC parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00000000); // Configure receiver parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3208903f); // Start power on sequence // Enable bias currents to transceivers and wait 200ns scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Take receiver out of power down and wait 200ns scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801611a); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Take receiver out of reset and wait 200ns scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801631a); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Take transmitter out of power down and wait 200ns scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016318); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Take transmitter out of reset and wait 200ns scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Take transmitter out of DC idle scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // Transfer control to the PEs scu_afe_register_write( this_controller, afe_dfx_master_control0, 0x00010f00); #else // !defined(SPREADSHEET_AFE_SETTINGS) // These are the AFEE settings used by the SV group // Clear DFX Status registers scu_afe_register_write( this_controller, afe_dfx_master_control0, 0x0081000f); // Configure bias currents to normal scu_afe_register_write( this_controller, afe_bias_control, 0x0000aa00); // Enable PLL scu_afe_register_write( this_controller, afe_pll_control0, 0x80000908); // Wait for the PLL to lock // Note: this is done later in the SV shell script however this looks // like the location to do this since we have enabled the PLL. do { scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); afe_status = scu_afe_register_read( this_controller, afe_common_block_status); } while((afe_status & 0x00001000) == 0); // Make sure BIST is disabled scu_afe_register_write( this_controller, afe_dfx_master_control1, 0x00000000); // Shorten SAS SNW lock time scu_afe_register_write( this_controller, afe_pmsn_master_control0, 0x7bd316ad); for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { // Initialize transceiver channels scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000174); // Configure SSC control scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000); // Configure transceiver modes scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0000651a); // Power up TX RX and RX OOB scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518); // Enable RX OOB Detect scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); #if 0 // Configure transmitter parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000); // Configure transmitter equalization scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e); // Configure transmitter SSC parameters // Power up TX RX scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // FFE = Max scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x00000080); // DFE1-5 = small scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x01041042); // Enable DFE/FFE and freeze scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x320891bf); #endif // Take receiver out of power down and wait 200ns scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006118); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // TX Electrical Idle scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006108); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Leave DFE/FFE on scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x0317108f); // Configure receiver parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01e00021); // Bring RX out of reset scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006109); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006009); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006209); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // Transfer control to the PEs scu_afe_register_write( this_controller, afe_dfx_master_control0, 0x00010f00); #endif } #elif defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD) void scic_sds_controller_afe_initialization( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 afe_status; U32 phy_id; U8 cable_selection_mask; if ( (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A0) && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A2) && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_B0) && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C0) && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C1) ) { // A programming bug has occurred if we are attempting to // support a PCI revision other than those listed. Default // to B0, and attempt to limp along if it isn't B0. ASSERT(FALSE); this_controller->pci_revision = SCIC_SDS_PCI_REVISION_C1; } cable_selection_mask = this_controller->oem_parameters.sds1.controller.cable_selection_mask; // These are the AFEE settings used by the SV group // Clear DFX Status registers scu_afe_register_write( this_controller, afe_dfx_master_control0, 0x0081000f); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) ) { // PM Rx Equalization Save, PM SPhy Rx Acknowledgement Timer, PM Stagger Timer scu_afe_register_write( this_controller, afe_pmsn_master_control2, 0x0007FFFF); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // Configure bias currents to normal if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) scu_afe_register_write(this_controller, afe_bias_control, 0x00005500); else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) scu_afe_register_write(this_controller, afe_bias_control, 0x00005A00); else if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) ) scu_afe_register_write(this_controller, afe_bias_control, 0x00005F00); else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) scu_afe_register_write(this_controller, afe_bias_control, 0x00005500); // For C0 the AFE BIAS Controll is unchanged scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Enable PLL if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) ) { scu_afe_register_write(this_controller, afe_pll_control0, 0x80040908); } else if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) ) { scu_afe_register_write(this_controller, afe_pll_control0, 0x80040A08); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) { scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write(this_controller, afe_pll_control0, 0x00000b08); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08); } scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Wait for the PLL to lock // Note: this is done later in the SV shell script however this looks // like the location to do this since we have enabled the PLL. do { afe_status = scu_afe_register_read( this_controller, afe_common_block_status); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } while((afe_status & 0x00001000) == 0); if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) ) { // Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) scu_afe_register_write( this_controller, afe_pmsn_master_control0, 0x7bcc96ad); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { U8 cable_length_long = (cable_selection_mask >> phy_id) & 1; U8 cable_length_medium = (cable_selection_mask >> (phy_id + 4)) & 1; if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) ) { // All defaults, except the Receive Word Alignament/Comma Detect // Enable....(0xe800) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004512 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x0050100F ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) { // Configure transmitter SSC parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) { // Configure transmitter SSC parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // All defaults, except the Receive Word Alignament/Comma Detect // Enable....(0xe800) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014500 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) { // Configure transmitter SSC parameters scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // All defaults, except the Receive Word Alignament/Comma Detect // Enable....(0xe800) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001C500 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // Power up TX and RX out from power down (PWRDNTX and PWRDNRX) // & increase TX int & ext bias 20%....(0xe85c) if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x000003D4 ); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x000003F0 ); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) { // Power down TX and RX (PWRDNTX and PWRDNRX) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x000003d7 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Power up TX and RX out from power down (PWRDNTX and PWRDNRX) // & increase TX int & ext bias 20%....(0xe85c) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x000003d4 ); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x000001e7 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Power up TX and RX out from power down (PWRDNTX and PWRDNRX) // & increase TX int & ext bias 20%....(0xe85c) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x000001e4 ); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, cable_length_long ? 0x000002F7 : cable_length_medium ? 0x000001F7 : 0x000001F7 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Power up TX and RX out from power down (PWRDNTX and PWRDNRX) // & increase TX int & ext bias 20%....(0xe85c) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_channel_control, cable_length_long ? 0x000002F4 : cable_length_medium ? 0x000001F4 : 0x000001F4 ); } scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) ) { // Enable TX equalization (0xe824) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) ) { // RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On), // RDD=0x0(RX Detect Enabled) ....(0xe800) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004100); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014100); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001c100); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // Leave DFE/FFE on if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3F09983F ); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3F11103F ); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3F11103F ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Enable TX equalization (0xe824) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01400c0f); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3f6f103f); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Enable TX equalization (0xe824) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000); } else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1) { scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, cable_length_long ? 0x01500C0C : cable_length_medium ? 0x01400C0D : 0x02400C0D ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x000003e0); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, cable_length_long ? 0x33091C1F : cable_length_medium ? 0x3315181F : 0x2B17161F ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); // Enable TX equalization (0xe824) scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000); } scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control0 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control1 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control2 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); scu_afe_register_write( this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control3 ); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } // Transfer control to the PEs scu_afe_register_write( this_controller, afe_dfx_master_control0, 0x00010f00); scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY); } #else #error "Unsupported board type" #endif //****************************************************************************- //* SCIC SDS Controller Internal Start/Stop Routines //****************************************************************************- /** * @brief This method will attempt to transition into the ready state * for the controller and indicate that the controller start * operation has completed if all criteria are met. * * @param[in,out] this_controller This parameter indicates the controller * object for which to transition to ready. * @param[in] status This parameter indicates the status value to be * pass into the call to scic_cb_controller_start_complete(). * * @return none. */ static void scic_sds_controller_transition_to_ready( SCIC_SDS_CONTROLLER_T *this_controller, SCI_STATUS status ) { SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_transition_to_ready(0x%x, 0x%x) enter\n", this_controller, status )); if (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_STARTING) { // We move into the ready state, because some of the phys/ports // may be up and operational. sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_READY ); scic_cb_controller_start_complete(this_controller, status); } } /** * @brief This method is the general timeout handler for the controller. * It will take the correct timetout action based on the current * controller state * * @param[in] controller This parameter indicates the controller on which * a timeout occurred. * * @return none */ void scic_sds_controller_timeout_handler( SCI_CONTROLLER_HANDLE_T controller ) { SCI_BASE_CONTROLLER_STATES current_state; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; current_state = sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller) ); if (current_state == SCI_BASE_CONTROLLER_STATE_STARTING) { scic_sds_controller_transition_to_ready( this_controller, SCI_FAILURE_TIMEOUT ); } else if (current_state == SCI_BASE_CONTROLLER_STATE_STOPPING) { sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); scic_cb_controller_stop_complete(controller, SCI_FAILURE_TIMEOUT); } else { /// @todo Now what do we want to do in this case? SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "Controller timer fired when controller was not in a state being timed.\n" )); } } /** * @brief * * @param[in] this_controller * * @return SCI_STATUS */ SCI_STATUS scic_sds_controller_stop_ports( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 index; SCI_STATUS status; SCI_STATUS port_status; status = SCI_SUCCESS; for (index = 0; index < this_controller->logical_port_entries; index++) { port_status = this_controller->port_table[index]. state_handlers->parent.stop_handler(&this_controller->port_table[index].parent); if ( (port_status != SCI_SUCCESS) && (port_status != SCI_FAILURE_INVALID_STATE) ) { status = SCI_FAILURE; SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, "Controller stop operation failed to stop port %d because of status %d.\n", this_controller->port_table[index].logical_port_index, port_status )); } } return status; } /** * @brief * * @param[in] this_controller */ static void scic_sds_controller_phy_timer_start( SCIC_SDS_CONTROLLER_T *this_controller ) { scic_cb_timer_start( this_controller, this_controller->phy_startup_timer, SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT ); this_controller->phy_startup_timer_pending = TRUE; } /** * @brief * * @param[in] this_controller */ void scic_sds_controller_phy_timer_stop( SCIC_SDS_CONTROLLER_T *this_controller ) { scic_cb_timer_stop( this_controller, this_controller->phy_startup_timer ); this_controller->phy_startup_timer_pending = FALSE; } /** * @brief This method is called internally to determine whether the * controller start process is complete. This is only true when: * - all links have been given an opportunity to start * - have no indication of a connected device * - have an indication of a connected device and it has * finished the link training process. * * @param[in] this_controller This parameter specifies the controller * object for which to start the next phy. * * @return BOOL */ BOOL scic_sds_controller_is_start_complete( SCIC_SDS_CONTROLLER_T *this_controller ) { U8 index; for (index = 0; index < SCI_MAX_PHYS; index++) { SCIC_SDS_PHY_T *the_phy = & this_controller->phy_table[index]; if ( ( this_controller->oem_parameters.sds1.controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE ) || ( ( this_controller->oem_parameters.sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE ) && (scic_sds_phy_get_port(the_phy) != SCI_INVALID_HANDLE) ) ) { /** * The controller start operation is complete if and only * if: * - all links have been given an opportunity to start * - have no indication of a connected device * - have an indication of a connected device and it has * finished the link training process. */ if ( ( (the_phy->is_in_link_training == FALSE) && (the_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_INITIAL) ) || ( (the_phy->is_in_link_training == FALSE) && (the_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_STOPPED) ) || ( (the_phy->is_in_link_training == TRUE) && (the_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_STARTING) ) || ( this_controller->port_agent.phy_ready_mask != this_controller->port_agent.phy_configured_mask ) ) { return FALSE; } } } return TRUE; } /** * @brief This method is called internally by the controller object to * start the next phy on the controller. If all the phys have * been starte, then this method will attempt to transition the * controller to the READY state and inform the user * (scic_cb_controller_start_complete()). * * @param[in] this_controller This parameter specifies the controller * object for which to start the next phy. * * @return SCI_STATUS */ SCI_STATUS scic_sds_controller_start_next_phy( SCIC_SDS_CONTROLLER_T *this_controller ) { SCI_STATUS status; status = SCI_SUCCESS; if (this_controller->phy_startup_timer_pending == FALSE) { if (this_controller->next_phy_to_start == SCI_MAX_PHYS) { // The controller has successfully finished the start process. // Inform the SCI Core user and transition to the READY state. if (scic_sds_controller_is_start_complete(this_controller) == TRUE) { scic_sds_controller_transition_to_ready( this_controller, SCI_SUCCESS ); } } else { SCIC_SDS_PHY_T * the_phy; the_phy = &this_controller->phy_table[this_controller->next_phy_to_start]; if ( this_controller->oem_parameters.sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE ) { if (scic_sds_phy_get_port(the_phy) == SCI_INVALID_HANDLE) { this_controller->next_phy_to_start++; // Caution recursion ahead be forwarned // // The PHY was never added to a PORT in MPC mode so start the next phy in sequence // This phy will never go link up and will not draw power the OEM parameters either // configured the phy incorrectly for the PORT or it was never assigned to a PORT return scic_sds_controller_start_next_phy(this_controller); } } status = scic_phy_start(the_phy); if (status == SCI_SUCCESS) { scic_sds_controller_phy_timer_start(this_controller); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY, "Controller stop operation failed to stop phy %d because of status %d.\n", this_controller->phy_table[this_controller->next_phy_to_start].phy_index, status )); } this_controller->next_phy_to_start++; } } return status; } /** * @brief * * @param[in] this_controller * * @return SCI_STATUS */ SCI_STATUS scic_sds_controller_stop_phys( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 index; SCI_STATUS status; SCI_STATUS phy_status; status = SCI_SUCCESS; for (index = 0; index < SCI_MAX_PHYS; index++) { phy_status = scic_phy_stop(&this_controller->phy_table[index]); if ( (phy_status != SCI_SUCCESS) && (phy_status != SCI_FAILURE_INVALID_STATE) ) { status = SCI_FAILURE; SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY, "Controller stop operation failed to stop phy %d because of status %d.\n", this_controller->phy_table[index].phy_index, phy_status )); } } return status; } /** * @brief * * @param[in] this_controller * * @return SCI_STATUS */ SCI_STATUS scic_sds_controller_stop_devices( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 index; SCI_STATUS status; SCI_STATUS device_status; status = SCI_SUCCESS; for (index = 0; index < this_controller->remote_node_entries; index++) { if (this_controller->device_table[index] != SCI_INVALID_HANDLE) { /// @todo What timeout value do we want to provide to this request? device_status = scic_remote_device_stop(this_controller->device_table[index], 0); if ( (device_status != SCI_SUCCESS) && (device_status != SCI_FAILURE_INVALID_STATE) ) { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET, "Controller stop operation failed to stop device 0x%x because of status %d.\n", this_controller->device_table[index], device_status )); } } } return status; } //****************************************************************************- //* SCIC SDS Controller Power Control (Staggered Spinup) //****************************************************************************- /** * This method starts the power control timer for this controller object. * * @param this_controller */ static void scic_sds_controller_power_control_timer_start( SCIC_SDS_CONTROLLER_T *this_controller ) { scic_cb_timer_start( this_controller, this_controller->power_control.timer, SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL ); this_controller->power_control.timer_started = TRUE; } /** * This method stops the power control timer for this controller object. * * @param this_controller */ static void scic_sds_controller_power_control_timer_stop( SCIC_SDS_CONTROLLER_T *this_controller ) { if (this_controller->power_control.timer_started) { scic_cb_timer_stop( this_controller, this_controller->power_control.timer ); this_controller->power_control.timer_started = FALSE; } } /** * This method stops and starts the power control timer for this controller object. * * @param this_controller */ static void scic_sds_controller_power_control_timer_restart( SCIC_SDS_CONTROLLER_T *this_controller ) { scic_sds_controller_power_control_timer_stop(this_controller); scic_sds_controller_power_control_timer_start(this_controller); } /** * @brief * * @param[in] controller */ void scic_sds_controller_power_control_timer_handler( void *controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; this_controller->power_control.remote_devices_granted_power = 0; if (this_controller->power_control.phys_waiting == 0) { this_controller->power_control.timer_started = FALSE; } else { SCIC_SDS_PHY_T *the_phy = NULL; U8 i; for (i=0; (i < SCI_MAX_PHYS) && (this_controller->power_control.phys_waiting != 0); i++) { if (this_controller->power_control.requesters[i] != NULL) { if ( this_controller->power_control.remote_devices_granted_power < this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up ) { the_phy = this_controller->power_control.requesters[i]; this_controller->power_control.requesters[i] = NULL; this_controller->power_control.phys_waiting--; this_controller->power_control.remote_devices_granted_power ++; scic_sds_phy_consume_power_handler(the_phy); if (the_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { U8 j; SCIC_SDS_PHY_T * current_requester_phy; for (j = 0; j < SCI_MAX_PHYS; j++) { current_requester_phy = this_controller->power_control.requesters[j]; //Search the power_control queue to see if there are other phys attached to //the same remote device. If found, take all of them out of await_sas_power state. if (current_requester_phy != NULL && current_requester_phy != the_phy && current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high && current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low) { this_controller->power_control.requesters[j] = NULL; this_controller->power_control.phys_waiting--; scic_sds_phy_consume_power_handler(current_requester_phy); } } } } else { break; } } } // It doesn't matter if the power list is empty, we need to start the // timer in case another phy becomes ready. scic_sds_controller_power_control_timer_start(this_controller); } } /** * @brief This method inserts the phy in the stagger spinup control queue. * * @param[in] this_controller * @param[in] the_phy */ void scic_sds_controller_power_control_queue_insert( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PHY_T *the_phy ) { ASSERT (the_phy != NULL); if( this_controller->power_control.remote_devices_granted_power < this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up ) { this_controller->power_control.remote_devices_granted_power ++; scic_sds_phy_consume_power_handler(the_phy); //stop and start the power_control timer. When the timer fires, the //no_of_devices_granted_power will be set to 0 scic_sds_controller_power_control_timer_restart (this_controller); } else { //there are phys, attached to the same sas address as this phy, are already //in READY state, this phy don't need wait. U8 i; SCIC_SDS_PHY_T * current_phy; for(i = 0; i < SCI_MAX_PHYS; i++) { current_phy = &this_controller->phy_table[i]; if (current_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_READY && current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS && current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high && current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low) { scic_sds_phy_consume_power_handler(the_phy); break; } } if (i == SCI_MAX_PHYS) { //Add the phy in the waiting list this_controller->power_control.requesters[the_phy->phy_index] = the_phy; this_controller->power_control.phys_waiting++; } } } /** * @brief This method removes the phy from the stagger spinup control * queue. * * @param[in] this_controller * @param[in] the_phy */ void scic_sds_controller_power_control_queue_remove( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PHY_T *the_phy ) { ASSERT (the_phy != NULL); if (this_controller->power_control.requesters[the_phy->phy_index] != NULL) { this_controller->power_control.phys_waiting--; } this_controller->power_control.requesters[the_phy->phy_index] = NULL; } //****************************************************************************- //* SCIC SDS Controller Completion Routines //****************************************************************************- /** * @brief This method returns a TRUE value if the completion queue has * entries that can be processed * * @param[in] this_controller * * @return BOOL * @retval TRUE if the completion queue has entries to process * FALSE if the completion queue has no entries to process */ static BOOL scic_sds_controller_completion_queue_has_entries( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 get_value = this_controller->completion_queue_get; U32 get_index = get_value & SMU_COMPLETION_QUEUE_GET_POINTER_MASK; if ( NORMALIZE_GET_POINTER_CYCLE_BIT(get_value) == COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index]) ) { return TRUE; } return FALSE; } // --------------------------------------------------------------------------- /** * @brief This method processes a task completion notification. This is * called from within the controller completion handler. * * @param[in] this_controller * @param[in] completion_entry * * @return none */ static void scic_sds_controller_task_completion( SCIC_SDS_CONTROLLER_T *this_controller, U32 completion_entry ) { U32 index; SCIC_SDS_REQUEST_T *io_request; index = SCU_GET_COMPLETION_INDEX(completion_entry); io_request = this_controller->io_request_table[index]; // Make sure that we really want to process this IO request if ( (io_request != SCI_INVALID_HANDLE) && (io_request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) && ( scic_sds_io_tag_get_sequence(io_request->io_tag) == this_controller->io_request_sequence[index] ) ) { // Yep this is a valid io request pass it along to the io request handler scic_sds_io_request_tc_completion(io_request, completion_entry); } } /** * @brief This method processes an SDMA completion event. This is called * from within the controller completion handler. * * @param[in] this_controller * @param[in] completion_entry * * @return none */ static void scic_sds_controller_sdma_completion( SCIC_SDS_CONTROLLER_T *this_controller, U32 completion_entry ) { U32 index; SCIC_SDS_REQUEST_T *io_request; SCIC_SDS_REMOTE_DEVICE_T *device; index = SCU_GET_COMPLETION_INDEX(completion_entry); switch (scu_get_command_request_type(completion_entry)) { case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC: case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC: io_request = this_controller->io_request_table[index]; SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SMP_IO_REQUEST | SCIC_LOG_OBJECT_SSP_IO_REQUEST | SCIC_LOG_OBJECT_STP_IO_REQUEST, "SCIC SDS Completion type SDMA %x for io request %x\n", completion_entry, io_request )); /// @todo For a post TC operation we need to fail the IO request break; case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC: case SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC: case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC: device = this_controller->device_table[index]; SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET | SCIC_LOG_OBJECT_SMP_REMOTE_TARGET | SCIC_LOG_OBJECT_STP_REMOTE_TARGET, "SCIC SDS Completion type SDMA %x for remote device %x\n", completion_entry, device )); /// @todo For a port RNC operation we need to fail the device break; default: SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC SDS Completion unknown SDMA completion type %x\n", completion_entry )); break; } /// This is an unexpected completion type and is un-recoverable /// Transition to the failed state and wait for a controller reset sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); } /** * This method processes an unsolicited frame message. This is called from * within the controller completion handler. * * @param[in] this_controller * @param[in] completion_entry * * @return none */ static void scic_sds_controller_unsolicited_frame( SCIC_SDS_CONTROLLER_T *this_controller, U32 completion_entry ) { U32 index; U32 frame_index; SCU_UNSOLICITED_FRAME_HEADER_T * frame_header; SCIC_SDS_PHY_T * phy; SCIC_SDS_REMOTE_DEVICE_T * device; SCI_STATUS result = SCI_FAILURE; frame_index = SCU_GET_FRAME_INDEX(completion_entry); frame_header = this_controller->uf_control.buffers.array[frame_index].header; this_controller->uf_control.buffers.array[frame_index].state = UNSOLICITED_FRAME_IN_USE; if (SCU_GET_FRAME_ERROR(completion_entry)) { /// @todo If the IAF frame or SIGNATURE FIS frame has an error will /// this cause a problem? We expect the phy initialization will /// fail if there is an error in the frame. scic_sds_controller_release_frame(this_controller, frame_index); return; } if (frame_header->is_address_frame) { index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry); phy = &this_controller->phy_table[index]; if (phy != NULL) { result = scic_sds_phy_frame_handler(phy, frame_index); } } else { index = SCU_GET_COMPLETION_INDEX(completion_entry); if (index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { // This is a signature fis or a frame from a direct attached SATA // device that has not yet been created. In either case forwared // the frame to the PE and let it take care of the frame data. index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry); phy = &this_controller->phy_table[index]; result = scic_sds_phy_frame_handler(phy, frame_index); } else { if (index < this_controller->remote_node_entries) device = this_controller->device_table[index]; else device = NULL; if (device != NULL) result = scic_sds_remote_device_frame_handler(device, frame_index); else scic_sds_controller_release_frame(this_controller, frame_index); } } if (result != SCI_SUCCESS) { /// @todo Is there any reason to report some additional error message /// when we get this failure notifiction? } } /** * @brief This method processes an event completion entry. This is called * from within the controller completion handler. * * @param[in] this_controller * @param[in] completion_entry * * @return none */ static void scic_sds_controller_event_completion( SCIC_SDS_CONTROLLER_T *this_controller, U32 completion_entry ) { U32 index; SCIC_SDS_REQUEST_T *io_request; SCIC_SDS_REMOTE_DEVICE_T *device; SCIC_SDS_PHY_T *phy; index = SCU_GET_COMPLETION_INDEX(completion_entry); switch (scu_get_event_type(completion_entry)) { case SCU_EVENT_TYPE_SMU_COMMAND_ERROR: /// @todo The driver did something wrong and we need to fix the condtion. SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller 0x%x received SMU command error 0x%x\n", this_controller, completion_entry )); break; case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR: // report fatal memory error this_controller->parent.error = SCI_CONTROLLER_FATAL_MEMORY_ERROR; sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); //continue as in following events case SCU_EVENT_TYPE_SMU_PCQ_ERROR: case SCU_EVENT_TYPE_SMU_ERROR: SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller 0x%x received fatal controller event 0x%x\n", this_controller, completion_entry )); break; case SCU_EVENT_TYPE_TRANSPORT_ERROR: io_request = this_controller->io_request_table[index]; scic_sds_io_request_event_handler(io_request, completion_entry); break; case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT: switch (scu_get_event_specifier(completion_entry)) { case SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE: case SCU_EVENT_SPECIFIC_TASK_TIMEOUT: io_request = this_controller->io_request_table[index]; if (io_request != SCI_INVALID_HANDLE) { scic_sds_io_request_event_handler(io_request, completion_entry); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SMP_IO_REQUEST | SCIC_LOG_OBJECT_SSP_IO_REQUEST | SCIC_LOG_OBJECT_STP_IO_REQUEST, "SCIC Controller 0x%x received event 0x%x for io request object that doesnt exist.\n", this_controller, completion_entry )); } break; case SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT: device = this_controller->device_table[index]; if (device != SCI_INVALID_HANDLE) { scic_sds_remote_device_event_handler(device, completion_entry); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SMP_REMOTE_TARGET | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET | SCIC_LOG_OBJECT_STP_REMOTE_TARGET, "SCIC Controller 0x%x received event 0x%x for remote device object that doesnt exist.\n", this_controller, completion_entry )); } break; } break; case SCU_EVENT_TYPE_BROADCAST_CHANGE: // direct the broadcast change event to the phy first and then let // the phy redirect the broadcast change to the port object case SCU_EVENT_TYPE_ERR_CNT_EVENT: // direct error counter event to the phy object since that is where // we get the event notification. This is a type 4 event. case SCU_EVENT_TYPE_OSSP_EVENT: index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry); phy = &this_controller->phy_table[index]; scic_sds_phy_event_handler(phy, completion_entry); break; case SCU_EVENT_TYPE_RNC_SUSPEND_TX: case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: case SCU_EVENT_TYPE_RNC_OPS_MISC: if (index < this_controller->remote_node_entries) { device = this_controller->device_table[index]; if (device != NULL) { scic_sds_remote_device_event_handler(device, completion_entry); } } else { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SMP_REMOTE_TARGET | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET | SCIC_LOG_OBJECT_STP_REMOTE_TARGET, "SCIC Controller 0x%x received event 0x%x for remote device object 0x%0x that doesnt exist.\n", this_controller, completion_entry, index )); } break; default: SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller received unknown event code %x\n", completion_entry )); break; } } /** * @brief This method is a private routine for processing the completion * queue entries. * * @param[in] this_controller * * @return none */ static void scic_sds_controller_process_completions( SCIC_SDS_CONTROLLER_T *this_controller ) { U32 completion_count = 0; U32 completion_entry; U32 get_index; U32 get_cycle; U32 event_index; U32 event_cycle; SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_process_completions(0x%x) enter\n", this_controller )); SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_COMPLETION_QUEUE, "completion queue begining get : 0x%08x\n", this_controller->completion_queue_get )); // Get the component parts of the completion queue get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get); get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get; event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get); event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get; while ( NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle) == COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index]) ) { completion_count++; completion_entry = this_controller->completion_queue[get_index]; INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle); SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_COMPLETION_QUEUE, "completion queue entry : 0x%08x\n", completion_entry )); switch (SCU_GET_COMPLETION_TYPE(completion_entry)) { case SCU_COMPLETION_TYPE_TASK: scic_sds_controller_task_completion(this_controller, completion_entry); break; case SCU_COMPLETION_TYPE_SDMA: scic_sds_controller_sdma_completion(this_controller, completion_entry); break; case SCU_COMPLETION_TYPE_UFI: scic_sds_controller_unsolicited_frame(this_controller, completion_entry); break; case SCU_COMPLETION_TYPE_EVENT: scic_sds_controller_event_completion(this_controller, completion_entry); break; case SCU_COMPLETION_TYPE_NOTIFY: // Presently we do the same thing with a notify event that we do with the // other event codes. INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle); scic_sds_controller_event_completion(this_controller, completion_entry); break; default: SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller received unknown completion type %x\n", completion_entry )); break; } } // Update the get register if we completed one or more entries if (completion_count > 0) { this_controller->completion_queue_get = SMU_CQGR_GEN_BIT(ENABLE) | SMU_CQGR_GEN_BIT(EVENT_ENABLE) | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index) | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index) ; SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get); } SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_COMPLETION_QUEUE, "completion queue ending get : 0x%08x\n", this_controller->completion_queue_get )); } /** * @brief This method is a private routine for processing the completion * queue entries. * * @param[in] this_controller * * @return none */ static void scic_sds_controller_transitioned_process_completions( SCIC_SDS_CONTROLLER_T * this_controller ) { U32 completion_count = 0; U32 completion_entry; U32 get_index; U32 get_cycle; U32 event_index; U32 event_cycle; SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_transitioned_process_completions(0x%x) enter\n", this_controller )); SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_COMPLETION_QUEUE, "completion queue begining get : 0x%08x\n", this_controller->completion_queue_get )); // Get the component parts of the completion queue get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get); get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get; event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get); event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get; while ( NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle) == COMPLETION_QUEUE_CYCLE_BIT( this_controller->completion_queue[get_index]) ) { completion_count++; completion_entry = this_controller->completion_queue[get_index]; INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle); SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_COMPLETION_QUEUE, "completion queue entry : 0x%08x\n", completion_entry )); switch (SCU_GET_COMPLETION_TYPE(completion_entry)) { case SCU_COMPLETION_TYPE_TASK: scic_sds_controller_task_completion(this_controller, completion_entry); break; case SCU_COMPLETION_TYPE_NOTIFY: INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle); // Fall-through case SCU_COMPLETION_TYPE_EVENT: case SCU_COMPLETION_TYPE_SDMA: case SCU_COMPLETION_TYPE_UFI: default: SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller ignoring completion type %x\n", completion_entry )); break; } } // Update the get register if we completed one or more entries if (completion_count > 0) { this_controller->completion_queue_get = SMU_CQGR_GEN_BIT(ENABLE) | SMU_CQGR_GEN_BIT(EVENT_ENABLE) | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index) | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index) ; SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get); } SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_COMPLETION_QUEUE, "completion queue ending get : 0x%08x\n", this_controller->completion_queue_get )); } //****************************************************************************- //* SCIC SDS Controller Interrupt and Completion functions //****************************************************************************- /** * @brief This method provides standard (common) processing of interrupts * for polling and legacy based interrupts. * * @param[in] controller * @param[in] interrupt_status * * @return This method returns a boolean (BOOL) indication as to * whether an completions are pending to be processed. * @retval TRUE if an interrupt is to be processed * @retval FALSE if no interrupt was pending */ static BOOL scic_sds_controller_standard_interrupt_handler( SCIC_SDS_CONTROLLER_T *this_controller, U32 interrupt_status ) { BOOL is_completion_needed = FALSE; SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_standard_interrupt_handler(0x%d,0x%d) enter\n", this_controller, interrupt_status )); if ( (interrupt_status & SMU_ISR_QUEUE_ERROR) || ( (interrupt_status & SMU_ISR_QUEUE_SUSPEND) && (!scic_sds_controller_completion_queue_has_entries(this_controller)) ) ) { // We have a fatal error on the read of the completion queue bar // OR // We have a fatal error there is nothing in the completion queue // but we have a report from the hardware that the queue is full /// @todo how do we request the a controller reset is_completion_needed = TRUE; this_controller->encountered_fatal_error = TRUE; } if (scic_sds_controller_completion_queue_has_entries(this_controller)) { is_completion_needed = TRUE; } return is_completion_needed; } /** * @brief This is the method provided to handle polling for interrupts * for the controller object. * * @param[in] controller * * @return BOOL * @retval TRUE if an interrupt is to be processed * @retval FALSE if no interrupt was pending */ static BOOL scic_sds_controller_polling_interrupt_handler( SCI_CONTROLLER_HANDLE_T controller ) { U32 interrupt_status; SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_polling_interrupt_handler(0x%d) enter\n", controller )); /* * In INTERRUPT_POLLING_MODE we exit the interrupt handler if the hardware * indicates nothing is pending. Since we are not being called from a real * interrupt, we don't want to confuse the hardware by servicing the * completion queue before the hardware indicates it is ready. We'll * simply wait for another polling interval and check again. */ interrupt_status = SMU_ISR_READ(this_controller); if ((interrupt_status & (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)) == 0) { return FALSE; } return scic_sds_controller_standard_interrupt_handler( controller, interrupt_status ); } /** * @brief This is the method provided to handle completions when interrupt * polling is in use. * * @param[in] controller * * @return none */ static void scic_sds_controller_polling_completion_handler( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_polling_completion_handler(0x%d) enter\n", controller )); if (this_controller->encountered_fatal_error == TRUE) { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller has encountered a fatal error.\n" )); sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); } else if (scic_sds_controller_completion_queue_has_entries(this_controller)) { if (this_controller->restrict_completions == FALSE) scic_sds_controller_process_completions(this_controller); else scic_sds_controller_transitioned_process_completions(this_controller); } /* * The interrupt handler does not adjust the CQ's * get pointer. So, SCU's INTx pin stays asserted during the * interrupt handler even though it tries to clear the interrupt * source. Therefore, the completion handler must ensure that the * interrupt source is cleared. Otherwise, we get a spurious * interrupt for which the interrupt handler will not issue a * corresponding completion event. Also, we unmask interrupts. */ SMU_ISR_WRITE( this_controller, (U32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND) ); } #if !defined(DISABLE_INTERRUPTS) /** * @brief This is the method provided to handle legacy interrupts for the * controller object. * * @param[in] controller * * @return BOOL * @retval TRUE if an interrupt is processed * FALSE if no interrupt was processed */ static BOOL scic_sds_controller_legacy_interrupt_handler( SCI_CONTROLLER_HANDLE_T controller ) { U32 interrupt_status; BOOL is_completion_needed; SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller; interrupt_status = SMU_ISR_READ(this_controller); is_completion_needed = scic_sds_controller_standard_interrupt_handler( this_controller, interrupt_status ); return is_completion_needed; } /** * @brief This is the method provided to handle legacy completions it is * expected that the SCI User will call this completion handler * anytime the interrupt handler reports that it has handled an * interrupt. * * @param[in] controller * * @return none */ static void scic_sds_controller_legacy_completion_handler( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_legacy_completion_handler(0x%d) enter\n", controller )); scic_sds_controller_polling_completion_handler(controller); SMU_IMR_WRITE(this_controller, 0x00000000); #ifdef IMR_READ_FENCE { volatile U32 int_mask_value = 0; ULONG count = 0; /* * Temporary code since we have seen with legacy interrupts * that interrupts are still masked after clearing the mask * above. This may be an Arlington problem or it may be an * old driver problem. Presently this code is turned off * since we have not seen this problem recently. */ do { int_mask_value = SMU_IMR_READ(this_controler); if (count++ > 10) { #ifdef ALLOW_ENTER_DEBUGGER __debugbreak(); #endif break; } } while (int_mask_value != 0); } #endif } /** * @brief This is the method provided to handle an MSIX interrupt message * when there is just a single MSIX message being provided by the * hardware. This mode of operation is single vector mode. * * @param[in] controller * * @return BOOL * @retval TRUE if an interrupt is processed * FALSE if no interrupt was processed */ static BOOL scic_sds_controller_single_vector_interrupt_handler( SCI_CONTROLLER_HANDLE_T controller ) { U32 interrupt_status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; // Mask the interrupts // There is a race in the hardware that could cause us not to be notified // of an interrupt completion if we do not take this step. We will unmask // the interrupts in the completion routine. SMU_IMR_WRITE(this_controller, 0xFFFFFFFF); interrupt_status = SMU_ISR_READ(this_controller); interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND); if ( (interrupt_status == 0) && scic_sds_controller_completion_queue_has_entries(this_controller) ) { // There is at least one completion queue entry to process so we can // return a success and ignore for now the case of an error interrupt SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION); return TRUE; } if (interrupt_status != 0) { // There is an error interrupt pending so let it through and handle // in the callback return TRUE; } // Clear any offending interrupts since we could not find any to handle // and unmask them all SMU_ISR_WRITE(this_controller, 0x00000000); SMU_IMR_WRITE(this_controller, 0x00000000); return FALSE; } /** * @brief This is the method provided to handle completions for a single * MSIX message. * * @param[in] controller */ static void scic_sds_controller_single_vector_completion_handler( SCI_CONTROLLER_HANDLE_T controller ) { U32 interrupt_status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_single_vector_completion_handler(0x%d) enter\n", controller )); interrupt_status = SMU_ISR_READ(this_controller); interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND); if (interrupt_status & SMU_ISR_QUEUE_ERROR) { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller has encountered a fatal error.\n" )); // We have a fatal condition and must reset the controller // Leave the interrupt mask in place and get the controller reset sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); return; } if ( (interrupt_status & SMU_ISR_QUEUE_SUSPEND) && !scic_sds_controller_completion_queue_has_entries(this_controller) ) { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller has encountered a fatal error.\n" )); // We have a fatal condtion and must reset the controller // Leave the interrupt mask in place and get the controller reset sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); return; } if (scic_sds_controller_completion_queue_has_entries(this_controller)) { scic_sds_controller_process_completions(this_controller); // We dont care which interrupt got us to processing the completion queu // so clear them both. SMU_ISR_WRITE( this_controller, (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND) ); } SMU_IMR_WRITE(this_controller, 0x00000000); } /** * @brief This is the method provided to handle a MSIX message for a normal * completion. * * @param[in] controller * * @return BOOL * @retval TRUE if an interrupt is processed * FALSE if no interrupt was processed */ static BOOL scic_sds_controller_normal_vector_interrupt_handler( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; if (scic_sds_controller_completion_queue_has_entries(this_controller)) { return TRUE; } else { // we have a spurious interrupt it could be that we have already // emptied the completion queue from a previous interrupt SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION); // There is a race in the hardware that could cause us not to be notified // of an interrupt completion if we do not take this step. We will mask // then unmask the interrupts so if there is another interrupt pending // the clearing of the interrupt source we get the next interrupt message. SMU_IMR_WRITE(this_controller, 0xFF000000); SMU_IMR_WRITE(this_controller, 0x00000000); } return FALSE; } /** * @brief This is the method provided to handle the completions for a * normal MSIX message. * * @param[in] controller */ static void scic_sds_controller_normal_vector_completion_handler( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_normal_vector_completion_handler(0x%d) enter\n", controller )); // Empty out the completion queue if (scic_sds_controller_completion_queue_has_entries(this_controller)) { scic_sds_controller_process_completions(this_controller); } // Clear the interrupt and enable all interrupts again SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION); // Could we write the value of SMU_ISR_COMPLETION? SMU_IMR_WRITE(this_controller, 0xFF000000); SMU_IMR_WRITE(this_controller, 0x00000000); } /** * @brief This is the method provided to handle the error MSIX message * interrupt. This is the normal operating mode for the hardware if * MSIX is enabled. * * @param[in] controller * * @return BOOL * @retval TRUE if an interrupt is processed * FALSE if no interrupt was processed */ static BOOL scic_sds_controller_error_vector_interrupt_handler( SCI_CONTROLLER_HANDLE_T controller ) { U32 interrupt_status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; interrupt_status = SMU_ISR_READ(this_controller); interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND); if (interrupt_status != 0) { // There is an error interrupt pending so let it through and handle // in the callback return TRUE; } // There is a race in the hardware that could cause us not to be notified // of an interrupt completion if we do not take this step. We will mask // then unmask the error interrupts so if there was another interrupt // pending we will be notified. // Could we write the value of (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)? SMU_IMR_WRITE(this_controller, 0x000000FF); SMU_IMR_WRITE(this_controller, 0x00000000); return FALSE; } /** * @brief This is the method provided to handle the error completions when * the hardware is using two MSIX messages. * * @param[in] controller */ static void scic_sds_controller_error_vector_completion_handler( SCI_CONTROLLER_HANDLE_T controller ) { U32 interrupt_status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_error_vector_completion_handler(0x%d) enter\n", controller )); interrupt_status = SMU_ISR_READ(this_controller); if ( (interrupt_status & SMU_ISR_QUEUE_SUSPEND) && scic_sds_controller_completion_queue_has_entries(this_controller) ) { scic_sds_controller_process_completions(this_controller); SMU_ISR_WRITE(this_controller, SMU_ISR_QUEUE_SUSPEND); } else { SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller reports CRC error on completion ISR %x\n", interrupt_status )); sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_FAILED ); return; } // If we dont process any completions I am not sure that we want to do this. // We are in the middle of a hardware fault and should probably be reset. SMU_IMR_WRITE(this_controller, 0x00000000); } #endif // !defined(DISABLE_INTERRUPTS) //****************************************************************************- //* SCIC SDS Controller External Methods //****************************************************************************- /** * @brief This method returns the sizeof the SCIC SDS Controller Object * * @return U32 */ U32 scic_sds_controller_get_object_size(void) { return sizeof(SCIC_SDS_CONTROLLER_T); } /** * This method returns the minimum number of timers that are required by the * controller object. This will include required timers for phys and ports. * * @return U32 * @retval The minimum number of timers that are required to make this * controller operational. */ U32 scic_sds_controller_get_min_timer_count(void) { return SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT + scic_sds_port_get_min_timer_count() + scic_sds_phy_get_min_timer_count(); } /** * This method returns the maximum number of timers that are required by the * controller object. This will include required timers for phys and ports. * * @return U32 * @retval The maximum number of timers that will be used by the controller * object */ U32 scic_sds_controller_get_max_timer_count(void) { return SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT + scic_sds_port_get_max_timer_count() + scic_sds_phy_get_max_timer_count(); } /** * @brief * * @param[in] this_controller * @param[in] the_port * @param[in] the_phy * * @return none */ void scic_sds_controller_link_up( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PORT_T *the_port, SCIC_SDS_PHY_T *the_phy ) { if (this_controller->state_handlers->link_up_handler != NULL) { this_controller->state_handlers->link_up_handler( this_controller, the_port, the_phy); } else { SCIC_LOG_INFO(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller linkup event from phy %d in unexpected state %d\n", the_phy->phy_index, sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } } /** * @brief * * @param[in] this_controller * @param[in] the_port * @param[in] the_phy */ void scic_sds_controller_link_down( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PORT_T *the_port, SCIC_SDS_PHY_T *the_phy ) { if (this_controller->state_handlers->link_down_handler != NULL) { this_controller->state_handlers->link_down_handler( this_controller, the_port, the_phy); } else { SCIC_LOG_INFO(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller linkdown event from phy %d in unexpected state %d\n", the_phy->phy_index, sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } } /** * @brief This method is called by the remote device to inform the controller * that this remote device has started. * * @param[in] this_controller * @param[in] the_device */ void scic_sds_controller_remote_device_started( SCIC_SDS_CONTROLLER_T * this_controller, SCIC_SDS_REMOTE_DEVICE_T * the_device ) { if (this_controller->state_handlers->remote_device_started_handler != NULL) { this_controller->state_handlers->remote_device_started_handler( this_controller, the_device ); } else { SCIC_LOG_INFO(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller 0x%x remote device started event from device 0x%x in unexpected state %d\n", this_controller, the_device, sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } } /** * @brief This is a helper method to determine if any remote devices on this * controller are still in the stopping state. * * @param[in] this_controller */ BOOL scic_sds_controller_has_remote_devices_stopping( SCIC_SDS_CONTROLLER_T * this_controller ) { U32 index; for (index = 0; index < this_controller->remote_node_entries; index++) { if ( (this_controller->device_table[index] != NULL) && ( this_controller->device_table[index]->parent.state_machine.current_state_id == SCI_BASE_REMOTE_DEVICE_STATE_STOPPING ) ) { return TRUE; } } return FALSE; } /** * @brief This method is called by the remote device to inform the controller * object that the remote device has stopped. * * @param[in] this_controller * @param[in] the_device */ void scic_sds_controller_remote_device_stopped( SCIC_SDS_CONTROLLER_T * this_controller, SCIC_SDS_REMOTE_DEVICE_T * the_device ) { if (this_controller->state_handlers->remote_device_stopped_handler != NULL) { this_controller->state_handlers->remote_device_stopped_handler( this_controller, the_device ); } else { SCIC_LOG_INFO(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller 0x%x remote device stopped event from device 0x%x in unexpected state %d\n", this_controller, the_device, sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } } /** * @brief This method will write to the SCU PCP register the request value. * The method is used to suspend/resume ports, devices, and phys. * * @param[in] this_controller * @param[in] request */ void scic_sds_controller_post_request( SCIC_SDS_CONTROLLER_T *this_controller, U32 request ) { SCIC_LOG_INFO(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_COMPLETION_QUEUE, "SCIC Controller 0x%08x post request 0x%08x\n", this_controller, request )); SMU_PCP_WRITE(this_controller, request); } /** * @brief This method will copy the soft copy of the task context into * the physical memory accessible by the controller. * * @note After this call is made the SCIC_SDS_IO_REQUEST object will * always point to the physical memory version of the task context. * Thus, all subsequent updates to the task context are performed in * the TC table (i.e. DMAable memory). * * @param[in] this_controller This parameter specifies the controller for * which to copy the task context. * @param[in] this_request This parameter specifies the request for which * the task context is being copied. * * @return none */ void scic_sds_controller_copy_task_context( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_REQUEST_T *this_request ) { SCU_TASK_CONTEXT_T *task_context_buffer; task_context_buffer = scic_sds_controller_get_task_context_buffer( this_controller, this_request->io_tag ); memcpy( task_context_buffer, this_request->task_context_buffer, SCI_FIELD_OFFSET(SCU_TASK_CONTEXT_T, sgl_snapshot_ac) ); // Now that the soft copy of the TC has been copied into the TC // table accessible by the silicon. Thus, any further changes to // the TC (e.g. TC termination) occur in the appropriate location. this_request->task_context_buffer = task_context_buffer; } /** * @brief This method returns the task context buffer for the given io tag. * * @param[in] this_controller * @param[in] io_tag * * @return struct SCU_TASK_CONTEXT* */ SCU_TASK_CONTEXT_T * scic_sds_controller_get_task_context_buffer( SCIC_SDS_CONTROLLER_T * this_controller, U16 io_tag ) { U16 task_index = scic_sds_io_tag_get_index(io_tag); if (task_index < this_controller->task_context_entries) { return &this_controller->task_context_table[task_index]; } return NULL; } /** * @brief This method returnst the sequence value from the io tag value * * @param[in] this_controller * @param[in] io_tag * * @return U16 */ U16 scic_sds_controller_get_io_sequence_from_tag( SCIC_SDS_CONTROLLER_T *this_controller, U16 io_tag ) { return scic_sds_io_tag_get_sequence(io_tag); } /** * @brief This method returns the IO request associated with the tag value * * @param[in] this_controller * @param[in] io_tag * * @return SCIC_SDS_IO_REQUEST_T* * @retval NULL if there is no valid IO request at the tag value */ SCIC_SDS_REQUEST_T *scic_sds_controller_get_io_request_from_tag( SCIC_SDS_CONTROLLER_T *this_controller, U16 io_tag ) { U16 task_index; U16 task_sequence; task_index = scic_sds_io_tag_get_index(io_tag); if (task_index < this_controller->task_context_entries) { if (this_controller->io_request_table[task_index] != SCI_INVALID_HANDLE) { task_sequence = scic_sds_io_tag_get_sequence(io_tag); if (task_sequence == this_controller->io_request_sequence[task_index]) { return this_controller->io_request_table[task_index]; } } } return SCI_INVALID_HANDLE; } /** * @brief This method allocates remote node index and the reserves the * remote node context space for use. This method can fail if there * are no more remote node index available. * * @param[in] this_controller This is the controller object which contains * the set of free remote node ids * @param[in] the_devce This is the device object which is requesting the a * remote node id * @param[out] node_id This is the remote node id that is assinged to the * device if one is available * * @return SCI_STATUS * @retval SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote * node index available. */ SCI_STATUS scic_sds_controller_allocate_remote_node_context( SCIC_SDS_CONTROLLER_T * this_controller, SCIC_SDS_REMOTE_DEVICE_T * the_device, U16 * node_id ) { U16 node_index; U32 remote_node_count = scic_sds_remote_device_node_count(the_device); node_index = scic_sds_remote_node_table_allocate_remote_node( &this_controller->available_remote_nodes, remote_node_count ); if (node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { this_controller->device_table[node_index] = the_device; *node_id = node_index; return SCI_SUCCESS; } return SCI_FAILURE_INSUFFICIENT_RESOURCES; } /** * @brief This method frees the remote node index back to the available * pool. Once this is done the remote node context buffer is no * longer valid and can not be used. * * @param[in] this_controller * @param[in] the_device * @param[in] node_id * * @return none */ void scic_sds_controller_free_remote_node_context( SCIC_SDS_CONTROLLER_T * this_controller, SCIC_SDS_REMOTE_DEVICE_T * the_device, U16 node_id ) { U32 remote_node_count = scic_sds_remote_device_node_count(the_device); if (this_controller->device_table[node_id] == the_device) { this_controller->device_table[node_id] = SCI_INVALID_HANDLE; scic_sds_remote_node_table_release_remote_node_index( &this_controller->available_remote_nodes, remote_node_count, node_id ); } } /** * @brief This method returns the SCU_REMOTE_NODE_CONTEXT for the specified * remote node id. * * @param[in] this_controller * @param[in] node_id * * @return SCU_REMOTE_NODE_CONTEXT_T* */ SCU_REMOTE_NODE_CONTEXT_T *scic_sds_controller_get_remote_node_context_buffer( SCIC_SDS_CONTROLLER_T *this_controller, U16 node_id ) { if ( (node_id < this_controller->remote_node_entries) && (this_controller->device_table[node_id] != SCI_INVALID_HANDLE) ) { return &this_controller->remote_node_context_table[node_id]; } return NULL; } /** * This method will combind the frame header and frame buffer to create * a SATA D2H register FIS * * @param[out] resposne_buffer This is the buffer into which the D2H register * FIS will be constructed. * @param[in] frame_header This is the frame header returned by the hardware. * @param[in] frame_buffer This is the frame buffer returned by the hardware. * * @erturn none */ void scic_sds_controller_copy_sata_response( void * response_buffer, void * frame_header, void * frame_buffer ) { memcpy( response_buffer, frame_header, sizeof(U32) ); memcpy( (char *)((char *)response_buffer + sizeof(U32)), frame_buffer, sizeof(SATA_FIS_REG_D2H_T) - sizeof(U32) ); } /** * @brief This method releases the frame once this is done the frame is * available for re-use by the hardware. The data contained in the * frame header and frame buffer is no longer valid. * The UF queue get pointer is only updated if UF control indicates * this is appropriate. * * @param[in] this_controller * @param[in] frame_index * * @return none */ void scic_sds_controller_release_frame( SCIC_SDS_CONTROLLER_T *this_controller, U32 frame_index ) { if (scic_sds_unsolicited_frame_control_release_frame( &this_controller->uf_control, frame_index) == TRUE) SCU_UFQGP_WRITE(this_controller, this_controller->uf_control.get); } #ifdef SCI_LOGGING void scic_sds_controller_initialize_state_logging( SCIC_SDS_CONTROLLER_T *this_controller ) { sci_base_state_machine_logger_initialize( &this_controller->parent.state_machine_logger, &this_controller->parent.state_machine, &this_controller->parent.parent, scic_cb_logger_log_states, "SCIC_SDS_CONTROLLER_T", "base state machine", SCIC_LOG_OBJECT_CONTROLLER ); } void scic_sds_controller_deinitialize_state_logging( SCIC_SDS_CONTROLLER_T *this_controller ) { sci_base_state_machine_logger_deinitialize( &this_controller->parent.state_machine_logger, &this_controller->parent.state_machine ); } #endif /** * @brief This method sets user parameters and OEM parameters to * default values. Users can override these values utilizing * the scic_user_parameters_set() and scic_oem_parameters_set() * methods. * * @param[in] controller This parameter specifies the controller for * which to set the configuration parameters to their * default values. * * @return none */ static void scic_sds_controller_set_default_config_parameters( SCIC_SDS_CONTROLLER_T *this_controller ) { U16 index; // Default to APC mode. this_controller->oem_parameters.sds1.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; // Default to 1 this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up = 1; // Default to no SSC operation. this_controller->oem_parameters.sds1.controller.ssc_sata_tx_spread_level = 0; this_controller->oem_parameters.sds1.controller.ssc_sas_tx_spread_level = 0; this_controller->oem_parameters.sds1.controller.ssc_sas_tx_type = 0; // Default to all phys to using short cables this_controller->oem_parameters.sds1.controller.cable_selection_mask = 0; // Initialize all of the port parameter information to narrow ports. for (index = 0; index < SCI_MAX_PORTS; index++) { this_controller->oem_parameters.sds1.ports[index].phy_mask = 0; } // Initialize all of the phy parameter information. for (index = 0; index < SCI_MAX_PHYS; index++) { // Default to 6G (i.e. Gen 3) for now. User can override if // they choose. this_controller->user_parameters.sds1.phys[index].max_speed_generation = 2; //the frequencies cannot be 0 this_controller->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f; this_controller->user_parameters.sds1.phys[index].in_connection_align_insertion_frequency = 0xff; this_controller->user_parameters.sds1.phys[index].notify_enable_spin_up_insertion_frequency = 0x33; // Previous Vitesse based expanders had a arbitration issue that // is worked around by having the upper 32-bits of SAS address // with a value greater then the Vitesse company identifier. // Hence, usage of 0x5FCFFFFF. this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.high = 0x5FCFFFFF; // Add in controller index to ensure each controller will have unique SAS addresses by default. this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.low = 0x00000001 + this_controller->controller_index; if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) ) { this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000E7C03; this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000E7C03; this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000E7C03; this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000E7C03; } else // This must be SCIC_SDS_PCI_REVISION_C0 { this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000BDD08; this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000B7069; this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000B7C09; this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000AFC6E; } } this_controller->user_parameters.sds1.stp_inactivity_timeout = 5; this_controller->user_parameters.sds1.ssp_inactivity_timeout = 5; this_controller->user_parameters.sds1.stp_max_occupancy_timeout = 5; this_controller->user_parameters.sds1.ssp_max_occupancy_timeout = 20; this_controller->user_parameters.sds1.no_outbound_task_timeout = 20; } /** * @brief This method release resources in SCI controller. * * @param[in] this_controller This parameter specifies the core * controller and associated objects whose resources are to be * released. * * @return This method returns a value indicating if the operation succeeded. * @retval SCI_SUCCESS This value indicates that all the timers are destroyed. * @retval SCI_FAILURE This value indicates certain failure during the process * of cleaning timer resource. */ static SCI_STATUS scic_sds_controller_release_resource( SCIC_SDS_CONTROLLER_T * this_controller ) { SCIC_SDS_PORT_T * port; SCIC_SDS_PHY_T * phy; U8 index; SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION, "scic_sds_controller_release_resource(0x%x) enter\n", this_controller )); if(this_controller->phy_startup_timer != NULL) { scic_cb_timer_destroy(this_controller, this_controller->phy_startup_timer); this_controller->phy_startup_timer = NULL; } if(this_controller->power_control.timer != NULL) { scic_cb_timer_destroy(this_controller, this_controller->power_control.timer); this_controller->power_control.timer = NULL; } if(this_controller->timeout_timer != NULL) { scic_cb_timer_destroy(this_controller, this_controller->timeout_timer); this_controller->timeout_timer = NULL; } scic_sds_port_configuration_agent_release_resource( this_controller, &this_controller->port_agent); for(index = 0; index < SCI_MAX_PORTS+1; index++) { port = &this_controller->port_table[index]; scic_sds_port_release_resource(this_controller, port); } for(index = 0; index < SCI_MAX_PHYS; index++) { phy = &this_controller->phy_table[index]; scic_sds_phy_release_resource(this_controller, phy); } return SCI_SUCCESS; } /** * @brief This method process the ports configured message from port configuration * agent. * * @param[in] this_controller This parameter specifies the core * controller that its ports are configured. * * @return None. */ void scic_sds_controller_port_agent_configured_ports( SCIC_SDS_CONTROLLER_T * this_controller ) { //simply transit to ready. The function below checks the controller state scic_sds_controller_transition_to_ready( this_controller, SCI_SUCCESS ); } //****************************************************************************- //* SCIC Controller Public Methods //****************************************************************************- SCI_STATUS scic_controller_construct( SCI_LIBRARY_HANDLE_T library, SCI_CONTROLLER_HANDLE_T controller, void * user_object ) { SCIC_SDS_LIBRARY_T *my_library; SCIC_SDS_CONTROLLER_T *this_controller; my_library = (SCIC_SDS_LIBRARY_T *)library; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(library), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION, "scic_controller_construct(0x%x, 0x%x) enter\n", library, controller )); // Just clear out the memory of the structure to be safe. memset(this_controller, 0, sizeof(SCIC_SDS_CONTROLLER_T)); // Make sure that the static data is assigned before moving onto the // base constroller construct as this will cause the controller to // enter its initial state and the controller_index and pci_revision // will be required to complete those operations correctly this_controller->controller_index = scic_sds_library_get_controller_index(my_library, this_controller); this_controller->pci_revision = my_library->pci_revision; sci_base_controller_construct( &this_controller->parent, sci_base_object_get_logger(my_library), scic_sds_controller_state_table, this_controller->memory_descriptors, ARRAY_SIZE(this_controller->memory_descriptors), NULL ); sci_object_set_association(controller, user_object); scic_sds_controller_initialize_state_logging(this_controller); scic_sds_pci_bar_initialization(this_controller); return SCI_SUCCESS; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_initialize( SCI_CONTROLLER_HANDLE_T controller ) { SCI_STATUS status = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_initialize(0x%x, 0x%d) enter\n", controller )); if (this_controller->state_handlers->parent.initialize_handler != NULL) { status = this_controller->state_handlers->parent.initialize_handler( (SCI_BASE_CONTROLLER_T *)controller ); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller initialize operation requested in invalid state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } return status; } // --------------------------------------------------------------------------- U32 scic_controller_get_suggested_start_timeout( SCI_CONTROLLER_HANDLE_T controller ) { // Validate the user supplied parameters. if (controller == SCI_INVALID_HANDLE) return 0; // The suggested minimum timeout value for a controller start operation: // // Signature FIS Timeout // + Phy Start Timeout // + Number of Phy Spin Up Intervals // --------------------------------- // Number of milliseconds for the controller start operation. // // NOTE: The number of phy spin up intervals will be equivalent // to the number of phys divided by the number phys allowed // per interval - 1 (once OEM parameters are supported). // Currently we assume only 1 phy per interval. return (SCIC_SDS_SIGNATURE_FIS_TIMEOUT + SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT + ((SCI_MAX_PHYS-1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL)); } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_start( SCI_CONTROLLER_HANDLE_T controller, U32 timeout ) { SCI_STATUS status = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_start(0x%x, 0x%d) enter\n", controller, timeout )); if (this_controller->state_handlers->parent.start_handler != NULL) { status = this_controller->state_handlers->parent.start_handler( (SCI_BASE_CONTROLLER_T *)controller, timeout ); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller start operation requested in invalid state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } return status; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_stop( SCI_CONTROLLER_HANDLE_T controller, U32 timeout ) { SCI_STATUS status = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_stop(0x%x, 0x%d) enter\n", controller, timeout )); if (this_controller->state_handlers->parent.stop_handler != NULL) { status = this_controller->state_handlers->parent.stop_handler( (SCI_BASE_CONTROLLER_T *)controller, timeout ); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller stop operation requested in invalid state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } return status; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_reset( SCI_CONTROLLER_HANDLE_T controller ) { SCI_STATUS status = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_reset(0x%x) enter\n", controller )); if (this_controller->state_handlers->parent.reset_handler != NULL) { status = this_controller->state_handlers->parent.reset_handler( (SCI_BASE_CONTROLLER_T *)controller ); } else { SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller reset operation requested in invalid state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); } return status; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_get_handler_methods( SCIC_INTERRUPT_TYPE interrupt_type, U16 message_count, SCIC_CONTROLLER_HANDLER_METHODS_T *handler_methods ) { SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT; switch (interrupt_type) { #if !defined(DISABLE_INTERRUPTS) case SCIC_LEGACY_LINE_INTERRUPT_TYPE: if (message_count == 0) { handler_methods[0].interrupt_handler = scic_sds_controller_legacy_interrupt_handler; handler_methods[0].completion_handler = scic_sds_controller_legacy_completion_handler; status = SCI_SUCCESS; } break; case SCIC_MSIX_INTERRUPT_TYPE: if (message_count == 1) { handler_methods[0].interrupt_handler = scic_sds_controller_single_vector_interrupt_handler; handler_methods[0].completion_handler = scic_sds_controller_single_vector_completion_handler; status = SCI_SUCCESS; } else if (message_count == 2) { handler_methods[0].interrupt_handler = scic_sds_controller_normal_vector_interrupt_handler; handler_methods[0].completion_handler = scic_sds_controller_normal_vector_completion_handler; handler_methods[1].interrupt_handler = scic_sds_controller_error_vector_interrupt_handler; handler_methods[1].completion_handler = scic_sds_controller_error_vector_completion_handler; status = SCI_SUCCESS; } break; #endif // !defined(DISABLE_INTERRUPTS) case SCIC_NO_INTERRUPTS: if (message_count == 0) { handler_methods[0].interrupt_handler = scic_sds_controller_polling_interrupt_handler; handler_methods[0].completion_handler = scic_sds_controller_polling_completion_handler; status = SCI_SUCCESS; } break; default: status = SCI_FAILURE_INVALID_PARAMETER_VALUE; break; } return status; } // --------------------------------------------------------------------------- SCI_IO_STATUS scic_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 ) { - SCI_IO_STATUS status; + SCI_STATUS status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request, io_tag )); status = this_controller->state_handlers->parent.start_io_handler( &this_controller->parent, (SCI_BASE_REMOTE_DEVICE_T *)remote_device, (SCI_BASE_REQUEST_T *)io_request, io_tag ); - return status; + return (SCI_IO_STATUS)status; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_terminate_request( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T request ) { SCI_STATUS status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_terminate_request(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, request )); status = this_controller->state_handlers->terminate_request_handler( &this_controller->parent, (SCI_BASE_REMOTE_DEVICE_T *)remote_device, (SCI_BASE_REQUEST_T *)request ); return status; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_complete_io( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T io_request ) { SCI_STATUS status; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request )); status = this_controller->state_handlers->parent.complete_io_handler( &this_controller->parent, (SCI_BASE_REMOTE_DEVICE_T *)remote_device, (SCI_BASE_REQUEST_T *)io_request ); return status; } // --------------------------------------------------------------------------- #if !defined(DISABLE_TASK_MANAGEMENT) SCI_TASK_STATUS scic_controller_start_task( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T task_request, U16 task_tag ) { - SCI_TASK_STATUS status = SCI_FAILURE_INVALID_STATE; + SCI_STATUS status = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, task_request, task_tag )); if (this_controller->state_handlers->parent.start_task_handler != NULL) { status = this_controller->state_handlers->parent.start_task_handler( &this_controller->parent, (SCI_BASE_REMOTE_DEVICE_T *)remote_device, (SCI_BASE_REQUEST_T *)task_request, task_tag ); } else { SCIC_LOG_INFO(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller starting task from invalid state\n" )); } - return status; + return (SCI_TASK_STATUS)status; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_complete_task( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T task_request ) { SCI_STATUS status = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, task_request )); if (this_controller->state_handlers->parent.complete_task_handler != NULL) { status = this_controller->state_handlers->parent.complete_task_handler( &this_controller->parent, (SCI_BASE_REMOTE_DEVICE_T *)remote_device, (SCI_BASE_REQUEST_T *)task_request ); } else { SCIC_LOG_INFO(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller completing task from invalid state\n" )); } return status; } #endif // !defined(DISABLE_TASK_MANAGEMENT) // --------------------------------------------------------------------------- SCI_STATUS scic_controller_get_port_handle( SCI_CONTROLLER_HANDLE_T controller, U8 port_index, SCI_PORT_HANDLE_T * port_handle ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_get_port_handle(0x%x, 0x%x, 0x%x) enter\n", controller, port_index, port_handle )); if (port_index < this_controller->logical_port_entries) { *port_handle = &this_controller->port_table[port_index]; return SCI_SUCCESS; } return SCI_FAILURE_INVALID_PORT; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_get_phy_handle( SCI_CONTROLLER_HANDLE_T controller, U8 phy_index, SCI_PHY_HANDLE_T * phy_handle ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_get_phy_handle(0x%x, 0x%x, 0x%x) enter\n", controller, phy_index, phy_handle )); if (phy_index < ARRAY_SIZE(this_controller->phy_table)) { *phy_handle = &this_controller->phy_table[phy_index]; return SCI_SUCCESS; } SCIC_LOG_ERROR(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_CONTROLLER, "Controller:0x%x PhyId:0x%x invalid phy index\n", this_controller, phy_index )); return SCI_FAILURE_INVALID_PHY; } // --------------------------------------------------------------------------- U16 scic_controller_allocate_io_tag( SCI_CONTROLLER_HANDLE_T controller ) { U16 task_context; U16 sequence_count; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_allocate_io_tag(0x%x) enter\n", controller )); if (!sci_pool_empty(this_controller->tci_pool)) { sci_pool_get(this_controller->tci_pool, task_context); sequence_count = this_controller->io_request_sequence[task_context]; return scic_sds_io_tag_construct(sequence_count, task_context); } return SCI_CONTROLLER_INVALID_IO_TAG; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_free_io_tag( SCI_CONTROLLER_HANDLE_T controller, U16 io_tag ) { U16 sequence; U16 index; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; ASSERT(io_tag != SCI_CONTROLLER_INVALID_IO_TAG); SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_free_io_tag(0x%x, 0x%x) enter\n", controller, io_tag )); sequence = scic_sds_io_tag_get_sequence(io_tag); index = scic_sds_io_tag_get_index(io_tag); if (!sci_pool_full(this_controller->tci_pool)) { if (sequence == this_controller->io_request_sequence[index]) { scic_sds_io_sequence_increment( this_controller->io_request_sequence[index]); sci_pool_put(this_controller->tci_pool, index); return SCI_SUCCESS; } } return SCI_FAILURE_INVALID_IO_TAG; } // --------------------------------------------------------------------------- void scic_controller_enable_interrupts( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; ASSERT(this_controller->smu_registers != NULL); SMU_IMR_WRITE(this_controller, 0x00000000); } // --------------------------------------------------------------------------- void scic_controller_disable_interrupts( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; ASSERT(this_controller->smu_registers != NULL); SMU_IMR_WRITE(this_controller, 0xffffffff); } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_set_mode( SCI_CONTROLLER_HANDLE_T controller, SCI_CONTROLLER_MODE operating_mode ) { SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller; SCI_STATUS status = SCI_SUCCESS; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_set_mode(0x%x, 0x%x) enter\n", controller, operating_mode )); if ( (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZING) || (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZED) ) { switch (operating_mode) { case SCI_MODE_SPEED: this_controller->remote_node_entries = MIN(this_controller->remote_node_entries, SCI_MAX_REMOTE_DEVICES); this_controller->task_context_entries = MIN(this_controller->task_context_entries, SCU_IO_REQUEST_COUNT); this_controller->uf_control.buffers.count = MIN(this_controller->uf_control.buffers.count, SCU_UNSOLICITED_FRAME_COUNT); this_controller->completion_event_entries = MIN(this_controller->completion_event_entries, SCU_EVENT_COUNT); this_controller->completion_queue_entries = MIN(this_controller->completion_queue_entries, SCU_COMPLETION_QUEUE_COUNT); scic_sds_controller_build_memory_descriptor_table(this_controller); break; case SCI_MODE_SIZE: this_controller->remote_node_entries = MIN(this_controller->remote_node_entries, SCI_MIN_REMOTE_DEVICES); this_controller->task_context_entries = MIN(this_controller->task_context_entries, SCI_MIN_IO_REQUESTS); this_controller->uf_control.buffers.count = MIN(this_controller->uf_control.buffers.count, SCU_MIN_UNSOLICITED_FRAMES); this_controller->completion_event_entries = MIN(this_controller->completion_event_entries, SCU_MIN_EVENTS); this_controller->completion_queue_entries = MIN(this_controller->completion_queue_entries, SCU_MIN_COMPLETION_QUEUE_ENTRIES); scic_sds_controller_build_memory_descriptor_table(this_controller); break; default: status = SCI_FAILURE_INVALID_PARAMETER_VALUE; break; } } else status = SCI_FAILURE_INVALID_STATE; return status; } /** * This method will reset the controller hardware. * * @param[in] this_controller The controller that is to be reset. */ void scic_sds_controller_reset_hardware( SCIC_SDS_CONTROLLER_T * this_controller ) { // Disable interrupts so we dont take any spurious interrupts scic_controller_disable_interrupts(this_controller); // Reset the SCU SMU_SMUSRCR_WRITE(this_controller, 0xFFFFFFFF); // Delay for 1ms to before clearing the CQP and UFQPR. scic_cb_stall_execution(1000); // The write to the CQGR clears the CQP SMU_CQGR_WRITE(this_controller, 0x00000000); // The write to the UFQGP clears the UFQPR SCU_UFQGP_WRITE(this_controller, 0x00000000); } // --------------------------------------------------------------------------- SCI_STATUS scic_user_parameters_set( SCI_CONTROLLER_HANDLE_T controller, SCIC_USER_PARAMETERS_T * scic_parms ) { SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; if ( (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_RESET) || (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZING) || (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZED) ) { U16 index; // Validate the user parameters. If they are not legal, then // return a failure. for (index = 0; index < SCI_MAX_PHYS; index++) { if (! ( scic_parms->sds1.phys[index].max_speed_generation <= SCIC_SDS_PARM_MAX_SPEED && scic_parms->sds1.phys[index].max_speed_generation > SCIC_SDS_PARM_NO_SPEED ) ) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if ( (scic_parms->sds1.phys[index].in_connection_align_insertion_frequency < 3) || (scic_parms->sds1.phys[index].align_insertion_frequency == 0) || (scic_parms->sds1.phys[index].notify_enable_spin_up_insertion_frequency == 0) ) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } if ( (scic_parms->sds1.stp_inactivity_timeout == 0) || (scic_parms->sds1.ssp_inactivity_timeout == 0) || (scic_parms->sds1.stp_max_occupancy_timeout == 0) || (scic_parms->sds1.ssp_max_occupancy_timeout == 0) || (scic_parms->sds1.no_outbound_task_timeout == 0) ) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } memcpy( (&this_controller->user_parameters), scic_parms, sizeof(*scic_parms)); return SCI_SUCCESS; } return SCI_FAILURE_INVALID_STATE; } // --------------------------------------------------------------------------- void scic_user_parameters_get( SCI_CONTROLLER_HANDLE_T controller, SCIC_USER_PARAMETERS_T * scic_parms ) { SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; memcpy(scic_parms, (&this_controller->user_parameters), sizeof(*scic_parms)); } // --------------------------------------------------------------------------- SCI_STATUS scic_oem_parameters_set( SCI_CONTROLLER_HANDLE_T controller, SCIC_OEM_PARAMETERS_T * scic_parms, U8 scic_parms_version ) { SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; SCI_BIOS_OEM_PARAM_ELEMENT_T *old_oem_params = (SCI_BIOS_OEM_PARAM_ELEMENT_T *)(&(scic_parms->sds1)); if ( (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_RESET) || (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZING) || (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZED) ) { U16 index; U8 combined_phy_mask = 0; /* * Set the OEM parameter version for the controller. This comes * from the OEM parameter block header or the registry depending * on what WCDL is set to retrieve. */ this_controller->oem_parameters_version = scic_parms_version; // Validate the oem parameters. If they are not legal, then // return a failure. for(index=0; indexsds1.ports[index].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } for(index=0; indexsds1.phys[index].sas_address.sci_format.high == 0 && scic_parms->sds1.phys[index].sas_address.sci_format.low == 0 ) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } #if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD) if ( (scic_parms->sds1.phys[index].afe_tx_amp_control0 == 0) || (scic_parms->sds1.phys[index].afe_tx_amp_control1 == 0) || (scic_parms->sds1.phys[index].afe_tx_amp_control2 == 0) || (scic_parms->sds1.phys[index].afe_tx_amp_control3 == 0) ) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } #endif } if (scic_parms->sds1.controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) { for(index=0; indexsds1.ports[index].phy_mask != 0) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } } else if (scic_parms->sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { for(index=0; indexsds1.ports[index].phy_mask; } if (combined_phy_mask == 0) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } else { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } if (scic_parms->sds1.controller.max_number_concurrent_device_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT) { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } if (old_oem_params->controller.do_enable_ssc != 0) { if ( (scic_parms_version == SCI_OEM_PARAM_VER_1_0) && (old_oem_params->controller.do_enable_ssc != 0x01)) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if (scic_parms_version >= SCI_OEM_PARAM_VER_1_1) { SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T *oem_params = (SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T*)(&(scic_parms->sds1)); U8 test = oem_params->controller.ssc_sata_tx_spread_level; if ( !((test == 0x0) || (test == 0x2) || (test == 0x3) || (test == 0x6) || (test == 0x7)) ) return SCI_FAILURE_INVALID_PARAMETER_VALUE; test = oem_params->controller.ssc_sas_tx_spread_level; if (oem_params->controller.ssc_sas_tx_type == 0) { if ( !((test == 0x0) || (test == 0x2) || (test == 0x3)) ) return SCI_FAILURE_INVALID_PARAMETER_VALUE; } else if (oem_params->controller.ssc_sas_tx_type == 1) { if ( !((test == 0x0) || (test == 0x3) || (test == 0x6)) ) return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } } memcpy( (&this_controller->oem_parameters), scic_parms, sizeof(*scic_parms)); return SCI_SUCCESS; } return SCI_FAILURE_INVALID_STATE; } // --------------------------------------------------------------------------- void scic_oem_parameters_get( SCI_CONTROLLER_HANDLE_T controller, SCIC_OEM_PARAMETERS_T * scic_parms ) { SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; memcpy(scic_parms, (&this_controller->oem_parameters), sizeof(*scic_parms)); } // --------------------------------------------------------------------------- #if !defined(DISABLE_INTERRUPTS) #define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS 853 #define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS 1280 #define INTERRUPT_COALESCE_TIMEOUT_MAX_US 2700000 #define INTERRUPT_COALESCE_NUMBER_MAX 256 #define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN 7 #define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX 28 SCI_STATUS scic_controller_set_interrupt_coalescence( SCI_CONTROLLER_HANDLE_T controller, U32 coalesce_number, U32 coalesce_timeout ) { SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller; U8 timeout_encode = 0; U32 min = 0; U32 max = 0; //Check if the input parameters fall in the range. if (coalesce_number > INTERRUPT_COALESCE_NUMBER_MAX) return SCI_FAILURE_INVALID_PARAMETER_VALUE; // Defined encoding for interrupt coalescing timeout: // Value Min Max Units // ----- --- --- ----- // 0 - - Disabled // 1 13.3 20.0 ns // 2 26.7 40.0 // 3 53.3 80.0 // 4 106.7 160.0 // 5 213.3 320.0 // 6 426.7 640.0 // 7 853.3 1280.0 // 8 1.7 2.6 us // 9 3.4 5.1 // 10 6.8 10.2 // 11 13.7 20.5 // 12 27.3 41.0 // 13 54.6 81.9 // 14 109.2 163.8 // 15 218.5 327.7 // 16 436.9 655.4 // 17 873.8 1310.7 // 18 1.7 2.6 ms // 19 3.5 5.2 // 20 7.0 10.5 // 21 14.0 21.0 // 22 28.0 41.9 // 23 55.9 83.9 // 24 111.8 167.8 // 25 223.7 335.5 // 26 447.4 671.1 // 27 894.8 1342.2 // 28 1.8 2.7 s // Others Undefined //Use the table above to decide the encode of interrupt coalescing timeout //value for register writing. if (coalesce_timeout == 0) timeout_encode = 0; else { //make the timeout value in unit of (10 ns). coalesce_timeout = coalesce_timeout * 100; min = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS / 10; max = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS / 10; //get the encode of timeout for register writing. for ( timeout_encode = INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN; timeout_encode <= INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX; timeout_encode++ ) { if (min <= coalesce_timeout && max > coalesce_timeout) break; else if (coalesce_timeout >= max && coalesce_timeout < min*2 && coalesce_timeout <= INTERRUPT_COALESCE_TIMEOUT_MAX_US*100) { if ( (coalesce_timeout-max) < (2*min - coalesce_timeout) ) break; else { timeout_encode++; break; } } else { max = max*2; min = min*2; } } if ( timeout_encode == INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX+1 ) //the value is out of range. return SCI_FAILURE_INVALID_PARAMETER_VALUE; } SMU_ICC_WRITE( scic_controller, (SMU_ICC_GEN_VAL(NUMBER, coalesce_number)| SMU_ICC_GEN_VAL(TIMER, timeout_encode)) ); scic_controller->interrupt_coalesce_number = (U16)coalesce_number; scic_controller->interrupt_coalesce_timeout = coalesce_timeout/100; return SCI_SUCCESS; } // --------------------------------------------------------------------------- void scic_controller_get_interrupt_coalescence( SCI_CONTROLLER_HANDLE_T controller, U32 * coalesce_number, U32 * coalesce_timeout ) { SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller; *coalesce_number = scic_controller->interrupt_coalesce_number; *coalesce_timeout = scic_controller->interrupt_coalesce_timeout; } #endif // !defined(DISABLE_INTERRUPTS) // --------------------------------------------------------------------------- U32 scic_controller_get_scratch_ram_size( SCI_CONTROLLER_HANDLE_T controller ) { return SCU_SCRATCH_RAM_SIZE_IN_DWORDS; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_read_scratch_ram_dword( SCI_CONTROLLER_HANDLE_T controller, U32 offset, U32 * value ) { U32 zpt_index; SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller; U32 status = SMU_SMUCSR_READ(scic_controller); //Check if the SCU Scratch RAM been initialized, if not return zeros if ((status & SCU_RAM_INIT_COMPLETED) != SCU_RAM_INIT_COMPLETED) { *value = 0x00000000; return SCI_SUCCESS; } if (offset < scic_controller_get_scratch_ram_size(controller)) { if(offset <= SCU_MAX_ZPT_DWORD_INDEX) { zpt_index = offset + (offset - (offset % 4)) + 4; *value = scu_controller_scratch_ram_register_read(scic_controller,zpt_index); } else //offset > SCU_MAX_ZPT_DWORD_INDEX { offset = offset - 132; zpt_index = offset + (offset - (offset % 4)) + 4; *value = scu_controller_scratch_ram_register_read_ext(scic_controller,zpt_index); } return SCI_SUCCESS; } else { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_write_scratch_ram_dword( SCI_CONTROLLER_HANDLE_T controller, U32 offset, U32 value ) { U32 zpt_index; if (offset < scic_controller_get_scratch_ram_size(controller)) { SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller; if(offset <= SCU_MAX_ZPT_DWORD_INDEX) { zpt_index = offset + (offset - (offset % 4)) + 4; scu_controller_scratch_ram_register_write(scic_controller,zpt_index,value); } else //offset > SCU_MAX_ZPT_DWORD_INDEX { offset = offset - 132; zpt_index = offset + (offset - (offset % 4)) + 4; scu_controller_scratch_ram_register_write_ext(scic_controller,zpt_index,value); } return SCI_SUCCESS; } else { return SCI_FAILURE_INVALID_PARAMETER_VALUE; } } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_suspend( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; U8 index; // As a precaution, disable interrupts. The user is required // to re-enable interrupts if so desired after the call. scic_controller_disable_interrupts(controller); // Stop all the timers // Maybe change the states of the objects to avoid processing stuff. // Suspend the Ports in order to ensure no unexpected // frame reception occurs on the links from the target for (index = 0; index < SCI_MAX_PORTS; index++) scic_sds_port_suspend_port_task_scheduler( &(this_controller->port_table[index])); // Disable/Reset the completion queue and unsolicited frame // queue. SMU_CQGR_WRITE(this_controller, 0x00000000); SCU_UFQGP_WRITE(this_controller, 0x00000000); // Clear any interrupts that may be pending or may have been generated // by setting CQGR and CQPR back to 0 SMU_ISR_WRITE(this_controller, 0xFFFFFFFF); //reset the software get pointer to completion queue. this_controller->completion_queue_get = 0; return SCI_SUCCESS; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_resume( SCI_CONTROLLER_HANDLE_T controller ) { SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; U8 index; // Initialize the completion queue and unsolicited frame queue. scic_sds_controller_initialize_completion_queue(this_controller); scic_sds_controller_initialize_unsolicited_frame_queue(this_controller); this_controller->restrict_completions = FALSE; // Release the port suspensions to allow for further successful // operation. for (index = 0; index < SCI_MAX_PORTS; index++) scic_sds_port_resume_port_task_scheduler( &(this_controller->port_table[index])); //check the link layer status register DWORD sync acquired bit to detect //link down event. If there is any link down event happened during controller //suspension, restart phy state machine. for (index = 0; index < SCI_MAX_PHYS; index ++) { SCIC_SDS_PHY_T * curr_phy = &this_controller->phy_table[index]; U32 link_layer_status = SCU_SAS_LLSTA_READ(curr_phy); if ((link_layer_status & SCU_SAS_LLSTA_DWORD_SYNCA_BIT) == 0) { //Need to put the phy back to start OOB. Then an appropriate link event //message will be send to scic user. scic_sds_phy_restart_starting_state(curr_phy); } } return SCI_SUCCESS; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_transition( SCI_CONTROLLER_HANDLE_T controller, BOOL restrict_completions ) { SCI_STATUS result = SCI_FAILURE_INVALID_STATE; SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller; U8 index; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_controller_transition(0x%x) enter\n", controller )); if (this_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_READY) { // Ensure that there are no outstanding IO operations at this // time. for (index = 0; index < SCI_MAX_PORTS; index++) { if (this_controller->port_table[index].started_request_count != 0) return result; } scic_controller_suspend(controller); // Loop through the memory descriptor list and reprogram // the silicon memory registers accordingly. result = scic_sds_controller_validate_memory_descriptor_table( this_controller); if (result == SCI_SUCCESS) { scic_sds_controller_ram_initialization(this_controller); this_controller->restrict_completions = restrict_completions; } scic_controller_resume(controller); } return result; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_get_max_ports( SCI_CONTROLLER_HANDLE_T controller, U8 * count ) { *count = SCI_MAX_PORTS; return SCI_SUCCESS; } // --------------------------------------------------------------------------- SCI_STATUS scic_controller_get_max_phys( SCI_CONTROLLER_HANDLE_T controller, U8 * count ) { *count = SCI_MAX_PHYS; return SCI_SUCCESS; } //****************************************************************************** //* CONTROLLER STATE MACHINE //****************************************************************************** /** * This macro returns the maximum number of logical ports supported by the * hardware. The caller passes in the value read from the device context * capacity register and this macro will mash and shift the value * appropriately. */ #define smu_dcc_get_max_ports(dcc_value) \ ( \ ( ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK)) \ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT ) + 1\ ) /** * This macro returns the maximum number of task contexts supported by the * hardware. The caller passes in the value read from the device context * capacity register and this macro will mash and shift the value * appropriately. */ #define smu_dcc_get_max_task_context(dcc_value) \ ( \ ( ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK)) \ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT ) + 1\ ) /** * This macro returns the maximum number of remote node contexts supported * by the hardware. The caller passes in the value read from the device * context capacity register and this macro will mash and shift the value * appropriately. */ #define smu_dcc_get_max_remote_node_context(dcc_value) \ ( \ ( ( (U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) )\ >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT ) + 1\ ) //***************************************************************************** //* DEFAULT STATE HANDLERS //***************************************************************************** /** * This method is called when the SCIC_SDS_CONTROLLER default start * io/task handler is in place. * - Issue a warning message * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was * used, would be cast to a SCIC_SDS_REMOTE_DEVICE. * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used, * would be cast to a SCIC_SDS_IO_REQUEST. * @param[in] io_tag This is the IO tag to be assigned to the IO request or * SCI_CONTROLLER_INVALID_IO_TAG. * * @return SCI_STATUS * @retval SCI_FAILURE_INVALID_STATE */ static SCI_STATUS scic_sds_controller_default_start_operation_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request, U16 io_tag ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller requested to start an io/task from invalid state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); return SCI_FAILURE_INVALID_STATE; } /** * This method is called when the SCIC_SDS_CONTROLLER default * request handler is in place. * - Issue a warning message * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was * used, would be cast to a SCIC_SDS_REMOTE_DEVICE. * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used, * would be cast to a SCIC_SDS_IO_REQUEST. * * @return SCI_STATUS * @retval SCI_FAILURE_INVALID_STATE */ static SCI_STATUS scic_sds_controller_default_request_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller request operation from invalid state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); return SCI_FAILURE_INVALID_STATE; } //***************************************************************************** //* GENERAL (COMMON) STATE HANDLERS //***************************************************************************** /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * reset handler is in place. * - Transition to SCI_BASE_CONTROLLER_STATE_RESETTING * * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a * SCIC_SDS_CONTROLLER object. * * @return SCI_STATUS * @retval SCI_SUCCESS */ static SCI_STATUS scic_sds_controller_general_reset_handler( SCI_BASE_CONTROLLER_T *controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_resetting_state_enter(0x%x) enter\n", controller )); //Release resource. So far only resource to be released are timers. scic_sds_controller_release_resource(this_controller); // The reset operation is not a graceful cleanup just perform the state // transition. sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_RESETTING ); return SCI_SUCCESS; } //***************************************************************************** //* RESET STATE HANDLERS //***************************************************************************** /** * This method is the SCIC_SDS_CONTROLLER initialize handler for the reset * state. * - Currently this function does nothing * * @param[in] controller This is the SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * * @return SCI_STATUS * @retval SCI_FAILURE * * @todo This function is not yet implemented and is a valid request from the * reset state. */ static SCI_STATUS scic_sds_controller_reset_state_initialize_handler( SCI_BASE_CONTROLLER_T *controller ) { U32 index; SCI_STATUS result = SCI_SUCCESS; SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION, "scic_sds_controller_reset_state_initialize_handler(0x%x) enter\n", controller )); sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_INITIALIZING ); this_controller->timeout_timer = scic_cb_timer_create( controller, scic_sds_controller_timeout_handler, controller ); scic_sds_controller_initialize_power_control(this_controller); /// todo: This should really be done in the reset state enter but /// the controller has not yet been initialized before getting /// to the reset enter state so the PCI BAR is not yet assigned scic_sds_controller_reset_hardware(this_controller); #if defined(ARLINGTON_BUILD) scic_sds_controller_lex_atux_initialization(this_controller); #elif defined(PLEASANT_RIDGE_BUILD) \ || defined(PBG_HBA_A0_BUILD) \ || defined(PBG_HBA_A2_BUILD) scic_sds_controller_afe_initialization(this_controller); #elif defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD) // There is nothing to do here for B0 since we do not have to // program the AFE registers. /// @todo The AFE settings are supposed to be correct for the B0 but /// presently they seem to be wrong. scic_sds_controller_afe_initialization(this_controller); #else // !defined(ARLINGTON_BUILD) && !defined(PLEASANT_RIDGE_BUILD) // What other systems do we want to add here? #endif // !defined(ARLINGTON_BUILD) && !defined(PLEASANT_RIDGE_BUILD) if (SCI_SUCCESS == result) { U32 status; U32 terminate_loop; // Take the hardware out of reset SMU_SMUSRCR_WRITE(this_controller, 0x00000000); /// @todo Provide meaningfull error code for hardware failure //result = SCI_FAILURE_CONTROLLER_HARDWARE; result = SCI_FAILURE; terminate_loop = 100; while (terminate_loop-- && (result != SCI_SUCCESS)) { // Loop until the hardware reports success scic_cb_stall_execution(SCU_CONTEXT_RAM_INIT_STALL_TIME); status = SMU_SMUCSR_READ(this_controller); if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED) { result = SCI_SUCCESS; } } } #ifdef ARLINGTON_BUILD scic_sds_controller_enable_chipwatch(this_controller); #endif if (result == SCI_SUCCESS) { U32 max_supported_ports; U32 max_supported_devices; U32 max_supported_io_requests; U32 device_context_capacity; // Determine what are the actaul device capacities that the // hardware will support device_context_capacity = SMU_DCC_READ(this_controller); max_supported_ports = smu_dcc_get_max_ports(device_context_capacity); max_supported_devices = smu_dcc_get_max_remote_node_context(device_context_capacity); max_supported_io_requests = smu_dcc_get_max_task_context(device_context_capacity); // Make all PEs that are unassigned match up with the logical ports for (index = 0; index < max_supported_ports; index++) { scu_register_write( this_controller, this_controller->scu_registers->peg0.ptsg.protocol_engine[index], index ); } // Now that we have the correct hardware reported minimum values // build the MDL for the controller. Default to a performance // configuration. scic_controller_set_mode(this_controller, SCI_MODE_SPEED); // Record the smaller of the two capacity values this_controller->logical_port_entries = MIN(max_supported_ports, this_controller->logical_port_entries); this_controller->task_context_entries = MIN(max_supported_io_requests, this_controller->task_context_entries); this_controller->remote_node_entries = MIN(max_supported_devices, this_controller->remote_node_entries); } // Initialize hardware PCI Relaxed ordering in DMA engines if (result == SCI_SUCCESS) { U32 dma_configuration; // Configure the payload DMA dma_configuration = SCU_PDMACR_READ(this_controller); dma_configuration |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE); SCU_PDMACR_WRITE(this_controller, dma_configuration); // Configure the control DMA dma_configuration = SCU_CDMACR_READ(this_controller); dma_configuration |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE); SCU_CDMACR_WRITE(this_controller, dma_configuration); } // Initialize the PHYs before the PORTs because the PHY registers // are accessed during the port initialization. if (result == SCI_SUCCESS) { // Initialize the phys for (index = 0; (result == SCI_SUCCESS) && (index < SCI_MAX_PHYS); index++) { result = scic_sds_phy_initialize( &this_controller->phy_table[index], &this_controller->scu_registers->peg0.pe[index].tl, &this_controller->scu_registers->peg0.pe[index].ll ); } } //Initialize the SGPIO Unit for HARDWARE controlled SGPIO if(result == SCI_SUCCESS) { scic_sgpio_hardware_initialize(this_controller); } if (result == SCI_SUCCESS) { // Initialize the logical ports for (index = 0; (index < this_controller->logical_port_entries) && (result == SCI_SUCCESS); index++) { result = scic_sds_port_initialize( &this_controller->port_table[index], &this_controller->scu_registers->peg0.ptsg.port[index], &this_controller->scu_registers->peg0.ptsg.protocol_engine, &this_controller->scu_registers->peg0.viit[index] ); } } if (SCI_SUCCESS == result) { result = scic_sds_port_configuration_agent_initialize( this_controller, &this_controller->port_agent ); } // Advance the controller state machine if (result == SCI_SUCCESS) { sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_INITIALIZED ); } else { //stay in the same state and release the resource scic_sds_controller_release_resource(this_controller); SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION, "Invalid Port Configuration from scic_sds_controller_reset_state_initialize_handler(0x%x) \n", controller )); } return result; } //***************************************************************************** //* INITIALIZED STATE HANDLERS //***************************************************************************** /** * This method is the SCIC_SDS_CONTROLLER start handler for the initialized * state. * - Validate we have a good memory descriptor table * - Initialze the physical memory before programming the hardware * - Program the SCU hardware with the physical memory addresses passed in * the memory descriptor table. * - Initialzie the TCi pool * - Initialize the RNi pool * - Initialize the completion queue * - Initialize the unsolicited frame data * - Take the SCU port task scheduler out of reset * - Start the first phy object. * - Transition to SCI_BASE_CONTROLLER_STATE_STARTING. * * @param[in] controller This is the SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] timeout This is the allowed time for the controller object to * reach the started state. * * @return SCI_STATUS * @retval SCI_SUCCESS if all of the controller start operations complete * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD if one or more of the * memory descriptor fields is invalid. */ static SCI_STATUS scic_sds_controller_initialized_state_start_handler( SCI_BASE_CONTROLLER_T * controller, U32 timeout ) { U16 index; SCI_STATUS result; SCIC_SDS_CONTROLLER_T * this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; // Make sure that the SCI User filled in the memory descriptor table correctly result = scic_sds_controller_validate_memory_descriptor_table(this_controller); if (result == SCI_SUCCESS) { // The memory descriptor list looks good so program the hardware scic_sds_controller_ram_initialization(this_controller); } if (SCI_SUCCESS == result) { // Build the TCi free pool sci_pool_initialize(this_controller->tci_pool); for (index = 0; index < this_controller->task_context_entries; index++) { sci_pool_put(this_controller->tci_pool, index); } // Build the RNi free pool scic_sds_remote_node_table_initialize( &this_controller->available_remote_nodes, this_controller->remote_node_entries ); } if (SCI_SUCCESS == result) { // Before anything else lets make sure we will not be interrupted // by the hardware. scic_controller_disable_interrupts(controller); // Enable the port task scheduler scic_sds_controller_enable_port_task_scheduler(this_controller); // Assign all the task entries to this controller physical function scic_sds_controller_assign_task_entries(this_controller); // Now initialze the completion queue scic_sds_controller_initialize_completion_queue(this_controller); // Initialize the unsolicited frame queue for use scic_sds_controller_initialize_unsolicited_frame_queue(this_controller); // Setup the phy start timer result = scic_sds_controller_initialize_phy_startup(this_controller); } // Start all of the ports on this controller for ( index = 0; (index < this_controller->logical_port_entries) && (result == SCI_SUCCESS); index++ ) { result = this_controller->port_table[index]. state_handlers->parent.start_handler(&this_controller->port_table[index].parent); } if (SCI_SUCCESS == result) { scic_sds_controller_start_next_phy(this_controller); // See if the user requested to timeout this operation. if (timeout != 0) scic_cb_timer_start(controller, this_controller->timeout_timer, timeout); sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_STARTING ); } return result; } //***************************************************************************** //* STARTING STATE HANDLERS //***************************************************************************** /** * This method is called when the SCIC_SDS_CONTROLLER is in the starting state * link up handler is called. This method will perform the following: * - Stop the phy timer * - Start the next phy * - Report the link up condition to the port object * * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the link up * notification. * @param[in] port This is SCIC_SDS_PORT with which the phy is associated. * @param[in] phy This is the SCIC_SDS_PHY which has gone link up. * * @return none */ static void scic_sds_controller_starting_state_link_up_handler( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PORT_T *port, SCIC_SDS_PHY_T *phy ) { scic_sds_controller_phy_timer_stop(this_controller); this_controller->port_agent.link_up_handler( this_controller, &this_controller->port_agent, port, phy ); //scic_sds_port_link_up(port, phy); scic_sds_controller_start_next_phy(this_controller); } /** * This method is called when the SCIC_SDS_CONTROLLER is in the starting state * link down handler is called. * - Report the link down condition to the port object * * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the * link down notification. * @param[in] port This is SCIC_SDS_PORT with which the phy is associated. * @param[in] phy This is the SCIC_SDS_PHY which has gone link down. * * @return none */ static void scic_sds_controller_starting_state_link_down_handler( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PORT_T *port, SCIC_SDS_PHY_T *phy ) { this_controller->port_agent.link_down_handler( this_controller, &this_controller->port_agent, port, phy ); //scic_sds_port_link_down(port, phy); } //***************************************************************************** //* READY STATE HANDLERS //***************************************************************************** /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * stop handler is called. * - Start the timeout timer * - Transition to SCI_BASE_CONTROLLER_STATE_STOPPING. * * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a * SCIC_SDS_CONTROLLER object. * @param[in] timeout The timeout for when the stop operation should report a * failure. * * @return SCI_STATUS * @retval SCI_SUCCESS */ static SCI_STATUS scic_sds_controller_ready_state_stop_handler( SCI_BASE_CONTROLLER_T *controller, U32 timeout ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; // See if the user requested to timeout this operation if (timeout != 0) scic_cb_timer_start(controller, this_controller->timeout_timer, timeout); sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_STOPPING ); return SCI_SUCCESS; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * and the start io handler is called. * - Start the io request on the remote device * - if successful * - assign the io_request to the io_request_table * - post the request to the hardware * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * @param[in] io_tag This is the IO tag to be assigned to the IO request or * SCI_CONTROLLER_INVALID_IO_TAG. * * @return SCI_STATUS * @retval SCI_SUCCESS if the start io operation succeeds * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be * allocated for the io request. * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid * state to accept io requests. * * @todo How does the io_tag parameter get assigned to the io request? */ static SCI_STATUS scic_sds_controller_ready_state_start_io_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request, U16 io_tag ) { SCI_STATUS status; SCIC_SDS_CONTROLLER_T *this_controller; SCIC_SDS_REQUEST_T *the_request; SCIC_SDS_REMOTE_DEVICE_T *the_device; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; the_request = (SCIC_SDS_REQUEST_T *)io_request; the_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device; status = scic_sds_remote_device_start_io(this_controller, the_device, the_request); if (status == SCI_SUCCESS) { this_controller->io_request_table[ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request; scic_sds_controller_post_request( this_controller, scic_sds_request_get_post_context(the_request) ); } return status; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * and the complete io handler is called. * - Complete the io request on the remote device * - if successful * - remove the io_request to the io_request_table * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * * @return SCI_STATUS * @retval SCI_SUCCESS if the start io operation succeeds * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid * state to accept io requests. */ static SCI_STATUS scic_sds_controller_ready_state_complete_io_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request ) { U16 index; SCI_STATUS status; SCIC_SDS_CONTROLLER_T *this_controller; SCIC_SDS_REQUEST_T *the_request; SCIC_SDS_REMOTE_DEVICE_T *the_device; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; the_request = (SCIC_SDS_REQUEST_T *)io_request; the_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device; status = scic_sds_remote_device_complete_io( this_controller, the_device, the_request); if (status == SCI_SUCCESS) { index = scic_sds_io_tag_get_index(the_request->io_tag); this_controller->io_request_table[index] = SCI_INVALID_HANDLE; } return status; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * and the continue io handler is called. * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * * @return SCI_STATUS */ static SCI_STATUS scic_sds_controller_ready_state_continue_io_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request ) { SCIC_SDS_CONTROLLER_T *this_controller; SCIC_SDS_REQUEST_T *the_request; the_request = (SCIC_SDS_REQUEST_T *)io_request; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; this_controller->io_request_table[ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request; scic_sds_controller_post_request( this_controller, scic_sds_request_get_post_context(the_request) ); return SCI_SUCCESS; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * and the start task handler is called. * - The remote device is requested to start the task request * - if successful * - assign the task to the io_request_table * - post the request to the SCU hardware * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * @param[in] task_tag This is the task tag to be assigned to the task request * or SCI_CONTROLLER_INVALID_IO_TAG. * * @return SCI_STATUS * @retval SCI_SUCCESS if the start io operation succeeds * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be * allocated for the io request. * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid * state to accept io requests. * * @todo How does the io tag get assigned in this code path? */ static SCI_STATUS scic_sds_controller_ready_state_start_task_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request, U16 task_tag ) { SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *) controller; SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *) io_request; SCIC_SDS_REMOTE_DEVICE_T *the_device = (SCIC_SDS_REMOTE_DEVICE_T *) remote_device; SCI_STATUS status; status = scic_sds_remote_device_start_task( this_controller, the_device, the_request ); if (status == SCI_SUCCESS) { this_controller->io_request_table[ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request; scic_sds_controller_post_request( this_controller, scic_sds_request_get_post_context(the_request) ); } else if (status == SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS) { this_controller->io_request_table[ scic_sds_io_tag_get_index(the_request->io_tag)] = the_request; //We will let framework know this task request started successfully, //although core is still woring on starting the request (to post tc when //RNC is resumed.) status = SCI_SUCCESS; } return status; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the ready state * and the terminate request handler is called. * - call the io request terminate function * - if successful * - post the terminate request to the SCU hardware * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * * @return SCI_STATUS * @retval SCI_SUCCESS if the start io operation succeeds * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid * state to accept io requests. */ static SCI_STATUS scic_sds_controller_ready_state_terminate_request_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request ) { SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *) controller; SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *) io_request; SCI_STATUS status; status = scic_sds_io_request_terminate(the_request); if (status == SCI_SUCCESS) { // Utilize the original post context command and or in the POST_TC_ABORT // request sub-type. scic_sds_controller_post_request( this_controller, scic_sds_request_get_post_context(the_request) | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT ); } return status; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the starting state * link up handler is called. This method will perform the following: * - Stop the phy timer * - Start the next phy * - Report the link up condition to the port object * * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the link up * notification. * @param[in] port This is SCIC_SDS_PORT with which the phy is associated. * @param[in] phy This is the SCIC_SDS_PHY which has gone link up. * * @return none */ static void scic_sds_controller_ready_state_link_up_handler( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PORT_T *port, SCIC_SDS_PHY_T *phy ) { this_controller->port_agent.link_up_handler( this_controller, &this_controller->port_agent, port, phy ); } /** * This method is called when the SCIC_SDS_CONTROLLER is in the starting state * link down handler is called. * - Report the link down condition to the port object * * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the * link down notification. * @param[in] port This is SCIC_SDS_PORT with which the phy is associated. * @param[in] phy This is the SCIC_SDS_PHY which has gone link down. * * @return none */ static void scic_sds_controller_ready_state_link_down_handler( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_PORT_T *port, SCIC_SDS_PHY_T *phy ) { this_controller->port_agent.link_down_handler( this_controller, &this_controller->port_agent, port, phy ); } //***************************************************************************** //* STOPPING STATE HANDLERS //***************************************************************************** /** * This method is called when the SCIC_SDS_CONTROLLER is in a stopping state * and the complete io handler is called. * - This function is not yet implemented * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * * @return SCI_STATUS * @retval SCI_FAILURE */ static SCI_STATUS scic_sds_controller_stopping_state_complete_io_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; /// @todo Implement this function return SCI_FAILURE; } /** * This method is called when the SCIC_SDS_CONTROLLER is in a stopping state * and the a remote device has stopped. * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * * @return none */ static void scic_sds_controller_stopping_state_device_stopped_handler( SCIC_SDS_CONTROLLER_T * controller, SCIC_SDS_REMOTE_DEVICE_T * remote_device ) { if (!scic_sds_controller_has_remote_devices_stopping(controller)) { sci_base_state_machine_change_state( &controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_STOPPED ); } } //***************************************************************************** //* STOPPED STATE HANDLERS //***************************************************************************** //***************************************************************************** //* FAILED STATE HANDLERS //***************************************************************************** /** * This method is called when the SCIC_SDS_CONTROLLER failed state start * io/task handler is in place. * - Issue a warning message * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was * used, would be cast to a SCIC_SDS_REMOTE_DEVICE. * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used, * would be cast to a SCIC_SDS_IO_REQUEST. * @param[in] io_tag This is the IO tag to be assigned to the IO request or * SCI_CONTROLLER_INVALID_IO_TAG. * * @return SCI_FAILURE * @retval SCI_FAILURE */ static SCI_STATUS scic_sds_controller_failed_state_start_operation_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request, U16 io_tag ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; SCIC_LOG_WARNING(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "SCIC Controller requested to start an io/task from failed state %d\n", sci_base_state_machine_get_state( scic_sds_controller_get_base_state_machine(this_controller)) )); return SCI_FAILURE; } /** * This method is called when the SCIC_SDS_CONTROLLER is in the failed state * reset handler is in place. * - Transition to SCI_BASE_CONTROLLER_STATE_RESETTING * * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a * SCIC_SDS_CONTROLLER object. * * @return SCI_STATUS * @retval SCI_FAILURE if fatal memory error occurred */ static SCI_STATUS scic_sds_controller_failed_state_reset_handler( SCI_BASE_CONTROLLER_T *controller ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller = (SCIC_SDS_CONTROLLER_T *)controller; if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR) { SCIC_LOG_TRACE(( sci_base_object_get_logger(controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_resetting_state_enter(0x%x) enter\n not allowed with fatal memory error", controller )); return SCI_FAILURE; } else { return scic_sds_controller_general_reset_handler(controller); } } /** * This method is called when the SCIC_SDS_CONTROLLER is in the failed state * and the terminate request handler is called. * - call the io request terminate function * - if successful * - post the terminate request to the SCU hardware * * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast * into a SCIC_SDS_CONTROLLER object. * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a * SCIC_SDS_REMOTE_DEVICE object. * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a * SCIC_SDS_IO_REQUEST object. * * @return SCI_STATUS * @retval SCI_SUCCESS if the start io operation succeeds * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid * state to accept io requests. */ static SCI_STATUS scic_sds_controller_failed_state_terminate_request_handler( SCI_BASE_CONTROLLER_T *controller, SCI_BASE_REMOTE_DEVICE_T *remote_device, SCI_BASE_REQUEST_T *io_request ) { SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *) io_request; return scic_sds_io_request_terminate(the_request); } SCIC_SDS_CONTROLLER_STATE_HANDLER_T scic_sds_controller_state_handler_table[SCI_BASE_CONTROLLER_MAX_STATES] = { // SCI_BASE_CONTROLLER_STATE_INITIAL { { NULL, NULL, NULL, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_RESET { { NULL, NULL, NULL, scic_sds_controller_reset_state_initialize_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_INITIALIZING { { NULL, NULL, NULL, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_INITIALIZED { { scic_sds_controller_initialized_state_start_handler, NULL, NULL, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_STARTING { { NULL, NULL, NULL, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, scic_sds_controller_starting_state_link_up_handler, scic_sds_controller_starting_state_link_down_handler, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_READY { { NULL, scic_sds_controller_ready_state_stop_handler, scic_sds_controller_general_reset_handler, NULL, scic_sds_controller_ready_state_start_io_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_ready_state_complete_io_handler, scic_sds_controller_default_request_handler, scic_sds_controller_ready_state_continue_io_handler, scic_sds_controller_ready_state_start_task_handler, scic_sds_controller_ready_state_complete_io_handler }, scic_sds_controller_ready_state_terminate_request_handler, scic_sds_controller_ready_state_link_up_handler, scic_sds_controller_ready_state_link_down_handler, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_RESETTING { { NULL, NULL, NULL, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_STOPPING { { NULL, NULL, NULL, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_stopping_state_complete_io_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, scic_sds_controller_stopping_state_device_stopped_handler }, // SCI_BASE_CONTROLLER_STATE_STOPPED { { NULL, NULL, scic_sds_controller_failed_state_reset_handler, NULL, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_default_request_handler, NULL, NULL, NULL, NULL }, // SCI_BASE_CONTROLLER_STATE_FAILED { { NULL, NULL, scic_sds_controller_general_reset_handler, NULL, scic_sds_controller_failed_state_start_operation_handler, scic_sds_controller_failed_state_start_operation_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, scic_sds_controller_default_request_handler, NULL, NULL }, scic_sds_controller_failed_state_terminate_request_handler, NULL, NULL, NULL } }; /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_INITIAL. * - Set the state handlers to the controllers initial state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none * * @todo This function should initialze the controller object. */ static void scic_sds_controller_initial_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_INITIAL); sci_base_state_machine_change_state( &this_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESET); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_RESET. * - Set the state handlers to the controllers reset state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_reset_state_enter( SCI_BASE_OBJECT_T *object ) { U8 index; SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_RESET); scic_sds_port_configuration_agent_construct(&this_controller->port_agent); // Construct the ports for this controller for (index = 0; index < (SCI_MAX_PORTS + 1); index++) { scic_sds_port_construct( &this_controller->port_table[index], (index == SCI_MAX_PORTS) ? SCIC_SDS_DUMMY_PORT : index, this_controller ); } // Construct the phys for this controller for (index = 0; index < SCI_MAX_PHYS; index++) { // Add all the PHYs to the dummy port scic_sds_phy_construct( &this_controller->phy_table[index], &this_controller->port_table[SCI_MAX_PORTS], index ); } this_controller->invalid_phy_mask = 0; // Set the default maximum values this_controller->completion_event_entries = SCU_EVENT_COUNT; this_controller->completion_queue_entries = SCU_COMPLETION_QUEUE_COUNT; this_controller->remote_node_entries = SCI_MAX_REMOTE_DEVICES; this_controller->logical_port_entries = SCI_MAX_PORTS; this_controller->task_context_entries = SCU_IO_REQUEST_COUNT; this_controller->uf_control.buffers.count = SCU_UNSOLICITED_FRAME_COUNT; this_controller->uf_control.address_table.count= SCU_UNSOLICITED_FRAME_COUNT; // Initialize the User and OEM parameters to default values. scic_sds_controller_set_default_config_parameters(this_controller); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_INITIALIZING. * - Set the state handlers to the controllers initializing state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_initializing_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZING); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_INITIALIZED. * - Set the state handlers to the controllers initialized state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_initialized_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZED); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_STARTING. * - Set the state handlers to the controllers starting state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_starting_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_STARTING); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit * from the SCI_BASE_CONTROLLER_STATE_STARTING. * - This function stops the controller starting timeout timer. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_starting_state_exit( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_cb_timer_stop(object, this_controller->timeout_timer); // We are done with this timer since we are exiting the starting // state so remove it scic_cb_timer_destroy( this_controller, this_controller->phy_startup_timer ); this_controller->phy_startup_timer = NULL; } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_READY. * - Set the state handlers to the controllers ready state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_ready_state_enter( SCI_BASE_OBJECT_T *object ) { U32 clock_gating_unit_value; SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_READY); /** * enable clock gating for power control of the scu unit */ clock_gating_unit_value = SMU_CGUCR_READ(this_controller); clock_gating_unit_value &= ~( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE) | SMU_CGUCR_GEN_BIT(TXCLK_ENABLE) | SMU_CGUCR_GEN_BIT(XCLK_ENABLE) ); clock_gating_unit_value |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE); SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value); //set the default interrupt coalescence number and timeout value. scic_controller_set_interrupt_coalescence( this_controller, 0x10, 250); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit * from the SCI_BASE_CONTROLLER_STATE_READY. * - This function does nothing. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_ready_state_exit( SCI_BASE_OBJECT_T *object ) { U32 clock_gating_unit_value; SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; /** * restore clock gating for power control of the scu unit */ clock_gating_unit_value = SMU_CGUCR_READ(this_controller); clock_gating_unit_value &= ~SMU_CGUCR_GEN_BIT(IDLE_ENABLE); clock_gating_unit_value |= ( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE) | SMU_CGUCR_GEN_BIT(TXCLK_ENABLE) | SMU_CGUCR_GEN_BIT(XCLK_ENABLE) ); SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value); //disable interrupt coalescence. scic_controller_set_interrupt_coalescence(this_controller, 0, 0); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_READY. * - Set the state handlers to the controllers ready state. * - Stop all of the remote devices on this controller * - Stop the ports on this controller * - Stop the phys on this controller * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_stopping_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_STOPPING); // Stop all of the components for this controller in the reverse order // from which they are initialized. scic_sds_controller_stop_devices(this_controller); scic_sds_controller_stop_ports(this_controller); if (!scic_sds_controller_has_remote_devices_stopping(this_controller)) { sci_base_state_machine_change_state( &this_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_STOPPED ); } } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit * from the SCI_BASE_CONTROLLER_STATE_STOPPING. * - This function stops the controller stopping timeout timer. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_stopping_state_exit( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_cb_timer_stop(this_controller, this_controller->timeout_timer); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_STOPPED. * - Set the state handlers to the controllers stopped state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_stopped_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_STOPPED); // We are done with this timer until the next timer we initialize scic_cb_timer_destroy( this_controller, this_controller->timeout_timer ); this_controller->timeout_timer = NULL; // Controller has stopped so disable all the phys on this controller scic_sds_controller_stop_phys(this_controller); scic_sds_port_configuration_agent_destroy( this_controller, &this_controller->port_agent ); scic_cb_controller_stop_complete(this_controller, SCI_SUCCESS); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_RESETTING. * - Set the state handlers to the controllers resetting state. * - Write to the SCU hardware reset register to force a reset * - Transition to the SCI_BASE_CONTROLLER_STATE_RESET * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_resetting_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; SCIC_LOG_TRACE(( sci_base_object_get_logger(this_controller), SCIC_LOG_OBJECT_CONTROLLER, "scic_sds_controller_resetting_state_enter(0x%x) enter\n", this_controller )); scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_RESETTING); scic_sds_controller_reset_hardware(this_controller); sci_base_state_machine_change_state( scic_sds_controller_get_base_state_machine(this_controller), SCI_BASE_CONTROLLER_STATE_RESET ); } static SCI_STATUS scic_sds_abort_reqests( SCIC_SDS_CONTROLLER_T * controller, SCIC_SDS_REMOTE_DEVICE_T * remote_device, SCIC_SDS_PORT_T * port ) { SCI_STATUS status = SCI_SUCCESS; SCI_STATUS terminate_status = SCI_SUCCESS; SCIC_SDS_REQUEST_T *the_request; U32 index; U32 request_count; if (remote_device != NULL) request_count = remote_device->started_request_count; else if (port != NULL) request_count = port->started_request_count; else request_count = SCI_MAX_IO_REQUESTS; for (index = 0; (index < SCI_MAX_IO_REQUESTS) && (request_count > 0); index++) { the_request = controller->io_request_table[index]; if (the_request != NULL) { if (the_request->target_device == remote_device || the_request->target_device->owning_port == port || (remote_device == NULL && port == NULL)) { terminate_status = scic_controller_terminate_request( controller, the_request->target_device, the_request ); if (terminate_status != SCI_SUCCESS) status = terminate_status; request_count--; } } } return status; } SCI_STATUS scic_sds_terminate_reqests( SCIC_SDS_CONTROLLER_T *this_controller, SCIC_SDS_REMOTE_DEVICE_T *this_remote_device, SCIC_SDS_PORT_T *this_port ) { SCI_STATUS status = SCI_SUCCESS; SCI_STATUS abort_status = SCI_SUCCESS; // move all request to abort state abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port); if (abort_status != SCI_SUCCESS) status = abort_status; //move all request to complete state if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR) abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port); if (abort_status != SCI_SUCCESS) status = abort_status; return status; } static SCI_STATUS scic_sds_terminate_all_requests( SCIC_SDS_CONTROLLER_T * controller ) { return scic_sds_terminate_reqests(controller, NULL, NULL); } /** * This method implements the actions taken by the SCIC_SDS_CONTROLLER on * entry to the SCI_BASE_CONTROLLER_STATE_FAILED. * - Set the state handlers to the controllers failed state. * * @param[in] object This is the SCI_BASE_OBJECT which is cast to a * SCIC_SDS_CONTROLLER object. * * @return none */ static void scic_sds_controller_failed_state_enter( SCI_BASE_OBJECT_T *object ) { SCIC_SDS_CONTROLLER_T *this_controller; this_controller= (SCIC_SDS_CONTROLLER_T *)object; scic_sds_controller_set_base_state_handlers( this_controller, SCI_BASE_CONTROLLER_STATE_FAILED); if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR) scic_sds_terminate_all_requests(this_controller); else scic_sds_controller_release_resource(this_controller); //notify framework the controller failed. scic_cb_controller_error(this_controller, this_controller->parent.error); } // --------------------------------------------------------------------------- SCI_BASE_STATE_T scic_sds_controller_state_table[SCI_BASE_CONTROLLER_MAX_STATES] = { { SCI_BASE_CONTROLLER_STATE_INITIAL, scic_sds_controller_initial_state_enter, NULL, }, { SCI_BASE_CONTROLLER_STATE_RESET, scic_sds_controller_reset_state_enter, NULL, }, { SCI_BASE_CONTROLLER_STATE_INITIALIZING, scic_sds_controller_initializing_state_enter, NULL, }, { SCI_BASE_CONTROLLER_STATE_INITIALIZED, scic_sds_controller_initialized_state_enter, NULL, }, { SCI_BASE_CONTROLLER_STATE_STARTING, scic_sds_controller_starting_state_enter, scic_sds_controller_starting_state_exit, }, { SCI_BASE_CONTROLLER_STATE_READY, scic_sds_controller_ready_state_enter, scic_sds_controller_ready_state_exit, }, { SCI_BASE_CONTROLLER_STATE_RESETTING, scic_sds_controller_resetting_state_enter, NULL, }, { SCI_BASE_CONTROLLER_STATE_STOPPING, scic_sds_controller_stopping_state_enter, scic_sds_controller_stopping_state_exit, }, { SCI_BASE_CONTROLLER_STATE_STOPPED, scic_sds_controller_stopped_state_enter, NULL, }, { SCI_BASE_CONTROLLER_STATE_FAILED, scic_sds_controller_failed_state_enter, NULL, } }; Index: head/sys/dev/isci/scil/scif_sas_controller.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_controller.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_controller.c (revision 231296) @@ -1,1249 +1,1255 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the implementation of the SCIF_SAS_CONTROLLER * object. */ #include #include #include #include #include #include #include #include #include //****************************************************************************** //* P U B L I C M E T H O D S //****************************************************************************** SCI_STATUS scif_controller_construct( SCI_LIBRARY_HANDLE_T library, SCI_CONTROLLER_HANDLE_T controller, void * user_object ) { SCI_STATUS status = SCI_SUCCESS; SCIF_SAS_LIBRARY_T * fw_library = (SCIF_SAS_LIBRARY_T*) library; SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if ((library == SCI_INVALID_HANDLE) || (controller == SCI_INVALID_HANDLE)) return SCI_FAILURE_INVALID_PARAMETER_VALUE; SCIF_LOG_TRACE(( sci_base_object_get_logger(library), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "scif_controller_construct(0x%x, 0x%x) enter\n", library, controller )); // Construct the base controller. As part of constructing the base // controller we ask it to also manage the MDL iteration for the Core. sci_base_controller_construct( &fw_controller->parent, sci_base_object_get_logger(fw_library), scif_sas_controller_state_table, fw_controller->mdes, SCIF_SAS_MAX_MEMORY_DESCRIPTORS, sci_controller_get_memory_descriptor_list_handle(fw_controller->core_object) ); scif_sas_controller_initialize_state_logging(fw_controller); sci_object_set_association(fw_controller, user_object); status = scic_controller_construct( fw_library->core_object, fw_controller->core_object, fw_controller ); // If the core controller was successfully constructed, then // finish construction of the framework controller. if (status == SCI_SUCCESS) { // Set the association in the core controller to this framework // controller. sci_object_set_association( (SCI_OBJECT_HANDLE_T) fw_controller->core_object, fw_controller ); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESET ); } return status; } // --------------------------------------------------------------------------- SCI_STATUS scif_controller_initialize( SCI_CONTROLLER_HANDLE_T controller ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if (controller == 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_INITIALIZATION, "scif_controller_initialize(0x%x) enter\n", controller )); return fw_controller->state_handlers->initialize_handler( &fw_controller->parent ); } // --------------------------------------------------------------------------- U32 scif_controller_get_suggested_start_timeout( SCI_CONTROLLER_HANDLE_T controller ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if (controller == SCI_INVALID_HANDLE) return 0; // Currently we aren't adding any additional time into the suggested // timeout value for the start operation. Simply utilize the core // value. return scic_controller_get_suggested_start_timeout(fw_controller->core_object); } // --------------------------------------------------------------------------- SCI_STATUS scif_controller_start( SCI_CONTROLLER_HANDLE_T controller, U32 timeout ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if (controller == 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_INITIALIZATION, "scif_controller_start(0x%x, 0x%x) enter\n", controller, timeout )); return fw_controller->state_handlers-> start_handler(&fw_controller->parent, timeout); } // --------------------------------------------------------------------------- SCI_STATUS scif_controller_stop( SCI_CONTROLLER_HANDLE_T controller, U32 timeout ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if (controller == 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_SHUTDOWN, "scif_controller_stop(0x%x, 0x%x) enter\n", controller, timeout )); return fw_controller->state_handlers-> stop_handler(&fw_controller->parent, timeout); } // --------------------------------------------------------------------------- SCI_STATUS scif_controller_reset( SCI_CONTROLLER_HANDLE_T controller ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if (controller == 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_CONTROLLER_RESET, "scif_controller_reset(0x%x) enter\n", controller )); return fw_controller->state_handlers-> reset_handler(&fw_controller->parent); } // --------------------------------------------------------------------------- SCI_CONTROLLER_HANDLE_T scif_controller_get_scic_handle( SCI_CONTROLLER_HANDLE_T controller ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; return fw_controller->core_object; } // --------------------------------------------------------------------------- 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) ) { - return fw_controller->state_handlers->start_io_handler( + 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 - return SCI_FAILURE_INSUFFICIENT_RESOURCES; + status = SCI_FAILURE_INSUFFICIENT_RESOURCES; + + return (SCI_IO_STATUS)status; } // --------------------------------------------------------------------------- SCI_TASK_STATUS scif_controller_start_task( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T task_request, U16 io_tag ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; + SCI_STATUS status; // 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; + return SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE; } SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT, "scif_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, task_request, io_tag )); if (scif_sas_controller_sufficient_resource(controller)) { - return fw_controller->state_handlers->start_task_handler( + status = fw_controller->state_handlers->start_task_handler( (SCI_BASE_CONTROLLER_T*) controller, (SCI_BASE_REMOTE_DEVICE_T*) remote_device, (SCI_BASE_REQUEST_T*) task_request, io_tag ); } else - return SCI_FAILURE_INSUFFICIENT_RESOURCES; + status = SCI_FAILURE_INSUFFICIENT_RESOURCES; + + return (SCI_TASK_STATUS)status; } // --------------------------------------------------------------------------- SCI_STATUS scif_controller_complete_io( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T io_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request )); return fw_controller->state_handlers->complete_io_handler( (SCI_BASE_CONTROLLER_T*) controller, (SCI_BASE_REMOTE_DEVICE_T*) remote_device, (SCI_BASE_REQUEST_T*) io_request ); } // --------------------------------------------------------------------------- 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_STATUS scif_controller_get_domain_handle( SCI_CONTROLLER_HANDLE_T controller, U8 port_index, SCI_DOMAIN_HANDLE_T * domain_handle ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; // Validate the user supplied parameters. if (controller == SCI_INVALID_HANDLE) return SCI_FAILURE_INVALID_PARAMETER_VALUE; // Retrieve the domain handle if the supplied index is legitimate. if (port_index < SCI_MAX_PORTS) { *domain_handle = &fw_controller->domains[port_index]; return SCI_SUCCESS; } return SCI_FAILURE_INVALID_PORT; } /** * @brief This method builds the memory descriptor list for this * controller. * * @param[in] fw_controller This parameter specifies the framework * controller object for which to build the MDL. * * @return none */ void scif_sas_controller_build_mdl( SCIF_SAS_CONTROLLER_T * fw_controller ) { // one internal request for each domain. sci_base_mde_construct( &fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO], 4, fw_controller->internal_request_entries * scif_sas_internal_request_get_object_size(), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); } // --------------------------------------------------------------------------- SCI_STATUS scif_controller_set_mode( SCI_CONTROLLER_HANDLE_T controller, SCI_CONTROLLER_MODE mode ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; SCI_STATUS status = SCI_SUCCESS; if ( (fw_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZING) || (fw_controller->parent.state_machine.current_state_id == SCI_BASE_CONTROLLER_STATE_INITIALIZED) ) { switch (mode) { case SCI_MODE_SPEED: fw_controller->internal_request_entries = MIN(fw_controller->internal_request_entries, SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT); scif_sas_controller_build_mdl(fw_controller); break; case SCI_MODE_SIZE: fw_controller->internal_request_entries = MIN(fw_controller->internal_request_entries, SCIF_SAS_MIN_INTERNAL_REQUEST_COUNT); scif_sas_controller_build_mdl(fw_controller); break; default: status = SCI_FAILURE_INVALID_PARAMETER_VALUE; break; } } else status = SCI_FAILURE_INVALID_STATE; if (status != SCI_SUCCESS) { return status; } else { // Currently, the framework doesn't change any configurations for // speed or size modes. Default to speed mode basically. return scic_controller_set_mode(fw_controller->core_object, mode); } } // --------------------------------------------------------------------------- U32 scif_controller_get_sat_compliance_version( void ) { /// @todo Fix return of SAT compliance version. return 0; } // --------------------------------------------------------------------------- U32 scif_controller_get_sat_compliance_version_revision( void ) { /// @todo Fix return of SAT compliance revision. return 0; } // --------------------------------------------------------------------------- SCI_STATUS scif_user_parameters_set( SCI_CONTROLLER_HANDLE_T controller, SCIF_USER_PARAMETERS_T * scif_parms ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; //validate all the registry entries before overwriting the default parameter //values. if (scif_parms->sas.is_sata_ncq_enabled != 1 && scif_parms->sas.is_sata_ncq_enabled != 0) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if (scif_parms->sas.max_ncq_depth < 1 && scif_parms->sas.max_ncq_depth > 32) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if (scif_parms->sas.is_sata_standby_timer_enabled != 1 && scif_parms->sas.is_sata_standby_timer_enabled != 0) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if (scif_parms->sas.is_non_zero_buffer_offsets_enabled != 1 && scif_parms->sas.is_non_zero_buffer_offsets_enabled != 0) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if (scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK && scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK_SET && scif_parms->sas.reset_type != SCI_SAS_CLEAR_TASK_SET && scif_parms->sas.reset_type != SCI_SAS_LOGICAL_UNIT_RESET && scif_parms->sas.reset_type != SCI_SAS_I_T_NEXUS_RESET && scif_parms->sas.reset_type != SCI_SAS_CLEAR_ACA && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK_SET && scif_parms->sas.reset_type != SCI_SAS_QUERY_ASYNCHRONOUS_EVENT && scif_parms->sas.reset_type != SCI_SAS_HARD_RESET) return SCI_FAILURE_INVALID_PARAMETER_VALUE; if (scif_parms->sas.clear_affiliation_during_controller_stop != 1 && scif_parms->sas.clear_affiliation_during_controller_stop !=0) return SCI_FAILURE_INVALID_PARAMETER_VALUE; memcpy((&fw_controller->user_parameters), scif_parms, sizeof(*scif_parms)); // In the future more could be done to prevent setting parameters at the // wrong time, but for now we'll simply set the values even if it is too // late for them to take affect. return SCI_SUCCESS; } // --------------------------------------------------------------------------- #if !defined(DISABLE_INTERRUPTS) /** * @brief This routine check each domain of the controller to see if * any domain is overriding interrupt coalescence. * * @param[in] fw_controller frame controller * @param[in] fw_smp_phy The smp phy to be freed. * * @return none */ static BOOL scif_sas_controller_is_overriding_interrupt_coalescence( SCIF_SAS_CONTROLLER_T * fw_controller ) { U8 index; for(index = 0; index < SCI_MAX_DOMAINS; index++) { if(fw_controller->domains[index].parent.state_machine.current_state_id == SCI_BASE_DOMAIN_STATE_DISCOVERING) return TRUE; } return FALSE; } SCI_STATUS scif_controller_set_interrupt_coalescence( SCI_CONTROLLER_HANDLE_T controller, U32 coalesce_number, U32 coalesce_timeout ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T * )controller; ///when framework is in the middle of temporarily overriding the interrupt ///coalescence values, user's request of setting interrupt coalescence ///will be saved. As soon as the framework done the temporary overriding, ///it will serve user's request to set new interrupt coalescence. if (scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller)) { U32 curr_coalesce_number; U32 curr_coalesce_timeout; SCI_STATUS core_status; // save current interrupt coalescence info. scic_controller_get_interrupt_coalescence ( fw_controller->core_object, &curr_coalesce_number, &curr_coalesce_timeout); //try user's request out in the core, but immediately restore core's //current setting. core_status = scic_controller_set_interrupt_coalescence( fw_controller->core_object, coalesce_number, coalesce_timeout); if ( core_status == SCI_SUCCESS ) { fw_controller->saved_interrupt_coalesce_number = (U16)coalesce_number; fw_controller->saved_interrupt_coalesce_timeout = coalesce_timeout; } //restore current interrupt coalescence. scic_controller_set_interrupt_coalescence( fw_controller->core_object, curr_coalesce_number, curr_coalesce_timeout); return core_status; } else { ///If framework is not internally overriding the interrupt coalescence, ///serve user's request immediately by passing the reqeust to core. return scic_controller_set_interrupt_coalescence( fw_controller->core_object, coalesce_number, coalesce_timeout); } } // --------------------------------------------------------------------------- void scif_controller_get_interrupt_coalescence( SCI_CONTROLLER_HANDLE_T controller, U32 * coalesce_number, U32 * coalesce_timeout ) { SCIF_SAS_CONTROLLER_T * scif_controller = (SCIF_SAS_CONTROLLER_T * )controller; scic_controller_get_interrupt_coalescence( scif_controller->core_object, coalesce_number, coalesce_timeout); } /** * @brief This method will save the interrupt coalescence values. If * the interrupt coalescence values have already been saved, * then this method performs no operations. * * @param[in,out] fw_controller This parameter specifies the controller * for which to save the interrupt coalescence values. * * @return none */ void scif_sas_controller_save_interrupt_coalescence( SCIF_SAS_CONTROLLER_T * fw_controller ) { if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller)) { // Override core's interrupt coalescing settings during SMP // DISCOVER process cause' there is only 1 outstanding SMP // request per domain is allowed. scic_controller_get_interrupt_coalescence( fw_controller->core_object, (U32*)&(fw_controller->saved_interrupt_coalesce_number), &(fw_controller->saved_interrupt_coalesce_timeout) ); // Temporarily disable the interrupt coalescing. scic_controller_set_interrupt_coalescence(fw_controller->core_object,0,0); } } /** * @brief This method will restore the interrupt coalescence values. If * the interrupt coalescence values have not already been saved, * then this method performs no operations. * * @param[in,out] fw_controller This parameter specifies the controller * for which to restore the interrupt coalescence values. * * @return none */ void scif_sas_controller_restore_interrupt_coalescence( SCIF_SAS_CONTROLLER_T * fw_controller ) { if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller)) scic_controller_set_interrupt_coalescence( fw_controller->core_object, fw_controller->saved_interrupt_coalesce_number, fw_controller->saved_interrupt_coalesce_timeout ); } #endif // !defined(DISABLE_INTERRUPTS) // --------------------------------------------------------------------------- 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); } // --------------------------------------------------------------------------- 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); } // --------------------------------------------------------------------------- void scic_cb_controller_error( SCI_CONTROLLER_HANDLE_T controller, SCI_CONTROLLER_ERROR error ) { SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*) sci_object_get_association(controller); fw_controller->parent.error = error; SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN, "scic_cb_controller_not_ready(0x%x) enter\n", controller )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_FAILED ); } //****************************************************************************** //* P R O T E C T E D M E T H O D S //****************************************************************************** /** * @brief This method is utilized to continue an internal IO operation * on the controller. This method is utilized for SAT translated * requests that generate multiple ATA commands in order to fulfill * the original SCSI request. * * @param[in] controller This parameter specifies the controller on which * to continue an internal IO request. * @param[in] remote_device This parameter specifies the remote device * on which to continue an internal IO request. * @param[in] io_request This parameter specifies the IO request to be * continue. * * @return Indicate if the continue operation was successful. * @retval SCI_SUCCESS This value is returned if the operation succeeded. */ SCI_STATUS scif_sas_controller_continue_io( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T io_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; return fw_controller->state_handlers->continue_io_handler( (SCI_BASE_CONTROLLER_T*) controller, (SCI_BASE_REMOTE_DEVICE_T*) remote_device, (SCI_BASE_REQUEST_T*) io_request ); } /** * @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 )); } //----------------------------------------------------------------------------- // INTERNAL REQUEST RELATED METHODS //----------------------------------------------------------------------------- /** * @brief This routine is to allocate the memory for creating a new internal * request. * * @param[in] scif_controller handle to frame controller * * @return void* address to internal request memory */ void * scif_sas_controller_allocate_internal_request( SCIF_SAS_CONTROLLER_T * fw_controller ) { POINTER_UINT internal_io_address; if( !sci_pool_empty(fw_controller->internal_request_memory_pool) ) { sci_pool_get( fw_controller->internal_request_memory_pool, internal_io_address ); //clean the memory. memset((char*)internal_io_address, 0, scif_sas_internal_request_get_object_size()); return (void *) internal_io_address; } else return NULL; } /** * @brief This routine is to free the memory for a completed internal request. * * @param[in] scif_controller handle to frame controller * @param[in] fw_internal_io The internal IO to be freed. * * @return none */ void scif_sas_controller_free_internal_request( SCIF_SAS_CONTROLLER_T * fw_controller, void * fw_internal_request_buffer ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_controller_free_internal_request(0x%x, 0x%x) enter\n", fw_controller, fw_internal_request_buffer )); //return the memory to to pool. if( !sci_pool_full(fw_controller->internal_request_memory_pool) ) { sci_pool_put( fw_controller->internal_request_memory_pool, (POINTER_UINT) fw_internal_request_buffer ); } } /** * @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 This method will check how many outstanding IOs currently and number * of IOs in high priority queue, if the overall number exceeds the max_tc, * return FALSE. * * @param[in] fw_controller The framework controller. * * @return BOOL Indicate whether there is sufficient resource to start an IO. * @retvalue TRUE The controller has sufficient resource. * @retvalue FALSE There is not sufficient resource available. */ BOOL scif_sas_controller_sufficient_resource( SCIF_SAS_CONTROLLER_T *fw_controller ) { SCIF_SAS_DOMAIN_T * fw_domain; U32 domain_index; U32 outstanding_io_count = 0; U32 high_priority_io_count = 0; for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++) { fw_domain = &fw_controller->domains[domain_index]; outstanding_io_count += fw_domain->request_list.element_count; } high_priority_io_count = sci_pool_count(fw_controller->hprq.pool); if ( (outstanding_io_count + high_priority_io_count) > SCI_MAX_IO_REQUESTS ) return FALSE; return TRUE; } /** * @brief This method is the starting point to complete high prority io for a * controller then down to domain, device. * * @param[in] fw_controller The framework controller * @param[in] remote_device The framework remote device. * @param[in] io_request The high priority io request to be completed. * * @return SCI_STATUS indicate the completion status from framework down to the * core. */ SCI_STATUS scif_sas_controller_complete_high_priority_io( SCIF_SAS_CONTROLLER_T *fw_controller, SCIF_SAS_REMOTE_DEVICE_T *remote_device, SCIF_SAS_REQUEST_T *io_request ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_complete_high_priority_io(0x%x, 0x%x, 0x%x) enter\n", fw_controller, remote_device, io_request )); //call controller's new added complete_high_priority_io_handler return fw_controller->state_handlers->complete_high_priority_io_handler( (SCI_BASE_CONTROLLER_T*) fw_controller, (SCI_BASE_REMOTE_DEVICE_T*) remote_device, (SCI_BASE_REQUEST_T*) io_request ); } /** * @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 routine is to free the memory for a released smp phy. * * @param[in] fw_controller The framework controller, a smp phy is released * to its memory. * @param[in] fw_smp_phy The smp phy to be freed. * * @return none */ void scif_sas_controller_free_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_free_smp_phy(0x%x, 0x%x) enter\n", fw_controller, smp_phy )); //return the memory to the list. sci_fast_list_insert_tail( &fw_controller->smp_phy_memory_list, &smp_phy->list_element ); } /** * @brief This method clear affiliation for all the EA SATA devices associated * to this controller. * * @param[in] fw_controller This parameter specifies the framework * controller object for whose remote devices are to be stopped. * * @return This method returns a value indicating if the operation completed. * @retval SCI_COMPLETE This value indicates that all the EA SATA devices' * affiliation was cleared. * @retval SCI_INCOMPLETE This value indicates clear affiliation activity is * yet to be completed. */ SCI_STATUS scif_sas_controller_clear_affiliation( SCIF_SAS_CONTROLLER_T * fw_controller ) { U8 index; SCI_STATUS status; SCIF_SAS_DOMAIN_T * fw_domain; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "scif_sas_controller_clear_affiliation(0x%x) enter\n", fw_controller )); index = fw_controller->current_domain_to_clear_affiliation; if (index < SCI_MAX_DOMAINS) { fw_domain = &fw_controller->domains[index]; //Need to stop all the on-going smp activities before clearing affiliation. scif_sas_domain_cancel_smp_activities(fw_domain); scif_sas_domain_start_clear_affiliation(fw_domain); status = SCI_WARNING_SEQUENCE_INCOMPLETE; } else { //the controller has done clear affiliation work to all its domains. scif_sas_controller_continue_to_stop(fw_controller); status = SCI_SUCCESS; } return status; } /** * @brief This method sets SCIF user parameters to * default values. Users can override these values utilizing * the sciF_user_parameters_set() methods. * * @param[in] controller This parameter specifies the controller for * which to set the configuration parameters to their * default values. * * @return none */ void scif_sas_controller_set_default_config_parameters( SCIF_SAS_CONTROLLER_T * this_controller ) { SCIF_USER_PARAMETERS_T * scif_parms = &(this_controller->user_parameters); scif_parms->sas.is_sata_ncq_enabled = TRUE; scif_parms->sas.max_ncq_depth = 32; scif_parms->sas.is_sata_standby_timer_enabled = FALSE; scif_parms->sas.is_non_zero_buffer_offsets_enabled = FALSE; scif_parms->sas.reset_type = SCI_SAS_LOGICAL_UNIT_RESET; scif_parms->sas.clear_affiliation_during_controller_stop = TRUE; scif_parms->sas.ignore_fua = FALSE; } /** * @brief This method releases resource for framework controller and associated * objects. * * @param[in] fw_controller This parameter specifies the framework * controller and associated objects whose resources are to be released. * * @return This method returns a value indicating if the operation succeeded. * @retval SCI_SUCCESS This value indicates that resource release succeeded. * @retval SCI_FAILURE This value indicates certain failure during the process * of resource release. */ SCI_STATUS scif_sas_controller_release_resource( SCIF_SAS_CONTROLLER_T * fw_controller ) { U8 index; SCIF_SAS_DOMAIN_T * fw_domain; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "scif_sas_controller_release_resource(0x%x) enter\n", fw_controller )); //currently the only resource to be released is domain's timer. for (index = 0; index < SCI_MAX_DOMAINS; index++) { fw_domain = &fw_controller->domains[index]; scif_sas_domain_release_resource(fw_controller, fw_domain); } return SCI_SUCCESS; } #ifdef SCI_LOGGING /** * This method will start state transition logging for the framework * controller object. * * @param[in] fw_controller The framework controller object on which to * observe state changes. * * @return none */ void scif_sas_controller_initialize_state_logging( SCIF_SAS_CONTROLLER_T * fw_controller ) { sci_base_state_machine_logger_initialize( &fw_controller->parent.state_machine_logger, &fw_controller->parent.state_machine, &fw_controller->parent.parent, scif_cb_logger_log_states, "SCIF_SAS_CONTROLLER_T", "base state machine", SCIF_LOG_OBJECT_CONTROLLER ); } /** * This method will remove the logging of state transitions from the framework * controller object. * * @param[in] fw_controller The framework controller to change. * * @return none */ void scif_sas_controller_deinitialize_state_logging( SCIF_SAS_CONTROLLER_T * fw_controller ) { sci_base_state_machine_logger_deinitialize( &fw_controller->parent.state_machine_logger, &fw_controller->parent.state_machine ); } #endif // SCI_LOGGING Index: head/sys/dev/isci/scil/scif_sas_controller_state_handlers.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_controller_state_handlers.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_controller_state_handlers.c (revision 231296) @@ -1,1845 +1,1845 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains all of the state handler routines for each * of the controller states defined by the SCI_BASE_CONTROLLER state * machine. */ #include #include #include #include #include #include #include #include #include //****************************************************************************** //* P R I V A T E M E T H O D S //****************************************************************************** /** * @brief This method simply executes the reset operation by entering * the reset state and allowing the state to perform it's work. * * @param[in] fw_controller This parameter specifies the SAS framework * controller for execute the reset. * * @return Indicate the status of the reset operation. Was it successful? * @retval SCI_SUCCESS This value is returned if it was successfully reset. */ static SCI_STATUS scif_sas_controller_execute_reset( SCIF_SAS_CONTROLLER_T * fw_controller ) { SCI_STATUS status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_CONTROLLER_RESET, "scif_sas_controller_execute_reset(0x%x) enter\n", fw_controller )); //clean the timer to avoid timer leak. scif_sas_controller_release_resource(fw_controller); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESETTING ); // Retrieve the status for the operations performed during the entrance // to the resetting state were executing successfully. status = fw_controller->operation_status; fw_controller->operation_status = SCI_SUCCESS; return status; } /** * @brief This method checks that the memory descriptor list is valid * and hasn't been corrupted in some way by the user. * * @param[in] fw_controller This parameter specifies the framework * controller object for which to validation the MDL. * * @return This method returns a value indicating if the operation succeeded. * @retval SCI_SUCCESS This value indicates that MDL is valid. * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD This value indicates * that some portion of the memory descriptor list is invalid. */ static SCI_STATUS scif_sas_controller_validate_mdl( SCIF_SAS_CONTROLLER_T * fw_controller ) { BOOL is_mde_list_valid; // Currently there is only a single MDE in the list. is_mde_list_valid = sci_base_mde_is_valid( &fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO], 4, fw_controller->internal_request_entries * scif_sas_internal_request_get_object_size(), SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); if (is_mde_list_valid == FALSE) return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD; return SCI_SUCCESS; } /** * @brief This method stops all the domains associated to this * controller. * * @param[in] fw_controller This parameter specifies the framework * controller object for whose remote devices are to be stopped. * * @return This method returns a value indicating if the operation succeeded. * @retval SCI_SUCCESS This value indicates that all the devices are stopped. * @retval SCI_FAILURE This value indicates certain failure during the process * of stopping remote devices. */ static SCI_STATUS scif_sas_controller_stop_domains( SCIF_SAS_CONTROLLER_T * fw_controller ) { U8 index; SCI_STATUS status = SCI_SUCCESS; SCIF_SAS_DOMAIN_T * fw_domain; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "scif_sas_controller_stop_domains(0x%x) enter\n", fw_controller )); for (index = 0; index < SCI_MAX_DOMAINS && status == SCI_SUCCESS; index++) { fw_domain = &fw_controller->domains[index]; //Change this domain to STOPPING state. All the remote devices will be //stopped subsquentially. if (fw_domain->parent.state_machine.current_state_id == SCI_BASE_DOMAIN_STATE_READY || fw_domain->parent.state_machine.current_state_id == SCI_BASE_DOMAIN_STATE_DISCOVERING) { sci_base_state_machine_change_state( &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPING ); } } return status; } /** * @brief This method continue to stop the controller after clear affiliation * is done. * * @param[in] fw_controller This parameter specifies the framework * controller object to be stopped. * * @return This method returns a value indicating if the operation succeeded. * @retval SCI_SUCCESS This value indicates the controller_stop succeeds. * @retval SCI_FAILURE This value indicates certain failure during the process * of stopping controller. */ SCI_STATUS scif_sas_controller_continue_to_stop( SCIF_SAS_CONTROLLER_T * fw_controller ) { SCI_STATUS status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN, "scif_sas_controller_continue_to_stop (0x%x).\n", fw_controller )); //stop all the domains and their remote devices. status = scif_sas_controller_stop_domains(fw_controller); if (status == SCI_SUCCESS) { // Attempt to stop the core controller. status = scic_controller_stop(fw_controller->core_object, 0); if (status != SCI_SUCCESS) { SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN, "Controller:0x%x Status:0x%x unable to stop controller.\n", fw_controller, status )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_FAILED ); } } else { SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN, "Controller:0x%x Status:0x%x unable to stop domains.\n", fw_controller, status )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_FAILED ); } return status; } //****************************************************************************** //* R E S E T H A N D L E R S //****************************************************************************** /** * @brief This method provides RESET state specific handling for * when a user attempts to initialize a controller. This is a legal * state in which to attempt an initialize call. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform an initialize * operation. * * @return This method returns an indication of whether the initialize * operation succeeded. * @retval SCI_SUCCESS This value when the initialization completes * successfully. */ static SCI_STATUS scif_sas_controller_reset_initialize_handler( SCI_BASE_CONTROLLER_T * controller ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)controller; SCI_STATUS status; U32 index; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "scif_sas_controller_reset_initialize_handler(0x%x) enter\n", controller )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_INITIALIZING ); scif_sas_controller_build_mdl(fw_controller); // Perform any domain object initialization that is necessary. for (index = 0; index < SCI_MAX_DOMAINS; index++) scif_sas_domain_initialize(&fw_controller->domains[index]); scif_cb_lock_associate(fw_controller, &fw_controller->hprq.lock); // Attempt to initialize the core controller. status = scic_controller_initialize(fw_controller->core_object); if (status == SCI_SUCCESS) { sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_INITIALIZED ); } if (status != SCI_SUCCESS) { // Initialization failed, Release resources and do not change state scif_sas_controller_release_resource(fw_controller); SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "Controller:0x%x Status:0x%x unable to successfully initialize.\n", fw_controller, status )); } return status; } //****************************************************************************** //* I N I T I A L I Z E D H A N D L E R S //****************************************************************************** /** * @brief This method provides INITIALIZED state specific handling for * when a user attempts to start a controller. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start * operation. * @param[in] timeout This parameter specifies the timeout value (in * milliseconds) to be utilized for this operation. * * @return This method returns an indication of whether the start operation * succeeded. * @retval SCI_SUCCESS This value is returned when the start operation * begins successfully. */ static SCI_STATUS scif_sas_controller_initialized_start_handler( SCI_BASE_CONTROLLER_T * controller, U32 timeout ) { SCI_STATUS status = SCI_SUCCESS; SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)controller; U16 index = 0; SCI_PHYSICAL_MEMORY_DESCRIPTOR_T internal_reqeust_mde = fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO]; void * internal_request_virtual_address = internal_reqeust_mde.virtual_address; POINTER_UINT address = (POINTER_UINT)internal_request_virtual_address; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "scif_sas_controller_initialized_start_handler(0x%x, 0x%x) enter\n", controller, timeout )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_STARTING ); status = scif_sas_controller_validate_mdl(fw_controller); // initialization work for internal request path. It must be done before // starting domain. if (status == SCI_SUCCESS) { // fill in the sci_pool for internal requests. sci_pool_initialize(fw_controller->internal_request_memory_pool); for (index = 0; index < fw_controller->internal_request_entries; index++) { sci_pool_put(fw_controller->internal_request_memory_pool, address); address += scif_sas_internal_request_get_object_size(); } // Using DPC for starting internal IOs, if yes, we need to intialize // DPC here. scif_cb_start_internal_io_task_create(fw_controller); } if (status == SCI_SUCCESS) { // Kick-start the domain state machines and, by association, the // core port's. // This will ensure we get valid port objects supplied with link up // messages. for (index = 0; (index < SCI_MAX_DOMAINS) && (status == SCI_SUCCESS); index++) { sci_base_state_machine_change_state( &fw_controller->domains[index].parent.state_machine, SCI_BASE_DOMAIN_STATE_STARTING ); status = fw_controller->domains[index].operation.status; } } // Validate that all the domain state machines began successfully. if (status != SCI_SUCCESS) { SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "Controller:0x%x Domain:0x%x Status:0x%x unable to start\n", fw_controller, index, status )); return status; } // Attempt to start the core controller. status = scic_controller_start(fw_controller->core_object, timeout); if (status != SCI_SUCCESS) { SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "Controller:0x%x Status:0x%x unable to start controller.\n", fw_controller, status )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_FAILED ); } return status; } //****************************************************************************** //* R E A D Y H A N D L E R S //****************************************************************************** /** * @brief This method provides READY state specific handling for * when a user attempts to stop a controller. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a stop * operation. * @param[in] timeout This parameter specifies the timeout value (in * milliseconds) to be utilized for this operation. * * @return This method returns an indication of whether the stop operation * succeeded. * @retval SCI_SUCCESS This value is returned when the stop operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_stop_handler( SCI_BASE_CONTROLLER_T * controller, U32 timeout ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)controller; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION, "scif_sas_controller_ready_stop_handler(0x%x, 0x%x) enter\n", controller, timeout )); sci_base_state_machine_change_state( &fw_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_STOPPING ); if (fw_controller->user_parameters.sas.clear_affiliation_during_controller_stop) { fw_controller->current_domain_to_clear_affiliation = 0; //clear affiliation first. After the last domain finishes clearing //affiliation, it will call back to controller to continue to stop. scif_sas_controller_clear_affiliation(fw_controller); } else scif_sas_controller_continue_to_stop(fw_controller); //Must return SUCCESS at this point. return SCI_SUCCESS; } /** * @brief This method provides READY state specific handling for * when a user attempts to reset a controller. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a reset * operation. * * @return This method returns an indication of whether the reset operation * succeeded. * @retval SCI_SUCCESS This value is returned when the reset operation * completes successfully. */ static SCI_STATUS scif_sas_controller_ready_reset_handler( SCI_BASE_CONTROLLER_T * controller ) { return scif_sas_controller_execute_reset((SCIF_SAS_CONTROLLER_T*)controller); } /** * @brief This method provides READY state specific handling for * when a user attempts to start an IO request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_io() for * more information. * * @return This method returns an indication of whether the start IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the start IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_start_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, U16 io_tag ) { SCI_STATUS status; SCIF_SAS_IO_REQUEST_T *fw_io = (SCIF_SAS_IO_REQUEST_T*)io_request; SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)controller; SCIF_SAS_REMOTE_DEVICE_T *fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) remote_device; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_ready_start_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request, io_tag )); status = fw_device->domain->state_handlers->start_io_handler( &fw_device->domain->parent, remote_device, io_request ); // Check to see that the other objects in the framework allowed // this IO to be started. if (status == SCI_SUCCESS) { // Ask the core to start processing for this IO request. - status = scic_controller_start_io( + status = (SCI_STATUS)scic_controller_start_io( fw_controller->core_object, fw_device->core_object, fw_io->parent.core_object, io_tag ); if (status == SCI_SUCCESS) { // We were able to start the core request. As a result, // commit to starting the request for the framework by changing // the state of the IO request. sci_base_state_machine_change_state( &io_request->state_machine, SCI_BASE_REQUEST_STATE_STARTED ); } else { // We were unable to start the core IO request. As a result, // back out the start operation for the framework. It's easier to // back out the framework start operation then to backout the core // start IO operation. fw_device->domain->state_handlers->complete_io_handler( &fw_device->domain->parent, remote_device, io_request ); // Invoke the IO completion handler. For most IOs, this does nothing // since we are still in the constructed state. For NCQ, this will // the return of the NCQ tag back to the remote device free pool. fw_io->parent.state_handlers->complete_handler(io_request); SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x IORequest:0x%x Status:0x%x core IO start failed\n", fw_controller, fw_io, status )); } } else { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x IORequest:0x%x Status:0x%x IO start failed\n", fw_controller, fw_io, status )); } return status; } /** * @brief This method provides READY state specific handling for * when a user attempts to complete an IO request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a complete IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * * @return This method returns an indication of whether the complete IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the complete IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_complete_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) remote_device; SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request; SCI_STATUS status; SCI_STATUS core_status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_ready_complete_io_handler(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request )); fw_io->parent.state_handlers->destruct_handler(&fw_io->parent.parent); status = fw_device->domain->state_handlers->complete_io_handler( &fw_device->domain->parent, remote_device, io_request ); // Ask the core to finish processing for this IO request. core_status = scic_controller_complete_io( fw_controller->core_object, fw_device->core_object, fw_io->parent.core_object ); if (status == SCI_SUCCESS) status = core_status; if (status != SCI_SUCCESS) { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x IORequest:0x%x Status:0x%x CoreStatus:0x%x " "failure to complete IO\n", fw_controller, fw_io, status, core_status )); } return status; } /** * @brief This method provides READY state specific handling for * when a user attempts to complete a high priority IO request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a complete IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * * @return This method returns an indication of whether the complete IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the complete IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_complete_high_priority_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) remote_device; SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request; SCI_IO_STATUS core_completion_status = scic_request_get_sci_status(fw_io->parent.core_object); U8 response_data[SCIF_SAS_RESPONSE_DATA_LENGTH]; SCI_STATUS status; SCI_STATUS core_status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_ready_complete_high_priority_io_handler(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request )); // In high priority path, we ask the core to finish IO request before framework. // retrieve and save io response from core now. memcpy(response_data, scic_io_request_get_response_iu_address(fw_io->parent.core_object), SCIF_SAS_RESPONSE_DATA_LENGTH ); core_status = scic_controller_complete_io( fw_controller->core_object, fw_device->core_object, fw_io->parent.core_object ); fw_io->parent.state_handlers->destruct_handler(&fw_io->parent.parent); status = fw_device->domain->state_handlers->complete_high_priority_io_handler( &fw_device->domain->parent, remote_device, io_request, (void *)response_data, core_completion_status ); if (status == SCI_SUCCESS) status = core_status; if (status == SCI_SUCCESS) { //issue DPC to start next internal io in high prioriy queue. if( !sci_pool_empty(fw_controller->hprq.pool) ) scif_cb_start_internal_io_task_schedule( fw_controller, scif_sas_controller_start_high_priority_io, fw_controller ); } else { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x IORequest:0x%x Status:0x%x CoreStatus:0x%x " "failure to complete IO\n", fw_controller, fw_io, status, core_status )); } return status; } /** * @brief This method provides READY state specific handling for * when a user attempts to continue an IO request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a continue IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * * @return This method returns an indication of whether the continue IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the continue IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_continue_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_ready_continue_io_handler(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request )); /// @todo Function unimplemented. fix return code handling. return SCI_FAILURE; } /** * @brief This method provides READY state specific handling for * when a user attempts to start a task request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start task * operation. * @param[in] remote_device This parameter specifies the remote deivce * 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. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_task() for * more information. * * @return This method returns an indication of whether the start task * operation succeeded. * @retval SCI_SUCCESS This value is returned when the start task operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_start_task_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * task_request, U16 io_tag ) { SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller; 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; SCI_STATUS status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT, "scif_sas_controller_ready_start_task_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, task_request, io_tag )); status = fw_device->domain->state_handlers->start_task_handler( &fw_device->domain->parent, remote_device, task_request ); if (status == SCI_SUCCESS) { if (scif_sas_task_request_get_function(fw_task) == SCI_SAS_HARD_RESET) { // Go off to special target reset path. Don't start task to core. scif_sas_remote_device_target_reset( fw_device, (SCIF_SAS_REQUEST_T *)fw_task ); return SCI_SUCCESS; } // Ask the core to start processing for this task request. - status = scic_controller_start_task( + status = (SCI_STATUS)scic_controller_start_task( fw_controller->core_object, fw_device->core_object, fw_task->parent.core_object, io_tag ); if (status == SCI_SUCCESS) { // We were able to start the core request. As a result, // commit to starting the request for the framework by changing // the state of the task request. fw_task->parent.state_handlers->start_handler(&fw_task->parent.parent); } else { // We were unable to start the core task request. As a result, // back out the start operation for the framework. It's easier to // back out the framework start operation then to backout the core // start task operation. fw_device->domain->state_handlers->complete_task_handler( &fw_device->domain->parent, remote_device, task_request ); if (status == SCI_SUCCESS) { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x TaskRequest:0x%x Status:0x%x core start failed\n", fw_controller, fw_task, status )); } } } else { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x TaskRequest:0x%x Status:0x%x Task start failed\n", fw_controller, fw_task, status )); } return status; } /** * @brief This method provides READY state specific handling for * when a user attempts to complete a task request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a complete task * operation. * @param[in] remote_device This parameter specifies the remote deivce * 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 of whether the complete task * operation succeeded. * @retval SCI_SUCCESS This value is returned when the complete task operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_complete_task_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * task_request ) { SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)controller; 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; SCI_STATUS status; SCI_STATUS core_status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT, "scif_sas_controller_ready_complete_task_handler(0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, task_request )); status = fw_device->domain->state_handlers->complete_task_handler( &fw_device->domain->parent, remote_device, task_request ); if (scif_sas_task_request_get_function(fw_task) == SCI_SAS_HARD_RESET) { //No more things to do in the core, since this task is for Target Reset. return status; } fw_task->parent.state_handlers->destruct_handler(&fw_task->parent.parent); // Ask the core to finish processing for this task request. core_status = scic_controller_complete_task( fw_controller->core_object, fw_device->core_object, fw_task->parent.core_object ); if (status == SCI_SUCCESS) status = core_status; if (status != SCI_SUCCESS) { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x TaskRequest:0x%x Status:0x%x CoreStatus:0x%x " "failed to complete\n", fw_controller, fw_task, status, core_status )); } return status; } /** * @brief This method provides common handling for several states * when a user attempts to start an internal request. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_io() for * more information. * * @return This method returns an indication of whether the start IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the start IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_common_start_high_priority_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, U16 io_tag ) { SCI_STATUS status; SCIF_SAS_IO_REQUEST_T *fw_io = (SCIF_SAS_IO_REQUEST_T*)io_request; SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)controller; SCIF_SAS_REMOTE_DEVICE_T *fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) remote_device; status = fw_device->domain->state_handlers->start_high_priority_io_handler( &fw_device->domain->parent, remote_device, io_request ); // Check to see that the other objects in the framework allowed // this IO to be started. if (status == SCI_SUCCESS) { // Ask the core to start processing for this IO request. - status = scic_controller_start_io( + status = (SCI_STATUS)scic_controller_start_io( fw_controller->core_object, fw_device->core_object, fw_io->parent.core_object, io_tag ); if (status == SCI_SUCCESS) { // We were able to start the core request. As a result, // commit to starting the request for the framework by changing // the state of the IO request. sci_base_state_machine_change_state( &io_request->state_machine, SCI_BASE_REQUEST_STATE_STARTED ); } else { // We were unable to start the core IO request. As a result, // back out the start operation for the framework. It's easier to // back out the framework start operation then to backout the core // start IO operation. fw_device->domain->state_handlers->complete_io_handler( &fw_device->domain->parent, remote_device, io_request ); // Invoke the IO completion handler. For most IOs, this does nothing // since we are still in the constructed state. For NCQ, this will // the return of the NCQ tag back to the remote device free pool. fw_io->parent.state_handlers->complete_handler(io_request); SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x IORequest:0x%x Status:0x%x core IO start failed\n", fw_controller, fw_io, status )); } } else { SCIF_LOG_WARNING(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x IORequest:0x%x Status:0x%x IO start failed\n", fw_controller, fw_io, status )); // Invoke the IO completion handler. For most IOs, this does nothing // since we are still in the constructed state. For NCQ, this will // the return of the NCQ tag back to the remote device free pool. fw_io->parent.state_handlers->complete_handler(io_request); } if (fw_io->parent.is_internal && status != SCI_SUCCESS ) { SCIC_TRANSPORT_PROTOCOL protocol = scic_io_request_get_protocol(fw_io->parent.core_object); U8 retry_count = fw_io->retry_count; scif_sas_internal_io_request_destruct( fw_device->domain->controller, (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_io ); if ( protocol == SCIC_SMP_PROTOCOL ) { if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL) { //destroy the smp_activity_timer scif_cb_timer_destroy ( fw_controller, fw_device->protocol_device.smp_device.smp_activity_timer ); fw_device->protocol_device.smp_device.smp_activity_timer = NULL; } //we should retry for finite times if ( retry_count < SCIF_SAS_IO_RETRY_LIMIT) { //An internal smp request failed being started, most likely due to remote device //is not in ready state, for example, UPDATING_PORT_WIDTH state. In this case, //we should retry the IO. scif_sas_smp_remote_device_retry_internal_io( (SCIF_SAS_REMOTE_DEVICE_T *)remote_device, retry_count, SMP_REQUEST_RETRY_WAIT_DURATION ); } } } return status; } /** * @brief This method provides READY state specific handling for * when a user attempts to start an internal request. If the high * priority IO is also internal, this method will schedule its timer. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_io() for * more information. * * @return This method returns an indication of whether the start IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the start IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_ready_start_high_priority_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, U16 io_tag ) { SCI_STATUS status; SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)io_request; SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_ready_start_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request, io_tag )); status = scif_sas_controller_common_start_high_priority_io_handler( controller, remote_device, io_request, io_tag); if (status == SCI_SUCCESS) { //External io could also be put in high priority queue. i.e. the //smp request for EA Target Reset. if (fw_io->parent.is_internal) { SCIF_SAS_INTERNAL_IO_REQUEST_T * fw_internal_io = (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_io; //start the timer for internal io scif_cb_timer_start( (SCI_CONTROLLER_HANDLE_T)controller, fw_internal_io->internal_io_timer, SCIF_SAS_INTERNAL_REQUEST_TIMEOUT ); } } else { //If failed to start, most likely the device or domain is not in //correct state, and the IO has been cleaned up in controller's start //high priority IO handler. We should just continue to start the next //IO in the HP queue. SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_controller_start_high_priority_io(0x%x, 0x%x), starting io failed\n", controller, fw_io )); } return status; } //****************************************************************************** //* S T O P P I N G H A N D L E R S //****************************************************************************** /** * @brief This method provides STOPPING state specific handling for * when a user attempts to start an internal request. Note that we don't * start the timer for internal IO during controller stopping state. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_io() for * more information. * * @return This method returns an indication of whether the start IO * operation succeeded. * @retval SCI_SUCCESS This value is returned when the start IO operation * begins successfully. */ static SCI_STATUS scif_sas_controller_stopping_start_high_priority_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, U16 io_tag ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_controller_stopping_start_high_priority_io_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request, io_tag )); return scif_sas_controller_common_start_high_priority_io_handler( controller, remote_device, io_request, io_tag); } //****************************************************************************** //* S T O P P E D H A N D L E R S //****************************************************************************** /** * @brief This method provides STOPPED state specific handling for * when a user attempts to reset a controller. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a reset * operation. * * @return This method returns an indication of whether the reset operation * succeeded. * @retval SCI_SUCCESS This value is returned when the reset operation * completes successfully. */ static SCI_STATUS scif_sas_controller_stopped_reset_handler( SCI_BASE_CONTROLLER_T * controller ) { return scif_sas_controller_execute_reset((SCIF_SAS_CONTROLLER_T*)controller); } //****************************************************************************** //* F A I L E D H A N D L E R S //****************************************************************************** /** * @brief This method provides FAILED state specific handling for * when a user attempts to reset a controller. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a reset * operation. * * @return This method returns an indication of whether the reset operation * succeeded. * @retval SCI_SUCCESS This value is returned when the reset operation * completes successfully. */ static SCI_STATUS scif_sas_controller_failed_reset_handler( SCI_BASE_CONTROLLER_T * controller ) { return scif_sas_controller_execute_reset((SCIF_SAS_CONTROLLER_T*)controller); } //****************************************************************************** //* D E F A U L T H A N D L E R S //****************************************************************************** /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to start a controller and a start operation * is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start operation. * @param[in] timeout This parameter specifies the timeout value (in * milliseconds) to be utilized for this operation. * * @return This method returns an indication that start operations are not * allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_start_handler( SCI_BASE_CONTROLLER_T * controller, U32 timeout ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to start controller.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to stop a controller and a stop operation * is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a stop operation. * @param[in] timeout This parameter specifies the timeout value (in * milliseconds) to be utilized for this operation. * * @return This method returns an indication that stop operations are not * allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_stop_handler( SCI_BASE_CONTROLLER_T * controller, U32 timeout ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to stop controller.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to reset a controller and a reset operation * is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a reset operation. * * @return This method returns an indication that reset operations are not * allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_reset_handler( SCI_BASE_CONTROLLER_T * controller ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to reset controller.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to initialize a controller and an initialize * operation is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform an initialize * operation. * * @return This method returns an indication that initialize operations * are not allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_initialize_handler( SCI_BASE_CONTROLLER_T * controller ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to initialize controller.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to start an IO on a controller and a start * IO operation is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_io() for * more information. * * @return This method returns an indication that start IO operations * are not allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_start_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, U16 io_tag ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to start IO.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to complete an IO on a controller and a * complete IO operation is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a complete IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * * @return This method returns an indication that complete IO operations * are not allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_complete_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to complete IO.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to continue an IO on a controller and a * continue IO operation is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a continue IO * operation. * @param[in] remote_device This parameter specifies the remote deivce * object on which the user is attempting to perform a start IO * operation. * @param[in] io_request This parameter specifies the IO request to be * started. * * @return This method returns an indication that continue IO operations * are not allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_continue_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to continue IO.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to start a task on a controller and a start * task operation is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a start task * operation. * @param[in] remote_device This parameter specifies the remote deivce * 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. * @param[in] io_tag This parameter specifies the optional allocated * IO tag. Please reference scif_controller_start_task() for * more information. * * @return This method returns an indication that start task operations * are not allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_start_task_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * task_request, U16 io_tag ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to start task mgmt.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } /** * @brief This method provides default handling (i.e. returns an error) * when a user attempts to complete a task on a controller and a * complete task operation is not allowed. * * @param[in] controller This parameter specifies the controller object * on which the user is attempting to perform a complete task * operation. * @param[in] remote_device This parameter specifies the remote deivce * 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 that complete task operations * are not allowed. * @retval SCI_FAILURE_INVALID_STATE This value is always returned. */ static SCI_STATUS scif_sas_controller_default_complete_task_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * task_request ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to complete task mgmt.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); return SCI_FAILURE_INVALID_STATE; } static SCI_STATUS scif_sas_controller_failed_state_start_io_handler( SCI_BASE_CONTROLLER_T * controller, SCI_BASE_REMOTE_DEVICE_T * remote_device, SCI_BASE_REQUEST_T * io_request, U16 io_tag ) { SCIF_LOG_WARNING(( sci_base_object_get_logger((SCIF_SAS_CONTROLLER_T *)controller), SCIF_LOG_OBJECT_CONTROLLER, "Controller:0x%x State:0x%x invalid state to start IO.\n", controller, sci_base_state_machine_get_state( &((SCIF_SAS_CONTROLLER_T *)controller)->parent.state_machine) )); - return SCI_IO_FAILURE; + return SCI_FAILURE; } #define scif_sas_controller_stopping_complete_io_handler \ scif_sas_controller_ready_complete_io_handler #define scif_sas_controller_stopping_complete_task_handler \ scif_sas_controller_ready_complete_task_handler #define scif_sas_controller_default_start_high_priority_io_handler \ scif_sas_controller_default_start_io_handler #define scif_sas_controller_default_complete_high_priority_io_handler \ scif_sas_controller_default_complete_io_handler #define scif_sas_controller_stopping_complete_high_priority_io_handler \ scif_sas_controller_ready_complete_high_priority_io_handler SCI_BASE_CONTROLLER_STATE_HANDLER_T scif_sas_controller_state_handler_table[SCI_BASE_CONTROLLER_MAX_STATES] = { // SCI_BASE_CONTROLLER_STATE_INITIAL { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_RESET { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_reset_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_INITIALIZING { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_INITIALIZED { scif_sas_controller_initialized_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_STARTING { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_READY { scif_sas_controller_default_start_handler, scif_sas_controller_ready_stop_handler, scif_sas_controller_ready_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_ready_start_io_handler, scif_sas_controller_ready_start_high_priority_io_handler, scif_sas_controller_ready_complete_io_handler, scif_sas_controller_ready_complete_high_priority_io_handler, scif_sas_controller_ready_continue_io_handler, scif_sas_controller_ready_start_task_handler, scif_sas_controller_ready_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_RESETTING { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_STOPPING { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_default_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_stopping_start_high_priority_io_handler, scif_sas_controller_stopping_complete_io_handler, scif_sas_controller_stopping_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, /**@todo Allow in core?*/ scif_sas_controller_stopping_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_STOPPED { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_stopped_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_default_start_io_handler, scif_sas_controller_default_start_high_priority_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler }, // SCI_BASE_CONTROLLER_STATE_FAILED { scif_sas_controller_default_start_handler, scif_sas_controller_default_stop_handler, scif_sas_controller_failed_reset_handler, scif_sas_controller_default_initialize_handler, scif_sas_controller_failed_state_start_io_handler, scif_sas_controller_failed_state_start_io_handler, scif_sas_controller_default_complete_io_handler, scif_sas_controller_default_complete_high_priority_io_handler, scif_sas_controller_default_continue_io_handler, scif_sas_controller_default_start_task_handler, scif_sas_controller_default_complete_task_handler } }; Index: head/sys/dev/isci/scil/scif_sas_io_request.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_io_request.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_io_request.c (revision 231296) @@ -1,820 +1,820 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the implementation of the SCIF_SAS_IO_REQUEST * object. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * @brief This method represents common functionality for the * scif_io_request_construct() and scif_sas_io_request_continue() * methods. * * @return This method returns an indication as to whether the * construction succeeded. */ static SCI_STATUS scif_sas_io_request_construct( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_IO_REQUEST_T * fw_io, U16 io_tag, void * user_io_request_object, SCI_IO_REQUEST_HANDLE_T * scif_io_request, BOOL is_initial_construction ) { SCI_STATUS status; SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols); //Currently, all the io requests sent to smp target are internal. //so we fail all the external io toward to it. //Todo: is there a better way to handle external io to smp target? if (dev_protocols.u.bits.attached_smp_target) return SCI_FAILURE_INVALID_REMOTE_DEVICE; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_io_request_construct(0x%x,0x%x,0x%x,0x%x,0x%x,0x%x) enter\n", fw_device, fw_io, io_tag, user_io_request_object, scif_io_request, is_initial_construction )); // Initialize the users handle to the framework IO request. *scif_io_request = fw_io; // Construct the parent object first in order to ensure logging can // function. scif_sas_request_construct( &fw_io->parent, fw_device, sci_base_object_get_logger(fw_device), scif_sas_io_request_state_table ); status = scic_io_request_construct( fw_device->domain->controller->core_object, fw_device->core_object, io_tag, fw_io, ((U8 *)fw_io) + sizeof(SCIF_SAS_IO_REQUEST_T), &fw_io->parent.core_object ); if (status == SCI_SUCCESS) { // These associations must be set early for the core io request // object construction to complete correctly as there will be // callbacks into the user driver framework during core construction sci_object_set_association(fw_io, user_io_request_object); sci_object_set_association(fw_io->parent.core_object, fw_io); // Perform protocol specific core IO request construction. if (dev_protocols.u.bits.attached_ssp_target) status = scic_io_request_construct_basic_ssp(fw_io->parent.core_object); else if (dev_protocols.u.bits.attached_stp_target) { if (is_initial_construction == TRUE) sati_sequence_construct(&fw_io->parent.stp.sequence); #if !defined(DISABLE_ATAPI) if (!scic_remote_device_is_atapi(fw_device->core_object)) { #endif status = scif_sas_stp_io_request_construct(fw_io); #if !defined(DISABLE_ATAPI) } else status = scif_sas_stp_packet_io_request_construct(fw_io); #endif } sci_base_state_machine_logger_initialize( &fw_io->parent.parent.state_machine_logger, &fw_io->parent.parent.state_machine, &fw_io->parent.parent.parent, scif_cb_logger_log_states, "SCIF_IO_REQUEST_T", "base_state_machine", SCIF_LOG_OBJECT_IO_REQUEST ); } return status; } //****************************************************************************** //* P U B L I C M E T H O D S //****************************************************************************** U32 scif_io_request_get_object_size( void ) { return (sizeof(SCIF_SAS_IO_REQUEST_T) + scic_io_request_get_object_size()); } // ---------------------------------------------------------------------------- U32 scif_io_request_get_number_of_bytes_transferred( SCI_IO_REQUEST_HANDLE_T scif_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_request = (SCIF_SAS_IO_REQUEST_T*) scif_io_request; if(scic_io_request_get_protocol(scif_io_request_get_scic_handle(scif_io_request)) == SCIC_STP_PROTOCOL) { U16 sati_data_bytes_set = sati_get_number_data_bytes_set(&(fw_request->parent.stp.sequence)); if (sati_data_bytes_set != 0) return sati_data_bytes_set; else { #if !defined(DISABLE_ATAPI) U8 sat_protocol = fw_request->parent.stp.sequence.protocol; if ( sat_protocol & SAT_PROTOCOL_PACKET) return scif_sas_stp_packet_io_request_get_number_of_bytes_transferred(fw_request); else #endif return scic_io_request_get_number_of_bytes_transferred( scif_io_request_get_scic_handle(scif_io_request)); } } else { return scic_io_request_get_number_of_bytes_transferred( scif_io_request_get_scic_handle(scif_io_request)); } } // --------------------------------------------------------------------------- SCI_STATUS scif_io_request_construct( SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device, U16 io_tag, void * user_io_request_object, void * io_request_memory, SCI_IO_REQUEST_HANDLE_T * scif_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request_memory; SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) scif_remote_device; return scif_sas_io_request_construct( fw_device, fw_io, io_tag, user_io_request_object, scif_io_request, TRUE ); } // --------------------------------------------------------------------------- SCI_STATUS scif_request_construct( SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device, U16 io_tag, void * user_io_request_object, void * io_request_memory, SCI_IO_REQUEST_HANDLE_T * scif_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request_memory; SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) scif_remote_device; SCI_STATUS status; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_IO_REQUEST, "scif_io_request_construct(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n", scif_controller, scif_remote_device, io_tag, user_io_request_object, io_request_memory, scif_io_request )); // Step 1: Create the scif io request. // Initialize the users handle to the framework IO request. *scif_io_request = fw_io; // Construct the parent object first in order to ensure logging can // function. scif_sas_request_construct( &fw_io->parent, fw_device, sci_base_object_get_logger(fw_device), scif_sas_io_request_state_table ); status = scic_io_request_construct( (void *) ((SCIF_SAS_CONTROLLER_T *)scif_controller)->core_object, (void *) fw_device->core_object, io_tag, fw_io, (U8 *)io_request_memory + sizeof(SCIF_SAS_IO_REQUEST_T), &fw_io->parent.core_object ); if (status == SCI_SUCCESS) { // These associations must be set early for the core io request // object construction to complete correctly as there will be // callbacks into the user driver framework during core construction sci_object_set_association(fw_io, user_io_request_object); sci_object_set_association(fw_io->parent.core_object, fw_io); sci_base_state_machine_logger_initialize( &fw_io->parent.parent.state_machine_logger, &fw_io->parent.parent.state_machine, &fw_io->parent.parent.parent, scif_cb_logger_log_states, "SCIF_IO_REQUEST_T", "base_state_machine", SCIF_LOG_OBJECT_IO_REQUEST ); } return status; } // ---------------------------------------------------------------------------- SCI_STATUS scif_io_request_construct_with_core ( SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T scif_remote_device, void * scic_io_request, void * user_io_request_object, void * io_request_memory, SCI_IO_REQUEST_HANDLE_T * scif_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) io_request_memory; SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) scif_remote_device; SCI_STATUS status = SCI_SUCCESS; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_IO_REQUEST, "scif_io_request_construct_pass_through(0x%x, 0x%x, 0x%x, 0x%x) enter\n", scif_remote_device, user_io_request_object, io_request_memory, scif_io_request )); // Initialize the users handle to the framework IO request. *scif_io_request = fw_io; // Construct the parent object first in order to ensure logging can // function. scif_sas_request_construct( &fw_io->parent, fw_device, sci_base_object_get_logger(fw_device), scif_sas_io_request_state_table ); fw_io->parent.core_object = scic_io_request; //set association sci_object_set_association(fw_io, user_io_request_object); sci_object_set_association(fw_io->parent.core_object, fw_io); sci_base_state_machine_logger_initialize( &fw_io->parent.parent.state_machine_logger, &fw_io->parent.parent.state_machine, &fw_io->parent.parent.parent, scif_cb_logger_log_states, "SCIF_IO_REQUEST_T", "base_state_machine", SCIF_LOG_OBJECT_IO_REQUEST ); return status; } // --------------------------------------------------------------------------- void * scif_io_request_get_response_iu_address( SCI_IO_REQUEST_HANDLE_T scif_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)scif_io_request; return (scic_io_request_get_response_iu_address(fw_io->parent.core_object )); } // --------------------------------------------------------------------------- SCI_IO_REQUEST_HANDLE_T scif_io_request_get_scic_handle( SCI_IO_REQUEST_HANDLE_T scif_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scif_io_request; return fw_io->parent.core_object; } // --------------------------------------------------------------------------- void scic_cb_io_request_complete( SCI_CONTROLLER_HANDLE_T controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_IO_REQUEST_HANDLE_T io_request, SCI_IO_STATUS completion_status ) { SCI_STATUS status; SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) sci_object_get_association(controller); SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) sci_object_get_association(remote_device); SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) sci_object_get_association(io_request); SCIF_LOG_TRACE(( sci_base_object_get_logger(controller), SCIF_LOG_OBJECT_IO_REQUEST, "scic_cb_io_request_complete(0x%x, 0x%x, 0x%x, 0x%x) enter\n", controller, remote_device, io_request, completion_status )); // Invoke the common completion handler routine. // A non-successful return indicates we are not in a correct state to // receive a completion notification for this request. status = fw_request->state_handlers->complete_handler(&fw_request->parent); // If the status indicates the completion handler was successful, then // allow protocol specific completion processing to occur. if (status == SCI_SUCCESS) { if (fw_request->protocol_complete_handler != NULL) { status = fw_request->protocol_complete_handler( fw_controller, fw_device, fw_request, (SCI_STATUS *)&completion_status ); } // If this isn't an internal framework IO request, then simply pass the // notification up to the SCIF user. if ( status == SCI_SUCCESS ) { if (fw_request->is_high_priority == FALSE) { if (fw_request->is_waiting_for_abort_task_set == FALSE) { scif_cb_io_request_complete( fw_controller, fw_device, fw_request, completion_status); } else { // do nothing - will complete the I/O when the abort task // set completes } } else scif_sas_controller_complete_high_priority_io( fw_controller, fw_device, fw_request); } else if ( status == SCI_WARNING_SEQUENCE_INCOMPLETE ) { scif_sas_io_request_continue(fw_controller, fw_device, fw_request); } } } // --------------------------------------------------------------------------- U32 scic_cb_io_request_get_transfer_length( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return (scif_cb_io_request_get_transfer_length( fw_io->parent.parent.parent.associated_object )); } // --------------------------------------------------------------------------- SCI_IO_REQUEST_DATA_DIRECTION scic_cb_io_request_get_data_direction( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return (scif_cb_io_request_get_data_direction( fw_io->parent.parent.parent.associated_object )); } // --------------------------------------------------------------------------- #ifndef SCI_SGL_OPTIMIZATION_ENABLED void scic_cb_io_request_get_next_sge( void * scic_user_io_request, void * current_sge_address, void **next_sge ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; scif_cb_io_request_get_next_sge( fw_io->parent.parent.parent.associated_object, current_sge_address, next_sge ); } #endif // --------------------------------------------------------------------------- SCI_PHYSICAL_ADDRESS scic_cb_sge_get_address_field( void * scic_user_io_request, void * sge_address ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_sge_get_address_field( fw_io->parent.parent.parent.associated_object, sge_address ); } // --------------------------------------------------------------------------- U32 scic_cb_sge_get_length_field( void * scic_user_io_request, void * sge_address ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_sge_get_length_field( fw_io->parent.parent.parent.associated_object, sge_address ); } // --------------------------------------------------------------------------- void * scic_cb_ssp_io_request_get_cdb_address( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_io_request_get_cdb_address( fw_io->parent.parent.parent.associated_object ); } // --------------------------------------------------------------------------- U32 scic_cb_ssp_io_request_get_cdb_length( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_io_request_get_cdb_length( fw_io->parent.parent.parent.associated_object ); } // --------------------------------------------------------------------------- #if !defined(DISABLE_ATAPI) void * scic_cb_stp_packet_io_request_get_cdb_address( void * scic_user_io_request ) { SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*)scic_user_io_request; SATI_TRANSLATOR_SEQUENCE_T * sati_sequence = &fw_request->stp.sequence; if (sati_sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE) return scif_cb_io_request_get_cdb_address( fw_request->parent.parent.associated_object ); else return &(sati_sequence->command_specific_data.sati_atapi_data.request_sense_cdb); } #endif // --------------------------------------------------------------------------- #if !defined(DISABLE_ATAPI) U32 scic_cb_stp_packet_io_request_get_cdb_length( void * scic_user_io_request ) { SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) scic_user_io_request; SATI_TRANSLATOR_SEQUENCE_T * sati_sequence = &fw_request->stp.sequence; if (sati_sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE) return scif_cb_io_request_get_cdb_length( fw_request->parent.parent.associated_object ); else return SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH; } #endif // --------------------------------------------------------------------------- U32 scic_cb_ssp_io_request_get_lun( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_io_request_get_lun( fw_io->parent.parent.parent.associated_object ); } // --------------------------------------------------------------------------- U32 scic_cb_ssp_io_request_get_task_attribute( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_io_request_get_task_attribute( fw_io->parent.parent.parent.associated_object ); } // --------------------------------------------------------------------------- U32 scic_cb_ssp_io_request_get_command_priority( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return scif_cb_io_request_get_command_priority( fw_io->parent.parent.parent.associated_object ); } // --------------------------------------------------------------------------- BOOL scic_cb_request_is_initial_construction( void * scic_user_io_request ) { SCIF_SAS_REQUEST_T * fw_request = (SCIF_SAS_REQUEST_T*) scic_user_io_request; SCIF_SAS_REMOTE_DEVICE_T* fw_device = fw_request->device; SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols); if (dev_protocols.u.bits.attached_stp_target && fw_request->stp.sequence.state == SATI_SEQUENCE_STATE_INCOMPLETE) return FALSE; return TRUE; } //****************************************************************************** //* P R O T E C T E D M E T H O D S //****************************************************************************** /** * @brief This method constructs an scif sas smp request. * * @param[in] fw_controller The framework controller * @param[in] fw_device The smp device that the smp request targets to. * @param[in] fw_io_memory The memory space for the smp request. * @param[in] core_io_memory The memory space for the core request. * @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_io_request_construct_smp( SCIF_SAS_CONTROLLER_T * fw_controller, SCIF_SAS_REMOTE_DEVICE_T * fw_device, void * fw_io_memory, void * core_io_memory, U16 io_tag, SMP_REQUEST_T * smp_command, void * user_request_object ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*)fw_io_memory; SCI_STATUS status = SCI_SUCCESS; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_io_request_construct_smp(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) enter\n", fw_controller, fw_device, fw_io_memory, core_io_memory, io_tag, smp_command, user_request_object )); // Construct the parent object first in order to ensure logging can // function. scif_sas_request_construct( &fw_io->parent, fw_device, sci_base_object_get_logger(fw_controller), scif_sas_io_request_state_table ); status = scic_io_request_construct( fw_device->domain->controller->core_object, fw_device->core_object, io_tag, (void*)fw_io, (U8 *)core_io_memory, &fw_io->parent.core_object ); if (status == SCI_SUCCESS) { //set object association. sci_object_set_association(fw_io, user_request_object); sci_object_set_association(fw_io->parent.core_object, fw_io); scif_sas_smp_request_construct(&fw_io->parent, smp_command); fw_io->parent.is_high_priority = TRUE; sci_base_state_machine_logger_initialize( &fw_io->parent.parent.state_machine_logger, &fw_io->parent.parent.state_machine, &fw_io->parent.parent.parent, scif_cb_logger_log_states, "SCIF_IO_REQUEST_T", "base_state_machine", SCIF_LOG_OBJECT_IO_REQUEST ); } return status; } /** * @brief This method continues a scif sas request. * * @param[in] fw_controller The framework controller * @param[in] fw_device The device that the IO request targets to. * @param[in] fw_request The IO request to be continued. * * @return Indicate if the internal io was successfully constructed. * @retval SCI_SUCCESS This value is returned if the internal io was * successfully continued. * @retval SCI_FAILURE This value is returned if the io was failed to * be continued. */ SCI_STATUS scif_sas_io_request_continue( SCIF_SAS_CONTROLLER_T * fw_controller, SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request ) { SCI_IO_REQUEST_HANDLE_T dummy_handle; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_request), SCIF_LOG_OBJECT_IO_REQUEST, "scif_sas_io_request_continue(0x%x, 0x%x, 0x%x) enter\n", fw_controller, fw_device, fw_request )); //complete this io request in framework and core. scif_controller_complete_io(fw_controller, fw_device, fw_request); //construct next command in the sequence using the same memory. We pass //a dummy pointer to let the framework user keep the pointer to this IO //request untouched. scif_sas_io_request_construct( fw_device, (SCIF_SAS_IO_REQUEST_T*)fw_request, SCI_CONTROLLER_INVALID_IO_TAG, (void *)sci_object_get_association(fw_request), &dummy_handle, FALSE ); //start the new constructed IO. - return scif_controller_start_io( + return (SCI_STATUS)scif_controller_start_io( (SCI_CONTROLLER_HANDLE_T) fw_controller, (SCI_REMOTE_DEVICE_HANDLE_T) fw_device, (SCI_IO_REQUEST_HANDLE_T) fw_request, SCI_CONTROLLER_INVALID_IO_TAG ); } Index: head/sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_remote_device_ready_substates.c (revision 231296) @@ -1,290 +1,290 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the entrance and exit methods for the ready * sub-state machine states (OPERATIONAL, TASK_MGMT). */ #include #include #include #include #include #include //****************************************************************************** //* P R O T E C T E D M E T H O D S //****************************************************************************** /** * @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 implements the actions taken when exiting the * READY OPERATIONAL substate. This method issues a * scif_cb_remote_device_not_ready() notification to the framework * 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_exit( SCI_BASE_OBJECT_T *object ) { SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; // Notify the user that the device has become ready. scif_cb_remote_device_not_ready( fw_device->domain->controller, fw_device->domain, fw_device ); } /** * @brief This method implements the actions taken when entering the * READY SUSPENDED substate. This includes setting the state * handler methods. * * @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_suspended_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_SUSPENDED ); } /** * @brief This method implements the actions taken when entering the * READY TASK MGMT substate. This includes setting the state * handler methods. * * @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_taskmgmt_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_TASK_MGMT ); } /** * @brief This method implements the actions taken when entering the * READY NCQ ERROR substate. This includes setting the state * handler methods. * * @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_ncq_error_substate_enter( SCI_BASE_OBJECT_T *object ) { SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; SCI_STATUS status = SCI_SUCCESS; SCI_TASK_REQUEST_HANDLE_T handle; SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; SCIF_SAS_TASK_REQUEST_T * fw_task_request; SCIF_SAS_REQUEST_T * fw_request; void * internal_task_memory; SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCI_FAST_LIST_ELEMENT_T * pending_request_element; SCIF_SAS_REQUEST_T * pending_request = NULL; SET_STATE_HANDLER( fw_device, scif_sas_remote_device_ready_substate_handler_table, SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR ); internal_task_memory = scif_sas_controller_allocate_internal_request(fw_controller); ASSERT(internal_task_memory != NULL); fw_task_request = (SCIF_SAS_TASK_REQUEST_T*)internal_task_memory; fw_request = &fw_task_request->parent; //construct the scif io request status = scif_sas_internal_task_request_construct( fw_controller, fw_device, SCI_CONTROLLER_INVALID_IO_TAG, (void *)fw_task_request, &handle, SCI_SAS_ABORT_TASK_SET ); pending_request_element = fw_domain->request_list.list_head; // Cycle through the fast list of IO requests. Mark each request // pending to this remote device so that they are not completed // to the operating system when the request is terminated, but // rather when the abort task set completes. while (pending_request_element != NULL) { pending_request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(pending_request_element); // The current element may be deleted from the list becasue of // IO completion so advance to the next element early pending_request_element = sci_fast_list_get_next(pending_request_element); if (pending_request->device == fw_device) { pending_request->is_waiting_for_abort_task_set = TRUE; } } - status = scif_controller_start_task( + scif_controller_start_task( fw_controller, fw_device, fw_request, SCI_CONTROLLER_INVALID_IO_TAG ); } SCI_BASE_STATE_T scif_sas_remote_device_ready_substate_table [SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_MAX_STATES] = { { SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_OPERATIONAL, scif_sas_remote_device_ready_operational_substate_enter, scif_sas_remote_device_ready_operational_substate_exit }, { SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_SUSPENDED, scif_sas_remote_device_ready_suspended_substate_enter, NULL }, { SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_TASK_MGMT, scif_sas_remote_device_ready_taskmgmt_substate_enter, NULL }, { SCIF_SAS_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR, scif_sas_remote_device_ready_ncq_error_substate_enter, NULL } }; Index: head/sys/dev/isci/scil/scif_sas_smp_remote_device.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_smp_remote_device.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_smp_remote_device.c (revision 231296) @@ -1,2624 +1,2624 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the methods for the SCIF_SAS_SMP_REMOTE_DEVICE object. */ #include #include #include #include #include #include #include #include #include #include /** * @brief This method resets all fields for a smp remote device. This is a * private method. * * @param[in] fw_device the framework SMP device that is being * constructed. * * @return none */ void scif_sas_smp_remote_device_clear( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { //reset all fields in smp_device, indicate that the smp device is not //in discovery process. fw_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; fw_device->protocol_device.smp_device.current_smp_request = NOT_IN_SMP_ACTIVITY; fw_device->protocol_device.smp_device.current_activity_phy_index = 0; fw_device->protocol_device.smp_device.curr_config_route_index = 0; fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL; fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE; fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL; fw_device->protocol_device.smp_device.scheduled_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; fw_device->protocol_device.smp_device.io_retry_count = 0; fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL; if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL) { //stop the timer scif_cb_timer_stop( fw_device->domain->controller, fw_device->protocol_device.smp_device.smp_activity_timer ); //destroy the timer scif_cb_timer_destroy( fw_device->domain->controller, fw_device->protocol_device.smp_device.smp_activity_timer ); fw_device->protocol_device.smp_device.smp_activity_timer = NULL; } } /** * @brief This method intializes a smp remote device. * * @param[in] fw_device the framework SMP device that is being * constructed. * * @return none */ void scif_sas_smp_remote_device_construct( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE, "scif_sas_smp_remote_device_construct(0x%x) enter\n", fw_device )); fw_device->protocol_device.smp_device.number_of_phys = 0; fw_device->protocol_device.smp_device.expander_route_indexes = 0; fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE; fw_device->protocol_device.smp_device.is_externally_configurable = FALSE; fw_device->protocol_device.smp_device.is_able_to_config_others = FALSE; sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list); scif_sas_smp_remote_device_clear(fw_device); } /** * @brief This method decodes a smp response to this smp device and then * continue the smp discover process. * * @param[in] fw_device The framework device that a SMP response targets to. * @param[in] fw_request The pointer to an smp request whose response * is to be decoded. * @param[in] response_data The response data passed in. * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_smp_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request, void * response_data, SCI_IO_STATUS completion_status ) { SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data; SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE; if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL) { //if there is a timer being used, recycle it now. Since we may //use the timer for other purpose next. scif_cb_timer_destroy( fw_device->domain->controller, fw_device->protocol_device.smp_device.smp_activity_timer ); fw_device->protocol_device.smp_device.smp_activity_timer = NULL; } //if Core set the status of this io to be RETRY_REQUIRED, we should //retry the IO without even decode the response. if (completion_status == SCI_FAILURE_RETRY_REQUIRED) { scif_sas_smp_remote_device_continue_current_activity( fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED ); return SCI_FAILURE_RETRY_REQUIRED; } //check the current smp request, decide what's next smp request to issue. switch (fw_device->protocol_device.smp_device.current_smp_request) { case SMP_FUNCTION_REPORT_GENERAL: { //interpret REPORT GENERAL response. status = scif_sas_smp_remote_device_decode_report_general_response( fw_device, smp_response ); break; } case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: { // No need to perform any parsing. Just want to see // the information in a trace if necessary. status = SCI_SUCCESS; break; } case SMP_FUNCTION_DISCOVER: { if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) { //decode discover response status = scif_sas_smp_remote_device_decode_initial_discover_response( fw_device, smp_response ); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) { //decode discover response as a polling result for a remote device //target reset. status = scif_sas_smp_remote_device_decode_target_reset_discover_response( fw_device, smp_response ); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE) { //decode discover response status = scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response( fw_device, smp_response ); } else ASSERT(0); break; } case SMP_FUNCTION_REPORT_PHY_SATA: { //decode the report phy sata response. status = scif_sas_smp_remote_device_decode_report_phy_sata_response( fw_device, smp_response ); break; } case SMP_FUNCTION_PHY_CONTROL: { if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) { //decode the phy control response. status = scif_sas_smp_remote_device_decode_discover_phy_control_response( fw_device, smp_response ); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) { //decode discover response as a polling result for a remote device //target reset. status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response( fw_device, smp_response ); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION) { //currently don't care about the status. status = SCI_SUCCESS; } else ASSERT(0); break; } case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION: { //Note, currently we don't expect any abnormal status from config route info response, //but there is a possibility that we exceed the maximum route index. We will take care //of errors later. status = scif_sas_smp_remote_device_decode_config_route_info_response( fw_device, smp_response ); break; } default: //unsupported case, TBD status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE; break; } //end of switch //Continue current activity based on response's decoding status. scif_sas_smp_remote_device_continue_current_activity( fw_device, fw_request, status ); return status; } /** * @brief This method decodes a smp Report Genernal response to this smp device * and then continue the smp discover process. * * @param[in] fw_device The framework device that the REPORT GENERAL command * targets to. * @param[in] report_general_response The pointer to a report general response * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SMP_RESPONSE_REPORT_GENERAL_T * report_general_response = &smp_response->response.report_general; SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Report General function result(0x%x)\n", response_header->function_result )); return SCI_FAILURE; } //get info from report general response. fw_device->protocol_device.smp_device.number_of_phys = (U8)report_general_response->number_of_phys; //currently there is byte swap issue in U16 data. fw_device->protocol_device.smp_device.expander_route_indexes = ((report_general_response->expander_route_indexes & 0xff) << 8) | ((report_general_response->expander_route_indexes & 0xff00) >> 8); fw_device->protocol_device.smp_device.is_table_to_table_supported = (BOOL)report_general_response->table_to_table_supported; fw_device->protocol_device.smp_device.is_externally_configurable = (BOOL)report_general_response->configurable_route_table; fw_device->protocol_device.smp_device.is_able_to_config_others = (BOOL)report_general_response->configures_others; //If the top level expander of a domain is able to configure others, //no config route table is needed in the domain. Or else, //we'll let all the externally configurable expanders in the damain //configure route table. if (fw_device->containing_device == NULL && ! fw_device->protocol_device.smp_device.is_able_to_config_others) fw_device->domain->is_config_route_table_needed = TRUE; //knowing number of phys this expander has, we can allocate all the smp phys for //this expander now if it is not done already. if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0) scif_sas_smp_remote_device_populate_smp_phy_list(fw_device); if (report_general_response->configuring) return SCI_FAILURE_RETRY_REQUIRED; return SCI_SUCCESS; } /** * @brief This method decodes a smp Discover response to this smp device * and then continue the smp discover process. This is only ever * called for the very first discover stage during a given domain * discovery process. * * @param[in] fw_device The framework device that the DISCOVER command * targets to. * @param[in] discover_response The pointer to a DISCOVER response * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCI_SAS_ADDRESS_T attached_device_address; SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device; SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover; SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result == SMP_RESULT_PHY_VACANT) { return SCI_SUCCESS; } else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Discover function result(0x%x)\n", response_header->function_result )); return SCI_FAILURE; } //only if there is target device attached. We don't add device that is //initiator only. if ( ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) && ( discover_response->protocols.u.bits.attached_ssp_target || discover_response->protocols.u.bits.attached_stp_target || discover_response->protocols.u.bits.attached_smp_target || discover_response->protocols.u.bits.attached_sata_device ) ) { attached_device_address = discover_response->attached_sas_address; attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *) scif_domain_get_device_by_sas_address( fw_domain, &attached_device_address ); //need to check if the device already existed in the domian. if (attached_remote_device != SCI_INVALID_HANDLE) { #if !defined(DISABLE_WIDE_PORTED_TARGETS) if ( attached_remote_device->is_currently_discovered == TRUE && attached_remote_device != fw_device->containing_device ) { //a downstream wide port target is found. attached_remote_device->device_port_width++; } else #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) { //The device already existed. Mark the device as discovered. attached_remote_device->is_currently_discovered = TRUE; } #if !defined(DISABLE_WIDE_PORTED_TARGETS) if (attached_remote_device->device_port_width != scic_remote_device_get_port_width(attached_remote_device->core_object) && discover_response->protocols.u.bits.attached_ssp_target ) { scif_sas_remote_device_update_port_width( attached_remote_device, attached_remote_device->device_port_width); } #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) if ( discover_response->protocols.u.bits.attached_smp_target && attached_remote_device != fw_device->containing_device) { //another expander device is discovered. Its own smp discover will starts after //this discover finishes. attached_remote_device->protocol_device.smp_device.scheduled_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER; } } else { //report the discovery of a disk for all types of end device. scif_cb_domain_ea_device_added( fw_domain->controller, fw_domain, fw_device, discover_response ); //get info from discover response to see what we found. And do //extra work according to end device's protocol type. if ( discover_response->protocols.u.bits.attached_ssp_target || discover_response->protocols.u.bits.attached_smp_target) { //for SSP or SMP target, no extra work. ; } else if ( (discover_response->protocols.u.bits.attached_stp_target) || (discover_response->protocols.u.bits.attached_sata_device) ) { // We treat a SATA Device bit the same as an attached STP // target. discover_response->protocols.u.bits.attached_stp_target = 1; //kick off REPORT PHY SATA to the same phy. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_REPORT_PHY_SATA; } } } else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD || discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD) &&(discover_response->protocols.u.bits.attached_stp_target || discover_response->protocols.u.bits.attached_sata_device) ) { attached_remote_device = scif_sas_domain_get_device_by_containing_device( fw_domain, fw_device, discover_response->phy_identifier ); if (attached_remote_device != SCI_INVALID_HANDLE) { //Here, the only reason a device already existed in domain but //the initial discover rersponse shows it in SPINUP_HOLD, is that //a device has been removed and coming back in SPINUP_HOLD before //we detected. The possibility of this situation is very very rare. //we need to remove the device then add it back using the new //discover response. scif_cb_domain_device_removed( fw_domain->controller, fw_domain, attached_remote_device ); } discover_response->protocols.u.bits.attached_stp_target = 1; //still report ea_device_added(). But this device will not be //started during scif_remote_device_ea_construct(). scif_cb_domain_ea_device_added( fw_domain->controller, fw_domain, fw_device, discover_response ); //need to send Phy Control (RESET) to release the phy from spinup hold //condition. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_PHY_CONTROL; } //update the smp phy info based on this DISCOVER response. return scif_sas_smp_remote_device_save_smp_phy_info( fw_device, discover_response); } /** * @brief This method decodes a smp Report Phy Sata response to this * smp device and then continue the smp discover process. * * @param[in] fw_device The framework device that the REPORT PHY SATA * command targets to. * @param[in] report_phy_sata_response The pointer to a REPORT PHY * SATA response * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response = &smp_response->response.report_phy_sata; SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Report Phy Sata function result(0x%x)\n", response_header->function_result )); return SCI_FAILURE; } scif_sas_remote_device_save_report_phy_sata_information( report_phy_sata_response ); // continue the discover process. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_DISCOVER; return SCI_SUCCESS; } /** * @brief This method decodes a smp Phy Control response to this smp device and * then continue the smp TARGET RESET process. * * @param[in] fw_device The framework device that the Phy Control command * targets to. * @param[in] smp_response The pointer to a Phy Control response * @param[in] fw_io The scif IO request that associates to this smp response. * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCI_STATUS status = SCI_SUCCESS; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Phy Control function unaccepted result(0x%x)\n", response_header->function_result )); status = SCI_FAILURE_RETRY_REQUIRED; } // phy Control succeeded. return status; } /** * @brief This method decodes a smp Phy Control response to this smp device and * then continue the smp DISCOVER process. * * @param[in] fw_device The framework device that the Phy Control command * targets to. * @param[in] smp_response The pointer to a Phy Control response * * @return Almost always SCI_SUCCESS */ SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCI_STATUS status = SCI_SUCCESS; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Phy Control function unaccepted result(0x%x)\n", response_header->function_result )); return SCI_FAILURE_RETRY_REQUIRED; } // continue the discover process. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_DISCOVER; // phy Control succeeded. return status; } /** * @brief This method decodes a smp Discover response to this smp device * and then continue the smp discover process. * * @param[in] fw_device The framework device that the DISCOVER command * targets to. * @param[in] discover_response The pointer to a DISCOVER response * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SCIF_SAS_DOMAIN_T * fw_domain; SCI_SAS_ADDRESS_T attached_device_address; SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover; SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Discover function result(0x%x)\n", response_header->function_result )); return SCI_FAILURE_RETRY_REQUIRED; } //only if there is device attached. if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) { fw_domain = fw_device->domain; attached_device_address = discover_response->attached_sas_address; // the device should have already existed in the domian. ASSERT(scif_domain_get_device_by_sas_address( fw_domain, &attached_device_address ) != SCI_INVALID_HANDLE); return SCI_SUCCESS; } else return SCI_FAILURE_RETRY_REQUIRED; } /** * @brief This method decodes a smp Discover response to this smp device * for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says * SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's * start_handler(). But if a DISCOVER response still shows SPINUP * in NPL state, we need to return retry_required status * * @param[in] fw_device The framework device that the DISCOVER command * targets to. * @param[in] discover_response The pointer to a DISCOVER response * * @return SCI_SUCCESS * SCI_FAILURE_RETRY_REQUIRED */ SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover; SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Discover function result(0x%x)\n", response_header->function_result )); return SCI_FAILURE; } if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) { if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD && ( discover_response->protocols.u.bits.attached_stp_target ||discover_response->protocols.u.bits.attached_sata_device ) ) { SCIF_SAS_REMOTE_DEVICE_T * target_device = scif_sas_domain_get_device_by_containing_device( fw_device->domain, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index ); //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD. scic_remote_device_set_max_connection_rate( target_device->core_object, discover_response->u2.sas1_1.negotiated_physical_link_rate ); //Need to update the smp phy info too. scif_sas_smp_remote_device_save_smp_phy_info( fw_device, discover_response); //This device has already constructed, only need to call start_handler //of this device here. return target_device->state_handlers->parent.start_handler( &target_device->parent ); } else return SCI_FAILURE_RETRY_REQUIRED; } else return SCI_FAILURE_RETRY_REQUIRED; } /** * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp * device and then continue to config route table. * * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command * targets to. * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response * * @return none */ SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_T * smp_response ) { SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n", fw_device, smp_response )); if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST) { //case of exceeding max route index. We need to remove the devices that are not //able to be edit to route table. The destination config route smp phy //is used to remove devices. scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device); return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX; } else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) { /// @todo: more decoding work needed when the function_result is not /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some /// function result. SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "Discover function result(0x%x)\n", response_header->function_result )); return SCI_FAILURE; } return SCI_SUCCESS; } /** * @brief This method starts the smp Discover process for an expander by * sending Report General request. * * @param[in] fw_device The framework smp device that a command * targets to. * * @return none */ void scif_sas_smp_remote_device_start_discover( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_start_discover(0x%x) enter\n", fw_device )); //For safety, clear the device again, there may be some config route table //related info are not cleared yet. scif_sas_smp_remote_device_clear(fw_device); //set current activity fw_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER; //Set current_smp_request to REPORT GENERAL. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_REPORT_GENERAL; //reset discover_to_start flag. fw_device->protocol_device.smp_device.scheduled_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; //build the first smp request Report Genernal. scif_sas_smp_request_construct_report_general(fw_controller, fw_device); //issue DPC to start this request. scif_cb_start_internal_io_task_schedule( fw_controller, scif_sas_controller_start_high_priority_io, fw_controller ); } /** * @brief This method continues the smp Discover process. * * @param[in] fw_device The framework smp device that a DISCOVER command * targets to. * @param[in] fw_request The pointer to an smp request whose response * has been decoded. * @param[in] status The decoding status of the smp request's response * * @return none */ void scif_sas_smp_remote_device_continue_current_activity( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request, SCI_STATUS status ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request; // save the retry count. U8 io_retry_count = fw_io->retry_count; if (fw_request->is_internal) { // Complete this internal io request now. We want to free this io before // we create another SMP request, which is going to happen soon. scif_sas_internal_io_request_complete( fw_device->domain->controller, (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request, SCI_SUCCESS ); } if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) { if (status == SCI_SUCCESS) { //continue the discover process. scif_sas_smp_remote_device_continue_discover(fw_device); } else if (status == SCI_FAILURE_RETRY_REQUIRED) { //Retry the smp request. Since we are in the middle of Discover //process, all the smp requests are internal. A new smp request //will be created for retry. U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT; if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) scif_sas_smp_remote_device_retry_internal_io ( fw_device, io_retry_count, retry_wait_duration); else scif_sas_smp_remote_device_fail_discover(fw_device); } else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION) { //remove this expander device and its child devices. No need to //continue the discover on this device. scif_sas_domain_remove_expander_device(fw_device->domain, fw_device); //continue the domain's smp discover. scif_sas_domain_continue_discover(fw_device->domain); } else { //terminate the discover process. scif_sas_smp_remote_device_fail_discover(fw_device); } } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) { if (status == SCI_SUCCESS) { //continue the target reset process. scif_sas_smp_remote_device_continue_target_reset( fw_device, fw_request); } else if (status == SCI_FAILURE_RETRY_REQUIRED) { //Retry the same smp request. Since we are in the middle of Target //reset process, all the smp requests are using external resource. //We will use the exactly same memory to retry. if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) { if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) { //create the timer to wait before retry. fw_device->protocol_device.smp_device.smp_activity_timer = scif_cb_timer_create( (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry, (void*)fw_request ); } else { ASSERT(0); } //start the timer to wait scif_cb_timer_start( (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, fw_device->protocol_device.smp_device.smp_activity_timer, SMP_REQUEST_RETRY_WAIT_DURATION //20 miliseconds ); } else scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request); } else //terminate the discover process. scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE) { SCIF_SAS_REMOTE_DEVICE_T * target_device = scif_sas_domain_get_device_by_containing_device( fw_device->domain, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index ); if (status == SCI_SUCCESS) { //move on to next round of SPINUP_HOLD_REALSE activity. scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device); } else if (status == SCI_FAILURE_RETRY_REQUIRED) { U32 delay = (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) / SCIF_SAS_IO_RETRY_LIMIT); //Retry the smp request. Since we are in the middle of Discover //process, all the smp requests are internal. A new smp request //will be created for retry. if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) { scif_sas_smp_remote_device_retry_internal_io( fw_device, io_retry_count, delay); } else //give up on this target device. { scif_sas_smp_remote_device_fail_target_spinup_hold_release( fw_device , target_device); } } else //give up on this target device. scif_sas_smp_remote_device_fail_target_spinup_hold_release( fw_device, target_device); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE) { SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next( &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) ); SCI_FAST_LIST_T * destination_smp_phy_list = fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list; SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL; if (next_phy_element != NULL && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX) { fw_device->protocol_device.smp_device.curr_config_route_index++; fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element); // Update the anchor for config route index. fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor = fw_device->protocol_device.smp_device.curr_config_route_index; scif_sas_smp_remote_device_configure_route_table(fw_device); } else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device) == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port( fw_device->protocol_device.smp_device.config_route_smp_phy_anchor) )!= NULL ) { //config the other phy in the same wide port fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = next_phy_in_wide_port; fw_device->protocol_device.smp_device.current_activity_phy_index = fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier; fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = sci_fast_list_get_head(destination_smp_phy_list); if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0) fw_device->protocol_device.smp_device.curr_config_route_index = fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1; else fw_device->protocol_device.smp_device.curr_config_route_index = 0; scif_sas_smp_remote_device_configure_route_table(fw_device); } else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE) { fw_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE; scif_sas_smp_remote_device_clean_route_table(fw_device); } else { //set this device's activity to NON. fw_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; //we need to notify domain that this device finished config route table, domain //may pick up other activities (i.e. Discover) for other expanders. scif_sas_domain_continue_discover(fw_device->domain); } } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE) { scif_sas_smp_remote_device_clean_route_table(fw_device); } else if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION) { scif_sas_smp_remote_device_continue_clear_affiliation(fw_device); } } /** * @brief This method continues the smp Discover process. * * @param[in] fw_device The framework smp device that a DISCOVER command * targets to. * * @return none */ void scif_sas_smp_remote_device_continue_discover( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n", fw_device )); switch (fw_device->protocol_device.smp_device.current_smp_request) { case SMP_FUNCTION_REPORT_GENERAL: // send the REPORT MANUFACTURER_INFO request fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION; scif_sas_smp_request_construct_report_manufacturer_info( fw_domain->controller, fw_device ); break; case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: //send the first SMP DISCOVER request. fw_device->protocol_device.smp_device.current_activity_phy_index = 0; fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_DISCOVER; scif_sas_smp_request_construct_discover( fw_domain->controller, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index, NULL, NULL ); break; case SMP_FUNCTION_DISCOVER: fw_device->protocol_device.smp_device.current_activity_phy_index++; if ( (fw_device->protocol_device.smp_device.current_activity_phy_index < fw_device->protocol_device.smp_device.number_of_phys) ) { scif_sas_smp_request_construct_discover( fw_domain->controller, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index, NULL, NULL ); } else scif_sas_smp_remote_device_finish_initial_discover(fw_device); break; case SMP_FUNCTION_REPORT_PHY_SATA: scif_sas_smp_request_construct_report_phy_sata( fw_device->domain->controller, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index ); break; case SMP_FUNCTION_PHY_CONTROL: scif_sas_smp_request_construct_phy_control( fw_device->domain->controller, fw_device, PHY_OPERATION_HARD_RESET, fw_device->protocol_device.smp_device.current_activity_phy_index, NULL, NULL ); break; default: break; } } /** * @brief This method finishes the initial smp DISCOVER process. There * may be a spinup_hold release phase following of initial discover, * depending on whether there are SATA device in the domain * in SATA_SPINUP_HOLD condition. * * @param[in] fw_device The framework smp device that finishes all the * DISCOVER requests. * * @return none */ void scif_sas_smp_remote_device_finish_initial_discover( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold = scif_sas_domain_find_device_in_spinup_hold(fw_device->domain); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n", fw_device )); if ( device_in_sata_spinup_hold != NULL ) { //call the common private routine to reset all fields of this smp device. scif_sas_smp_remote_device_clear(fw_device); //Move on to next activity SPINUP_HOLD_RELEASE fw_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE; //create the timer to delay a little bit before going to //sata spinup hold release activity. if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) { fw_device->protocol_device.smp_device.smp_activity_timer = scif_cb_timer_create( (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release, (void*)fw_device ); } else { ASSERT (0); } scif_cb_timer_start( (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, fw_device->protocol_device.smp_device.smp_activity_timer, SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION ); } else scif_sas_smp_remote_device_finish_discover(fw_device); } /** * @brief This method finishes the smp DISCOVER process. * * @param[in] fw_device The framework smp device that finishes all the * DISCOVER requests. * * @return none */ void scif_sas_smp_remote_device_finish_discover( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n", fw_device )); if ( fw_domain->is_config_route_table_needed && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL) scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device); //call the common private routine to reset all fields of this smp device. scif_sas_smp_remote_device_clear(fw_device); #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT scif_sas_smp_remote_device_print_smp_phy_list(fw_device); #endif //notify domain this smp device's discover finishes, it's up to domain //to continue the discover process in a bigger scope. scif_sas_domain_continue_discover(fw_domain); } /** * @brief This method continues the smp Target Reset (Phy Control) process. * * @param[in] fw_device The framework smp device that a smp reset targets to. * * @return none */ void scif_sas_smp_remote_device_continue_target_reset( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; SCIF_SAS_REMOTE_DEVICE_T * target_device = scif_sas_domain_get_device_by_containing_device( fw_device->domain, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index ); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n", fw_device, fw_request )); if (fw_device->protocol_device.smp_device.current_smp_request == SMP_FUNCTION_PHY_CONTROL) { //query the core remote device to get suggested reset timeout value //then scale down by factor of 8 to get the duration of the pause //before sending out Discover command to poll. U32 delay = (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8); //create the timer to send Discover command polling target device's //coming back. if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) { fw_device->protocol_device.smp_device.smp_activity_timer = scif_cb_timer_create( (SCI_CONTROLLER_HANDLE_T *)fw_controller, (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll, (void*)fw_request ); } else { ASSERT(0); } //start the timer scif_cb_timer_start( (SCI_CONTROLLER_HANDLE_T)fw_controller, fw_device->protocol_device.smp_device.smp_activity_timer, delay ); } else if (fw_device->protocol_device.smp_device.current_smp_request == SMP_FUNCTION_DISCOVER) { //tell target reset successful scif_sas_remote_device_target_reset_complete( target_device, fw_request, SCI_SUCCESS); } } /** * @brief This routine is invoked by timer or when 2 BCN are received * after Phy Control command. This routine will construct a * Discover command to the same expander phy to poll the target * device's coming back. This new request is then put into * high priority queue and will be started by a DPC soon. * * @param[in] fw_request The scif request for smp activities. */ void scif_sas_smp_remote_device_target_reset_poll( SCIF_SAS_REQUEST_T * fw_request ) { SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device; SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; void * new_command_handle; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n", fw_request )); // Before we construct new io using the same memory, we need to // remove the IO from the list of outstanding requests on the domain // so that we don't damage the domain's fast list of request. sci_fast_list_remove_element(&fw_request->list_element); fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_DISCOVER; //sent smp discover request to poll on remote device's coming back. //construct Discover command using the same memory as fw_request. new_command_handle = scif_sas_smp_request_construct_discover( fw_device->domain->controller, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index, (void *)sci_object_get_association(fw_request), (void *)fw_request ); //put into the high priority queue. sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle); //schedule the DPC to start new Discover command. scif_cb_start_internal_io_task_schedule( fw_controller, scif_sas_controller_start_high_priority_io, fw_controller ); } /** * @brief This method fails discover process. * * @param[in] fw_device The framework smp device that failed at current * activity. * * @return none */ void scif_sas_smp_remote_device_fail_discover( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n", fw_device )); switch (fw_device->protocol_device.smp_device.current_smp_request) { case SMP_FUNCTION_REPORT_GENERAL: case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: scif_sas_smp_remote_device_finish_discover(fw_device); break; case SMP_FUNCTION_DISCOVER: case SMP_FUNCTION_REPORT_PHY_SATA: //Retry limit reached, we will continue to send DISCOVER to next phy. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_DISCOVER; scif_sas_smp_remote_device_continue_discover(fw_device); break; default: break; } } /** * @brief This method fails Target Reset. * * @param[in] fw_device The framework smp device that failed at current * activity. * @param[in] fw_request The smp request created for target reset * using external resource. * * @return none */ void scif_sas_smp_remote_device_fail_target_reset( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request ) { SCIF_SAS_REMOTE_DEVICE_T * target_device = scif_sas_domain_get_device_by_containing_device( fw_device->domain, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index ); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n", fw_device, target_device, fw_request )); //tell target reset failed scif_sas_remote_device_target_reset_complete( target_device, fw_request, SCI_FAILURE); } /** * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity. * This function searches domain's device list, find a device in STOPPED STATE * and its connection_rate is SPINIP, then send DISCOVER command to its expander * phy id to poll. But if searching the domain's device list for SATA devices on * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished. * We then call fw_domain->device_start_complete_handler() for this smp-device. * * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE * activity. * * @return none */ void scif_sas_smp_remote_device_sata_spinup_hold_release( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller; SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n", fw_device )); //search throught domain's device list to find a sata device on spinup_hold //state to poll. device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain); if (device_to_poll != NULL) { //send DISCOVER command to this device's expaner phy. fw_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_DISCOVER; fw_device->protocol_device.smp_device.current_activity_phy_index = device_to_poll->expander_phy_identifier; scif_sas_smp_request_construct_discover( fw_domain->controller, fw_device, fw_device->protocol_device.smp_device.current_activity_phy_index, NULL, NULL ); //schedule the DPC to start new Discover command. scif_cb_start_internal_io_task_schedule( fw_controller, scif_sas_controller_start_high_priority_io, fw_controller ); } else //SATA SPINUP HOLD RELEASE activity is done. scif_sas_smp_remote_device_finish_discover (fw_device); } /** * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA * SATA device. It will remove a remote_device object for a sata device * that fails to come out of spinup_hold. * * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE * activity. * @param[in] target_device The expander attached device failed being brought out * of SPINUP_HOLD state. * * @return none */ void scif_sas_smp_remote_device_fail_target_spinup_hold_release( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REMOTE_DEVICE_T * target_device ) { SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n", fw_device, target_device )); //need to remove the device, since we have to give up on spinup_hold_release //activity on this device. scif_cb_domain_device_removed( fw_domain->controller, fw_domain, target_device ); //move on to next round of SPINUP_HOLD_REALSE activity. scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device); } /** * @brief This method retry only internal IO for the smp device. * * @param[in] fw_device The framework smp device that has an smp request to retry. * @param[in] io_retry_count current count for times the IO being retried. * @param[in] delay The time delay before the io gets retried. * * @return none */ void scif_sas_smp_remote_device_retry_internal_io( SCIF_SAS_REMOTE_DEVICE_T * fw_device, U8 io_retry_count, U32 delay ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n", fw_device, io_retry_count, delay )); fw_device->protocol_device.smp_device.io_retry_count = io_retry_count; //create the timer for poll target device's coming back. if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) { fw_device->protocol_device.smp_device.smp_activity_timer = scif_cb_timer_create( (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry, (void*)fw_device ); } else { ASSERT(0); } //start the timer for a purpose of waiting. scif_cb_timer_start( (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, fw_device->protocol_device.smp_device.smp_activity_timer, delay ); } /** * @brief This method indicates whether an expander device is in Discover * process. * * @param[in] fw_device The framework smp device. * * @return Whether an expander device is in the middle of discovery process. */ BOOL scif_sas_smp_remote_device_is_in_activity( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { return(fw_device->protocol_device.smp_device.current_activity != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE); } /** * @brief This method search through the smp phy list of an expander to * find a smp phy by its phy id of the expander. * * @param[in] phy_identifier The search criteria. * @param[in] smp_remote_device The expander that owns the smp phy list. * * @return The found smp phy or a NULL pointer to indicate no smp phy is found. */ SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id( U8 phy_identifier, SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device ) { SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; ASSERT(phy_identifier < smp_remote_device->smp_phy_list.number_of_phys); 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->phy_identifier == phy_identifier) return curr_smp_phy; } return NULL; } /** * @brief This method takes care of removing smp phy list of a smp devcie, which is * about to be removed. * * @param[in] fw_device The expander device that is about to be removed. * * @return none. */ void scif_sas_smp_remote_device_removed( SCIF_SAS_REMOTE_DEVICE_T * this_device ) { SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &this_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_LOG_TRACE(( sci_base_object_get_logger(this_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_removed(0x%x) enter\n", this_device )); //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys //in phy connections. while (element != NULL) { curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); element = sci_fast_list_get_next(element); scif_sas_smp_phy_destruct(curr_smp_phy); } this_device->protocol_device.smp_device.number_of_phys = 0; this_device->protocol_device.smp_device.expander_route_indexes = 0; this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE; this_device->protocol_device.smp_device.is_externally_configurable = FALSE; this_device->protocol_device.smp_device.is_able_to_config_others = FALSE; scif_sas_smp_remote_device_clear(this_device); } /** * @brief This method takes care of terminated smp request to a smp device. The * terminated smp request is most likely timeout and being aborted. A timeout * maybe due to OPEN REJECT (NO DESTINATION). * * @param[in] fw_device The expander device that a timed out smp request towards to. * @param[in] fw_request A failed smp request that is terminated by scic. * * @return none. */ void scif_sas_smp_remote_device_terminated_request_handler( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_REQUEST_T * fw_request ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n", fw_device, fw_request )); scif_sas_smp_remote_device_decode_smp_response( - fw_device, fw_request, NULL, SCI_FAILURE_RETRY_REQUIRED + fw_device, fw_request, NULL, SCI_IO_FAILURE_RETRY_REQUIRED ); } /** * @brief This method allocates and populates the smp phy list of a expander device. * * @param[in] fw_device The expander device, whose smp phy list is to be populated after * getting REPORT GENERAL response. * * @return none. */ void scif_sas_smp_remote_device_populate_smp_phy_list( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL; U8 expander_phy_id = 0; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n", fw_device )); for ( expander_phy_id = 0; expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys; expander_phy_id++ ) { this_smp_phy = scif_sas_controller_allocate_smp_phy(fw_device->domain->controller); ASSERT( this_smp_phy != NULL ); if ( this_smp_phy != NULL ) scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id); } } /** * @brief This method updates a smp phy of a expander device based on DISCOVER response. * * @param[in] fw_device The expander device, one of whose smp phys is to be updated. * @param[in] discover_response The smp DISCOVER response. * * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute, * return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise, * return SCI_SUCCESS */ SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SMP_RESPONSE_DISCOVER_T * discover_response ) { SCI_STATUS status = SCI_SUCCESS; SCIF_SAS_SMP_PHY_T * smp_phy = NULL; SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n", fw_device, discover_response )); smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id( discover_response->phy_identifier, &fw_device->protocol_device.smp_device ); ASSERT( smp_phy != NULL ); //Note, attached_device could be NULL, not all the smp phy have to connected to a device. attached_device = (SCIF_SAS_REMOTE_DEVICE_T *) scif_domain_get_device_by_sas_address( fw_device->domain, &discover_response->attached_sas_address); scif_sas_smp_phy_save_information( smp_phy, attached_device, discover_response); //handle the special case of smp phys between expanders. if ( discover_response->protocols.u.bits.attached_smp_target ) { //this fw_device is a child expander, just found its parent expander. //And there is no smp_phy constructed yet, record this phy connection. if ( attached_device != NULL && attached_device == fw_device->containing_device ) { //record the smp phy info, for this phy connects to a upstream smp device. //the connection of a pair of smp phys are completed. status = scif_sas_smp_phy_set_attached_phy( smp_phy, discover_response->attached_phy_identifier, attached_device ); if (status == SCI_SUCCESS) { //check the routing attribute for this phy and its containing device's //expander_phy_routing_attribute. if ( scif_sas_smp_phy_verify_routing_attribute( smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS ) return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION; } } } return status; } #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT void scif_sas_smp_remote_device_print_smp_phy_list( 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_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE, "==========EXPANDER DEVICE (0x%x) smp phy list========== \n", fw_device )); while (element != NULL) { curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); element = sci_fast_list_get_next(element); //print every thing about a smp phy SCIF_LOG_ERROR(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE, "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n", curr_smp_phy->phy_identifier, curr_smp_phy, curr_smp_phy->u.end_device, curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low, curr_smp_phy->attached_device_type, curr_smp_phy->routing_attribute )); } } #endif /** * @brief This method configure upstream expander(s)' (if there is any) route info. * * @param[in] this_device The expander device that is currently in discover process. * * @return none. */ void scif_sas_smp_remote_device_configure_upstream_expander_route_info( SCIF_SAS_REMOTE_DEVICE_T * this_device ) { SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device; SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander = scif_sas_remote_device_find_upstream_expander(this_device); SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(this_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n", this_device )); //traverse back to find root device. while(curr_parent_expander != NULL ) { //must set destination_smp_phy outside of find_upstream_expander() using the device //that is just about to finish the discovery. curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy = (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object( this_device->protocol_device.smp_device.smp_phy_list.list_head); curr_child_expander = curr_parent_expander; curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander); } //found the root device: curr_child_expander. configure it and its downstream expander(s) till //this_device or a self-configuring expander that configures others; curr_config_route_info_expander = curr_child_expander; while ( curr_config_route_info_expander != NULL && curr_config_route_info_expander != this_device && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE ) { if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable) { SCIF_SAS_SMP_PHY_T * phy_being_config = curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor; curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index = phy_being_config->config_route_table_index_anchor; if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0) curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++; curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE; //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device //same as curr_config_route_info_expander. curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander( curr_config_route_info_expander); } else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others) { //no need to config route table to this expander and its children. //find its downstream expander and clear the planned config route table activity. SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander = scif_sas_remote_device_find_downstream_expander( curr_config_route_info_expander); scif_sas_smp_remote_device_clear(curr_config_route_info_expander); while ( curr_downstream_expander != NULL && curr_downstream_expander != this_device ) { scif_sas_smp_remote_device_clear(curr_downstream_expander); curr_downstream_expander = scif_sas_remote_device_find_downstream_expander( curr_config_route_info_expander); } break; } else { // current expander is a self-configuring expander, which is not externally // configurable, and doesn't config others. we need to simply skip this expander. curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander( curr_config_route_info_expander); } } } /** * @brief This method finds the immediate upstream expander of a given expander device. * * @param[in] this_device The given expander device, whose upstream expander is to be found. * * @return The immediate upstream expander. Or a NULL pointer if this_device is root already. */ SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander( SCIF_SAS_REMOTE_DEVICE_T * this_device ) { SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &this_device->protocol_device.smp_device; SCIF_SAS_REMOTE_DEVICE_T * upstream_expander = NULL; SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(this_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n", this_device )); 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->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) && curr_smp_phy->u.attached_phy != NULL && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE ) { //set the current_activity and current_config_route_index for that //upstream expander. upstream_expander = curr_smp_phy->u.attached_phy->owning_device; upstream_expander->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION; //if the upstream_expander's config route table method is config phy0 only or //config all phys, the current activity phy is found. upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = scif_sas_smp_remote_device_find_smp_phy_by_id( curr_smp_phy->u.attached_phy->phy_identifier, &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device) ); //if the upstream_expander's config route table method is config middle phy only //config highest phy only, the current activity phy needs a update. if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander) == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY ) { upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = scif_sas_smp_phy_find_middle_phy_in_wide_port ( upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor ); } else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander) == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY ) { upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = scif_sas_smp_phy_find_highest_phy_in_wide_port ( upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor ); } upstream_expander->protocol_device.smp_device.current_activity_phy_index = upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier; return upstream_expander; } } return NULL; } /** * @brief This method finds the immediate downstream expander of a given expander device. * * @param[in] this_device The given expander device, whose downstream expander is to be found. * * @return The immediate downstream expander. Or a NULL pointer if there is none. */ SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander( SCIF_SAS_REMOTE_DEVICE_T * this_device ) { SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device = &this_device->protocol_device.smp_device; SCIF_SAS_REMOTE_DEVICE_T * downstream_expander = NULL; SCI_FAST_LIST_ELEMENT_T * element = this_smp_remote_device->smp_phy_list.list_head; SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(this_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n", this_device )); 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->routing_attribute == TABLE_ROUTING_ATTRIBUTE && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE && curr_smp_phy->u.attached_phy != NULL) { //set the current_activity and current_config_route_index for that //upstream expander. downstream_expander = curr_smp_phy->u.attached_phy->owning_device; if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device == this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device ) return downstream_expander; } } return NULL; } /** * @brief This method follows route table optimization rule to check if a destination_device * should be recorded in the device_being_config's route table * * @param[in] device_being_config The upstream expander device, whose route table is being configured. * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be * recorded in route table. * * @return BOOL This method returns TRUE if a destination_device should be recorded in route table. * This method returns FALSE if a destination_device need not to be recorded * in route table. */ BOOL scif_sas_smp_remote_device_do_config_route_info( SCIF_SAS_REMOTE_DEVICE_T * device_being_config, SCIF_SAS_SMP_PHY_T * destination_smp_phy ) { SCI_SAS_ADDRESS_T device_being_config_sas_address; SCIF_LOG_TRACE(( sci_base_object_get_logger(device_being_config), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n", device_being_config, destination_smp_phy )); scic_remote_device_get_sas_address( device_being_config->core_object, &device_being_config_sas_address ); //refer to SAS-2 spec 4.8.3, rule (b) if ((destination_smp_phy->attached_sas_address.low == 0 && destination_smp_phy->attached_sas_address.high == 0) && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED)) { return FALSE; } //refer to SAS-2 spec 4.8.3, rule (c), self-referencing. if (destination_smp_phy->attached_sas_address.high == device_being_config_sas_address.high && destination_smp_phy->attached_sas_address.low == device_being_config_sas_address.low) { return FALSE; } //There will be no cases that falling into rule (a), (d), (e) to be excluded, //based on our current mechanism of cofig route table. return TRUE; } /** * @brief This method configures device_being_config's route table for all the enclosed devices in * a downstream smp device, destination_device. * * @param[in] device_being_config The upstream expander device, whose route table is being configured. * * @return None */ void scif_sas_smp_remote_device_configure_route_table( SCIF_SAS_REMOTE_DEVICE_T * device_being_config ) { //go through the smp phy list of this_device. SCI_FAST_LIST_ELEMENT_T * element = &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element); SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(device_being_config), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n", device_being_config )); device_being_config->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE; while (element != NULL) { curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); element = sci_fast_list_get_next(element); //check if this phy needs to be added to the expander's route table. if (scif_sas_smp_remote_device_do_config_route_info( device_being_config, curr_smp_phy) == TRUE ) { SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &device_being_config->protocol_device.smp_device; smp_remote_device->curr_config_route_destination_smp_phy = curr_smp_phy; //Then config this_device's route table entry at the phy and next route_index. //send config_route_info using curr_smp_phy.phy_identifier and sas_address. scif_sas_smp_request_construct_config_route_info( device_being_config->domain->controller, device_being_config, smp_remote_device->current_activity_phy_index, smp_remote_device->curr_config_route_index, curr_smp_phy->attached_sas_address, FALSE ); //schedule the DPC. scif_cb_start_internal_io_task_schedule( device_being_config->domain->controller, scif_sas_controller_start_high_priority_io, device_being_config->domain->controller ); //stop here, we need to wait for config route info's response then send //the next one. break; } } } /** * @brief This method walks through an expander's route table to clean table * attribute phys' route entries. This routine finds one table entry * to clean and will be called repeatly till it finishes cleanning the * whole table. * * @param[in] fw_device The expander device, whose route table entry is to be cleaned. * * @return None. */ void scif_sas_smp_remote_device_clean_route_table( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_SAS_SMP_PHY_T * smp_phy_being_config; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n", fw_device )); //from anchors, start to clean all the other route table entries. fw_device->protocol_device.smp_device.curr_config_route_index++; if ( fw_device->protocol_device.smp_device.curr_config_route_index >= fw_device->protocol_device.smp_device.expander_route_indexes ) { fw_device->protocol_device.smp_device.curr_config_route_index = 0; do //find next table attribute PHY. { fw_device->protocol_device.smp_device.current_activity_phy_index++; if (fw_device->protocol_device.smp_device.current_activity_phy_index == fw_device->protocol_device.smp_device.number_of_phys) fw_device->protocol_device.smp_device.current_activity_phy_index=0; //phy_index changed, so update the smp_phy_being_config. smp_phy_being_config = scif_sas_smp_remote_device_find_smp_phy_by_id( fw_device->protocol_device.smp_device.current_activity_phy_index, &(fw_device->protocol_device.smp_device) ); } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE ); if ( smp_phy_being_config->phy_identifier != fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier) { if (smp_phy_being_config->config_route_table_index_anchor != 0) fw_device->protocol_device.smp_device.curr_config_route_index = smp_phy_being_config->config_route_table_index_anchor + 1; else fw_device->protocol_device.smp_device.curr_config_route_index = 0; } } if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index == fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier && fw_device->protocol_device.smp_device.curr_config_route_index == 0) ) { //clean this route entry. scif_sas_smp_remote_device_clean_route_table_entry(fw_device); } else { fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE; //set this device's activity to NON. fw_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; //we need to notify domain that this device finished config route table, domain //may pick up other activities (i.e. Discover) for other expanders. scif_sas_domain_continue_discover(fw_device->domain); } } /** * @brief This method cleans a device's route table antry. * * @param[in] fw_device The expander device, whose route table entry is to be cleaned. * * @return None. */ void scif_sas_smp_remote_device_clean_route_table_entry( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCI_SAS_ADDRESS_T empty_sas_address; SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &(fw_device->protocol_device.smp_device); SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n", fw_device )); empty_sas_address.high = 0; empty_sas_address.low = 0; scif_sas_smp_request_construct_config_route_info( fw_device->domain->controller, fw_device, smp_remote_device->current_activity_phy_index, smp_remote_device->curr_config_route_index, empty_sas_address, TRUE ); //schedule the DPC. scif_cb_start_internal_io_task_schedule( fw_device->domain->controller, scif_sas_controller_start_high_priority_io, fw_device->domain->controller ); } /** * @brief This method handles the case of exceeding route index when config route table * for a device, by removing the attached device of current config route * destination smp phy and the rest of smp phys in the same smp phy list. * * @param[in] fw_device The expander device, whose route table to be edited but failed * with a SMP function result of INDEX DOES NOT EXIST. * * @return None. */ void scif_sas_smp_remote_device_cancel_config_route_table_activity( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { //go through the rest of the smp phy list of destination device. SCI_FAST_LIST_ELEMENT_T * element = &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element); SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; SCIF_SAS_REMOTE_DEVICE_T * curr_attached_device = NULL; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n", fw_device )); while (element != NULL) { curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); element = sci_fast_list_get_next(element); //check if this phy needs to be added to the expander's route table but can't due to //exceeding max route index. if (scif_sas_smp_remote_device_do_config_route_info( fw_device, curr_smp_phy) == TRUE ) { //set the is_currently_discovered to FALSE for attached device. Then when //domain finish discover, domain will remove this device. curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *) scif_domain_get_device_by_sas_address( fw_device->domain, &(curr_smp_phy->attached_sas_address)); if (curr_attached_device != NULL) curr_attached_device->is_currently_discovered = FALSE; } } } /** * @brief This method cancel current activity and terminate the outstanding internal IO * if there is one. * * @param[in] fw_device The expander device, whose smp activity is to be canceled. * * @return None. */ void scif_sas_smp_remote_device_cancel_smp_activity( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_device), SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n", fw_device )); //Terminate all of the requests in the silicon for this device. scif_sas_domain_terminate_requests( fw_device->domain, fw_device, NULL, NULL ); if (fw_device->protocol_device.smp_device.current_activity == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE) scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device); //Clear the device to stop the smp sctivity. scif_sas_smp_remote_device_clear(fw_device); } /** * @brief This method tells the way to configure route table for a expander. The * possible ways are: configure phy 0's route table, configure middle * phy's route table, configure highest order phy's route table, * configure all phys. * * @param[in] fw_device The expander device, whose config route table method is * to be chosen. * * @return one in 4 possible options. */ U8 scif_sas_smp_remote_device_get_config_route_table_method( SCIF_SAS_REMOTE_DEVICE_T * fw_device ) { U8 config_route_table_method; //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY; config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS; return config_route_table_method; } /** * @brief This method starts the EA target reset process by constructing * and starting a PHY CONTROL (hard reset) smp request. * * @param[in] expander_device The expander device, to which a PHY Control smp command is * sent. * @param[in] target_device The expander attahced target device, to which the target reset * request is sent. * @param[in] fw_request The target reset task request. * * @return none */ void scif_sas_smp_remote_device_start_target_reset( SCIF_SAS_REMOTE_DEVICE_T * expander_device, SCIF_SAS_REMOTE_DEVICE_T * target_device, SCIF_SAS_REQUEST_T * fw_request ) { SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller; //set current_activity and current_smp_request to expander device. expander_device->protocol_device.smp_device.current_activity = SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET; expander_device->protocol_device.smp_device.current_smp_request = SMP_FUNCTION_PHY_CONTROL; expander_device->protocol_device.smp_device.current_activity_phy_index = target_device->expander_phy_identifier; //A Phy Control smp request has been constructed towards parent device. //Walk the high priority io path. fw_controller->state_handlers->start_high_priority_io_handler( (SCI_BASE_CONTROLLER_T*) fw_controller, (SCI_BASE_REMOTE_DEVICE_T*) expander_device, (SCI_BASE_REQUEST_T*) fw_request, SCI_CONTROLLER_INVALID_IO_TAG ); } Index: head/sys/dev/isci/scil/scif_sas_stp_io_request.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_stp_io_request.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_stp_io_request.c (revision 231296) @@ -1,623 +1,623 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /** * @file * * @brief This file contains the method implementations for the * SCIF_SAS_STP_IO_REQUEST object. The contents will implement * SATA/STP specific functionality. */ #include #include #include #include #include #include #include #include #include #include #include //****************************************************************************** // P R I V A T E M E T H O D S //****************************************************************************** /** * @brief This method provides SATA/STP CONSTRUCTED state specific handling * for when the user attempts to start the supplied IO request. It * will allocate 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 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_start_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_start_handler(0x%x) enter\n", io_request )); if (fw_io->parent.stp.sequence.protocol == SAT_PROTOCOL_FPDMA) { SATA_FIS_REG_H2D_T * fis; // For NCQ, we need to attempt to allocate an available tag. fw_io->parent.stp.ncq_tag = scif_sas_stp_remote_device_allocate_ncq_tag( fw_io->parent.device ); if (fw_io->parent.stp.ncq_tag == SCIF_SAS_INVALID_NCQ_TAG) return SCI_FAILURE_NO_NCQ_TAG_AVAILABLE; // Set the NCQ tag in the host to device register FIS (upper 5 bits // of the 8-bit sector count register). fis = scic_stp_io_request_get_h2d_reg_address(fw_io->parent.core_object); fis->sector_count = (fw_io->parent.stp.ncq_tag << 3); // The Core also requires that we inform it separately regarding the // NCQ tag for this IO. scic_stp_io_request_set_ncq_tag( fw_io->parent.core_object, fw_io->parent.stp.ncq_tag ); } return SCI_SUCCESS; } /** * @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 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; } #if !defined(DISABLE_ATAPI) /** * @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; } #endif // !defined(DISABLE_ATAPI) //****************************************************************************** // P R O T E C T E D M E T H O D S //****************************************************************************** /** * @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 = SATI_SUCCESS; + 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; } #if !defined(DISABLE_ATAPI) /** * @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; } #endif #if !defined(DISABLE_ATAPI) /** * @brief This method will get the number of bytes transferred in an packet IO. * * @param[in] fw_io This parameter specifies the stp packet io request whose * actual transferred length is to be retrieved. * * @return Actual length of transferred data. */ U32 scif_sas_stp_packet_io_request_get_number_of_bytes_transferred( SCIF_SAS_IO_REQUEST_T * fw_io ) { SCI_IO_REQUEST_HANDLE_T scic_io = scif_io_request_get_scic_handle(fw_io); SCI_IO_STATUS io_status = scic_request_get_sci_status (scic_io); U32 actual_data_length; if (io_status == SCI_IO_FAILURE_RESPONSE_VALID) actual_data_length = 0; else if (io_status == SCI_IO_SUCCESS_IO_DONE_EARLY) { actual_data_length = sati_atapi_translate_number_of_bytes_transferred( &fw_io->parent.stp.sequence, fw_io, fw_io); if (actual_data_length == 0) actual_data_length = scic_io_request_get_number_of_bytes_transferred(scic_io); } else actual_data_length = scic_io_request_get_number_of_bytes_transferred(scic_io); return actual_data_length; } #endif //****************************************************************************** // P U B L I C M E T H O D S //****************************************************************************** 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; } // --------------------------------------------------------------------------- U8 scic_cb_request_get_sat_protocol( void * scic_user_io_request ) { SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T*) scic_user_io_request; return fw_io->parent.stp.sequence.protocol; } U8 *scic_cb_io_request_get_virtual_address_from_sgl( void * scic_user_io_request, U32 byte_offset ) { SCIF_SAS_REQUEST_T *fw_request = (SCIF_SAS_REQUEST_T *) sci_object_get_association(scic_user_io_request); return scif_cb_io_request_get_virtual_address_from_sgl( sci_object_get_association(fw_request), byte_offset ); } #ifdef ENABLE_OSSL_COPY_BUFFER void scic_cb_io_request_copy_buffer( void * scic_user_io_request, U8 *source_addr, U32 offset, U32 length ) { SCIF_SAS_REQUEST_T *fw_request = (SCIF_SAS_REQUEST_T *)sci_object_get_association(scic_user_io_request); return scif_cb_io_request_copy_buffer( sci_object_get_association(fw_request), source_addr, offset, length ); } #endif // --------------------------------------------------------------------------- SCI_BASE_REQUEST_STATE_HANDLER_T stp_io_request_constructed_handlers = { scif_sas_stp_io_request_constructed_start_handler, scif_sas_io_request_constructed_abort_handler, scif_sas_stp_io_request_constructed_complete_handler, scif_sas_io_request_default_destruct_handler }; Index: head/sys/dev/isci/scil/scif_sas_stp_task_request.c =================================================================== --- head/sys/dev/isci/scil/scif_sas_stp_task_request.c (revision 231295) +++ head/sys/dev/isci/scil/scif_sas_stp_task_request.c (revision 231296) @@ -1,265 +1,265 @@ /*- * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include /** * @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_task_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 ) { #if !defined(DISABLE_SATI_TASK_MANAGEMENT) SCIF_SAS_TASK_REQUEST_T * fw_task = (SCIF_SAS_TASK_REQUEST_T *) fw_request; SCIF_LOG_TRACE(( sci_base_object_get_logger(fw_controller), SCIF_LOG_OBJECT_TASK_MANAGEMENT, "scif_sas_stp_core_cb_task_request_complete_handler(0x%x, 0x%x, 0x%x, 0x%x) enter\n", fw_controller, fw_device, fw_request, *completion_status )); // 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. if ( (*completion_status == SCI_SUCCESS) || (*completion_status == SCI_FAILURE_IO_RESPONSE_VALID) ) { SATI_STATUS sati_status = sati_translate_task_response( &fw_task->parent.stp.sequence, fw_task, fw_task ); 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. /// @todo multiple ATA commands are required, but not supported yet. return SCI_FAILURE; } else { // Something unexpected occurred during translation. Fail the // IO request to the user. *completion_status = SCI_FAILURE; } } else //A stp task request sometimes fails. { if (scif_sas_task_request_get_function(fw_task) == SCI_SAS_ABORT_TASK_SET) { scif_sas_stp_task_request_abort_task_set_failure_handler( fw_device, fw_task); } } return SCI_SUCCESS; #else // !defined(DISABLE_SATI_TASK_MANAGEMENT) return SCI_FAILURE; #endif // !defined(DISABLE_SATI_TASK_MANAGEMENT) } /** * @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 provides handling for failed stp TASK MANAGEMENT * request. * * @param[in] fw_device This parameter specifies the target device the * task management request towards to. * @param[in] fw_request This parameter specifies the failed task management * request. * @param[in] completion_status This parameter sprecifies the completion * status of the task management request's core status. * * @return None. */ void scif_sas_stp_task_request_abort_task_set_failure_handler( SCIF_SAS_REMOTE_DEVICE_T * fw_device, SCIF_SAS_TASK_REQUEST_T * fw_task ) { #if !defined(DISABLE_SATI_TASK_MANAGEMENT) SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; SCI_FAST_LIST_ELEMENT_T * pending_request_element; SCIF_SAS_REQUEST_T * pending_request = NULL; pending_request_element = fw_domain->request_list.list_head; // Cycle through the list of IO requests. search all the // outstanding IOs with "waiting for abort task set" flag, // completes them now. while (pending_request_element != NULL) { pending_request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(pending_request_element); // The current element may be deleted from the list becasue of // IO completion so advance to the next element early pending_request_element = sci_fast_list_get_next(pending_request_element); if ( pending_request->device == fw_device && pending_request->is_waiting_for_abort_task_set == TRUE ) { //In case the pending_request is still in the middle of aborting. //abort it again to the core. SCI_STATUS abort_status; //Reset the flag now since we are process the read log ext command now. pending_request->is_waiting_for_abort_task_set = FALSE; abort_status = scic_controller_terminate_request( fw_domain->controller->core_object, fw_device->core_object, pending_request->core_object ); if (abort_status == SCI_FAILURE_INVALID_STATE) { //the request must have not be in aborting state anymore, complete it now. scif_cb_io_request_complete( fw_domain->controller, fw_device, pending_request, - SCI_FAILURE_IO_TERMINATED + SCI_IO_FAILURE_TERMINATED ); } //otherwise, the abort succeeded. Since the waiting flag is cleared, //the pending request will be completed later. } } #endif //#if !defined(DISABLE_SATI_TASK_MANAGEMENT) } Index: head/sys/modules/isci/Makefile =================================================================== --- head/sys/modules/isci/Makefile (revision 231295) +++ head/sys/modules/isci/Makefile (revision 231296) @@ -1,92 +1,90 @@ # isci driver Makefile # # $FreeBSD$ ISCI_SRC_PATH = ${.CURDIR}/../.. .PATH: ${ISCI_SRC_PATH}/dev/isci ${ISCI_SRC_PATH}/dev/isci/scil KMOD = isci SRCS = isci.c isci_oem_parameters.c \ isci_controller.c isci_domain.c isci_io_request.c \ isci_timer.c isci_remote_device.c isci_logger.c \ isci_task_request.c isci_sysctl.c isci_interrupt.c SRCS += \ sci_base_controller.c \ sci_base_domain.c \ sci_base_iterator.c \ sci_base_library.c \ sci_base_logger.c \ sci_base_memory_descriptor_list.c \ sci_base_memory_descriptor_list_decorator.c \ sci_base_object.c \ sci_base_observer.c \ sci_base_phy.c \ sci_base_port.c \ sci_base_remote_device.c \ sci_base_request.c \ sci_base_state_machine.c \ sci_base_state_machine_logger.c \ sci_base_state_machine_observer.c \ sci_base_subject.c SRCS += \ sci_abstract_list.c \ sci_util.c SRCS += \ scic_sds_controller.c \ scic_sds_library.c scic_sds_pci.c \ scic_sds_phy.c scic_sds_port.c \ scic_sds_port_configuration_agent.c \ scic_sds_remote_device.c scic_sds_remote_node_context.c \ scic_sds_remote_node_table.c scic_sds_request.c \ scic_sds_sgpio.c scic_sds_smp_remote_device.c \ scic_sds_smp_request.c scic_sds_ssp_request.c \ scic_sds_stp_packet_request.c scic_sds_stp_remote_device.c \ scic_sds_stp_request.c scic_sds_unsolicited_frame_control.c SRCS += \ scif_sas_controller.c \ scif_sas_controller_state_handlers.c \ scif_sas_controller_states.c scif_sas_domain.c \ scif_sas_domain_state_handlers.c scif_sas_domain_states.c \ scif_sas_high_priority_request_queue.c \ scif_sas_internal_io_request.c scif_sas_io_request.c \ scif_sas_io_request_state_handlers.c \ scif_sas_io_request_states.c scif_sas_library.c \ scif_sas_remote_device.c \ scif_sas_remote_device_ready_substate_handlers.c \ scif_sas_remote_device_ready_substates.c \ scif_sas_remote_device_starting_substate_handlers.c \ scif_sas_remote_device_starting_substates.c \ scif_sas_remote_device_state_handlers.c \ scif_sas_remote_device_states.c scif_sas_request.c \ scif_sas_smp_activity_clear_affiliation.c \ scif_sas_smp_io_request.c scif_sas_smp_phy.c \ scif_sas_smp_remote_device.c scif_sas_stp_io_request.c \ scif_sas_stp_remote_device.c scif_sas_stp_task_request.c \ scif_sas_task_request.c scif_sas_task_request_state_handlers.c \ scif_sas_task_request_states.c scif_sas_timer.c SRCS += \ sati.c \ sati_abort_task_set.c sati_atapi.c \ sati_device.c sati_inquiry.c sati_log_sense.c \ sati_lun_reset.c sati_mode_pages.c sati_mode_select.c \ sati_mode_sense.c sati_mode_sense_6.c sati_mode_sense_10.c \ sati_move.c sati_passthrough.c sati_read.c sati_read_buffer.c \ sati_read_capacity.c \ sati_report_luns.c sati_request_sense.c sati_reassign_blocks.c \ sati_start_stop_unit.c sati_synchronize_cache.c \ sati_test_unit_ready.c sati_unmap.c sati_util.c \ sati_verify.c sati_write.c \ sati_write_buffer.c sati_write_long.c sati_write_and_verify.c SRCS += opt_scsi.h opt_cam.h opt_isci.h SRCS += device_if.h bus_if.h pci_if.h -CC = gcc - .include