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