17282444bSPedro F. Giffuni /*- 27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 37282444bSPedro F. Giffuni * 4db1fda10SXin LI * Copyright (c) 2010, LSI Corp. 5db1fda10SXin LI * All rights reserved. 6db1fda10SXin LI * Author : Manjunath Ranganathaiah 7db1fda10SXin LI * Support: freebsdraid@lsi.com 8db1fda10SXin LI * 9db1fda10SXin LI * Redistribution and use in source and binary forms, with or without 10db1fda10SXin LI * modification, are permitted provided that the following conditions 11db1fda10SXin LI * are met: 12db1fda10SXin LI * 13db1fda10SXin LI * 1. Redistributions of source code must retain the above copyright 14db1fda10SXin LI * notice, this list of conditions and the following disclaimer. 15db1fda10SXin LI * 2. Redistributions in binary form must reproduce the above copyright 16db1fda10SXin LI * notice, this list of conditions and the following disclaimer in 17db1fda10SXin LI * the documentation and/or other materials provided with the 18db1fda10SXin LI * distribution. 19db1fda10SXin LI * 3. Neither the name of the <ORGANIZATION> nor the names of its 20db1fda10SXin LI * contributors may be used to endorse or promote products derived 21db1fda10SXin LI * from this software without specific prior written permission. 22db1fda10SXin LI * 23db1fda10SXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24db1fda10SXin LI * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25db1fda10SXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26db1fda10SXin LI * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27db1fda10SXin LI * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28db1fda10SXin LI * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29db1fda10SXin LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30db1fda10SXin LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31db1fda10SXin LI * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32db1fda10SXin LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33db1fda10SXin LI * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34db1fda10SXin LI * POSSIBILITY OF SUCH DAMAGE. 35db1fda10SXin LI */ 36db1fda10SXin LI 374b7ec270SMarius Strobl #include <sys/cdefs.h> 384b7ec270SMarius Strobl __FBSDID("$FreeBSD$"); 39db1fda10SXin LI 40db1fda10SXin LI #include <dev/tws/tws.h> 41db1fda10SXin LI #include <dev/tws/tws_services.h> 42db1fda10SXin LI #include <dev/tws/tws_hdm.h> 43db1fda10SXin LI 44db1fda10SXin LI #include <cam/cam.h> 45db1fda10SXin LI #include <cam/cam_ccb.h> 46cca5be24SEdward Tomasz Napierala #include <cam/cam_xpt.h> 47db1fda10SXin LI 48db1fda10SXin LI MALLOC_DEFINE(M_TWS, "twsbuf", "buffers used by tws driver"); 49db1fda10SXin LI int tws_queue_depth = TWS_MAX_REQS; 50db1fda10SXin LI int tws_enable_msi = 0; 51db1fda10SXin LI int tws_enable_msix = 0; 52db1fda10SXin LI 53db1fda10SXin LI /* externs */ 54db1fda10SXin LI extern int tws_cam_attach(struct tws_softc *sc); 55db1fda10SXin LI extern void tws_cam_detach(struct tws_softc *sc); 56db1fda10SXin LI extern int tws_init_ctlr(struct tws_softc *sc); 57db1fda10SXin LI extern boolean tws_ctlr_ready(struct tws_softc *sc); 58db1fda10SXin LI extern void tws_turn_off_interrupts(struct tws_softc *sc); 59db1fda10SXin LI extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, 60db1fda10SXin LI u_int8_t q_type ); 61db1fda10SXin LI extern struct tws_request *tws_q_remove_request(struct tws_softc *sc, 62db1fda10SXin LI struct tws_request *req, u_int8_t q_type ); 63db1fda10SXin LI extern struct tws_request *tws_q_remove_head(struct tws_softc *sc, 64db1fda10SXin LI u_int8_t q_type ); 65db1fda10SXin LI extern boolean tws_get_response(struct tws_softc *sc, u_int16_t *req_id); 66db1fda10SXin LI extern boolean tws_ctlr_reset(struct tws_softc *sc); 67db1fda10SXin LI extern void tws_intr(void *arg); 68db1fda10SXin LI extern int tws_use_32bit_sgls; 69db1fda10SXin LI 70db1fda10SXin LI struct tws_request *tws_get_request(struct tws_softc *sc, u_int16_t type); 71db1fda10SXin LI int tws_init_connect(struct tws_softc *sc, u_int16_t mc); 72db1fda10SXin LI void tws_send_event(struct tws_softc *sc, u_int8_t event); 73db1fda10SXin LI uint8_t tws_get_state(struct tws_softc *sc); 74db1fda10SXin LI void tws_release_request(struct tws_request *req); 75db1fda10SXin LI 76db1fda10SXin LI /* Function prototypes */ 77db1fda10SXin LI static d_open_t tws_open; 78db1fda10SXin LI static d_close_t tws_close; 79db1fda10SXin LI static d_read_t tws_read; 80db1fda10SXin LI static d_write_t tws_write; 81db1fda10SXin LI extern d_ioctl_t tws_ioctl; 82db1fda10SXin LI 83db1fda10SXin LI static int tws_init(struct tws_softc *sc); 84db1fda10SXin LI static void tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs, 85db1fda10SXin LI int nseg, int error); 86db1fda10SXin LI 87db1fda10SXin LI static int tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size); 88db1fda10SXin LI static int tws_init_aen_q(struct tws_softc *sc); 89db1fda10SXin LI static int tws_init_trace_q(struct tws_softc *sc); 90db1fda10SXin LI static int tws_setup_irq(struct tws_softc *sc); 91db1fda10SXin LI int tws_setup_intr(struct tws_softc *sc, int irqs); 92db1fda10SXin LI int tws_teardown_intr(struct tws_softc *sc); 93db1fda10SXin LI 94db1fda10SXin LI /* Character device entry points */ 95db1fda10SXin LI 96db1fda10SXin LI static struct cdevsw tws_cdevsw = { 97db1fda10SXin LI .d_version = D_VERSION, 98db1fda10SXin LI .d_open = tws_open, 99db1fda10SXin LI .d_close = tws_close, 100db1fda10SXin LI .d_read = tws_read, 101db1fda10SXin LI .d_write = tws_write, 102db1fda10SXin LI .d_ioctl = tws_ioctl, 103db1fda10SXin LI .d_name = "tws", 104db1fda10SXin LI }; 105db1fda10SXin LI 106db1fda10SXin LI /* 107db1fda10SXin LI * In the cdevsw routines, we find our softc by using the si_drv1 member 108db1fda10SXin LI * of struct cdev. We set this variable to point to our softc in our 109db1fda10SXin LI * attach routine when we create the /dev entry. 110db1fda10SXin LI */ 111db1fda10SXin LI 112db1fda10SXin LI int 113f045564dSJohn Baldwin tws_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 114db1fda10SXin LI { 115db1fda10SXin LI struct tws_softc *sc = dev->si_drv1; 116db1fda10SXin LI 117db1fda10SXin LI if ( sc ) 118db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, oflags); 119db1fda10SXin LI return (0); 120db1fda10SXin LI } 121db1fda10SXin LI 122db1fda10SXin LI int 123f045564dSJohn Baldwin tws_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 124db1fda10SXin LI { 125db1fda10SXin LI struct tws_softc *sc = dev->si_drv1; 126db1fda10SXin LI 127db1fda10SXin LI if ( sc ) 128db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, fflag); 129db1fda10SXin LI return (0); 130db1fda10SXin LI } 131db1fda10SXin LI 132db1fda10SXin LI int 133db1fda10SXin LI tws_read(struct cdev *dev, struct uio *uio, int ioflag) 134db1fda10SXin LI { 135db1fda10SXin LI struct tws_softc *sc = dev->si_drv1; 136db1fda10SXin LI 137db1fda10SXin LI if ( sc ) 138db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, ioflag); 139db1fda10SXin LI return (0); 140db1fda10SXin LI } 141db1fda10SXin LI 142db1fda10SXin LI int 143db1fda10SXin LI tws_write(struct cdev *dev, struct uio *uio, int ioflag) 144db1fda10SXin LI { 145db1fda10SXin LI struct tws_softc *sc = dev->si_drv1; 146db1fda10SXin LI 147db1fda10SXin LI if ( sc ) 148db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, ioflag); 149db1fda10SXin LI return (0); 150db1fda10SXin LI } 151db1fda10SXin LI 152db1fda10SXin LI /* PCI Support Functions */ 153db1fda10SXin LI 154db1fda10SXin LI /* 155db1fda10SXin LI * Compare the device ID of this device against the IDs that this driver 156db1fda10SXin LI * supports. If there is a match, set the description and return success. 157db1fda10SXin LI */ 158db1fda10SXin LI static int 159db1fda10SXin LI tws_probe(device_t dev) 160db1fda10SXin LI { 161db1fda10SXin LI static u_int8_t first_ctlr = 1; 162db1fda10SXin LI 163db1fda10SXin LI if ((pci_get_vendor(dev) == TWS_VENDOR_ID) && 164db1fda10SXin LI (pci_get_device(dev) == TWS_DEVICE_ID)) { 165db1fda10SXin LI device_set_desc(dev, "LSI 3ware SAS/SATA Storage Controller"); 166db1fda10SXin LI if (first_ctlr) { 167db1fda10SXin LI printf("LSI 3ware device driver for SAS/SATA storage " 168db1fda10SXin LI "controllers, version: %s\n", TWS_DRIVER_VERSION_STRING); 169db1fda10SXin LI first_ctlr = 0; 170db1fda10SXin LI } 171db1fda10SXin LI 17247833734SXin LI return(BUS_PROBE_DEFAULT); 173db1fda10SXin LI } 174db1fda10SXin LI return (ENXIO); 175db1fda10SXin LI } 176db1fda10SXin LI 177db1fda10SXin LI /* Attach function is only called if the probe is successful. */ 178db1fda10SXin LI 179db1fda10SXin LI static int 180db1fda10SXin LI tws_attach(device_t dev) 181db1fda10SXin LI { 182db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 183c68534f1SScott Long u_int32_t bar; 184db1fda10SXin LI int error=0,i; 185db1fda10SXin LI 186db1fda10SXin LI /* no tracing yet */ 187db1fda10SXin LI /* Look up our softc and initialize its fields. */ 188db1fda10SXin LI sc->tws_dev = dev; 189db1fda10SXin LI sc->device_id = pci_get_device(dev); 190db1fda10SXin LI sc->subvendor_id = pci_get_subvendor(dev); 191db1fda10SXin LI sc->subdevice_id = pci_get_subdevice(dev); 192db1fda10SXin LI 193db1fda10SXin LI /* Intialize mutexes */ 194db1fda10SXin LI mtx_init( &sc->q_lock, "tws_q_lock", NULL, MTX_DEF); 195db1fda10SXin LI mtx_init( &sc->sim_lock, "tws_sim_lock", NULL, MTX_DEF); 196db1fda10SXin LI mtx_init( &sc->gen_lock, "tws_gen_lock", NULL, MTX_DEF); 19795161fc3SJim Harris mtx_init( &sc->io_lock, "tws_io_lock", NULL, MTX_DEF | MTX_RECURSE); 198fd90e2edSJung-uk Kim callout_init(&sc->stats_timer, 1); 199db1fda10SXin LI 200db1fda10SXin LI if ( tws_init_trace_q(sc) == FAILURE ) 201db1fda10SXin LI printf("trace init failure\n"); 202db1fda10SXin LI /* send init event */ 203db1fda10SXin LI mtx_lock(&sc->gen_lock); 204db1fda10SXin LI tws_send_event(sc, TWS_INIT_START); 205db1fda10SXin LI mtx_unlock(&sc->gen_lock); 206db1fda10SXin LI 207db1fda10SXin LI #if _BYTE_ORDER == _BIG_ENDIAN 208db1fda10SXin LI TWS_TRACE(sc, "BIG endian", 0, 0); 209db1fda10SXin LI #endif 210db1fda10SXin LI /* sysctl context setup */ 211db1fda10SXin LI sysctl_ctx_init(&sc->tws_clist); 212db1fda10SXin LI sc->tws_oidp = SYSCTL_ADD_NODE(&sc->tws_clist, 213db1fda10SXin LI SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 2147029da5cSPawel Biernacki device_get_nameunit(dev), CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 215db1fda10SXin LI if ( sc->tws_oidp == NULL ) { 216db1fda10SXin LI tws_log(sc, SYSCTL_TREE_NODE_ADD); 217db1fda10SXin LI goto attach_fail_1; 218db1fda10SXin LI } 219db1fda10SXin LI SYSCTL_ADD_STRING(&sc->tws_clist, SYSCTL_CHILDREN(sc->tws_oidp), 220db1fda10SXin LI OID_AUTO, "driver_version", CTLFLAG_RD, 221db1fda10SXin LI TWS_DRIVER_VERSION_STRING, 0, "TWS driver version"); 222db1fda10SXin LI 223c68534f1SScott Long pci_enable_busmaster(dev); 224db1fda10SXin LI 225db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR0, 4); 226db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar0 ", bar, 0); 227db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR1, 4); 228db1fda10SXin LI bar = bar & ~TWS_BIT2; 229db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar1 ", bar, 0); 230db1fda10SXin LI 231db1fda10SXin LI /* MFA base address is BAR2 register used for 232db1fda10SXin LI * push mode. Firmware will evatualy move to 233db1fda10SXin LI * pull mode during witch this needs to change 234db1fda10SXin LI */ 235db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 236db1fda10SXin LI sc->mfa_base = (u_int64_t)pci_read_config(dev, TWS_PCI_BAR2, 4); 237db1fda10SXin LI sc->mfa_base = sc->mfa_base & ~TWS_BIT2; 238db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar2 ", sc->mfa_base, 0); 239db1fda10SXin LI #endif 240db1fda10SXin LI 241db1fda10SXin LI /* allocate MMIO register space */ 242db1fda10SXin LI sc->reg_res_id = TWS_PCI_BAR1; /* BAR1 offset */ 24343cd6160SJustin Hibbits if ((sc->reg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 24443cd6160SJustin Hibbits &(sc->reg_res_id), RF_ACTIVE)) 245db1fda10SXin LI == NULL) { 246db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 247db1fda10SXin LI goto attach_fail_1; 248db1fda10SXin LI } 249db1fda10SXin LI sc->bus_tag = rman_get_bustag(sc->reg_res); 250db1fda10SXin LI sc->bus_handle = rman_get_bushandle(sc->reg_res); 251db1fda10SXin LI 252db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 253db1fda10SXin LI /* Allocate bus space for inbound mfa */ 254db1fda10SXin LI sc->mfa_res_id = TWS_PCI_BAR2; /* BAR2 offset */ 255eff83876SJustin Hibbits if ((sc->mfa_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 256eff83876SJustin Hibbits &(sc->mfa_res_id), RF_ACTIVE)) 257db1fda10SXin LI == NULL) { 258db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 259db1fda10SXin LI goto attach_fail_2; 260db1fda10SXin LI } 261db1fda10SXin LI sc->bus_mfa_tag = rman_get_bustag(sc->mfa_res); 262db1fda10SXin LI sc->bus_mfa_handle = rman_get_bushandle(sc->mfa_res); 263db1fda10SXin LI #endif 264db1fda10SXin LI 265db1fda10SXin LI /* Allocate and register our interrupt. */ 266db1fda10SXin LI sc->intr_type = TWS_INTx; /* default */ 267db1fda10SXin LI 268db1fda10SXin LI if ( tws_enable_msi ) 269db1fda10SXin LI sc->intr_type = TWS_MSI; 270db1fda10SXin LI if ( tws_setup_irq(sc) == FAILURE ) { 271db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 272db1fda10SXin LI goto attach_fail_3; 273db1fda10SXin LI } 274db1fda10SXin LI 275db1fda10SXin LI /* 276db1fda10SXin LI * Create a /dev entry for this device. The kernel will assign us 277db1fda10SXin LI * a major number automatically. We use the unit number of this 278db1fda10SXin LI * device as the minor number and name the character device 279db1fda10SXin LI * "tws<unit>". 280db1fda10SXin LI */ 281db1fda10SXin LI sc->tws_cdev = make_dev(&tws_cdevsw, device_get_unit(dev), 282db1fda10SXin LI UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "tws%u", 283db1fda10SXin LI device_get_unit(dev)); 284db1fda10SXin LI sc->tws_cdev->si_drv1 = sc; 285db1fda10SXin LI 286db1fda10SXin LI if ( tws_init(sc) == FAILURE ) { 287db1fda10SXin LI tws_log(sc, TWS_INIT_FAILURE); 288db1fda10SXin LI goto attach_fail_4; 289db1fda10SXin LI } 290db1fda10SXin LI if ( tws_init_ctlr(sc) == FAILURE ) { 291db1fda10SXin LI tws_log(sc, TWS_CTLR_INIT_FAILURE); 292db1fda10SXin LI goto attach_fail_4; 293db1fda10SXin LI } 294db1fda10SXin LI if ((error = tws_cam_attach(sc))) { 295db1fda10SXin LI tws_log(sc, TWS_CAM_ATTACH); 296db1fda10SXin LI goto attach_fail_4; 297db1fda10SXin LI } 298db1fda10SXin LI /* send init complete event */ 299db1fda10SXin LI mtx_lock(&sc->gen_lock); 300db1fda10SXin LI tws_send_event(sc, TWS_INIT_COMPLETE); 301db1fda10SXin LI mtx_unlock(&sc->gen_lock); 302db1fda10SXin LI 303db1fda10SXin LI TWS_TRACE_DEBUG(sc, "attached successfully", 0, sc->device_id); 304db1fda10SXin LI return(0); 305db1fda10SXin LI 306db1fda10SXin LI attach_fail_4: 307db1fda10SXin LI tws_teardown_intr(sc); 308db1fda10SXin LI destroy_dev(sc->tws_cdev); 30930a13db0SJohn Baldwin if (sc->dma_mem_phys) 31030a13db0SJohn Baldwin bus_dmamap_unload(sc->cmd_tag, sc->cmd_map); 31130a13db0SJohn Baldwin if (sc->dma_mem) 31230a13db0SJohn Baldwin bus_dmamem_free(sc->cmd_tag, sc->dma_mem, sc->cmd_map); 31330a13db0SJohn Baldwin if (sc->cmd_tag) 31430a13db0SJohn Baldwin bus_dma_tag_destroy(sc->cmd_tag); 315db1fda10SXin LI attach_fail_3: 316db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 317db1fda10SXin LI if ( sc->irq_res[i] ){ 318db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 319db1fda10SXin LI SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i])) 320db1fda10SXin LI TWS_TRACE(sc, "bus irq res", 0, 0); 321db1fda10SXin LI } 322db1fda10SXin LI } 323db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 324db1fda10SXin LI attach_fail_2: 325db1fda10SXin LI #endif 326db1fda10SXin LI if ( sc->mfa_res ){ 327db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 328db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 329db1fda10SXin LI TWS_TRACE(sc, "bus release ", 0, sc->mfa_res_id); 330db1fda10SXin LI } 331db1fda10SXin LI if ( sc->reg_res ){ 332db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 333db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 334db1fda10SXin LI TWS_TRACE(sc, "bus release2 ", 0, sc->reg_res_id); 335db1fda10SXin LI } 336db1fda10SXin LI attach_fail_1: 337db1fda10SXin LI mtx_destroy(&sc->q_lock); 338db1fda10SXin LI mtx_destroy(&sc->sim_lock); 339db1fda10SXin LI mtx_destroy(&sc->gen_lock); 340db1fda10SXin LI mtx_destroy(&sc->io_lock); 341db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist); 342db1fda10SXin LI return (ENXIO); 343db1fda10SXin LI } 344db1fda10SXin LI 345db1fda10SXin LI /* Detach device. */ 346db1fda10SXin LI 347db1fda10SXin LI static int 348db1fda10SXin LI tws_detach(device_t dev) 349db1fda10SXin LI { 350db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 351db1fda10SXin LI int i; 352174d86a0SRobert Wing u_int32_t reg __tws_debug; 353db1fda10SXin LI 354db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 355db1fda10SXin LI 356db1fda10SXin LI mtx_lock(&sc->gen_lock); 357db1fda10SXin LI tws_send_event(sc, TWS_UNINIT_START); 358db1fda10SXin LI mtx_unlock(&sc->gen_lock); 359db1fda10SXin LI 360db1fda10SXin LI /* needs to disable interrupt before detaching from cam */ 361db1fda10SXin LI tws_turn_off_interrupts(sc); 362db1fda10SXin LI /* clear door bell */ 363db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4); 364db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4); 365db1fda10SXin LI TWS_TRACE_DEBUG(sc, "turn-off-intr", reg, 0); 366db1fda10SXin LI sc->obfl_q_overrun = false; 367db1fda10SXin LI tws_init_connect(sc, 1); 368db1fda10SXin LI 369db1fda10SXin LI /* Teardown the state in our softc created in our attach routine. */ 370db1fda10SXin LI /* Disconnect the interrupt handler. */ 371db1fda10SXin LI tws_teardown_intr(sc); 372db1fda10SXin LI 373db1fda10SXin LI /* Release irq resource */ 374db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 375db1fda10SXin LI if ( sc->irq_res[i] ){ 376db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 377db1fda10SXin LI SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i])) 378db1fda10SXin LI TWS_TRACE(sc, "bus release irq resource", 379db1fda10SXin LI i, sc->irq_res_id[i]); 380db1fda10SXin LI } 381db1fda10SXin LI } 382db1fda10SXin LI if ( sc->intr_type == TWS_MSI ) { 383db1fda10SXin LI pci_release_msi(sc->tws_dev); 384db1fda10SXin LI } 385db1fda10SXin LI 386db1fda10SXin LI tws_cam_detach(sc); 387db1fda10SXin LI 38830a13db0SJohn Baldwin if (sc->dma_mem_phys) 38930a13db0SJohn Baldwin bus_dmamap_unload(sc->cmd_tag, sc->cmd_map); 39030a13db0SJohn Baldwin if (sc->dma_mem) 39130a13db0SJohn Baldwin bus_dmamem_free(sc->cmd_tag, sc->dma_mem, sc->cmd_map); 39230a13db0SJohn Baldwin if (sc->cmd_tag) 39330a13db0SJohn Baldwin bus_dma_tag_destroy(sc->cmd_tag); 39430a13db0SJohn Baldwin 395db1fda10SXin LI /* Release memory resource */ 396db1fda10SXin LI if ( sc->mfa_res ){ 397db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 398db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 399db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->mfa_res_id); 400db1fda10SXin LI } 401db1fda10SXin LI if ( sc->reg_res ){ 402db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 403db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 404db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->reg_res_id); 405db1fda10SXin LI } 406db1fda10SXin LI 407166a4e47SJohn Baldwin for ( i=0; i< tws_queue_depth; i++) { 408166a4e47SJohn Baldwin if (sc->reqs[i].dma_map) 409166a4e47SJohn Baldwin bus_dmamap_destroy(sc->data_tag, sc->reqs[i].dma_map); 410166a4e47SJohn Baldwin callout_drain(&sc->reqs[i].timeout); 411166a4e47SJohn Baldwin } 412166a4e47SJohn Baldwin 413166a4e47SJohn Baldwin callout_drain(&sc->stats_timer); 414db1fda10SXin LI free(sc->reqs, M_TWS); 415db1fda10SXin LI free(sc->sense_bufs, M_TWS); 416cca5be24SEdward Tomasz Napierala xpt_free_ccb(sc->scan_ccb); 417c5f33959SXin LI if (sc->ioctl_data_mem) 418c5f33959SXin LI bus_dmamem_free(sc->data_tag, sc->ioctl_data_mem, sc->ioctl_data_map); 419166a4e47SJohn Baldwin if (sc->data_tag) 420166a4e47SJohn Baldwin bus_dma_tag_destroy(sc->data_tag); 421db1fda10SXin LI free(sc->aen_q.q, M_TWS); 422db1fda10SXin LI free(sc->trace_q.q, M_TWS); 423db1fda10SXin LI mtx_destroy(&sc->q_lock); 424db1fda10SXin LI mtx_destroy(&sc->sim_lock); 425db1fda10SXin LI mtx_destroy(&sc->gen_lock); 426db1fda10SXin LI mtx_destroy(&sc->io_lock); 427db1fda10SXin LI destroy_dev(sc->tws_cdev); 428db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist); 429db1fda10SXin LI return (0); 430db1fda10SXin LI } 431db1fda10SXin LI 432db1fda10SXin LI int 433db1fda10SXin LI tws_setup_intr(struct tws_softc *sc, int irqs) 434db1fda10SXin LI { 435db1fda10SXin LI int i, error; 436db1fda10SXin LI 437db1fda10SXin LI for(i=0;i<irqs;i++) { 438db1fda10SXin LI if (!(sc->intr_handle[i])) { 439db1fda10SXin LI if ((error = bus_setup_intr(sc->tws_dev, sc->irq_res[i], 440db1fda10SXin LI INTR_TYPE_CAM | INTR_MPSAFE, 441db1fda10SXin LI NULL, 442db1fda10SXin LI tws_intr, sc, &sc->intr_handle[i]))) { 443db1fda10SXin LI tws_log(sc, SETUP_INTR_RES); 444db1fda10SXin LI return(FAILURE); 445db1fda10SXin LI } 446db1fda10SXin LI } 447db1fda10SXin LI } 448db1fda10SXin LI return(SUCCESS); 449db1fda10SXin LI 450db1fda10SXin LI } 451db1fda10SXin LI 452db1fda10SXin LI int 453db1fda10SXin LI tws_teardown_intr(struct tws_softc *sc) 454db1fda10SXin LI { 455a21f086aSScott Long int i; 456db1fda10SXin LI 457db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 458db1fda10SXin LI if (sc->intr_handle[i]) { 459a21f086aSScott Long bus_teardown_intr(sc->tws_dev, 460db1fda10SXin LI sc->irq_res[i], sc->intr_handle[i]); 461db1fda10SXin LI sc->intr_handle[i] = NULL; 462db1fda10SXin LI } 463db1fda10SXin LI } 464db1fda10SXin LI return(SUCCESS); 465db1fda10SXin LI } 466db1fda10SXin LI 467db1fda10SXin LI static int 468db1fda10SXin LI tws_setup_irq(struct tws_softc *sc) 469db1fda10SXin LI { 470db1fda10SXin LI int messages; 471db1fda10SXin LI 472db1fda10SXin LI switch(sc->intr_type) { 473db1fda10SXin LI case TWS_INTx : 474db1fda10SXin LI sc->irqs = 1; 475db1fda10SXin LI sc->irq_res_id[0] = 0; 476db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 477db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 478db1fda10SXin LI if ( ! sc->irq_res[0] ) 479db1fda10SXin LI return(FAILURE); 480db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 481db1fda10SXin LI return(FAILURE); 482db1fda10SXin LI device_printf(sc->tws_dev, "Using legacy INTx\n"); 483db1fda10SXin LI break; 484db1fda10SXin LI case TWS_MSI : 485db1fda10SXin LI sc->irqs = 1; 486db1fda10SXin LI sc->irq_res_id[0] = 1; 487db1fda10SXin LI messages = 1; 488db1fda10SXin LI if (pci_alloc_msi(sc->tws_dev, &messages) != 0 ) { 489db1fda10SXin LI TWS_TRACE(sc, "pci alloc msi fail", 0, messages); 490db1fda10SXin LI return(FAILURE); 491db1fda10SXin LI } 492db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 493db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 494db1fda10SXin LI 495db1fda10SXin LI if ( !sc->irq_res[0] ) 496db1fda10SXin LI return(FAILURE); 497db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 498db1fda10SXin LI return(FAILURE); 499db1fda10SXin LI device_printf(sc->tws_dev, "Using MSI\n"); 500db1fda10SXin LI break; 501db1fda10SXin LI } 502db1fda10SXin LI 503db1fda10SXin LI return(SUCCESS); 504db1fda10SXin LI } 505db1fda10SXin LI 506db1fda10SXin LI static int 507db1fda10SXin LI tws_init(struct tws_softc *sc) 508db1fda10SXin LI { 509db1fda10SXin LI 510db1fda10SXin LI u_int32_t max_sg_elements; 511db1fda10SXin LI u_int32_t dma_mem_size; 512db1fda10SXin LI u_int32_t reg; 513db1fda10SXin LI 514db1fda10SXin LI sc->seq_id = 0; 515db1fda10SXin LI if ( tws_queue_depth > TWS_MAX_REQS ) 516db1fda10SXin LI tws_queue_depth = TWS_MAX_REQS; 517db1fda10SXin LI if (tws_queue_depth < TWS_RESERVED_REQS+1) 518db1fda10SXin LI tws_queue_depth = TWS_RESERVED_REQS+1; 519db1fda10SXin LI sc->is64bit = (sizeof(bus_addr_t) == 8) ? true : false; 520db1fda10SXin LI max_sg_elements = (sc->is64bit && !tws_use_32bit_sgls) ? 521db1fda10SXin LI TWS_MAX_64BIT_SG_ELEMENTS : 522db1fda10SXin LI TWS_MAX_32BIT_SG_ELEMENTS; 523db1fda10SXin LI dma_mem_size = (sizeof(struct tws_command_packet) * tws_queue_depth) + 524db1fda10SXin LI (TWS_SECTOR_SIZE) ; 525b6f97155SScott Long if ( bus_dma_tag_create(bus_get_dma_tag(sc->tws_dev), /* PCI parent */ 526db1fda10SXin LI TWS_ALIGNMENT, /* alignment */ 527db1fda10SXin LI 0, /* boundary */ 528db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 529db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 530db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 531db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsize */ 532db1fda10SXin LI max_sg_elements, /* numsegs */ 533db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */ 534db1fda10SXin LI 0, /* flags */ 535db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */ 536db1fda10SXin LI &sc->parent_tag /* tag */ 537db1fda10SXin LI )) { 538db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA parent tag Create fail", max_sg_elements, 539db1fda10SXin LI sc->is64bit); 540db1fda10SXin LI return(ENOMEM); 541db1fda10SXin LI } 542db1fda10SXin LI /* In bound message frame requires 16byte alignment. 543db1fda10SXin LI * Outbound MF's can live with 4byte alignment - for now just 544db1fda10SXin LI * use 16 for both. 545db1fda10SXin LI */ 546db1fda10SXin LI if ( bus_dma_tag_create(sc->parent_tag, /* parent */ 547db1fda10SXin LI TWS_IN_MF_ALIGNMENT, /* alignment */ 548db1fda10SXin LI 0, /* boundary */ 549db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 550db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 551db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 552db1fda10SXin LI dma_mem_size, /* maxsize */ 553db1fda10SXin LI 1, /* numsegs */ 554db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */ 555db1fda10SXin LI 0, /* flags */ 556db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */ 557db1fda10SXin LI &sc->cmd_tag /* tag */ 558db1fda10SXin LI )) { 559db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 560db1fda10SXin LI return(ENOMEM); 561db1fda10SXin LI } 562db1fda10SXin LI 563db1fda10SXin LI if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem, 564db1fda10SXin LI BUS_DMA_NOWAIT, &sc->cmd_map)) { 565db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA mem alloc fail", max_sg_elements, sc->is64bit); 566db1fda10SXin LI return(ENOMEM); 567db1fda10SXin LI } 568db1fda10SXin LI 569db1fda10SXin LI /* if bus_dmamem_alloc succeeds then bus_dmamap_load will succeed */ 570db1fda10SXin LI sc->dma_mem_phys=0; 571a21f086aSScott Long bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem, 572db1fda10SXin LI dma_mem_size, tws_dmamap_cmds_load_cbfn, 573db1fda10SXin LI &sc->dma_mem_phys, 0); 574db1fda10SXin LI 575db1fda10SXin LI /* 576db1fda10SXin LI * Create a dma tag for data buffers; size will be the maximum 577db1fda10SXin LI * possible I/O size (128kB). 578db1fda10SXin LI */ 579db1fda10SXin LI if (bus_dma_tag_create(sc->parent_tag, /* parent */ 580db1fda10SXin LI TWS_ALIGNMENT, /* alignment */ 581db1fda10SXin LI 0, /* boundary */ 582db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 583db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 584db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 585db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsize */ 586db1fda10SXin LI max_sg_elements, /* nsegments */ 587db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsegsize */ 588db1fda10SXin LI BUS_DMA_ALLOCNOW, /* flags */ 589db1fda10SXin LI busdma_lock_mutex, /* lockfunc */ 590db1fda10SXin LI &sc->io_lock, /* lockfuncarg */ 591db1fda10SXin LI &sc->data_tag /* tag */)) { 592db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 593db1fda10SXin LI return(ENOMEM); 594db1fda10SXin LI } 595db1fda10SXin LI 596db1fda10SXin LI sc->reqs = malloc(sizeof(struct tws_request) * tws_queue_depth, M_TWS, 597db1fda10SXin LI M_WAITOK | M_ZERO); 598db1fda10SXin LI sc->sense_bufs = malloc(sizeof(struct tws_sense) * tws_queue_depth, M_TWS, 599db1fda10SXin LI M_WAITOK | M_ZERO); 600cca5be24SEdward Tomasz Napierala sc->scan_ccb = xpt_alloc_ccb(); 601c5f33959SXin LI if (bus_dmamem_alloc(sc->data_tag, (void **)&sc->ioctl_data_mem, 602c5f33959SXin LI (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &sc->ioctl_data_map)) { 603c5f33959SXin LI device_printf(sc->tws_dev, "Cannot allocate ioctl data mem\n"); 604c5f33959SXin LI return(ENOMEM); 605c5f33959SXin LI } 606db1fda10SXin LI 607db1fda10SXin LI if ( !tws_ctlr_ready(sc) ) 608db1fda10SXin LI if( !tws_ctlr_reset(sc) ) 609db1fda10SXin LI return(FAILURE); 610db1fda10SXin LI 611db1fda10SXin LI bzero(&sc->stats, sizeof(struct tws_stats)); 612db1fda10SXin LI tws_init_qs(sc); 613db1fda10SXin LI tws_turn_off_interrupts(sc); 614db1fda10SXin LI 615db1fda10SXin LI /* 616db1fda10SXin LI * enable pull mode by setting bit1 . 617db1fda10SXin LI * setting bit0 to 1 will enable interrupt coalesing 618db1fda10SXin LI * will revisit. 619db1fda10SXin LI */ 620db1fda10SXin LI 621db1fda10SXin LI #ifdef TWS_PULL_MODE_ENABLE 622db1fda10SXin LI 623db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_CTL, 4); 624db1fda10SXin LI TWS_TRACE_DEBUG(sc, "i20 ctl", reg, TWS_I2O0_CTL); 625db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_CTL, reg | TWS_BIT1, 4); 626db1fda10SXin LI 627db1fda10SXin LI #endif 628db1fda10SXin LI 629db1fda10SXin LI TWS_TRACE_DEBUG(sc, "dma_mem_phys", sc->dma_mem_phys, TWS_I2O0_CTL); 630db1fda10SXin LI if ( tws_init_reqs(sc, dma_mem_size) == FAILURE ) 631db1fda10SXin LI return(FAILURE); 632db1fda10SXin LI if ( tws_init_aen_q(sc) == FAILURE ) 633db1fda10SXin LI return(FAILURE); 634db1fda10SXin LI 635db1fda10SXin LI return(SUCCESS); 636db1fda10SXin LI 637db1fda10SXin LI } 638db1fda10SXin LI 639db1fda10SXin LI static int 640db1fda10SXin LI tws_init_aen_q(struct tws_softc *sc) 641db1fda10SXin LI { 642db1fda10SXin LI sc->aen_q.head=0; 643db1fda10SXin LI sc->aen_q.tail=0; 644db1fda10SXin LI sc->aen_q.depth=256; 645db1fda10SXin LI sc->aen_q.overflow=0; 646db1fda10SXin LI sc->aen_q.q = malloc(sizeof(struct tws_event_packet)*sc->aen_q.depth, 647db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO); 648db1fda10SXin LI return(SUCCESS); 649db1fda10SXin LI } 650db1fda10SXin LI 651db1fda10SXin LI static int 652db1fda10SXin LI tws_init_trace_q(struct tws_softc *sc) 653db1fda10SXin LI { 654db1fda10SXin LI sc->trace_q.head=0; 655db1fda10SXin LI sc->trace_q.tail=0; 656db1fda10SXin LI sc->trace_q.depth=256; 657db1fda10SXin LI sc->trace_q.overflow=0; 658db1fda10SXin LI sc->trace_q.q = malloc(sizeof(struct tws_trace_rec)*sc->trace_q.depth, 659db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO); 660db1fda10SXin LI return(SUCCESS); 661db1fda10SXin LI } 662db1fda10SXin LI 663db1fda10SXin LI static int 664db1fda10SXin LI tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size) 665db1fda10SXin LI { 666db1fda10SXin LI 667db1fda10SXin LI struct tws_command_packet *cmd_buf; 668db1fda10SXin LI cmd_buf = (struct tws_command_packet *)sc->dma_mem; 669db1fda10SXin LI int i; 670db1fda10SXin LI 671db1fda10SXin LI bzero(cmd_buf, dma_mem_size); 672db1fda10SXin LI TWS_TRACE_DEBUG(sc, "phy cmd", sc->dma_mem_phys, 0); 673db1fda10SXin LI mtx_lock(&sc->q_lock); 674db1fda10SXin LI for ( i=0; i< tws_queue_depth; i++) 675db1fda10SXin LI { 676db1fda10SXin LI if (bus_dmamap_create(sc->data_tag, 0, &sc->reqs[i].dma_map)) { 677db1fda10SXin LI /* log a ENOMEM failure msg here */ 6783093cb15SXin LI mtx_unlock(&sc->q_lock); 679db1fda10SXin LI return(FAILURE); 680db1fda10SXin LI } 681db1fda10SXin LI sc->reqs[i].cmd_pkt = &cmd_buf[i]; 682db1fda10SXin LI 683db1fda10SXin LI sc->sense_bufs[i].hdr = &cmd_buf[i].hdr ; 684db1fda10SXin LI sc->sense_bufs[i].hdr_pkt_phy = sc->dma_mem_phys + 685db1fda10SXin LI (i * sizeof(struct tws_command_packet)); 686db1fda10SXin LI 687db1fda10SXin LI sc->reqs[i].cmd_pkt_phy = sc->dma_mem_phys + 688db1fda10SXin LI sizeof(struct tws_command_header) + 689db1fda10SXin LI (i * sizeof(struct tws_command_packet)); 690db1fda10SXin LI sc->reqs[i].request_id = i; 691db1fda10SXin LI sc->reqs[i].sc = sc; 692db1fda10SXin LI 693db1fda10SXin LI sc->reqs[i].cmd_pkt->hdr.header_desc.size_header = 128; 694db1fda10SXin LI 695fd90e2edSJung-uk Kim callout_init(&sc->reqs[i].timeout, 1); 696db1fda10SXin LI sc->reqs[i].state = TWS_REQ_STATE_FREE; 697db1fda10SXin LI if ( i >= TWS_RESERVED_REQS ) 698db1fda10SXin LI tws_q_insert_tail(sc, &sc->reqs[i], TWS_FREE_Q); 699db1fda10SXin LI } 700db1fda10SXin LI mtx_unlock(&sc->q_lock); 701db1fda10SXin LI return(SUCCESS); 702db1fda10SXin LI } 703db1fda10SXin LI 704db1fda10SXin LI static void 705db1fda10SXin LI tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs, 706db1fda10SXin LI int nseg, int error) 707db1fda10SXin LI { 708db1fda10SXin LI 709db1fda10SXin LI /* printf("command load done \n"); */ 710db1fda10SXin LI 711db1fda10SXin LI *((bus_addr_t *)arg) = segs[0].ds_addr; 712db1fda10SXin LI } 713db1fda10SXin LI 714db1fda10SXin LI void 715db1fda10SXin LI tws_send_event(struct tws_softc *sc, u_int8_t event) 716db1fda10SXin LI { 717db1fda10SXin LI mtx_assert(&sc->gen_lock, MA_OWNED); 718db1fda10SXin LI TWS_TRACE_DEBUG(sc, "received event ", 0, event); 719db1fda10SXin LI switch (event) { 720db1fda10SXin LI case TWS_INIT_START: 721db1fda10SXin LI sc->tws_state = TWS_INIT; 722db1fda10SXin LI break; 723db1fda10SXin LI 724db1fda10SXin LI case TWS_INIT_COMPLETE: 725db1fda10SXin LI if (sc->tws_state != TWS_INIT) { 726db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_ONLINE\n", sc->tws_state); 727db1fda10SXin LI } else { 728db1fda10SXin LI sc->tws_state = TWS_ONLINE; 729db1fda10SXin LI } 730db1fda10SXin LI break; 731db1fda10SXin LI 732db1fda10SXin LI case TWS_RESET_START: 733db1fda10SXin LI /* We can transition to reset state from any state except reset*/ 734db1fda10SXin LI if (sc->tws_state != TWS_RESET) { 735db1fda10SXin LI sc->tws_prev_state = sc->tws_state; 736db1fda10SXin LI sc->tws_state = TWS_RESET; 737db1fda10SXin LI } 738db1fda10SXin LI break; 739db1fda10SXin LI 740db1fda10SXin LI case TWS_RESET_COMPLETE: 741db1fda10SXin LI if (sc->tws_state != TWS_RESET) { 742db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => %d (previous state)\n", sc->tws_state, sc->tws_prev_state); 743db1fda10SXin LI } else { 744db1fda10SXin LI sc->tws_state = sc->tws_prev_state; 745db1fda10SXin LI } 746db1fda10SXin LI break; 747db1fda10SXin LI 748db1fda10SXin LI case TWS_SCAN_FAILURE: 749db1fda10SXin LI if (sc->tws_state != TWS_ONLINE) { 750db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_OFFLINE\n", sc->tws_state); 751db1fda10SXin LI } else { 752db1fda10SXin LI sc->tws_state = TWS_OFFLINE; 753db1fda10SXin LI } 754db1fda10SXin LI break; 755db1fda10SXin LI 756db1fda10SXin LI case TWS_UNINIT_START: 757db1fda10SXin LI if ((sc->tws_state != TWS_ONLINE) && (sc->tws_state != TWS_OFFLINE)) { 758db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_UNINIT\n", sc->tws_state); 759db1fda10SXin LI } else { 760db1fda10SXin LI sc->tws_state = TWS_UNINIT; 761db1fda10SXin LI } 762db1fda10SXin LI break; 763db1fda10SXin LI } 764db1fda10SXin LI 765db1fda10SXin LI } 766db1fda10SXin LI 767db1fda10SXin LI uint8_t 768db1fda10SXin LI tws_get_state(struct tws_softc *sc) 769db1fda10SXin LI { 770db1fda10SXin LI 771db1fda10SXin LI return((u_int8_t)sc->tws_state); 772db1fda10SXin LI 773db1fda10SXin LI } 774db1fda10SXin LI 775db1fda10SXin LI /* Called during system shutdown after sync. */ 776db1fda10SXin LI 777db1fda10SXin LI static int 778db1fda10SXin LI tws_shutdown(device_t dev) 779db1fda10SXin LI { 780db1fda10SXin LI 781db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 782db1fda10SXin LI 783db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 784db1fda10SXin LI 785db1fda10SXin LI tws_turn_off_interrupts(sc); 786db1fda10SXin LI tws_init_connect(sc, 1); 787db1fda10SXin LI 788db1fda10SXin LI return (0); 789db1fda10SXin LI } 790db1fda10SXin LI 791db1fda10SXin LI /* 792db1fda10SXin LI * Device suspend routine. 793db1fda10SXin LI */ 794db1fda10SXin LI static int 795db1fda10SXin LI tws_suspend(device_t dev) 796db1fda10SXin LI { 797db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 798db1fda10SXin LI 799db1fda10SXin LI if ( sc ) 800db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 801db1fda10SXin LI return (0); 802db1fda10SXin LI } 803db1fda10SXin LI 804db1fda10SXin LI /* 805db1fda10SXin LI * Device resume routine. 806db1fda10SXin LI */ 807db1fda10SXin LI static int 808db1fda10SXin LI tws_resume(device_t dev) 809db1fda10SXin LI { 810db1fda10SXin LI 811db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 812db1fda10SXin LI 813db1fda10SXin LI if ( sc ) 814db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 815db1fda10SXin LI return (0); 816db1fda10SXin LI } 817db1fda10SXin LI 818db1fda10SXin LI struct tws_request * 819db1fda10SXin LI tws_get_request(struct tws_softc *sc, u_int16_t type) 820db1fda10SXin LI { 821db1fda10SXin LI struct mtx *my_mutex = ((type == TWS_REQ_TYPE_SCSI_IO) ? &sc->q_lock : &sc->gen_lock); 822db1fda10SXin LI struct tws_request *r = NULL; 823db1fda10SXin LI 824db1fda10SXin LI mtx_lock(my_mutex); 825db1fda10SXin LI 826db1fda10SXin LI if (type == TWS_REQ_TYPE_SCSI_IO) { 827db1fda10SXin LI r = tws_q_remove_head(sc, TWS_FREE_Q); 828db1fda10SXin LI } else { 829db1fda10SXin LI if ( sc->reqs[type].state == TWS_REQ_STATE_FREE ) { 830db1fda10SXin LI r = &sc->reqs[type]; 831db1fda10SXin LI } 832db1fda10SXin LI } 833db1fda10SXin LI 834db1fda10SXin LI if ( r ) { 835db1fda10SXin LI bzero(&r->cmd_pkt->cmd, sizeof(struct tws_command_apache)); 836db1fda10SXin LI r->data = NULL; 837db1fda10SXin LI r->length = 0; 838db1fda10SXin LI r->type = type; 839db1fda10SXin LI r->flags = TWS_DIR_UNKNOWN; 840db1fda10SXin LI r->error_code = TWS_REQ_RET_INVALID; 841db1fda10SXin LI r->cb = NULL; 842db1fda10SXin LI r->ccb_ptr = NULL; 843166a4e47SJohn Baldwin callout_stop(&r->timeout); 844db1fda10SXin LI r->next = r->prev = NULL; 845db1fda10SXin LI 846db1fda10SXin LI r->state = ((type == TWS_REQ_TYPE_SCSI_IO) ? TWS_REQ_STATE_TRAN : TWS_REQ_STATE_BUSY); 847db1fda10SXin LI } 848db1fda10SXin LI 849db1fda10SXin LI mtx_unlock(my_mutex); 850db1fda10SXin LI 851db1fda10SXin LI return(r); 852db1fda10SXin LI } 853db1fda10SXin LI 854db1fda10SXin LI void 855db1fda10SXin LI tws_release_request(struct tws_request *req) 856db1fda10SXin LI { 857db1fda10SXin LI 858db1fda10SXin LI struct tws_softc *sc = req->sc; 859db1fda10SXin LI 860db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", sc, 0); 861db1fda10SXin LI mtx_lock(&sc->q_lock); 862db1fda10SXin LI tws_q_insert_tail(sc, req, TWS_FREE_Q); 863db1fda10SXin LI mtx_unlock(&sc->q_lock); 864db1fda10SXin LI } 865db1fda10SXin LI 866db1fda10SXin LI static device_method_t tws_methods[] = { 867db1fda10SXin LI /* Device interface */ 868db1fda10SXin LI DEVMETHOD(device_probe, tws_probe), 869db1fda10SXin LI DEVMETHOD(device_attach, tws_attach), 870db1fda10SXin LI DEVMETHOD(device_detach, tws_detach), 871db1fda10SXin LI DEVMETHOD(device_shutdown, tws_shutdown), 872db1fda10SXin LI DEVMETHOD(device_suspend, tws_suspend), 873db1fda10SXin LI DEVMETHOD(device_resume, tws_resume), 874db1fda10SXin LI 8754b7ec270SMarius Strobl DEVMETHOD_END 876db1fda10SXin LI }; 877db1fda10SXin LI 878db1fda10SXin LI static driver_t tws_driver = { 879db1fda10SXin LI "tws", 880db1fda10SXin LI tws_methods, 881db1fda10SXin LI sizeof(struct tws_softc) 882db1fda10SXin LI }; 883db1fda10SXin LI 884db1fda10SXin LI /* DEFINE_CLASS_0(tws, tws_driver, tws_methods, sizeof(struct tws_softc)); */ 885*716debedSJohn Baldwin DRIVER_MODULE(tws, pci, tws_driver, 0, 0); 886db1fda10SXin LI MODULE_DEPEND(tws, cam, 1, 1, 1); 887db1fda10SXin LI MODULE_DEPEND(tws, pci, 1, 1, 1); 888db1fda10SXin LI 889db1fda10SXin LI TUNABLE_INT("hw.tws.queue_depth", &tws_queue_depth); 890db1fda10SXin LI TUNABLE_INT("hw.tws.enable_msi", &tws_enable_msi); 891