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); 186db1fda10SXin LI u_int32_t cmd, 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); 200db1fda10SXin LI mtx_init( &sc->io_lock, "tws_io_lock", NULL, MTX_DEF); 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 227db1fda10SXin LI cmd = pci_read_config(dev, PCIR_COMMAND, 2); 228db1fda10SXin LI if ( (cmd & PCIM_CMD_PORTEN) == 0) { 229db1fda10SXin LI tws_log(sc, PCI_COMMAND_READ); 230db1fda10SXin LI goto attach_fail_1; 231db1fda10SXin LI } 232db1fda10SXin LI /* Force the busmaster enable bit on. */ 233db1fda10SXin LI cmd |= PCIM_CMD_BUSMASTEREN; 234db1fda10SXin LI pci_write_config(dev, PCIR_COMMAND, cmd, 2); 235db1fda10SXin LI 236db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR0, 4); 237db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar0 ", bar, 0); 238db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR1, 4); 239db1fda10SXin LI bar = bar & ~TWS_BIT2; 240db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar1 ", bar, 0); 241db1fda10SXin LI 242db1fda10SXin LI /* MFA base address is BAR2 register used for 243db1fda10SXin LI * push mode. Firmware will evatualy move to 244db1fda10SXin LI * pull mode during witch this needs to change 245db1fda10SXin LI */ 246db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 247db1fda10SXin LI sc->mfa_base = (u_int64_t)pci_read_config(dev, TWS_PCI_BAR2, 4); 248db1fda10SXin LI sc->mfa_base = sc->mfa_base & ~TWS_BIT2; 249db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar2 ", sc->mfa_base, 0); 250db1fda10SXin LI #endif 251db1fda10SXin LI 252db1fda10SXin LI /* allocate MMIO register space */ 253db1fda10SXin LI sc->reg_res_id = TWS_PCI_BAR1; /* BAR1 offset */ 254db1fda10SXin LI if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 255db1fda10SXin LI &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE)) 256db1fda10SXin LI == NULL) { 257db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 258db1fda10SXin LI goto attach_fail_1; 259db1fda10SXin LI } 260db1fda10SXin LI sc->bus_tag = rman_get_bustag(sc->reg_res); 261db1fda10SXin LI sc->bus_handle = rman_get_bushandle(sc->reg_res); 262db1fda10SXin LI 263db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE 264db1fda10SXin LI /* Allocate bus space for inbound mfa */ 265db1fda10SXin LI sc->mfa_res_id = TWS_PCI_BAR2; /* BAR2 offset */ 266db1fda10SXin LI if ((sc->mfa_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 267db1fda10SXin LI &(sc->mfa_res_id), 0, ~0, 0x100000, RF_ACTIVE)) 268db1fda10SXin LI == NULL) { 269db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 270db1fda10SXin LI goto attach_fail_2; 271db1fda10SXin LI } 272db1fda10SXin LI sc->bus_mfa_tag = rman_get_bustag(sc->mfa_res); 273db1fda10SXin LI sc->bus_mfa_handle = rman_get_bushandle(sc->mfa_res); 274db1fda10SXin LI #endif 275db1fda10SXin LI 276db1fda10SXin LI /* Allocate and register our interrupt. */ 277db1fda10SXin LI sc->intr_type = TWS_INTx; /* default */ 278db1fda10SXin LI 279db1fda10SXin LI if ( tws_enable_msi ) 280db1fda10SXin LI sc->intr_type = TWS_MSI; 281db1fda10SXin LI if ( tws_setup_irq(sc) == FAILURE ) { 282db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES); 283db1fda10SXin LI goto attach_fail_3; 284db1fda10SXin LI } 285db1fda10SXin LI 286db1fda10SXin LI /* 287db1fda10SXin LI * Create a /dev entry for this device. The kernel will assign us 288db1fda10SXin LI * a major number automatically. We use the unit number of this 289db1fda10SXin LI * device as the minor number and name the character device 290db1fda10SXin LI * "tws<unit>". 291db1fda10SXin LI */ 292db1fda10SXin LI sc->tws_cdev = make_dev(&tws_cdevsw, device_get_unit(dev), 293db1fda10SXin LI UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "tws%u", 294db1fda10SXin LI device_get_unit(dev)); 295db1fda10SXin LI sc->tws_cdev->si_drv1 = sc; 296db1fda10SXin LI 297db1fda10SXin LI if ( tws_init(sc) == FAILURE ) { 298db1fda10SXin LI tws_log(sc, TWS_INIT_FAILURE); 299db1fda10SXin LI goto attach_fail_4; 300db1fda10SXin LI } 301db1fda10SXin LI if ( tws_init_ctlr(sc) == FAILURE ) { 302db1fda10SXin LI tws_log(sc, TWS_CTLR_INIT_FAILURE); 303db1fda10SXin LI goto attach_fail_4; 304db1fda10SXin LI } 305db1fda10SXin LI if ((error = tws_cam_attach(sc))) { 306db1fda10SXin LI tws_log(sc, TWS_CAM_ATTACH); 307db1fda10SXin LI goto attach_fail_4; 308db1fda10SXin LI } 309db1fda10SXin LI /* send init complete event */ 310db1fda10SXin LI mtx_lock(&sc->gen_lock); 311db1fda10SXin LI tws_send_event(sc, TWS_INIT_COMPLETE); 312db1fda10SXin LI mtx_unlock(&sc->gen_lock); 313db1fda10SXin LI 314db1fda10SXin LI TWS_TRACE_DEBUG(sc, "attached successfully", 0, sc->device_id); 315db1fda10SXin LI return(0); 316db1fda10SXin LI 317db1fda10SXin LI attach_fail_4: 318db1fda10SXin LI tws_teardown_intr(sc); 319db1fda10SXin LI destroy_dev(sc->tws_cdev); 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 393db1fda10SXin LI /* Release memory resource */ 394db1fda10SXin LI if ( sc->mfa_res ){ 395db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 396db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 397db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->mfa_res_id); 398db1fda10SXin LI } 399db1fda10SXin LI if ( sc->reg_res ){ 400db1fda10SXin LI if (bus_release_resource(sc->tws_dev, 401db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 402db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->reg_res_id); 403db1fda10SXin LI } 404db1fda10SXin LI 405db1fda10SXin LI free(sc->reqs, M_TWS); 406db1fda10SXin LI free(sc->sense_bufs, M_TWS); 407db1fda10SXin LI free(sc->scan_ccb, M_TWS); 408db1fda10SXin LI free(sc->aen_q.q, M_TWS); 409db1fda10SXin LI free(sc->trace_q.q, M_TWS); 410db1fda10SXin LI mtx_destroy(&sc->q_lock); 411db1fda10SXin LI mtx_destroy(&sc->sim_lock); 412db1fda10SXin LI mtx_destroy(&sc->gen_lock); 413db1fda10SXin LI mtx_destroy(&sc->io_lock); 414db1fda10SXin LI destroy_dev(sc->tws_cdev); 415db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist); 416db1fda10SXin LI return (0); 417db1fda10SXin LI } 418db1fda10SXin LI 419db1fda10SXin LI int 420db1fda10SXin LI tws_setup_intr(struct tws_softc *sc, int irqs) 421db1fda10SXin LI { 422db1fda10SXin LI int i, error; 423db1fda10SXin LI 424db1fda10SXin LI for(i=0;i<irqs;i++) { 425db1fda10SXin LI if (!(sc->intr_handle[i])) { 426db1fda10SXin LI if ((error = bus_setup_intr(sc->tws_dev, sc->irq_res[i], 427db1fda10SXin LI INTR_TYPE_CAM | INTR_MPSAFE, 428db1fda10SXin LI #if (__FreeBSD_version >= 700000) 429db1fda10SXin LI NULL, 430db1fda10SXin LI #endif 431db1fda10SXin LI tws_intr, sc, &sc->intr_handle[i]))) { 432db1fda10SXin LI tws_log(sc, SETUP_INTR_RES); 433db1fda10SXin LI return(FAILURE); 434db1fda10SXin LI } 435db1fda10SXin LI } 436db1fda10SXin LI } 437db1fda10SXin LI return(SUCCESS); 438db1fda10SXin LI 439db1fda10SXin LI } 440db1fda10SXin LI 441db1fda10SXin LI 442db1fda10SXin LI int 443db1fda10SXin LI tws_teardown_intr(struct tws_softc *sc) 444db1fda10SXin LI { 445db1fda10SXin LI int i, error; 446db1fda10SXin LI 447db1fda10SXin LI for(i=0;i<sc->irqs;i++) { 448db1fda10SXin LI if (sc->intr_handle[i]) { 449db1fda10SXin LI error = bus_teardown_intr(sc->tws_dev, 450db1fda10SXin LI sc->irq_res[i], sc->intr_handle[i]); 451db1fda10SXin LI sc->intr_handle[i] = NULL; 452db1fda10SXin LI } 453db1fda10SXin LI } 454db1fda10SXin LI return(SUCCESS); 455db1fda10SXin LI } 456db1fda10SXin LI 457db1fda10SXin LI 458db1fda10SXin LI static int 459db1fda10SXin LI tws_setup_irq(struct tws_softc *sc) 460db1fda10SXin LI { 461db1fda10SXin LI int messages; 462db1fda10SXin LI u_int16_t cmd; 463db1fda10SXin LI 464db1fda10SXin LI cmd = pci_read_config(sc->tws_dev, PCIR_COMMAND, 2); 465db1fda10SXin LI switch(sc->intr_type) { 466db1fda10SXin LI case TWS_INTx : 467db1fda10SXin LI cmd = cmd & ~0x0400; 468db1fda10SXin LI pci_write_config(sc->tws_dev, PCIR_COMMAND, cmd, 2); 469db1fda10SXin LI sc->irqs = 1; 470db1fda10SXin LI sc->irq_res_id[0] = 0; 471db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 472db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 473db1fda10SXin LI if ( ! sc->irq_res[0] ) 474db1fda10SXin LI return(FAILURE); 475db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 476db1fda10SXin LI return(FAILURE); 477db1fda10SXin LI device_printf(sc->tws_dev, "Using legacy INTx\n"); 478db1fda10SXin LI break; 479db1fda10SXin LI case TWS_MSI : 480db1fda10SXin LI cmd = cmd | 0x0400; 481db1fda10SXin LI pci_write_config(sc->tws_dev, PCIR_COMMAND, cmd, 2); 482db1fda10SXin LI sc->irqs = 1; 483db1fda10SXin LI sc->irq_res_id[0] = 1; 484db1fda10SXin LI messages = 1; 485db1fda10SXin LI if (pci_alloc_msi(sc->tws_dev, &messages) != 0 ) { 486db1fda10SXin LI TWS_TRACE(sc, "pci alloc msi fail", 0, messages); 487db1fda10SXin LI return(FAILURE); 488db1fda10SXin LI } 489db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 490db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 491db1fda10SXin LI 492db1fda10SXin LI if ( !sc->irq_res[0] ) 493db1fda10SXin LI return(FAILURE); 494db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 495db1fda10SXin LI return(FAILURE); 496db1fda10SXin LI device_printf(sc->tws_dev, "Using MSI\n"); 497db1fda10SXin LI break; 498db1fda10SXin LI 499db1fda10SXin LI } 500db1fda10SXin LI 501db1fda10SXin LI return(SUCCESS); 502db1fda10SXin LI } 503db1fda10SXin LI 504db1fda10SXin LI static int 505db1fda10SXin LI tws_init(struct tws_softc *sc) 506db1fda10SXin LI { 507db1fda10SXin LI 508db1fda10SXin LI u_int32_t max_sg_elements; 509db1fda10SXin LI u_int32_t dma_mem_size; 510db1fda10SXin LI int error; 511db1fda10SXin LI u_int32_t reg; 512db1fda10SXin LI 513db1fda10SXin LI sc->seq_id = 0; 514db1fda10SXin LI if ( tws_queue_depth > TWS_MAX_REQS ) 515db1fda10SXin LI tws_queue_depth = TWS_MAX_REQS; 516db1fda10SXin LI if (tws_queue_depth < TWS_RESERVED_REQS+1) 517db1fda10SXin LI tws_queue_depth = TWS_RESERVED_REQS+1; 518db1fda10SXin LI sc->is64bit = (sizeof(bus_addr_t) == 8) ? true : false; 519db1fda10SXin LI max_sg_elements = (sc->is64bit && !tws_use_32bit_sgls) ? 520db1fda10SXin LI TWS_MAX_64BIT_SG_ELEMENTS : 521db1fda10SXin LI TWS_MAX_32BIT_SG_ELEMENTS; 522db1fda10SXin LI dma_mem_size = (sizeof(struct tws_command_packet) * tws_queue_depth) + 523db1fda10SXin LI (TWS_SECTOR_SIZE) ; 524db1fda10SXin LI if ( bus_dma_tag_create(NULL, /* parent */ 525db1fda10SXin LI TWS_ALIGNMENT, /* alignment */ 526db1fda10SXin LI 0, /* boundary */ 527db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 528db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 529db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 530db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsize */ 531db1fda10SXin LI max_sg_elements, /* numsegs */ 532db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */ 533db1fda10SXin LI 0, /* flags */ 534db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */ 535db1fda10SXin LI &sc->parent_tag /* tag */ 536db1fda10SXin LI )) { 537db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA parent tag Create fail", max_sg_elements, 538db1fda10SXin LI sc->is64bit); 539db1fda10SXin LI return(ENOMEM); 540db1fda10SXin LI } 541db1fda10SXin LI /* In bound message frame requires 16byte alignment. 542db1fda10SXin LI * Outbound MF's can live with 4byte alignment - for now just 543db1fda10SXin LI * use 16 for both. 544db1fda10SXin LI */ 545db1fda10SXin LI if ( bus_dma_tag_create(sc->parent_tag, /* parent */ 546db1fda10SXin LI TWS_IN_MF_ALIGNMENT, /* alignment */ 547db1fda10SXin LI 0, /* boundary */ 548db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 549db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 550db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 551db1fda10SXin LI dma_mem_size, /* maxsize */ 552db1fda10SXin LI 1, /* numsegs */ 553db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */ 554db1fda10SXin LI 0, /* flags */ 555db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */ 556db1fda10SXin LI &sc->cmd_tag /* tag */ 557db1fda10SXin LI )) { 558db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 559db1fda10SXin LI return(ENOMEM); 560db1fda10SXin LI } 561db1fda10SXin LI 562db1fda10SXin LI if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem, 563db1fda10SXin LI BUS_DMA_NOWAIT, &sc->cmd_map)) { 564db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA mem alloc fail", max_sg_elements, sc->is64bit); 565db1fda10SXin LI return(ENOMEM); 566db1fda10SXin LI } 567db1fda10SXin LI 568db1fda10SXin LI /* if bus_dmamem_alloc succeeds then bus_dmamap_load will succeed */ 569db1fda10SXin LI sc->dma_mem_phys=0; 570db1fda10SXin LI error = bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem, 571db1fda10SXin LI dma_mem_size, tws_dmamap_cmds_load_cbfn, 572db1fda10SXin LI &sc->dma_mem_phys, 0); 573db1fda10SXin LI 574db1fda10SXin LI /* 575db1fda10SXin LI * Create a dma tag for data buffers; size will be the maximum 576db1fda10SXin LI * possible I/O size (128kB). 577db1fda10SXin LI */ 578db1fda10SXin LI if (bus_dma_tag_create(sc->parent_tag, /* parent */ 579db1fda10SXin LI TWS_ALIGNMENT, /* alignment */ 580db1fda10SXin LI 0, /* boundary */ 581db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 582db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */ 583db1fda10SXin LI NULL, NULL, /* filter, filterarg */ 584db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsize */ 585db1fda10SXin LI max_sg_elements, /* nsegments */ 586db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsegsize */ 587db1fda10SXin LI BUS_DMA_ALLOCNOW, /* flags */ 588db1fda10SXin LI busdma_lock_mutex, /* lockfunc */ 589db1fda10SXin LI &sc->io_lock, /* lockfuncarg */ 590db1fda10SXin LI &sc->data_tag /* tag */)) { 591db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 592db1fda10SXin LI return(ENOMEM); 593db1fda10SXin LI } 594db1fda10SXin LI 595db1fda10SXin LI sc->reqs = malloc(sizeof(struct tws_request) * tws_queue_depth, M_TWS, 596db1fda10SXin LI M_WAITOK | M_ZERO); 597db1fda10SXin LI if ( sc->reqs == NULL ) { 598db1fda10SXin LI TWS_TRACE_DEBUG(sc, "malloc failed", 0, sc->is64bit); 599db1fda10SXin LI return(ENOMEM); 600db1fda10SXin LI } 601db1fda10SXin LI sc->sense_bufs = malloc(sizeof(struct tws_sense) * tws_queue_depth, M_TWS, 602db1fda10SXin LI M_WAITOK | M_ZERO); 603db1fda10SXin LI if ( sc->sense_bufs == NULL ) { 604db1fda10SXin LI TWS_TRACE_DEBUG(sc, "sense malloc failed", 0, sc->is64bit); 605db1fda10SXin LI return(ENOMEM); 606db1fda10SXin LI } 607db1fda10SXin LI sc->scan_ccb = malloc(sizeof(union ccb), M_TWS, M_WAITOK | M_ZERO); 608db1fda10SXin LI if ( sc->scan_ccb == NULL ) { 609db1fda10SXin LI TWS_TRACE_DEBUG(sc, "ccb malloc failed", 0, sc->is64bit); 610db1fda10SXin LI return(ENOMEM); 611db1fda10SXin LI } 612db1fda10SXin LI 613db1fda10SXin LI if ( !tws_ctlr_ready(sc) ) 614db1fda10SXin LI if( !tws_ctlr_reset(sc) ) 615db1fda10SXin LI return(FAILURE); 616db1fda10SXin LI 617db1fda10SXin LI bzero(&sc->stats, sizeof(struct tws_stats)); 618db1fda10SXin LI tws_init_qs(sc); 619db1fda10SXin LI tws_turn_off_interrupts(sc); 620db1fda10SXin LI 621db1fda10SXin LI /* 622db1fda10SXin LI * enable pull mode by setting bit1 . 623db1fda10SXin LI * setting bit0 to 1 will enable interrupt coalesing 624db1fda10SXin LI * will revisit. 625db1fda10SXin LI */ 626db1fda10SXin LI 627db1fda10SXin LI #ifdef TWS_PULL_MODE_ENABLE 628db1fda10SXin LI 629db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_CTL, 4); 630db1fda10SXin LI TWS_TRACE_DEBUG(sc, "i20 ctl", reg, TWS_I2O0_CTL); 631db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_CTL, reg | TWS_BIT1, 4); 632db1fda10SXin LI 633db1fda10SXin LI #endif 634db1fda10SXin LI 635db1fda10SXin LI TWS_TRACE_DEBUG(sc, "dma_mem_phys", sc->dma_mem_phys, TWS_I2O0_CTL); 636db1fda10SXin LI if ( tws_init_reqs(sc, dma_mem_size) == FAILURE ) 637db1fda10SXin LI return(FAILURE); 638db1fda10SXin LI if ( tws_init_aen_q(sc) == FAILURE ) 639db1fda10SXin LI return(FAILURE); 640db1fda10SXin LI 641db1fda10SXin LI return(SUCCESS); 642db1fda10SXin LI 643db1fda10SXin LI } 644db1fda10SXin LI 645db1fda10SXin LI static int 646db1fda10SXin LI tws_init_aen_q(struct tws_softc *sc) 647db1fda10SXin LI { 648db1fda10SXin LI sc->aen_q.head=0; 649db1fda10SXin LI sc->aen_q.tail=0; 650db1fda10SXin LI sc->aen_q.depth=256; 651db1fda10SXin LI sc->aen_q.overflow=0; 652db1fda10SXin LI sc->aen_q.q = malloc(sizeof(struct tws_event_packet)*sc->aen_q.depth, 653db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO); 654db1fda10SXin LI if ( ! sc->aen_q.q ) 655db1fda10SXin LI return(FAILURE); 656db1fda10SXin LI return(SUCCESS); 657db1fda10SXin LI } 658db1fda10SXin LI 659db1fda10SXin LI static int 660db1fda10SXin LI tws_init_trace_q(struct tws_softc *sc) 661db1fda10SXin LI { 662db1fda10SXin LI sc->trace_q.head=0; 663db1fda10SXin LI sc->trace_q.tail=0; 664db1fda10SXin LI sc->trace_q.depth=256; 665db1fda10SXin LI sc->trace_q.overflow=0; 666db1fda10SXin LI sc->trace_q.q = malloc(sizeof(struct tws_trace_rec)*sc->trace_q.depth, 667db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO); 668db1fda10SXin LI if ( ! sc->trace_q.q ) 669db1fda10SXin LI return(FAILURE); 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 */ 688*3093cb15SXin 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 705db1fda10SXin LI sc->reqs[i].state = TWS_REQ_STATE_FREE; 706db1fda10SXin LI if ( i >= TWS_RESERVED_REQS ) 707db1fda10SXin LI tws_q_insert_tail(sc, &sc->reqs[i], TWS_FREE_Q); 708db1fda10SXin LI } 709db1fda10SXin LI mtx_unlock(&sc->q_lock); 710db1fda10SXin LI return(SUCCESS); 711db1fda10SXin LI } 712db1fda10SXin LI 713db1fda10SXin LI static void 714db1fda10SXin LI tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs, 715db1fda10SXin LI int nseg, int error) 716db1fda10SXin LI { 717db1fda10SXin LI 718db1fda10SXin LI /* printf("command load done \n"); */ 719db1fda10SXin LI 720db1fda10SXin LI *((bus_addr_t *)arg) = segs[0].ds_addr; 721db1fda10SXin LI } 722db1fda10SXin LI 723db1fda10SXin LI void 724db1fda10SXin LI tws_send_event(struct tws_softc *sc, u_int8_t event) 725db1fda10SXin LI { 726db1fda10SXin LI mtx_assert(&sc->gen_lock, MA_OWNED); 727db1fda10SXin LI TWS_TRACE_DEBUG(sc, "received event ", 0, event); 728db1fda10SXin LI switch (event) { 729db1fda10SXin LI 730db1fda10SXin LI case TWS_INIT_START: 731db1fda10SXin LI sc->tws_state = TWS_INIT; 732db1fda10SXin LI break; 733db1fda10SXin LI 734db1fda10SXin LI case TWS_INIT_COMPLETE: 735db1fda10SXin LI if (sc->tws_state != TWS_INIT) { 736db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_ONLINE\n", sc->tws_state); 737db1fda10SXin LI } else { 738db1fda10SXin LI sc->tws_state = TWS_ONLINE; 739db1fda10SXin LI } 740db1fda10SXin LI break; 741db1fda10SXin LI 742db1fda10SXin LI case TWS_RESET_START: 743db1fda10SXin LI /* We can transition to reset state from any state except reset*/ 744db1fda10SXin LI if (sc->tws_state != TWS_RESET) { 745db1fda10SXin LI sc->tws_prev_state = sc->tws_state; 746db1fda10SXin LI sc->tws_state = TWS_RESET; 747db1fda10SXin LI } 748db1fda10SXin LI break; 749db1fda10SXin LI 750db1fda10SXin LI case TWS_RESET_COMPLETE: 751db1fda10SXin LI if (sc->tws_state != TWS_RESET) { 752db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => %d (previous state)\n", sc->tws_state, sc->tws_prev_state); 753db1fda10SXin LI } else { 754db1fda10SXin LI sc->tws_state = sc->tws_prev_state; 755db1fda10SXin LI } 756db1fda10SXin LI break; 757db1fda10SXin LI 758db1fda10SXin LI case TWS_SCAN_FAILURE: 759db1fda10SXin LI if (sc->tws_state != TWS_ONLINE) { 760db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_OFFLINE\n", sc->tws_state); 761db1fda10SXin LI } else { 762db1fda10SXin LI sc->tws_state = TWS_OFFLINE; 763db1fda10SXin LI } 764db1fda10SXin LI break; 765db1fda10SXin LI 766db1fda10SXin LI case TWS_UNINIT_START: 767db1fda10SXin LI if ((sc->tws_state != TWS_ONLINE) && (sc->tws_state != TWS_OFFLINE)) { 768db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_UNINIT\n", sc->tws_state); 769db1fda10SXin LI } else { 770db1fda10SXin LI sc->tws_state = TWS_UNINIT; 771db1fda10SXin LI } 772db1fda10SXin LI break; 773db1fda10SXin LI } 774db1fda10SXin LI 775db1fda10SXin LI } 776db1fda10SXin LI 777db1fda10SXin LI uint8_t 778db1fda10SXin LI tws_get_state(struct tws_softc *sc) 779db1fda10SXin LI { 780db1fda10SXin LI 781db1fda10SXin LI return((u_int8_t)sc->tws_state); 782db1fda10SXin LI 783db1fda10SXin LI } 784db1fda10SXin LI 785db1fda10SXin LI /* Called during system shutdown after sync. */ 786db1fda10SXin LI 787db1fda10SXin LI static int 788db1fda10SXin LI tws_shutdown(device_t dev) 789db1fda10SXin LI { 790db1fda10SXin LI 791db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 792db1fda10SXin LI 793db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 794db1fda10SXin LI 795db1fda10SXin LI tws_turn_off_interrupts(sc); 796db1fda10SXin LI tws_init_connect(sc, 1); 797db1fda10SXin LI 798db1fda10SXin LI return (0); 799db1fda10SXin LI } 800db1fda10SXin LI 801db1fda10SXin LI /* 802db1fda10SXin LI * Device suspend routine. 803db1fda10SXin LI */ 804db1fda10SXin LI static int 805db1fda10SXin LI tws_suspend(device_t dev) 806db1fda10SXin LI { 807db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 808db1fda10SXin LI 809db1fda10SXin LI if ( sc ) 810db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 811db1fda10SXin LI return (0); 812db1fda10SXin LI } 813db1fda10SXin LI 814db1fda10SXin LI /* 815db1fda10SXin LI * Device resume routine. 816db1fda10SXin LI */ 817db1fda10SXin LI static int 818db1fda10SXin LI tws_resume(device_t dev) 819db1fda10SXin LI { 820db1fda10SXin LI 821db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev); 822db1fda10SXin LI 823db1fda10SXin LI if ( sc ) 824db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0); 825db1fda10SXin LI return (0); 826db1fda10SXin LI } 827db1fda10SXin LI 828db1fda10SXin LI 829db1fda10SXin LI struct tws_request * 830db1fda10SXin LI tws_get_request(struct tws_softc *sc, u_int16_t type) 831db1fda10SXin LI { 832db1fda10SXin LI struct mtx *my_mutex = ((type == TWS_REQ_TYPE_SCSI_IO) ? &sc->q_lock : &sc->gen_lock); 833db1fda10SXin LI struct tws_request *r = NULL; 834db1fda10SXin LI 835db1fda10SXin LI mtx_lock(my_mutex); 836db1fda10SXin LI 837db1fda10SXin LI if (type == TWS_REQ_TYPE_SCSI_IO) { 838db1fda10SXin LI r = tws_q_remove_head(sc, TWS_FREE_Q); 839db1fda10SXin LI } else { 840db1fda10SXin LI if ( sc->reqs[type].state == TWS_REQ_STATE_FREE ) { 841db1fda10SXin LI r = &sc->reqs[type]; 842db1fda10SXin LI } 843db1fda10SXin LI } 844db1fda10SXin LI 845db1fda10SXin LI if ( r ) { 846db1fda10SXin LI bzero(&r->cmd_pkt->cmd, sizeof(struct tws_command_apache)); 847db1fda10SXin LI r->data = NULL; 848db1fda10SXin LI r->length = 0; 849db1fda10SXin LI r->type = type; 850db1fda10SXin LI r->flags = TWS_DIR_UNKNOWN; 851db1fda10SXin LI r->error_code = TWS_REQ_RET_INVALID; 852db1fda10SXin LI r->cb = NULL; 853db1fda10SXin LI r->ccb_ptr = NULL; 854db1fda10SXin LI r->thandle.callout = NULL; 855db1fda10SXin LI r->next = r->prev = NULL; 856db1fda10SXin LI 857db1fda10SXin LI r->state = ((type == TWS_REQ_TYPE_SCSI_IO) ? TWS_REQ_STATE_TRAN : TWS_REQ_STATE_BUSY); 858db1fda10SXin LI } 859db1fda10SXin LI 860db1fda10SXin LI mtx_unlock(my_mutex); 861db1fda10SXin LI 862db1fda10SXin LI return(r); 863db1fda10SXin LI } 864db1fda10SXin LI 865db1fda10SXin LI void 866db1fda10SXin LI tws_release_request(struct tws_request *req) 867db1fda10SXin LI { 868db1fda10SXin LI 869db1fda10SXin LI struct tws_softc *sc = req->sc; 870db1fda10SXin LI 871db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", sc, 0); 872db1fda10SXin LI mtx_lock(&sc->q_lock); 873db1fda10SXin LI tws_q_insert_tail(sc, req, TWS_FREE_Q); 874db1fda10SXin LI mtx_unlock(&sc->q_lock); 875db1fda10SXin LI } 876db1fda10SXin LI 877db1fda10SXin LI static device_method_t tws_methods[] = { 878db1fda10SXin LI /* Device interface */ 879db1fda10SXin LI DEVMETHOD(device_probe, tws_probe), 880db1fda10SXin LI DEVMETHOD(device_attach, tws_attach), 881db1fda10SXin LI DEVMETHOD(device_detach, tws_detach), 882db1fda10SXin LI DEVMETHOD(device_shutdown, tws_shutdown), 883db1fda10SXin LI DEVMETHOD(device_suspend, tws_suspend), 884db1fda10SXin LI DEVMETHOD(device_resume, tws_resume), 885db1fda10SXin LI 8864b7ec270SMarius Strobl DEVMETHOD_END 887db1fda10SXin LI }; 888db1fda10SXin LI 889db1fda10SXin LI static driver_t tws_driver = { 890db1fda10SXin LI "tws", 891db1fda10SXin LI tws_methods, 892db1fda10SXin LI sizeof(struct tws_softc) 893db1fda10SXin LI }; 894db1fda10SXin LI 895db1fda10SXin LI 896db1fda10SXin LI static devclass_t tws_devclass; 897db1fda10SXin LI 898db1fda10SXin LI /* DEFINE_CLASS_0(tws, tws_driver, tws_methods, sizeof(struct tws_softc)); */ 899db1fda10SXin LI DRIVER_MODULE(tws, pci, tws_driver, tws_devclass, 0, 0); 900db1fda10SXin LI MODULE_DEPEND(tws, cam, 1, 1, 1); 901db1fda10SXin LI MODULE_DEPEND(tws, pci, 1, 1, 1); 902db1fda10SXin LI 903db1fda10SXin LI TUNABLE_INT("hw.tws.queue_depth", &tws_queue_depth); 904db1fda10SXin LI TUNABLE_INT("hw.tws.enable_msi", &tws_enable_msi); 905