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 116db1fda10SXin LI tws_open(struct cdev *dev, int oflags, int devtype, d_thread_t *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 126db1fda10SXin LI tws_close(struct cdev *dev, int fflag, int devtype, d_thread_t *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); 201db1fda10SXin LI 202db1fda10SXin LI if ( tws_init_trace_q(sc) == FAILURE ) 203db1fda10SXin LI printf("trace init failure\n"); 204db1fda10SXin LI /* send init event */ 205db1fda10SXin LI mtx_lock(&sc->gen_lock); 206db1fda10SXin LI tws_send_event(sc, TWS_INIT_START); 207db1fda10SXin LI mtx_unlock(&sc->gen_lock); 208db1fda10SXin LI 209db1fda10SXin LI 210db1fda10SXin LI #if _BYTE_ORDER == _BIG_ENDIAN 211db1fda10SXin LI TWS_TRACE(sc, "BIG endian", 0, 0); 212db1fda10SXin LI #endif 213db1fda10SXin LI /* sysctl context setup */ 214db1fda10SXin LI sysctl_ctx_init(&sc->tws_clist); 215db1fda10SXin LI sc->tws_oidp = SYSCTL_ADD_NODE(&sc->tws_clist, 216db1fda10SXin LI SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 217db1fda10SXin LI device_get_nameunit(dev), 218db1fda10SXin LI CTLFLAG_RD, 0, ""); 219db1fda10SXin LI if ( sc->tws_oidp == NULL ) { 220db1fda10SXin LI tws_log(sc, SYSCTL_TREE_NODE_ADD); 221db1fda10SXin LI goto attach_fail_1; 222db1fda10SXin LI } 223db1fda10SXin LI SYSCTL_ADD_STRING(&sc->tws_clist, SYSCTL_CHILDREN(sc->tws_oidp), 224db1fda10SXin LI OID_AUTO, "driver_version", CTLFLAG_RD, 225db1fda10SXin LI TWS_DRIVER_VERSION_STRING, 0, "TWS driver version"); 226db1fda10SXin LI 227c68534f1SScott Long pci_enable_busmaster(dev); 228db1fda10SXin LI 229db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR0, 4); 230db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar0 ", bar, 0); 231db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR1, 4); 232db1fda10SXin LI bar = bar & ~TWS_BIT2; 233db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar1 ", bar, 0); 234db1fda10SXin LI 235db1fda10SXin LI /* MFA base address is BAR2 register used for 236db1fda10SXin LI * push mode. Firmware will evatualy move to 237db1fda10SXin LI * pull mode during witch this needs to change 238db1fda10SXin LI */ 239db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 240db1fda10SXin LI sc->mfa_base = (u_int64_t)pci_read_config(dev, TWS_PCI_BAR2, 4); 241db1fda10SXin LI sc->mfa_base = sc->mfa_base & ~TWS_BIT2; 242db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar2 ", sc->mfa_base, 0); 243db1fda10SXin LI #endif 244db1fda10SXin LI 245db1fda10SXin LI /* allocate MMIO register space */ 246db1fda10SXin LI sc->reg_res_id = TWS_PCI_BAR1; /* BAR1 offset */ 247db1fda10SXin LI if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 248db1fda10SXin LI &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE)) 249db1fda10SXin LI == NULL) { 250db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 251db1fda10SXin LI goto attach_fail_1; 252db1fda10SXin LI } 253db1fda10SXin LI sc->bus_tag = rman_get_bustag(sc->reg_res); 254db1fda10SXin LI sc->bus_handle = rman_get_bushandle(sc->reg_res); 255db1fda10SXin LI 256db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 257db1fda10SXin LI /* Allocate bus space for inbound mfa */ 258db1fda10SXin LI sc->mfa_res_id = TWS_PCI_BAR2; /* BAR2 offset */ 259db1fda10SXin LI if ((sc->mfa_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 260db1fda10SXin LI &(sc->mfa_res_id), 0, ~0, 0x100000, RF_ACTIVE)) 261db1fda10SXin LI == NULL) { 262db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 263db1fda10SXin LI goto attach_fail_2; 264db1fda10SXin LI } 265db1fda10SXin LI sc->bus_mfa_tag = rman_get_bustag(sc->mfa_res); 266db1fda10SXin LI sc->bus_mfa_handle = rman_get_bushandle(sc->mfa_res); 267db1fda10SXin LI #endif 268db1fda10SXin LI 269db1fda10SXin LI /* Allocate and register our interrupt. */ 270db1fda10SXin LI sc->intr_type = TWS_INTx; /* default */ 271db1fda10SXin LI 272db1fda10SXin LI if ( tws_enable_msi ) 273db1fda10SXin LI sc->intr_type = TWS_MSI; 274db1fda10SXin LI if ( tws_setup_irq(sc) == FAILURE ) { 275db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 276db1fda10SXin LI goto attach_fail_3; 277db1fda10SXin LI } 278db1fda10SXin LI 279db1fda10SXin LI /* 280db1fda10SXin LI * Create a /dev entry for this device. The kernel will assign us 281db1fda10SXin LI * a major number automatically. We use the unit number of this 282db1fda10SXin LI * device as the minor number and name the character device 283db1fda10SXin LI * "tws<unit>". 284db1fda10SXin LI */ 285db1fda10SXin LI sc->tws_cdev = make_dev(&tws_cdevsw, device_get_unit(dev), 286db1fda10SXin LI UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "tws%u", 287db1fda10SXin LI device_get_unit(dev)); 288db1fda10SXin LI sc->tws_cdev->si_drv1 = sc; 289db1fda10SXin LI 290db1fda10SXin LI if ( tws_init(sc) == FAILURE ) { 291db1fda10SXin LI tws_log(sc, TWS_INIT_FAILURE); 292db1fda10SXin LI goto attach_fail_4; 293db1fda10SXin LI } 294db1fda10SXin LI if ( tws_init_ctlr(sc) == FAILURE ) { 295db1fda10SXin LI tws_log(sc, TWS_CTLR_INIT_FAILURE); 296db1fda10SXin LI goto attach_fail_4; 297db1fda10SXin LI } 298db1fda10SXin LI if ((error = tws_cam_attach(sc))) { 299db1fda10SXin LI tws_log(sc, TWS_CAM_ATTACH); 300db1fda10SXin LI goto attach_fail_4; 301db1fda10SXin LI } 302db1fda10SXin LI /* send init complete event */ 303db1fda10SXin LI mtx_lock(&sc->gen_lock); 304db1fda10SXin LI tws_send_event(sc, TWS_INIT_COMPLETE); 305db1fda10SXin LI mtx_unlock(&sc->gen_lock); 306db1fda10SXin LI 307db1fda10SXin LI TWS_TRACE_DEBUG(sc, "attached successfully", 0, sc->device_id); 308db1fda10SXin LI return(0); 309db1fda10SXin LI 310db1fda10SXin LI attach_fail_4: 311db1fda10SXin LI tws_teardown_intr(sc); 312db1fda10SXin LI destroy_dev(sc->tws_cdev); 313*30a13db0SJohn Baldwin if (sc->dma_mem_phys) 314*30a13db0SJohn Baldwin bus_dmamap_unload(sc->cmd_tag, sc->cmd_map); 315*30a13db0SJohn Baldwin if (sc->dma_mem) 316*30a13db0SJohn Baldwin bus_dmamem_free(sc->cmd_tag, sc->dma_mem, sc->cmd_map); 317*30a13db0SJohn Baldwin if (sc->cmd_tag) 318*30a13db0SJohn Baldwin bus_dma_tag_destroy(sc->cmd_tag); 319db1fda10SXin LI attach_fail_3: 320db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 321db1fda10SXin LI if ( sc->irq_res[i] ){ 322db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 323db1fda10SXin LI SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i])) 324db1fda10SXin LI TWS_TRACE(sc, "bus irq res", 0, 0); 325db1fda10SXin LI } 326db1fda10SXin LI } 327db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 328db1fda10SXin LI attach_fail_2: 329db1fda10SXin LI #endif 330db1fda10SXin LI if ( sc->mfa_res ){ 331db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 332db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 333db1fda10SXin LI TWS_TRACE(sc, "bus release ", 0, sc->mfa_res_id); 334db1fda10SXin LI } 335db1fda10SXin LI if ( sc->reg_res ){ 336db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 337db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 338db1fda10SXin LI TWS_TRACE(sc, "bus release2 ", 0, sc->reg_res_id); 339db1fda10SXin LI } 340db1fda10SXin LI attach_fail_1: 341db1fda10SXin LI mtx_destroy(&sc->q_lock); 342db1fda10SXin LI mtx_destroy(&sc->sim_lock); 343db1fda10SXin LI mtx_destroy(&sc->gen_lock); 344db1fda10SXin LI mtx_destroy(&sc->io_lock); 345db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist); 346db1fda10SXin LI return (ENXIO); 347db1fda10SXin LI } 348db1fda10SXin LI 349db1fda10SXin LI /* Detach device. */ 350db1fda10SXin LI 351db1fda10SXin LI static int 352db1fda10SXin LI tws_detach(device_t dev) 353db1fda10SXin LI { 354db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 355db1fda10SXin LI int i; 356db1fda10SXin LI u_int32_t reg; 357db1fda10SXin LI 358db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 359db1fda10SXin LI 360db1fda10SXin LI mtx_lock(&sc->gen_lock); 361db1fda10SXin LI tws_send_event(sc, TWS_UNINIT_START); 362db1fda10SXin LI mtx_unlock(&sc->gen_lock); 363db1fda10SXin LI 364db1fda10SXin LI /* needs to disable interrupt before detaching from cam */ 365db1fda10SXin LI tws_turn_off_interrupts(sc); 366db1fda10SXin LI /* clear door bell */ 367db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4); 368db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4); 369db1fda10SXin LI TWS_TRACE_DEBUG(sc, "turn-off-intr", reg, 0); 370db1fda10SXin LI sc->obfl_q_overrun = false; 371db1fda10SXin LI tws_init_connect(sc, 1); 372db1fda10SXin LI 373db1fda10SXin LI /* Teardown the state in our softc created in our attach routine. */ 374db1fda10SXin LI /* Disconnect the interrupt handler. */ 375db1fda10SXin LI tws_teardown_intr(sc); 376db1fda10SXin LI 377db1fda10SXin LI /* Release irq resource */ 378db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 379db1fda10SXin LI if ( sc->irq_res[i] ){ 380db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 381db1fda10SXin LI SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i])) 382db1fda10SXin LI TWS_TRACE(sc, "bus release irq resource", 383db1fda10SXin LI i, sc->irq_res_id[i]); 384db1fda10SXin LI } 385db1fda10SXin LI } 386db1fda10SXin LI if ( sc->intr_type == TWS_MSI ) { 387db1fda10SXin LI pci_release_msi(sc->tws_dev); 388db1fda10SXin LI } 389db1fda10SXin LI 390db1fda10SXin LI tws_cam_detach(sc); 391db1fda10SXin LI 392*30a13db0SJohn Baldwin if (sc->dma_mem_phys) 393*30a13db0SJohn Baldwin bus_dmamap_unload(sc->cmd_tag, sc->cmd_map); 394*30a13db0SJohn Baldwin if (sc->dma_mem) 395*30a13db0SJohn Baldwin bus_dmamem_free(sc->cmd_tag, sc->dma_mem, sc->cmd_map); 396*30a13db0SJohn Baldwin if (sc->cmd_tag) 397*30a13db0SJohn Baldwin bus_dma_tag_destroy(sc->cmd_tag); 398*30a13db0SJohn Baldwin 399db1fda10SXin LI /* Release memory resource */ 400db1fda10SXin LI if ( sc->mfa_res ){ 401db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 402db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 403db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->mfa_res_id); 404db1fda10SXin LI } 405db1fda10SXin LI if ( sc->reg_res ){ 406db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 407db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 408db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->reg_res_id); 409db1fda10SXin LI } 410db1fda10SXin LI 411db1fda10SXin LI free(sc->reqs, M_TWS); 412db1fda10SXin LI free(sc->sense_bufs, M_TWS); 413db1fda10SXin LI free(sc->scan_ccb, M_TWS); 414c5f33959SXin LI if (sc->ioctl_data_mem) 415c5f33959SXin LI bus_dmamem_free(sc->data_tag, sc->ioctl_data_mem, sc->ioctl_data_map); 416db1fda10SXin LI free(sc->aen_q.q, M_TWS); 417db1fda10SXin LI free(sc->trace_q.q, M_TWS); 418db1fda10SXin LI mtx_destroy(&sc->q_lock); 419db1fda10SXin LI mtx_destroy(&sc->sim_lock); 420db1fda10SXin LI mtx_destroy(&sc->gen_lock); 421db1fda10SXin LI mtx_destroy(&sc->io_lock); 422db1fda10SXin LI destroy_dev(sc->tws_cdev); 423db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist); 424db1fda10SXin LI return (0); 425db1fda10SXin LI } 426db1fda10SXin LI 427db1fda10SXin LI int 428db1fda10SXin LI tws_setup_intr(struct tws_softc *sc, int irqs) 429db1fda10SXin LI { 430db1fda10SXin LI int i, error; 431db1fda10SXin LI 432db1fda10SXin LI for(i=0;i<irqs;i++) { 433db1fda10SXin LI if (!(sc->intr_handle[i])) { 434db1fda10SXin LI if ((error = bus_setup_intr(sc->tws_dev, sc->irq_res[i], 435db1fda10SXin LI INTR_TYPE_CAM | INTR_MPSAFE, 436db1fda10SXin LI #if (__FreeBSD_version >= 700000) 437db1fda10SXin LI NULL, 438db1fda10SXin LI #endif 439db1fda10SXin LI tws_intr, sc, &sc->intr_handle[i]))) { 440db1fda10SXin LI tws_log(sc, SETUP_INTR_RES); 441db1fda10SXin LI return(FAILURE); 442db1fda10SXin LI } 443db1fda10SXin LI } 444db1fda10SXin LI } 445db1fda10SXin LI return(SUCCESS); 446db1fda10SXin LI 447db1fda10SXin LI } 448db1fda10SXin LI 449db1fda10SXin LI 450db1fda10SXin LI int 451db1fda10SXin LI tws_teardown_intr(struct tws_softc *sc) 452db1fda10SXin LI { 453db1fda10SXin LI int i, error; 454db1fda10SXin LI 455db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 456db1fda10SXin LI if (sc->intr_handle[i]) { 457db1fda10SXin LI error = bus_teardown_intr(sc->tws_dev, 458db1fda10SXin LI sc->irq_res[i], sc->intr_handle[i]); 459db1fda10SXin LI sc->intr_handle[i] = NULL; 460db1fda10SXin LI } 461db1fda10SXin LI } 462db1fda10SXin LI return(SUCCESS); 463db1fda10SXin LI } 464db1fda10SXin LI 465db1fda10SXin LI 466db1fda10SXin LI static int 467db1fda10SXin LI tws_setup_irq(struct tws_softc *sc) 468db1fda10SXin LI { 469db1fda10SXin LI int messages; 470db1fda10SXin LI 471db1fda10SXin LI switch(sc->intr_type) { 472db1fda10SXin LI case TWS_INTx : 473db1fda10SXin LI sc->irqs = 1; 474db1fda10SXin LI sc->irq_res_id[0] = 0; 475db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 476db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 477db1fda10SXin LI if ( ! sc->irq_res[0] ) 478db1fda10SXin LI return(FAILURE); 479db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 480db1fda10SXin LI return(FAILURE); 481db1fda10SXin LI device_printf(sc->tws_dev, "Using legacy INTx\n"); 482db1fda10SXin LI break; 483db1fda10SXin LI case TWS_MSI : 484db1fda10SXin LI sc->irqs = 1; 485db1fda10SXin LI sc->irq_res_id[0] = 1; 486db1fda10SXin LI messages = 1; 487db1fda10SXin LI if (pci_alloc_msi(sc->tws_dev, &messages) != 0 ) { 488db1fda10SXin LI TWS_TRACE(sc, "pci alloc msi fail", 0, messages); 489db1fda10SXin LI return(FAILURE); 490db1fda10SXin LI } 491db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 492db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 493db1fda10SXin LI 494db1fda10SXin LI if ( !sc->irq_res[0] ) 495db1fda10SXin LI return(FAILURE); 496db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 497db1fda10SXin LI return(FAILURE); 498db1fda10SXin LI device_printf(sc->tws_dev, "Using MSI\n"); 499db1fda10SXin LI break; 500db1fda10SXin LI 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 int error; 513db1fda10SXin LI u_int32_t reg; 514db1fda10SXin LI 515db1fda10SXin LI sc->seq_id = 0; 516db1fda10SXin LI if ( tws_queue_depth > TWS_MAX_REQS ) 517db1fda10SXin LI tws_queue_depth = TWS_MAX_REQS; 518db1fda10SXin LI if (tws_queue_depth < TWS_RESERVED_REQS+1) 519db1fda10SXin LI tws_queue_depth = TWS_RESERVED_REQS+1; 520db1fda10SXin LI sc->is64bit = (sizeof(bus_addr_t) == 8) ? true : false; 521db1fda10SXin LI max_sg_elements = (sc->is64bit && !tws_use_32bit_sgls) ? 522db1fda10SXin LI TWS_MAX_64BIT_SG_ELEMENTS : 523db1fda10SXin LI TWS_MAX_32BIT_SG_ELEMENTS; 524db1fda10SXin LI dma_mem_size = (sizeof(struct tws_command_packet) * tws_queue_depth) + 525db1fda10SXin LI (TWS_SECTOR_SIZE) ; 526b6f97155SScott Long if ( bus_dma_tag_create(bus_get_dma_tag(sc->tws_dev), /* PCI parent */ 527db1fda10SXin LI TWS_ALIGNMENT, /* alignment */ 528db1fda10SXin LI 0, /* boundary */ 529db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 530db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 531db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 532db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsize */ 533db1fda10SXin LI max_sg_elements, /* numsegs */ 534db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */ 535db1fda10SXin LI 0, /* flags */ 536db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */ 537db1fda10SXin LI &sc->parent_tag /* tag */ 538db1fda10SXin LI )) { 539db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA parent tag Create fail", max_sg_elements, 540db1fda10SXin LI sc->is64bit); 541db1fda10SXin LI return(ENOMEM); 542db1fda10SXin LI } 543db1fda10SXin LI /* In bound message frame requires 16byte alignment. 544db1fda10SXin LI * Outbound MF's can live with 4byte alignment - for now just 545db1fda10SXin LI * use 16 for both. 546db1fda10SXin LI */ 547db1fda10SXin LI if ( bus_dma_tag_create(sc->parent_tag, /* parent */ 548db1fda10SXin LI TWS_IN_MF_ALIGNMENT, /* alignment */ 549db1fda10SXin LI 0, /* boundary */ 550db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 551db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 552db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 553db1fda10SXin LI dma_mem_size, /* maxsize */ 554db1fda10SXin LI 1, /* numsegs */ 555db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */ 556db1fda10SXin LI 0, /* flags */ 557db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */ 558db1fda10SXin LI &sc->cmd_tag /* tag */ 559db1fda10SXin LI )) { 560db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 561db1fda10SXin LI return(ENOMEM); 562db1fda10SXin LI } 563db1fda10SXin LI 564db1fda10SXin LI if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem, 565db1fda10SXin LI BUS_DMA_NOWAIT, &sc->cmd_map)) { 566db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA mem alloc fail", max_sg_elements, sc->is64bit); 567db1fda10SXin LI return(ENOMEM); 568db1fda10SXin LI } 569db1fda10SXin LI 570db1fda10SXin LI /* if bus_dmamem_alloc succeeds then bus_dmamap_load will succeed */ 571db1fda10SXin LI sc->dma_mem_phys=0; 572db1fda10SXin LI error = bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem, 573db1fda10SXin LI dma_mem_size, tws_dmamap_cmds_load_cbfn, 574db1fda10SXin LI &sc->dma_mem_phys, 0); 575db1fda10SXin LI 576db1fda10SXin LI /* 577db1fda10SXin LI * Create a dma tag for data buffers; size will be the maximum 578db1fda10SXin LI * possible I/O size (128kB). 579db1fda10SXin LI */ 580db1fda10SXin LI if (bus_dma_tag_create(sc->parent_tag, /* parent */ 581db1fda10SXin LI TWS_ALIGNMENT, /* alignment */ 582db1fda10SXin LI 0, /* boundary */ 583db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 584db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 585db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 586db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsize */ 587db1fda10SXin LI max_sg_elements, /* nsegments */ 588db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsegsize */ 589db1fda10SXin LI BUS_DMA_ALLOCNOW, /* flags */ 590db1fda10SXin LI busdma_lock_mutex, /* lockfunc */ 591db1fda10SXin LI &sc->io_lock, /* lockfuncarg */ 592db1fda10SXin LI &sc->data_tag /* tag */)) { 593db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 594db1fda10SXin LI return(ENOMEM); 595db1fda10SXin LI } 596db1fda10SXin LI 597db1fda10SXin LI sc->reqs = malloc(sizeof(struct tws_request) * tws_queue_depth, M_TWS, 598db1fda10SXin LI M_WAITOK | M_ZERO); 599db1fda10SXin LI if ( sc->reqs == NULL ) { 600db1fda10SXin LI TWS_TRACE_DEBUG(sc, "malloc failed", 0, sc->is64bit); 601db1fda10SXin LI return(ENOMEM); 602db1fda10SXin LI } 603db1fda10SXin LI sc->sense_bufs = malloc(sizeof(struct tws_sense) * tws_queue_depth, M_TWS, 604db1fda10SXin LI M_WAITOK | M_ZERO); 605db1fda10SXin LI if ( sc->sense_bufs == NULL ) { 606db1fda10SXin LI TWS_TRACE_DEBUG(sc, "sense malloc failed", 0, sc->is64bit); 607db1fda10SXin LI return(ENOMEM); 608db1fda10SXin LI } 609db1fda10SXin LI sc->scan_ccb = malloc(sizeof(union ccb), M_TWS, M_WAITOK | M_ZERO); 610db1fda10SXin LI if ( sc->scan_ccb == NULL ) { 611db1fda10SXin LI TWS_TRACE_DEBUG(sc, "ccb malloc failed", 0, sc->is64bit); 612db1fda10SXin LI return(ENOMEM); 613db1fda10SXin LI } 614c5f33959SXin LI if (bus_dmamem_alloc(sc->data_tag, (void **)&sc->ioctl_data_mem, 615c5f33959SXin LI (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &sc->ioctl_data_map)) { 616c5f33959SXin LI device_printf(sc->tws_dev, "Cannot allocate ioctl data mem\n"); 617c5f33959SXin LI return(ENOMEM); 618c5f33959SXin LI } 619db1fda10SXin LI 620db1fda10SXin LI if ( !tws_ctlr_ready(sc) ) 621db1fda10SXin LI if( !tws_ctlr_reset(sc) ) 622db1fda10SXin LI return(FAILURE); 623db1fda10SXin LI 624db1fda10SXin LI bzero(&sc->stats, sizeof(struct tws_stats)); 625db1fda10SXin LI tws_init_qs(sc); 626db1fda10SXin LI tws_turn_off_interrupts(sc); 627db1fda10SXin LI 628db1fda10SXin LI /* 629db1fda10SXin LI * enable pull mode by setting bit1 . 630db1fda10SXin LI * setting bit0 to 1 will enable interrupt coalesing 631db1fda10SXin LI * will revisit. 632db1fda10SXin LI */ 633db1fda10SXin LI 634db1fda10SXin LI #ifdef TWS_PULL_MODE_ENABLE 635db1fda10SXin LI 636db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_CTL, 4); 637db1fda10SXin LI TWS_TRACE_DEBUG(sc, "i20 ctl", reg, TWS_I2O0_CTL); 638db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_CTL, reg | TWS_BIT1, 4); 639db1fda10SXin LI 640db1fda10SXin LI #endif 641db1fda10SXin LI 642db1fda10SXin LI TWS_TRACE_DEBUG(sc, "dma_mem_phys", sc->dma_mem_phys, TWS_I2O0_CTL); 643db1fda10SXin LI if ( tws_init_reqs(sc, dma_mem_size) == FAILURE ) 644db1fda10SXin LI return(FAILURE); 645db1fda10SXin LI if ( tws_init_aen_q(sc) == FAILURE ) 646db1fda10SXin LI return(FAILURE); 647db1fda10SXin LI 648db1fda10SXin LI return(SUCCESS); 649db1fda10SXin LI 650db1fda10SXin LI } 651db1fda10SXin LI 652db1fda10SXin LI static int 653db1fda10SXin LI tws_init_aen_q(struct tws_softc *sc) 654db1fda10SXin LI { 655db1fda10SXin LI sc->aen_q.head=0; 656db1fda10SXin LI sc->aen_q.tail=0; 657db1fda10SXin LI sc->aen_q.depth=256; 658db1fda10SXin LI sc->aen_q.overflow=0; 659db1fda10SXin LI sc->aen_q.q = malloc(sizeof(struct tws_event_packet)*sc->aen_q.depth, 660db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO); 661db1fda10SXin LI if ( ! sc->aen_q.q ) 662db1fda10SXin LI return(FAILURE); 663db1fda10SXin LI return(SUCCESS); 664db1fda10SXin LI } 665db1fda10SXin LI 666db1fda10SXin LI static int 667db1fda10SXin LI tws_init_trace_q(struct tws_softc *sc) 668db1fda10SXin LI { 669db1fda10SXin LI sc->trace_q.head=0; 670db1fda10SXin LI sc->trace_q.tail=0; 671db1fda10SXin LI sc->trace_q.depth=256; 672db1fda10SXin LI sc->trace_q.overflow=0; 673db1fda10SXin LI sc->trace_q.q = malloc(sizeof(struct tws_trace_rec)*sc->trace_q.depth, 674db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO); 675db1fda10SXin LI if ( ! sc->trace_q.q ) 676db1fda10SXin LI return(FAILURE); 677db1fda10SXin LI return(SUCCESS); 678db1fda10SXin LI } 679db1fda10SXin LI 680db1fda10SXin LI static int 681db1fda10SXin LI tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size) 682db1fda10SXin LI { 683db1fda10SXin LI 684db1fda10SXin LI struct tws_command_packet *cmd_buf; 685db1fda10SXin LI cmd_buf = (struct tws_command_packet *)sc->dma_mem; 686db1fda10SXin LI int i; 687db1fda10SXin LI 688db1fda10SXin LI bzero(cmd_buf, dma_mem_size); 689db1fda10SXin LI TWS_TRACE_DEBUG(sc, "phy cmd", sc->dma_mem_phys, 0); 690db1fda10SXin LI mtx_lock(&sc->q_lock); 691db1fda10SXin LI for ( i=0; i< tws_queue_depth; i++) 692db1fda10SXin LI { 693db1fda10SXin LI if (bus_dmamap_create(sc->data_tag, 0, &sc->reqs[i].dma_map)) { 694db1fda10SXin LI /* log a ENOMEM failure msg here */ 6953093cb15SXin LI mtx_unlock(&sc->q_lock); 696db1fda10SXin LI return(FAILURE); 697db1fda10SXin LI } 698db1fda10SXin LI sc->reqs[i].cmd_pkt = &cmd_buf[i]; 699db1fda10SXin LI 700db1fda10SXin LI sc->sense_bufs[i].hdr = &cmd_buf[i].hdr ; 701db1fda10SXin LI sc->sense_bufs[i].hdr_pkt_phy = sc->dma_mem_phys + 702db1fda10SXin LI (i * sizeof(struct tws_command_packet)); 703db1fda10SXin LI 704db1fda10SXin LI sc->reqs[i].cmd_pkt_phy = sc->dma_mem_phys + 705db1fda10SXin LI sizeof(struct tws_command_header) + 706db1fda10SXin LI (i * sizeof(struct tws_command_packet)); 707db1fda10SXin LI sc->reqs[i].request_id = i; 708db1fda10SXin LI sc->reqs[i].sc = sc; 709db1fda10SXin LI 710db1fda10SXin LI sc->reqs[i].cmd_pkt->hdr.header_desc.size_header = 128; 711db1fda10SXin LI 712eb8a7632SScott Long callout_handle_init(&sc->reqs[i].thandle); 713db1fda10SXin LI sc->reqs[i].state = TWS_REQ_STATE_FREE; 714db1fda10SXin LI if ( i >= TWS_RESERVED_REQS ) 715db1fda10SXin LI tws_q_insert_tail(sc, &sc->reqs[i], TWS_FREE_Q); 716db1fda10SXin LI } 717db1fda10SXin LI mtx_unlock(&sc->q_lock); 718db1fda10SXin LI return(SUCCESS); 719db1fda10SXin LI } 720db1fda10SXin LI 721db1fda10SXin LI static void 722db1fda10SXin LI tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs, 723db1fda10SXin LI int nseg, int error) 724db1fda10SXin LI { 725db1fda10SXin LI 726db1fda10SXin LI /* printf("command load done \n"); */ 727db1fda10SXin LI 728db1fda10SXin LI *((bus_addr_t *)arg) = segs[0].ds_addr; 729db1fda10SXin LI } 730db1fda10SXin LI 731db1fda10SXin LI void 732db1fda10SXin LI tws_send_event(struct tws_softc *sc, u_int8_t event) 733db1fda10SXin LI { 734db1fda10SXin LI mtx_assert(&sc->gen_lock, MA_OWNED); 735db1fda10SXin LI TWS_TRACE_DEBUG(sc, "received event ", 0, event); 736db1fda10SXin LI switch (event) { 737db1fda10SXin LI 738db1fda10SXin LI case TWS_INIT_START: 739db1fda10SXin LI sc->tws_state = TWS_INIT; 740db1fda10SXin LI break; 741db1fda10SXin LI 742db1fda10SXin LI case TWS_INIT_COMPLETE: 743db1fda10SXin LI if (sc->tws_state != TWS_INIT) { 744db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_ONLINE\n", sc->tws_state); 745db1fda10SXin LI } else { 746db1fda10SXin LI sc->tws_state = TWS_ONLINE; 747db1fda10SXin LI } 748db1fda10SXin LI break; 749db1fda10SXin LI 750db1fda10SXin LI case TWS_RESET_START: 751db1fda10SXin LI /* We can transition to reset state from any state except reset*/ 752db1fda10SXin LI if (sc->tws_state != TWS_RESET) { 753db1fda10SXin LI sc->tws_prev_state = sc->tws_state; 754db1fda10SXin LI sc->tws_state = TWS_RESET; 755db1fda10SXin LI } 756db1fda10SXin LI break; 757db1fda10SXin LI 758db1fda10SXin LI case TWS_RESET_COMPLETE: 759db1fda10SXin LI if (sc->tws_state != TWS_RESET) { 760db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => %d (previous state)\n", sc->tws_state, sc->tws_prev_state); 761db1fda10SXin LI } else { 762db1fda10SXin LI sc->tws_state = sc->tws_prev_state; 763db1fda10SXin LI } 764db1fda10SXin LI break; 765db1fda10SXin LI 766db1fda10SXin LI case TWS_SCAN_FAILURE: 767db1fda10SXin LI if (sc->tws_state != TWS_ONLINE) { 768db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_OFFLINE\n", sc->tws_state); 769db1fda10SXin LI } else { 770db1fda10SXin LI sc->tws_state = TWS_OFFLINE; 771db1fda10SXin LI } 772db1fda10SXin LI break; 773db1fda10SXin LI 774db1fda10SXin LI case TWS_UNINIT_START: 775db1fda10SXin LI if ((sc->tws_state != TWS_ONLINE) && (sc->tws_state != TWS_OFFLINE)) { 776db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_UNINIT\n", sc->tws_state); 777db1fda10SXin LI } else { 778db1fda10SXin LI sc->tws_state = TWS_UNINIT; 779db1fda10SXin LI } 780db1fda10SXin LI break; 781db1fda10SXin LI } 782db1fda10SXin LI 783db1fda10SXin LI } 784db1fda10SXin LI 785db1fda10SXin LI uint8_t 786db1fda10SXin LI tws_get_state(struct tws_softc *sc) 787db1fda10SXin LI { 788db1fda10SXin LI 789db1fda10SXin LI return((u_int8_t)sc->tws_state); 790db1fda10SXin LI 791db1fda10SXin LI } 792db1fda10SXin LI 793db1fda10SXin LI /* Called during system shutdown after sync. */ 794db1fda10SXin LI 795db1fda10SXin LI static int 796db1fda10SXin LI tws_shutdown(device_t dev) 797db1fda10SXin LI { 798db1fda10SXin LI 799db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 800db1fda10SXin LI 801db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 802db1fda10SXin LI 803db1fda10SXin LI tws_turn_off_interrupts(sc); 804db1fda10SXin LI tws_init_connect(sc, 1); 805db1fda10SXin LI 806db1fda10SXin LI return (0); 807db1fda10SXin LI } 808db1fda10SXin LI 809db1fda10SXin LI /* 810db1fda10SXin LI * Device suspend routine. 811db1fda10SXin LI */ 812db1fda10SXin LI static int 813db1fda10SXin LI tws_suspend(device_t dev) 814db1fda10SXin LI { 815db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 816db1fda10SXin LI 817db1fda10SXin LI if ( sc ) 818db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 819db1fda10SXin LI return (0); 820db1fda10SXin LI } 821db1fda10SXin LI 822db1fda10SXin LI /* 823db1fda10SXin LI * Device resume routine. 824db1fda10SXin LI */ 825db1fda10SXin LI static int 826db1fda10SXin LI tws_resume(device_t dev) 827db1fda10SXin LI { 828db1fda10SXin LI 829db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 830db1fda10SXin LI 831db1fda10SXin LI if ( sc ) 832db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 833db1fda10SXin LI return (0); 834db1fda10SXin LI } 835db1fda10SXin LI 836db1fda10SXin LI 837db1fda10SXin LI struct tws_request * 838db1fda10SXin LI tws_get_request(struct tws_softc *sc, u_int16_t type) 839db1fda10SXin LI { 840db1fda10SXin LI struct mtx *my_mutex = ((type == TWS_REQ_TYPE_SCSI_IO) ? &sc->q_lock : &sc->gen_lock); 841db1fda10SXin LI struct tws_request *r = NULL; 842db1fda10SXin LI 843db1fda10SXin LI mtx_lock(my_mutex); 844db1fda10SXin LI 845db1fda10SXin LI if (type == TWS_REQ_TYPE_SCSI_IO) { 846db1fda10SXin LI r = tws_q_remove_head(sc, TWS_FREE_Q); 847db1fda10SXin LI } else { 848db1fda10SXin LI if ( sc->reqs[type].state == TWS_REQ_STATE_FREE ) { 849db1fda10SXin LI r = &sc->reqs[type]; 850db1fda10SXin LI } 851db1fda10SXin LI } 852db1fda10SXin LI 853db1fda10SXin LI if ( r ) { 854db1fda10SXin LI bzero(&r->cmd_pkt->cmd, sizeof(struct tws_command_apache)); 855db1fda10SXin LI r->data = NULL; 856db1fda10SXin LI r->length = 0; 857db1fda10SXin LI r->type = type; 858db1fda10SXin LI r->flags = TWS_DIR_UNKNOWN; 859db1fda10SXin LI r->error_code = TWS_REQ_RET_INVALID; 860db1fda10SXin LI r->cb = NULL; 861db1fda10SXin LI r->ccb_ptr = NULL; 862db1fda10SXin LI r->thandle.callout = NULL; 863db1fda10SXin LI r->next = r->prev = NULL; 864db1fda10SXin LI 865db1fda10SXin LI r->state = ((type == TWS_REQ_TYPE_SCSI_IO) ? TWS_REQ_STATE_TRAN : TWS_REQ_STATE_BUSY); 866db1fda10SXin LI } 867db1fda10SXin LI 868db1fda10SXin LI mtx_unlock(my_mutex); 869db1fda10SXin LI 870db1fda10SXin LI return(r); 871db1fda10SXin LI } 872db1fda10SXin LI 873db1fda10SXin LI void 874db1fda10SXin LI tws_release_request(struct tws_request *req) 875db1fda10SXin LI { 876db1fda10SXin LI 877db1fda10SXin LI struct tws_softc *sc = req->sc; 878db1fda10SXin LI 879db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", sc, 0); 880db1fda10SXin LI mtx_lock(&sc->q_lock); 881db1fda10SXin LI tws_q_insert_tail(sc, req, TWS_FREE_Q); 882db1fda10SXin LI mtx_unlock(&sc->q_lock); 883db1fda10SXin LI } 884db1fda10SXin LI 885db1fda10SXin LI static device_method_t tws_methods[] = { 886db1fda10SXin LI /* Device interface */ 887db1fda10SXin LI DEVMETHOD(device_probe, tws_probe), 888db1fda10SXin LI DEVMETHOD(device_attach, tws_attach), 889db1fda10SXin LI DEVMETHOD(device_detach, tws_detach), 890db1fda10SXin LI DEVMETHOD(device_shutdown, tws_shutdown), 891db1fda10SXin LI DEVMETHOD(device_suspend, tws_suspend), 892db1fda10SXin LI DEVMETHOD(device_resume, tws_resume), 893db1fda10SXin LI 8944b7ec270SMarius Strobl DEVMETHOD_END 895db1fda10SXin LI }; 896db1fda10SXin LI 897db1fda10SXin LI static driver_t tws_driver = { 898db1fda10SXin LI "tws", 899db1fda10SXin LI tws_methods, 900db1fda10SXin LI sizeof(struct tws_softc) 901db1fda10SXin LI }; 902db1fda10SXin LI 903db1fda10SXin LI 904db1fda10SXin LI static devclass_t tws_devclass; 905db1fda10SXin LI 906db1fda10SXin LI /* DEFINE_CLASS_0(tws, tws_driver, tws_methods, sizeof(struct tws_softc)); */ 907db1fda10SXin LI DRIVER_MODULE(tws, pci, tws_driver, tws_devclass, 0, 0); 908db1fda10SXin LI MODULE_DEPEND(tws, cam, 1, 1, 1); 909db1fda10SXin LI MODULE_DEPEND(tws, pci, 1, 1, 1); 910db1fda10SXin LI 911db1fda10SXin LI TUNABLE_INT("hw.tws.queue_depth", &tws_queue_depth); 912db1fda10SXin LI TUNABLE_INT("hw.tws.enable_msi", &tws_enable_msi); 913