xref: /freebsd-13-stable/sys/dev/twa/tw_osl_freebsd.c (revision 3bc80996974a61a4223eae4c1ccd47b6ee32a48a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
5  * Copyright (c) 2004-05 Vinod Kashyap.
6  * Copyright (c) 2000 Michael Smith
7  * Copyright (c) 2000 BSDi
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 /*
34  * AMCC'S 3ware driver for 9000 series storage controllers.
35  *
36  * Author: Vinod Kashyap
37  * Modifications by: Adam Radford
38  * Modifications by: Manjunath Ranganathaiah
39  */
40 
41 /*
42  * FreeBSD specific functions not related to CAM, and other
43  * miscellaneous functions.
44  */
45 
46 #include <dev/twa/tw_osl_includes.h>
47 #include <dev/twa/tw_cl_fwif.h>
48 #include <dev/twa/tw_cl_ioctl.h>
49 #include <dev/twa/tw_osl_ioctl.h>
50 
51 #ifdef TW_OSL_DEBUG
52 TW_INT32	TW_DEBUG_LEVEL_FOR_OSL = TW_OSL_DEBUG;
53 TW_INT32	TW_OSL_DEBUG_LEVEL_FOR_CL = TW_OSL_DEBUG;
54 #endif /* TW_OSL_DEBUG */
55 
56 static MALLOC_DEFINE(TW_OSLI_MALLOC_CLASS, "twa_commands", "twa commands");
57 
58 static	d_open_t		twa_open;
59 static	d_close_t		twa_close;
60 static	d_ioctl_t		twa_ioctl;
61 
62 static struct cdevsw twa_cdevsw = {
63 	.d_version =	D_VERSION,
64 	.d_open =	twa_open,
65 	.d_close =	twa_close,
66 	.d_ioctl =	twa_ioctl,
67 	.d_name =	"twa",
68 };
69 
70 static devclass_t	twa_devclass;
71 
72 /*
73  * Function name:	twa_open
74  * Description:		Called when the controller is opened.
75  *			Simply marks the controller as open.
76  *
77  * Input:		dev	-- control device corresponding to the ctlr
78  *			flags	-- mode of open
79  *			fmt	-- device type (character/block etc.)
80  *			proc	-- current process
81  * Output:		None
82  * Return value:	0	-- success
83  *			non-zero-- failure
84  */
85 static TW_INT32
twa_open(struct cdev * dev,TW_INT32 flags,TW_INT32 fmt,struct thread * proc)86 twa_open(struct cdev *dev, TW_INT32 flags, TW_INT32 fmt, struct thread *proc)
87 {
88 	struct twa_softc	*sc = (struct twa_softc *)(dev->si_drv1);
89 
90 	tw_osli_dbg_dprintf(5, sc, "entered");
91 	sc->open = TW_CL_TRUE;
92 	return(0);
93 }
94 
95 /*
96  * Function name:	twa_close
97  * Description:		Called when the controller is closed.
98  *			Simply marks the controller as not open.
99  *
100  * Input:		dev	-- control device corresponding to the ctlr
101  *			flags	-- mode of corresponding open
102  *			fmt	-- device type (character/block etc.)
103  *			proc	-- current process
104  * Output:		None
105  * Return value:	0	-- success
106  *			non-zero-- failure
107  */
108 static TW_INT32
twa_close(struct cdev * dev,TW_INT32 flags,TW_INT32 fmt,struct thread * proc)109 twa_close(struct cdev *dev, TW_INT32 flags, TW_INT32 fmt, struct thread *proc)
110 {
111 	struct twa_softc	*sc = (struct twa_softc *)(dev->si_drv1);
112 
113 	tw_osli_dbg_dprintf(5, sc, "entered");
114 	sc->open = TW_CL_FALSE;
115 	return(0);
116 }
117 
118 /*
119  * Function name:	twa_ioctl
120  * Description:		Called when an ioctl is posted to the controller.
121  *			Handles any OS Layer specific cmds, passes the rest
122  *			on to the Common Layer.
123  *
124  * Input:		dev	-- control device corresponding to the ctlr
125  *			cmd	-- ioctl cmd
126  *			buf	-- ptr to buffer in kernel memory, which is
127  *				   a copy of the input buffer in user-space
128  *			flags	-- mode of corresponding open
129  *			proc	-- current process
130  * Output:		buf	-- ptr to buffer in kernel memory, which will
131  *				   be copied to the output buffer in user-space
132  * Return value:	0	-- success
133  *			non-zero-- failure
134  */
135 static TW_INT32
twa_ioctl(struct cdev * dev,u_long cmd,caddr_t buf,TW_INT32 flags,struct thread * proc)136 twa_ioctl(struct cdev *dev, u_long cmd, caddr_t buf, TW_INT32 flags, struct thread *proc)
137 {
138 	struct twa_softc	*sc = (struct twa_softc *)(dev->si_drv1);
139 	TW_INT32		error;
140 
141 	tw_osli_dbg_dprintf(5, sc, "entered");
142 
143 	switch (cmd) {
144 	case TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH:
145 		tw_osli_dbg_dprintf(6, sc, "ioctl: fw_passthru");
146 		error = tw_osli_fw_passthru(sc, (TW_INT8 *)buf);
147 		break;
148 
149 	case TW_OSL_IOCTL_SCAN_BUS:
150 		/* Request CAM for a bus scan. */
151 		tw_osli_dbg_dprintf(6, sc, "ioctl: scan bus");
152 		error = tw_osli_request_bus_scan(sc);
153 		break;
154 
155 	default:
156 		tw_osli_dbg_dprintf(6, sc, "ioctl: 0x%lx", cmd);
157 		error = tw_cl_ioctl(&sc->ctlr_handle, cmd, buf);
158 		break;
159 	}
160 	return(error);
161 }
162 
163 static TW_INT32	twa_probe(device_t dev);
164 static TW_INT32	twa_attach(device_t dev);
165 static TW_INT32	twa_detach(device_t dev);
166 static TW_INT32	twa_shutdown(device_t dev);
167 static TW_VOID	twa_busdma_lock(TW_VOID *lock_arg, bus_dma_lock_op_t op);
168 static TW_VOID	twa_pci_intr(TW_VOID *arg);
169 static TW_VOID	twa_watchdog(TW_VOID *arg);
170 int twa_setup_intr(struct twa_softc *sc);
171 int twa_teardown_intr(struct twa_softc *sc);
172 
173 static TW_INT32	tw_osli_alloc_mem(struct twa_softc *sc);
174 static TW_VOID	tw_osli_free_resources(struct twa_softc *sc);
175 
176 static TW_VOID	twa_map_load_data_callback(TW_VOID *arg,
177 	bus_dma_segment_t *segs, TW_INT32 nsegments, TW_INT32 error);
178 static TW_VOID	twa_map_load_callback(TW_VOID *arg,
179 	bus_dma_segment_t *segs, TW_INT32 nsegments, TW_INT32 error);
180 
181 static device_method_t	twa_methods[] = {
182 	/* Device interface */
183 	DEVMETHOD(device_probe,		twa_probe),
184 	DEVMETHOD(device_attach,	twa_attach),
185 	DEVMETHOD(device_detach,	twa_detach),
186 	DEVMETHOD(device_shutdown,	twa_shutdown),
187 
188 	DEVMETHOD_END
189 };
190 
191 static driver_t	twa_pci_driver = {
192 	"twa",
193 	twa_methods,
194 	sizeof(struct twa_softc)
195 };
196 
197 DRIVER_MODULE(twa, pci, twa_pci_driver, twa_devclass, 0, 0);
198 MODULE_DEPEND(twa, cam, 1, 1, 1);
199 MODULE_DEPEND(twa, pci, 1, 1, 1);
200 
201 /*
202  * Function name:	twa_probe
203  * Description:		Called at driver load time.  Claims 9000 ctlrs.
204  *
205  * Input:		dev	-- bus device corresponding to the ctlr
206  * Output:		None
207  * Return value:	<= 0	-- success
208  *			> 0	-- failure
209  */
210 static TW_INT32
twa_probe(device_t dev)211 twa_probe(device_t dev)
212 {
213 	static TW_UINT8	first_ctlr = 1;
214 
215 	tw_osli_dbg_printf(3, "entered");
216 
217 	if (tw_cl_ctlr_supported(pci_get_vendor(dev), pci_get_device(dev))) {
218 		device_set_desc(dev, TW_OSLI_DEVICE_NAME);
219 		/* Print the driver version only once. */
220 		if (first_ctlr) {
221 			printf("3ware device driver for 9000 series storage "
222 				"controllers, version: %s\n",
223 				TW_OSL_DRIVER_VERSION_STRING);
224 			first_ctlr = 0;
225 		}
226 		return(0);
227 	}
228 	return(ENXIO);
229 }
230 
twa_setup_intr(struct twa_softc * sc)231 int twa_setup_intr(struct twa_softc *sc)
232 {
233 	int error = 0;
234 
235 	if (!(sc->intr_handle) && (sc->irq_res)) {
236 		error = bus_setup_intr(sc->bus_dev, sc->irq_res,
237 					INTR_TYPE_CAM | INTR_MPSAFE,
238 					NULL, twa_pci_intr,
239 					sc, &sc->intr_handle);
240 	}
241 	return( error );
242 }
243 
twa_teardown_intr(struct twa_softc * sc)244 int twa_teardown_intr(struct twa_softc *sc)
245 {
246 	int error = 0;
247 
248 	if ((sc->intr_handle) && (sc->irq_res)) {
249 		error = bus_teardown_intr(sc->bus_dev,
250 						sc->irq_res, sc->intr_handle);
251 		sc->intr_handle = NULL;
252 	}
253 	return( error );
254 }
255 
256 /*
257  * Function name:	twa_attach
258  * Description:		Allocates pci resources; updates sc; adds a node to the
259  *			sysctl tree to expose the driver version; makes calls
260  *			(to the Common Layer) to initialize ctlr, and to
261  *			attach to CAM.
262  *
263  * Input:		dev	-- bus device corresponding to the ctlr
264  * Output:		None
265  * Return value:	0	-- success
266  *			non-zero-- failure
267  */
268 static TW_INT32
twa_attach(device_t dev)269 twa_attach(device_t dev)
270 {
271 	struct twa_softc	*sc = device_get_softc(dev);
272 	TW_INT32		bar_num;
273 	TW_INT32		bar0_offset;
274 	TW_INT32		bar_size;
275 	TW_INT32		error;
276 
277 	tw_osli_dbg_dprintf(3, sc, "entered");
278 
279 	sc->ctlr_handle.osl_ctlr_ctxt = sc;
280 
281 	/* Initialize the softc structure. */
282 	sc->bus_dev = dev;
283 	sc->device_id = pci_get_device(dev);
284 
285 	/* Initialize the mutexes right here. */
286 	sc->io_lock = &(sc->io_lock_handle);
287 	mtx_init(sc->io_lock, "tw_osl_io_lock", NULL, MTX_SPIN);
288 	sc->q_lock = &(sc->q_lock_handle);
289 	mtx_init(sc->q_lock, "tw_osl_q_lock", NULL, MTX_SPIN);
290 	sc->sim_lock = &(sc->sim_lock_handle);
291 	mtx_init(sc->sim_lock, "tw_osl_sim_lock", NULL, MTX_DEF | MTX_RECURSE);
292 
293 	sysctl_ctx_init(&sc->sysctl_ctxt);
294 	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctxt,
295 	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, device_get_nameunit(dev),
296 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
297 	if (sc->sysctl_tree == NULL) {
298 		tw_osli_printf(sc, "error = %d",
299 			TW_CL_SEVERITY_ERROR_STRING,
300 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
301 			0x2000,
302 			"Cannot add sysctl tree node",
303 			ENXIO);
304 		return(ENXIO);
305 	}
306 	SYSCTL_ADD_STRING(&sc->sysctl_ctxt, SYSCTL_CHILDREN(sc->sysctl_tree),
307 		OID_AUTO, "driver_version", CTLFLAG_RD,
308 		TW_OSL_DRIVER_VERSION_STRING, 0, "TWA driver version");
309 
310 	/* Force the busmaster enable bit on, in case the BIOS forgot. */
311 	pci_enable_busmaster(dev);
312 
313 	/* Allocate the PCI register window. */
314 	if ((error = tw_cl_get_pci_bar_info(sc->device_id, TW_CL_BAR_TYPE_MEM,
315 		&bar_num, &bar0_offset, &bar_size))) {
316 		tw_osli_printf(sc, "error = %d",
317 			TW_CL_SEVERITY_ERROR_STRING,
318 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
319 			0x201F,
320 			"Can't get PCI BAR info",
321 			error);
322 		tw_osli_free_resources(sc);
323 		return(error);
324 	}
325 	sc->reg_res_id = PCIR_BARS + bar0_offset;
326 	if ((sc->reg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
327 				&(sc->reg_res_id), RF_ACTIVE))
328 				== NULL) {
329 		tw_osli_printf(sc, "error = %d",
330 			TW_CL_SEVERITY_ERROR_STRING,
331 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
332 			0x2002,
333 			"Can't allocate register window",
334 			ENXIO);
335 		tw_osli_free_resources(sc);
336 		return(ENXIO);
337 	}
338 	sc->bus_tag = rman_get_bustag(sc->reg_res);
339 	sc->bus_handle = rman_get_bushandle(sc->reg_res);
340 
341 	/* Allocate and register our interrupt. */
342 	sc->irq_res_id = 0;
343 	if ((sc->irq_res = bus_alloc_resource_any(sc->bus_dev, SYS_RES_IRQ,
344 				&(sc->irq_res_id),
345 				RF_SHAREABLE | RF_ACTIVE)) == NULL) {
346 		tw_osli_printf(sc, "error = %d",
347 			TW_CL_SEVERITY_ERROR_STRING,
348 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
349 			0x2003,
350 			"Can't allocate interrupt",
351 			ENXIO);
352 		tw_osli_free_resources(sc);
353 		return(ENXIO);
354 	}
355 	if ((error = twa_setup_intr(sc))) {
356 		tw_osli_printf(sc, "error = %d",
357 			TW_CL_SEVERITY_ERROR_STRING,
358 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
359 			0x2004,
360 			"Can't set up interrupt",
361 			error);
362 		tw_osli_free_resources(sc);
363 		return(error);
364 	}
365 
366 	if ((error = tw_osli_alloc_mem(sc))) {
367 		tw_osli_printf(sc, "error = %d",
368 			TW_CL_SEVERITY_ERROR_STRING,
369 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
370 			0x2005,
371 			"Memory allocation failure",
372 			error);
373 		tw_osli_free_resources(sc);
374 		return(error);
375 	}
376 
377 	/* Initialize the Common Layer for this controller. */
378 	if ((error = tw_cl_init_ctlr(&sc->ctlr_handle, sc->flags, sc->device_id,
379 			TW_OSLI_MAX_NUM_REQUESTS, TW_OSLI_MAX_NUM_AENS,
380 			sc->non_dma_mem, sc->dma_mem,
381 			sc->dma_mem_phys
382 			))) {
383 		tw_osli_printf(sc, "error = %d",
384 			TW_CL_SEVERITY_ERROR_STRING,
385 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
386 			0x2006,
387 			"Failed to initialize Common Layer/controller",
388 			error);
389 		tw_osli_free_resources(sc);
390 		return(error);
391 	}
392 
393 	/* Create the control device. */
394 	sc->ctrl_dev = make_dev(&twa_cdevsw, device_get_unit(sc->bus_dev),
395 			UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR,
396 			"twa%d", device_get_unit(sc->bus_dev));
397 	sc->ctrl_dev->si_drv1 = sc;
398 
399 	if ((error = tw_osli_cam_attach(sc))) {
400 		tw_osli_free_resources(sc);
401 		tw_osli_printf(sc, "error = %d",
402 			TW_CL_SEVERITY_ERROR_STRING,
403 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
404 			0x2007,
405 			"Failed to initialize CAM",
406 			error);
407 		return(error);
408 	}
409 
410 	sc->watchdog_index = 0;
411 	callout_init(&(sc->watchdog_callout[0]), 1);
412 	callout_init(&(sc->watchdog_callout[1]), 1);
413 	callout_reset(&(sc->watchdog_callout[0]), 5*hz, twa_watchdog, &sc->ctlr_handle);
414 	gone_in_dev(dev, 14, "twa(4) removed");
415 
416 	return(0);
417 }
418 
419 static TW_VOID
twa_watchdog(TW_VOID * arg)420 twa_watchdog(TW_VOID *arg)
421 {
422 	struct tw_cl_ctlr_handle *ctlr_handle =
423 		(struct tw_cl_ctlr_handle *)arg;
424 	struct twa_softc		*sc = ctlr_handle->osl_ctlr_ctxt;
425 	int				i;
426 	int				i_need_a_reset = 0;
427 	int				driver_is_active = 0;
428 	int				my_watchdog_was_pending = 1234;
429 	TW_UINT64			current_time;
430 	struct tw_osli_req_context	*my_req;
431 
432 //==============================================================================
433 	current_time = (TW_UINT64) (tw_osl_get_local_time());
434 
435 	for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) {
436 		my_req = &(sc->req_ctx_buf[i]);
437 
438 		if ((my_req->state == TW_OSLI_REQ_STATE_BUSY) &&
439 			(my_req->deadline) &&
440 			(my_req->deadline < current_time)) {
441 			tw_cl_set_reset_needed(ctlr_handle);
442 #ifdef    TW_OSL_DEBUG
443 			device_printf((sc)->bus_dev, "Request %d timed out! d = %llu, c = %llu\n", i, my_req->deadline, current_time);
444 #else  /* TW_OSL_DEBUG */
445 			device_printf((sc)->bus_dev, "Request %d timed out!\n", i);
446 #endif /* TW_OSL_DEBUG */
447 			break;
448 		}
449 	}
450 //==============================================================================
451 
452 	i_need_a_reset = tw_cl_is_reset_needed(ctlr_handle);
453 
454 	i = (int) ((sc->watchdog_index++) & 1);
455 
456 	driver_is_active = tw_cl_is_active(ctlr_handle);
457 
458 	if (i_need_a_reset) {
459 #ifdef    TW_OSL_DEBUG
460 		device_printf((sc)->bus_dev, "Watchdog rescheduled in 70 seconds\n");
461 #endif /* TW_OSL_DEBUG */
462 		my_watchdog_was_pending =
463 			callout_reset(&(sc->watchdog_callout[i]), 70*hz, twa_watchdog, &sc->ctlr_handle);
464 		tw_cl_reset_ctlr(ctlr_handle);
465 #ifdef    TW_OSL_DEBUG
466 		device_printf((sc)->bus_dev, "Watchdog reset completed!\n");
467 #endif /* TW_OSL_DEBUG */
468 	} else if (driver_is_active) {
469 		my_watchdog_was_pending =
470 			callout_reset(&(sc->watchdog_callout[i]),  5*hz, twa_watchdog, &sc->ctlr_handle);
471 	}
472 #ifdef    TW_OSL_DEBUG
473 	if (i_need_a_reset || my_watchdog_was_pending)
474 		device_printf((sc)->bus_dev, "i_need_a_reset = %d, "
475 		"driver_is_active = %d, my_watchdog_was_pending = %d\n",
476 		i_need_a_reset, driver_is_active, my_watchdog_was_pending);
477 #endif /* TW_OSL_DEBUG */
478 }
479 
480 /*
481  * Function name:	tw_osli_alloc_mem
482  * Description:		Allocates memory needed both by CL and OSL.
483  *
484  * Input:		sc	-- OSL internal controller context
485  * Output:		None
486  * Return value:	0	-- success
487  *			non-zero-- failure
488  */
489 static TW_INT32
tw_osli_alloc_mem(struct twa_softc * sc)490 tw_osli_alloc_mem(struct twa_softc *sc)
491 {
492 	struct tw_osli_req_context	*req;
493 	TW_UINT32			max_sg_elements;
494 	TW_UINT32			non_dma_mem_size;
495 	TW_UINT32			dma_mem_size;
496 	TW_INT32			error;
497 	TW_INT32			i;
498 
499 	tw_osli_dbg_dprintf(3, sc, "entered");
500 
501 	sc->flags |= (sizeof(bus_addr_t) == 8) ? TW_CL_64BIT_ADDRESSES : 0;
502 	sc->flags |= (sizeof(bus_size_t) == 8) ? TW_CL_64BIT_SG_LENGTH : 0;
503 
504 	max_sg_elements = (sizeof(bus_addr_t) == 8) ?
505 		TW_CL_MAX_64BIT_SG_ELEMENTS : TW_CL_MAX_32BIT_SG_ELEMENTS;
506 
507 	if ((error = tw_cl_get_mem_requirements(&sc->ctlr_handle, sc->flags,
508 			sc->device_id, TW_OSLI_MAX_NUM_REQUESTS,  TW_OSLI_MAX_NUM_AENS,
509 			&(sc->alignment), &(sc->sg_size_factor),
510 			&non_dma_mem_size, &dma_mem_size
511 			))) {
512 		tw_osli_printf(sc, "error = %d",
513 			TW_CL_SEVERITY_ERROR_STRING,
514 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
515 			0x2008,
516 			"Can't get Common Layer's memory requirements",
517 			error);
518 		return(error);
519 	}
520 
521 	if ((sc->non_dma_mem = malloc(non_dma_mem_size, TW_OSLI_MALLOC_CLASS,
522 				M_WAITOK)) == NULL) {
523 		tw_osli_printf(sc, "error = %d",
524 			TW_CL_SEVERITY_ERROR_STRING,
525 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
526 			0x2009,
527 			"Can't allocate non-dma memory",
528 			ENOMEM);
529 		return(ENOMEM);
530 	}
531 
532 	/* Create the parent dma tag. */
533 	if (bus_dma_tag_create(bus_get_dma_tag(sc->bus_dev), /* parent */
534 				sc->alignment,		/* alignment */
535 				TW_OSLI_DMA_BOUNDARY,	/* boundary */
536 				BUS_SPACE_MAXADDR,	/* lowaddr */
537 				BUS_SPACE_MAXADDR, 	/* highaddr */
538 				NULL, NULL, 		/* filter, filterarg */
539 				TW_CL_MAX_IO_SIZE,	/* maxsize */
540 				max_sg_elements,	/* nsegments */
541 				TW_CL_MAX_IO_SIZE,	/* maxsegsize */
542 				0,			/* flags */
543 				NULL,			/* lockfunc */
544 				NULL,			/* lockfuncarg */
545 				&sc->parent_tag		/* tag */)) {
546 		tw_osli_printf(sc, "error = %d",
547 			TW_CL_SEVERITY_ERROR_STRING,
548 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
549 			0x200A,
550 			"Can't allocate parent DMA tag",
551 			ENOMEM);
552 		return(ENOMEM);
553 	}
554 
555 	/* Create a dma tag for Common Layer's DMA'able memory (dma_mem). */
556 	if (bus_dma_tag_create(sc->parent_tag,		/* parent */
557 				sc->alignment,		/* alignment */
558 				0,			/* boundary */
559 				BUS_SPACE_MAXADDR,	/* lowaddr */
560 				BUS_SPACE_MAXADDR, 	/* highaddr */
561 				NULL, NULL, 		/* filter, filterarg */
562 				dma_mem_size,		/* maxsize */
563 				1,			/* nsegments */
564 				BUS_SPACE_MAXSIZE,	/* maxsegsize */
565 				0,			/* flags */
566 				NULL,			/* lockfunc */
567 				NULL,			/* lockfuncarg */
568 				&sc->cmd_tag		/* tag */)) {
569 		tw_osli_printf(sc, "error = %d",
570 			TW_CL_SEVERITY_ERROR_STRING,
571 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
572 			0x200B,
573 			"Can't allocate DMA tag for Common Layer's "
574 			"DMA'able memory",
575 			ENOMEM);
576 		return(ENOMEM);
577 	}
578 
579 	if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem,
580 		BUS_DMA_NOWAIT, &sc->cmd_map)) {
581 		/* Try a second time. */
582 		if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem,
583 			BUS_DMA_NOWAIT, &sc->cmd_map)) {
584 			tw_osli_printf(sc, "error = %d",
585 				TW_CL_SEVERITY_ERROR_STRING,
586 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
587 				0x200C,
588 				"Can't allocate DMA'able memory for the"
589 				"Common Layer",
590 				ENOMEM);
591 			return(ENOMEM);
592 		}
593 	}
594 
595 	bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem,
596 		dma_mem_size, twa_map_load_callback,
597 		&sc->dma_mem_phys, 0);
598 
599 	/*
600 	 * Create a dma tag for data buffers; size will be the maximum
601 	 * possible I/O size (128kB).
602 	 */
603 	if (bus_dma_tag_create(sc->parent_tag,		/* parent */
604 				sc->alignment,		/* alignment */
605 				0,			/* boundary */
606 				BUS_SPACE_MAXADDR,	/* lowaddr */
607 				BUS_SPACE_MAXADDR, 	/* highaddr */
608 				NULL, NULL, 		/* filter, filterarg */
609 				TW_CL_MAX_IO_SIZE,	/* maxsize */
610 				max_sg_elements,	/* nsegments */
611 				TW_CL_MAX_IO_SIZE,	/* maxsegsize */
612 				BUS_DMA_ALLOCNOW,	/* flags */
613 				twa_busdma_lock,	/* lockfunc */
614 				sc->io_lock,		/* lockfuncarg */
615 				&sc->dma_tag		/* tag */)) {
616 		tw_osli_printf(sc, "error = %d",
617 			TW_CL_SEVERITY_ERROR_STRING,
618 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
619 			0x200F,
620 			"Can't allocate DMA tag for data buffers",
621 			ENOMEM);
622 		return(ENOMEM);
623 	}
624 
625 	/*
626 	 * Create a dma tag for ioctl data buffers; size will be the maximum
627 	 * possible I/O size (128kB).
628 	 */
629 	if (bus_dma_tag_create(sc->parent_tag,		/* parent */
630 				sc->alignment,		/* alignment */
631 				0,			/* boundary */
632 				BUS_SPACE_MAXADDR,	/* lowaddr */
633 				BUS_SPACE_MAXADDR, 	/* highaddr */
634 				NULL, NULL, 		/* filter, filterarg */
635 				TW_CL_MAX_IO_SIZE,	/* maxsize */
636 				max_sg_elements,	/* nsegments */
637 				TW_CL_MAX_IO_SIZE,	/* maxsegsize */
638 				BUS_DMA_ALLOCNOW,	/* flags */
639 				twa_busdma_lock,	/* lockfunc */
640 				sc->io_lock,		/* lockfuncarg */
641 				&sc->ioctl_tag		/* tag */)) {
642 		tw_osli_printf(sc, "error = %d",
643 			TW_CL_SEVERITY_ERROR_STRING,
644 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
645 			0x2010,
646 			"Can't allocate DMA tag for ioctl data buffers",
647 			ENOMEM);
648 		return(ENOMEM);
649 	}
650 
651 	/* Create just one map for all ioctl request data buffers. */
652 	if (bus_dmamap_create(sc->ioctl_tag, 0, &sc->ioctl_map)) {
653 		tw_osli_printf(sc, "error = %d",
654 			TW_CL_SEVERITY_ERROR_STRING,
655 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
656 			0x2011,
657 			"Can't create ioctl map",
658 			ENOMEM);
659 		return(ENOMEM);
660 	}
661 
662 	/* Initialize request queues. */
663 	tw_osli_req_q_init(sc, TW_OSLI_FREE_Q);
664 	tw_osli_req_q_init(sc, TW_OSLI_BUSY_Q);
665 
666 	if ((sc->req_ctx_buf = (struct tw_osli_req_context *)
667 			malloc((sizeof(struct tw_osli_req_context) *
668 				TW_OSLI_MAX_NUM_REQUESTS),
669 				TW_OSLI_MALLOC_CLASS, M_WAITOK)) == NULL) {
670 		tw_osli_printf(sc, "error = %d",
671 			TW_CL_SEVERITY_ERROR_STRING,
672 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
673 			0x2012,
674 			"Failed to allocate request packets",
675 			ENOMEM);
676 		return(ENOMEM);
677 	}
678 	bzero(sc->req_ctx_buf,
679 		sizeof(struct tw_osli_req_context) * TW_OSLI_MAX_NUM_REQUESTS);
680 
681 	for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) {
682 		req = &(sc->req_ctx_buf[i]);
683 		req->ctlr = sc;
684 		if (bus_dmamap_create(sc->dma_tag, 0, &req->dma_map)) {
685 			tw_osli_printf(sc, "request # = %d, error = %d",
686 				TW_CL_SEVERITY_ERROR_STRING,
687 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
688 				0x2013,
689 				"Can't create dma map",
690 				i, ENOMEM);
691 			return(ENOMEM);
692 		}
693 
694 		/* Initialize the ioctl wakeup/ timeout mutex */
695 		req->ioctl_wake_timeout_lock = &(req->ioctl_wake_timeout_lock_handle);
696 		mtx_init(req->ioctl_wake_timeout_lock, "tw_ioctl_wake_timeout_lock", NULL, MTX_DEF);
697 
698 		/* Insert request into the free queue. */
699 		tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
700 	}
701 
702 	return(0);
703 }
704 
705 /*
706  * Function name:	tw_osli_free_resources
707  * Description:		Performs clean-up at the time of going down.
708  *
709  * Input:		sc	-- ptr to OSL internal ctlr context
710  * Output:		None
711  * Return value:	None
712  */
713 static TW_VOID
tw_osli_free_resources(struct twa_softc * sc)714 tw_osli_free_resources(struct twa_softc *sc)
715 {
716 	struct tw_osli_req_context	*req;
717 	TW_INT32			error = 0;
718 
719 	tw_osli_dbg_dprintf(3, sc, "entered");
720 
721 	/* Detach from CAM */
722 	tw_osli_cam_detach(sc);
723 
724 	if (sc->req_ctx_buf)
725 		while ((req = tw_osli_req_q_remove_head(sc, TW_OSLI_FREE_Q)) !=
726 			NULL) {
727 			mtx_destroy(req->ioctl_wake_timeout_lock);
728 
729 			if ((error = bus_dmamap_destroy(sc->dma_tag,
730 					req->dma_map)))
731 				tw_osli_dbg_dprintf(1, sc,
732 					"dmamap_destroy(dma) returned %d",
733 					error);
734 		}
735 
736 	if ((sc->ioctl_tag) && (sc->ioctl_map))
737 		if ((error = bus_dmamap_destroy(sc->ioctl_tag, sc->ioctl_map)))
738 			tw_osli_dbg_dprintf(1, sc,
739 				"dmamap_destroy(ioctl) returned %d", error);
740 
741 	/* Free all memory allocated so far. */
742 	if (sc->req_ctx_buf)
743 		free(sc->req_ctx_buf, TW_OSLI_MALLOC_CLASS);
744 
745 	if (sc->non_dma_mem)
746 		free(sc->non_dma_mem, TW_OSLI_MALLOC_CLASS);
747 
748 	if (sc->dma_mem) {
749 		bus_dmamap_unload(sc->cmd_tag, sc->cmd_map);
750 		bus_dmamem_free(sc->cmd_tag, sc->dma_mem,
751 			sc->cmd_map);
752 	}
753 	if (sc->cmd_tag)
754 		if ((error = bus_dma_tag_destroy(sc->cmd_tag)))
755 			tw_osli_dbg_dprintf(1, sc,
756 				"dma_tag_destroy(cmd) returned %d", error);
757 
758 	if (sc->dma_tag)
759 		if ((error = bus_dma_tag_destroy(sc->dma_tag)))
760 			tw_osli_dbg_dprintf(1, sc,
761 				"dma_tag_destroy(dma) returned %d", error);
762 
763 	if (sc->ioctl_tag)
764 		if ((error = bus_dma_tag_destroy(sc->ioctl_tag)))
765 			tw_osli_dbg_dprintf(1, sc,
766 				"dma_tag_destroy(ioctl) returned %d", error);
767 
768 	if (sc->parent_tag)
769 		if ((error = bus_dma_tag_destroy(sc->parent_tag)))
770 			tw_osli_dbg_dprintf(1, sc,
771 				"dma_tag_destroy(parent) returned %d", error);
772 
773 	/* Disconnect the interrupt handler. */
774 	if ((error = twa_teardown_intr(sc)))
775 			tw_osli_dbg_dprintf(1, sc,
776 				"teardown_intr returned %d", error);
777 
778 	if (sc->irq_res != NULL)
779 		if ((error = bus_release_resource(sc->bus_dev,
780 				SYS_RES_IRQ, sc->irq_res_id, sc->irq_res)))
781 			tw_osli_dbg_dprintf(1, sc,
782 				"release_resource(irq) returned %d", error);
783 
784 	/* Release the register window mapping. */
785 	if (sc->reg_res != NULL)
786 		if ((error = bus_release_resource(sc->bus_dev,
787 				SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)))
788 			tw_osli_dbg_dprintf(1, sc,
789 				"release_resource(io) returned %d", error);
790 
791 	/* Destroy the control device. */
792 	if (sc->ctrl_dev != (struct cdev *)NULL)
793 		destroy_dev(sc->ctrl_dev);
794 
795 	if ((error = sysctl_ctx_free(&sc->sysctl_ctxt)))
796 		tw_osli_dbg_dprintf(1, sc,
797 			"sysctl_ctx_free returned %d", error);
798 
799 }
800 
801 /*
802  * Function name:	twa_detach
803  * Description:		Called when the controller is being detached from
804  *			the pci bus.
805  *
806  * Input:		dev	-- bus device corresponding to the ctlr
807  * Output:		None
808  * Return value:	0	-- success
809  *			non-zero-- failure
810  */
811 static TW_INT32
twa_detach(device_t dev)812 twa_detach(device_t dev)
813 {
814 	struct twa_softc	*sc = device_get_softc(dev);
815 	TW_INT32		error;
816 
817 	tw_osli_dbg_dprintf(3, sc, "entered");
818 
819 	error = EBUSY;
820 	if (sc->open) {
821 		tw_osli_printf(sc, "error = %d",
822 			TW_CL_SEVERITY_ERROR_STRING,
823 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
824 			0x2014,
825 			"Device open",
826 			error);
827 		goto out;
828 	}
829 
830 	/* Shut the controller down. */
831 	if ((error = twa_shutdown(dev)))
832 		goto out;
833 
834 	/* Free all resources associated with this controller. */
835 	tw_osli_free_resources(sc);
836 	error = 0;
837 
838 out:
839 	return(error);
840 }
841 
842 /*
843  * Function name:	twa_shutdown
844  * Description:		Called at unload/shutdown time.  Lets the controller
845  *			know that we are going down.
846  *
847  * Input:		dev	-- bus device corresponding to the ctlr
848  * Output:		None
849  * Return value:	0	-- success
850  *			non-zero-- failure
851  */
852 static TW_INT32
twa_shutdown(device_t dev)853 twa_shutdown(device_t dev)
854 {
855 	struct twa_softc	*sc = device_get_softc(dev);
856 	TW_INT32		error = 0;
857 
858 	tw_osli_dbg_dprintf(3, sc, "entered");
859 
860 	/* Disconnect interrupts. */
861 	error = twa_teardown_intr(sc);
862 
863 	/* Stop watchdog task. */
864 	callout_drain(&(sc->watchdog_callout[0]));
865 	callout_drain(&(sc->watchdog_callout[1]));
866 
867 	/* Disconnect from the controller. */
868 	if ((error = tw_cl_shutdown_ctlr(&(sc->ctlr_handle), 0))) {
869 		tw_osli_printf(sc, "error = %d",
870 			TW_CL_SEVERITY_ERROR_STRING,
871 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
872 			0x2015,
873 			"Failed to shutdown Common Layer/controller",
874 			error);
875 	}
876 	return(error);
877 }
878 
879 /*
880  * Function name:	twa_busdma_lock
881  * Description:		Function to provide synchronization during busdma_swi.
882  *
883  * Input:		lock_arg -- lock mutex sent as argument
884  *			op -- operation (lock/unlock) expected of the function
885  * Output:		None
886  * Return value:	None
887  */
888 TW_VOID
twa_busdma_lock(TW_VOID * lock_arg,bus_dma_lock_op_t op)889 twa_busdma_lock(TW_VOID *lock_arg, bus_dma_lock_op_t op)
890 {
891 	struct mtx	*lock;
892 
893 	lock = (struct mtx *)lock_arg;
894 	switch (op) {
895 	case BUS_DMA_LOCK:
896 		mtx_lock_spin(lock);
897 		break;
898 
899 	case BUS_DMA_UNLOCK:
900 		mtx_unlock_spin(lock);
901 		break;
902 
903 	default:
904 		panic("Unknown operation 0x%x for twa_busdma_lock!", op);
905 	}
906 }
907 
908 /*
909  * Function name:	twa_pci_intr
910  * Description:		Interrupt handler.  Wrapper for twa_interrupt.
911  *
912  * Input:		arg	-- ptr to OSL internal ctlr context
913  * Output:		None
914  * Return value:	None
915  */
916 static TW_VOID
twa_pci_intr(TW_VOID * arg)917 twa_pci_intr(TW_VOID *arg)
918 {
919 	struct twa_softc	*sc = (struct twa_softc *)arg;
920 
921 	tw_osli_dbg_dprintf(10, sc, "entered");
922 	tw_cl_interrupt(&(sc->ctlr_handle));
923 }
924 
925 /*
926  * Function name:	tw_osli_fw_passthru
927  * Description:		Builds a fw passthru cmd pkt, and submits it to CL.
928  *
929  * Input:		sc	-- ptr to OSL internal ctlr context
930  *			buf	-- ptr to ioctl pkt understood by CL
931  * Output:		None
932  * Return value:	0	-- success
933  *			non-zero-- failure
934  */
935 TW_INT32
tw_osli_fw_passthru(struct twa_softc * sc,TW_INT8 * buf)936 tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf)
937 {
938 	struct tw_osli_req_context		*req;
939 	struct tw_osli_ioctl_no_data_buf	*user_buf =
940 		(struct tw_osli_ioctl_no_data_buf *)buf;
941 	TW_TIME					end_time;
942 	TW_UINT32				timeout = 60;
943 	TW_UINT32				data_buf_size_adjusted;
944 	struct tw_cl_req_packet			*req_pkt;
945 	struct tw_cl_passthru_req_packet	*pt_req;
946 	TW_INT32				error;
947 
948 	tw_osli_dbg_dprintf(5, sc, "ioctl: passthru");
949 
950 	if ((req = tw_osli_get_request(sc)) == NULL)
951 		return(EBUSY);
952 
953 	req->req_handle.osl_req_ctxt = req;
954 	req->orig_req = buf;
955 	req->flags |= TW_OSLI_REQ_FLAGS_PASSTHRU;
956 
957 	req_pkt = &(req->req_pkt);
958 	req_pkt->status = 0;
959 	req_pkt->tw_osl_callback = tw_osl_complete_passthru;
960 	/* Let the Common Layer retry the request on cmd queue full. */
961 	req_pkt->flags |= TW_CL_REQ_RETRY_ON_BUSY;
962 
963 	pt_req = &(req_pkt->gen_req_pkt.pt_req);
964 	/*
965 	 * Make sure that the data buffer sent to firmware is a
966 	 * 512 byte multiple in size.
967 	 */
968 	data_buf_size_adjusted =
969 		(user_buf->driver_pkt.buffer_length +
970 		(sc->sg_size_factor - 1)) & ~(sc->sg_size_factor - 1);
971 	if ((req->length = data_buf_size_adjusted)) {
972 		if ((req->data = malloc(data_buf_size_adjusted,
973 			TW_OSLI_MALLOC_CLASS, M_WAITOK)) == NULL) {
974 			error = ENOMEM;
975 			tw_osli_printf(sc, "error = %d",
976 				TW_CL_SEVERITY_ERROR_STRING,
977 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
978 				0x2016,
979 				"Could not alloc mem for "
980 				"fw_passthru data_buf",
981 				error);
982 			goto fw_passthru_err;
983 		}
984 		/* Copy the payload. */
985 		if ((error = copyin((TW_VOID *)(user_buf->pdata),
986 			req->data,
987 			user_buf->driver_pkt.buffer_length)) != 0) {
988 			tw_osli_printf(sc, "error = %d",
989 				TW_CL_SEVERITY_ERROR_STRING,
990 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
991 				0x2017,
992 				"Could not copyin fw_passthru data_buf",
993 				error);
994 			goto fw_passthru_err;
995 		}
996 		pt_req->sgl_entries = 1; /* will be updated during mapping */
997 		req->flags |= (TW_OSLI_REQ_FLAGS_DATA_IN |
998 			TW_OSLI_REQ_FLAGS_DATA_OUT);
999 	} else
1000 		pt_req->sgl_entries = 0; /* no payload */
1001 
1002 	pt_req->cmd_pkt = (TW_VOID *)(&(user_buf->cmd_pkt));
1003 	pt_req->cmd_pkt_length = sizeof(struct tw_cl_command_packet);
1004 
1005 	if ((error = tw_osli_map_request(req)))
1006 		goto fw_passthru_err;
1007 
1008 	end_time = tw_osl_get_local_time() + timeout;
1009 	while (req->state != TW_OSLI_REQ_STATE_COMPLETE) {
1010 		mtx_lock(req->ioctl_wake_timeout_lock);
1011 		req->flags |= TW_OSLI_REQ_FLAGS_SLEEPING;
1012 
1013 		error = mtx_sleep(req, req->ioctl_wake_timeout_lock, 0,
1014 			    "twa_passthru", timeout*hz);
1015 		mtx_unlock(req->ioctl_wake_timeout_lock);
1016 
1017 		if (!(req->flags & TW_OSLI_REQ_FLAGS_SLEEPING))
1018 			error = 0;
1019 		req->flags &= ~TW_OSLI_REQ_FLAGS_SLEEPING;
1020 
1021 		if (! error) {
1022 			if (((error = req->error_code)) ||
1023 				((error = (req->state !=
1024 				TW_OSLI_REQ_STATE_COMPLETE))) ||
1025 				((error = req_pkt->status)))
1026 				goto fw_passthru_err;
1027 			break;
1028 		}
1029 
1030 		if (req_pkt->status) {
1031 			error = req_pkt->status;
1032 			goto fw_passthru_err;
1033 		}
1034 
1035 		if (error == EWOULDBLOCK) {
1036 			/* Time out! */
1037 			if ((!(req->error_code))                       &&
1038 			    (req->state == TW_OSLI_REQ_STATE_COMPLETE) &&
1039 			    (!(req_pkt->status))			  ) {
1040 #ifdef    TW_OSL_DEBUG
1041 				tw_osli_printf(sc, "request = %p",
1042 					TW_CL_SEVERITY_ERROR_STRING,
1043 					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1044 					0x7777,
1045 					"FALSE Passthru timeout!",
1046 					req);
1047 #endif /* TW_OSL_DEBUG */
1048 				error = 0; /* False error */
1049 				break;
1050 			}
1051 			if (!(tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
1052 #ifdef    TW_OSL_DEBUG
1053 				tw_osli_printf(sc, "request = %p",
1054 					TW_CL_SEVERITY_ERROR_STRING,
1055 					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1056 					0x2018,
1057 					"Passthru request timed out!",
1058 					req);
1059 #else  /* TW_OSL_DEBUG */
1060 			device_printf((sc)->bus_dev, "Passthru request timed out!\n");
1061 #endif /* TW_OSL_DEBUG */
1062 				tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
1063 			}
1064 
1065 			error = 0;
1066 			end_time = tw_osl_get_local_time() + timeout;
1067 			continue;
1068 			/*
1069 			 * Don't touch req after a reset.  It (and any
1070 			 * associated data) will be
1071 			 * unmapped by the callback.
1072 			 */
1073 		}
1074 		/*
1075 		 * Either the request got completed, or we were woken up by a
1076 		 * signal.  Calculate the new timeout, in case it was the latter.
1077 		 */
1078 		timeout = (end_time - tw_osl_get_local_time());
1079 	} /* End of while loop */
1080 
1081 	/* If there was a payload, copy it back. */
1082 	if ((!error) && (req->length))
1083 		if ((error = copyout(req->data, user_buf->pdata,
1084 			user_buf->driver_pkt.buffer_length)))
1085 			tw_osli_printf(sc, "error = %d",
1086 				TW_CL_SEVERITY_ERROR_STRING,
1087 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1088 				0x2019,
1089 				"Could not copyout fw_passthru data_buf",
1090 				error);
1091 
1092 fw_passthru_err:
1093 
1094 	if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
1095 		error = EBUSY;
1096 
1097 	user_buf->driver_pkt.os_status = error;
1098 	/* Free resources. */
1099 	if (req->data)
1100 		free(req->data, TW_OSLI_MALLOC_CLASS);
1101 	tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
1102 	return(error);
1103 }
1104 
1105 /*
1106  * Function name:	tw_osl_complete_passthru
1107  * Description:		Called to complete passthru requests.
1108  *
1109  * Input:		req_handle	-- ptr to request handle
1110  * Output:		None
1111  * Return value:	None
1112  */
1113 TW_VOID
tw_osl_complete_passthru(struct tw_cl_req_handle * req_handle)1114 tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle)
1115 {
1116 	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
1117 	struct tw_cl_req_packet		*req_pkt =
1118 		(struct tw_cl_req_packet *)(&req->req_pkt);
1119 	struct twa_softc		*sc = req->ctlr;
1120 
1121 	tw_osli_dbg_dprintf(5, sc, "entered");
1122 
1123 	if (req->state != TW_OSLI_REQ_STATE_BUSY) {
1124 		tw_osli_printf(sc, "request = %p, status = %d",
1125 			TW_CL_SEVERITY_ERROR_STRING,
1126 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1127 			0x201B,
1128 			"Unposted command completed!!",
1129 			req, req->state);
1130 	}
1131 
1132 	/*
1133 	 * Remove request from the busy queue.  Just mark it complete.
1134 	 * There's no need to move it into the complete queue as we are
1135 	 * going to be done with it right now.
1136 	 */
1137 	req->state = TW_OSLI_REQ_STATE_COMPLETE;
1138 	tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
1139 
1140 	tw_osli_unmap_request(req);
1141 
1142 	/*
1143 	 * Don't do a wake up if there was an error even before the request
1144 	 * was sent down to the Common Layer, and we hadn't gotten an
1145 	 * EINPROGRESS.  The request originator will then be returned an
1146 	 * error, and he can do the clean-up.
1147 	 */
1148 	if ((req->error_code) && (!(req->flags & TW_OSLI_REQ_FLAGS_IN_PROGRESS)))
1149 		return;
1150 
1151 	if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1152 		if (req->flags & TW_OSLI_REQ_FLAGS_SLEEPING) {
1153 			/* Wake up the sleeping command originator. */
1154 			tw_osli_dbg_dprintf(5, sc,
1155 				"Waking up originator of request %p", req);
1156 			req->flags &= ~TW_OSLI_REQ_FLAGS_SLEEPING;
1157 			wakeup_one(req);
1158 		} else {
1159 			/*
1160 			 * If the request completed even before mtx_sleep
1161 			 * was called, simply return.
1162 			 */
1163 			if (req->flags & TW_OSLI_REQ_FLAGS_MAPPED)
1164 				return;
1165 
1166 			if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
1167 				return;
1168 
1169 			tw_osli_printf(sc, "request = %p",
1170 				TW_CL_SEVERITY_ERROR_STRING,
1171 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1172 				0x201C,
1173 				"Passthru callback called, "
1174 				"and caller not sleeping",
1175 				req);
1176 		}
1177 	} else {
1178 		tw_osli_printf(sc, "request = %p",
1179 			TW_CL_SEVERITY_ERROR_STRING,
1180 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1181 			0x201D,
1182 			"Passthru callback called for non-passthru request",
1183 			req);
1184 	}
1185 }
1186 
1187 /*
1188  * Function name:	tw_osli_get_request
1189  * Description:		Gets a request pkt from the free queue.
1190  *
1191  * Input:		sc	-- ptr to OSL internal ctlr context
1192  * Output:		None
1193  * Return value:	ptr to request pkt	-- success
1194  *			NULL			-- failure
1195  */
1196 struct tw_osli_req_context *
tw_osli_get_request(struct twa_softc * sc)1197 tw_osli_get_request(struct twa_softc *sc)
1198 {
1199 	struct tw_osli_req_context	*req;
1200 
1201 	tw_osli_dbg_dprintf(4, sc, "entered");
1202 
1203 	/* Get a free request packet. */
1204 	req = tw_osli_req_q_remove_head(sc, TW_OSLI_FREE_Q);
1205 
1206 	/* Initialize some fields to their defaults. */
1207 	if (req) {
1208 		req->req_handle.osl_req_ctxt = NULL;
1209 		req->req_handle.cl_req_ctxt = NULL;
1210 		req->req_handle.is_io = 0;
1211 		req->data = NULL;
1212 		req->length = 0;
1213 		req->deadline = 0;
1214 		req->real_data = NULL;
1215 		req->real_length = 0;
1216 		req->state = TW_OSLI_REQ_STATE_INIT;/* req being initialized */
1217 		req->flags = 0;
1218 		req->error_code = 0;
1219 		req->orig_req = NULL;
1220 
1221 		bzero(&(req->req_pkt), sizeof(struct tw_cl_req_packet));
1222 	}
1223 	return(req);
1224 }
1225 
1226 /*
1227  * Function name:	twa_map_load_data_callback
1228  * Description:		Callback of bus_dmamap_load for the buffer associated
1229  *			with data.  Updates the cmd pkt (size/sgl_entries
1230  *			fields, as applicable) to reflect the number of sg
1231  *			elements.
1232  *
1233  * Input:		arg	-- ptr to OSL internal request context
1234  *			segs	-- ptr to a list of segment descriptors
1235  *			nsegments--# of segments
1236  *			error	-- 0 if no errors encountered before callback,
1237  *				   non-zero if errors were encountered
1238  * Output:		None
1239  * Return value:	None
1240  */
1241 static TW_VOID
twa_map_load_data_callback(TW_VOID * arg,bus_dma_segment_t * segs,TW_INT32 nsegments,TW_INT32 error)1242 twa_map_load_data_callback(TW_VOID *arg, bus_dma_segment_t *segs,
1243 	TW_INT32 nsegments, TW_INT32 error)
1244 {
1245 	struct tw_osli_req_context	*req =
1246 		(struct tw_osli_req_context *)arg;
1247 	struct twa_softc		*sc = req->ctlr;
1248 	struct tw_cl_req_packet		*req_pkt = &(req->req_pkt);
1249 
1250 	tw_osli_dbg_dprintf(10, sc, "entered");
1251 
1252 	if (error == EINVAL) {
1253 		req->error_code = error;
1254 		return;
1255 	}
1256 
1257 	/* Mark the request as currently being processed. */
1258 	req->state = TW_OSLI_REQ_STATE_BUSY;
1259 	/* Move the request into the busy queue. */
1260 	tw_osli_req_q_insert_tail(req, TW_OSLI_BUSY_Q);
1261 
1262 	req->flags |= TW_OSLI_REQ_FLAGS_MAPPED;
1263 
1264 	if (error == EFBIG) {
1265 		req->error_code = error;
1266 		goto out;
1267 	}
1268 
1269 	if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1270 		struct tw_cl_passthru_req_packet	*pt_req;
1271 
1272 		if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN)
1273 			bus_dmamap_sync(sc->ioctl_tag, sc->ioctl_map,
1274 				BUS_DMASYNC_PREREAD);
1275 
1276 		if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT) {
1277 			/*
1278 			 * If we're using an alignment buffer, and we're
1279 			 * writing data, copy the real data out.
1280 			 */
1281 			if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1282 				bcopy(req->real_data, req->data, req->real_length);
1283 			bus_dmamap_sync(sc->ioctl_tag, sc->ioctl_map,
1284 				BUS_DMASYNC_PREWRITE);
1285 		}
1286 
1287 		pt_req = &(req_pkt->gen_req_pkt.pt_req);
1288 		pt_req->sg_list = (TW_UINT8 *)segs;
1289 		pt_req->sgl_entries += (nsegments - 1);
1290 		error = tw_cl_fw_passthru(&(sc->ctlr_handle), req_pkt,
1291 			&(req->req_handle));
1292 	} else {
1293 		struct tw_cl_scsi_req_packet	*scsi_req;
1294 
1295 		if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN)
1296 			bus_dmamap_sync(sc->dma_tag, req->dma_map,
1297 				BUS_DMASYNC_PREREAD);
1298 
1299 		if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT) {
1300 			/*
1301 			 * If we're using an alignment buffer, and we're
1302 			 * writing data, copy the real data out.
1303 			 */
1304 			if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1305 				bcopy(req->real_data, req->data, req->real_length);
1306 			bus_dmamap_sync(sc->dma_tag, req->dma_map,
1307 				BUS_DMASYNC_PREWRITE);
1308 		}
1309 
1310 		scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
1311 		scsi_req->sg_list = (TW_UINT8 *)segs;
1312 		scsi_req->sgl_entries += (nsegments - 1);
1313 		error = tw_cl_start_io(&(sc->ctlr_handle), req_pkt,
1314 			&(req->req_handle));
1315 	}
1316 
1317 out:
1318 	if (error) {
1319 		req->error_code = error;
1320 		req_pkt->tw_osl_callback(&(req->req_handle));
1321 		/*
1322 		 * If the caller had been returned EINPROGRESS, and he has
1323 		 * registered a callback for handling completion, the callback
1324 		 * will never get called because we were unable to submit the
1325 		 * request.  So, free up the request right here.
1326 		 */
1327 		if (req->flags & TW_OSLI_REQ_FLAGS_IN_PROGRESS)
1328 			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
1329 	}
1330 }
1331 
1332 /*
1333  * Function name:	twa_map_load_callback
1334  * Description:		Callback of bus_dmamap_load for the buffer associated
1335  *			with a cmd pkt.
1336  *
1337  * Input:		arg	-- ptr to variable to hold phys addr
1338  *			segs	-- ptr to a list of segment descriptors
1339  *			nsegments--# of segments
1340  *			error	-- 0 if no errors encountered before callback,
1341  *				   non-zero if errors were encountered
1342  * Output:		None
1343  * Return value:	None
1344  */
1345 static TW_VOID
twa_map_load_callback(TW_VOID * arg,bus_dma_segment_t * segs,TW_INT32 nsegments,TW_INT32 error)1346 twa_map_load_callback(TW_VOID *arg, bus_dma_segment_t *segs,
1347 	TW_INT32 nsegments, TW_INT32 error)
1348 {
1349 	*((bus_addr_t *)arg) = segs[0].ds_addr;
1350 }
1351 
1352 /*
1353  * Function name:	tw_osli_map_request
1354  * Description:		Maps a cmd pkt and data associated with it, into
1355  *			DMA'able memory.
1356  *
1357  * Input:		req	-- ptr to request pkt
1358  * Output:		None
1359  * Return value:	0	-- success
1360  *			non-zero-- failure
1361  */
1362 TW_INT32
tw_osli_map_request(struct tw_osli_req_context * req)1363 tw_osli_map_request(struct tw_osli_req_context *req)
1364 {
1365 	struct twa_softc	*sc = req->ctlr;
1366 	TW_INT32		error = 0;
1367 
1368 	tw_osli_dbg_dprintf(10, sc, "entered");
1369 
1370 	/* If the command involves data, map that too. */
1371 	if (req->data != NULL) {
1372 		/*
1373 		 * It's sufficient for the data pointer to be 4-byte aligned
1374 		 * to work with 9000.  However, if 4-byte aligned addresses
1375 		 * are passed to bus_dmamap_load, we can get back sg elements
1376 		 * that are not 512-byte multiples in size.  So, we will let
1377 		 * only those buffers that are 512-byte aligned to pass
1378 		 * through, and bounce the rest, so as to make sure that we
1379 		 * always get back sg elements that are 512-byte multiples
1380 		 * in size.
1381 		 */
1382 		if (((vm_offset_t)req->data % sc->sg_size_factor) ||
1383 			(req->length % sc->sg_size_factor)) {
1384 			req->flags |= TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED;
1385 			/* Save original data pointer and length. */
1386 			req->real_data = req->data;
1387 			req->real_length = req->length;
1388 			req->length = (req->length +
1389 				(sc->sg_size_factor - 1)) &
1390 				~(sc->sg_size_factor - 1);
1391 			req->data = malloc(req->length, TW_OSLI_MALLOC_CLASS,
1392 					M_NOWAIT);
1393 			if (req->data == NULL) {
1394 				tw_osli_printf(sc, "error = %d",
1395 					TW_CL_SEVERITY_ERROR_STRING,
1396 					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1397 					0x201E,
1398 					"Failed to allocate memory "
1399 					"for bounce buffer",
1400 					ENOMEM);
1401 				/* Restore original data pointer and length. */
1402 				req->data = req->real_data;
1403 				req->length = req->real_length;
1404 				return(ENOMEM);
1405 			}
1406 		}
1407 
1408 		/*
1409 		 * Map the data buffer into bus space and build the SG list.
1410 		 */
1411 		if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1412 			/* Lock against multiple simultaneous ioctl calls. */
1413 			mtx_lock_spin(sc->io_lock);
1414 			error = bus_dmamap_load(sc->ioctl_tag, sc->ioctl_map,
1415 				req->data, req->length,
1416 				twa_map_load_data_callback, req,
1417 				BUS_DMA_WAITOK);
1418 			mtx_unlock_spin(sc->io_lock);
1419 		} else if (req->flags & TW_OSLI_REQ_FLAGS_CCB) {
1420 			error = bus_dmamap_load_ccb(sc->dma_tag, req->dma_map,
1421 				req->orig_req, twa_map_load_data_callback, req,
1422 				BUS_DMA_WAITOK);
1423 		} else {
1424 			/*
1425 			 * There's only one CAM I/O thread running at a time.
1426 			 * So, there's no need to hold the io_lock.
1427 			 */
1428 			error = bus_dmamap_load(sc->dma_tag, req->dma_map,
1429 				req->data, req->length,
1430 				twa_map_load_data_callback, req,
1431 				BUS_DMA_WAITOK);
1432 		}
1433 
1434 		if (!error)
1435 			error = req->error_code;
1436 		else {
1437 			if (error == EINPROGRESS) {
1438 				/*
1439 				 * Specifying sc->io_lock as the lockfuncarg
1440 				 * in ...tag_create should protect the access
1441 				 * of ...FLAGS_MAPPED from the callback.
1442 				 */
1443 				mtx_lock_spin(sc->io_lock);
1444 				if (!(req->flags & TW_OSLI_REQ_FLAGS_MAPPED))
1445 					req->flags |= TW_OSLI_REQ_FLAGS_IN_PROGRESS;
1446 				tw_osli_disallow_new_requests(sc, &(req->req_handle));
1447 				mtx_unlock_spin(sc->io_lock);
1448 				error = 0;
1449 			} else {
1450 				tw_osli_printf(sc, "error = %d",
1451 					TW_CL_SEVERITY_ERROR_STRING,
1452 					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1453 					0x9999,
1454 					"Failed to map DMA memory "
1455 					"for I/O request",
1456 					error);
1457 				req->flags |= TW_OSLI_REQ_FLAGS_FAILED;
1458 				/* Free alignment buffer if it was used. */
1459 				if (req->flags &
1460 					TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) {
1461 					free(req->data, TW_OSLI_MALLOC_CLASS);
1462 					/*
1463 					 * Restore original data pointer
1464 					 * and length.
1465 					 */
1466 					req->data = req->real_data;
1467 					req->length = req->real_length;
1468 				}
1469 			}
1470 		}
1471 
1472 	} else {
1473 		/* Mark the request as currently being processed. */
1474 		req->state = TW_OSLI_REQ_STATE_BUSY;
1475 		/* Move the request into the busy queue. */
1476 		tw_osli_req_q_insert_tail(req, TW_OSLI_BUSY_Q);
1477 		if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU)
1478 			error = tw_cl_fw_passthru(&sc->ctlr_handle,
1479 					&(req->req_pkt), &(req->req_handle));
1480 		else
1481 			error = tw_cl_start_io(&sc->ctlr_handle,
1482 					&(req->req_pkt), &(req->req_handle));
1483 		if (error) {
1484 			req->error_code = error;
1485 			req->req_pkt.tw_osl_callback(&(req->req_handle));
1486 		}
1487 	}
1488 	return(error);
1489 }
1490 
1491 /*
1492  * Function name:	tw_osli_unmap_request
1493  * Description:		Undoes the mapping done by tw_osli_map_request.
1494  *
1495  * Input:		req	-- ptr to request pkt
1496  * Output:		None
1497  * Return value:	None
1498  */
1499 TW_VOID
tw_osli_unmap_request(struct tw_osli_req_context * req)1500 tw_osli_unmap_request(struct tw_osli_req_context *req)
1501 {
1502 	struct twa_softc	*sc = req->ctlr;
1503 
1504 	tw_osli_dbg_dprintf(10, sc, "entered");
1505 
1506 	/* If the command involved data, unmap that too. */
1507 	if (req->data != NULL) {
1508 		if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1509 			/* Lock against multiple simultaneous ioctl calls. */
1510 			mtx_lock_spin(sc->io_lock);
1511 
1512 			if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN) {
1513 				bus_dmamap_sync(sc->ioctl_tag,
1514 					sc->ioctl_map, BUS_DMASYNC_POSTREAD);
1515 
1516 				/*
1517 				 * If we are using a bounce buffer, and we are
1518 				 * reading data, copy the real data in.
1519 				 */
1520 				if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1521 					bcopy(req->data, req->real_data,
1522 						req->real_length);
1523 			}
1524 
1525 			if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT)
1526 				bus_dmamap_sync(sc->ioctl_tag, sc->ioctl_map,
1527 					BUS_DMASYNC_POSTWRITE);
1528 
1529 			bus_dmamap_unload(sc->ioctl_tag, sc->ioctl_map);
1530 
1531 			mtx_unlock_spin(sc->io_lock);
1532 		} else {
1533 			if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN) {
1534 				bus_dmamap_sync(sc->dma_tag,
1535 					req->dma_map, BUS_DMASYNC_POSTREAD);
1536 
1537 				/*
1538 				 * If we are using a bounce buffer, and we are
1539 				 * reading data, copy the real data in.
1540 				 */
1541 				if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1542 					bcopy(req->data, req->real_data,
1543 						req->real_length);
1544 			}
1545 			if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT)
1546 				bus_dmamap_sync(sc->dma_tag, req->dma_map,
1547 					BUS_DMASYNC_POSTWRITE);
1548 
1549 			bus_dmamap_unload(sc->dma_tag, req->dma_map);
1550 		}
1551 	}
1552 
1553 	/* Free alignment buffer if it was used. */
1554 	if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) {
1555 		free(req->data, TW_OSLI_MALLOC_CLASS);
1556 		/* Restore original data pointer and length. */
1557 		req->data = req->real_data;
1558 		req->length = req->real_length;
1559 	}
1560 }
1561 
1562 #ifdef TW_OSL_DEBUG
1563 
1564 TW_VOID	twa_report_stats(TW_VOID);
1565 TW_VOID	twa_reset_stats(TW_VOID);
1566 TW_VOID	tw_osli_print_ctlr_stats(struct twa_softc *sc);
1567 TW_VOID twa_print_req_info(struct tw_osli_req_context *req);
1568 
1569 /*
1570  * Function name:	twa_report_stats
1571  * Description:		For being called from ddb.  Calls functions that print
1572  *			OSL and CL internal stats for the controller.
1573  *
1574  * Input:		None
1575  * Output:		None
1576  * Return value:	None
1577  */
1578 TW_VOID
twa_report_stats(TW_VOID)1579 twa_report_stats(TW_VOID)
1580 {
1581 	struct twa_softc	*sc;
1582 	TW_INT32		i;
1583 
1584 	for (i = 0; (sc = devclass_get_softc(twa_devclass, i)) != NULL; i++) {
1585 		tw_osli_print_ctlr_stats(sc);
1586 		tw_cl_print_ctlr_stats(&sc->ctlr_handle);
1587 	}
1588 }
1589 
1590 /*
1591  * Function name:	tw_osli_print_ctlr_stats
1592  * Description:		For being called from ddb.  Prints OSL controller stats
1593  *
1594  * Input:		sc	-- ptr to OSL internal controller context
1595  * Output:		None
1596  * Return value:	None
1597  */
1598 TW_VOID
tw_osli_print_ctlr_stats(struct twa_softc * sc)1599 tw_osli_print_ctlr_stats(struct twa_softc *sc)
1600 {
1601 	twa_printf(sc, "osl_ctlr_ctxt = %p\n", sc);
1602 	twa_printf(sc, "OSLq type  current  max\n");
1603 	twa_printf(sc, "free      %04d     %04d\n",
1604 		sc->q_stats[TW_OSLI_FREE_Q].cur_len,
1605 		sc->q_stats[TW_OSLI_FREE_Q].max_len);
1606 	twa_printf(sc, "busy      %04d     %04d\n",
1607 		sc->q_stats[TW_OSLI_BUSY_Q].cur_len,
1608 		sc->q_stats[TW_OSLI_BUSY_Q].max_len);
1609 }
1610 
1611 /*
1612  * Function name:	twa_print_req_info
1613  * Description:		For being called from ddb.  Calls functions that print
1614  *			OSL and CL internal details for the request.
1615  *
1616  * Input:		req	-- ptr to OSL internal request context
1617  * Output:		None
1618  * Return value:	None
1619  */
1620 TW_VOID
twa_print_req_info(struct tw_osli_req_context * req)1621 twa_print_req_info(struct tw_osli_req_context *req)
1622 {
1623 	struct twa_softc	*sc = req->ctlr;
1624 
1625 	twa_printf(sc, "OSL details for request:\n");
1626 	twa_printf(sc, "osl_req_ctxt = %p, cl_req_ctxt = %p\n"
1627 		"data = %p, length = 0x%x, real_data = %p, real_length = 0x%x\n"
1628 		"state = 0x%x, flags = 0x%x, error = 0x%x, orig_req = %p\n"
1629 		"next_req = %p, prev_req = %p, dma_map = %p\n",
1630 		req->req_handle.osl_req_ctxt, req->req_handle.cl_req_ctxt,
1631 		req->data, req->length, req->real_data, req->real_length,
1632 		req->state, req->flags, req->error_code, req->orig_req,
1633 		req->link.next, req->link.prev, req->dma_map);
1634 	tw_cl_print_req_info(&(req->req_handle));
1635 }
1636 
1637 /*
1638  * Function name:	twa_reset_stats
1639  * Description:		For being called from ddb.
1640  *			Resets some OSL controller stats.
1641  *
1642  * Input:		None
1643  * Output:		None
1644  * Return value:	None
1645  */
1646 TW_VOID
twa_reset_stats(TW_VOID)1647 twa_reset_stats(TW_VOID)
1648 {
1649 	struct twa_softc	*sc;
1650 	TW_INT32		i;
1651 
1652 	for (i = 0; (sc = devclass_get_softc(twa_devclass, i)) != NULL; i++) {
1653 		sc->q_stats[TW_OSLI_FREE_Q].max_len = 0;
1654 		sc->q_stats[TW_OSLI_BUSY_Q].max_len = 0;
1655 		tw_cl_reset_stats(&sc->ctlr_handle);
1656 	}
1657 }
1658 
1659 #endif /* TW_OSL_DEBUG */
1660