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