167555Smsmith/*- 267555Smsmith * Copyright (c) 2000 Michael Smith 3123103Sps * Copyright (c) 2003 Paul Saab 4123103Sps * Copyright (c) 2003 Vinod Kashyap 567555Smsmith * Copyright (c) 2000 BSDi 667555Smsmith * All rights reserved. 767555Smsmith * 867555Smsmith * Redistribution and use in source and binary forms, with or without 967555Smsmith * modification, are permitted provided that the following conditions 1067555Smsmith * are met: 1167555Smsmith * 1. Redistributions of source code must retain the above copyright 1267555Smsmith * notice, this list of conditions and the following disclaimer. 1367555Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1467555Smsmith * notice, this list of conditions and the following disclaimer in the 1567555Smsmith * documentation and/or other materials provided with the distribution. 1667555Smsmith * 1767555Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1867555Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1967555Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2067555Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2167555Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2267555Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2367555Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2467555Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2567555Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2667555Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2767555Smsmith * SUCH DAMAGE. 2867555Smsmith */ 2967555Smsmith 30227843Smarius#include <sys/cdefs.h> 31227843Smarius__FBSDID("$FreeBSD$"); 32227843Smarius 3367555Smsmith/* 3467555Smsmith * FreeBSD-specific code. 3567555Smsmith */ 3667555Smsmith 3767555Smsmith#include <dev/twe/twe_compat.h> 3867555Smsmith#include <dev/twe/twereg.h> 3967555Smsmith#include <dev/twe/tweio.h> 4067555Smsmith#include <dev/twe/twevar.h> 4167555Smsmith#include <dev/twe/twe_tables.h> 4267555Smsmith 43123103Sps#include <vm/vm.h> 44123103Sps 4567555Smsmithstatic devclass_t twe_devclass; 4667555Smsmith 4769543Smsmith#ifdef TWE_DEBUG 4869543Smsmithstatic u_int32_t twed_bio_in; 4969543Smsmith#define TWED_BIO_IN twed_bio_in++ 5069543Smsmithstatic u_int32_t twed_bio_out; 5169543Smsmith#define TWED_BIO_OUT twed_bio_out++ 5269543Smsmith#else 5369543Smsmith#define TWED_BIO_IN 5469543Smsmith#define TWED_BIO_OUT 5569543Smsmith#endif 5669543Smsmith 57118816Spsstatic void twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 58118816Spsstatic void twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 59118816Sps 6067555Smsmith/******************************************************************************** 6167555Smsmith ******************************************************************************** 6267555Smsmith Control device interface 6367555Smsmith ******************************************************************************** 6467555Smsmith ********************************************************************************/ 6567555Smsmith 6667555Smsmithstatic d_open_t twe_open; 6767555Smsmithstatic d_close_t twe_close; 6867555Smsmithstatic d_ioctl_t twe_ioctl_wrapper; 6967555Smsmith 7067555Smsmithstatic struct cdevsw twe_cdevsw = { 71126080Sphk .d_version = D_VERSION, 72111815Sphk .d_open = twe_open, 73111815Sphk .d_close = twe_close, 74111815Sphk .d_ioctl = twe_ioctl_wrapper, 75111815Sphk .d_name = "twe", 7667555Smsmith}; 7767555Smsmith 7867555Smsmith/******************************************************************************** 7967555Smsmith * Accept an open operation on the control device. 8067555Smsmith */ 8167555Smsmithstatic int 82192450Simptwe_open(struct cdev *dev, int flags, int fmt, struct thread *td) 8367555Smsmith{ 84191060Sed struct twe_softc *sc = (struct twe_softc *)dev->si_drv1; 8567555Smsmith 86239244Sjhb TWE_IO_LOCK(sc); 87239244Sjhb if (sc->twe_state & TWE_STATE_DETACHING) { 88239244Sjhb TWE_IO_UNLOCK(sc); 89239244Sjhb return (ENXIO); 90239244Sjhb } 9167555Smsmith sc->twe_state |= TWE_STATE_OPEN; 92239244Sjhb TWE_IO_UNLOCK(sc); 9367555Smsmith return(0); 9467555Smsmith} 9567555Smsmith 9667555Smsmith/******************************************************************************** 9767555Smsmith * Accept the last close on the control device. 9867555Smsmith */ 9967555Smsmithstatic int 100192450Simptwe_close(struct cdev *dev, int flags, int fmt, struct thread *td) 10167555Smsmith{ 102191060Sed struct twe_softc *sc = (struct twe_softc *)dev->si_drv1; 10367555Smsmith 104239244Sjhb TWE_IO_LOCK(sc); 10567555Smsmith sc->twe_state &= ~TWE_STATE_OPEN; 106239244Sjhb TWE_IO_UNLOCK(sc); 10767555Smsmith return (0); 10867555Smsmith} 10967555Smsmith 11067555Smsmith/******************************************************************************** 11167555Smsmith * Handle controller-specific control operations. 11267555Smsmith */ 11367555Smsmithstatic int 114192450Simptwe_ioctl_wrapper(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) 11567555Smsmith{ 11667555Smsmith struct twe_softc *sc = (struct twe_softc *)dev->si_drv1; 11767555Smsmith 11867555Smsmith return(twe_ioctl(sc, cmd, addr)); 11967555Smsmith} 12067555Smsmith 12167555Smsmith/******************************************************************************** 12267555Smsmith ******************************************************************************** 12367555Smsmith PCI device interface 12467555Smsmith ******************************************************************************** 12567555Smsmith ********************************************************************************/ 12667555Smsmith 12767555Smsmithstatic int twe_probe(device_t dev); 12867555Smsmithstatic int twe_attach(device_t dev); 12967555Smsmithstatic void twe_free(struct twe_softc *sc); 13067555Smsmithstatic int twe_detach(device_t dev); 131123103Spsstatic int twe_shutdown(device_t dev); 13267555Smsmithstatic int twe_suspend(device_t dev); 13367555Smsmithstatic int twe_resume(device_t dev); 13467555Smsmithstatic void twe_pci_intr(void *arg); 13567555Smsmithstatic void twe_intrhook(void *arg); 13667555Smsmith 13767555Smsmithstatic device_method_t twe_methods[] = { 13867555Smsmith /* Device interface */ 13967555Smsmith DEVMETHOD(device_probe, twe_probe), 14067555Smsmith DEVMETHOD(device_attach, twe_attach), 14167555Smsmith DEVMETHOD(device_detach, twe_detach), 14267555Smsmith DEVMETHOD(device_shutdown, twe_shutdown), 14367555Smsmith DEVMETHOD(device_suspend, twe_suspend), 14467555Smsmith DEVMETHOD(device_resume, twe_resume), 14567555Smsmith 146227843Smarius DEVMETHOD_END 14767555Smsmith}; 14867555Smsmith 14967555Smsmithstatic driver_t twe_pci_driver = { 15067555Smsmith "twe", 15167555Smsmith twe_methods, 15267555Smsmith sizeof(struct twe_softc) 15367555Smsmith}; 15467555Smsmith 15567555SmsmithDRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, 0, 0); 15667555Smsmith 15767555Smsmith/******************************************************************************** 15867555Smsmith * Match a 3ware Escalade ATA RAID controller. 15967555Smsmith */ 16067555Smsmithstatic int 16167555Smsmithtwe_probe(device_t dev) 16267555Smsmith{ 16367555Smsmith 16467555Smsmith debug_called(4); 16567555Smsmith 16667555Smsmith if ((pci_get_vendor(dev) == TWE_VENDOR_ID) && 16767684Smsmith ((pci_get_device(dev) == TWE_DEVICE_ID) || 16867684Smsmith (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) { 169123103Sps device_set_desc_copy(dev, TWE_DEVICE_NAME ". Driver version " TWE_DRIVER_VERSION_STRING); 170142880Simp return(BUS_PROBE_DEFAULT); 17167555Smsmith } 17267555Smsmith return(ENXIO); 17367555Smsmith} 17467555Smsmith 17567555Smsmith/******************************************************************************** 17667555Smsmith * Allocate resources, initialise the controller. 17767555Smsmith */ 17867555Smsmithstatic int 17967555Smsmithtwe_attach(device_t dev) 18067555Smsmith{ 18167555Smsmith struct twe_softc *sc; 182239244Sjhb struct sysctl_oid *sysctl_tree; 18367555Smsmith int rid, error; 18467555Smsmith 18567555Smsmith debug_called(4); 18667555Smsmith 18767555Smsmith /* 18867555Smsmith * Initialise the softc structure. 18967555Smsmith */ 19067555Smsmith sc = device_get_softc(dev); 19167555Smsmith sc->twe_dev = dev; 192239244Sjhb mtx_init(&sc->twe_io_lock, "twe I/O", NULL, MTX_DEF); 193239244Sjhb sx_init(&sc->twe_config_lock, "twe config"); 19467555Smsmith 195239244Sjhb /* 196239244Sjhb * XXX: This sysctl tree must stay at hw.tweX rather than using 197239244Sjhb * the device_get_sysctl_tree() created by new-bus because 198239244Sjhb * existing 3rd party binary tools such as tw_cli and 3dm2 use the 199239244Sjhb * existence of this sysctl node to discover controllers. 200239244Sjhb */ 201239244Sjhb sysctl_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 202118508Sps SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 203118508Sps device_get_nameunit(dev), CTLFLAG_RD, 0, ""); 204239244Sjhb if (sysctl_tree == NULL) { 205118508Sps twe_printf(sc, "cannot add sysctl tree node\n"); 206118508Sps return (ENXIO); 207118508Sps } 208239244Sjhb SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(sysctl_tree), 209123103Sps OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0, 210118508Sps "TWE driver version"); 211118508Sps 21267555Smsmith /* 21367555Smsmith * Force the busmaster enable bit on, in case the BIOS forgot. 21467555Smsmith */ 215239244Sjhb pci_enable_busmaster(dev); 21667555Smsmith 21767555Smsmith /* 21867555Smsmith * Allocate the PCI register window. 21967555Smsmith */ 22067555Smsmith rid = TWE_IO_CONFIG_REG; 221127135Snjl if ((sc->twe_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 222127135Snjl RF_ACTIVE)) == NULL) { 22367555Smsmith twe_printf(sc, "can't allocate register window\n"); 22467555Smsmith twe_free(sc); 22567555Smsmith return(ENXIO); 22667555Smsmith } 22767555Smsmith 22867555Smsmith /* 22967555Smsmith * Allocate the parent bus DMA tag appropriate for PCI. 23067555Smsmith */ 231232854Sscottl if (bus_dma_tag_create(bus_get_dma_tag(dev), /* PCI parent */ 23267555Smsmith 1, 0, /* alignment, boundary */ 23367555Smsmith BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 23467555Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 23567555Smsmith NULL, NULL, /* filter, filterarg */ 236280347Smav BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 237280347Smav BUS_SPACE_UNRESTRICTED, /* nsegments */ 23867555Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 239143191Sscottl 0, /* flags */ 240117126Sscottl NULL, /* lockfunc */ 241117126Sscottl NULL, /* lockarg */ 24267555Smsmith &sc->twe_parent_dmat)) { 24367555Smsmith twe_printf(sc, "can't allocate parent DMA tag\n"); 24467555Smsmith twe_free(sc); 24567555Smsmith return(ENOMEM); 24667555Smsmith } 24767555Smsmith 24867555Smsmith /* 24967555Smsmith * Allocate and connect our interrupt. 25067555Smsmith */ 25167555Smsmith rid = 0; 252127135Snjl if ((sc->twe_irq = bus_alloc_resource_any(sc->twe_dev, SYS_RES_IRQ, 253127135Snjl &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 25467555Smsmith twe_printf(sc, "can't allocate interrupt\n"); 25567555Smsmith twe_free(sc); 25667555Smsmith return(ENXIO); 25767555Smsmith } 258239244Sjhb if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE, 259166901Spiso NULL, twe_pci_intr, sc, &sc->twe_intr)) { 26067555Smsmith twe_printf(sc, "can't set up interrupt\n"); 26167555Smsmith twe_free(sc); 26267555Smsmith return(ENXIO); 26367555Smsmith } 26467555Smsmith 26567555Smsmith /* 266118816Sps * Create DMA tag for mapping command's into controller-addressable space. 267118816Sps */ 268118816Sps if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */ 269118816Sps 1, 0, /* alignment, boundary */ 270118816Sps BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 271118816Sps BUS_SPACE_MAXADDR, /* highaddr */ 272118816Sps NULL, NULL, /* filter, filterarg */ 273118816Sps sizeof(TWE_Command) * 274118816Sps TWE_Q_LENGTH, 1, /* maxsize, nsegments */ 275118816Sps BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 276143191Sscottl 0, /* flags */ 277118816Sps NULL, /* lockfunc */ 278118816Sps NULL, /* lockarg */ 279118816Sps &sc->twe_cmd_dmat)) { 280118816Sps twe_printf(sc, "can't allocate data buffer DMA tag\n"); 281118816Sps twe_free(sc); 282118816Sps return(ENOMEM); 283118816Sps } 284118816Sps /* 285118816Sps * Allocate memory and make it available for DMA. 286118816Sps */ 287118816Sps if (bus_dmamem_alloc(sc->twe_cmd_dmat, (void **)&sc->twe_cmd, 288118816Sps BUS_DMA_NOWAIT, &sc->twe_cmdmap)) { 289118816Sps twe_printf(sc, "can't allocate command memory\n"); 290118816Sps return(ENOMEM); 291118816Sps } 292118816Sps bus_dmamap_load(sc->twe_cmd_dmat, sc->twe_cmdmap, sc->twe_cmd, 293118816Sps sizeof(TWE_Command) * TWE_Q_LENGTH, 294118816Sps twe_setup_request_dmamap, sc, 0); 295118816Sps bzero(sc->twe_cmd, sizeof(TWE_Command) * TWE_Q_LENGTH); 296118816Sps 297118816Sps /* 29867555Smsmith * Create DMA tag for mapping objects into controller-addressable space. 29967555Smsmith */ 30069543Smsmith if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */ 30169543Smsmith 1, 0, /* alignment, boundary */ 302118816Sps BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 30367555Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 30467555Smsmith NULL, NULL, /* filter, filterarg */ 305280347Smav (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE,/* maxsize */ 306280347Smav TWE_MAX_SGL_LENGTH, /* nsegments */ 30769543Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 308143191Sscottl BUS_DMA_ALLOCNOW, /* flags */ 309118816Sps busdma_lock_mutex, /* lockfunc */ 310239244Sjhb &sc->twe_io_lock, /* lockarg */ 31167555Smsmith &sc->twe_buffer_dmat)) { 31267555Smsmith twe_printf(sc, "can't allocate data buffer DMA tag\n"); 31367555Smsmith twe_free(sc); 31467555Smsmith return(ENOMEM); 31567555Smsmith } 31667555Smsmith 31767555Smsmith /* 318118816Sps * Create DMA tag for mapping objects into controller-addressable space. 319118816Sps */ 320118816Sps if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */ 321118816Sps 1, 0, /* alignment, boundary */ 322118816Sps BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 323118816Sps BUS_SPACE_MAXADDR, /* highaddr */ 324118816Sps NULL, NULL, /* filter, filterarg */ 325280347Smav DFLTPHYS, 1, /* maxsize, nsegments */ 326118816Sps BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 327143191Sscottl 0, /* flags */ 328118816Sps NULL, /* lockfunc */ 329118816Sps NULL, /* lockarg */ 330118816Sps &sc->twe_immediate_dmat)) { 331118816Sps twe_printf(sc, "can't allocate data buffer DMA tag\n"); 332118816Sps twe_free(sc); 333118816Sps return(ENOMEM); 334118816Sps } 335118816Sps /* 336118816Sps * Allocate memory for requests which cannot sleep or support continuation. 337118816Sps */ 338118816Sps if (bus_dmamem_alloc(sc->twe_immediate_dmat, (void **)&sc->twe_immediate, 339118816Sps BUS_DMA_NOWAIT, &sc->twe_immediate_map)) { 340118816Sps twe_printf(sc, "can't allocate memory for immediate requests\n"); 341118816Sps return(ENOMEM); 342118816Sps } 343118816Sps 344118816Sps /* 34567555Smsmith * Initialise the controller and driver core. 34667555Smsmith */ 347118816Sps if ((error = twe_setup(sc))) { 348118816Sps twe_free(sc); 34967555Smsmith return(error); 350118816Sps } 35167555Smsmith 35267555Smsmith /* 35367555Smsmith * Print some information about the controller and configuration. 35467555Smsmith */ 35567555Smsmith twe_describe_controller(sc); 35667555Smsmith 35767555Smsmith /* 35867555Smsmith * Create the control device. 35967555Smsmith */ 36067555Smsmith sc->twe_dev_t = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev), UID_ROOT, GID_OPERATOR, 36167555Smsmith S_IRUSR | S_IWUSR, "twe%d", device_get_unit(sc->twe_dev)); 36267555Smsmith sc->twe_dev_t->si_drv1 = sc; 36367555Smsmith /* 36467555Smsmith * Schedule ourselves to bring the controller up once interrupts are available. 36567555Smsmith * This isn't strictly necessary, since we disable interrupts while probing the 36667555Smsmith * controller, but it is more in keeping with common practice for other disk 36767555Smsmith * devices. 36867555Smsmith */ 36967555Smsmith sc->twe_ich.ich_func = twe_intrhook; 37067555Smsmith sc->twe_ich.ich_arg = sc; 37167555Smsmith if (config_intrhook_establish(&sc->twe_ich) != 0) { 37267555Smsmith twe_printf(sc, "can't establish configuration hook\n"); 37367555Smsmith twe_free(sc); 37467555Smsmith return(ENXIO); 37567555Smsmith } 37667555Smsmith 37767555Smsmith return(0); 37867555Smsmith} 37967555Smsmith 38067555Smsmith/******************************************************************************** 38167555Smsmith * Free all of the resources associated with (sc). 38267555Smsmith * 38367555Smsmith * Should not be called if the controller is active. 38467555Smsmith */ 38567555Smsmithstatic void 38667555Smsmithtwe_free(struct twe_softc *sc) 38767555Smsmith{ 38867555Smsmith struct twe_request *tr; 38967555Smsmith 39067555Smsmith debug_called(4); 39167555Smsmith 39267555Smsmith /* throw away any command buffers */ 39367555Smsmith while ((tr = twe_dequeue_free(sc)) != NULL) 39467555Smsmith twe_free_request(tr); 39567555Smsmith 396118816Sps if (sc->twe_cmd != NULL) { 397118816Sps bus_dmamap_unload(sc->twe_cmd_dmat, sc->twe_cmdmap); 398118816Sps bus_dmamem_free(sc->twe_cmd_dmat, sc->twe_cmd, sc->twe_cmdmap); 399118816Sps } 400118816Sps 401118816Sps if (sc->twe_immediate != NULL) { 402118816Sps bus_dmamap_unload(sc->twe_immediate_dmat, sc->twe_immediate_map); 403118816Sps bus_dmamem_free(sc->twe_immediate_dmat, sc->twe_immediate, 404118816Sps sc->twe_immediate_map); 405118816Sps } 406118816Sps 407118816Sps if (sc->twe_immediate_dmat) 408118816Sps bus_dma_tag_destroy(sc->twe_immediate_dmat); 409118816Sps 41067555Smsmith /* destroy the data-transfer DMA tag */ 41167555Smsmith if (sc->twe_buffer_dmat) 41267555Smsmith bus_dma_tag_destroy(sc->twe_buffer_dmat); 41367555Smsmith 41467555Smsmith /* disconnect the interrupt handler */ 41567555Smsmith if (sc->twe_intr) 41667555Smsmith bus_teardown_intr(sc->twe_dev, sc->twe_irq, sc->twe_intr); 41767555Smsmith if (sc->twe_irq != NULL) 41867555Smsmith bus_release_resource(sc->twe_dev, SYS_RES_IRQ, 0, sc->twe_irq); 41967555Smsmith 42067555Smsmith /* destroy the parent DMA tag */ 42167555Smsmith if (sc->twe_parent_dmat) 42267555Smsmith bus_dma_tag_destroy(sc->twe_parent_dmat); 42367555Smsmith 42467555Smsmith /* release the register window mapping */ 42567555Smsmith if (sc->twe_io != NULL) 42667555Smsmith bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io); 42767555Smsmith 42867555Smsmith /* destroy control device */ 429130585Sphk if (sc->twe_dev_t != (struct cdev *)NULL) 43067555Smsmith destroy_dev(sc->twe_dev_t); 431118508Sps 432239244Sjhb sx_destroy(&sc->twe_config_lock); 433239244Sjhb mtx_destroy(&sc->twe_io_lock); 43467555Smsmith} 43567555Smsmith 43667555Smsmith/******************************************************************************** 43767555Smsmith * Disconnect from the controller completely, in preparation for unload. 43867555Smsmith */ 43967555Smsmithstatic int 44067555Smsmithtwe_detach(device_t dev) 44167555Smsmith{ 44267555Smsmith struct twe_softc *sc = device_get_softc(dev); 44367555Smsmith 44467555Smsmith debug_called(4); 44567555Smsmith 446239244Sjhb TWE_IO_LOCK(sc); 447239244Sjhb if (sc->twe_state & TWE_STATE_OPEN) { 448239244Sjhb TWE_IO_UNLOCK(sc); 449239244Sjhb return (EBUSY); 450239244Sjhb } 451239244Sjhb sc->twe_state |= TWE_STATE_DETACHING; 452239244Sjhb TWE_IO_UNLOCK(sc); 45367555Smsmith 45467555Smsmith /* 45567555Smsmith * Shut the controller down. 45667555Smsmith */ 457239244Sjhb if (twe_shutdown(dev)) { 458239244Sjhb TWE_IO_LOCK(sc); 459239244Sjhb sc->twe_state &= ~TWE_STATE_DETACHING; 460239244Sjhb TWE_IO_UNLOCK(sc); 461239244Sjhb return (EBUSY); 462239244Sjhb } 46367555Smsmith 46467555Smsmith twe_free(sc); 46567555Smsmith 466239244Sjhb return(0); 46767555Smsmith} 46867555Smsmith 46967555Smsmith/******************************************************************************** 47067555Smsmith * Bring the controller down to a dormant state and detach all child devices. 47167555Smsmith * 47267555Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't 47367555Smsmith * allow shutdown if any device is open. 47467555Smsmith */ 475123103Spsstatic int 47667555Smsmithtwe_shutdown(device_t dev) 47767555Smsmith{ 47867555Smsmith struct twe_softc *sc = device_get_softc(dev); 479239244Sjhb int i, error = 0; 48067555Smsmith 48167555Smsmith debug_called(4); 48267555Smsmith 48367555Smsmith /* 48467555Smsmith * Delete all our child devices. 48567555Smsmith */ 486239244Sjhb TWE_CONFIG_LOCK(sc); 48767555Smsmith for (i = 0; i < TWE_MAX_UNITS; i++) { 488123103Sps if (sc->twe_drive[i].td_disk != 0) { 489239244Sjhb if ((error = twe_detach_drive(sc, i)) != 0) { 490239244Sjhb TWE_CONFIG_UNLOCK(sc); 491239244Sjhb return (error); 492239244Sjhb } 493123103Sps } 49467555Smsmith } 495239244Sjhb TWE_CONFIG_UNLOCK(sc); 49667555Smsmith 49767555Smsmith /* 49867555Smsmith * Bring the controller down. 49967555Smsmith */ 500239244Sjhb TWE_IO_LOCK(sc); 50167555Smsmith twe_deinit(sc); 502239244Sjhb TWE_IO_UNLOCK(sc); 50367555Smsmith 504239244Sjhb return(0); 50567555Smsmith} 50667555Smsmith 50767555Smsmith/******************************************************************************** 50867555Smsmith * Bring the controller to a quiescent state, ready for system suspend. 50967555Smsmith */ 51067555Smsmithstatic int 51167555Smsmithtwe_suspend(device_t dev) 51267555Smsmith{ 51367555Smsmith struct twe_softc *sc = device_get_softc(dev); 51467555Smsmith 51567555Smsmith debug_called(4); 51667555Smsmith 517239244Sjhb TWE_IO_LOCK(sc); 51867555Smsmith sc->twe_state |= TWE_STATE_SUSPEND; 51967555Smsmith 52067555Smsmith twe_disable_interrupts(sc); 521239244Sjhb TWE_IO_UNLOCK(sc); 52267555Smsmith 52367555Smsmith return(0); 52467555Smsmith} 52567555Smsmith 52667555Smsmith/******************************************************************************** 52767555Smsmith * Bring the controller back to a state ready for operation. 52867555Smsmith */ 52967555Smsmithstatic int 53067555Smsmithtwe_resume(device_t dev) 53167555Smsmith{ 53267555Smsmith struct twe_softc *sc = device_get_softc(dev); 53367555Smsmith 53467555Smsmith debug_called(4); 53567555Smsmith 536239244Sjhb TWE_IO_LOCK(sc); 53767555Smsmith sc->twe_state &= ~TWE_STATE_SUSPEND; 53867555Smsmith twe_enable_interrupts(sc); 539239244Sjhb TWE_IO_UNLOCK(sc); 54067555Smsmith 54167555Smsmith return(0); 54267555Smsmith} 54367555Smsmith 54467555Smsmith/******************************************************************************* 54567555Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 54667555Smsmith * status. 54767555Smsmith */ 54867555Smsmithstatic void 54967555Smsmithtwe_pci_intr(void *arg) 55067555Smsmith{ 551239244Sjhb struct twe_softc *sc = arg; 552239244Sjhb 553239244Sjhb TWE_IO_LOCK(sc); 554239244Sjhb twe_intr(sc); 555239244Sjhb TWE_IO_UNLOCK(sc); 55667555Smsmith} 55767555Smsmith 55867555Smsmith/******************************************************************************** 55967555Smsmith * Delayed-startup hook 56067555Smsmith */ 56167555Smsmithstatic void 56267555Smsmithtwe_intrhook(void *arg) 56367555Smsmith{ 56467555Smsmith struct twe_softc *sc = (struct twe_softc *)arg; 56567555Smsmith 56667555Smsmith /* pull ourselves off the intrhook chain */ 56767555Smsmith config_intrhook_disestablish(&sc->twe_ich); 56867555Smsmith 56967555Smsmith /* call core startup routine */ 57067555Smsmith twe_init(sc); 57167555Smsmith} 57267555Smsmith 57367555Smsmith/******************************************************************************** 57467555Smsmith * Given a detected drive, attach it to the bio interface. 57567555Smsmith * 576123103Sps * This is called from twe_add_unit. 57767555Smsmith */ 578123103Spsint 57967555Smsmithtwe_attach_drive(struct twe_softc *sc, struct twe_drive *dr) 58067555Smsmith{ 58167555Smsmith char buf[80]; 58267555Smsmith int error; 58367555Smsmith 584239244Sjhb mtx_lock(&Giant); 58567555Smsmith dr->td_disk = device_add_child(sc->twe_dev, NULL, -1); 58667555Smsmith if (dr->td_disk == NULL) { 587239244Sjhb mtx_unlock(&Giant); 588123103Sps twe_printf(sc, "Cannot add unit\n"); 589123103Sps return (EIO); 59067555Smsmith } 59167555Smsmith device_set_ivars(dr->td_disk, dr); 59267555Smsmith 59367555Smsmith /* 59467555Smsmith * XXX It would make sense to test the online/initialising bits, but they seem to be 59567555Smsmith * always set... 59667555Smsmith */ 597118508Sps sprintf(buf, "Unit %d, %s, %s", 598123103Sps dr->td_twe_unit, 599118508Sps twe_describe_code(twe_table_unittype, dr->td_type), 60067555Smsmith twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK)); 60167555Smsmith device_set_desc_copy(dr->td_disk, buf); 60267555Smsmith 603239244Sjhb error = device_probe_and_attach(dr->td_disk); 604239244Sjhb mtx_unlock(&Giant); 605239244Sjhb if (error != 0) { 606123103Sps twe_printf(sc, "Cannot attach unit to controller. error = %d\n", error); 607123103Sps return (EIO); 608123103Sps } 609123103Sps return (0); 61067555Smsmith} 61167555Smsmith 61267555Smsmith/******************************************************************************** 613118508Sps * Detach the specified unit if it exsists 614118508Sps * 615118508Sps * This is called from twe_del_unit. 616118508Sps */ 617123103Spsint 618118508Spstwe_detach_drive(struct twe_softc *sc, int unit) 619118508Sps{ 620123103Sps int error = 0; 621118508Sps 622239244Sjhb TWE_CONFIG_ASSERT_LOCKED(sc); 623239244Sjhb mtx_lock(&Giant); 624239244Sjhb error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk); 625239244Sjhb mtx_unlock(&Giant); 626239244Sjhb if (error != 0) { 627123103Sps twe_printf(sc, "failed to delete unit %d\n", unit); 628123103Sps return(error); 629118508Sps } 630123103Sps bzero(&sc->twe_drive[unit], sizeof(sc->twe_drive[unit])); 631123103Sps return(error); 632118508Sps} 633118508Sps 634118508Sps/******************************************************************************** 63591790Smsmith * Clear a PCI parity error. 63691790Smsmith */ 63791790Smsmithvoid 63891790Smsmithtwe_clear_pci_parity_error(struct twe_softc *sc) 63991790Smsmith{ 64091790Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PARITY_ERROR); 64191790Smsmith pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PARITY_ERROR, 2); 64291790Smsmith} 64391790Smsmith 64491790Smsmith/******************************************************************************** 64591790Smsmith * Clear a PCI abort. 64691790Smsmith */ 64791790Smsmithvoid 64891790Smsmithtwe_clear_pci_abort(struct twe_softc *sc) 64991790Smsmith{ 65091790Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PCI_ABORT); 65191790Smsmith pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PCI_ABORT, 2); 65291790Smsmith} 65391790Smsmith 65491790Smsmith/******************************************************************************** 65567555Smsmith ******************************************************************************** 65667555Smsmith Disk device 65767555Smsmith ******************************************************************************** 65867555Smsmith ********************************************************************************/ 65967555Smsmith 66067555Smsmith/* 66167555Smsmith * Disk device softc 66267555Smsmith */ 663123103Spsstruct twed_softc 66467555Smsmith{ 66567555Smsmith device_t twed_dev; 66667555Smsmith struct twe_softc *twed_controller; /* parent device softc */ 66767555Smsmith struct twe_drive *twed_drive; /* drive data in parent softc */ 668125975Sphk struct disk *twed_disk; /* generic disk handle */ 66967555Smsmith}; 67067555Smsmith 67167555Smsmith/* 67267555Smsmith * Disk device bus interface 67367555Smsmith */ 67467555Smsmithstatic int twed_probe(device_t dev); 67567555Smsmithstatic int twed_attach(device_t dev); 67667555Smsmithstatic int twed_detach(device_t dev); 67767555Smsmith 67867555Smsmithstatic device_method_t twed_methods[] = { 67967555Smsmith DEVMETHOD(device_probe, twed_probe), 68067555Smsmith DEVMETHOD(device_attach, twed_attach), 68167555Smsmith DEVMETHOD(device_detach, twed_detach), 68267555Smsmith { 0, 0 } 68367555Smsmith}; 68467555Smsmith 68567555Smsmithstatic driver_t twed_driver = { 68667555Smsmith "twed", 68767555Smsmith twed_methods, 68867555Smsmith sizeof(struct twed_softc) 68967555Smsmith}; 69067555Smsmith 69167555Smsmithstatic devclass_t twed_devclass; 69267555SmsmithDRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0); 69367555Smsmith 69467555Smsmith/* 69567555Smsmith * Disk device control interface. 69667555Smsmith */ 69767555Smsmith 69867555Smsmith/******************************************************************************** 69967555Smsmith * Handle open from generic layer. 70067555Smsmith * 70167555Smsmith * Note that this is typically only called by the diskslice code, and not 70267555Smsmith * for opens on subdevices (eg. slices, partitions). 70367555Smsmith */ 70467555Smsmithstatic int 705111471Sphktwed_open(struct disk *dp) 70667555Smsmith{ 707111471Sphk struct twed_softc *sc = (struct twed_softc *)dp->d_drv1; 70867555Smsmith 70967555Smsmith debug_called(4); 71067555Smsmith 71167555Smsmith if (sc == NULL) 71267555Smsmith return (ENXIO); 71367555Smsmith 71467555Smsmith /* check that the controller is up and running */ 71567555Smsmith if (sc->twed_controller->twe_state & TWE_STATE_SHUTDOWN) 71667555Smsmith return(ENXIO); 71767555Smsmith 71867555Smsmith return (0); 71967555Smsmith} 72067555Smsmith 72167555Smsmith/******************************************************************************** 72267555Smsmith * Handle an I/O request. 72367555Smsmith */ 72467555Smsmithstatic void 725240209Sjhbtwed_strategy(struct bio *bp) 72667555Smsmith{ 727240209Sjhb struct twed_softc *sc = bp->bio_disk->d_drv1; 72867555Smsmith 72967555Smsmith debug_called(4); 73067555Smsmith 731123103Sps bp->bio_driver1 = &sc->twed_drive->td_twe_unit; 73269543Smsmith TWED_BIO_IN; 73369543Smsmith 73467555Smsmith /* bogus disk? */ 735123103Sps if (sc == NULL || sc->twed_drive->td_disk == NULL) { 736240209Sjhb bp->bio_error = EINVAL; 737240209Sjhb bp->bio_flags |= BIO_ERROR; 73869543Smsmith printf("twe: bio for invalid disk!\n"); 739240209Sjhb biodone(bp); 74069543Smsmith TWED_BIO_OUT; 74167555Smsmith return; 74267555Smsmith } 74367555Smsmith 74469543Smsmith /* queue the bio on the controller */ 745239244Sjhb TWE_IO_LOCK(sc->twed_controller); 74669543Smsmith twe_enqueue_bio(sc->twed_controller, bp); 74769543Smsmith 74869543Smsmith /* poke the controller to start I/O */ 74969543Smsmith twe_startio(sc->twed_controller); 750239244Sjhb TWE_IO_UNLOCK(sc->twed_controller); 75167555Smsmith return; 75267555Smsmith} 75367555Smsmith 75467555Smsmith/******************************************************************************** 75569543Smsmith * System crashdump support 75669543Smsmith */ 757105215Sphkstatic int 758111220Sphktwed_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 75969543Smsmith{ 760111220Sphk struct twed_softc *twed_sc; 761111220Sphk struct twe_softc *twe_sc; 76269543Smsmith int error; 763111220Sphk struct disk *dp; 76469543Smsmith 765111220Sphk dp = arg; 766111471Sphk twed_sc = (struct twed_softc *)dp->d_drv1; 767126115Scperciva if (twed_sc == NULL) 768126115Scperciva return(ENXIO); 769111220Sphk twe_sc = (struct twe_softc *)twed_sc->twed_controller; 77069543Smsmith 771110481Sps if (length > 0) { 772123103Sps if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit, offset / TWE_BLOCK_SIZE, virtual, length / TWE_BLOCK_SIZE)) != 0) 77369543Smsmith return(error); 77469543Smsmith } 77569543Smsmith return(0); 77669543Smsmith} 77769543Smsmith 77869543Smsmith/******************************************************************************** 77967555Smsmith * Handle completion of an I/O request. 78067555Smsmith */ 78167555Smsmithvoid 782240209Sjhbtwed_intr(struct bio *bp) 78367555Smsmith{ 78467555Smsmith debug_called(4); 78567555Smsmith 78667555Smsmith /* if no error, transfer completed */ 787240209Sjhb if (!(bp->bio_flags & BIO_ERROR)) 788240209Sjhb bp->bio_resid = 0; 78967555Smsmith 790240209Sjhb biodone(bp); 79169543Smsmith TWED_BIO_OUT; 79267555Smsmith} 79367555Smsmith 79467555Smsmith/******************************************************************************** 79567555Smsmith * Default probe stub. 79667555Smsmith */ 79767555Smsmithstatic int 79867555Smsmithtwed_probe(device_t dev) 79967555Smsmith{ 80067555Smsmith return (0); 80167555Smsmith} 80267555Smsmith 80367555Smsmith/******************************************************************************** 80467555Smsmith * Attach a unit to the controller. 80567555Smsmith */ 80667555Smsmithstatic int 80767555Smsmithtwed_attach(device_t dev) 80867555Smsmith{ 80967555Smsmith struct twed_softc *sc; 81067555Smsmith device_t parent; 81167555Smsmith 81267555Smsmith debug_called(4); 81367555Smsmith 81467555Smsmith /* initialise our softc */ 81567555Smsmith sc = device_get_softc(dev); 81667555Smsmith parent = device_get_parent(dev); 81767555Smsmith sc->twed_controller = (struct twe_softc *)device_get_softc(parent); 81867555Smsmith sc->twed_drive = device_get_ivars(dev); 81967555Smsmith sc->twed_dev = dev; 82067555Smsmith 82167555Smsmith /* report the drive */ 82267555Smsmith twed_printf(sc, "%uMB (%u sectors)\n", 82367555Smsmith sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE), 82467555Smsmith sc->twed_drive->td_size); 82567555Smsmith 82667555Smsmith /* attach a generic disk device to ourselves */ 827111471Sphk 828123103Sps sc->twed_drive->td_sys_unit = device_get_unit(dev); 829111471Sphk 830125975Sphk sc->twed_disk = disk_alloc(); 831125975Sphk sc->twed_disk->d_open = twed_open; 832125975Sphk sc->twed_disk->d_strategy = twed_strategy; 833125975Sphk sc->twed_disk->d_dump = (dumper_t *)twed_dump; 834125975Sphk sc->twed_disk->d_name = "twed"; 835125975Sphk sc->twed_disk->d_drv1 = sc; 836125975Sphk sc->twed_disk->d_maxsize = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE; 837125975Sphk sc->twed_disk->d_sectorsize = TWE_BLOCK_SIZE; 838125975Sphk sc->twed_disk->d_mediasize = TWE_BLOCK_SIZE * (off_t)sc->twed_drive->td_size; 839200991Smav if (sc->twed_drive->td_type == TWE_UD_CONFIG_RAID0 || 840200991Smav sc->twed_drive->td_type == TWE_UD_CONFIG_RAID5 || 841200991Smav sc->twed_drive->td_type == TWE_UD_CONFIG_RAID10) { 842200991Smav sc->twed_disk->d_stripesize = 843200991Smav TWE_BLOCK_SIZE << sc->twed_drive->td_stripe; 844200991Smav sc->twed_disk->d_stripeoffset = 0; 845200991Smav } 846125975Sphk sc->twed_disk->d_fwsectors = sc->twed_drive->td_sectors; 847125975Sphk sc->twed_disk->d_fwheads = sc->twed_drive->td_heads; 848125975Sphk sc->twed_disk->d_unit = sc->twed_drive->td_sys_unit; 849125975Sphk 850125975Sphk disk_create(sc->twed_disk, DISK_VERSION); 851125975Sphk 85267555Smsmith /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */ 85367555Smsmith 85467555Smsmith return (0); 85567555Smsmith} 85667555Smsmith 85767555Smsmith/******************************************************************************** 85867555Smsmith * Disconnect ourselves from the system. 85967555Smsmith */ 86067555Smsmithstatic int 86167555Smsmithtwed_detach(device_t dev) 86267555Smsmith{ 86367555Smsmith struct twed_softc *sc = (struct twed_softc *)device_get_softc(dev); 86467555Smsmith 86567555Smsmith debug_called(4); 86667555Smsmith 867125975Sphk if (sc->twed_disk->d_flags & DISKFLAG_OPEN) 86867555Smsmith return(EBUSY); 86967555Smsmith 870125975Sphk disk_destroy(sc->twed_disk); 871123103Sps 87267555Smsmith return(0); 87367555Smsmith} 87467555Smsmith 87567555Smsmith/******************************************************************************** 87667555Smsmith ******************************************************************************** 87767555Smsmith Misc 87867555Smsmith ******************************************************************************** 87967555Smsmith ********************************************************************************/ 88067555Smsmith 88167555Smsmith/******************************************************************************** 88267555Smsmith * Allocate a command buffer 88367555Smsmith */ 884227293Sedstatic MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe_commands", "twe commands"); 88567555Smsmith 88667555Smsmithstruct twe_request * 887118816Spstwe_allocate_request(struct twe_softc *sc, int tag) 88867555Smsmith{ 88967555Smsmith struct twe_request *tr; 89067555Smsmith 891239244Sjhb tr = malloc(sizeof(struct twe_request), TWE_MALLOC_CLASS, M_WAITOK | M_ZERO); 89267555Smsmith tr->tr_sc = sc; 893118816Sps tr->tr_tag = tag; 89467555Smsmith if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) { 89567555Smsmith twe_free_request(tr); 896118816Sps twe_printf(sc, "unable to allocate dmamap for tag %d\n", tag); 89767555Smsmith return(NULL); 89867555Smsmith } 89967555Smsmith return(tr); 90067555Smsmith} 90167555Smsmith 90267555Smsmith/******************************************************************************** 90367555Smsmith * Permanently discard a command buffer. 90467555Smsmith */ 90567555Smsmithvoid 90667555Smsmithtwe_free_request(struct twe_request *tr) 90767555Smsmith{ 90867555Smsmith struct twe_softc *sc = tr->tr_sc; 90967555Smsmith 91067555Smsmith debug_called(4); 91167555Smsmith 91267555Smsmith bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap); 91367555Smsmith free(tr, TWE_MALLOC_CLASS); 91467555Smsmith} 91567555Smsmith 91667555Smsmith/******************************************************************************** 91767555Smsmith * Map/unmap (tr)'s command and data in the controller's addressable space. 91867555Smsmith * 91967555Smsmith * These routines ensure that the data which the controller is going to try to 92067555Smsmith * access is actually visible to the controller, in a machine-independant 92180202Skris * fashion. Due to a hardware limitation, I/O buffers must be 512-byte aligned 92267555Smsmith * and we take care of that here as well. 92367555Smsmith */ 92467555Smsmithstatic void 925118508Spstwe_fillin_sgl(TWE_SG_Entry *sgl, bus_dma_segment_t *segs, int nsegments, int max_sgl) 926118508Sps{ 927118508Sps int i; 928118508Sps 929118508Sps for (i = 0; i < nsegments; i++) { 930118508Sps sgl[i].address = segs[i].ds_addr; 931118508Sps sgl[i].length = segs[i].ds_len; 932118508Sps } 933118508Sps for (; i < max_sgl; i++) { /* XXX necessary? */ 934118508Sps sgl[i].address = 0; 935118508Sps sgl[i].length = 0; 936118508Sps } 937118508Sps} 938118508Sps 939118508Spsstatic void 94067555Smsmithtwe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 94167555Smsmith{ 94267555Smsmith struct twe_request *tr = (struct twe_request *)arg; 943118816Sps struct twe_softc *sc = tr->tr_sc; 944118816Sps TWE_Command *cmd = TWE_FIND_COMMAND(tr); 94567555Smsmith 94667555Smsmith debug_called(4); 94767555Smsmith 948118816Sps if (tr->tr_flags & TWE_CMD_MAPPED) 949118816Sps panic("already mapped command"); 950118816Sps 951118816Sps tr->tr_flags |= TWE_CMD_MAPPED; 952118816Sps 953127415Svkashyap if (tr->tr_flags & TWE_CMD_IN_PROGRESS) 954127415Svkashyap sc->twe_state &= ~TWE_STATE_FRZN; 95567555Smsmith /* save base of first segment in command (applicable if there only one segment) */ 95667555Smsmith tr->tr_dataphys = segs[0].ds_addr; 95767555Smsmith 95867555Smsmith /* correct command size for s/g list size */ 959118816Sps cmd->generic.size += 2 * nsegments; 96067555Smsmith 96167555Smsmith /* 96267555Smsmith * Due to the fact that parameter and I/O commands have the scatter/gather list in 96367555Smsmith * different places, we need to determine which sort of command this actually is 96467555Smsmith * before we can populate it correctly. 96567555Smsmith */ 96667555Smsmith switch(cmd->generic.opcode) { 96767555Smsmith case TWE_OP_GET_PARAM: 96867555Smsmith case TWE_OP_SET_PARAM: 96967555Smsmith cmd->generic.sgl_offset = 2; 970118508Sps twe_fillin_sgl(&cmd->param.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); 97167555Smsmith break; 97267555Smsmith case TWE_OP_READ: 97367555Smsmith case TWE_OP_WRITE: 97467555Smsmith cmd->generic.sgl_offset = 3; 975118508Sps twe_fillin_sgl(&cmd->io.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); 97667555Smsmith break; 977118508Sps case TWE_OP_ATA_PASSTHROUGH: 978118508Sps cmd->generic.sgl_offset = 5; 979118508Sps twe_fillin_sgl(&cmd->ata.sgl[0], segs, nsegments, TWE_MAX_ATA_SGL_LENGTH); 980118508Sps break; 98167555Smsmith default: 982118508Sps /* 983118508Sps * Fall back to what the linux driver does. 984118508Sps * Do this because the API may send an opcode 985118508Sps * the driver knows nothing about and this will 986118508Sps * at least stop PCIABRT's from hosing us. 987118508Sps */ 988118508Sps switch (cmd->generic.sgl_offset) { 989118508Sps case 2: 990118508Sps twe_fillin_sgl(&cmd->param.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); 991118508Sps break; 992118508Sps case 3: 993118508Sps twe_fillin_sgl(&cmd->io.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); 994118508Sps break; 995118508Sps case 5: 996118508Sps twe_fillin_sgl(&cmd->ata.sgl[0], segs, nsegments, TWE_MAX_ATA_SGL_LENGTH); 997118508Sps break; 998118508Sps } 99967555Smsmith } 1000118816Sps 1001118816Sps if (tr->tr_flags & TWE_CMD_DATAIN) { 1002118816Sps if (tr->tr_flags & TWE_CMD_IMMEDIATE) { 1003118816Sps bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map, 1004118816Sps BUS_DMASYNC_PREREAD); 1005118816Sps } else { 1006118816Sps bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, 1007118816Sps BUS_DMASYNC_PREREAD); 1008118816Sps } 1009118816Sps } 1010118816Sps 1011118816Sps if (tr->tr_flags & TWE_CMD_DATAOUT) { 1012118816Sps /* 1013118816Sps * if we're using an alignment buffer, and we're writing data 1014118816Sps * copy the real data out 1015118816Sps */ 1016118816Sps if (tr->tr_flags & TWE_CMD_ALIGNBUF) 1017118816Sps bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length); 1018118816Sps 1019118816Sps if (tr->tr_flags & TWE_CMD_IMMEDIATE) { 1020118816Sps bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map, 1021118816Sps BUS_DMASYNC_PREWRITE); 1022118816Sps } else { 1023118816Sps bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, 1024118816Sps BUS_DMASYNC_PREWRITE); 1025118816Sps } 1026118816Sps } 1027118816Sps 1028130358Svkashyap if (twe_start(tr) == EBUSY) { 1029130358Svkashyap tr->tr_sc->twe_state |= TWE_STATE_CTLR_BUSY; 1030118846Sps twe_requeue_ready(tr); 1031130358Svkashyap } 103267555Smsmith} 103367555Smsmith 103467555Smsmithstatic void 103567555Smsmithtwe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 103667555Smsmith{ 1037118816Sps struct twe_softc *sc = (struct twe_softc *)arg; 103867555Smsmith 103967555Smsmith debug_called(4); 104067555Smsmith 104167555Smsmith /* command can't cross a page boundary */ 1042118816Sps sc->twe_cmdphys = segs[0].ds_addr; 104367555Smsmith} 104467555Smsmith 1045118816Spsint 104667555Smsmithtwe_map_request(struct twe_request *tr) 104767555Smsmith{ 104867555Smsmith struct twe_softc *sc = tr->tr_sc; 1049118816Sps int error = 0; 105067555Smsmith 105167555Smsmith debug_called(4); 105267555Smsmith 1053239244Sjhb if (!dumping) 1054239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 1055130358Svkashyap if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) { 1056130358Svkashyap twe_requeue_ready(tr); 1057118816Sps return (EBUSY); 1058130358Svkashyap } 105967555Smsmith 1060118816Sps bus_dmamap_sync(sc->twe_cmd_dmat, sc->twe_cmdmap, BUS_DMASYNC_PREWRITE); 106167555Smsmith 106267555Smsmith /* 106367555Smsmith * If the command involves data, map that too. 106467555Smsmith */ 1065118816Sps if (tr->tr_data != NULL && ((tr->tr_flags & TWE_CMD_MAPPED) == 0)) { 106667555Smsmith 106767555Smsmith /* 106867555Smsmith * Data must be 64-byte aligned; allocate a fixup buffer if it's not. 106967555Smsmith */ 107067555Smsmith if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) { 107167555Smsmith tr->tr_realdata = tr->tr_data; /* save pointer to 'real' data */ 107267555Smsmith tr->tr_flags |= TWE_CMD_ALIGNBUF; 1073127415Svkashyap tr->tr_data = malloc(tr->tr_length, TWE_MALLOC_CLASS, M_NOWAIT); 1074127415Svkashyap if (tr->tr_data == NULL) { 1075127415Svkashyap twe_printf(sc, "%s: malloc failed\n", __func__); 1076127415Svkashyap tr->tr_data = tr->tr_realdata; /* restore original data pointer */ 1077127415Svkashyap return(ENOMEM); 1078127415Svkashyap } 107967555Smsmith } 108067555Smsmith 108167555Smsmith /* 108267555Smsmith * Map the data buffer into bus space and build the s/g list. 1083127415Svkashyap */ 1084118816Sps if (tr->tr_flags & TWE_CMD_IMMEDIATE) { 1085127415Svkashyap error = bus_dmamap_load(sc->twe_immediate_dmat, sc->twe_immediate_map, sc->twe_immediate, 1086141492Sscottl tr->tr_length, twe_setup_data_dmamap, tr, BUS_DMA_NOWAIT); 1087118816Sps } else { 1088118816Sps error = bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length, 1089118816Sps twe_setup_data_dmamap, tr, 0); 109067555Smsmith } 1091118816Sps if (error == EINPROGRESS) { 1092127415Svkashyap tr->tr_flags |= TWE_CMD_IN_PROGRESS; 1093118816Sps sc->twe_state |= TWE_STATE_FRZN; 1094118816Sps error = 0; 1095118816Sps } 1096118816Sps } else 1097127415Svkashyap if ((error = twe_start(tr)) == EBUSY) { 1098130358Svkashyap sc->twe_state |= TWE_STATE_CTLR_BUSY; 1099127415Svkashyap twe_requeue_ready(tr); 1100127415Svkashyap } 1101118816Sps 1102118816Sps return(error); 110367555Smsmith} 110467555Smsmith 110567555Smsmithvoid 110667555Smsmithtwe_unmap_request(struct twe_request *tr) 110767555Smsmith{ 110867555Smsmith struct twe_softc *sc = tr->tr_sc; 110967555Smsmith 111067555Smsmith debug_called(4); 111167555Smsmith 1112239244Sjhb if (!dumping) 1113239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 1114118816Sps bus_dmamap_sync(sc->twe_cmd_dmat, sc->twe_cmdmap, BUS_DMASYNC_POSTWRITE); 111567555Smsmith 111667555Smsmith /* 111767555Smsmith * If the command involved data, unmap that too. 111867555Smsmith */ 111967555Smsmith if (tr->tr_data != NULL) { 112067555Smsmith if (tr->tr_flags & TWE_CMD_DATAIN) { 1121118816Sps if (tr->tr_flags & TWE_CMD_IMMEDIATE) { 1122118816Sps bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map, 1123118816Sps BUS_DMASYNC_POSTREAD); 1124118816Sps } else { 1125118816Sps bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, 1126118816Sps BUS_DMASYNC_POSTREAD); 1127118816Sps } 1128118816Sps 112967555Smsmith /* if we're using an alignment buffer, and we're reading data, copy the real data in */ 113067555Smsmith if (tr->tr_flags & TWE_CMD_ALIGNBUF) 113167555Smsmith bcopy(tr->tr_data, tr->tr_realdata, tr->tr_length); 113267555Smsmith } 1133118816Sps if (tr->tr_flags & TWE_CMD_DATAOUT) { 1134118816Sps if (tr->tr_flags & TWE_CMD_IMMEDIATE) { 1135118816Sps bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map, 1136118816Sps BUS_DMASYNC_POSTWRITE); 1137118816Sps } else { 1138118816Sps bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, 1139118816Sps BUS_DMASYNC_POSTWRITE); 1140118816Sps } 1141118816Sps } 114267555Smsmith 1143118816Sps if (tr->tr_flags & TWE_CMD_IMMEDIATE) { 1144118816Sps bus_dmamap_unload(sc->twe_immediate_dmat, sc->twe_immediate_map); 1145118816Sps } else { 1146118816Sps bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap); 1147118816Sps } 114867555Smsmith } 114967555Smsmith 115067555Smsmith /* free alignment buffer if it was used */ 115167555Smsmith if (tr->tr_flags & TWE_CMD_ALIGNBUF) { 115267555Smsmith free(tr->tr_data, TWE_MALLOC_CLASS); 115367555Smsmith tr->tr_data = tr->tr_realdata; /* restore 'real' data pointer */ 115467555Smsmith } 115567555Smsmith} 115667555Smsmith 115767555Smsmith#ifdef TWE_DEBUG 1158127415Svkashyapvoid twe_report(void); 115967555Smsmith/******************************************************************************** 116067555Smsmith * Print current controller status, call from DDB. 116167555Smsmith */ 116267555Smsmithvoid 116367555Smsmithtwe_report(void) 116467555Smsmith{ 116567555Smsmith struct twe_softc *sc; 1166239244Sjhb int i; 116767555Smsmith 116867555Smsmith for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++) 116967555Smsmith twe_print_controller(sc); 117069543Smsmith printf("twed: total bio count in %u out %u\n", twed_bio_in, twed_bio_out); 117167555Smsmith} 117267555Smsmith#endif 1173