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