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 *
291e0dd9ddSSascha Wildner * $FreeBSD: head/sys/dev/twa/tw_osl_freebsd.c 254263 2013-08-12 23:30:01Z scottl $
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
5785b59853SSascha Wildner static 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 = {
6507702f9dSSascha Wildner { "twa", 0, D_MPSAFE },
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
732c77752eSSascha Wildner static int twa_msi_enable = 0;
742c77752eSSascha Wildner TUNABLE_INT("hw.twa.msi.enable", &twa_msi_enable);
752c77752eSSascha Wildner
76df54c2f9SSascha Wildner
77df54c2f9SSascha Wildner /*
78df54c2f9SSascha Wildner * Function name: twa_open
79df54c2f9SSascha Wildner * Description: Called when the controller is opened.
80df54c2f9SSascha Wildner * Simply marks the controller as open.
81df54c2f9SSascha Wildner *
82df54c2f9SSascha Wildner * Input: dev -- control device corresponding to the ctlr
83df54c2f9SSascha Wildner * flags -- mode of open
84df54c2f9SSascha Wildner * fmt -- device type (character/block etc.)
85df54c2f9SSascha Wildner * proc -- current process
86df54c2f9SSascha Wildner * Output: None
87df54c2f9SSascha Wildner * Return value: 0 -- success
88df54c2f9SSascha Wildner * non-zero-- failure
89df54c2f9SSascha Wildner */
90df54c2f9SSascha Wildner static TW_INT32
twa_open(struct dev_open_args * ap)91df54c2f9SSascha Wildner twa_open(struct dev_open_args *ap)
92df54c2f9SSascha Wildner {
93df54c2f9SSascha Wildner cdev_t dev = ap->a_head.a_dev;
94df54c2f9SSascha Wildner struct twa_softc *sc = (struct twa_softc *)(dev->si_drv1);
95df54c2f9SSascha Wildner
96df54c2f9SSascha Wildner tw_osli_dbg_dprintf(5, sc, "entered");
97df54c2f9SSascha Wildner sc->open = TW_CL_TRUE;
98df54c2f9SSascha Wildner return(0);
99df54c2f9SSascha Wildner }
100df54c2f9SSascha Wildner
101df54c2f9SSascha Wildner
102df54c2f9SSascha Wildner
103df54c2f9SSascha Wildner /*
104df54c2f9SSascha Wildner * Function name: twa_close
105df54c2f9SSascha Wildner * Description: Called when the controller is closed.
106df54c2f9SSascha Wildner * Simply marks the controller as not open.
107df54c2f9SSascha Wildner *
108df54c2f9SSascha Wildner * Input: dev -- control device corresponding to the ctlr
109df54c2f9SSascha Wildner * flags -- mode of corresponding open
110df54c2f9SSascha Wildner * fmt -- device type (character/block etc.)
111df54c2f9SSascha Wildner * proc -- current process
112df54c2f9SSascha Wildner * Output: None
113df54c2f9SSascha Wildner * Return value: 0 -- success
114df54c2f9SSascha Wildner * non-zero-- failure
115df54c2f9SSascha Wildner */
116df54c2f9SSascha Wildner static TW_INT32
twa_close(struct dev_close_args * ap)117df54c2f9SSascha Wildner twa_close(struct dev_close_args *ap)
118df54c2f9SSascha Wildner {
119df54c2f9SSascha Wildner cdev_t dev = ap->a_head.a_dev;
120df54c2f9SSascha Wildner struct twa_softc *sc = (struct twa_softc *)(dev->si_drv1);
121df54c2f9SSascha Wildner
122df54c2f9SSascha Wildner tw_osli_dbg_dprintf(5, sc, "entered");
123df54c2f9SSascha Wildner sc->open = TW_CL_FALSE;
124df54c2f9SSascha Wildner return(0);
125df54c2f9SSascha Wildner }
126df54c2f9SSascha Wildner
127df54c2f9SSascha Wildner
128df54c2f9SSascha Wildner
129df54c2f9SSascha Wildner /*
130df54c2f9SSascha Wildner * Function name: twa_ioctl
131df54c2f9SSascha Wildner * Description: Called when an ioctl is posted to the controller.
132df54c2f9SSascha Wildner * Handles any OS Layer specific cmds, passes the rest
133df54c2f9SSascha Wildner * on to the Common Layer.
134df54c2f9SSascha Wildner *
135df54c2f9SSascha Wildner * Input: dev -- control device corresponding to the ctlr
136df54c2f9SSascha Wildner * cmd -- ioctl cmd
137df54c2f9SSascha Wildner * buf -- ptr to buffer in kernel memory, which is
138df54c2f9SSascha Wildner * a copy of the input buffer in user-space
139df54c2f9SSascha Wildner * flags -- mode of corresponding open
140df54c2f9SSascha Wildner * proc -- current process
141df54c2f9SSascha Wildner * Output: buf -- ptr to buffer in kernel memory, which will
142df54c2f9SSascha Wildner * be copied to the output buffer in user-space
143df54c2f9SSascha Wildner * Return value: 0 -- success
144df54c2f9SSascha Wildner * non-zero-- failure
145df54c2f9SSascha Wildner */
146df54c2f9SSascha Wildner static TW_INT32
twa_ioctl(struct dev_ioctl_args * ap)147df54c2f9SSascha Wildner twa_ioctl(struct dev_ioctl_args *ap)
148df54c2f9SSascha Wildner {
149df54c2f9SSascha Wildner cdev_t dev = ap->a_head.a_dev;
150df54c2f9SSascha Wildner u_long cmd = ap->a_cmd;
151df54c2f9SSascha Wildner caddr_t buf = ap->a_data;
152df54c2f9SSascha Wildner struct twa_softc *sc = (struct twa_softc *)(dev->si_drv1);
153df54c2f9SSascha Wildner TW_INT32 error;
154df54c2f9SSascha Wildner
155df54c2f9SSascha Wildner tw_osli_dbg_dprintf(5, sc, "entered");
156df54c2f9SSascha Wildner
157df54c2f9SSascha Wildner switch (cmd) {
158df54c2f9SSascha Wildner case TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH:
159df54c2f9SSascha Wildner tw_osli_dbg_dprintf(6, sc, "ioctl: fw_passthru");
160df54c2f9SSascha Wildner error = tw_osli_fw_passthru(sc, (TW_INT8 *)buf);
161df54c2f9SSascha Wildner break;
162df54c2f9SSascha Wildner
163df54c2f9SSascha Wildner case TW_OSL_IOCTL_SCAN_BUS:
164df54c2f9SSascha Wildner /* Request CAM for a bus scan. */
165df54c2f9SSascha Wildner tw_osli_dbg_dprintf(6, sc, "ioctl: scan bus");
166df54c2f9SSascha Wildner error = tw_osli_request_bus_scan(sc);
167df54c2f9SSascha Wildner break;
168df54c2f9SSascha Wildner
169df54c2f9SSascha Wildner default:
170df54c2f9SSascha Wildner tw_osli_dbg_dprintf(6, sc, "ioctl: 0x%lx", cmd);
171df54c2f9SSascha Wildner error = tw_cl_ioctl(&sc->ctlr_handle, cmd, buf);
172df54c2f9SSascha Wildner break;
173df54c2f9SSascha Wildner }
174df54c2f9SSascha Wildner return(error);
175df54c2f9SSascha Wildner }
176df54c2f9SSascha Wildner
177df54c2f9SSascha Wildner
178df54c2f9SSascha Wildner
179df54c2f9SSascha Wildner static TW_INT32 twa_probe(device_t dev);
180df54c2f9SSascha Wildner static TW_INT32 twa_attach(device_t dev);
181df54c2f9SSascha Wildner static TW_INT32 twa_detach(device_t dev);
182df54c2f9SSascha Wildner static TW_INT32 twa_shutdown(device_t dev);
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
204d3c9c58eSSascha Wildner DEVMETHOD_END
205df54c2f9SSascha Wildner };
206df54c2f9SSascha Wildner
207df54c2f9SSascha Wildner static driver_t twa_pci_driver = {
208df54c2f9SSascha Wildner "twa",
209df54c2f9SSascha Wildner twa_methods,
210df54c2f9SSascha Wildner sizeof(struct twa_softc)
211df54c2f9SSascha Wildner };
212df54c2f9SSascha Wildner
213aa2b9d05SSascha Wildner DRIVER_MODULE(twa, pci, twa_pci_driver, twa_devclass, NULL, NULL);
214df54c2f9SSascha Wildner MODULE_DEPEND(twa, cam, 1, 1, 1);
215df54c2f9SSascha Wildner MODULE_DEPEND(twa, pci, 1, 1, 1);
216b84936a8SSascha Wildner MODULE_VERSION(twa, 1);
217df54c2f9SSascha Wildner
218df54c2f9SSascha Wildner
219df54c2f9SSascha Wildner /*
220df54c2f9SSascha Wildner * Function name: twa_probe
221df54c2f9SSascha Wildner * Description: Called at driver load time. Claims 9000 ctlrs.
222df54c2f9SSascha Wildner *
223df54c2f9SSascha Wildner * Input: dev -- bus device corresponding to the ctlr
224df54c2f9SSascha Wildner * Output: None
225df54c2f9SSascha Wildner * Return value: <= 0 -- success
226df54c2f9SSascha Wildner * > 0 -- failure
227df54c2f9SSascha Wildner */
228df54c2f9SSascha Wildner static TW_INT32
twa_probe(device_t dev)229df54c2f9SSascha Wildner twa_probe(device_t dev)
230df54c2f9SSascha Wildner {
231df54c2f9SSascha Wildner static TW_UINT8 first_ctlr = 1;
232df54c2f9SSascha Wildner
233df54c2f9SSascha Wildner tw_osli_dbg_printf(3, "entered");
234df54c2f9SSascha Wildner
235df54c2f9SSascha Wildner if (tw_cl_ctlr_supported(pci_get_vendor(dev), pci_get_device(dev))) {
236df54c2f9SSascha Wildner device_set_desc(dev, TW_OSLI_DEVICE_NAME);
237df54c2f9SSascha Wildner /* Print the driver version only once. */
238df54c2f9SSascha Wildner if (first_ctlr) {
239df54c2f9SSascha Wildner kprintf("3ware device driver for 9000 series storage "
240df54c2f9SSascha Wildner "controllers, version: %s\n",
241df54c2f9SSascha Wildner TW_OSL_DRIVER_VERSION_STRING);
242df54c2f9SSascha Wildner first_ctlr = 0;
243df54c2f9SSascha Wildner }
244df54c2f9SSascha Wildner return(0);
245df54c2f9SSascha Wildner }
246df54c2f9SSascha Wildner return(ENXIO);
247df54c2f9SSascha Wildner }
248df54c2f9SSascha Wildner
twa_setup_intr(struct twa_softc * sc)2494fbf05f9SSascha Wildner int twa_setup_intr(struct twa_softc *sc)
2504fbf05f9SSascha Wildner {
2514fbf05f9SSascha Wildner int error = 0;
2524fbf05f9SSascha Wildner
2534fbf05f9SSascha Wildner if (!(sc->intr_handle) && (sc->irq_res)) {
2544fbf05f9SSascha Wildner error = bus_setup_intr(sc->bus_dev, sc->irq_res,
25585b59853SSascha Wildner INTR_MPSAFE,
2564fbf05f9SSascha Wildner twa_pci_intr,
2574fbf05f9SSascha Wildner sc, &sc->intr_handle, NULL);
2584fbf05f9SSascha Wildner }
2594fbf05f9SSascha Wildner return( error );
2604fbf05f9SSascha Wildner }
2614fbf05f9SSascha Wildner
2624fbf05f9SSascha Wildner
twa_teardown_intr(struct twa_softc * sc)2634fbf05f9SSascha Wildner int twa_teardown_intr(struct twa_softc *sc)
2644fbf05f9SSascha Wildner {
2654fbf05f9SSascha Wildner int error = 0;
2664fbf05f9SSascha Wildner
2674fbf05f9SSascha Wildner if ((sc->intr_handle) && (sc->irq_res)) {
2684fbf05f9SSascha Wildner error = bus_teardown_intr(sc->bus_dev,
2694fbf05f9SSascha Wildner sc->irq_res, sc->intr_handle);
2704fbf05f9SSascha Wildner sc->intr_handle = NULL;
2714fbf05f9SSascha Wildner }
2724fbf05f9SSascha Wildner return( error );
2734fbf05f9SSascha Wildner }
2744fbf05f9SSascha Wildner
275df54c2f9SSascha Wildner
276df54c2f9SSascha Wildner
277df54c2f9SSascha Wildner /*
278df54c2f9SSascha Wildner * Function name: twa_attach
279df54c2f9SSascha Wildner * Description: Allocates pci resources; updates sc; adds a node to the
280df54c2f9SSascha Wildner * sysctl tree to expose the driver version; makes calls
281df54c2f9SSascha Wildner * (to the Common Layer) to initialize ctlr, and to
282df54c2f9SSascha Wildner * attach to CAM.
283df54c2f9SSascha Wildner *
284df54c2f9SSascha Wildner * Input: dev -- bus device corresponding to the ctlr
285df54c2f9SSascha Wildner * Output: None
286df54c2f9SSascha Wildner * Return value: 0 -- success
287df54c2f9SSascha Wildner * non-zero-- failure
288df54c2f9SSascha Wildner */
289df54c2f9SSascha Wildner static TW_INT32
twa_attach(device_t dev)290df54c2f9SSascha Wildner twa_attach(device_t dev)
291df54c2f9SSascha Wildner {
292df54c2f9SSascha Wildner struct twa_softc *sc = device_get_softc(dev);
293df54c2f9SSascha Wildner TW_INT32 bar_num;
294df54c2f9SSascha Wildner TW_INT32 bar0_offset;
295df54c2f9SSascha Wildner TW_INT32 bar_size;
2962c77752eSSascha Wildner TW_INT32 irq_flags;
297df54c2f9SSascha Wildner TW_INT32 error;
298df54c2f9SSascha Wildner
299df54c2f9SSascha Wildner sc->ctlr_handle.osl_ctlr_ctxt = sc;
300df54c2f9SSascha Wildner
301df54c2f9SSascha Wildner /* Initialize the softc structure. */
302df54c2f9SSascha Wildner sc->bus_dev = dev;
30393fd7312SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
304df54c2f9SSascha Wildner sc->device_id = pci_get_device(dev);
305df54c2f9SSascha Wildner
306df54c2f9SSascha Wildner /* Initialize the mutexes right here. */
307df54c2f9SSascha Wildner sc->io_lock = &(sc->io_lock_handle);
308ba87a4abSSascha Wildner spin_init(sc->io_lock, "twa_iolock");
309df54c2f9SSascha Wildner sc->q_lock = &(sc->q_lock_handle);
310ba87a4abSSascha Wildner spin_init(sc->q_lock, "twa_qlock");
311df54c2f9SSascha Wildner sc->sim_lock = &(sc->sim_lock_handle);
312df54c2f9SSascha Wildner lockinit(sc->sim_lock, "tw_osl_sim_lock", 0, LK_CANRECURSE);
313df54c2f9SSascha Wildner
31426595b18SSascha Wildner SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
31526595b18SSascha Wildner SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
316df54c2f9SSascha Wildner OID_AUTO, "driver_version", CTLFLAG_RD,
317df54c2f9SSascha Wildner TW_OSL_DRIVER_VERSION_STRING, 0, "TWA driver version");
318df54c2f9SSascha Wildner
319df54c2f9SSascha Wildner /* Force the busmaster enable bit on, in case the BIOS forgot. */
3201e0dd9ddSSascha Wildner pci_enable_busmaster(dev);
321df54c2f9SSascha Wildner
322df54c2f9SSascha Wildner /* Allocate the PCI register window. */
323df54c2f9SSascha Wildner if ((error = tw_cl_get_pci_bar_info(sc->device_id, TW_CL_BAR_TYPE_MEM,
324df54c2f9SSascha Wildner &bar_num, &bar0_offset, &bar_size))) {
325df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
326df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
327df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
328df54c2f9SSascha Wildner 0x201F,
329df54c2f9SSascha Wildner "Can't get PCI BAR info",
330df54c2f9SSascha Wildner error);
331df54c2f9SSascha Wildner tw_osli_free_resources(sc);
332df54c2f9SSascha Wildner return(error);
333df54c2f9SSascha Wildner }
334df54c2f9SSascha Wildner sc->reg_res_id = PCIR_BARS + bar0_offset;
335df54c2f9SSascha Wildner if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
336df54c2f9SSascha Wildner &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE))
337df54c2f9SSascha Wildner == NULL) {
338df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
339df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
340df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
341df54c2f9SSascha Wildner 0x2002,
342df54c2f9SSascha Wildner "Can't allocate register window",
343df54c2f9SSascha Wildner ENXIO);
344df54c2f9SSascha Wildner tw_osli_free_resources(sc);
345df54c2f9SSascha Wildner return(ENXIO);
346df54c2f9SSascha Wildner }
347df54c2f9SSascha Wildner sc->bus_tag = rman_get_bustag(sc->reg_res);
348df54c2f9SSascha Wildner sc->bus_handle = rman_get_bushandle(sc->reg_res);
349df54c2f9SSascha Wildner
350df54c2f9SSascha Wildner /* Allocate and register our interrupt. */
351df54c2f9SSascha Wildner sc->irq_res_id = 0;
3522c77752eSSascha Wildner sc->irq_type = pci_alloc_1intr(sc->bus_dev, twa_msi_enable,
3532c77752eSSascha Wildner &sc->irq_res_id, &irq_flags);
354df54c2f9SSascha Wildner if ((sc->irq_res = bus_alloc_resource(sc->bus_dev, SYS_RES_IRQ,
355df54c2f9SSascha Wildner &(sc->irq_res_id), 0, ~0, 1,
3562c77752eSSascha Wildner irq_flags)) == NULL) {
357df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
358df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
359df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
360df54c2f9SSascha Wildner 0x2003,
361df54c2f9SSascha Wildner "Can't allocate interrupt",
362df54c2f9SSascha Wildner ENXIO);
363df54c2f9SSascha Wildner tw_osli_free_resources(sc);
364df54c2f9SSascha Wildner return(ENXIO);
365df54c2f9SSascha Wildner }
3664fbf05f9SSascha Wildner if ((error = twa_setup_intr(sc))) {
367df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
368df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
369df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
370df54c2f9SSascha Wildner 0x2004,
371df54c2f9SSascha Wildner "Can't set up interrupt",
372df54c2f9SSascha Wildner error);
373df54c2f9SSascha Wildner tw_osli_free_resources(sc);
374df54c2f9SSascha Wildner return(error);
375df54c2f9SSascha Wildner }
376df54c2f9SSascha Wildner
377df54c2f9SSascha Wildner if ((error = tw_osli_alloc_mem(sc))) {
378df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
379df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
380df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
381df54c2f9SSascha Wildner 0x2005,
382df54c2f9SSascha Wildner "Memory allocation failure",
383df54c2f9SSascha Wildner error);
384df54c2f9SSascha Wildner tw_osli_free_resources(sc);
385df54c2f9SSascha Wildner return(error);
386df54c2f9SSascha Wildner }
387df54c2f9SSascha Wildner
388df54c2f9SSascha Wildner /* Initialize the Common Layer for this controller. */
389df54c2f9SSascha Wildner if ((error = tw_cl_init_ctlr(&sc->ctlr_handle, sc->flags, sc->device_id,
390df54c2f9SSascha Wildner TW_OSLI_MAX_NUM_REQUESTS, TW_OSLI_MAX_NUM_AENS,
391df54c2f9SSascha Wildner sc->non_dma_mem, sc->dma_mem,
392df54c2f9SSascha Wildner sc->dma_mem_phys
393df54c2f9SSascha Wildner ))) {
394df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
395df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
396df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
397df54c2f9SSascha Wildner 0x2006,
398df54c2f9SSascha Wildner "Failed to initialize Common Layer/controller",
399df54c2f9SSascha Wildner error);
400df54c2f9SSascha Wildner tw_osli_free_resources(sc);
401df54c2f9SSascha Wildner return(error);
402df54c2f9SSascha Wildner }
403df54c2f9SSascha Wildner
404df54c2f9SSascha Wildner /* Create the control device. */
405df54c2f9SSascha Wildner sc->ctrl_dev = make_dev(&twa_ops, device_get_unit(sc->bus_dev),
406df54c2f9SSascha Wildner UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR,
407df54c2f9SSascha Wildner "twa%d", device_get_unit(sc->bus_dev));
408df54c2f9SSascha Wildner sc->ctrl_dev->si_drv1 = sc;
409df54c2f9SSascha Wildner
410df54c2f9SSascha Wildner if ((error = tw_osli_cam_attach(sc))) {
411df54c2f9SSascha Wildner tw_osli_free_resources(sc);
412df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
413df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
414df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
415df54c2f9SSascha Wildner 0x2007,
416df54c2f9SSascha Wildner "Failed to initialize CAM",
417df54c2f9SSascha Wildner error);
418df54c2f9SSascha Wildner return(error);
419df54c2f9SSascha Wildner }
420df54c2f9SSascha Wildner
4214fbf05f9SSascha Wildner sc->watchdog_index = 0;
4221e0dd9ddSSascha Wildner callout_init_mp(&(sc->watchdog_callout[0]));
4231e0dd9ddSSascha Wildner callout_init_mp(&(sc->watchdog_callout[1]));
4244fbf05f9SSascha Wildner callout_reset(&(sc->watchdog_callout[0]), 5*hz, twa_watchdog, &sc->ctlr_handle);
4254fbf05f9SSascha Wildner
426df54c2f9SSascha Wildner return(0);
427df54c2f9SSascha Wildner }
428df54c2f9SSascha Wildner
429df54c2f9SSascha Wildner
4304fbf05f9SSascha Wildner static TW_VOID
twa_watchdog(TW_VOID * arg)4314fbf05f9SSascha Wildner twa_watchdog(TW_VOID *arg)
4324fbf05f9SSascha Wildner {
4334fbf05f9SSascha Wildner struct tw_cl_ctlr_handle *ctlr_handle =
4344fbf05f9SSascha Wildner (struct tw_cl_ctlr_handle *)arg;
4354fbf05f9SSascha Wildner struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt;
4364fbf05f9SSascha Wildner int i;
4374fbf05f9SSascha Wildner int i_need_a_reset = 0;
4384fbf05f9SSascha Wildner int driver_is_active = 0;
4394fbf05f9SSascha Wildner TW_UINT64 current_time;
4404fbf05f9SSascha Wildner struct tw_osli_req_context *my_req;
4414fbf05f9SSascha Wildner
4424fbf05f9SSascha Wildner
4434fbf05f9SSascha Wildner //==============================================================================
4444fbf05f9SSascha Wildner current_time = (TW_UINT64) (tw_osl_get_local_time());
4454fbf05f9SSascha Wildner
4464fbf05f9SSascha Wildner for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) {
4474fbf05f9SSascha Wildner my_req = &(sc->req_ctx_buf[i]);
4484fbf05f9SSascha Wildner
4494fbf05f9SSascha Wildner if ((my_req->state == TW_OSLI_REQ_STATE_BUSY) &&
4504fbf05f9SSascha Wildner (my_req->deadline) &&
4514fbf05f9SSascha Wildner (my_req->deadline < current_time)) {
4524fbf05f9SSascha Wildner tw_cl_set_reset_needed(ctlr_handle);
4534fbf05f9SSascha Wildner #ifdef TW_OSL_DEBUG
4544fbf05f9SSascha Wildner device_printf((sc)->bus_dev, "Request %d timed out! d = %llu, c = %llu\n", i, my_req->deadline, current_time);
4554fbf05f9SSascha Wildner #else /* TW_OSL_DEBUG */
4564fbf05f9SSascha Wildner device_printf((sc)->bus_dev, "Request %d timed out!\n", i);
4574fbf05f9SSascha Wildner #endif /* TW_OSL_DEBUG */
4584fbf05f9SSascha Wildner break;
4594fbf05f9SSascha Wildner }
4604fbf05f9SSascha Wildner }
4614fbf05f9SSascha Wildner //==============================================================================
4624fbf05f9SSascha Wildner
4634fbf05f9SSascha Wildner i_need_a_reset = tw_cl_is_reset_needed(ctlr_handle);
4644fbf05f9SSascha Wildner
4654fbf05f9SSascha Wildner i = (int) ((sc->watchdog_index++) & 1);
4664fbf05f9SSascha Wildner
4674fbf05f9SSascha Wildner driver_is_active = tw_cl_is_active(ctlr_handle);
4684fbf05f9SSascha Wildner
4694fbf05f9SSascha Wildner if (i_need_a_reset) {
4704fbf05f9SSascha Wildner #ifdef TW_OSL_DEBUG
4714fbf05f9SSascha Wildner device_printf((sc)->bus_dev, "Watchdog rescheduled in 70 seconds\n");
4724fbf05f9SSascha Wildner #endif /* TW_OSL_DEBUG */
4734fbf05f9SSascha Wildner callout_reset(&(sc->watchdog_callout[i]), 70*hz, twa_watchdog, &sc->ctlr_handle);
4744fbf05f9SSascha Wildner tw_cl_reset_ctlr(ctlr_handle);
4754fbf05f9SSascha Wildner #ifdef TW_OSL_DEBUG
4764fbf05f9SSascha Wildner device_printf((sc)->bus_dev, "Watchdog reset completed!\n");
4774fbf05f9SSascha Wildner #endif /* TW_OSL_DEBUG */
4784fbf05f9SSascha Wildner } else if (driver_is_active) {
4794fbf05f9SSascha Wildner callout_reset(&(sc->watchdog_callout[i]), 5*hz, twa_watchdog, &sc->ctlr_handle);
4804fbf05f9SSascha Wildner }
4814fbf05f9SSascha Wildner #ifdef TW_OSL_DEBUG
4824fbf05f9SSascha Wildner if (i_need_a_reset)
4834fbf05f9SSascha Wildner device_printf((sc)->bus_dev, "i_need_a_reset = %d, "
4844fbf05f9SSascha Wildner "driver_is_active = %d\n",
4854fbf05f9SSascha Wildner i_need_a_reset, driver_is_active);
4864fbf05f9SSascha Wildner #endif /* TW_OSL_DEBUG */
4874fbf05f9SSascha Wildner }
4884fbf05f9SSascha Wildner
489df54c2f9SSascha Wildner
490df54c2f9SSascha Wildner /*
491df54c2f9SSascha Wildner * Function name: tw_osli_alloc_mem
492df54c2f9SSascha Wildner * Description: Allocates memory needed both by CL and OSL.
493df54c2f9SSascha Wildner *
494df54c2f9SSascha Wildner * Input: sc -- OSL internal controller context
495df54c2f9SSascha Wildner * Output: None
496df54c2f9SSascha Wildner * Return value: 0 -- success
497df54c2f9SSascha Wildner * non-zero-- failure
498df54c2f9SSascha Wildner */
499df54c2f9SSascha Wildner static TW_INT32
tw_osli_alloc_mem(struct twa_softc * sc)500df54c2f9SSascha Wildner tw_osli_alloc_mem(struct twa_softc *sc)
501df54c2f9SSascha Wildner {
502df54c2f9SSascha Wildner struct tw_osli_req_context *req;
503df54c2f9SSascha Wildner TW_UINT32 max_sg_elements;
504df54c2f9SSascha Wildner TW_UINT32 non_dma_mem_size;
505df54c2f9SSascha Wildner TW_UINT32 dma_mem_size;
506df54c2f9SSascha Wildner TW_INT32 error;
507df54c2f9SSascha Wildner TW_INT32 i;
508df54c2f9SSascha Wildner
509df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
510df54c2f9SSascha Wildner
511df54c2f9SSascha Wildner sc->flags |= (sizeof(bus_addr_t) == 8) ? TW_CL_64BIT_ADDRESSES : 0;
512df54c2f9SSascha Wildner sc->flags |= (sizeof(bus_size_t) == 8) ? TW_CL_64BIT_SG_LENGTH : 0;
513df54c2f9SSascha Wildner
514df54c2f9SSascha Wildner max_sg_elements = (sizeof(bus_addr_t) == 8) ?
515df54c2f9SSascha Wildner TW_CL_MAX_64BIT_SG_ELEMENTS : TW_CL_MAX_32BIT_SG_ELEMENTS;
516df54c2f9SSascha Wildner
517df54c2f9SSascha Wildner if ((error = tw_cl_get_mem_requirements(&sc->ctlr_handle, sc->flags,
518df54c2f9SSascha Wildner sc->device_id, TW_OSLI_MAX_NUM_REQUESTS, TW_OSLI_MAX_NUM_AENS,
519df54c2f9SSascha Wildner &(sc->alignment), &(sc->sg_size_factor),
520df54c2f9SSascha Wildner &non_dma_mem_size, &dma_mem_size
521df54c2f9SSascha Wildner ))) {
522df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
523df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
524df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
525df54c2f9SSascha Wildner 0x2008,
526df54c2f9SSascha Wildner "Can't get Common Layer's memory requirements",
527df54c2f9SSascha Wildner error);
528df54c2f9SSascha Wildner return(error);
529df54c2f9SSascha Wildner }
530df54c2f9SSascha Wildner
5311af9e7c6SSascha Wildner sc->non_dma_mem = kmalloc(non_dma_mem_size, TW_OSLI_MALLOC_CLASS,
5321af9e7c6SSascha Wildner M_WAITOK);
533df54c2f9SSascha Wildner
534df54c2f9SSascha Wildner /* Create the parent dma tag. */
535df54c2f9SSascha Wildner if (bus_dma_tag_create(NULL, /* parent */
536df54c2f9SSascha Wildner sc->alignment, /* alignment */
537df54c2f9SSascha Wildner TW_OSLI_DMA_BOUNDARY, /* boundary */
538df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* lowaddr */
539df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* highaddr */
540df54c2f9SSascha Wildner TW_CL_MAX_IO_SIZE, /* maxsize */
541df54c2f9SSascha Wildner max_sg_elements, /* nsegments */
542df54c2f9SSascha Wildner TW_CL_MAX_IO_SIZE, /* maxsegsize */
543df54c2f9SSascha Wildner 0, /* flags */
544df54c2f9SSascha Wildner &sc->parent_tag /* tag */)) {
545df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
546df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
547df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
548df54c2f9SSascha Wildner 0x200A,
549df54c2f9SSascha Wildner "Can't allocate parent DMA tag",
550df54c2f9SSascha Wildner ENOMEM);
551df54c2f9SSascha Wildner return(ENOMEM);
552df54c2f9SSascha Wildner }
553df54c2f9SSascha Wildner
554df54c2f9SSascha Wildner /* Create a dma tag for Common Layer's DMA'able memory (dma_mem). */
555df54c2f9SSascha Wildner if (bus_dma_tag_create(sc->parent_tag, /* parent */
556df54c2f9SSascha Wildner sc->alignment, /* alignment */
557df54c2f9SSascha Wildner 0, /* boundary */
558df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* lowaddr */
559df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* highaddr */
560df54c2f9SSascha Wildner dma_mem_size, /* maxsize */
561df54c2f9SSascha Wildner 1, /* nsegments */
562df54c2f9SSascha Wildner BUS_SPACE_MAXSIZE, /* maxsegsize */
563df54c2f9SSascha Wildner 0, /* flags */
564df54c2f9SSascha Wildner &sc->cmd_tag /* tag */)) {
565df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
566df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
567df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
568df54c2f9SSascha Wildner 0x200B,
569df54c2f9SSascha Wildner "Can't allocate DMA tag for Common Layer's "
570df54c2f9SSascha Wildner "DMA'able memory",
571df54c2f9SSascha Wildner ENOMEM);
572df54c2f9SSascha Wildner return(ENOMEM);
573df54c2f9SSascha Wildner }
574df54c2f9SSascha Wildner
575df54c2f9SSascha Wildner if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem,
576df54c2f9SSascha Wildner BUS_DMA_NOWAIT, &sc->cmd_map)) {
577df54c2f9SSascha Wildner /* Try a second time. */
578df54c2f9SSascha Wildner if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem,
579df54c2f9SSascha Wildner BUS_DMA_NOWAIT, &sc->cmd_map)) {
580df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
581df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
582df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
583df54c2f9SSascha Wildner 0x200C,
584df54c2f9SSascha Wildner "Can't allocate DMA'able memory for the"
585df54c2f9SSascha Wildner "Common Layer",
586df54c2f9SSascha Wildner ENOMEM);
587df54c2f9SSascha Wildner return(ENOMEM);
588df54c2f9SSascha Wildner }
589df54c2f9SSascha Wildner }
590df54c2f9SSascha Wildner
591df54c2f9SSascha Wildner bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem,
592df54c2f9SSascha Wildner dma_mem_size, twa_map_load_callback,
593df54c2f9SSascha Wildner &sc->dma_mem_phys, 0);
594df54c2f9SSascha Wildner
595df54c2f9SSascha Wildner /*
596df54c2f9SSascha Wildner * Create a dma tag for data buffers; size will be the maximum
597df54c2f9SSascha Wildner * possible I/O size (128kB).
598df54c2f9SSascha Wildner */
599df54c2f9SSascha Wildner if (bus_dma_tag_create(sc->parent_tag, /* parent */
600df54c2f9SSascha Wildner sc->alignment, /* alignment */
601df54c2f9SSascha Wildner 0, /* boundary */
602df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* lowaddr */
603df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* highaddr */
604df54c2f9SSascha Wildner TW_CL_MAX_IO_SIZE, /* maxsize */
605df54c2f9SSascha Wildner max_sg_elements, /* nsegments */
606df54c2f9SSascha Wildner TW_CL_MAX_IO_SIZE, /* maxsegsize */
607df54c2f9SSascha Wildner BUS_DMA_ALLOCNOW, /* flags */
608df54c2f9SSascha Wildner &sc->dma_tag /* tag */)) {
609df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
610df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
611df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
612df54c2f9SSascha Wildner 0x200F,
613df54c2f9SSascha Wildner "Can't allocate DMA tag for data buffers",
614df54c2f9SSascha Wildner ENOMEM);
615df54c2f9SSascha Wildner return(ENOMEM);
616df54c2f9SSascha Wildner }
617df54c2f9SSascha Wildner
618df54c2f9SSascha Wildner /*
619df54c2f9SSascha Wildner * Create a dma tag for ioctl data buffers; size will be the maximum
620df54c2f9SSascha Wildner * possible I/O size (128kB).
621df54c2f9SSascha Wildner */
622df54c2f9SSascha Wildner if (bus_dma_tag_create(sc->parent_tag, /* parent */
623df54c2f9SSascha Wildner sc->alignment, /* alignment */
624df54c2f9SSascha Wildner 0, /* boundary */
625df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* lowaddr */
626df54c2f9SSascha Wildner BUS_SPACE_MAXADDR, /* highaddr */
627df54c2f9SSascha Wildner TW_CL_MAX_IO_SIZE, /* maxsize */
628df54c2f9SSascha Wildner max_sg_elements, /* nsegments */
629df54c2f9SSascha Wildner TW_CL_MAX_IO_SIZE, /* maxsegsize */
630df54c2f9SSascha Wildner BUS_DMA_ALLOCNOW, /* flags */
631df54c2f9SSascha Wildner &sc->ioctl_tag /* tag */)) {
632df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
633df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
634df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
635df54c2f9SSascha Wildner 0x2010,
636df54c2f9SSascha Wildner "Can't allocate DMA tag for ioctl data buffers",
637df54c2f9SSascha Wildner ENOMEM);
638df54c2f9SSascha Wildner return(ENOMEM);
639df54c2f9SSascha Wildner }
640df54c2f9SSascha Wildner
641df54c2f9SSascha Wildner /* Create just one map for all ioctl request data buffers. */
642df54c2f9SSascha Wildner if (bus_dmamap_create(sc->ioctl_tag, 0, &sc->ioctl_map)) {
643df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
644df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
645df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
646df54c2f9SSascha Wildner 0x2011,
647df54c2f9SSascha Wildner "Can't create ioctl map",
648df54c2f9SSascha Wildner ENOMEM);
649df54c2f9SSascha Wildner return(ENOMEM);
650df54c2f9SSascha Wildner }
651df54c2f9SSascha Wildner
652df54c2f9SSascha Wildner
653df54c2f9SSascha Wildner /* Initialize request queues. */
654df54c2f9SSascha Wildner tw_osli_req_q_init(sc, TW_OSLI_FREE_Q);
655df54c2f9SSascha Wildner tw_osli_req_q_init(sc, TW_OSLI_BUSY_Q);
656df54c2f9SSascha Wildner
6571af9e7c6SSascha Wildner sc->req_ctx_buf = kmalloc((sizeof(struct tw_osli_req_context) *
6581af9e7c6SSascha Wildner TW_OSLI_MAX_NUM_REQUESTS), TW_OSLI_MALLOC_CLASS,
6591af9e7c6SSascha Wildner M_WAITOK | M_ZERO);
660df54c2f9SSascha Wildner for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) {
661df54c2f9SSascha Wildner req = &(sc->req_ctx_buf[i]);
662df54c2f9SSascha Wildner req->ctlr = sc;
663df54c2f9SSascha Wildner if (bus_dmamap_create(sc->dma_tag, 0, &req->dma_map)) {
664df54c2f9SSascha Wildner tw_osli_printf(sc, "request # = %d, error = %d",
665df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
666df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
667df54c2f9SSascha Wildner 0x2013,
668df54c2f9SSascha Wildner "Can't create dma map",
669df54c2f9SSascha Wildner i, ENOMEM);
670df54c2f9SSascha Wildner return(ENOMEM);
671df54c2f9SSascha Wildner }
672df54c2f9SSascha Wildner
673df54c2f9SSascha Wildner /* Initialize the ioctl wakeup/ timeout mutex */
674df54c2f9SSascha Wildner req->ioctl_wake_timeout_lock = &(req->ioctl_wake_timeout_lock_handle);
675df54c2f9SSascha Wildner lockinit(req->ioctl_wake_timeout_lock, "tw_ioctl_wake_timeout_lock", 0, 0);
676df54c2f9SSascha Wildner
677df54c2f9SSascha Wildner /* Insert request into the free queue. */
678df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
679df54c2f9SSascha Wildner }
680df54c2f9SSascha Wildner
681df54c2f9SSascha Wildner return(0);
682df54c2f9SSascha Wildner }
683df54c2f9SSascha Wildner
684df54c2f9SSascha Wildner
685df54c2f9SSascha Wildner
686df54c2f9SSascha Wildner /*
687df54c2f9SSascha Wildner * Function name: tw_osli_free_resources
688df54c2f9SSascha Wildner * Description: Performs clean-up at the time of going down.
689df54c2f9SSascha Wildner *
690df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal ctlr context
691df54c2f9SSascha Wildner * Output: None
692df54c2f9SSascha Wildner * Return value: None
693df54c2f9SSascha Wildner */
694df54c2f9SSascha Wildner static TW_VOID
tw_osli_free_resources(struct twa_softc * sc)695df54c2f9SSascha Wildner tw_osli_free_resources(struct twa_softc *sc)
696df54c2f9SSascha Wildner {
697df54c2f9SSascha Wildner struct tw_osli_req_context *req;
698df54c2f9SSascha Wildner TW_INT32 error = 0;
699df54c2f9SSascha Wildner
700df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
701df54c2f9SSascha Wildner
702df54c2f9SSascha Wildner /* Detach from CAM */
703df54c2f9SSascha Wildner tw_osli_cam_detach(sc);
704df54c2f9SSascha Wildner
705df54c2f9SSascha Wildner if (sc->req_ctx_buf)
706df54c2f9SSascha Wildner while ((req = tw_osli_req_q_remove_head(sc, TW_OSLI_FREE_Q)) !=
707df54c2f9SSascha Wildner NULL) {
708df54c2f9SSascha Wildner lockuninit(req->ioctl_wake_timeout_lock);
709df54c2f9SSascha Wildner
710df54c2f9SSascha Wildner if ((error = bus_dmamap_destroy(sc->dma_tag,
711df54c2f9SSascha Wildner req->dma_map)))
712df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
713df54c2f9SSascha Wildner "dmamap_destroy(dma) returned %d",
714df54c2f9SSascha Wildner error);
715df54c2f9SSascha Wildner }
716df54c2f9SSascha Wildner
717df54c2f9SSascha Wildner if ((sc->ioctl_tag) && (sc->ioctl_map))
718df54c2f9SSascha Wildner if ((error = bus_dmamap_destroy(sc->ioctl_tag, sc->ioctl_map)))
719df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
720df54c2f9SSascha Wildner "dmamap_destroy(ioctl) returned %d", error);
721df54c2f9SSascha Wildner
722df54c2f9SSascha Wildner /* Free all memory allocated so far. */
723df54c2f9SSascha Wildner if (sc->req_ctx_buf)
724df54c2f9SSascha Wildner kfree(sc->req_ctx_buf, TW_OSLI_MALLOC_CLASS);
725df54c2f9SSascha Wildner
726df54c2f9SSascha Wildner if (sc->non_dma_mem)
727df54c2f9SSascha Wildner kfree(sc->non_dma_mem, TW_OSLI_MALLOC_CLASS);
728df54c2f9SSascha Wildner
729df54c2f9SSascha Wildner if (sc->dma_mem) {
730df54c2f9SSascha Wildner bus_dmamap_unload(sc->cmd_tag, sc->cmd_map);
731df54c2f9SSascha Wildner bus_dmamem_free(sc->cmd_tag, sc->dma_mem,
732df54c2f9SSascha Wildner sc->cmd_map);
733df54c2f9SSascha Wildner }
734df54c2f9SSascha Wildner if (sc->cmd_tag)
735df54c2f9SSascha Wildner if ((error = bus_dma_tag_destroy(sc->cmd_tag)))
736df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
737df54c2f9SSascha Wildner "dma_tag_destroy(cmd) returned %d", error);
738df54c2f9SSascha Wildner
739df54c2f9SSascha Wildner if (sc->dma_tag)
740df54c2f9SSascha Wildner if ((error = bus_dma_tag_destroy(sc->dma_tag)))
741df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
742df54c2f9SSascha Wildner "dma_tag_destroy(dma) returned %d", error);
743df54c2f9SSascha Wildner
744df54c2f9SSascha Wildner if (sc->ioctl_tag)
745df54c2f9SSascha Wildner if ((error = bus_dma_tag_destroy(sc->ioctl_tag)))
746df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
747df54c2f9SSascha Wildner "dma_tag_destroy(ioctl) returned %d", error);
748df54c2f9SSascha Wildner
749df54c2f9SSascha Wildner if (sc->parent_tag)
750df54c2f9SSascha Wildner if ((error = bus_dma_tag_destroy(sc->parent_tag)))
751df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
752df54c2f9SSascha Wildner "dma_tag_destroy(parent) returned %d", error);
753df54c2f9SSascha Wildner
754df54c2f9SSascha Wildner
755df54c2f9SSascha Wildner /* Disconnect the interrupt handler. */
7564fbf05f9SSascha Wildner if ((error = twa_teardown_intr(sc)))
757df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
758df54c2f9SSascha Wildner "teardown_intr returned %d", error);
759df54c2f9SSascha Wildner
760df54c2f9SSascha Wildner if (sc->irq_res != NULL)
761df54c2f9SSascha Wildner if ((error = bus_release_resource(sc->bus_dev,
762df54c2f9SSascha Wildner SYS_RES_IRQ, sc->irq_res_id, sc->irq_res)))
763df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
764df54c2f9SSascha Wildner "release_resource(irq) returned %d", error);
765df54c2f9SSascha Wildner
7662c77752eSSascha Wildner if (sc->irq_type == PCI_INTR_TYPE_MSI)
7672c77752eSSascha Wildner pci_release_msi(sc->bus_dev);
768df54c2f9SSascha Wildner
769df54c2f9SSascha Wildner /* Release the register window mapping. */
770df54c2f9SSascha Wildner if (sc->reg_res != NULL)
771df54c2f9SSascha Wildner if ((error = bus_release_resource(sc->bus_dev,
772df54c2f9SSascha Wildner SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)))
773df54c2f9SSascha Wildner tw_osli_dbg_dprintf(1, sc,
774df54c2f9SSascha Wildner "release_resource(io) returned %d", error);
775df54c2f9SSascha Wildner
776df54c2f9SSascha Wildner /* Destroy the control device. */
777a60655aaSSascha Wildner if (sc->ctrl_dev != NULL)
778df54c2f9SSascha Wildner destroy_dev(sc->ctrl_dev);
7795f31229cSSascha Wildner dev_ops_remove_minor(&twa_ops, device_get_unit(sc->bus_dev));
780df54c2f9SSascha Wildner }
781df54c2f9SSascha Wildner
782df54c2f9SSascha Wildner
783df54c2f9SSascha Wildner
784df54c2f9SSascha Wildner /*
785df54c2f9SSascha Wildner * Function name: twa_detach
786df54c2f9SSascha Wildner * Description: Called when the controller is being detached from
787df54c2f9SSascha Wildner * the pci bus.
788df54c2f9SSascha Wildner *
789df54c2f9SSascha Wildner * Input: dev -- bus device corresponding to the ctlr
790df54c2f9SSascha Wildner * Output: None
791df54c2f9SSascha Wildner * Return value: 0 -- success
792df54c2f9SSascha Wildner * non-zero-- failure
793df54c2f9SSascha Wildner */
794df54c2f9SSascha Wildner static TW_INT32
twa_detach(device_t dev)795df54c2f9SSascha Wildner twa_detach(device_t dev)
796df54c2f9SSascha Wildner {
797df54c2f9SSascha Wildner struct twa_softc *sc = device_get_softc(dev);
798df54c2f9SSascha Wildner TW_INT32 error;
799df54c2f9SSascha Wildner
800df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
801df54c2f9SSascha Wildner
802df54c2f9SSascha Wildner error = EBUSY;
803df54c2f9SSascha Wildner if (sc->open) {
804df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
805df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
806df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
807df54c2f9SSascha Wildner 0x2014,
808df54c2f9SSascha Wildner "Device open",
809df54c2f9SSascha Wildner error);
810df54c2f9SSascha Wildner goto out;
811df54c2f9SSascha Wildner }
812df54c2f9SSascha Wildner
813df54c2f9SSascha Wildner /* Shut the controller down. */
814df54c2f9SSascha Wildner if ((error = twa_shutdown(dev)))
815df54c2f9SSascha Wildner goto out;
816df54c2f9SSascha Wildner
817df54c2f9SSascha Wildner /* Free all resources associated with this controller. */
818df54c2f9SSascha Wildner tw_osli_free_resources(sc);
819df54c2f9SSascha Wildner error = 0;
820df54c2f9SSascha Wildner
821df54c2f9SSascha Wildner out:
822df54c2f9SSascha Wildner return(error);
823df54c2f9SSascha Wildner }
824df54c2f9SSascha Wildner
825df54c2f9SSascha Wildner
826df54c2f9SSascha Wildner
827df54c2f9SSascha Wildner /*
828df54c2f9SSascha Wildner * Function name: twa_shutdown
829df54c2f9SSascha Wildner * Description: Called at unload/shutdown time. Lets the controller
830df54c2f9SSascha Wildner * know that we are going down.
831df54c2f9SSascha Wildner *
832df54c2f9SSascha Wildner * Input: dev -- bus device corresponding to the ctlr
833df54c2f9SSascha Wildner * Output: None
834df54c2f9SSascha Wildner * Return value: 0 -- success
835df54c2f9SSascha Wildner * non-zero-- failure
836df54c2f9SSascha Wildner */
837df54c2f9SSascha Wildner static TW_INT32
twa_shutdown(device_t dev)838df54c2f9SSascha Wildner twa_shutdown(device_t dev)
839df54c2f9SSascha Wildner {
840df54c2f9SSascha Wildner struct twa_softc *sc = device_get_softc(dev);
841df54c2f9SSascha Wildner TW_INT32 error = 0;
842df54c2f9SSascha Wildner
843df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
844df54c2f9SSascha Wildner
8454fbf05f9SSascha Wildner /* Disconnect interrupts. */
8464fbf05f9SSascha Wildner error = twa_teardown_intr(sc);
8474fbf05f9SSascha Wildner
8484fbf05f9SSascha Wildner /* Stop watchdog task. */
849*eb67213aSMatthew Dillon callout_cancel(&(sc->watchdog_callout[0]));
850*eb67213aSMatthew Dillon callout_cancel(&(sc->watchdog_callout[1]));
8514fbf05f9SSascha Wildner
852df54c2f9SSascha Wildner /* Disconnect from the controller. */
853df54c2f9SSascha Wildner if ((error = tw_cl_shutdown_ctlr(&(sc->ctlr_handle), 0))) {
854df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
855df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
856df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
857df54c2f9SSascha Wildner 0x2015,
858df54c2f9SSascha Wildner "Failed to shutdown Common Layer/controller",
859df54c2f9SSascha Wildner error);
860df54c2f9SSascha Wildner }
861df54c2f9SSascha Wildner return(error);
862df54c2f9SSascha Wildner }
863df54c2f9SSascha Wildner
864df54c2f9SSascha Wildner
865df54c2f9SSascha Wildner
866df54c2f9SSascha Wildner /*
867df54c2f9SSascha Wildner * Function name: twa_pci_intr
868df54c2f9SSascha Wildner * Description: Interrupt handler. Wrapper for twa_interrupt.
869df54c2f9SSascha Wildner *
870df54c2f9SSascha Wildner * Input: arg -- ptr to OSL internal ctlr context
871df54c2f9SSascha Wildner * Output: None
872df54c2f9SSascha Wildner * Return value: None
873df54c2f9SSascha Wildner */
874df54c2f9SSascha Wildner static TW_VOID
twa_pci_intr(TW_VOID * arg)875df54c2f9SSascha Wildner twa_pci_intr(TW_VOID *arg)
876df54c2f9SSascha Wildner {
877df54c2f9SSascha Wildner struct twa_softc *sc = (struct twa_softc *)arg;
878df54c2f9SSascha Wildner
879df54c2f9SSascha Wildner tw_osli_dbg_dprintf(10, sc, "entered");
880df54c2f9SSascha Wildner tw_cl_interrupt(&(sc->ctlr_handle));
881df54c2f9SSascha Wildner }
882df54c2f9SSascha Wildner
883df54c2f9SSascha Wildner
884df54c2f9SSascha Wildner /*
885df54c2f9SSascha Wildner * Function name: tw_osli_fw_passthru
886df54c2f9SSascha Wildner * Description: Builds a fw passthru cmd pkt, and submits it to CL.
887df54c2f9SSascha Wildner *
888df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal ctlr context
889df54c2f9SSascha Wildner * buf -- ptr to ioctl pkt understood by CL
890df54c2f9SSascha Wildner * Output: None
891df54c2f9SSascha Wildner * Return value: 0 -- success
892df54c2f9SSascha Wildner * non-zero-- failure
893df54c2f9SSascha Wildner */
894df54c2f9SSascha Wildner TW_INT32
tw_osli_fw_passthru(struct twa_softc * sc,TW_INT8 * buf)895df54c2f9SSascha Wildner tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf)
896df54c2f9SSascha Wildner {
897df54c2f9SSascha Wildner struct tw_osli_req_context *req;
898df54c2f9SSascha Wildner struct tw_osli_ioctl_no_data_buf *user_buf =
899df54c2f9SSascha Wildner (struct tw_osli_ioctl_no_data_buf *)buf;
900df54c2f9SSascha Wildner TW_TIME end_time;
901df54c2f9SSascha Wildner TW_UINT32 timeout = 60;
902df54c2f9SSascha Wildner TW_UINT32 data_buf_size_adjusted;
903df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt;
904df54c2f9SSascha Wildner struct tw_cl_passthru_req_packet *pt_req;
905df54c2f9SSascha Wildner TW_INT32 error;
906df54c2f9SSascha Wildner
907df54c2f9SSascha Wildner tw_osli_dbg_dprintf(5, sc, "ioctl: passthru");
908df54c2f9SSascha Wildner
909df54c2f9SSascha Wildner if ((req = tw_osli_get_request(sc)) == NULL)
910df54c2f9SSascha Wildner return(EBUSY);
911df54c2f9SSascha Wildner
912df54c2f9SSascha Wildner req->req_handle.osl_req_ctxt = req;
913df54c2f9SSascha Wildner req->orig_req = buf;
914df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_PASSTHRU;
915df54c2f9SSascha Wildner
916df54c2f9SSascha Wildner req_pkt = &(req->req_pkt);
917df54c2f9SSascha Wildner req_pkt->status = 0;
918df54c2f9SSascha Wildner req_pkt->tw_osl_callback = tw_osl_complete_passthru;
919df54c2f9SSascha Wildner /* Let the Common Layer retry the request on cmd queue full. */
920df54c2f9SSascha Wildner req_pkt->flags |= TW_CL_REQ_RETRY_ON_BUSY;
921df54c2f9SSascha Wildner
922df54c2f9SSascha Wildner pt_req = &(req_pkt->gen_req_pkt.pt_req);
923df54c2f9SSascha Wildner /*
924df54c2f9SSascha Wildner * Make sure that the data buffer sent to firmware is a
925df54c2f9SSascha Wildner * 512 byte multiple in size.
926df54c2f9SSascha Wildner */
927965b839fSSascha Wildner data_buf_size_adjusted = roundup2(user_buf->driver_pkt.buffer_length,
928965b839fSSascha Wildner sc->sg_size_factor);
929df54c2f9SSascha Wildner if ((req->length = data_buf_size_adjusted)) {
9301af9e7c6SSascha Wildner req->data = kmalloc(data_buf_size_adjusted,
9311af9e7c6SSascha Wildner TW_OSLI_MALLOC_CLASS, M_WAITOK);
932df54c2f9SSascha Wildner /* Copy the payload. */
933df54c2f9SSascha Wildner if ((error = copyin((TW_VOID *)(user_buf->pdata),
934df54c2f9SSascha Wildner req->data,
935df54c2f9SSascha Wildner user_buf->driver_pkt.buffer_length)) != 0) {
936df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
937df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
938df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
939df54c2f9SSascha Wildner 0x2017,
940df54c2f9SSascha Wildner "Could not copyin fw_passthru data_buf",
941df54c2f9SSascha Wildner error);
942df54c2f9SSascha Wildner goto fw_passthru_err;
943df54c2f9SSascha Wildner }
944df54c2f9SSascha Wildner pt_req->sgl_entries = 1; /* will be updated during mapping */
945df54c2f9SSascha Wildner req->flags |= (TW_OSLI_REQ_FLAGS_DATA_IN |
946df54c2f9SSascha Wildner TW_OSLI_REQ_FLAGS_DATA_OUT);
947df54c2f9SSascha Wildner } else
948df54c2f9SSascha Wildner pt_req->sgl_entries = 0; /* no payload */
949df54c2f9SSascha Wildner
950df54c2f9SSascha Wildner pt_req->cmd_pkt = (TW_VOID *)(&(user_buf->cmd_pkt));
951df54c2f9SSascha Wildner pt_req->cmd_pkt_length = sizeof(struct tw_cl_command_packet);
952df54c2f9SSascha Wildner
953df54c2f9SSascha Wildner if ((error = tw_osli_map_request(req)))
954df54c2f9SSascha Wildner goto fw_passthru_err;
955df54c2f9SSascha Wildner
956df54c2f9SSascha Wildner end_time = tw_osl_get_local_time() + timeout;
957df54c2f9SSascha Wildner while (req->state != TW_OSLI_REQ_STATE_COMPLETE) {
958df54c2f9SSascha Wildner lockmgr(req->ioctl_wake_timeout_lock, LK_EXCLUSIVE);
959df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_SLEEPING;
960df54c2f9SSascha Wildner
961df54c2f9SSascha Wildner error = lksleep(req, req->ioctl_wake_timeout_lock, 0,
962df54c2f9SSascha Wildner "twa_passthru", timeout*hz);
963df54c2f9SSascha Wildner lockmgr(req->ioctl_wake_timeout_lock, LK_RELEASE);
964df54c2f9SSascha Wildner
965df54c2f9SSascha Wildner if (!(req->flags & TW_OSLI_REQ_FLAGS_SLEEPING))
966df54c2f9SSascha Wildner error = 0;
967df54c2f9SSascha Wildner req->flags &= ~TW_OSLI_REQ_FLAGS_SLEEPING;
968df54c2f9SSascha Wildner
969df54c2f9SSascha Wildner if (! error) {
970df54c2f9SSascha Wildner if (((error = req->error_code)) ||
971df54c2f9SSascha Wildner ((error = (req->state !=
972df54c2f9SSascha Wildner TW_OSLI_REQ_STATE_COMPLETE))) ||
973df54c2f9SSascha Wildner ((error = req_pkt->status)))
974df54c2f9SSascha Wildner goto fw_passthru_err;
975df54c2f9SSascha Wildner break;
976df54c2f9SSascha Wildner }
977df54c2f9SSascha Wildner
978df54c2f9SSascha Wildner if (req_pkt->status) {
979df54c2f9SSascha Wildner error = req_pkt->status;
980df54c2f9SSascha Wildner goto fw_passthru_err;
981df54c2f9SSascha Wildner }
982df54c2f9SSascha Wildner
983df54c2f9SSascha Wildner if (error == EWOULDBLOCK) {
984df54c2f9SSascha Wildner /* Time out! */
985df54c2f9SSascha Wildner if ((!(req->error_code)) &&
986df54c2f9SSascha Wildner (req->state == TW_OSLI_REQ_STATE_COMPLETE) &&
987df54c2f9SSascha Wildner (!(req_pkt->status)) ) {
988df54c2f9SSascha Wildner #ifdef TW_OSL_DEBUG
989df54c2f9SSascha Wildner tw_osli_printf(sc, "request = %p",
990df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
991df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
992df54c2f9SSascha Wildner 0x7777,
993df54c2f9SSascha Wildner "FALSE Passthru timeout!",
994df54c2f9SSascha Wildner req);
995df54c2f9SSascha Wildner #endif /* TW_OSL_DEBUG */
996df54c2f9SSascha Wildner error = 0; /* False error */
997df54c2f9SSascha Wildner break;
998df54c2f9SSascha Wildner }
9994fbf05f9SSascha Wildner if (!(tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
10004fbf05f9SSascha Wildner #ifdef TW_OSL_DEBUG
1001df54c2f9SSascha Wildner tw_osli_printf(sc, "request = %p",
1002df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1003df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1004df54c2f9SSascha Wildner 0x2018,
1005df54c2f9SSascha Wildner "Passthru request timed out!",
1006df54c2f9SSascha Wildner req);
10074fbf05f9SSascha Wildner #else /* TW_OSL_DEBUG */
10084fbf05f9SSascha Wildner device_printf((sc)->bus_dev, "Passthru request timed out!\n");
10094fbf05f9SSascha Wildner #endif /* TW_OSL_DEBUG */
10104fbf05f9SSascha Wildner tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
10114fbf05f9SSascha Wildner }
10124fbf05f9SSascha Wildner
10134fbf05f9SSascha Wildner error = 0;
10144fbf05f9SSascha Wildner end_time = tw_osl_get_local_time() + timeout;
10154fbf05f9SSascha Wildner continue;
1016df54c2f9SSascha Wildner /*
1017df54c2f9SSascha Wildner * Don't touch req after a reset. It (and any
10184fbf05f9SSascha Wildner * associated data) will be
1019df54c2f9SSascha Wildner * unmapped by the callback.
1020df54c2f9SSascha Wildner */
1021df54c2f9SSascha Wildner }
1022df54c2f9SSascha Wildner /*
1023df54c2f9SSascha Wildner * Either the request got completed, or we were woken up by a
1024df54c2f9SSascha Wildner * signal. Calculate the new timeout, in case it was the latter.
1025df54c2f9SSascha Wildner */
1026df54c2f9SSascha Wildner timeout = (end_time - tw_osl_get_local_time());
10274fbf05f9SSascha Wildner } /* End of while loop */
1028df54c2f9SSascha Wildner
1029df54c2f9SSascha Wildner /* If there was a payload, copy it back. */
1030df54c2f9SSascha Wildner if ((!error) && (req->length))
1031df54c2f9SSascha Wildner if ((error = copyout(req->data, user_buf->pdata,
1032df54c2f9SSascha Wildner user_buf->driver_pkt.buffer_length)))
1033df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
1034df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1035df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1036df54c2f9SSascha Wildner 0x2019,
1037df54c2f9SSascha Wildner "Could not copyout fw_passthru data_buf",
1038df54c2f9SSascha Wildner error);
1039df54c2f9SSascha Wildner
1040df54c2f9SSascha Wildner fw_passthru_err:
10414fbf05f9SSascha Wildner
10424fbf05f9SSascha Wildner if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
10434fbf05f9SSascha Wildner error = EBUSY;
1044df54c2f9SSascha Wildner
1045df54c2f9SSascha Wildner user_buf->driver_pkt.os_status = error;
1046df54c2f9SSascha Wildner /* Free resources. */
1047df54c2f9SSascha Wildner if (req->data)
1048df54c2f9SSascha Wildner kfree(req->data, TW_OSLI_MALLOC_CLASS);
1049df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
1050df54c2f9SSascha Wildner return(error);
1051df54c2f9SSascha Wildner }
1052df54c2f9SSascha Wildner
1053df54c2f9SSascha Wildner
1054df54c2f9SSascha Wildner
1055df54c2f9SSascha Wildner /*
1056df54c2f9SSascha Wildner * Function name: tw_osl_complete_passthru
1057df54c2f9SSascha Wildner * Description: Called to complete passthru requests.
1058df54c2f9SSascha Wildner *
1059df54c2f9SSascha Wildner * Input: req_handle -- ptr to request handle
1060df54c2f9SSascha Wildner * Output: None
1061df54c2f9SSascha Wildner * Return value: None
1062df54c2f9SSascha Wildner */
1063df54c2f9SSascha Wildner TW_VOID
tw_osl_complete_passthru(struct tw_cl_req_handle * req_handle)1064df54c2f9SSascha Wildner tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle)
1065df54c2f9SSascha Wildner {
1066df54c2f9SSascha Wildner struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
10674fbf05f9SSascha Wildner struct tw_cl_req_packet *req_pkt =
10684fbf05f9SSascha Wildner (struct tw_cl_req_packet *)(&req->req_pkt);
1069df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
1070df54c2f9SSascha Wildner
1071df54c2f9SSascha Wildner tw_osli_dbg_dprintf(5, sc, "entered");
1072df54c2f9SSascha Wildner
1073df54c2f9SSascha Wildner if (req->state != TW_OSLI_REQ_STATE_BUSY) {
1074df54c2f9SSascha Wildner tw_osli_printf(sc, "request = %p, status = %d",
1075df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1076df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1077df54c2f9SSascha Wildner 0x201B,
1078df54c2f9SSascha Wildner "Unposted command completed!!",
1079df54c2f9SSascha Wildner req, req->state);
1080df54c2f9SSascha Wildner }
1081df54c2f9SSascha Wildner
1082df54c2f9SSascha Wildner /*
1083df54c2f9SSascha Wildner * Remove request from the busy queue. Just mark it complete.
1084df54c2f9SSascha Wildner * There's no need to move it into the complete queue as we are
1085df54c2f9SSascha Wildner * going to be done with it right now.
1086df54c2f9SSascha Wildner */
1087df54c2f9SSascha Wildner req->state = TW_OSLI_REQ_STATE_COMPLETE;
1088df54c2f9SSascha Wildner tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
1089df54c2f9SSascha Wildner
1090df54c2f9SSascha Wildner tw_osli_unmap_request(req);
1091df54c2f9SSascha Wildner
1092df54c2f9SSascha Wildner /*
1093df54c2f9SSascha Wildner * Don't do a wake up if there was an error even before the request
1094df54c2f9SSascha Wildner * was sent down to the Common Layer, and we hadn't gotten an
1095df54c2f9SSascha Wildner * EINPROGRESS. The request originator will then be returned an
1096df54c2f9SSascha Wildner * error, and he can do the clean-up.
1097df54c2f9SSascha Wildner */
1098df54c2f9SSascha Wildner if ((req->error_code) && (!(req->flags & TW_OSLI_REQ_FLAGS_IN_PROGRESS)))
1099df54c2f9SSascha Wildner return;
1100df54c2f9SSascha Wildner
1101df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1102df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_SLEEPING) {
1103df54c2f9SSascha Wildner /* Wake up the sleeping command originator. */
1104df54c2f9SSascha Wildner tw_osli_dbg_dprintf(5, sc,
1105df54c2f9SSascha Wildner "Waking up originator of request %p", req);
1106df54c2f9SSascha Wildner req->flags &= ~TW_OSLI_REQ_FLAGS_SLEEPING;
1107df54c2f9SSascha Wildner wakeup_one(req);
1108df54c2f9SSascha Wildner } else {
1109df54c2f9SSascha Wildner /*
1110df54c2f9SSascha Wildner * If the request completed even before mtx_sleep
1111df54c2f9SSascha Wildner * was called, simply return.
1112df54c2f9SSascha Wildner */
1113df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_MAPPED)
1114df54c2f9SSascha Wildner return;
1115df54c2f9SSascha Wildner
11164fbf05f9SSascha Wildner if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
11174fbf05f9SSascha Wildner return;
11184fbf05f9SSascha Wildner
1119df54c2f9SSascha Wildner tw_osli_printf(sc, "request = %p",
1120df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1121df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1122df54c2f9SSascha Wildner 0x201C,
1123df54c2f9SSascha Wildner "Passthru callback called, "
1124df54c2f9SSascha Wildner "and caller not sleeping",
1125df54c2f9SSascha Wildner req);
1126df54c2f9SSascha Wildner }
1127df54c2f9SSascha Wildner } else {
1128df54c2f9SSascha Wildner tw_osli_printf(sc, "request = %p",
1129df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1130df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1131df54c2f9SSascha Wildner 0x201D,
1132df54c2f9SSascha Wildner "Passthru callback called for non-passthru request",
1133df54c2f9SSascha Wildner req);
1134df54c2f9SSascha Wildner }
1135df54c2f9SSascha Wildner }
1136df54c2f9SSascha Wildner
1137df54c2f9SSascha Wildner
1138df54c2f9SSascha Wildner
1139df54c2f9SSascha Wildner /*
1140df54c2f9SSascha Wildner * Function name: tw_osli_get_request
1141df54c2f9SSascha Wildner * Description: Gets a request pkt from the free queue.
1142df54c2f9SSascha Wildner *
1143df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal ctlr context
1144df54c2f9SSascha Wildner * Output: None
1145df54c2f9SSascha Wildner * Return value: ptr to request pkt -- success
1146df54c2f9SSascha Wildner * NULL -- failure
1147df54c2f9SSascha Wildner */
1148df54c2f9SSascha Wildner struct tw_osli_req_context *
tw_osli_get_request(struct twa_softc * sc)1149df54c2f9SSascha Wildner tw_osli_get_request(struct twa_softc *sc)
1150df54c2f9SSascha Wildner {
1151df54c2f9SSascha Wildner struct tw_osli_req_context *req;
1152df54c2f9SSascha Wildner
1153df54c2f9SSascha Wildner tw_osli_dbg_dprintf(4, sc, "entered");
1154df54c2f9SSascha Wildner
1155df54c2f9SSascha Wildner /* Get a free request packet. */
1156df54c2f9SSascha Wildner req = tw_osli_req_q_remove_head(sc, TW_OSLI_FREE_Q);
1157df54c2f9SSascha Wildner
1158df54c2f9SSascha Wildner /* Initialize some fields to their defaults. */
1159df54c2f9SSascha Wildner if (req) {
1160df54c2f9SSascha Wildner req->req_handle.osl_req_ctxt = NULL;
1161df54c2f9SSascha Wildner req->req_handle.cl_req_ctxt = NULL;
1162df54c2f9SSascha Wildner req->req_handle.is_io = 0;
1163df54c2f9SSascha Wildner req->data = NULL;
1164df54c2f9SSascha Wildner req->length = 0;
11654fbf05f9SSascha Wildner req->deadline = 0;
1166df54c2f9SSascha Wildner req->real_data = NULL;
1167df54c2f9SSascha Wildner req->real_length = 0;
1168df54c2f9SSascha Wildner req->state = TW_OSLI_REQ_STATE_INIT;/* req being initialized */
1169df54c2f9SSascha Wildner req->flags = 0;
1170df54c2f9SSascha Wildner req->error_code = 0;
1171df54c2f9SSascha Wildner req->orig_req = NULL;
1172df54c2f9SSascha Wildner
1173df54c2f9SSascha Wildner bzero(&(req->req_pkt), sizeof(struct tw_cl_req_packet));
1174df54c2f9SSascha Wildner
1175df54c2f9SSascha Wildner }
1176df54c2f9SSascha Wildner return(req);
1177df54c2f9SSascha Wildner }
1178df54c2f9SSascha Wildner
1179df54c2f9SSascha Wildner
1180df54c2f9SSascha Wildner
1181df54c2f9SSascha Wildner /*
1182df54c2f9SSascha Wildner * Function name: twa_map_load_data_callback
1183df54c2f9SSascha Wildner * Description: Callback of bus_dmamap_load for the buffer associated
1184df54c2f9SSascha Wildner * with data. Updates the cmd pkt (size/sgl_entries
1185df54c2f9SSascha Wildner * fields, as applicable) to reflect the number of sg
1186df54c2f9SSascha Wildner * elements.
1187df54c2f9SSascha Wildner *
1188df54c2f9SSascha Wildner * Input: arg -- ptr to OSL internal request context
1189df54c2f9SSascha Wildner * segs -- ptr to a list of segment descriptors
1190df54c2f9SSascha Wildner * nsegments--# of segments
1191df54c2f9SSascha Wildner * error -- 0 if no errors encountered before callback,
1192df54c2f9SSascha Wildner * non-zero if errors were encountered
1193df54c2f9SSascha Wildner * Output: None
1194df54c2f9SSascha Wildner * Return value: None
1195df54c2f9SSascha Wildner */
1196df54c2f9SSascha Wildner static TW_VOID
twa_map_load_data_callback(TW_VOID * arg,bus_dma_segment_t * segs,TW_INT32 nsegments,TW_INT32 error)1197df54c2f9SSascha Wildner twa_map_load_data_callback(TW_VOID *arg, bus_dma_segment_t *segs,
1198df54c2f9SSascha Wildner TW_INT32 nsegments, TW_INT32 error)
1199df54c2f9SSascha Wildner {
1200df54c2f9SSascha Wildner struct tw_osli_req_context *req =
1201df54c2f9SSascha Wildner (struct tw_osli_req_context *)arg;
1202df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
1203df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt = &(req->req_pkt);
1204df54c2f9SSascha Wildner
1205df54c2f9SSascha Wildner tw_osli_dbg_dprintf(10, sc, "entered");
1206df54c2f9SSascha Wildner
12074fbf05f9SSascha Wildner if (error == EINVAL) {
12084fbf05f9SSascha Wildner req->error_code = error;
12094fbf05f9SSascha Wildner return;
12104fbf05f9SSascha Wildner }
12114fbf05f9SSascha Wildner
1212df54c2f9SSascha Wildner /* Mark the request as currently being processed. */
1213df54c2f9SSascha Wildner req->state = TW_OSLI_REQ_STATE_BUSY;
1214df54c2f9SSascha Wildner /* Move the request into the busy queue. */
1215df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_BUSY_Q);
1216df54c2f9SSascha Wildner
1217df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_MAPPED;
1218df54c2f9SSascha Wildner
1219df54c2f9SSascha Wildner if (error == EFBIG) {
1220df54c2f9SSascha Wildner req->error_code = error;
1221df54c2f9SSascha Wildner goto out;
1222df54c2f9SSascha Wildner }
1223df54c2f9SSascha Wildner
1224df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1225df54c2f9SSascha Wildner struct tw_cl_passthru_req_packet *pt_req;
1226df54c2f9SSascha Wildner
1227df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN)
1228df54c2f9SSascha Wildner bus_dmamap_sync(sc->ioctl_tag, sc->ioctl_map,
1229df54c2f9SSascha Wildner BUS_DMASYNC_PREREAD);
1230df54c2f9SSascha Wildner
1231df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT) {
1232df54c2f9SSascha Wildner /*
1233df54c2f9SSascha Wildner * If we're using an alignment buffer, and we're
1234df54c2f9SSascha Wildner * writing data, copy the real data out.
1235df54c2f9SSascha Wildner */
1236df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1237df54c2f9SSascha Wildner bcopy(req->real_data, req->data, req->real_length);
1238df54c2f9SSascha Wildner bus_dmamap_sync(sc->ioctl_tag, sc->ioctl_map,
1239df54c2f9SSascha Wildner BUS_DMASYNC_PREWRITE);
1240df54c2f9SSascha Wildner }
1241df54c2f9SSascha Wildner
1242df54c2f9SSascha Wildner pt_req = &(req_pkt->gen_req_pkt.pt_req);
1243df54c2f9SSascha Wildner pt_req->sg_list = (TW_UINT8 *)segs;
1244df54c2f9SSascha Wildner pt_req->sgl_entries += (nsegments - 1);
1245df54c2f9SSascha Wildner error = tw_cl_fw_passthru(&(sc->ctlr_handle), req_pkt,
1246df54c2f9SSascha Wildner &(req->req_handle));
1247df54c2f9SSascha Wildner } else {
1248df54c2f9SSascha Wildner struct tw_cl_scsi_req_packet *scsi_req;
1249df54c2f9SSascha Wildner
1250df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN)
1251df54c2f9SSascha Wildner bus_dmamap_sync(sc->dma_tag, req->dma_map,
1252df54c2f9SSascha Wildner BUS_DMASYNC_PREREAD);
1253df54c2f9SSascha Wildner
1254df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT) {
1255df54c2f9SSascha Wildner /*
1256df54c2f9SSascha Wildner * If we're using an alignment buffer, and we're
1257df54c2f9SSascha Wildner * writing data, copy the real data out.
1258df54c2f9SSascha Wildner */
1259df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1260df54c2f9SSascha Wildner bcopy(req->real_data, req->data, req->real_length);
1261df54c2f9SSascha Wildner bus_dmamap_sync(sc->dma_tag, req->dma_map,
1262df54c2f9SSascha Wildner BUS_DMASYNC_PREWRITE);
1263df54c2f9SSascha Wildner }
1264df54c2f9SSascha Wildner
1265df54c2f9SSascha Wildner scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
1266df54c2f9SSascha Wildner scsi_req->sg_list = (TW_UINT8 *)segs;
1267df54c2f9SSascha Wildner scsi_req->sgl_entries += (nsegments - 1);
1268df54c2f9SSascha Wildner error = tw_cl_start_io(&(sc->ctlr_handle), req_pkt,
1269df54c2f9SSascha Wildner &(req->req_handle));
1270df54c2f9SSascha Wildner }
1271df54c2f9SSascha Wildner
1272df54c2f9SSascha Wildner out:
1273df54c2f9SSascha Wildner if (error) {
1274df54c2f9SSascha Wildner req->error_code = error;
1275df54c2f9SSascha Wildner req_pkt->tw_osl_callback(&(req->req_handle));
1276df54c2f9SSascha Wildner /*
1277df54c2f9SSascha Wildner * If the caller had been returned EINPROGRESS, and he has
1278df54c2f9SSascha Wildner * registered a callback for handling completion, the callback
1279df54c2f9SSascha Wildner * will never get called because we were unable to submit the
1280df54c2f9SSascha Wildner * request. So, free up the request right here.
1281df54c2f9SSascha Wildner */
1282df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_IN_PROGRESS)
1283df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
1284df54c2f9SSascha Wildner }
1285df54c2f9SSascha Wildner }
1286df54c2f9SSascha Wildner
1287df54c2f9SSascha Wildner
1288df54c2f9SSascha Wildner
1289df54c2f9SSascha Wildner /*
1290df54c2f9SSascha Wildner * Function name: twa_map_load_callback
1291df54c2f9SSascha Wildner * Description: Callback of bus_dmamap_load for the buffer associated
1292df54c2f9SSascha Wildner * with a cmd pkt.
1293df54c2f9SSascha Wildner *
1294df54c2f9SSascha Wildner * Input: arg -- ptr to variable to hold phys addr
1295df54c2f9SSascha Wildner * segs -- ptr to a list of segment descriptors
1296df54c2f9SSascha Wildner * nsegments--# of segments
1297df54c2f9SSascha Wildner * error -- 0 if no errors encountered before callback,
1298df54c2f9SSascha Wildner * non-zero if errors were encountered
1299df54c2f9SSascha Wildner * Output: None
1300df54c2f9SSascha Wildner * Return value: None
1301df54c2f9SSascha Wildner */
1302df54c2f9SSascha Wildner static TW_VOID
twa_map_load_callback(TW_VOID * arg,bus_dma_segment_t * segs,TW_INT32 nsegments,TW_INT32 error)1303df54c2f9SSascha Wildner twa_map_load_callback(TW_VOID *arg, bus_dma_segment_t *segs,
1304df54c2f9SSascha Wildner TW_INT32 nsegments, TW_INT32 error)
1305df54c2f9SSascha Wildner {
1306df54c2f9SSascha Wildner *((bus_addr_t *)arg) = segs[0].ds_addr;
1307df54c2f9SSascha Wildner }
1308df54c2f9SSascha Wildner
1309df54c2f9SSascha Wildner
1310df54c2f9SSascha Wildner
1311df54c2f9SSascha Wildner /*
1312df54c2f9SSascha Wildner * Function name: tw_osli_map_request
1313df54c2f9SSascha Wildner * Description: Maps a cmd pkt and data associated with it, into
1314df54c2f9SSascha Wildner * DMA'able memory.
1315df54c2f9SSascha Wildner *
1316df54c2f9SSascha Wildner * Input: req -- ptr to request pkt
1317df54c2f9SSascha Wildner * Output: None
1318df54c2f9SSascha Wildner * Return value: 0 -- success
1319df54c2f9SSascha Wildner * non-zero-- failure
1320df54c2f9SSascha Wildner */
1321df54c2f9SSascha Wildner TW_INT32
tw_osli_map_request(struct tw_osli_req_context * req)1322df54c2f9SSascha Wildner tw_osli_map_request(struct tw_osli_req_context *req)
1323df54c2f9SSascha Wildner {
1324df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
1325df54c2f9SSascha Wildner TW_INT32 error = 0;
1326df54c2f9SSascha Wildner
1327df54c2f9SSascha Wildner tw_osli_dbg_dprintf(10, sc, "entered");
1328df54c2f9SSascha Wildner
1329df54c2f9SSascha Wildner /* If the command involves data, map that too. */
1330df54c2f9SSascha Wildner if (req->data != NULL) {
1331df54c2f9SSascha Wildner /*
1332df54c2f9SSascha Wildner * It's sufficient for the data pointer to be 4-byte aligned
1333df54c2f9SSascha Wildner * to work with 9000. However, if 4-byte aligned addresses
1334df54c2f9SSascha Wildner * are passed to bus_dmamap_load, we can get back sg elements
1335df54c2f9SSascha Wildner * that are not 512-byte multiples in size. So, we will let
1336df54c2f9SSascha Wildner * only those buffers that are 512-byte aligned to pass
1337df54c2f9SSascha Wildner * through, and bounce the rest, so as to make sure that we
1338df54c2f9SSascha Wildner * always get back sg elements that are 512-byte multiples
1339df54c2f9SSascha Wildner * in size.
1340df54c2f9SSascha Wildner */
1341df54c2f9SSascha Wildner if (((vm_offset_t)req->data % sc->sg_size_factor) ||
1342df54c2f9SSascha Wildner (req->length % sc->sg_size_factor)) {
1343df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED;
1344df54c2f9SSascha Wildner /* Save original data pointer and length. */
1345df54c2f9SSascha Wildner req->real_data = req->data;
1346df54c2f9SSascha Wildner req->real_length = req->length;
1347965b839fSSascha Wildner req->length = roundup2(req->length, sc->sg_size_factor);
1348df54c2f9SSascha Wildner req->data = kmalloc(req->length, TW_OSLI_MALLOC_CLASS,
1349df54c2f9SSascha Wildner M_NOWAIT);
1350df54c2f9SSascha Wildner if (req->data == NULL) {
1351df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
1352df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1353df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1354df54c2f9SSascha Wildner 0x201E,
1355df54c2f9SSascha Wildner "Failed to allocate memory "
1356df54c2f9SSascha Wildner "for bounce buffer",
1357df54c2f9SSascha Wildner ENOMEM);
1358df54c2f9SSascha Wildner /* Restore original data pointer and length. */
1359df54c2f9SSascha Wildner req->data = req->real_data;
1360df54c2f9SSascha Wildner req->length = req->real_length;
1361df54c2f9SSascha Wildner return(ENOMEM);
1362df54c2f9SSascha Wildner }
1363df54c2f9SSascha Wildner }
1364df54c2f9SSascha Wildner
1365df54c2f9SSascha Wildner /*
1366df54c2f9SSascha Wildner * Map the data buffer into bus space and build the SG list.
1367df54c2f9SSascha Wildner */
1368df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1369df54c2f9SSascha Wildner /* Lock against multiple simultaneous ioctl calls. */
1370287a8577SAlex Hornung spin_lock(sc->io_lock);
1371df54c2f9SSascha Wildner error = bus_dmamap_load(sc->ioctl_tag, sc->ioctl_map,
1372df54c2f9SSascha Wildner req->data, req->length,
1373df54c2f9SSascha Wildner twa_map_load_data_callback, req,
1374df54c2f9SSascha Wildner BUS_DMA_WAITOK);
1375287a8577SAlex Hornung spin_unlock(sc->io_lock);
1376df54c2f9SSascha Wildner } else {
1377df54c2f9SSascha Wildner /*
1378df54c2f9SSascha Wildner * There's only one CAM I/O thread running at a time.
1379df54c2f9SSascha Wildner * So, there's no need to hold the io_lock.
1380df54c2f9SSascha Wildner */
1381df54c2f9SSascha Wildner error = bus_dmamap_load(sc->dma_tag, req->dma_map,
1382df54c2f9SSascha Wildner req->data, req->length,
1383df54c2f9SSascha Wildner twa_map_load_data_callback, req,
1384df54c2f9SSascha Wildner BUS_DMA_WAITOK);
1385df54c2f9SSascha Wildner }
1386df54c2f9SSascha Wildner
1387df54c2f9SSascha Wildner if (!error)
1388df54c2f9SSascha Wildner error = req->error_code;
1389df54c2f9SSascha Wildner else {
1390df54c2f9SSascha Wildner if (error == EINPROGRESS) {
1391df54c2f9SSascha Wildner /*
1392df54c2f9SSascha Wildner * Specifying sc->io_lock as the lockfuncarg
1393df54c2f9SSascha Wildner * in ...tag_create should protect the access
1394df54c2f9SSascha Wildner * of ...FLAGS_MAPPED from the callback.
1395df54c2f9SSascha Wildner */
1396287a8577SAlex Hornung spin_lock(sc->io_lock);
1397df54c2f9SSascha Wildner if (!(req->flags & TW_OSLI_REQ_FLAGS_MAPPED))
1398df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_IN_PROGRESS;
1399df54c2f9SSascha Wildner tw_osli_disallow_new_requests(sc, &(req->req_handle));
1400287a8577SAlex Hornung spin_unlock(sc->io_lock);
1401df54c2f9SSascha Wildner error = 0;
1402df54c2f9SSascha Wildner } else {
14034fbf05f9SSascha Wildner tw_osli_printf(sc, "error = %d",
14044fbf05f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
14054fbf05f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
14064fbf05f9SSascha Wildner 0x9999,
14074fbf05f9SSascha Wildner "Failed to map DMA memory "
14084fbf05f9SSascha Wildner "for I/O request",
14094fbf05f9SSascha Wildner error);
14104fbf05f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_FAILED;
1411df54c2f9SSascha Wildner /* Free alignment buffer if it was used. */
1412df54c2f9SSascha Wildner if (req->flags &
1413df54c2f9SSascha Wildner TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) {
1414df54c2f9SSascha Wildner kfree(req->data, TW_OSLI_MALLOC_CLASS);
1415df54c2f9SSascha Wildner /*
1416df54c2f9SSascha Wildner * Restore original data pointer
1417df54c2f9SSascha Wildner * and length.
1418df54c2f9SSascha Wildner */
1419df54c2f9SSascha Wildner req->data = req->real_data;
1420df54c2f9SSascha Wildner req->length = req->real_length;
1421df54c2f9SSascha Wildner }
1422df54c2f9SSascha Wildner }
1423df54c2f9SSascha Wildner }
1424df54c2f9SSascha Wildner
1425df54c2f9SSascha Wildner } else {
1426df54c2f9SSascha Wildner /* Mark the request as currently being processed. */
1427df54c2f9SSascha Wildner req->state = TW_OSLI_REQ_STATE_BUSY;
1428df54c2f9SSascha Wildner /* Move the request into the busy queue. */
1429df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_BUSY_Q);
1430df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU)
1431df54c2f9SSascha Wildner error = tw_cl_fw_passthru(&sc->ctlr_handle,
1432df54c2f9SSascha Wildner &(req->req_pkt), &(req->req_handle));
1433df54c2f9SSascha Wildner else
1434df54c2f9SSascha Wildner error = tw_cl_start_io(&sc->ctlr_handle,
1435df54c2f9SSascha Wildner &(req->req_pkt), &(req->req_handle));
1436df54c2f9SSascha Wildner if (error) {
1437df54c2f9SSascha Wildner req->error_code = error;
1438df54c2f9SSascha Wildner req->req_pkt.tw_osl_callback(&(req->req_handle));
1439df54c2f9SSascha Wildner }
1440df54c2f9SSascha Wildner }
1441df54c2f9SSascha Wildner return(error);
1442df54c2f9SSascha Wildner }
1443df54c2f9SSascha Wildner
1444df54c2f9SSascha Wildner
1445df54c2f9SSascha Wildner
1446df54c2f9SSascha Wildner /*
1447df54c2f9SSascha Wildner * Function name: tw_osli_unmap_request
1448df54c2f9SSascha Wildner * Description: Undoes the mapping done by tw_osli_map_request.
1449df54c2f9SSascha Wildner *
1450df54c2f9SSascha Wildner * Input: req -- ptr to request pkt
1451df54c2f9SSascha Wildner * Output: None
1452df54c2f9SSascha Wildner * Return value: None
1453df54c2f9SSascha Wildner */
1454df54c2f9SSascha Wildner TW_VOID
tw_osli_unmap_request(struct tw_osli_req_context * req)1455df54c2f9SSascha Wildner tw_osli_unmap_request(struct tw_osli_req_context *req)
1456df54c2f9SSascha Wildner {
1457df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
1458df54c2f9SSascha Wildner
1459df54c2f9SSascha Wildner tw_osli_dbg_dprintf(10, sc, "entered");
1460df54c2f9SSascha Wildner
1461df54c2f9SSascha Wildner /* If the command involved data, unmap that too. */
1462df54c2f9SSascha Wildner if (req->data != NULL) {
1463df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_PASSTHRU) {
1464df54c2f9SSascha Wildner /* Lock against multiple simultaneous ioctl calls. */
1465287a8577SAlex Hornung spin_lock(sc->io_lock);
1466df54c2f9SSascha Wildner
1467df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN) {
1468df54c2f9SSascha Wildner bus_dmamap_sync(sc->ioctl_tag,
1469df54c2f9SSascha Wildner sc->ioctl_map, BUS_DMASYNC_POSTREAD);
1470df54c2f9SSascha Wildner
1471df54c2f9SSascha Wildner /*
1472df54c2f9SSascha Wildner * If we are using a bounce buffer, and we are
1473df54c2f9SSascha Wildner * reading data, copy the real data in.
1474df54c2f9SSascha Wildner */
1475df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1476df54c2f9SSascha Wildner bcopy(req->data, req->real_data,
1477df54c2f9SSascha Wildner req->real_length);
1478df54c2f9SSascha Wildner }
1479df54c2f9SSascha Wildner
1480df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT)
1481df54c2f9SSascha Wildner bus_dmamap_sync(sc->ioctl_tag, sc->ioctl_map,
1482df54c2f9SSascha Wildner BUS_DMASYNC_POSTWRITE);
1483df54c2f9SSascha Wildner
1484df54c2f9SSascha Wildner bus_dmamap_unload(sc->ioctl_tag, sc->ioctl_map);
1485df54c2f9SSascha Wildner
1486287a8577SAlex Hornung spin_unlock(sc->io_lock);
1487df54c2f9SSascha Wildner } else {
1488df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_IN) {
1489df54c2f9SSascha Wildner bus_dmamap_sync(sc->dma_tag,
1490df54c2f9SSascha Wildner req->dma_map, BUS_DMASYNC_POSTREAD);
1491df54c2f9SSascha Wildner
1492df54c2f9SSascha Wildner /*
1493df54c2f9SSascha Wildner * If we are using a bounce buffer, and we are
1494df54c2f9SSascha Wildner * reading data, copy the real data in.
1495df54c2f9SSascha Wildner */
1496df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED)
1497df54c2f9SSascha Wildner bcopy(req->data, req->real_data,
1498df54c2f9SSascha Wildner req->real_length);
1499df54c2f9SSascha Wildner }
1500df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_OUT)
1501df54c2f9SSascha Wildner bus_dmamap_sync(sc->dma_tag, req->dma_map,
1502df54c2f9SSascha Wildner BUS_DMASYNC_POSTWRITE);
1503df54c2f9SSascha Wildner
1504df54c2f9SSascha Wildner bus_dmamap_unload(sc->dma_tag, req->dma_map);
1505df54c2f9SSascha Wildner }
1506df54c2f9SSascha Wildner }
1507df54c2f9SSascha Wildner
1508df54c2f9SSascha Wildner /* Free alignment buffer if it was used. */
1509df54c2f9SSascha Wildner if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) {
1510df54c2f9SSascha Wildner kfree(req->data, TW_OSLI_MALLOC_CLASS);
1511df54c2f9SSascha Wildner /* Restore original data pointer and length. */
1512df54c2f9SSascha Wildner req->data = req->real_data;
1513df54c2f9SSascha Wildner req->length = req->real_length;
1514df54c2f9SSascha Wildner }
1515df54c2f9SSascha Wildner }
1516df54c2f9SSascha Wildner
1517df54c2f9SSascha Wildner
1518df54c2f9SSascha Wildner
1519df54c2f9SSascha Wildner #ifdef TW_OSL_DEBUG
1520df54c2f9SSascha Wildner
1521df54c2f9SSascha Wildner TW_VOID twa_report_stats(TW_VOID);
1522df54c2f9SSascha Wildner TW_VOID twa_reset_stats(TW_VOID);
1523df54c2f9SSascha Wildner TW_VOID tw_osli_print_ctlr_stats(struct twa_softc *sc);
1524df54c2f9SSascha Wildner TW_VOID twa_print_req_info(struct tw_osli_req_context *req);
1525df54c2f9SSascha Wildner
1526df54c2f9SSascha Wildner
1527df54c2f9SSascha Wildner /*
1528df54c2f9SSascha Wildner * Function name: twa_report_stats
1529df54c2f9SSascha Wildner * Description: For being called from ddb. Calls functions that print
1530df54c2f9SSascha Wildner * OSL and CL internal stats for the controller.
1531df54c2f9SSascha Wildner *
1532df54c2f9SSascha Wildner * Input: None
1533df54c2f9SSascha Wildner * Output: None
1534df54c2f9SSascha Wildner * Return value: None
1535df54c2f9SSascha Wildner */
1536df54c2f9SSascha Wildner TW_VOID
twa_report_stats(TW_VOID)1537df54c2f9SSascha Wildner twa_report_stats(TW_VOID)
1538df54c2f9SSascha Wildner {
1539df54c2f9SSascha Wildner struct twa_softc *sc;
1540df54c2f9SSascha Wildner TW_INT32 i;
1541df54c2f9SSascha Wildner
1542df54c2f9SSascha Wildner for (i = 0; (sc = devclass_get_softc(twa_devclass, i)) != NULL; i++) {
1543df54c2f9SSascha Wildner tw_osli_print_ctlr_stats(sc);
1544df54c2f9SSascha Wildner tw_cl_print_ctlr_stats(&sc->ctlr_handle);
1545df54c2f9SSascha Wildner }
1546df54c2f9SSascha Wildner }
1547df54c2f9SSascha Wildner
1548df54c2f9SSascha Wildner
1549df54c2f9SSascha Wildner
1550df54c2f9SSascha Wildner /*
1551df54c2f9SSascha Wildner * Function name: tw_osli_print_ctlr_stats
1552df54c2f9SSascha Wildner * Description: For being called from ddb. Prints OSL controller stats
1553df54c2f9SSascha Wildner *
1554df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal controller context
1555df54c2f9SSascha Wildner * Output: None
1556df54c2f9SSascha Wildner * Return value: None
1557df54c2f9SSascha Wildner */
1558df54c2f9SSascha Wildner TW_VOID
tw_osli_print_ctlr_stats(struct twa_softc * sc)1559df54c2f9SSascha Wildner tw_osli_print_ctlr_stats(struct twa_softc *sc)
1560df54c2f9SSascha Wildner {
1561df54c2f9SSascha Wildner twa_printf(sc, "osl_ctlr_ctxt = %p\n", sc);
1562df54c2f9SSascha Wildner twa_printf(sc, "OSLq type current max\n");
1563df54c2f9SSascha Wildner twa_printf(sc, "free %04d %04d\n",
1564df54c2f9SSascha Wildner sc->q_stats[TW_OSLI_FREE_Q].cur_len,
1565df54c2f9SSascha Wildner sc->q_stats[TW_OSLI_FREE_Q].max_len);
1566df54c2f9SSascha Wildner twa_printf(sc, "busy %04d %04d\n",
1567df54c2f9SSascha Wildner sc->q_stats[TW_OSLI_BUSY_Q].cur_len,
1568df54c2f9SSascha Wildner sc->q_stats[TW_OSLI_BUSY_Q].max_len);
1569df54c2f9SSascha Wildner }
1570df54c2f9SSascha Wildner
1571df54c2f9SSascha Wildner
1572df54c2f9SSascha Wildner
1573df54c2f9SSascha Wildner /*
1574df54c2f9SSascha Wildner * Function name: twa_print_req_info
1575df54c2f9SSascha Wildner * Description: For being called from ddb. Calls functions that print
1576df54c2f9SSascha Wildner * OSL and CL internal details for the request.
1577df54c2f9SSascha Wildner *
1578df54c2f9SSascha Wildner * Input: req -- ptr to OSL internal request context
1579df54c2f9SSascha Wildner * Output: None
1580df54c2f9SSascha Wildner * Return value: None
1581df54c2f9SSascha Wildner */
1582df54c2f9SSascha Wildner TW_VOID
twa_print_req_info(struct tw_osli_req_context * req)1583df54c2f9SSascha Wildner twa_print_req_info(struct tw_osli_req_context *req)
1584df54c2f9SSascha Wildner {
1585df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
1586df54c2f9SSascha Wildner
1587df54c2f9SSascha Wildner twa_printf(sc, "OSL details for request:\n");
1588df54c2f9SSascha Wildner twa_printf(sc, "osl_req_ctxt = %p, cl_req_ctxt = %p\n"
1589df54c2f9SSascha Wildner "data = %p, length = 0x%x, real_data = %p, real_length = 0x%x\n"
1590df54c2f9SSascha Wildner "state = 0x%x, flags = 0x%x, error = 0x%x, orig_req = %p\n"
1591df54c2f9SSascha Wildner "next_req = %p, prev_req = %p, dma_map = %p\n",
1592df54c2f9SSascha Wildner req->req_handle.osl_req_ctxt, req->req_handle.cl_req_ctxt,
1593df54c2f9SSascha Wildner req->data, req->length, req->real_data, req->real_length,
1594df54c2f9SSascha Wildner req->state, req->flags, req->error_code, req->orig_req,
1595df54c2f9SSascha Wildner req->link.next, req->link.prev, req->dma_map);
1596df54c2f9SSascha Wildner tw_cl_print_req_info(&(req->req_handle));
1597df54c2f9SSascha Wildner }
1598df54c2f9SSascha Wildner
1599df54c2f9SSascha Wildner
1600df54c2f9SSascha Wildner
1601df54c2f9SSascha Wildner /*
1602df54c2f9SSascha Wildner * Function name: twa_reset_stats
1603df54c2f9SSascha Wildner * Description: For being called from ddb.
1604df54c2f9SSascha Wildner * Resets some OSL controller stats.
1605df54c2f9SSascha Wildner *
1606df54c2f9SSascha Wildner * Input: None
1607df54c2f9SSascha Wildner * Output: None
1608df54c2f9SSascha Wildner * Return value: None
1609df54c2f9SSascha Wildner */
1610df54c2f9SSascha Wildner TW_VOID
twa_reset_stats(TW_VOID)1611df54c2f9SSascha Wildner twa_reset_stats(TW_VOID)
1612df54c2f9SSascha Wildner {
1613df54c2f9SSascha Wildner struct twa_softc *sc;
1614df54c2f9SSascha Wildner TW_INT32 i;
1615df54c2f9SSascha Wildner
1616df54c2f9SSascha Wildner for (i = 0; (sc = devclass_get_softc(twa_devclass, i)) != NULL; i++) {
1617df54c2f9SSascha Wildner sc->q_stats[TW_OSLI_FREE_Q].max_len = 0;
1618df54c2f9SSascha Wildner sc->q_stats[TW_OSLI_BUSY_Q].max_len = 0;
1619df54c2f9SSascha Wildner tw_cl_reset_stats(&sc->ctlr_handle);
1620df54c2f9SSascha Wildner }
1621df54c2f9SSascha Wildner }
1622df54c2f9SSascha Wildner
1623df54c2f9SSascha Wildner #endif /* TW_OSL_DEBUG */
1624