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