1230557Sjimharris/*-
2230557Sjimharris * BSD LICENSE
3230557Sjimharris *
4230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
5230557Sjimharris * All rights reserved.
6230557Sjimharris *
7230557Sjimharris * Redistribution and use in source and binary forms, with or without
8230557Sjimharris * modification, are permitted provided that the following conditions
9230557Sjimharris * are met:
10230557Sjimharris *
11230557Sjimharris *   * Redistributions of source code must retain the above copyright
12230557Sjimharris *     notice, this list of conditions and the following disclaimer.
13230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
14230557Sjimharris *     notice, this list of conditions and the following disclaimer in
15230557Sjimharris *     the documentation and/or other materials provided with the
16230557Sjimharris *     distribution.
17230557Sjimharris *
18230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29230557Sjimharris */
30230557Sjimharris
31230557Sjimharris#include <sys/cdefs.h>
32230557Sjimharris__FBSDID("$FreeBSD$");
33230557Sjimharris
34230557Sjimharris#include <dev/isci/isci.h>
35230557Sjimharris
36230557Sjimharris#include <sys/conf.h>
37230557Sjimharris#include <sys/malloc.h>
38230557Sjimharris
39233371Sjimharris#include <cam/cam_periph.h>
40233371Sjimharris#include <cam/cam_xpt_periph.h>
41233371Sjimharris
42230557Sjimharris#include <dev/isci/scil/sci_memory_descriptor_list.h>
43230557Sjimharris#include <dev/isci/scil/sci_memory_descriptor_list_decorator.h>
44230557Sjimharris
45230557Sjimharris#include <dev/isci/scil/scif_controller.h>
46230557Sjimharris#include <dev/isci/scil/scif_library.h>
47230557Sjimharris#include <dev/isci/scil/scif_io_request.h>
48230557Sjimharris#include <dev/isci/scil/scif_task_request.h>
49230557Sjimharris#include <dev/isci/scil/scif_remote_device.h>
50230557Sjimharris#include <dev/isci/scil/scif_domain.h>
51230557Sjimharris#include <dev/isci/scil/scif_user_callback.h>
52240965Sjimharris#include <dev/isci/scil/scic_sgpio.h>
53230557Sjimharris
54240965Sjimharris#include <dev/led/led.h>
55240965Sjimharris
56230557Sjimharrisvoid isci_action(struct cam_sim *sim, union ccb *ccb);
57230557Sjimharrisvoid isci_poll(struct cam_sim *sim);
58230557Sjimharris
59230557Sjimharris#define ccb_sim_ptr sim_priv.entries[0].ptr
60230557Sjimharris
61230557Sjimharris/**
62230557Sjimharris * @brief This user callback will inform the user that the controller has
63230557Sjimharris *        had a serious unexpected error.  The user should not the error,
64230557Sjimharris *        disable interrupts, and wait for current ongoing processing to
65230557Sjimharris *        complete.  Subsequently, the user should reset the controller.
66230557Sjimharris *
67230557Sjimharris * @param[in]  controller This parameter specifies the controller that had
68230557Sjimharris *                        an error.
69230557Sjimharris *
70230557Sjimharris * @return none
71230557Sjimharris */
72230557Sjimharrisvoid scif_cb_controller_error(SCI_CONTROLLER_HANDLE_T controller,
73230557Sjimharris    SCI_CONTROLLER_ERROR error)
74230557Sjimharris{
75230557Sjimharris
76230557Sjimharris	isci_log_message(0, "ISCI", "scif_cb_controller_error: 0x%x\n",
77230557Sjimharris	    error);
78230557Sjimharris}
79230557Sjimharris
80230557Sjimharris/**
81230557Sjimharris * @brief This user callback will inform the user that the controller has
82230557Sjimharris *        finished the start process.
83230557Sjimharris *
84230557Sjimharris * @param[in]  controller This parameter specifies the controller that was
85230557Sjimharris *             started.
86230557Sjimharris * @param[in]  completion_status This parameter specifies the results of
87230557Sjimharris *             the start operation.  SCI_SUCCESS indicates successful
88230557Sjimharris *             completion.
89230557Sjimharris *
90230557Sjimharris * @return none
91230557Sjimharris */
92230557Sjimharrisvoid scif_cb_controller_start_complete(SCI_CONTROLLER_HANDLE_T controller,
93230557Sjimharris    SCI_STATUS completion_status)
94230557Sjimharris{
95230557Sjimharris	uint32_t index;
96230557Sjimharris	struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
97230557Sjimharris	    sci_object_get_association(controller);
98230557Sjimharris
99230557Sjimharris	isci_controller->is_started = TRUE;
100230557Sjimharris
101230557Sjimharris	/* Set bits for all domains.  We will clear them one-by-one once
102230557Sjimharris	 *  the domains complete discovery, or return error when calling
103230557Sjimharris	 *  scif_domain_discover.  Once all bits are clear, we will register
104230557Sjimharris	 *  the controller with CAM.
105230557Sjimharris	 */
106230557Sjimharris	isci_controller->initial_discovery_mask = (1 << SCI_MAX_DOMAINS) - 1;
107230557Sjimharris
108230557Sjimharris	for(index = 0; index < SCI_MAX_DOMAINS; index++) {
109230557Sjimharris		SCI_STATUS status;
110230557Sjimharris		SCI_DOMAIN_HANDLE_T domain =
111230557Sjimharris		    isci_controller->domain[index].sci_object;
112230557Sjimharris
113230557Sjimharris		status = scif_domain_discover(
114230557Sjimharris			domain,
115230557Sjimharris			scif_domain_get_suggested_discover_timeout(domain),
116230557Sjimharris			DEVICE_TIMEOUT
117230557Sjimharris		);
118230557Sjimharris
119230557Sjimharris		if (status != SCI_SUCCESS)
120230557Sjimharris		{
121230557Sjimharris			isci_controller_domain_discovery_complete(
122230557Sjimharris			    isci_controller, &isci_controller->domain[index]);
123230557Sjimharris		}
124230557Sjimharris	}
125230557Sjimharris}
126230557Sjimharris
127230557Sjimharris/**
128230557Sjimharris * @brief This user callback will inform the user that the controller has
129230557Sjimharris *        finished the stop process. Note, after user calls
130230557Sjimharris *        scif_controller_stop(), before user receives this controller stop
131230557Sjimharris *        complete callback, user should not expect any callback from
132230557Sjimharris *        framework, such like scif_cb_domain_change_notification().
133230557Sjimharris *
134230557Sjimharris * @param[in]  controller This parameter specifies the controller that was
135230557Sjimharris *             stopped.
136230557Sjimharris * @param[in]  completion_status This parameter specifies the results of
137230557Sjimharris *             the stop operation.  SCI_SUCCESS indicates successful
138230557Sjimharris *             completion.
139230557Sjimharris *
140230557Sjimharris * @return none
141230557Sjimharris */
142230557Sjimharrisvoid scif_cb_controller_stop_complete(SCI_CONTROLLER_HANDLE_T controller,
143230557Sjimharris    SCI_STATUS completion_status)
144230557Sjimharris{
145230557Sjimharris	struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
146230557Sjimharris	    sci_object_get_association(controller);
147230557Sjimharris
148230557Sjimharris	isci_controller->is_started = FALSE;
149230557Sjimharris}
150230557Sjimharris
151239545Sjimharrisstatic void
152239545Sjimharrisisci_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
153239545Sjimharris{
154239545Sjimharris	SCI_PHYSICAL_ADDRESS *phys_addr = arg;
155239545Sjimharris
156239545Sjimharris	*phys_addr = seg[0].ds_addr;
157239545Sjimharris}
158239545Sjimharris
159230557Sjimharris/**
160230557Sjimharris * @brief This method will be invoked to allocate memory dynamically.
161230557Sjimharris *
162230557Sjimharris * @param[in]  controller This parameter represents the controller
163230557Sjimharris *             object for which to allocate memory.
164230557Sjimharris * @param[out] mde This parameter represents the memory descriptor to
165230557Sjimharris *             be filled in by the user that will reference the newly
166230557Sjimharris *             allocated memory.
167230557Sjimharris *
168230557Sjimharris * @return none
169230557Sjimharris */
170230557Sjimharrisvoid scif_cb_controller_allocate_memory(SCI_CONTROLLER_HANDLE_T controller,
171230557Sjimharris    SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde)
172230557Sjimharris{
173239545Sjimharris	struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
174239545Sjimharris	    sci_object_get_association(controller);
175230557Sjimharris
176239545Sjimharris	/*
177239545Sjimharris	 * Note this routine is only used for buffers needed to translate
178239545Sjimharris	 * SCSI UNMAP commands to ATA DSM commands for SATA disks.
179239545Sjimharris	 *
180239545Sjimharris	 * We first try to pull a buffer from the controller's pool, and only
181239545Sjimharris	 * call contigmalloc if one isn't there.
182239545Sjimharris	 */
183239545Sjimharris	if (!sci_pool_empty(isci_controller->unmap_buffer_pool)) {
184239545Sjimharris		sci_pool_get(isci_controller->unmap_buffer_pool,
185239545Sjimharris		    mde->virtual_address);
186239545Sjimharris	} else
187239545Sjimharris		mde->virtual_address = contigmalloc(PAGE_SIZE,
188239545Sjimharris		    M_ISCI, M_NOWAIT, 0, BUS_SPACE_MAXADDR,
189239545Sjimharris		    mde->constant_memory_alignment, 0);
190239545Sjimharris
191239545Sjimharris	if (mde->virtual_address != NULL)
192239545Sjimharris		bus_dmamap_load(isci_controller->buffer_dma_tag,
193239545Sjimharris		    NULL, mde->virtual_address, PAGE_SIZE,
194239545Sjimharris		    isci_single_map, &mde->physical_address,
195239545Sjimharris		    BUS_DMA_NOWAIT);
196230557Sjimharris}
197230557Sjimharris
198230557Sjimharris/**
199230557Sjimharris * @brief This method will be invoked to allocate memory dynamically.
200230557Sjimharris *
201230557Sjimharris * @param[in]  controller This parameter represents the controller
202230557Sjimharris *             object for which to allocate memory.
203230557Sjimharris * @param[out] mde This parameter represents the memory descriptor to
204230557Sjimharris *             be filled in by the user that will reference the newly
205230557Sjimharris *             allocated memory.
206230557Sjimharris *
207230557Sjimharris * @return none
208230557Sjimharris */
209230557Sjimharrisvoid scif_cb_controller_free_memory(SCI_CONTROLLER_HANDLE_T controller,
210230557Sjimharris    SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde)
211230557Sjimharris{
212239545Sjimharris	struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
213239545Sjimharris	    sci_object_get_association(controller);
214230557Sjimharris
215239545Sjimharris	/*
216239545Sjimharris	 * Put the buffer back into the controller's buffer pool, rather
217239545Sjimharris	 * than invoking configfree.  This helps reduce chance we won't
218239545Sjimharris	 * have buffers available when system is under memory pressure.
219239545Sjimharris	 */
220239545Sjimharris	sci_pool_put(isci_controller->unmap_buffer_pool,
221239545Sjimharris	    mde->virtual_address);
222230557Sjimharris}
223230557Sjimharris
224230557Sjimharrisvoid isci_controller_construct(struct ISCI_CONTROLLER *controller,
225230557Sjimharris    struct isci_softc *isci)
226230557Sjimharris{
227230557Sjimharris	SCI_CONTROLLER_HANDLE_T scif_controller_handle;
228230557Sjimharris
229230557Sjimharris	scif_library_allocate_controller(isci->sci_library_handle,
230230557Sjimharris	    &scif_controller_handle);
231230557Sjimharris
232230557Sjimharris	scif_controller_construct(isci->sci_library_handle,
233230557Sjimharris	    scif_controller_handle, NULL);
234230557Sjimharris
235230557Sjimharris	controller->isci = isci;
236230557Sjimharris	controller->scif_controller_handle = scif_controller_handle;
237230557Sjimharris
238230557Sjimharris	/* This allows us to later use
239230557Sjimharris	 *  sci_object_get_association(scif_controller_handle)
240230557Sjimharris	 * inside of a callback routine to get our struct ISCI_CONTROLLER object
241230557Sjimharris	 */
242230557Sjimharris	sci_object_set_association(scif_controller_handle, (void *)controller);
243230557Sjimharris
244230557Sjimharris	controller->is_started = FALSE;
245230557Sjimharris	controller->is_frozen = FALSE;
246235751Sjimharris	controller->release_queued_ccbs = FALSE;
247230557Sjimharris	controller->sim = NULL;
248230557Sjimharris	controller->initial_discovery_mask = 0;
249230557Sjimharris
250230557Sjimharris	sci_fast_list_init(&controller->pending_device_reset_list);
251230557Sjimharris
252230557Sjimharris	mtx_init(&controller->lock, "isci", NULL, MTX_DEF);
253230557Sjimharris
254230557Sjimharris	uint32_t domain_index;
255230557Sjimharris
256230557Sjimharris	for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++) {
257230557Sjimharris		isci_domain_construct( &controller->domain[domain_index],
258230557Sjimharris		    domain_index, controller);
259230557Sjimharris	}
260230557Sjimharris
261230557Sjimharris	controller->timer_memory = malloc(
262230557Sjimharris	    sizeof(struct ISCI_TIMER) * SCI_MAX_TIMERS, M_ISCI,
263230557Sjimharris	    M_NOWAIT | M_ZERO);
264230557Sjimharris
265230557Sjimharris	sci_pool_initialize(controller->timer_pool);
266230557Sjimharris
267230557Sjimharris	struct ISCI_TIMER *timer = (struct ISCI_TIMER *)
268230557Sjimharris	    controller->timer_memory;
269230557Sjimharris
270230557Sjimharris	for ( int i = 0; i < SCI_MAX_TIMERS; i++ ) {
271230557Sjimharris		sci_pool_put(controller->timer_pool, timer++);
272230557Sjimharris	}
273239545Sjimharris
274239545Sjimharris	sci_pool_initialize(controller->unmap_buffer_pool);
275230557Sjimharris}
276230557Sjimharris
277241403Sjimharrisstatic void isci_led_fault_func(void *priv, int onoff)
278240965Sjimharris{
279241403Sjimharris	struct ISCI_PHY *phy = priv;
280240965Sjimharris
281241403Sjimharris	/* map onoff to the fault LED */
282241403Sjimharris	phy->led_fault = onoff;
283241403Sjimharris	scic_sgpio_update_led_state(phy->handle, 1 << phy->index,
284241403Sjimharris		phy->led_fault, phy->led_locate, 0);
285241403Sjimharris}
286241403Sjimharris
287241403Sjimharrisstatic void isci_led_locate_func(void *priv, int onoff)
288241403Sjimharris{
289241403Sjimharris	struct ISCI_PHY *phy = priv;
290241403Sjimharris
291240965Sjimharris	/* map onoff to the locate LED */
292241403Sjimharris	phy->led_locate = onoff;
293241403Sjimharris	scic_sgpio_update_led_state(phy->handle, 1 << phy->index,
294241403Sjimharris		phy->led_fault, phy->led_locate, 0);
295240965Sjimharris}
296240965Sjimharris
297230557SjimharrisSCI_STATUS isci_controller_initialize(struct ISCI_CONTROLLER *controller)
298230557Sjimharris{
299230557Sjimharris	SCIC_USER_PARAMETERS_T scic_user_parameters;
300230557Sjimharris	SCI_CONTROLLER_HANDLE_T scic_controller_handle;
301240965Sjimharris	char led_name[64];
302230557Sjimharris	unsigned long tunable;
303230557Sjimharris	int i;
304230557Sjimharris
305230557Sjimharris	scic_controller_handle =
306230557Sjimharris	    scif_controller_get_scic_handle(controller->scif_controller_handle);
307230557Sjimharris
308230557Sjimharris	if (controller->isci->oem_parameters_found == TRUE)
309230557Sjimharris	{
310230557Sjimharris		scic_oem_parameters_set(
311230557Sjimharris		    scic_controller_handle,
312230557Sjimharris		    &controller->oem_parameters,
313230557Sjimharris		    (uint8_t)(controller->oem_parameters_version));
314230557Sjimharris	}
315230557Sjimharris
316230557Sjimharris	scic_user_parameters_get(scic_controller_handle, &scic_user_parameters);
317230557Sjimharris
318230557Sjimharris	if (TUNABLE_ULONG_FETCH("hw.isci.no_outbound_task_timeout", &tunable))
319230557Sjimharris		scic_user_parameters.sds1.no_outbound_task_timeout =
320230557Sjimharris		    (uint8_t)tunable;
321230557Sjimharris
322230557Sjimharris	if (TUNABLE_ULONG_FETCH("hw.isci.ssp_max_occupancy_timeout", &tunable))
323230557Sjimharris		scic_user_parameters.sds1.ssp_max_occupancy_timeout =
324230557Sjimharris		    (uint16_t)tunable;
325230557Sjimharris
326230557Sjimharris	if (TUNABLE_ULONG_FETCH("hw.isci.stp_max_occupancy_timeout", &tunable))
327230557Sjimharris		scic_user_parameters.sds1.stp_max_occupancy_timeout =
328230557Sjimharris		    (uint16_t)tunable;
329230557Sjimharris
330230557Sjimharris	if (TUNABLE_ULONG_FETCH("hw.isci.ssp_inactivity_timeout", &tunable))
331230557Sjimharris		scic_user_parameters.sds1.ssp_inactivity_timeout =
332230557Sjimharris		    (uint16_t)tunable;
333230557Sjimharris
334230557Sjimharris	if (TUNABLE_ULONG_FETCH("hw.isci.stp_inactivity_timeout", &tunable))
335230557Sjimharris		scic_user_parameters.sds1.stp_inactivity_timeout =
336230557Sjimharris		    (uint16_t)tunable;
337230557Sjimharris
338230557Sjimharris	if (TUNABLE_ULONG_FETCH("hw.isci.max_speed_generation", &tunable))
339230557Sjimharris		for (i = 0; i < SCI_MAX_PHYS; i++)
340230557Sjimharris			scic_user_parameters.sds1.phys[i].max_speed_generation =
341230557Sjimharris			    (uint8_t)tunable;
342230557Sjimharris
343230557Sjimharris	scic_user_parameters_set(scic_controller_handle, &scic_user_parameters);
344230557Sjimharris
345230557Sjimharris	/* Scheduler bug in SCU requires SCIL to reserve some task contexts as a
346230557Sjimharris	 *  a workaround - one per domain.
347230557Sjimharris	 */
348230557Sjimharris	controller->queue_depth = SCI_MAX_IO_REQUESTS - SCI_MAX_DOMAINS;
349230557Sjimharris
350230557Sjimharris	if (TUNABLE_INT_FETCH("hw.isci.controller_queue_depth",
351230557Sjimharris	    &controller->queue_depth)) {
352230557Sjimharris		controller->queue_depth = max(1, min(controller->queue_depth,
353230557Sjimharris		    SCI_MAX_IO_REQUESTS - SCI_MAX_DOMAINS));
354230557Sjimharris	}
355230557Sjimharris
356230557Sjimharris	/* Reserve one request so that we can ensure we have one available TC
357230557Sjimharris	 *  to do internal device resets.
358230557Sjimharris	 */
359230557Sjimharris	controller->sim_queue_depth = controller->queue_depth - 1;
360230557Sjimharris
361230557Sjimharris	/* Although we save one TC to do internal device resets, it is possible
362230557Sjimharris	 *  we could end up using several TCs for simultaneous device resets
363230557Sjimharris	 *  while at the same time having CAM fill our controller queue.  To
364230557Sjimharris	 *  simulate this condition, and how our driver handles it, we can set
365230557Sjimharris	 *  this io_shortage parameter, which will tell CAM that we have a
366230557Sjimharris	 *  large queue depth than we really do.
367230557Sjimharris	 */
368230557Sjimharris	uint32_t io_shortage = 0;
369230557Sjimharris	TUNABLE_INT_FETCH("hw.isci.io_shortage", &io_shortage);
370230557Sjimharris	controller->sim_queue_depth += io_shortage;
371230557Sjimharris
372233371Sjimharris	/* Attach to CAM using xpt_bus_register now, then immediately freeze
373233371Sjimharris	 *  the simq.  It will get released later when initial domain discovery
374233371Sjimharris	 *  is complete.
375233371Sjimharris	 */
376233371Sjimharris	controller->has_been_scanned = FALSE;
377233371Sjimharris	mtx_lock(&controller->lock);
378233371Sjimharris	isci_controller_attach_to_cam(controller);
379233371Sjimharris	xpt_freeze_simq(controller->sim, 1);
380233371Sjimharris	mtx_unlock(&controller->lock);
381233371Sjimharris
382240965Sjimharris	for (i = 0; i < SCI_MAX_PHYS; i++) {
383241403Sjimharris		controller->phys[i].handle = scic_controller_handle;
384241403Sjimharris		controller->phys[i].index = i;
385241403Sjimharris
386241403Sjimharris		/* fault */
387241403Sjimharris		controller->phys[i].led_fault = 0;
388241403Sjimharris		sprintf(led_name, "isci.bus%d.port%d.fault", controller->index, i);
389241403Sjimharris		controller->phys[i].cdev_fault = led_create(isci_led_fault_func,
390241403Sjimharris		    &controller->phys[i], led_name);
391241403Sjimharris
392241403Sjimharris		/* locate */
393241403Sjimharris		controller->phys[i].led_locate = 0;
394241403Sjimharris		sprintf(led_name, "isci.bus%d.port%d.locate", controller->index, i);
395241403Sjimharris		controller->phys[i].cdev_locate = led_create(isci_led_locate_func,
396241403Sjimharris		    &controller->phys[i], led_name);
397240965Sjimharris	}
398240965Sjimharris
399230557Sjimharris	return (scif_controller_initialize(controller->scif_controller_handle));
400230557Sjimharris}
401230557Sjimharris
402230557Sjimharrisint isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller)
403230557Sjimharris{
404230557Sjimharris	int error;
405230557Sjimharris	device_t device =  controller->isci->device;
406230557Sjimharris	uint32_t max_segment_size = isci_io_request_get_max_io_size();
407230557Sjimharris	uint32_t status = 0;
408230557Sjimharris	struct ISCI_MEMORY *uncached_controller_memory =
409230557Sjimharris	    &controller->uncached_controller_memory;
410230557Sjimharris	struct ISCI_MEMORY *cached_controller_memory =
411230557Sjimharris	    &controller->cached_controller_memory;
412230557Sjimharris	struct ISCI_MEMORY *request_memory =
413230557Sjimharris	    &controller->request_memory;
414230557Sjimharris	POINTER_UINT virtual_address;
415230557Sjimharris	bus_addr_t physical_address;
416230557Sjimharris
417230557Sjimharris	controller->mdl = sci_controller_get_memory_descriptor_list_handle(
418230557Sjimharris	    controller->scif_controller_handle);
419230557Sjimharris
420230557Sjimharris	uncached_controller_memory->size = sci_mdl_decorator_get_memory_size(
421230557Sjimharris	    controller->mdl, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS);
422230557Sjimharris
423230557Sjimharris	error = isci_allocate_dma_buffer(device, uncached_controller_memory);
424230557Sjimharris
425230557Sjimharris	if (error != 0)
426230557Sjimharris	    return (error);
427230557Sjimharris
428230557Sjimharris	sci_mdl_decorator_assign_memory( controller->mdl,
429230557Sjimharris	    SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS,
430230557Sjimharris	    uncached_controller_memory->virtual_address,
431230557Sjimharris	    uncached_controller_memory->physical_address);
432230557Sjimharris
433230557Sjimharris	cached_controller_memory->size = sci_mdl_decorator_get_memory_size(
434230557Sjimharris	    controller->mdl,
435230557Sjimharris	    SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
436230557Sjimharris	);
437230557Sjimharris
438230557Sjimharris	error = isci_allocate_dma_buffer(device, cached_controller_memory);
439230557Sjimharris
440230557Sjimharris	if (error != 0)
441230557Sjimharris	    return (error);
442230557Sjimharris
443230557Sjimharris	sci_mdl_decorator_assign_memory(controller->mdl,
444230557Sjimharris	    SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS,
445230557Sjimharris	    cached_controller_memory->virtual_address,
446230557Sjimharris	    cached_controller_memory->physical_address);
447230557Sjimharris
448230557Sjimharris	request_memory->size =
449230557Sjimharris	    controller->queue_depth * isci_io_request_get_object_size();
450230557Sjimharris
451230557Sjimharris	error = isci_allocate_dma_buffer(device, request_memory);
452230557Sjimharris
453230557Sjimharris	if (error != 0)
454230557Sjimharris	    return (error);
455230557Sjimharris
456230557Sjimharris	/* For STP PIO testing, we want to ensure we can force multiple SGLs
457230557Sjimharris	 *  since this has been a problem area in SCIL.  This tunable parameter
458230557Sjimharris	 *  will allow us to force DMA segments to a smaller size, ensuring
459230557Sjimharris	 *  that even if a physically contiguous buffer is attached to this
460230557Sjimharris	 *  I/O, the DMA subsystem will pass us multiple segments in our DMA
461230557Sjimharris	 *  load callback.
462230557Sjimharris	 */
463230557Sjimharris	TUNABLE_INT_FETCH("hw.isci.max_segment_size", &max_segment_size);
464230557Sjimharris
465230557Sjimharris	/* Create DMA tag for our I/O requests.  Then we can create DMA maps based off
466230557Sjimharris	 *  of this tag and store them in each of our ISCI_IO_REQUEST objects.  This
467230557Sjimharris	 *  will enable better performance than creating the DMA maps everytime we get
468230557Sjimharris	 *  an I/O.
469230557Sjimharris	 */
470230557Sjimharris	status = bus_dma_tag_create(bus_get_dma_tag(device), 0x1, 0x0,
471230557Sjimharris	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
472230557Sjimharris	    isci_io_request_get_max_io_size(),
473230557Sjimharris	    SCI_MAX_SCATTER_GATHER_ELEMENTS, max_segment_size, 0, NULL, NULL,
474230557Sjimharris	    &controller->buffer_dma_tag);
475230557Sjimharris
476230557Sjimharris	sci_pool_initialize(controller->request_pool);
477230557Sjimharris
478230557Sjimharris	virtual_address = request_memory->virtual_address;
479230557Sjimharris	physical_address = request_memory->physical_address;
480230557Sjimharris
481230557Sjimharris	for (int i = 0; i < controller->queue_depth; i++) {
482230557Sjimharris		struct ISCI_REQUEST *request =
483230557Sjimharris		    (struct ISCI_REQUEST *)virtual_address;
484230557Sjimharris
485230557Sjimharris		isci_request_construct(request,
486230557Sjimharris		    controller->scif_controller_handle,
487230557Sjimharris		    controller->buffer_dma_tag, physical_address);
488230557Sjimharris
489230557Sjimharris		sci_pool_put(controller->request_pool, request);
490230557Sjimharris
491230557Sjimharris		virtual_address += isci_request_get_object_size();
492230557Sjimharris		physical_address += isci_request_get_object_size();
493230557Sjimharris	}
494230557Sjimharris
495230557Sjimharris	uint32_t remote_device_size = sizeof(struct ISCI_REMOTE_DEVICE) +
496230557Sjimharris	    scif_remote_device_get_object_size();
497230557Sjimharris
498230557Sjimharris	controller->remote_device_memory = (uint8_t *) malloc(
499230557Sjimharris	    remote_device_size * SCI_MAX_REMOTE_DEVICES, M_ISCI,
500230557Sjimharris	    M_NOWAIT | M_ZERO);
501230557Sjimharris
502230557Sjimharris	sci_pool_initialize(controller->remote_device_pool);
503230557Sjimharris
504230557Sjimharris	uint8_t *remote_device_memory_ptr = controller->remote_device_memory;
505230557Sjimharris
506230557Sjimharris	for (int i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
507230557Sjimharris		struct ISCI_REMOTE_DEVICE *remote_device =
508230557Sjimharris		    (struct ISCI_REMOTE_DEVICE *)remote_device_memory_ptr;
509230557Sjimharris
510230557Sjimharris		controller->remote_device[i] = NULL;
511230557Sjimharris		remote_device->index = i;
512230557Sjimharris		remote_device->is_resetting = FALSE;
513230557Sjimharris		remote_device->frozen_lun_mask = 0;
514230557Sjimharris		sci_fast_list_element_init(remote_device,
515230557Sjimharris		    &remote_device->pending_device_reset_element);
516234106Sjimharris		TAILQ_INIT(&remote_device->queued_ccbs);
517235751Sjimharris		remote_device->release_queued_ccb = FALSE;
518235751Sjimharris		remote_device->queued_ccb_in_progress = NULL;
519233622Sjimharris
520233622Sjimharris		/*
521233622Sjimharris		 * For the first SCI_MAX_DOMAINS device objects, do not put
522233622Sjimharris		 *  them in the pool, rather assign them to each domain.  This
523233622Sjimharris		 *  ensures that any device attached directly to port "i" will
524233622Sjimharris		 *  always get CAM target id "i".
525233622Sjimharris		 */
526233622Sjimharris		if (i < SCI_MAX_DOMAINS)
527233622Sjimharris			controller->domain[i].da_remote_device = remote_device;
528233622Sjimharris		else
529233622Sjimharris			sci_pool_put(controller->remote_device_pool,
530233622Sjimharris			    remote_device);
531230557Sjimharris		remote_device_memory_ptr += remote_device_size;
532230557Sjimharris	}
533230557Sjimharris
534230557Sjimharris	return (0);
535230557Sjimharris}
536230557Sjimharris
537230557Sjimharrisvoid isci_controller_start(void *controller_handle)
538230557Sjimharris{
539230557Sjimharris	struct ISCI_CONTROLLER *controller =
540230557Sjimharris	    (struct ISCI_CONTROLLER *)controller_handle;
541230557Sjimharris	SCI_CONTROLLER_HANDLE_T scif_controller_handle =
542230557Sjimharris	    controller->scif_controller_handle;
543230557Sjimharris
544230557Sjimharris	scif_controller_start(scif_controller_handle,
545230557Sjimharris	    scif_controller_get_suggested_start_timeout(scif_controller_handle));
546230557Sjimharris
547230557Sjimharris	scic_controller_enable_interrupts(
548230557Sjimharris	    scif_controller_get_scic_handle(controller->scif_controller_handle));
549230557Sjimharris}
550230557Sjimharris
551230557Sjimharrisvoid isci_controller_domain_discovery_complete(
552230557Sjimharris    struct ISCI_CONTROLLER *isci_controller, struct ISCI_DOMAIN *isci_domain)
553230557Sjimharris{
554233371Sjimharris	if (!isci_controller->has_been_scanned)
555230557Sjimharris	{
556233371Sjimharris		/* Controller has not been scanned yet.  We'll clear
557230557Sjimharris		 *  the discovery bit for this domain, then check if all bits
558230557Sjimharris		 *  are now clear.  That would indicate that all domains are
559233371Sjimharris		 *  done with discovery and we can then proceed with initial
560233371Sjimharris		 *  scan.
561230557Sjimharris		 */
562230557Sjimharris
563230557Sjimharris		isci_controller->initial_discovery_mask &=
564230557Sjimharris		    ~(1 << isci_domain->index);
565230557Sjimharris
566230557Sjimharris		if (isci_controller->initial_discovery_mask == 0) {
567230557Sjimharris			struct isci_softc *driver = isci_controller->isci;
568230557Sjimharris			uint8_t next_index = isci_controller->index + 1;
569230557Sjimharris
570233371Sjimharris			isci_controller->has_been_scanned = TRUE;
571230557Sjimharris
572233371Sjimharris			/* Unfreeze simq to allow initial scan to proceed. */
573233371Sjimharris			xpt_release_simq(isci_controller->sim, TRUE);
574233371Sjimharris
575233371Sjimharris#if __FreeBSD_version < 800000
576233371Sjimharris			/* When driver is loaded after boot, we need to
577233371Sjimharris			 *  explicitly rescan here for versions <8.0, because
578233371Sjimharris			 *  CAM only automatically scans new buses at boot
579233371Sjimharris			 *  time.
580233371Sjimharris			 */
581233371Sjimharris			union ccb *ccb = xpt_alloc_ccb_nowait();
582233371Sjimharris
583249468Smav			xpt_create_path(&ccb->ccb_h.path, NULL,
584233371Sjimharris			    cam_sim_path(isci_controller->sim),
585233371Sjimharris			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
586233371Sjimharris
587233371Sjimharris			xpt_rescan(ccb);
588233371Sjimharris#endif
589233371Sjimharris
590230557Sjimharris			if (next_index < driver->controller_count) {
591230557Sjimharris				/*  There are more controllers that need to
592230557Sjimharris				 *   start.  So start the next one.
593230557Sjimharris				 */
594230557Sjimharris				isci_controller_start(
595230557Sjimharris				    &driver->controllers[next_index]);
596230557Sjimharris			}
597230557Sjimharris			else
598230557Sjimharris			{
599230557Sjimharris				/* All controllers have been started and completed discovery.
600230557Sjimharris				 *  Disestablish the config hook while will signal to the
601230557Sjimharris				 *  kernel during boot that it is safe to try to find and
602230557Sjimharris				 *  mount the root partition.
603230557Sjimharris				 */
604230557Sjimharris				config_intrhook_disestablish(
605230557Sjimharris				    &driver->config_hook);
606230557Sjimharris			}
607230557Sjimharris		}
608230557Sjimharris	}
609230557Sjimharris}
610230557Sjimharris
611230557Sjimharrisint isci_controller_attach_to_cam(struct ISCI_CONTROLLER *controller)
612230557Sjimharris{
613230557Sjimharris	struct isci_softc *isci = controller->isci;
614230557Sjimharris	device_t parent = device_get_parent(isci->device);
615230557Sjimharris	int unit = device_get_unit(isci->device);
616230557Sjimharris	struct cam_devq *isci_devq = cam_simq_alloc(controller->sim_queue_depth);
617230557Sjimharris
618230557Sjimharris	if(isci_devq == NULL) {
619230557Sjimharris		isci_log_message(0, "ISCI", "isci_devq is NULL \n");
620230557Sjimharris		return (-1);
621230557Sjimharris	}
622230557Sjimharris
623230557Sjimharris	controller->sim = cam_sim_alloc(isci_action, isci_poll, "isci",
624230557Sjimharris	    controller, unit, &controller->lock, controller->sim_queue_depth,
625230557Sjimharris	    controller->sim_queue_depth, isci_devq);
626230557Sjimharris
627230557Sjimharris	if(controller->sim == NULL) {
628230557Sjimharris		isci_log_message(0, "ISCI", "cam_sim_alloc... fails\n");
629230557Sjimharris		cam_simq_free(isci_devq);
630230557Sjimharris		return (-1);
631230557Sjimharris	}
632230557Sjimharris
633230557Sjimharris	if(xpt_bus_register(controller->sim, parent, controller->index)
634230557Sjimharris	    != CAM_SUCCESS) {
635230557Sjimharris		isci_log_message(0, "ISCI", "xpt_bus_register...fails \n");
636230557Sjimharris		cam_sim_free(controller->sim, TRUE);
637230557Sjimharris		mtx_unlock(&controller->lock);
638230557Sjimharris		return (-1);
639230557Sjimharris	}
640230557Sjimharris
641230557Sjimharris	if(xpt_create_path(&controller->path, NULL,
642230557Sjimharris	    cam_sim_path(controller->sim), CAM_TARGET_WILDCARD,
643230557Sjimharris	    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
644230557Sjimharris		isci_log_message(0, "ISCI", "xpt_create_path....fails\n");
645230557Sjimharris		xpt_bus_deregister(cam_sim_path(controller->sim));
646230557Sjimharris		cam_sim_free(controller->sim, TRUE);
647230557Sjimharris		mtx_unlock(&controller->lock);
648230557Sjimharris		return (-1);
649230557Sjimharris	}
650230557Sjimharris
651230557Sjimharris	return (0);
652230557Sjimharris}
653230557Sjimharris
654230557Sjimharrisvoid isci_poll(struct cam_sim *sim)
655230557Sjimharris{
656230557Sjimharris	struct ISCI_CONTROLLER *controller =
657230557Sjimharris	    (struct ISCI_CONTROLLER *)cam_sim_softc(sim);
658230557Sjimharris
659230557Sjimharris	isci_interrupt_poll_handler(controller);
660230557Sjimharris}
661230557Sjimharris
662230557Sjimharrisvoid isci_action(struct cam_sim *sim, union ccb *ccb)
663230557Sjimharris{
664230557Sjimharris	struct ISCI_CONTROLLER *controller =
665230557Sjimharris	    (struct ISCI_CONTROLLER *)cam_sim_softc(sim);
666230557Sjimharris
667230557Sjimharris	switch ( ccb->ccb_h.func_code ) {
668230557Sjimharris	case XPT_PATH_INQ:
669230557Sjimharris		{
670230557Sjimharris			struct ccb_pathinq *cpi = &ccb->cpi;
671230557Sjimharris			int bus = cam_sim_bus(sim);
672230557Sjimharris			ccb->ccb_h.ccb_sim_ptr = sim;
673230557Sjimharris			cpi->version_num = 1;
674230557Sjimharris			cpi->hba_inquiry = PI_TAG_ABLE;
675230557Sjimharris			cpi->target_sprt = 0;
676248775Sjimharris			cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN |
677248775Sjimharris			    PIM_UNMAPPED;
678230557Sjimharris			cpi->hba_eng_cnt = 0;
679230557Sjimharris			cpi->max_target = SCI_MAX_REMOTE_DEVICES - 1;
680230557Sjimharris			cpi->max_lun = ISCI_MAX_LUN;
681231860Ssbruno#if __FreeBSD_version >= 800102
682230557Sjimharris			cpi->maxio = isci_io_request_get_max_io_size();
683230557Sjimharris#endif
684230557Sjimharris			cpi->unit_number = cam_sim_unit(sim);
685230557Sjimharris			cpi->bus_id = bus;
686230557Sjimharris			cpi->initiator_id = SCI_MAX_REMOTE_DEVICES;
687230557Sjimharris			cpi->base_transfer_speed = 300000;
688230557Sjimharris			strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
689230557Sjimharris			strncpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN);
690230557Sjimharris			strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
691230557Sjimharris			cpi->transport = XPORT_SAS;
692230557Sjimharris			cpi->transport_version = 0;
693230557Sjimharris			cpi->protocol = PROTO_SCSI;
694230557Sjimharris			cpi->protocol_version = SCSI_REV_SPC2;
695230557Sjimharris			cpi->ccb_h.status = CAM_REQ_CMP;
696230557Sjimharris			xpt_done(ccb);
697230557Sjimharris		}
698230557Sjimharris		break;
699230557Sjimharris	case XPT_GET_TRAN_SETTINGS:
700230557Sjimharris		{
701230557Sjimharris			struct ccb_trans_settings *general_settings = &ccb->cts;
702230557Sjimharris			struct ccb_trans_settings_sas *sas_settings =
703230557Sjimharris			    &general_settings->xport_specific.sas;
704230557Sjimharris			struct ccb_trans_settings_scsi *scsi_settings =
705230557Sjimharris			    &general_settings->proto_specific.scsi;
706230557Sjimharris			struct ISCI_REMOTE_DEVICE *remote_device;
707230557Sjimharris
708230557Sjimharris			remote_device = controller->remote_device[ccb->ccb_h.target_id];
709230557Sjimharris
710230557Sjimharris			if (remote_device == NULL) {
711230557Sjimharris				ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
712230557Sjimharris				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
713230557Sjimharris				ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
714230557Sjimharris				xpt_done(ccb);
715230557Sjimharris				break;
716230557Sjimharris			}
717230557Sjimharris
718230557Sjimharris			general_settings->protocol = PROTO_SCSI;
719230557Sjimharris			general_settings->transport = XPORT_SAS;
720230557Sjimharris			general_settings->protocol_version = SCSI_REV_SPC2;
721230557Sjimharris			general_settings->transport_version = 0;
722230557Sjimharris			scsi_settings->valid = CTS_SCSI_VALID_TQ;
723230557Sjimharris			scsi_settings->flags = CTS_SCSI_FLAGS_TAG_ENB;
724230557Sjimharris			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
725230557Sjimharris			ccb->ccb_h.status |= CAM_REQ_CMP;
726230557Sjimharris
727230557Sjimharris			sas_settings->bitrate =
728230557Sjimharris			    isci_remote_device_get_bitrate(remote_device);
729230557Sjimharris
730230557Sjimharris			if (sas_settings->bitrate != 0)
731230557Sjimharris				sas_settings->valid = CTS_SAS_VALID_SPEED;
732230557Sjimharris
733230557Sjimharris			xpt_done(ccb);
734230557Sjimharris		}
735230557Sjimharris		break;
736230557Sjimharris	case XPT_SCSI_IO:
737230557Sjimharris		isci_io_request_execute_scsi_io(ccb, controller);
738230557Sjimharris		break;
739230557Sjimharris#if __FreeBSD_version >= 900026
740230557Sjimharris	case XPT_SMP_IO:
741230557Sjimharris		isci_io_request_execute_smp_io(ccb, controller);
742230557Sjimharris		break;
743230557Sjimharris#endif
744230557Sjimharris	case XPT_SET_TRAN_SETTINGS:
745230557Sjimharris		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
746230557Sjimharris		ccb->ccb_h.status |= CAM_REQ_CMP;
747230557Sjimharris		xpt_done(ccb);
748230557Sjimharris		break;
749230557Sjimharris	case XPT_CALC_GEOMETRY:
750230557Sjimharris		cam_calc_geometry(&ccb->ccg, /*extended*/1);
751230557Sjimharris		xpt_done(ccb);
752230557Sjimharris		break;
753230557Sjimharris	case XPT_RESET_DEV:
754230557Sjimharris		{
755230557Sjimharris			struct ISCI_REMOTE_DEVICE *remote_device =
756230557Sjimharris			    controller->remote_device[ccb->ccb_h.target_id];
757230557Sjimharris
758230557Sjimharris			if (remote_device != NULL)
759230557Sjimharris				isci_remote_device_reset(remote_device, ccb);
760230557Sjimharris			else {
761230557Sjimharris				ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
762230557Sjimharris				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
763230557Sjimharris				ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
764230557Sjimharris				xpt_done(ccb);
765230557Sjimharris			}
766230557Sjimharris		}
767230557Sjimharris		break;
768230557Sjimharris	case XPT_RESET_BUS:
769230557Sjimharris		ccb->ccb_h.status = CAM_REQ_CMP;
770230557Sjimharris		xpt_done(ccb);
771230557Sjimharris		break;
772230557Sjimharris	default:
773230557Sjimharris		isci_log_message(0, "ISCI", "Unhandled func_code 0x%x\n",
774230557Sjimharris		    ccb->ccb_h.func_code);
775230557Sjimharris		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
776230557Sjimharris		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
777230557Sjimharris		ccb->ccb_h.status |= CAM_REQ_INVALID;
778230557Sjimharris		xpt_done(ccb);
779230557Sjimharris		break;
780230557Sjimharris	}
781230557Sjimharris}
782230557Sjimharris
783235751Sjimharris/*
784235751Sjimharris * Unfortunately, SCIL doesn't cleanly handle retry conditions.
785235751Sjimharris *  CAM_REQUEUE_REQ works only when no one is using the pass(4) interface.  So
786235751Sjimharris *  when SCIL denotes an I/O needs to be retried (typically because of mixing
787235751Sjimharris *  tagged/non-tagged ATA commands, or running out of NCQ slots), we queue
788235751Sjimharris *  these I/O internally.  Once SCIL completes an I/O to this device, or we get
789235751Sjimharris *  a ready notification, we will retry the first I/O on the queue.
790235751Sjimharris *  Unfortunately, SCIL also doesn't cleanly handle starting the new I/O within
791235751Sjimharris *  the context of the completion handler, so we need to retry these I/O after
792235751Sjimharris *  the completion handler is done executing.
793235751Sjimharris */
794235751Sjimharrisvoid
795235751Sjimharrisisci_controller_release_queued_ccbs(struct ISCI_CONTROLLER *controller)
796235751Sjimharris{
797235751Sjimharris	struct ISCI_REMOTE_DEVICE *dev;
798235751Sjimharris	struct ccb_hdr *ccb_h;
799235751Sjimharris	int dev_idx;
800235751Sjimharris
801235751Sjimharris	KASSERT(mtx_owned(&controller->lock), ("controller lock not owned"));
802235751Sjimharris
803235751Sjimharris	controller->release_queued_ccbs = FALSE;
804235751Sjimharris	for (dev_idx = 0;
805235751Sjimharris	     dev_idx < SCI_MAX_REMOTE_DEVICES;
806235751Sjimharris	     dev_idx++) {
807235751Sjimharris
808235751Sjimharris		dev = controller->remote_device[dev_idx];
809235751Sjimharris		if (dev != NULL &&
810235751Sjimharris		    dev->release_queued_ccb == TRUE &&
811235751Sjimharris		    dev->queued_ccb_in_progress == NULL) {
812235751Sjimharris			dev->release_queued_ccb = FALSE;
813235751Sjimharris			ccb_h = TAILQ_FIRST(&dev->queued_ccbs);
814235751Sjimharris
815235751Sjimharris			if (ccb_h == NULL)
816235751Sjimharris				continue;
817235751Sjimharris
818235751Sjimharris			isci_log_message(1, "ISCI", "release %p %x\n", ccb_h,
819235751Sjimharris			    ((union ccb *)ccb_h)->csio.cdb_io.cdb_bytes[0]);
820235751Sjimharris
821235751Sjimharris			dev->queued_ccb_in_progress = (union ccb *)ccb_h;
822235751Sjimharris			isci_io_request_execute_scsi_io(
823235751Sjimharris			    (union ccb *)ccb_h, controller);
824235751Sjimharris		}
825235751Sjimharris	}
826235751Sjimharris}
827