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