isci_controller.c revision 231860
11573Srgrimes/*- 21573Srgrimes * BSD LICENSE 31573Srgrimes * 41573Srgrimes * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 51573Srgrimes * All rights reserved. 61573Srgrimes * 71573Srgrimes * Redistribution and use in source and binary forms, with or without 81573Srgrimes * modification, are permitted provided that the following conditions 91573Srgrimes * are met: 101573Srgrimes * 111573Srgrimes * * Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * * Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in 151573Srgrimes * the documentation and/or other materials provided with the 161573Srgrimes * distribution. 171573Srgrimes * 181573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 191573Srgrimes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 201573Srgrimes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 211573Srgrimes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 221573Srgrimes * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 231573Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 241573Srgrimes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 251573Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 261573Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 271573Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 281573Srgrimes * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 291573Srgrimes */ 301573Srgrimes 311573Srgrimes#include <sys/cdefs.h> 321573Srgrimes__FBSDID("$FreeBSD: head/sys/dev/isci/isci_controller.c 231860 2012-02-17 06:47:16Z sbruno $"); 331573Srgrimes 341573Srgrimes#include <dev/isci/isci.h> 351573Srgrimes 361573Srgrimes#include <sys/conf.h> 371573Srgrimes#include <sys/malloc.h> 3816586Sjraynard 391573Srgrimes#include <dev/isci/scil/sci_memory_descriptor_list.h> 4016586Sjraynard#include <dev/isci/scil/sci_memory_descriptor_list_decorator.h> 4116586Sjraynard 4221673Sjkh#include <dev/isci/scil/scif_controller.h> 431573Srgrimes#include <dev/isci/scil/scif_library.h> 441573Srgrimes#include <dev/isci/scil/scif_io_request.h> 451573Srgrimes#include <dev/isci/scil/scif_task_request.h> 461573Srgrimes#include <dev/isci/scil/scif_remote_device.h> 471573Srgrimes#include <dev/isci/scil/scif_domain.h> 481573Srgrimes#include <dev/isci/scil/scif_user_callback.h> 491573Srgrimes 501573Srgrimesvoid isci_action(struct cam_sim *sim, union ccb *ccb); 511573Srgrimesvoid isci_poll(struct cam_sim *sim); 521573Srgrimes 531573Srgrimes#define ccb_sim_ptr sim_priv.entries[0].ptr 541573Srgrimes 551573Srgrimes/** 561573Srgrimes * @brief This user callback will inform the user that the controller has 571573Srgrimes * had a serious unexpected error. The user should not the error, 581573Srgrimes * disable interrupts, and wait for current ongoing processing to 591573Srgrimes * complete. Subsequently, the user should reset the controller. 601573Srgrimes * 611573Srgrimes * @param[in] controller This parameter specifies the controller that had 621573Srgrimes * an error. 631573Srgrimes * 641573Srgrimes * @return none 651573Srgrimes */ 6613545Sjulianvoid scif_cb_controller_error(SCI_CONTROLLER_HANDLE_T controller, 6713545Sjulian SCI_CONTROLLER_ERROR error) 6813545Sjulian{ 6913545Sjulian 701573Srgrimes isci_log_message(0, "ISCI", "scif_cb_controller_error: 0x%x\n", 711573Srgrimes error); 721573Srgrimes} 731573Srgrimes 7416586Sjraynard/** 7516586Sjraynard * @brief This user callback will inform the user that the controller has 7616586Sjraynard * finished the start process. 7716586Sjraynard * 7821674Sjkh * @param[in] controller This parameter specifies the controller that was 7921674Sjkh * started. 8016586Sjraynard * @param[in] completion_status This parameter specifies the results of 811573Srgrimes * the start operation. SCI_SUCCESS indicates successful 821573Srgrimes * completion. 831573Srgrimes * 841573Srgrimes * @return none 851573Srgrimes */ 861573Srgrimesvoid scif_cb_controller_start_complete(SCI_CONTROLLER_HANDLE_T controller, 871573Srgrimes SCI_STATUS completion_status) 881573Srgrimes{ 891573Srgrimes uint32_t index; 901573Srgrimes struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *) 911573Srgrimes sci_object_get_association(controller); 921573Srgrimes 931573Srgrimes isci_controller->is_started = TRUE; 941573Srgrimes 951573Srgrimes /* Set bits for all domains. We will clear them one-by-one once 961573Srgrimes * the domains complete discovery, or return error when calling 971573Srgrimes * scif_domain_discover. Once all bits are clear, we will register 981573Srgrimes * the controller with CAM. 991573Srgrimes */ 1001573Srgrimes isci_controller->initial_discovery_mask = (1 << SCI_MAX_DOMAINS) - 1; 1011573Srgrimes 1021573Srgrimes for(index = 0; index < SCI_MAX_DOMAINS; index++) { 1031573Srgrimes SCI_STATUS status; 1041573Srgrimes SCI_DOMAIN_HANDLE_T domain = 1051573Srgrimes isci_controller->domain[index].sci_object; 1061573Srgrimes 1071573Srgrimes status = scif_domain_discover( 1081573Srgrimes domain, 1091573Srgrimes scif_domain_get_suggested_discover_timeout(domain), 1101573Srgrimes DEVICE_TIMEOUT 1111573Srgrimes ); 1121573Srgrimes 1131573Srgrimes if (status != SCI_SUCCESS) 1141573Srgrimes { 1151573Srgrimes isci_controller_domain_discovery_complete( 1161573Srgrimes isci_controller, &isci_controller->domain[index]); 1171573Srgrimes } 1181573Srgrimes } 1191573Srgrimes} 1201573Srgrimes 1211573Srgrimes/** 1221573Srgrimes * @brief This user callback will inform the user that the controller has 1231573Srgrimes * finished the stop process. Note, after user calls 1241573Srgrimes * scif_controller_stop(), before user receives this controller stop 1251573Srgrimes * complete callback, user should not expect any callback from 1261573Srgrimes * framework, such like scif_cb_domain_change_notification(). 1271573Srgrimes * 1281573Srgrimes * @param[in] controller This parameter specifies the controller that was 1291573Srgrimes * stopped. 1301573Srgrimes * @param[in] completion_status This parameter specifies the results of 1311573Srgrimes * the stop operation. SCI_SUCCESS indicates successful 1321573Srgrimes * completion. 1331573Srgrimes * 1341573Srgrimes * @return none 1351573Srgrimes */ 1361573Srgrimesvoid scif_cb_controller_stop_complete(SCI_CONTROLLER_HANDLE_T controller, 1371573Srgrimes SCI_STATUS completion_status) 1381573Srgrimes{ 1391573Srgrimes struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *) 1401573Srgrimes sci_object_get_association(controller); 1411573Srgrimes 1421573Srgrimes isci_controller->is_started = FALSE; 1431573Srgrimes} 1441573Srgrimes 1451573Srgrimes/** 1461573Srgrimes * @brief This method will be invoked to allocate memory dynamically. 1471573Srgrimes * 1481573Srgrimes * @param[in] controller This parameter represents the controller 1491573Srgrimes * object for which to allocate memory. 1501573Srgrimes * @param[out] mde This parameter represents the memory descriptor to 1511573Srgrimes * be filled in by the user that will reference the newly 1521573Srgrimes * allocated memory. 1531573Srgrimes * 1541573Srgrimes * @return none 1551573Srgrimes */ 1561573Srgrimesvoid scif_cb_controller_allocate_memory(SCI_CONTROLLER_HANDLE_T controller, 1571573Srgrimes SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde) 1581573Srgrimes{ 1591573Srgrimes 1601573Srgrimes} 1611573Srgrimes 1621573Srgrimes/** 1631573Srgrimes * @brief This method will be invoked to allocate memory dynamically. 1641573Srgrimes * 1651573Srgrimes * @param[in] controller This parameter represents the controller 1661573Srgrimes * object for which to allocate memory. 1671573Srgrimes * @param[out] mde This parameter represents the memory descriptor to 1681573Srgrimes * be filled in by the user that will reference the newly 1691573Srgrimes * allocated memory. 1701573Srgrimes * 1711573Srgrimes * @return none 1721573Srgrimes */ 1731573Srgrimesvoid scif_cb_controller_free_memory(SCI_CONTROLLER_HANDLE_T controller, 1741573Srgrimes SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde) 1751573Srgrimes{ 1761573Srgrimes 1771573Srgrimes} 1781573Srgrimes 1791573Srgrimesvoid isci_controller_construct(struct ISCI_CONTROLLER *controller, 1801573Srgrimes struct isci_softc *isci) 1811573Srgrimes{ 1821573Srgrimes SCI_CONTROLLER_HANDLE_T scif_controller_handle; 1831573Srgrimes 1841573Srgrimes scif_library_allocate_controller(isci->sci_library_handle, 1851573Srgrimes &scif_controller_handle); 1861573Srgrimes 1871573Srgrimes scif_controller_construct(isci->sci_library_handle, 1881573Srgrimes scif_controller_handle, NULL); 1891573Srgrimes 1901573Srgrimes controller->isci = isci; 1911573Srgrimes controller->scif_controller_handle = scif_controller_handle; 1921573Srgrimes 1931573Srgrimes /* This allows us to later use 1941573Srgrimes * sci_object_get_association(scif_controller_handle) 1951573Srgrimes * inside of a callback routine to get our struct ISCI_CONTROLLER object 1961573Srgrimes */ 1971573Srgrimes sci_object_set_association(scif_controller_handle, (void *)controller); 1981573Srgrimes 1991573Srgrimes controller->is_started = FALSE; 2001573Srgrimes controller->is_frozen = FALSE; 2011573Srgrimes controller->sim = NULL; 2021573Srgrimes controller->initial_discovery_mask = 0; 2031573Srgrimes 2041573Srgrimes sci_fast_list_init(&controller->pending_device_reset_list); 2051573Srgrimes 2061573Srgrimes mtx_init(&controller->lock, "isci", NULL, MTX_DEF); 2071573Srgrimes 2081573Srgrimes uint32_t domain_index; 2091573Srgrimes 2101573Srgrimes for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++) { 2111573Srgrimes isci_domain_construct( &controller->domain[domain_index], 2121573Srgrimes domain_index, controller); 2131573Srgrimes } 2141573Srgrimes 2151573Srgrimes controller->timer_memory = malloc( 2161573Srgrimes sizeof(struct ISCI_TIMER) * SCI_MAX_TIMERS, M_ISCI, 2171573Srgrimes M_NOWAIT | M_ZERO); 2181573Srgrimes 2191573Srgrimes sci_pool_initialize(controller->timer_pool); 2201573Srgrimes 2211573Srgrimes struct ISCI_TIMER *timer = (struct ISCI_TIMER *) 2221573Srgrimes controller->timer_memory; 2231573Srgrimes 2241573Srgrimes for ( int i = 0; i < SCI_MAX_TIMERS; i++ ) { 2251573Srgrimes sci_pool_put(controller->timer_pool, timer++); 2261573Srgrimes } 2271573Srgrimes} 2281573Srgrimes 2291573SrgrimesSCI_STATUS isci_controller_initialize(struct ISCI_CONTROLLER *controller) 2301573Srgrimes{ 2311573Srgrimes SCIC_USER_PARAMETERS_T scic_user_parameters; 2321573Srgrimes SCI_CONTROLLER_HANDLE_T scic_controller_handle; 2331573Srgrimes unsigned long tunable; 2341573Srgrimes int i; 2351573Srgrimes 2361573Srgrimes scic_controller_handle = 2371573Srgrimes scif_controller_get_scic_handle(controller->scif_controller_handle); 2381573Srgrimes 2391573Srgrimes if (controller->isci->oem_parameters_found == TRUE) 2401573Srgrimes { 2411573Srgrimes scic_oem_parameters_set( 2421573Srgrimes scic_controller_handle, 2431573Srgrimes &controller->oem_parameters, 2441573Srgrimes (uint8_t)(controller->oem_parameters_version)); 2451573Srgrimes } 2461573Srgrimes 2471573Srgrimes scic_user_parameters_get(scic_controller_handle, &scic_user_parameters); 2481573Srgrimes 2491573Srgrimes if (TUNABLE_ULONG_FETCH("hw.isci.no_outbound_task_timeout", &tunable)) 2501573Srgrimes scic_user_parameters.sds1.no_outbound_task_timeout = 2511573Srgrimes (uint8_t)tunable; 2521573Srgrimes 2531573Srgrimes if (TUNABLE_ULONG_FETCH("hw.isci.ssp_max_occupancy_timeout", &tunable)) 2541573Srgrimes scic_user_parameters.sds1.ssp_max_occupancy_timeout = 2551573Srgrimes (uint16_t)tunable; 2561573Srgrimes 2571573Srgrimes if (TUNABLE_ULONG_FETCH("hw.isci.stp_max_occupancy_timeout", &tunable)) 2581573Srgrimes scic_user_parameters.sds1.stp_max_occupancy_timeout = 2591573Srgrimes (uint16_t)tunable; 2601573Srgrimes 2611573Srgrimes if (TUNABLE_ULONG_FETCH("hw.isci.ssp_inactivity_timeout", &tunable)) 2621573Srgrimes scic_user_parameters.sds1.ssp_inactivity_timeout = 2631573Srgrimes (uint16_t)tunable; 2641573Srgrimes 2651573Srgrimes if (TUNABLE_ULONG_FETCH("hw.isci.stp_inactivity_timeout", &tunable)) 2661573Srgrimes scic_user_parameters.sds1.stp_inactivity_timeout = 2671573Srgrimes (uint16_t)tunable; 2681573Srgrimes 2691573Srgrimes if (TUNABLE_ULONG_FETCH("hw.isci.max_speed_generation", &tunable)) 2701573Srgrimes for (i = 0; i < SCI_MAX_PHYS; i++) 2711573Srgrimes scic_user_parameters.sds1.phys[i].max_speed_generation = 2721573Srgrimes (uint8_t)tunable; 2731573Srgrimes 2741573Srgrimes scic_user_parameters_set(scic_controller_handle, &scic_user_parameters); 2751573Srgrimes 2761573Srgrimes /* Scheduler bug in SCU requires SCIL to reserve some task contexts as a 2771573Srgrimes * a workaround - one per domain. 2781573Srgrimes */ 27921674Sjkh controller->queue_depth = SCI_MAX_IO_REQUESTS - SCI_MAX_DOMAINS; 2801573Srgrimes 2811573Srgrimes if (TUNABLE_INT_FETCH("hw.isci.controller_queue_depth", 2821573Srgrimes &controller->queue_depth)) { 2831573Srgrimes controller->queue_depth = max(1, min(controller->queue_depth, 2841573Srgrimes SCI_MAX_IO_REQUESTS - SCI_MAX_DOMAINS)); 2851573Srgrimes } 2861573Srgrimes 2871573Srgrimes /* Reserve one request so that we can ensure we have one available TC 2881573Srgrimes * to do internal device resets. 2891573Srgrimes */ 2901573Srgrimes controller->sim_queue_depth = controller->queue_depth - 1; 2911573Srgrimes 2921573Srgrimes /* Although we save one TC to do internal device resets, it is possible 2931573Srgrimes * we could end up using several TCs for simultaneous device resets 2941573Srgrimes * while at the same time having CAM fill our controller queue. To 2951573Srgrimes * simulate this condition, and how our driver handles it, we can set 2961573Srgrimes * this io_shortage parameter, which will tell CAM that we have a 2971573Srgrimes * large queue depth than we really do. 2981573Srgrimes */ 2991573Srgrimes uint32_t io_shortage = 0; 3001573Srgrimes TUNABLE_INT_FETCH("hw.isci.io_shortage", &io_shortage); 30121674Sjkh controller->sim_queue_depth += io_shortage; 3021573Srgrimes 3031573Srgrimes return (scif_controller_initialize(controller->scif_controller_handle)); 3041573Srgrimes} 3051573Srgrimes 3061573Srgrimesint isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller) 3071573Srgrimes{ 3081573Srgrimes int error; 3091573Srgrimes device_t device = controller->isci->device; 3101573Srgrimes uint32_t max_segment_size = isci_io_request_get_max_io_size(); 3111573Srgrimes uint32_t status = 0; 3121573Srgrimes struct ISCI_MEMORY *uncached_controller_memory = 3131573Srgrimes &controller->uncached_controller_memory; 3141573Srgrimes struct ISCI_MEMORY *cached_controller_memory = 3151573Srgrimes &controller->cached_controller_memory; 3161573Srgrimes struct ISCI_MEMORY *request_memory = 3171573Srgrimes &controller->request_memory; 3181573Srgrimes POINTER_UINT virtual_address; 3191573Srgrimes bus_addr_t physical_address; 3201573Srgrimes 32114727Sfenner controller->mdl = sci_controller_get_memory_descriptor_list_handle( 3221573Srgrimes controller->scif_controller_handle); 3231573Srgrimes 3241573Srgrimes uncached_controller_memory->size = sci_mdl_decorator_get_memory_size( 3251573Srgrimes controller->mdl, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS); 3261573Srgrimes 3271573Srgrimes error = isci_allocate_dma_buffer(device, uncached_controller_memory); 3281573Srgrimes 32921674Sjkh if (error != 0) 33021674Sjkh return (error); 33121674Sjkh 33221674Sjkh sci_mdl_decorator_assign_memory( controller->mdl, 3331573Srgrimes SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS, 3341573Srgrimes uncached_controller_memory->virtual_address, 3351573Srgrimes uncached_controller_memory->physical_address); 3361573Srgrimes 3371573Srgrimes cached_controller_memory->size = sci_mdl_decorator_get_memory_size( 3381573Srgrimes controller->mdl, 3391573Srgrimes SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS 3401573Srgrimes ); 3411573Srgrimes 3421573Srgrimes error = isci_allocate_dma_buffer(device, cached_controller_memory); 3431573Srgrimes 3441573Srgrimes if (error != 0) 3451573Srgrimes return (error); 3461573Srgrimes 3471573Srgrimes sci_mdl_decorator_assign_memory(controller->mdl, 3481573Srgrimes SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS, 3491573Srgrimes cached_controller_memory->virtual_address, 3501573Srgrimes cached_controller_memory->physical_address); 3511573Srgrimes 3521573Srgrimes request_memory->size = 3531573Srgrimes controller->queue_depth * isci_io_request_get_object_size(); 3541573Srgrimes 3551573Srgrimes error = isci_allocate_dma_buffer(device, request_memory); 3561573Srgrimes 3571573Srgrimes if (error != 0) 3581573Srgrimes return (error); 3591573Srgrimes 3601573Srgrimes /* For STP PIO testing, we want to ensure we can force multiple SGLs 3611573Srgrimes * since this has been a problem area in SCIL. This tunable parameter 3621573Srgrimes * will allow us to force DMA segments to a smaller size, ensuring 3631573Srgrimes * that even if a physically contiguous buffer is attached to this 3641573Srgrimes * I/O, the DMA subsystem will pass us multiple segments in our DMA 3651573Srgrimes * load callback. 3661573Srgrimes */ 3671573Srgrimes TUNABLE_INT_FETCH("hw.isci.max_segment_size", &max_segment_size); 3681573Srgrimes 3691573Srgrimes /* Create DMA tag for our I/O requests. Then we can create DMA maps based off 3701573Srgrimes * of this tag and store them in each of our ISCI_IO_REQUEST objects. This 3711573Srgrimes * will enable better performance than creating the DMA maps everytime we get 3721573Srgrimes * an I/O. 3731573Srgrimes */ 3741573Srgrimes status = bus_dma_tag_create(bus_get_dma_tag(device), 0x1, 0x0, 37521674Sjkh BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 37621674Sjkh isci_io_request_get_max_io_size(), 37721674Sjkh SCI_MAX_SCATTER_GATHER_ELEMENTS, max_segment_size, 0, NULL, NULL, 37821674Sjkh &controller->buffer_dma_tag); 37921674Sjkh 38021674Sjkh sci_pool_initialize(controller->request_pool); 38121674Sjkh 38221674Sjkh virtual_address = request_memory->virtual_address; 38321674Sjkh physical_address = request_memory->physical_address; 3841573Srgrimes 3851573Srgrimes for (int i = 0; i < controller->queue_depth; i++) { 3861573Srgrimes struct ISCI_REQUEST *request = 3871573Srgrimes (struct ISCI_REQUEST *)virtual_address; 3881573Srgrimes 38921674Sjkh isci_request_construct(request, 39021674Sjkh controller->scif_controller_handle, 39121674Sjkh controller->buffer_dma_tag, physical_address); 3921573Srgrimes 39321674Sjkh sci_pool_put(controller->request_pool, request); 39421674Sjkh 39521674Sjkh virtual_address += isci_request_get_object_size(); 3961573Srgrimes physical_address += isci_request_get_object_size(); 39721674Sjkh } 39821674Sjkh 39921674Sjkh uint32_t remote_device_size = sizeof(struct ISCI_REMOTE_DEVICE) + 40021674Sjkh scif_remote_device_get_object_size(); 40121674Sjkh 40221674Sjkh controller->remote_device_memory = (uint8_t *) malloc( 40321674Sjkh remote_device_size * SCI_MAX_REMOTE_DEVICES, M_ISCI, 40421674Sjkh M_NOWAIT | M_ZERO); 40521674Sjkh 40621674Sjkh sci_pool_initialize(controller->remote_device_pool); 40721674Sjkh 40821674Sjkh uint8_t *remote_device_memory_ptr = controller->remote_device_memory; 40921674Sjkh 41021674Sjkh for (int i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { 41121674Sjkh struct ISCI_REMOTE_DEVICE *remote_device = 41221674Sjkh (struct ISCI_REMOTE_DEVICE *)remote_device_memory_ptr; 41321674Sjkh 41421674Sjkh controller->remote_device[i] = NULL; 41521674Sjkh remote_device->index = i; 41621674Sjkh remote_device->is_resetting = FALSE; 41721674Sjkh remote_device->frozen_lun_mask = 0; 41821674Sjkh sci_fast_list_element_init(remote_device, 41921674Sjkh &remote_device->pending_device_reset_element); 42021674Sjkh sci_pool_put(controller->remote_device_pool, remote_device); 42121674Sjkh remote_device_memory_ptr += remote_device_size; 42221674Sjkh } 42313545Sjulian 42413545Sjulian return (0); 42513545Sjulian} 4261573Srgrimes 42713545Sjulianvoid isci_controller_start(void *controller_handle) 42813545Sjulian{ 42913545Sjulian struct ISCI_CONTROLLER *controller = 43013545Sjulian (struct ISCI_CONTROLLER *)controller_handle; 4311573Srgrimes SCI_CONTROLLER_HANDLE_T scif_controller_handle = 43213545Sjulian controller->scif_controller_handle; 4331573Srgrimes 4341573Srgrimes scif_controller_start(scif_controller_handle, 4351573Srgrimes scif_controller_get_suggested_start_timeout(scif_controller_handle)); 43613545Sjulian 43713545Sjulian scic_controller_enable_interrupts( 43813545Sjulian scif_controller_get_scic_handle(controller->scif_controller_handle)); 43913545Sjulian} 4401573Srgrimes 44113545Sjulianvoid isci_controller_domain_discovery_complete( 4421573Srgrimes struct ISCI_CONTROLLER *isci_controller, struct ISCI_DOMAIN *isci_domain) 4431573Srgrimes{ 44421674Sjkh if (isci_controller->sim == NULL) 44521674Sjkh { 44621674Sjkh /* Controller has not been attached to CAM yet. We'll clear 4471573Srgrimes * the discovery bit for this domain, then check if all bits 4481573Srgrimes * are now clear. That would indicate that all domains are 4491573Srgrimes * done with discovery and we can then attach the controller 4501573Srgrimes * to CAM. 4511573Srgrimes */ 4521573Srgrimes 4531573Srgrimes isci_controller->initial_discovery_mask &= 4541573Srgrimes ~(1 << isci_domain->index); 4551573Srgrimes 4561573Srgrimes if (isci_controller->initial_discovery_mask == 0) { 4571573Srgrimes struct isci_softc *driver = isci_controller->isci; 4581573Srgrimes uint8_t next_index = isci_controller->index + 1; 4591573Srgrimes 4601573Srgrimes isci_controller_attach_to_cam(isci_controller); 4611573Srgrimes 4621573Srgrimes if (next_index < driver->controller_count) { 4631573Srgrimes /* There are more controllers that need to 4641573Srgrimes * start. So start the next one. 4651573Srgrimes */ 4661573Srgrimes isci_controller_start( 4671573Srgrimes &driver->controllers[next_index]); 4681573Srgrimes } 4691573Srgrimes else 4701573Srgrimes { 4711573Srgrimes /* All controllers have been started and completed discovery. 4721573Srgrimes * Disestablish the config hook while will signal to the 4731573Srgrimes * kernel during boot that it is safe to try to find and 4741573Srgrimes * mount the root partition. 4751573Srgrimes */ 4761573Srgrimes config_intrhook_disestablish( 4771573Srgrimes &driver->config_hook); 4781573Srgrimes } 4791573Srgrimes } 4801573Srgrimes } 4811573Srgrimes} 4821573Srgrimes 4831573Srgrimesint isci_controller_attach_to_cam(struct ISCI_CONTROLLER *controller) 4841573Srgrimes{ 4851573Srgrimes struct isci_softc *isci = controller->isci; 4861573Srgrimes device_t parent = device_get_parent(isci->device); 4871573Srgrimes int unit = device_get_unit(isci->device); 4881573Srgrimes struct cam_devq *isci_devq = cam_simq_alloc(controller->sim_queue_depth); 4891573Srgrimes 4901573Srgrimes if(isci_devq == NULL) { 4911573Srgrimes isci_log_message(0, "ISCI", "isci_devq is NULL \n"); 4921573Srgrimes return (-1); 49321674Sjkh } 49421674Sjkh 4951573Srgrimes controller->sim = cam_sim_alloc(isci_action, isci_poll, "isci", 4961573Srgrimes controller, unit, &controller->lock, controller->sim_queue_depth, 4971573Srgrimes controller->sim_queue_depth, isci_devq); 4981573Srgrimes 4991573Srgrimes if(controller->sim == NULL) { 5001573Srgrimes isci_log_message(0, "ISCI", "cam_sim_alloc... fails\n"); 5011573Srgrimes cam_simq_free(isci_devq); 5021573Srgrimes return (-1); 5031573Srgrimes } 5041573Srgrimes 5051573Srgrimes if(xpt_bus_register(controller->sim, parent, controller->index) 50621674Sjkh != CAM_SUCCESS) { 5071573Srgrimes isci_log_message(0, "ISCI", "xpt_bus_register...fails \n"); 5081573Srgrimes cam_sim_free(controller->sim, TRUE); 5091573Srgrimes mtx_unlock(&controller->lock); 5101573Srgrimes return (-1); 5111573Srgrimes } 5121573Srgrimes 5131573Srgrimes if(xpt_create_path(&controller->path, NULL, 5141573Srgrimes cam_sim_path(controller->sim), CAM_TARGET_WILDCARD, 5151573Srgrimes CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 5161573Srgrimes isci_log_message(0, "ISCI", "xpt_create_path....fails\n"); 5171573Srgrimes xpt_bus_deregister(cam_sim_path(controller->sim)); 5181573Srgrimes cam_sim_free(controller->sim, TRUE); 5191573Srgrimes mtx_unlock(&controller->lock); 5201573Srgrimes return (-1); 5211573Srgrimes } 5221573Srgrimes 5231573Srgrimes return (0); 5241573Srgrimes} 5251573Srgrimes 5261573Srgrimesvoid isci_poll(struct cam_sim *sim) 5271573Srgrimes{ 5281573Srgrimes struct ISCI_CONTROLLER *controller = 5291573Srgrimes (struct ISCI_CONTROLLER *)cam_sim_softc(sim); 5301573Srgrimes 5311573Srgrimes isci_interrupt_poll_handler(controller); 53221674Sjkh} 53321674Sjkh 53421674Sjkhvoid isci_action(struct cam_sim *sim, union ccb *ccb) 53521674Sjkh{ 53621674Sjkh struct ISCI_CONTROLLER *controller = 53721674Sjkh (struct ISCI_CONTROLLER *)cam_sim_softc(sim); 53821674Sjkh 53921674Sjkh switch ( ccb->ccb_h.func_code ) { 54021674Sjkh case XPT_PATH_INQ: 5411573Srgrimes { 5421573Srgrimes struct ccb_pathinq *cpi = &ccb->cpi; 5431573Srgrimes int bus = cam_sim_bus(sim); 5441573Srgrimes ccb->ccb_h.ccb_sim_ptr = sim; 5451573Srgrimes cpi->version_num = 1; 5461573Srgrimes cpi->hba_inquiry = PI_TAG_ABLE; 5471573Srgrimes cpi->target_sprt = 0; 5481573Srgrimes cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; 5491573Srgrimes cpi->hba_eng_cnt = 0; 5501573Srgrimes cpi->max_target = SCI_MAX_REMOTE_DEVICES - 1; 5511573Srgrimes cpi->max_lun = ISCI_MAX_LUN; 5521573Srgrimes#if __FreeBSD_version >= 800102 5531573Srgrimes cpi->maxio = isci_io_request_get_max_io_size(); 5541573Srgrimes#endif 5551573Srgrimes cpi->unit_number = cam_sim_unit(sim); 5561573Srgrimes cpi->bus_id = bus; 5571573Srgrimes cpi->initiator_id = SCI_MAX_REMOTE_DEVICES; 55821674Sjkh cpi->base_transfer_speed = 300000; 5591573Srgrimes strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 5601573Srgrimes strncpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN); 5611573Srgrimes strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 5621573Srgrimes cpi->transport = XPORT_SAS; 5631573Srgrimes cpi->transport_version = 0; 5641573Srgrimes cpi->protocol = PROTO_SCSI; 5651573Srgrimes cpi->protocol_version = SCSI_REV_SPC2; 5661573Srgrimes cpi->ccb_h.status = CAM_REQ_CMP; 5671573Srgrimes xpt_done(ccb); 56821674Sjkh } 5691573Srgrimes break; 5701573Srgrimes case XPT_GET_TRAN_SETTINGS: 5711573Srgrimes { 5721573Srgrimes struct ccb_trans_settings *general_settings = &ccb->cts; 5731573Srgrimes struct ccb_trans_settings_sas *sas_settings = 5741573Srgrimes &general_settings->xport_specific.sas; 5751573Srgrimes struct ccb_trans_settings_scsi *scsi_settings = 5761573Srgrimes &general_settings->proto_specific.scsi; 5771573Srgrimes struct ISCI_REMOTE_DEVICE *remote_device; 5781573Srgrimes 5791573Srgrimes remote_device = controller->remote_device[ccb->ccb_h.target_id]; 5801573Srgrimes 5811573Srgrimes if (remote_device == NULL) { 5821573Srgrimes ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 5837033Sbde ccb->ccb_h.status &= ~CAM_STATUS_MASK; 5841573Srgrimes ccb->ccb_h.status |= CAM_DEV_NOT_THERE; 5857033Sbde xpt_done(ccb); 5867033Sbde break; 5871573Srgrimes } 5881573Srgrimes 5897033Sbde general_settings->protocol = PROTO_SCSI; 5907033Sbde general_settings->transport = XPORT_SAS; 5917033Sbde general_settings->protocol_version = SCSI_REV_SPC2; 5921573Srgrimes general_settings->transport_version = 0; 5937033Sbde scsi_settings->valid = CTS_SCSI_VALID_TQ; 59421674Sjkh scsi_settings->flags = CTS_SCSI_FLAGS_TAG_ENB; 5957033Sbde ccb->ccb_h.status &= ~CAM_STATUS_MASK; 59621674Sjkh ccb->ccb_h.status |= CAM_REQ_CMP; 5971573Srgrimes 5981573Srgrimes sas_settings->bitrate = 5991573Srgrimes isci_remote_device_get_bitrate(remote_device); 6001573Srgrimes 6011573Srgrimes if (sas_settings->bitrate != 0) 6021573Srgrimes sas_settings->valid = CTS_SAS_VALID_SPEED; 6031573Srgrimes 6041573Srgrimes xpt_done(ccb); 6051573Srgrimes } 6061573Srgrimes break; 6071573Srgrimes case XPT_SCSI_IO: 6081573Srgrimes isci_io_request_execute_scsi_io(ccb, controller); 6091573Srgrimes break; 6101573Srgrimes#if __FreeBSD_version >= 900026 6111573Srgrimes case XPT_SMP_IO: 6121573Srgrimes isci_io_request_execute_smp_io(ccb, controller); 6131573Srgrimes break; 6141573Srgrimes#endif 6151573Srgrimes case XPT_SET_TRAN_SETTINGS: 6161573Srgrimes ccb->ccb_h.status &= ~CAM_STATUS_MASK; 6171573Srgrimes ccb->ccb_h.status |= CAM_REQ_CMP; 6188870Srgrimes xpt_done(ccb); 6191573Srgrimes break; 6201573Srgrimes case XPT_CALC_GEOMETRY: 6211573Srgrimes cam_calc_geometry(&ccb->ccg, /*extended*/1); 6221573Srgrimes xpt_done(ccb); 6231573Srgrimes break; 6241573Srgrimes case XPT_RESET_DEV: 6251573Srgrimes { 6261573Srgrimes struct ISCI_REMOTE_DEVICE *remote_device = 6271573Srgrimes controller->remote_device[ccb->ccb_h.target_id]; 6281573Srgrimes 6291573Srgrimes if (remote_device != NULL) 6301573Srgrimes isci_remote_device_reset(remote_device, ccb); 6311573Srgrimes else { 6321573Srgrimes ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 6331573Srgrimes ccb->ccb_h.status &= ~CAM_STATUS_MASK; 6341573Srgrimes ccb->ccb_h.status |= CAM_DEV_NOT_THERE; 6351573Srgrimes xpt_done(ccb); 6361573Srgrimes } 6371573Srgrimes } 6381573Srgrimes break; 6391573Srgrimes case XPT_RESET_BUS: 6401573Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 6411573Srgrimes xpt_done(ccb); 6421573Srgrimes break; 6431573Srgrimes default: 6441573Srgrimes isci_log_message(0, "ISCI", "Unhandled func_code 0x%x\n", 6451573Srgrimes ccb->ccb_h.func_code); 64621674Sjkh ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 6471573Srgrimes ccb->ccb_h.status &= ~CAM_STATUS_MASK; 64821674Sjkh ccb->ccb_h.status |= CAM_REQ_INVALID; 6491573Srgrimes xpt_done(ccb); 65021674Sjkh break; 6511573Srgrimes } 65221674Sjkh} 6531573Srgrimes 6541573Srgrimes