void isci_controller_construct(struct ISCI_CONTROLLER *controller, struct isci_softc *isci) { SCI_CONTROLLER_HANDLE_T scif_controller_handle; scif_library_allocate_controller(isci->sci_library_handle, &scif_controller_handle); scif_controller_construct(isci->sci_library_handle, scif_controller_handle, NULL); controller->isci = isci; controller->scif_controller_handle = scif_controller_handle; /* This allows us to later use * sci_object_get_association(scif_controller_handle) * inside of a callback routine to get our struct ISCI_CONTROLLER object */ sci_object_set_association(scif_controller_handle, (void *)controller); controller->is_started = FALSE; controller->is_frozen = FALSE; controller->sim = NULL; controller->initial_discovery_mask = 0; sci_fast_list_init(&controller->pending_device_reset_list); mtx_init(&controller->lock, "isci", NULL, MTX_DEF); uint32_t domain_index; for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++) { isci_domain_construct( &controller->domain[domain_index], domain_index, controller); } controller->timer_memory = malloc( sizeof(struct ISCI_TIMER) * SCI_MAX_TIMERS, M_ISCI, M_NOWAIT | M_ZERO); sci_pool_initialize(controller->timer_pool); struct ISCI_TIMER *timer = (struct ISCI_TIMER *) controller->timer_memory; for ( int i = 0; i < SCI_MAX_TIMERS; i++ ) { sci_pool_put(controller->timer_pool, timer++); } }
/** * @brief This method initializes the fields of the HPRQ. It should be * called during the construction of the object containing or * utilizing it (i.e. SCIF_SAS_CONTROLLER). * * @param[in] fw_hprq This parameter specific the high priority request * queue object being constructed. * * @return none */ void scif_sas_high_priority_request_queue_construct( SCIF_SAS_HIGH_PRIORITY_REQUEST_QUEUE_T * fw_hprq, SCI_BASE_LOGGER_T * logger ) { SCIF_LOG_TRACE(( logger, SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, "scif_sas_high_priority_request_queue_construct(0x%x,0x%x) enter\n", fw_hprq, logger )); sci_base_object_construct((SCI_BASE_OBJECT_T*) &fw_hprq->lock, logger); fw_hprq->lock.level = SCI_LOCK_LEVEL_NONE; sci_pool_initialize(fw_hprq->pool); }
int isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller) { int error; device_t device = controller->isci->device; uint32_t max_segment_size = isci_io_request_get_max_io_size(); uint32_t status = 0; struct ISCI_MEMORY *uncached_controller_memory = &controller->uncached_controller_memory; struct ISCI_MEMORY *cached_controller_memory = &controller->cached_controller_memory; struct ISCI_MEMORY *request_memory = &controller->request_memory; POINTER_UINT virtual_address; bus_addr_t physical_address; controller->mdl = sci_controller_get_memory_descriptor_list_handle( controller->scif_controller_handle); uncached_controller_memory->size = sci_mdl_decorator_get_memory_size( controller->mdl, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS); error = isci_allocate_dma_buffer(device, uncached_controller_memory); if (error != 0) return (error); sci_mdl_decorator_assign_memory( controller->mdl, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS, uncached_controller_memory->virtual_address, uncached_controller_memory->physical_address); cached_controller_memory->size = sci_mdl_decorator_get_memory_size( controller->mdl, SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS ); error = isci_allocate_dma_buffer(device, cached_controller_memory); if (error != 0) return (error); sci_mdl_decorator_assign_memory(controller->mdl, SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS, cached_controller_memory->virtual_address, cached_controller_memory->physical_address); request_memory->size = controller->queue_depth * isci_io_request_get_object_size(); error = isci_allocate_dma_buffer(device, request_memory); if (error != 0) return (error); /* For STP PIO testing, we want to ensure we can force multiple SGLs * since this has been a problem area in SCIL. This tunable parameter * will allow us to force DMA segments to a smaller size, ensuring * that even if a physically contiguous buffer is attached to this * I/O, the DMA subsystem will pass us multiple segments in our DMA * load callback. */ TUNABLE_INT_FETCH("hw.isci.max_segment_size", &max_segment_size); /* Create DMA tag for our I/O requests. Then we can create DMA maps based off * of this tag and store them in each of our ISCI_IO_REQUEST objects. This * will enable better performance than creating the DMA maps everytime we get * an I/O. */ status = bus_dma_tag_create(bus_get_dma_tag(device), 0x1, 0x0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, isci_io_request_get_max_io_size(), SCI_MAX_SCATTER_GATHER_ELEMENTS, max_segment_size, 0, NULL, NULL, &controller->buffer_dma_tag); sci_pool_initialize(controller->request_pool); virtual_address = request_memory->virtual_address; physical_address = request_memory->physical_address; for (int i = 0; i < controller->queue_depth; i++) { struct ISCI_REQUEST *request = (struct ISCI_REQUEST *)virtual_address; isci_request_construct(request, controller->scif_controller_handle, controller->buffer_dma_tag, physical_address); sci_pool_put(controller->request_pool, request); virtual_address += isci_request_get_object_size(); physical_address += isci_request_get_object_size(); } uint32_t remote_device_size = sizeof(struct ISCI_REMOTE_DEVICE) + scif_remote_device_get_object_size(); controller->remote_device_memory = (uint8_t *) malloc( remote_device_size * SCI_MAX_REMOTE_DEVICES, M_ISCI, M_NOWAIT | M_ZERO); sci_pool_initialize(controller->remote_device_pool); uint8_t *remote_device_memory_ptr = controller->remote_device_memory; for (int i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { struct ISCI_REMOTE_DEVICE *remote_device = (struct ISCI_REMOTE_DEVICE *)remote_device_memory_ptr; controller->remote_device[i] = NULL; remote_device->index = i; remote_device->is_resetting = FALSE; remote_device->frozen_lun_mask = 0; sci_fast_list_element_init(remote_device, &remote_device->pending_device_reset_element); sci_pool_put(controller->remote_device_pool, remote_device); remote_device_memory_ptr += remote_device_size; } return (0); }