1130391Sle/* 2130391Sle * Copyright (c) 2010, LSI Corp. 3130391Sle * All rights reserved. 4130391Sle * Author : Manjunath Ranganathaiah 5130391Sle * Support: freebsdraid@lsi.com 6130391Sle * 7130391Sle * Redistribution and use in source and binary forms, with or without 8130391Sle * modification, are permitted provided that the following conditions 9130391Sle * are met: 10130391Sle * 11130391Sle * 1. Redistributions of source code must retain the above copyright 12130391Sle * notice, this list of conditions and the following disclaimer. 13130391Sle * 2. Redistributions in binary form must reproduce the above copyright 14130391Sle * notice, this list of conditions and the following disclaimer in 15130391Sle * the documentation and/or other materials provided with the 16130391Sle * distribution. 17130391Sle * 3. Neither the name of the <ORGANIZATION> nor the names of its 18130391Sle * contributors may be used to endorse or promote products derived 19130391Sle * from this software without specific prior written permission. 20130391Sle * 21130391Sle * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22130391Sle * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23130391Sle * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24130391Sle * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25130391Sle * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26130391Sle * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27130391Sle * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28130391Sle * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29130391Sle * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30130391Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31130391Sle * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32130391Sle * POSSIBILITY OF SUCH DAMAGE. 33130391Sle */ 34130391Sle 35130391Sle#include <sys/cdefs.h> 36130391Sle__FBSDID("$FreeBSD$"); 37130391Sle 38130391Sle#include <dev/tws/tws.h> 39130391Sle#include <dev/tws/tws_services.h> 40130391Sle#include <dev/tws/tws_hdm.h> 41130391Sle 42130391Sle#include <cam/cam.h> 43130391Sle#include <cam/cam_ccb.h> 44130391Sle 45130391SleMALLOC_DEFINE(M_TWS, "twsbuf", "buffers used by tws driver"); 46130391Sleint tws_queue_depth = TWS_MAX_REQS; 47130391Sleint tws_enable_msi = 0; 48130391Sleint tws_enable_msix = 0; 49130391Sle 50130391Sle 51130391Sle 52130391Sle/* externs */ 53130391Sleextern int tws_cam_attach(struct tws_softc *sc); 54130391Sleextern void tws_cam_detach(struct tws_softc *sc); 55130391Sleextern int tws_init_ctlr(struct tws_softc *sc); 56130391Sleextern boolean tws_ctlr_ready(struct tws_softc *sc); 57130391Sleextern void tws_turn_off_interrupts(struct tws_softc *sc); 58138110Sleextern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, 59130391Sle u_int8_t q_type ); 60130391Sleextern struct tws_request *tws_q_remove_request(struct tws_softc *sc, 61130391Sle struct tws_request *req, u_int8_t q_type ); 62138112Sleextern struct tws_request *tws_q_remove_head(struct tws_softc *sc, 63130391Sle u_int8_t q_type ); 64130391Sleextern boolean tws_get_response(struct tws_softc *sc, u_int16_t *req_id); 65130391Sleextern boolean tws_ctlr_reset(struct tws_softc *sc); 66130391Sleextern void tws_intr(void *arg); 67130391Sleextern int tws_use_32bit_sgls; 68130391Sle 69130391Sle 70130391Slestruct tws_request *tws_get_request(struct tws_softc *sc, u_int16_t type); 71130391Sleint tws_init_connect(struct tws_softc *sc, u_int16_t mc); 72130391Slevoid tws_send_event(struct tws_softc *sc, u_int8_t event); 73130391Sleuint8_t tws_get_state(struct tws_softc *sc); 74130391Slevoid tws_release_request(struct tws_request *req); 75130391Sle 76130391Sle 77130391Sle 78130391Sle/* Function prototypes */ 79130391Slestatic d_open_t tws_open; 80130391Slestatic d_close_t tws_close; 81130391Slestatic d_read_t tws_read; 82130391Slestatic d_write_t tws_write; 83130391Sleextern d_ioctl_t tws_ioctl; 84130391Sle 85130391Slestatic int tws_init(struct tws_softc *sc); 86130391Slestatic void tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs, 87130391Sle int nseg, int error); 88130391Sle 89130391Slestatic int tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size); 90130391Slestatic int tws_init_aen_q(struct tws_softc *sc); 91130391Slestatic int tws_init_trace_q(struct tws_softc *sc); 92130391Slestatic int tws_setup_irq(struct tws_softc *sc); 93130391Sleint tws_setup_intr(struct tws_softc *sc, int irqs); 94130391Sleint tws_teardown_intr(struct tws_softc *sc); 95130391Sle 96130391Sle 97130391Sle/* Character device entry points */ 98130391Sle 99130391Slestatic struct cdevsw tws_cdevsw = { 100130391Sle .d_version = D_VERSION, 101130391Sle .d_open = tws_open, 102130391Sle .d_close = tws_close, 103130391Sle .d_read = tws_read, 104130391Sle .d_write = tws_write, 105130391Sle .d_ioctl = tws_ioctl, 106130391Sle .d_name = "tws", 107130391Sle}; 108130391Sle 109130391Sle/* 110130391Sle * In the cdevsw routines, we find our softc by using the si_drv1 member 111130391Sle * of struct cdev. We set this variable to point to our softc in our 112130391Sle * attach routine when we create the /dev entry. 113130391Sle */ 114130391Sle 115130391Sleint 116130391Sletws_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td) 117130391Sle{ 118130391Sle struct tws_softc *sc = dev->si_drv1; 119130391Sle 120130391Sle if ( sc ) 121130391Sle TWS_TRACE_DEBUG(sc, "entry", dev, oflags); 122130391Sle return (0); 123130391Sle} 124130391Sle 125130391Sleint 126130391Sletws_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td) 127130391Sle{ 128130391Sle struct tws_softc *sc = dev->si_drv1; 129130391Sle 130130391Sle if ( sc ) 131130391Sle TWS_TRACE_DEBUG(sc, "entry", dev, fflag); 132130391Sle return (0); 133130391Sle} 134130391Sle 135130391Sleint 136130391Sletws_read(struct cdev *dev, struct uio *uio, int ioflag) 137130391Sle{ 138130391Sle struct tws_softc *sc = dev->si_drv1; 139130391Sle 140130391Sle if ( sc ) 141130391Sle TWS_TRACE_DEBUG(sc, "entry", dev, ioflag); 142130391Sle return (0); 143130391Sle} 144130391Sle 145130391Sleint 146130391Sletws_write(struct cdev *dev, struct uio *uio, int ioflag) 147130391Sle{ 148130391Sle struct tws_softc *sc = dev->si_drv1; 149130391Sle 150130391Sle if ( sc ) 151130391Sle TWS_TRACE_DEBUG(sc, "entry", dev, ioflag); 152130391Sle return (0); 153130391Sle} 154130391Sle 155130391Sle/* PCI Support Functions */ 156130391Sle 157130391Sle/* 158130391Sle * Compare the device ID of this device against the IDs that this driver 159130391Sle * supports. If there is a match, set the description and return success. 160133097Sle */ 161133097Slestatic int 162133097Sletws_probe(device_t dev) 163133097Sle{ 164133097Sle static u_int8_t first_ctlr = 1; 165133097Sle 166133097Sle if ((pci_get_vendor(dev) == TWS_VENDOR_ID) && 167133097Sle (pci_get_device(dev) == TWS_DEVICE_ID)) { 168133097Sle device_set_desc(dev, "LSI 3ware SAS/SATA Storage Controller"); 169133097Sle if (first_ctlr) { 170133097Sle printf("LSI 3ware device driver for SAS/SATA storage " 171133097Sle "controllers, version: %s\n", TWS_DRIVER_VERSION_STRING); 172133097Sle first_ctlr = 0; 173133097Sle } 174133097Sle 175133097Sle return(BUS_PROBE_DEFAULT); 176133097Sle } 177133097Sle return (ENXIO); 178133097Sle} 179133097Sle 180133097Sle/* Attach function is only called if the probe is successful. */ 181133097Sle 182133097Slestatic int 183133097Sletws_attach(device_t dev) 184133097Sle{ 185133097Sle struct tws_softc *sc = device_get_softc(dev); 186133097Sle u_int32_t bar; 187133097Sle int error=0,i; 188133097Sle 189133097Sle /* no tracing yet */ 190133097Sle /* Look up our softc and initialize its fields. */ 191133097Sle sc->tws_dev = dev; 192133097Sle sc->device_id = pci_get_device(dev); 193133097Sle sc->subvendor_id = pci_get_subvendor(dev); 194133097Sle sc->subdevice_id = pci_get_subdevice(dev); 195130391Sle 196130391Sle /* Intialize mutexes */ 197130391Sle mtx_init( &sc->q_lock, "tws_q_lock", NULL, MTX_DEF); 198130391Sle mtx_init( &sc->sim_lock, "tws_sim_lock", NULL, MTX_DEF); 199130391Sle mtx_init( &sc->gen_lock, "tws_gen_lock", NULL, MTX_DEF); 200130391Sle mtx_init( &sc->io_lock, "tws_io_lock", NULL, MTX_DEF | MTX_RECURSE); 201130391Sle 202130391Sle if ( tws_init_trace_q(sc) == FAILURE ) 203130391Sle printf("trace init failure\n"); 204130391Sle /* send init event */ 205130391Sle mtx_lock(&sc->gen_lock); 206130391Sle tws_send_event(sc, TWS_INIT_START); 207130391Sle mtx_unlock(&sc->gen_lock); 208130391Sle 209130391Sle 210130391Sle#if _BYTE_ORDER == _BIG_ENDIAN 211130391Sle TWS_TRACE(sc, "BIG endian", 0, 0); 212130391Sle#endif 213130391Sle /* sysctl context setup */ 214130391Sle sysctl_ctx_init(&sc->tws_clist); 215130391Sle sc->tws_oidp = SYSCTL_ADD_NODE(&sc->tws_clist, 216130391Sle SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 217130391Sle device_get_nameunit(dev), 218130391Sle CTLFLAG_RD, 0, ""); 219130391Sle if ( sc->tws_oidp == NULL ) { 220130391Sle tws_log(sc, SYSCTL_TREE_NODE_ADD); 221130391Sle goto attach_fail_1; 222130391Sle } 223130391Sle SYSCTL_ADD_STRING(&sc->tws_clist, SYSCTL_CHILDREN(sc->tws_oidp), 224130391Sle OID_AUTO, "driver_version", CTLFLAG_RD, 225130391Sle TWS_DRIVER_VERSION_STRING, 0, "TWS driver version"); 226130391Sle 227130391Sle pci_enable_busmaster(dev); 228130391Sle 229130391Sle bar = pci_read_config(dev, TWS_PCI_BAR0, 4); 230130391Sle TWS_TRACE_DEBUG(sc, "bar0 ", bar, 0); 231130391Sle bar = pci_read_config(dev, TWS_PCI_BAR1, 4); 232130391Sle bar = bar & ~TWS_BIT2; 233130391Sle TWS_TRACE_DEBUG(sc, "bar1 ", bar, 0); 234130391Sle 235130391Sle /* MFA base address is BAR2 register used for 236130391Sle * push mode. Firmware will evatualy move to 237130391Sle * pull mode during witch this needs to change 238130391Sle */ 239130391Sle#ifndef TWS_PULL_MODE_ENABLE 240130391Sle sc->mfa_base = (u_int64_t)pci_read_config(dev, TWS_PCI_BAR2, 4); 241130391Sle sc->mfa_base = sc->mfa_base & ~TWS_BIT2; 242130391Sle TWS_TRACE_DEBUG(sc, "bar2 ", sc->mfa_base, 0); 243130391Sle#endif 244130391Sle 245130391Sle /* allocate MMIO register space */ 246130391Sle sc->reg_res_id = TWS_PCI_BAR1; /* BAR1 offset */ 247130391Sle if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 248130391Sle &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE)) 249130391Sle == NULL) { 250130391Sle tws_log(sc, ALLOC_MEMORY_RES); 251130391Sle goto attach_fail_1; 252130391Sle } 253130391Sle sc->bus_tag = rman_get_bustag(sc->reg_res); 254130391Sle sc->bus_handle = rman_get_bushandle(sc->reg_res); 255130391Sle 256130391Sle#ifndef TWS_PULL_MODE_ENABLE 257130391Sle /* Allocate bus space for inbound mfa */ 258130391Sle sc->mfa_res_id = TWS_PCI_BAR2; /* BAR2 offset */ 259130391Sle if ((sc->mfa_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 260130391Sle &(sc->mfa_res_id), 0, ~0, 0x100000, RF_ACTIVE)) 261130391Sle == NULL) { 262130391Sle tws_log(sc, ALLOC_MEMORY_RES); 263130391Sle goto attach_fail_2; 264130391Sle } 265130391Sle sc->bus_mfa_tag = rman_get_bustag(sc->mfa_res); 266130391Sle sc->bus_mfa_handle = rman_get_bushandle(sc->mfa_res); 267130391Sle#endif 268130391Sle 269130391Sle /* Allocate and register our interrupt. */ 270130391Sle sc->intr_type = TWS_INTx; /* default */ 271130391Sle 272130391Sle if ( tws_enable_msi ) 273130391Sle sc->intr_type = TWS_MSI; 274130391Sle if ( tws_setup_irq(sc) == FAILURE ) { 275130391Sle tws_log(sc, ALLOC_MEMORY_RES); 276130391Sle goto attach_fail_3; 277130391Sle } 278130391Sle 279130391Sle /* 280130391Sle * Create a /dev entry for this device. The kernel will assign us 281130391Sle * a major number automatically. We use the unit number of this 282130391Sle * device as the minor number and name the character device 283130391Sle * "tws<unit>". 284130391Sle */ 285130391Sle sc->tws_cdev = make_dev(&tws_cdevsw, device_get_unit(dev), 286130391Sle UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "tws%u", 287130391Sle device_get_unit(dev)); 288130391Sle sc->tws_cdev->si_drv1 = sc; 289130391Sle 290130391Sle if ( tws_init(sc) == FAILURE ) { 291130391Sle tws_log(sc, TWS_INIT_FAILURE); 292130391Sle goto attach_fail_4; 293130391Sle } 294130391Sle if ( tws_init_ctlr(sc) == FAILURE ) { 295130391Sle tws_log(sc, TWS_CTLR_INIT_FAILURE); 296130391Sle goto attach_fail_4; 297130391Sle } 298130391Sle if ((error = tws_cam_attach(sc))) { 299130391Sle tws_log(sc, TWS_CAM_ATTACH); 300130391Sle goto attach_fail_4; 301130391Sle } 302130391Sle /* send init complete event */ 303130391Sle mtx_lock(&sc->gen_lock); 304130391Sle tws_send_event(sc, TWS_INIT_COMPLETE); 305130391Sle mtx_unlock(&sc->gen_lock); 306130391Sle 307130391Sle TWS_TRACE_DEBUG(sc, "attached successfully", 0, sc->device_id); 308130391Sle return(0); 309130391Sle 310130391Sleattach_fail_4: 311130391Sle tws_teardown_intr(sc); 312130391Sle destroy_dev(sc->tws_cdev); 313130391Sleattach_fail_3: 314130391Sle for(i=0;i<sc->irqs;i++) { 315130391Sle if ( sc->irq_res[i] ){ 316130391Sle if (bus_release_resource(sc->tws_dev, 317130391Sle SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i])) 318130391Sle TWS_TRACE(sc, "bus irq res", 0, 0); 319130391Sle } 320130391Sle } 321130391Sle#ifndef TWS_PULL_MODE_ENABLE 322130391Sleattach_fail_2: 323130391Sle#endif 324130391Sle if ( sc->mfa_res ){ 325130391Sle if (bus_release_resource(sc->tws_dev, 326130391Sle SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 327130391Sle TWS_TRACE(sc, "bus release ", 0, sc->mfa_res_id); 328130391Sle } 329130391Sle if ( sc->reg_res ){ 330130391Sle if (bus_release_resource(sc->tws_dev, 331130391Sle SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 332130391Sle TWS_TRACE(sc, "bus release2 ", 0, sc->reg_res_id); 333130391Sle } 334130391Sleattach_fail_1: 335130391Sle mtx_destroy(&sc->q_lock); 336130391Sle mtx_destroy(&sc->sim_lock); 337130391Sle mtx_destroy(&sc->gen_lock); 338130391Sle mtx_destroy(&sc->io_lock); 339130391Sle sysctl_ctx_free(&sc->tws_clist); 340130391Sle return (ENXIO); 341130391Sle} 342130391Sle 343130391Sle/* Detach device. */ 344130391Sle 345130391Slestatic int 346130391Sletws_detach(device_t dev) 347130391Sle{ 348130391Sle struct tws_softc *sc = device_get_softc(dev); 349130391Sle int i; 350130391Sle u_int32_t reg; 351130391Sle 352130391Sle TWS_TRACE_DEBUG(sc, "entry", 0, 0); 353130391Sle 354130391Sle mtx_lock(&sc->gen_lock); 355130391Sle tws_send_event(sc, TWS_UNINIT_START); 356130391Sle mtx_unlock(&sc->gen_lock); 357130391Sle 358130391Sle /* needs to disable interrupt before detaching from cam */ 359130391Sle tws_turn_off_interrupts(sc); 360130391Sle /* clear door bell */ 361130391Sle tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4); 362130391Sle reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4); 363130391Sle TWS_TRACE_DEBUG(sc, "turn-off-intr", reg, 0); 364130391Sle sc->obfl_q_overrun = false; 365130391Sle tws_init_connect(sc, 1); 366130391Sle 367130391Sle /* Teardown the state in our softc created in our attach routine. */ 368130391Sle /* Disconnect the interrupt handler. */ 369130391Sle tws_teardown_intr(sc); 370130391Sle 371130391Sle /* Release irq resource */ 372130391Sle for(i=0;i<sc->irqs;i++) { 373130391Sle if ( sc->irq_res[i] ){ 374130391Sle if (bus_release_resource(sc->tws_dev, 375130391Sle SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i])) 376130391Sle TWS_TRACE(sc, "bus release irq resource", 377130391Sle i, sc->irq_res_id[i]); 378130391Sle } 379130391Sle } 380130391Sle if ( sc->intr_type == TWS_MSI ) { 381130391Sle pci_release_msi(sc->tws_dev); 382130391Sle } 383130391Sle 384130391Sle tws_cam_detach(sc); 385130391Sle 386130391Sle /* Release memory resource */ 387130391Sle if ( sc->mfa_res ){ 388130391Sle if (bus_release_resource(sc->tws_dev, 389130391Sle SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res)) 390130391Sle TWS_TRACE(sc, "bus release mem resource", 0, sc->mfa_res_id); 391130391Sle } 392130391Sle if ( sc->reg_res ){ 393130391Sle if (bus_release_resource(sc->tws_dev, 394130391Sle SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res)) 395130391Sle TWS_TRACE(sc, "bus release mem resource", 0, sc->reg_res_id); 396130391Sle } 397130391Sle 398130391Sle free(sc->reqs, M_TWS); 399130391Sle free(sc->sense_bufs, M_TWS); 400130391Sle free(sc->scan_ccb, M_TWS); 401130391Sle if (sc->ioctl_data_mem) 402130391Sle bus_dmamem_free(sc->data_tag, sc->ioctl_data_mem, sc->ioctl_data_map); 403130391Sle free(sc->aen_q.q, M_TWS); 404130391Sle free(sc->trace_q.q, M_TWS); 405130391Sle mtx_destroy(&sc->q_lock); 406130391Sle mtx_destroy(&sc->sim_lock); 407130391Sle mtx_destroy(&sc->gen_lock); 408130391Sle mtx_destroy(&sc->io_lock); 409130391Sle destroy_dev(sc->tws_cdev); 410130391Sle sysctl_ctx_free(&sc->tws_clist); 411130391Sle return (0); 412130391Sle} 413130391Sle 414130391Sleint 415130391Sletws_setup_intr(struct tws_softc *sc, int irqs) 416130391Sle{ 417130391Sle int i, error; 418130391Sle 419130391Sle for(i=0;i<irqs;i++) { 420130391Sle if (!(sc->intr_handle[i])) { 421130391Sle if ((error = bus_setup_intr(sc->tws_dev, sc->irq_res[i], 422130391Sle INTR_TYPE_CAM | INTR_MPSAFE, 423130391Sle#if (__FreeBSD_version >= 700000) 424130391Sle NULL, 425130391Sle#endif 426130391Sle tws_intr, sc, &sc->intr_handle[i]))) { 427130391Sle tws_log(sc, SETUP_INTR_RES); 428130391Sle return(FAILURE); 429130391Sle } 430130391Sle } 431130391Sle } 432130391Sle return(SUCCESS); 433130391Sle 434130391Sle} 435130391Sle 436130391Sle 437130391Sleint 438130391Sletws_teardown_intr(struct tws_softc *sc) 439130391Sle{ 440130391Sle int i, error; 441130391Sle 442130391Sle for(i=0;i<sc->irqs;i++) { 443130391Sle if (sc->intr_handle[i]) { 444130391Sle error = bus_teardown_intr(sc->tws_dev, 445130391Sle sc->irq_res[i], sc->intr_handle[i]); 446130391Sle sc->intr_handle[i] = NULL; 447130391Sle } 448130391Sle } 449130391Sle return(SUCCESS); 450130391Sle} 451130391Sle 452130391Sle 453130391Slestatic int 454130391Sletws_setup_irq(struct tws_softc *sc) 455130391Sle{ 456130391Sle int messages; 457130391Sle 458130391Sle switch(sc->intr_type) { 459130391Sle case TWS_INTx : 460130391Sle sc->irqs = 1; 461130391Sle sc->irq_res_id[0] = 0; 462130391Sle sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 463130391Sle &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 464130391Sle if ( ! sc->irq_res[0] ) 465130391Sle return(FAILURE); 466130391Sle if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 467130391Sle return(FAILURE); 468130391Sle device_printf(sc->tws_dev, "Using legacy INTx\n"); 469130391Sle break; 470130391Sle case TWS_MSI : 471130391Sle sc->irqs = 1; 472130391Sle sc->irq_res_id[0] = 1; 473130391Sle messages = 1; 474130391Sle if (pci_alloc_msi(sc->tws_dev, &messages) != 0 ) { 475130391Sle TWS_TRACE(sc, "pci alloc msi fail", 0, messages); 476130391Sle return(FAILURE); 477130391Sle } 478130391Sle sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ, 479130391Sle &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE); 480130391Sle 481130391Sle if ( !sc->irq_res[0] ) 482130391Sle return(FAILURE); 483130391Sle if ( tws_setup_intr(sc, sc->irqs) == FAILURE ) 484130391Sle return(FAILURE); 485130391Sle device_printf(sc->tws_dev, "Using MSI\n"); 486138112Sle break; 487138112Sle 488138112Sle } 489138112Sle 490138112Sle return(SUCCESS); 491138112Sle} 492138112Sle 493138112Slestatic int 494138112Sletws_init(struct tws_softc *sc) 495138112Sle{ 496138112Sle 497138112Sle u_int32_t max_sg_elements; 498138112Sle u_int32_t dma_mem_size; 499138112Sle int error; 500138112Sle u_int32_t reg; 501138112Sle 502138112Sle sc->seq_id = 0; 503138112Sle if ( tws_queue_depth > TWS_MAX_REQS ) 504138112Sle tws_queue_depth = TWS_MAX_REQS; 505138112Sle if (tws_queue_depth < TWS_RESERVED_REQS+1) 506138112Sle tws_queue_depth = TWS_RESERVED_REQS+1; 507138112Sle sc->is64bit = (sizeof(bus_addr_t) == 8) ? true : false; 508138112Sle max_sg_elements = (sc->is64bit && !tws_use_32bit_sgls) ? 509138112Sle TWS_MAX_64BIT_SG_ELEMENTS : 510138112Sle TWS_MAX_32BIT_SG_ELEMENTS; 511138112Sle dma_mem_size = (sizeof(struct tws_command_packet) * tws_queue_depth) + 512138112Sle (TWS_SECTOR_SIZE) ; 513138112Sle if ( bus_dma_tag_create(bus_get_dma_tag(sc->tws_dev), /* PCI parent */ 514138112Sle TWS_ALIGNMENT, /* alignment */ 515138112Sle 0, /* boundary */ 516138112Sle BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 517138112Sle BUS_SPACE_MAXADDR, /* highaddr */ 518138112Sle NULL, NULL, /* filter, filterarg */ 519138112Sle BUS_SPACE_MAXSIZE, /* maxsize */ 520138112Sle max_sg_elements, /* numsegs */ 521138112Sle BUS_SPACE_MAXSIZE, /* maxsegsize */ 522138112Sle 0, /* flags */ 523138112Sle NULL, NULL, /* lockfunc, lockfuncarg */ 524138112Sle &sc->parent_tag /* tag */ 525138112Sle )) { 526138112Sle TWS_TRACE_DEBUG(sc, "DMA parent tag Create fail", max_sg_elements, 527138112Sle sc->is64bit); 528138112Sle return(ENOMEM); 529138112Sle } 530138112Sle /* In bound message frame requires 16byte alignment. 531138112Sle * Outbound MF's can live with 4byte alignment - for now just 532138112Sle * use 16 for both. 533138112Sle */ 534138112Sle if ( bus_dma_tag_create(sc->parent_tag, /* parent */ 535138112Sle TWS_IN_MF_ALIGNMENT, /* alignment */ 536138112Sle 0, /* boundary */ 537138112Sle BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 538138112Sle BUS_SPACE_MAXADDR, /* highaddr */ 539138112Sle NULL, NULL, /* filter, filterarg */ 540138112Sle dma_mem_size, /* maxsize */ 541130391Sle 1, /* numsegs */ 542130391Sle BUS_SPACE_MAXSIZE, /* maxsegsize */ 543130391Sle 0, /* flags */ 544130391Sle NULL, NULL, /* lockfunc, lockfuncarg */ 545130391Sle &sc->cmd_tag /* tag */ 546130391Sle )) { 547130391Sle TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 548130391Sle return(ENOMEM); 549130391Sle } 550130391Sle 551130391Sle if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem, 552130391Sle BUS_DMA_NOWAIT, &sc->cmd_map)) { 553130391Sle TWS_TRACE_DEBUG(sc, "DMA mem alloc fail", max_sg_elements, sc->is64bit); 554130391Sle return(ENOMEM); 555130391Sle } 556130391Sle 557130391Sle /* if bus_dmamem_alloc succeeds then bus_dmamap_load will succeed */ 558130391Sle sc->dma_mem_phys=0; 559130391Sle error = bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem, 560130391Sle dma_mem_size, tws_dmamap_cmds_load_cbfn, 561130391Sle &sc->dma_mem_phys, 0); 562130391Sle 563130391Sle /* 564130391Sle * Create a dma tag for data buffers; size will be the maximum 565130391Sle * possible I/O size (128kB). 566130391Sle */ 567130391Sle if (bus_dma_tag_create(sc->parent_tag, /* parent */ 568130391Sle TWS_ALIGNMENT, /* alignment */ 569130391Sle 0, /* boundary */ 570130391Sle BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 571130391Sle BUS_SPACE_MAXADDR, /* highaddr */ 572130391Sle NULL, NULL, /* filter, filterarg */ 573130391Sle TWS_MAX_IO_SIZE, /* maxsize */ 574130391Sle max_sg_elements, /* nsegments */ 575130391Sle TWS_MAX_IO_SIZE, /* maxsegsize */ 576130391Sle BUS_DMA_ALLOCNOW, /* flags */ 577130391Sle busdma_lock_mutex, /* lockfunc */ 578130391Sle &sc->io_lock, /* lockfuncarg */ 579130391Sle &sc->data_tag /* tag */)) { 580130391Sle TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit); 581130391Sle return(ENOMEM); 582130391Sle } 583130391Sle 584130391Sle sc->reqs = malloc(sizeof(struct tws_request) * tws_queue_depth, M_TWS, 585130391Sle M_WAITOK | M_ZERO); 586130391Sle if ( sc->reqs == NULL ) { 587130391Sle TWS_TRACE_DEBUG(sc, "malloc failed", 0, sc->is64bit); 588130391Sle return(ENOMEM); 589130391Sle } 590130391Sle sc->sense_bufs = malloc(sizeof(struct tws_sense) * tws_queue_depth, M_TWS, 591130391Sle M_WAITOK | M_ZERO); 592130391Sle if ( sc->sense_bufs == NULL ) { 593130391Sle TWS_TRACE_DEBUG(sc, "sense malloc failed", 0, sc->is64bit); 594130391Sle return(ENOMEM); 595130391Sle } 596130391Sle sc->scan_ccb = malloc(sizeof(union ccb), M_TWS, M_WAITOK | M_ZERO); 597130391Sle if ( sc->scan_ccb == NULL ) { 598130391Sle TWS_TRACE_DEBUG(sc, "ccb malloc failed", 0, sc->is64bit); 599130391Sle return(ENOMEM); 600130391Sle } 601130391Sle if (bus_dmamem_alloc(sc->data_tag, (void **)&sc->ioctl_data_mem, 602130391Sle (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &sc->ioctl_data_map)) { 603130391Sle device_printf(sc->tws_dev, "Cannot allocate ioctl data mem\n"); 604130391Sle return(ENOMEM); 605130391Sle } 606130391Sle 607130391Sle if ( !tws_ctlr_ready(sc) ) 608130391Sle if( !tws_ctlr_reset(sc) ) 609130391Sle return(FAILURE); 610130391Sle 611130391Sle bzero(&sc->stats, sizeof(struct tws_stats)); 612138110Sle tws_init_qs(sc); 613138110Sle tws_turn_off_interrupts(sc); 614138110Sle 615138110Sle /* 616138110Sle * enable pull mode by setting bit1 . 617138110Sle * setting bit0 to 1 will enable interrupt coalesing 618138110Sle * will revisit. 619138110Sle */ 620138110Sle 621138110Sle#ifdef TWS_PULL_MODE_ENABLE 622138110Sle 623138110Sle reg = tws_read_reg(sc, TWS_I2O0_CTL, 4); 624138110Sle TWS_TRACE_DEBUG(sc, "i20 ctl", reg, TWS_I2O0_CTL); 625138110Sle tws_write_reg(sc, TWS_I2O0_CTL, reg | TWS_BIT1, 4); 626138110Sle 627138110Sle#endif 628138110Sle 629138110Sle TWS_TRACE_DEBUG(sc, "dma_mem_phys", sc->dma_mem_phys, TWS_I2O0_CTL); 630138110Sle if ( tws_init_reqs(sc, dma_mem_size) == FAILURE ) 631138110Sle return(FAILURE); 632138110Sle if ( tws_init_aen_q(sc) == FAILURE ) 633138110Sle return(FAILURE); 634138110Sle 635138110Sle return(SUCCESS); 636138110Sle 637138110Sle} 638138110Sle 639138110Slestatic int 640138110Sletws_init_aen_q(struct tws_softc *sc) 641138110Sle{ 642138110Sle sc->aen_q.head=0; 643138110Sle sc->aen_q.tail=0; 644138110Sle sc->aen_q.depth=256; 645138110Sle sc->aen_q.overflow=0; 646138110Sle sc->aen_q.q = malloc(sizeof(struct tws_event_packet)*sc->aen_q.depth, 647138110Sle M_TWS, M_WAITOK | M_ZERO); 648138110Sle if ( ! sc->aen_q.q ) 649138110Sle return(FAILURE); 650138110Sle return(SUCCESS); 651138110Sle} 652138110Sle 653138110Slestatic int 654138110Sletws_init_trace_q(struct tws_softc *sc) 655138110Sle{ 656138110Sle sc->trace_q.head=0; 657138110Sle sc->trace_q.tail=0; 658138110Sle sc->trace_q.depth=256; 659138110Sle sc->trace_q.overflow=0; 660138110Sle sc->trace_q.q = malloc(sizeof(struct tws_trace_rec)*sc->trace_q.depth, 661138110Sle M_TWS, M_WAITOK | M_ZERO); 662138110Sle if ( ! sc->trace_q.q ) 663138110Sle return(FAILURE); 664138110Sle return(SUCCESS); 665138110Sle} 666138110Sle 667138110Slestatic int 668138110Sletws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size) 669138110Sle{ 670138110Sle 671138110Sle struct tws_command_packet *cmd_buf; 672138110Sle cmd_buf = (struct tws_command_packet *)sc->dma_mem; 673138110Sle int i; 674138110Sle 675138110Sle bzero(cmd_buf, dma_mem_size); 676138110Sle TWS_TRACE_DEBUG(sc, "phy cmd", sc->dma_mem_phys, 0); 677138110Sle mtx_lock(&sc->q_lock); 678138110Sle for ( i=0; i< tws_queue_depth; i++) 679138110Sle { 680138110Sle if (bus_dmamap_create(sc->data_tag, 0, &sc->reqs[i].dma_map)) { 681138110Sle /* log a ENOMEM failure msg here */ 682138110Sle mtx_unlock(&sc->q_lock); 683138110Sle return(FAILURE); 684138110Sle } 685138110Sle sc->reqs[i].cmd_pkt = &cmd_buf[i]; 686138110Sle 687138110Sle sc->sense_bufs[i].hdr = &cmd_buf[i].hdr ; 688138110Sle sc->sense_bufs[i].hdr_pkt_phy = sc->dma_mem_phys + 689138110Sle (i * sizeof(struct tws_command_packet)); 690138110Sle 691138110Sle sc->reqs[i].cmd_pkt_phy = sc->dma_mem_phys + 692138110Sle sizeof(struct tws_command_header) + 693138110Sle (i * sizeof(struct tws_command_packet)); 694138110Sle sc->reqs[i].request_id = i; 695130391Sle sc->reqs[i].sc = sc; 696130391Sle 697130391Sle sc->reqs[i].cmd_pkt->hdr.header_desc.size_header = 128; 698130391Sle 699130391Sle sc->reqs[i].state = TWS_REQ_STATE_FREE; 700130391Sle if ( i >= TWS_RESERVED_REQS ) 701130391Sle tws_q_insert_tail(sc, &sc->reqs[i], TWS_FREE_Q); 702130391Sle } 703130391Sle mtx_unlock(&sc->q_lock); 704130391Sle return(SUCCESS); 705130391Sle} 706130391Sle 707130391Slestatic void 708130391Sletws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs, 709130391Sle int nseg, int error) 710130391Sle{ 711130391Sle 712130391Sle /* printf("command load done \n"); */ 713130391Sle 714130391Sle *((bus_addr_t *)arg) = segs[0].ds_addr; 715130391Sle} 716130391Sle 717130391Slevoid 718130391Sletws_send_event(struct tws_softc *sc, u_int8_t event) 719130391Sle{ 720130391Sle mtx_assert(&sc->gen_lock, MA_OWNED); 721130391Sle TWS_TRACE_DEBUG(sc, "received event ", 0, event); 722130391Sle switch (event) { 723130391Sle 724130391Sle case TWS_INIT_START: 725130391Sle sc->tws_state = TWS_INIT; 726130391Sle break; 727130391Sle 728130391Sle case TWS_INIT_COMPLETE: 729130391Sle if (sc->tws_state != TWS_INIT) { 730130391Sle device_printf(sc->tws_dev, "invalid state transition %d => TWS_ONLINE\n", sc->tws_state); 731130391Sle } else { 732130391Sle sc->tws_state = TWS_ONLINE; 733130391Sle } 734130391Sle break; 735130391Sle 736130391Sle case TWS_RESET_START: 737130391Sle /* We can transition to reset state from any state except reset*/ 738130391Sle if (sc->tws_state != TWS_RESET) { 739130391Sle sc->tws_prev_state = sc->tws_state; 740130391Sle sc->tws_state = TWS_RESET; 741130391Sle } 742130391Sle break; 743130391Sle 744130391Sle case TWS_RESET_COMPLETE: 745130391Sle if (sc->tws_state != TWS_RESET) { 746130391Sle device_printf(sc->tws_dev, "invalid state transition %d => %d (previous state)\n", sc->tws_state, sc->tws_prev_state); 747130391Sle } else { 748130391Sle sc->tws_state = sc->tws_prev_state; 749130391Sle } 750130391Sle break; 751130391Sle 752130391Sle case TWS_SCAN_FAILURE: 753130391Sle if (sc->tws_state != TWS_ONLINE) { 754130391Sle device_printf(sc->tws_dev, "invalid state transition %d => TWS_OFFLINE\n", sc->tws_state); 755130391Sle } else { 756130391Sle sc->tws_state = TWS_OFFLINE; 757130391Sle } 758130391Sle break; 759130391Sle 760130391Sle case TWS_UNINIT_START: 761130391Sle if ((sc->tws_state != TWS_ONLINE) && (sc->tws_state != TWS_OFFLINE)) { 762130391Sle device_printf(sc->tws_dev, "invalid state transition %d => TWS_UNINIT\n", sc->tws_state); 763130391Sle } else { 764130391Sle sc->tws_state = TWS_UNINIT; 765130391Sle } 766130391Sle break; 767130391Sle } 768130391Sle 769130391Sle} 770130391Sle 771130391Sleuint8_t 772130391Sletws_get_state(struct tws_softc *sc) 773130391Sle{ 774130391Sle 775130391Sle return((u_int8_t)sc->tws_state); 776130391Sle 777130391Sle} 778130391Sle 779130391Sle/* Called during system shutdown after sync. */ 780130391Sle 781130391Slestatic int 782130391Sletws_shutdown(device_t dev) 783130391Sle{ 784130391Sle 785130391Sle struct tws_softc *sc = device_get_softc(dev); 786130391Sle 787130391Sle TWS_TRACE_DEBUG(sc, "entry", 0, 0); 788130391Sle 789130391Sle tws_turn_off_interrupts(sc); 790130391Sle tws_init_connect(sc, 1); 791130391Sle 792130391Sle return (0); 793130391Sle} 794130391Sle 795130391Sle/* 796130391Sle * Device suspend routine. 797130391Sle */ 798130391Slestatic int 799130391Sletws_suspend(device_t dev) 800130391Sle{ 801130391Sle struct tws_softc *sc = device_get_softc(dev); 802130391Sle 803130391Sle if ( sc ) 804130391Sle TWS_TRACE_DEBUG(sc, "entry", 0, 0); 805130391Sle return (0); 806130391Sle} 807130391Sle 808130391Sle/* 809130391Sle * Device resume routine. 810130391Sle */ 811130391Slestatic int 812130391Sletws_resume(device_t dev) 813130391Sle{ 814130391Sle 815130391Sle struct tws_softc *sc = device_get_softc(dev); 816130391Sle 817130391Sle if ( sc ) 818130391Sle TWS_TRACE_DEBUG(sc, "entry", 0, 0); 819130391Sle return (0); 820130391Sle} 821130391Sle 822130391Sle 823130391Slestruct tws_request * 824130391Sletws_get_request(struct tws_softc *sc, u_int16_t type) 825130391Sle{ 826130391Sle struct mtx *my_mutex = ((type == TWS_REQ_TYPE_SCSI_IO) ? &sc->q_lock : &sc->gen_lock); 827130391Sle struct tws_request *r = NULL; 828130391Sle 829130391Sle mtx_lock(my_mutex); 830130391Sle 831130391Sle if (type == TWS_REQ_TYPE_SCSI_IO) { 832130391Sle r = tws_q_remove_head(sc, TWS_FREE_Q); 833130391Sle } else { 834130391Sle if ( sc->reqs[type].state == TWS_REQ_STATE_FREE ) { 835130391Sle r = &sc->reqs[type]; 836130391Sle } 837130391Sle } 838130391Sle 839130391Sle if ( r ) { 840130391Sle bzero(&r->cmd_pkt->cmd, sizeof(struct tws_command_apache)); 841130391Sle r->data = NULL; 842130391Sle r->length = 0; 843130391Sle r->type = type; 844130391Sle r->flags = TWS_DIR_UNKNOWN; 845130391Sle r->error_code = TWS_REQ_RET_INVALID; 846130391Sle r->cb = NULL; 847130391Sle r->ccb_ptr = NULL; 848130391Sle r->thandle.callout = NULL; 849130391Sle r->next = r->prev = NULL; 850130391Sle 851130391Sle r->state = ((type == TWS_REQ_TYPE_SCSI_IO) ? TWS_REQ_STATE_TRAN : TWS_REQ_STATE_BUSY); 852130391Sle } 853130391Sle 854130391Sle mtx_unlock(my_mutex); 855130391Sle 856130391Sle return(r); 857130391Sle} 858130391Sle 859130391Slevoid 860138112Sletws_release_request(struct tws_request *req) 861138112Sle{ 862130391Sle 863130391Sle struct tws_softc *sc = req->sc; 864130391Sle 865130391Sle TWS_TRACE_DEBUG(sc, "entry", sc, 0); 866138110Sle mtx_lock(&sc->q_lock); 867138110Sle tws_q_insert_tail(sc, req, TWS_FREE_Q); 868138110Sle mtx_unlock(&sc->q_lock); 869138110Sle} 870130391Sle 871130391Slestatic device_method_t tws_methods[] = { 872130391Sle /* Device interface */ 873130391Sle DEVMETHOD(device_probe, tws_probe), 874130391Sle DEVMETHOD(device_attach, tws_attach), 875130391Sle DEVMETHOD(device_detach, tws_detach), 876130391Sle DEVMETHOD(device_shutdown, tws_shutdown), 877130391Sle DEVMETHOD(device_suspend, tws_suspend), 878130391Sle DEVMETHOD(device_resume, tws_resume), 879130391Sle 880130391Sle DEVMETHOD_END 881130391Sle}; 882130391Sle 883130391Slestatic driver_t tws_driver = { 884130391Sle "tws", 885130391Sle tws_methods, 886130391Sle sizeof(struct tws_softc) 887130391Sle}; 888130391Sle 889130391Sle 890130391Slestatic devclass_t tws_devclass; 891130391Sle 892130391Sle/* DEFINE_CLASS_0(tws, tws_driver, tws_methods, sizeof(struct tws_softc)); */ 893130391SleDRIVER_MODULE(tws, pci, tws_driver, tws_devclass, 0, 0); 894130391SleMODULE_DEPEND(tws, cam, 1, 1, 1); 895130391SleMODULE_DEPEND(tws, pci, 1, 1, 1); 896130391Sle 897130391SleTUNABLE_INT("hw.tws.queue_depth", &tws_queue_depth); 898130391SleTUNABLE_INT("hw.tws.enable_msi", &tws_enable_msi); 899130391Sle