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