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