twe_freebsd.c revision 69543
167555Smsmith/*- 267555Smsmith * Copyright (c) 2000 Michael Smith 367555Smsmith * Copyright (c) 2000 BSDi 467555Smsmith * All rights reserved. 567555Smsmith * 667555Smsmith * Redistribution and use in source and binary forms, with or without 767555Smsmith * modification, are permitted provided that the following conditions 867555Smsmith * are met: 967555Smsmith * 1. Redistributions of source code must retain the above copyright 1067555Smsmith * notice, this list of conditions and the following disclaimer. 1167555Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1267555Smsmith * notice, this list of conditions and the following disclaimer in the 1367555Smsmith * documentation and/or other materials provided with the distribution. 1467555Smsmith * 1567555Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667555Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767555Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1867555Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1967555Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067555Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167555Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267555Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367555Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467555Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567555Smsmith * SUCH DAMAGE. 2667555Smsmith * 2767555Smsmith * $FreeBSD: head/sys/dev/twe/twe_freebsd.c 69543 2000-12-03 02:11:35Z msmith $ 2867555Smsmith */ 2967555Smsmith 3067555Smsmith/* 3167555Smsmith * FreeBSD-specific code. 3267555Smsmith */ 3367555Smsmith 3469543Smsmith#include <sys/param.h> 3569543Smsmith#include <sys/cons.h> 3669543Smsmith#include <machine/bus.h> 3769543Smsmith#include <machine/clock.h> 3869543Smsmith#include <machine/md_var.h> 3969543Smsmith#include <vm/vm.h> 4069543Smsmith#include <vm/pmap.h> 4167555Smsmith#include <dev/twe/twe_compat.h> 4267555Smsmith#include <dev/twe/twereg.h> 4367555Smsmith#include <dev/twe/tweio.h> 4467555Smsmith#include <dev/twe/twevar.h> 4567555Smsmith#include <dev/twe/twe_tables.h> 4667555Smsmith 4767555Smsmith#include <sys/devicestat.h> 4867555Smsmith 4967555Smsmithstatic devclass_t twe_devclass; 5067555Smsmith 5169543Smsmith#ifdef TWE_DEBUG 5269543Smsmithstatic u_int32_t twed_bio_in; 5369543Smsmith#define TWED_BIO_IN twed_bio_in++ 5469543Smsmithstatic u_int32_t twed_bio_out; 5569543Smsmith#define TWED_BIO_OUT twed_bio_out++ 5669543Smsmith#else 5769543Smsmith#define TWED_BIO_IN 5869543Smsmith#define TWED_BIO_OUT 5969543Smsmith#endif 6069543Smsmith 6167555Smsmith/******************************************************************************** 6267555Smsmith ******************************************************************************** 6367555Smsmith Control device interface 6467555Smsmith ******************************************************************************** 6567555Smsmith ********************************************************************************/ 6667555Smsmith 6767555Smsmithstatic d_open_t twe_open; 6867555Smsmithstatic d_close_t twe_close; 6967555Smsmithstatic d_ioctl_t twe_ioctl_wrapper; 7067555Smsmith 7167555Smsmith#define TWE_CDEV_MAJOR 146 7267555Smsmith 7367555Smsmithstatic struct cdevsw twe_cdevsw = { 7467555Smsmith twe_open, 7567555Smsmith twe_close, 7667555Smsmith noread, 7767555Smsmith nowrite, 7867555Smsmith twe_ioctl_wrapper, 7967555Smsmith nopoll, 8067555Smsmith nommap, 8167555Smsmith nostrategy, 8267555Smsmith "twe", 8367555Smsmith TWE_CDEV_MAJOR, 8467555Smsmith nodump, 8567555Smsmith nopsize, 8667555Smsmith 0, 8767555Smsmith -1 8867555Smsmith}; 8967555Smsmith 9067555Smsmith/******************************************************************************** 9167555Smsmith * Accept an open operation on the control device. 9267555Smsmith */ 9367555Smsmithstatic int 9467555Smsmithtwe_open(dev_t dev, int flags, int fmt, struct proc *p) 9567555Smsmith{ 9667555Smsmith int unit = minor(dev); 9767555Smsmith struct twe_softc *sc = devclass_get_softc(twe_devclass, unit); 9867555Smsmith 9967555Smsmith sc->twe_state |= TWE_STATE_OPEN; 10067555Smsmith return(0); 10167555Smsmith} 10267555Smsmith 10367555Smsmith/******************************************************************************** 10467555Smsmith * Accept the last close on the control device. 10567555Smsmith */ 10667555Smsmithstatic int 10767555Smsmithtwe_close(dev_t dev, int flags, int fmt, struct proc *p) 10867555Smsmith{ 10967555Smsmith int unit = minor(dev); 11067555Smsmith struct twe_softc *sc = devclass_get_softc(twe_devclass, unit); 11167555Smsmith 11267555Smsmith sc->twe_state &= ~TWE_STATE_OPEN; 11367555Smsmith return (0); 11467555Smsmith} 11567555Smsmith 11667555Smsmith/******************************************************************************** 11767555Smsmith * Handle controller-specific control operations. 11867555Smsmith */ 11967555Smsmithstatic int 12067555Smsmithtwe_ioctl_wrapper(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) 12167555Smsmith{ 12267555Smsmith struct twe_softc *sc = (struct twe_softc *)dev->si_drv1; 12367555Smsmith 12467555Smsmith return(twe_ioctl(sc, cmd, addr)); 12567555Smsmith} 12667555Smsmith 12767555Smsmith/******************************************************************************** 12867555Smsmith ******************************************************************************** 12967555Smsmith PCI device interface 13067555Smsmith ******************************************************************************** 13167555Smsmith ********************************************************************************/ 13267555Smsmith 13367555Smsmithstatic int twe_probe(device_t dev); 13467555Smsmithstatic int twe_attach(device_t dev); 13567555Smsmithstatic void twe_free(struct twe_softc *sc); 13667555Smsmithstatic int twe_detach(device_t dev); 13767555Smsmithstatic int twe_shutdown(device_t dev); 13867555Smsmithstatic int twe_suspend(device_t dev); 13967555Smsmithstatic int twe_resume(device_t dev); 14067555Smsmithstatic void twe_pci_intr(void *arg); 14167555Smsmithstatic void twe_intrhook(void *arg); 14267555Smsmith 14367555Smsmithstatic device_method_t twe_methods[] = { 14467555Smsmith /* Device interface */ 14567555Smsmith DEVMETHOD(device_probe, twe_probe), 14667555Smsmith DEVMETHOD(device_attach, twe_attach), 14767555Smsmith DEVMETHOD(device_detach, twe_detach), 14867555Smsmith DEVMETHOD(device_shutdown, twe_shutdown), 14967555Smsmith DEVMETHOD(device_suspend, twe_suspend), 15067555Smsmith DEVMETHOD(device_resume, twe_resume), 15167555Smsmith 15267555Smsmith DEVMETHOD(bus_print_child, bus_generic_print_child), 15367555Smsmith DEVMETHOD(bus_driver_added, bus_generic_driver_added), 15467555Smsmith { 0, 0 } 15567555Smsmith}; 15667555Smsmith 15767555Smsmithstatic driver_t twe_pci_driver = { 15867555Smsmith "twe", 15967555Smsmith twe_methods, 16067555Smsmith sizeof(struct twe_softc) 16167555Smsmith}; 16267555Smsmith 16367555Smsmith#ifdef TWE_OVERRIDE 16467555SmsmithDRIVER_MODULE(Xtwe, pci, twe_pci_driver, twe_devclass, 0, 0); 16567555Smsmith#else 16667555SmsmithDRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, 0, 0); 16767555Smsmith#endif 16867555Smsmith 16967555Smsmith/******************************************************************************** 17067555Smsmith * Match a 3ware Escalade ATA RAID controller. 17167555Smsmith */ 17267555Smsmithstatic int 17367555Smsmithtwe_probe(device_t dev) 17467555Smsmith{ 17567555Smsmith 17667555Smsmith debug_called(4); 17767555Smsmith 17867555Smsmith if ((pci_get_vendor(dev) == TWE_VENDOR_ID) && 17967684Smsmith ((pci_get_device(dev) == TWE_DEVICE_ID) || 18067684Smsmith (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) { 18167555Smsmith device_set_desc(dev, TWE_DEVICE_NAME); 18267555Smsmith#ifdef TWE_OVERRIDE 18367555Smsmith return(0); 18467555Smsmith#else 18567555Smsmith return(-10); 18667555Smsmith#endif 18767555Smsmith } 18867555Smsmith return(ENXIO); 18967555Smsmith} 19067555Smsmith 19167555Smsmith/******************************************************************************** 19267555Smsmith * Allocate resources, initialise the controller. 19367555Smsmith */ 19467555Smsmithstatic int 19567555Smsmithtwe_attach(device_t dev) 19667555Smsmith{ 19767555Smsmith struct twe_softc *sc; 19867555Smsmith int rid, error; 19967555Smsmith u_int32_t command; 20067555Smsmith 20167555Smsmith debug_called(4); 20267555Smsmith 20367555Smsmith /* 20467555Smsmith * Initialise the softc structure. 20567555Smsmith */ 20667555Smsmith sc = device_get_softc(dev); 20767555Smsmith sc->twe_dev = dev; 20867555Smsmith 20967555Smsmith /* 21067555Smsmith * Make sure we are going to be able to talk to this board. 21167555Smsmith */ 21267555Smsmith command = pci_read_config(dev, PCIR_COMMAND, 2); 21367555Smsmith if ((command & PCIM_CMD_PORTEN) == 0) { 21467555Smsmith twe_printf(sc, "register window not available\n"); 21567555Smsmith return(ENXIO); 21667555Smsmith } 21767555Smsmith /* 21867555Smsmith * Force the busmaster enable bit on, in case the BIOS forgot. 21967555Smsmith */ 22067555Smsmith command |= PCIM_CMD_BUSMASTEREN; 22167555Smsmith pci_write_config(dev, PCIR_COMMAND, command, 2); 22267555Smsmith 22367555Smsmith /* 22467555Smsmith * Allocate the PCI register window. 22567555Smsmith */ 22667555Smsmith rid = TWE_IO_CONFIG_REG; 22767555Smsmith if ((sc->twe_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE)) == NULL) { 22867555Smsmith twe_printf(sc, "can't allocate register window\n"); 22967555Smsmith twe_free(sc); 23067555Smsmith return(ENXIO); 23167555Smsmith } 23267555Smsmith sc->twe_btag = rman_get_bustag(sc->twe_io); 23367555Smsmith sc->twe_bhandle = rman_get_bushandle(sc->twe_io); 23467555Smsmith 23567555Smsmith /* 23667555Smsmith * Allocate the parent bus DMA tag appropriate for PCI. 23767555Smsmith */ 23867555Smsmith if (bus_dma_tag_create(NULL, /* parent */ 23967555Smsmith 1, 0, /* alignment, boundary */ 24067555Smsmith BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 24167555Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 24267555Smsmith NULL, NULL, /* filter, filterarg */ 24367555Smsmith MAXBSIZE, TWE_MAX_SGL_LENGTH, /* maxsize, nsegments */ 24467555Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 24567555Smsmith BUS_DMA_ALLOCNOW, /* flags */ 24667555Smsmith &sc->twe_parent_dmat)) { 24767555Smsmith twe_printf(sc, "can't allocate parent DMA tag\n"); 24867555Smsmith twe_free(sc); 24967555Smsmith return(ENOMEM); 25067555Smsmith } 25167555Smsmith 25267555Smsmith /* 25367555Smsmith * Allocate and connect our interrupt. 25467555Smsmith */ 25567555Smsmith rid = 0; 25667555Smsmith if ((sc->twe_irq = bus_alloc_resource(sc->twe_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 25767555Smsmith twe_printf(sc, "can't allocate interrupt\n"); 25867555Smsmith twe_free(sc); 25967555Smsmith return(ENXIO); 26067555Smsmith } 26167555Smsmith if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO, twe_pci_intr, sc, &sc->twe_intr)) { 26267555Smsmith twe_printf(sc, "can't set up interrupt\n"); 26367555Smsmith twe_free(sc); 26467555Smsmith return(ENXIO); 26567555Smsmith } 26667555Smsmith 26767555Smsmith /* 26867555Smsmith * Create DMA tag for mapping objects into controller-addressable space. 26967555Smsmith */ 27069543Smsmith if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */ 27169543Smsmith 1, 0, /* alignment, boundary */ 27267555Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 27367555Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 27467555Smsmith NULL, NULL, /* filter, filterarg */ 27569543Smsmith MAXBSIZE, TWE_MAX_SGL_LENGTH,/* maxsize, nsegments */ 27669543Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 27767555Smsmith 0, /* flags */ 27867555Smsmith &sc->twe_buffer_dmat)) { 27967555Smsmith twe_printf(sc, "can't allocate data buffer DMA tag\n"); 28067555Smsmith twe_free(sc); 28167555Smsmith return(ENOMEM); 28267555Smsmith } 28367555Smsmith 28467555Smsmith /* 28567555Smsmith * Initialise the controller and driver core. 28667555Smsmith */ 28767555Smsmith if ((error = twe_setup(sc))) 28867555Smsmith return(error); 28967555Smsmith 29067555Smsmith /* 29167555Smsmith * Print some information about the controller and configuration. 29267555Smsmith */ 29367555Smsmith twe_describe_controller(sc); 29467555Smsmith 29567555Smsmith /* 29667555Smsmith * Create the control device. 29767555Smsmith */ 29867555Smsmith sc->twe_dev_t = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev), UID_ROOT, GID_OPERATOR, 29967555Smsmith S_IRUSR | S_IWUSR, "twe%d", device_get_unit(sc->twe_dev)); 30067555Smsmith sc->twe_dev_t->si_drv1 = sc; 30167555Smsmith /* 30267555Smsmith * Schedule ourselves to bring the controller up once interrupts are available. 30367555Smsmith * This isn't strictly necessary, since we disable interrupts while probing the 30467555Smsmith * controller, but it is more in keeping with common practice for other disk 30567555Smsmith * devices. 30667555Smsmith */ 30767555Smsmith sc->twe_ich.ich_func = twe_intrhook; 30867555Smsmith sc->twe_ich.ich_arg = sc; 30967555Smsmith if (config_intrhook_establish(&sc->twe_ich) != 0) { 31067555Smsmith twe_printf(sc, "can't establish configuration hook\n"); 31167555Smsmith twe_free(sc); 31267555Smsmith return(ENXIO); 31367555Smsmith } 31467555Smsmith 31567555Smsmith return(0); 31667555Smsmith} 31767555Smsmith 31867555Smsmith/******************************************************************************** 31967555Smsmith * Free all of the resources associated with (sc). 32067555Smsmith * 32167555Smsmith * Should not be called if the controller is active. 32267555Smsmith */ 32367555Smsmithstatic void 32467555Smsmithtwe_free(struct twe_softc *sc) 32567555Smsmith{ 32667555Smsmith struct twe_request *tr; 32767555Smsmith 32867555Smsmith debug_called(4); 32967555Smsmith 33067555Smsmith /* throw away any command buffers */ 33167555Smsmith while ((tr = twe_dequeue_free(sc)) != NULL) 33267555Smsmith twe_free_request(tr); 33367555Smsmith 33467555Smsmith /* destroy the data-transfer DMA tag */ 33567555Smsmith if (sc->twe_buffer_dmat) 33667555Smsmith bus_dma_tag_destroy(sc->twe_buffer_dmat); 33767555Smsmith 33867555Smsmith /* disconnect the interrupt handler */ 33967555Smsmith if (sc->twe_intr) 34067555Smsmith bus_teardown_intr(sc->twe_dev, sc->twe_irq, sc->twe_intr); 34167555Smsmith if (sc->twe_irq != NULL) 34267555Smsmith bus_release_resource(sc->twe_dev, SYS_RES_IRQ, 0, sc->twe_irq); 34367555Smsmith 34467555Smsmith /* destroy the parent DMA tag */ 34567555Smsmith if (sc->twe_parent_dmat) 34667555Smsmith bus_dma_tag_destroy(sc->twe_parent_dmat); 34767555Smsmith 34867555Smsmith /* release the register window mapping */ 34967555Smsmith if (sc->twe_io != NULL) 35067555Smsmith bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io); 35167555Smsmith 35267555Smsmith /* destroy control device */ 35367555Smsmith if (sc->twe_dev_t != (dev_t)NULL) 35467555Smsmith destroy_dev(sc->twe_dev_t); 35567555Smsmith} 35667555Smsmith 35767555Smsmith/******************************************************************************** 35867555Smsmith * Disconnect from the controller completely, in preparation for unload. 35967555Smsmith */ 36067555Smsmithstatic int 36167555Smsmithtwe_detach(device_t dev) 36267555Smsmith{ 36367555Smsmith struct twe_softc *sc = device_get_softc(dev); 36467555Smsmith int s, error; 36567555Smsmith 36667555Smsmith debug_called(4); 36767555Smsmith 36867555Smsmith error = EBUSY; 36967555Smsmith s = splbio(); 37067555Smsmith if (sc->twe_state & TWE_STATE_OPEN) 37167555Smsmith goto out; 37267555Smsmith 37367555Smsmith /* 37467555Smsmith * Shut the controller down. 37567555Smsmith */ 37667555Smsmith if ((error = twe_shutdown(dev))) 37767555Smsmith goto out; 37867555Smsmith 37967555Smsmith twe_free(sc); 38067555Smsmith 38167555Smsmith error = 0; 38267555Smsmith out: 38367555Smsmith splx(s); 38467555Smsmith return(error); 38567555Smsmith} 38667555Smsmith 38767555Smsmith/******************************************************************************** 38867555Smsmith * Bring the controller down to a dormant state and detach all child devices. 38967555Smsmith * 39067555Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't 39167555Smsmith * allow shutdown if any device is open. 39267555Smsmith */ 39367555Smsmithstatic int 39467555Smsmithtwe_shutdown(device_t dev) 39567555Smsmith{ 39667555Smsmith struct twe_softc *sc = device_get_softc(dev); 39767555Smsmith int i, s, error; 39867555Smsmith 39967555Smsmith debug_called(4); 40067555Smsmith 40167555Smsmith s = splbio(); 40267555Smsmith error = 0; 40367555Smsmith 40467555Smsmith /* 40567555Smsmith * Delete all our child devices. 40667555Smsmith */ 40767555Smsmith for (i = 0; i < TWE_MAX_UNITS; i++) { 40867555Smsmith if (sc->twe_drive[i].td_disk != 0) { 40967555Smsmith if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[i].td_disk)) != 0) 41067555Smsmith goto out; 41167555Smsmith sc->twe_drive[i].td_disk = 0; 41267555Smsmith } 41367555Smsmith } 41467555Smsmith 41567555Smsmith /* 41667555Smsmith * Bring the controller down. 41767555Smsmith */ 41867555Smsmith twe_deinit(sc); 41967555Smsmith 42067555Smsmith out: 42167555Smsmith splx(s); 42267555Smsmith return(error); 42367555Smsmith} 42467555Smsmith 42567555Smsmith/******************************************************************************** 42667555Smsmith * Bring the controller to a quiescent state, ready for system suspend. 42767555Smsmith */ 42867555Smsmithstatic int 42967555Smsmithtwe_suspend(device_t dev) 43067555Smsmith{ 43167555Smsmith struct twe_softc *sc = device_get_softc(dev); 43267555Smsmith int s; 43367555Smsmith 43467555Smsmith debug_called(4); 43567555Smsmith 43667555Smsmith s = splbio(); 43767555Smsmith sc->twe_state |= TWE_STATE_SUSPEND; 43867555Smsmith 43967555Smsmith twe_disable_interrupts(sc); 44067555Smsmith splx(s); 44167555Smsmith 44267555Smsmith return(0); 44367555Smsmith} 44467555Smsmith 44567555Smsmith/******************************************************************************** 44667555Smsmith * Bring the controller back to a state ready for operation. 44767555Smsmith */ 44867555Smsmithstatic int 44967555Smsmithtwe_resume(device_t dev) 45067555Smsmith{ 45167555Smsmith struct twe_softc *sc = device_get_softc(dev); 45267555Smsmith 45367555Smsmith debug_called(4); 45467555Smsmith 45567555Smsmith sc->twe_state &= ~TWE_STATE_SUSPEND; 45667555Smsmith twe_enable_interrupts(sc); 45767555Smsmith 45867555Smsmith return(0); 45967555Smsmith} 46067555Smsmith 46167555Smsmith/******************************************************************************* 46267555Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 46367555Smsmith * status. 46467555Smsmith */ 46567555Smsmithstatic void 46667555Smsmithtwe_pci_intr(void *arg) 46767555Smsmith{ 46867555Smsmith twe_intr((struct twe_softc *)arg); 46967555Smsmith} 47067555Smsmith 47167555Smsmith/******************************************************************************** 47267555Smsmith * Delayed-startup hook 47367555Smsmith */ 47467555Smsmithstatic void 47567555Smsmithtwe_intrhook(void *arg) 47667555Smsmith{ 47767555Smsmith struct twe_softc *sc = (struct twe_softc *)arg; 47867555Smsmith 47967555Smsmith /* pull ourselves off the intrhook chain */ 48067555Smsmith config_intrhook_disestablish(&sc->twe_ich); 48167555Smsmith 48267555Smsmith /* call core startup routine */ 48367555Smsmith twe_init(sc); 48467555Smsmith} 48567555Smsmith 48667555Smsmith/******************************************************************************** 48767555Smsmith * Given a detected drive, attach it to the bio interface. 48867555Smsmith * 48967555Smsmith * This is called from twe_init. 49067555Smsmith */ 49167555Smsmithvoid 49267555Smsmithtwe_attach_drive(struct twe_softc *sc, struct twe_drive *dr) 49367555Smsmith{ 49467555Smsmith char buf[80]; 49567555Smsmith int error; 49667555Smsmith 49767555Smsmith dr->td_disk = device_add_child(sc->twe_dev, NULL, -1); 49867555Smsmith if (dr->td_disk == NULL) { 49967555Smsmith twe_printf(sc, "device_add_child failed\n"); 50067555Smsmith return; 50167555Smsmith } 50267555Smsmith device_set_ivars(dr->td_disk, dr); 50367555Smsmith 50467555Smsmith /* 50567555Smsmith * XXX It would make sense to test the online/initialising bits, but they seem to be 50667555Smsmith * always set... 50767555Smsmith */ 50867555Smsmith sprintf(buf, "%s, %s", twe_describe_code(twe_table_unittype, dr->td_type), 50967555Smsmith twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK)); 51067555Smsmith device_set_desc_copy(dr->td_disk, buf); 51167555Smsmith 51267555Smsmith if ((error = bus_generic_attach(sc->twe_dev)) != 0) 51367555Smsmith twe_printf(sc, "bus_generic_attach returned %d\n", error); 51467555Smsmith} 51567555Smsmith 51667555Smsmith/******************************************************************************** 51767555Smsmith ******************************************************************************** 51867555Smsmith Disk device 51967555Smsmith ******************************************************************************** 52067555Smsmith ********************************************************************************/ 52167555Smsmith 52267555Smsmith/* 52367555Smsmith * Disk device softc 52467555Smsmith */ 52567555Smsmithstruct twed_softc 52667555Smsmith{ 52767555Smsmith device_t twed_dev; 52867555Smsmith dev_t twed_dev_t; 52967555Smsmith struct twe_softc *twed_controller; /* parent device softc */ 53067555Smsmith struct twe_drive *twed_drive; /* drive data in parent softc */ 53167555Smsmith struct disk twed_disk; /* generic disk handle */ 53267555Smsmith struct devstat twed_stats; /* accounting */ 53367555Smsmith struct disklabel twed_label; /* synthetic label */ 53467555Smsmith int twed_flags; 53567555Smsmith#define TWED_OPEN (1<<0) /* drive is open (can't shut down) */ 53667555Smsmith}; 53767555Smsmith 53867555Smsmith/* 53967555Smsmith * Disk device bus interface 54067555Smsmith */ 54167555Smsmithstatic int twed_probe(device_t dev); 54267555Smsmithstatic int twed_attach(device_t dev); 54367555Smsmithstatic int twed_detach(device_t dev); 54467555Smsmith 54567555Smsmithstatic device_method_t twed_methods[] = { 54667555Smsmith DEVMETHOD(device_probe, twed_probe), 54767555Smsmith DEVMETHOD(device_attach, twed_attach), 54867555Smsmith DEVMETHOD(device_detach, twed_detach), 54967555Smsmith { 0, 0 } 55067555Smsmith}; 55167555Smsmith 55267555Smsmithstatic driver_t twed_driver = { 55367555Smsmith "twed", 55467555Smsmith twed_methods, 55567555Smsmith sizeof(struct twed_softc) 55667555Smsmith}; 55767555Smsmith 55867555Smsmithstatic devclass_t twed_devclass; 55967555Smsmith#ifdef TWE_OVERRIDE 56067555SmsmithDRIVER_MODULE(Xtwed, Xtwe, twed_driver, twed_devclass, 0, 0); 56167555Smsmith#else 56267555SmsmithDRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0); 56367555Smsmith#endif 56467555Smsmith 56567555Smsmith/* 56667555Smsmith * Disk device control interface. 56767555Smsmith */ 56867555Smsmithstatic d_open_t twed_open; 56967555Smsmithstatic d_close_t twed_close; 57067555Smsmithstatic d_strategy_t twed_strategy; 57169543Smsmithstatic d_dump_t twed_dump; 57267555Smsmith 57367555Smsmith#define TWED_CDEV_MAJOR 147 57467555Smsmith 57567555Smsmithstatic struct cdevsw twed_cdevsw = { 57667555Smsmith twed_open, 57767555Smsmith twed_close, 57867555Smsmith physread, 57967555Smsmith physwrite, 58067555Smsmith noioctl, 58167555Smsmith nopoll, 58267555Smsmith nommap, 58367555Smsmith twed_strategy, 58467555Smsmith "twed", 58567555Smsmith TWED_CDEV_MAJOR, 58669543Smsmith twed_dump, 58767555Smsmith nopsize, 58867555Smsmith D_DISK, 58967555Smsmith -1 59067555Smsmith}; 59167555Smsmith 59267555Smsmithstatic struct cdevsw tweddisk_cdevsw; 59367555Smsmith#ifdef FREEBSD_4 59467555Smsmithstatic int disks_registered = 0; 59567555Smsmith#endif 59667555Smsmith 59767555Smsmith/******************************************************************************** 59867555Smsmith * Handle open from generic layer. 59967555Smsmith * 60067555Smsmith * Note that this is typically only called by the diskslice code, and not 60167555Smsmith * for opens on subdevices (eg. slices, partitions). 60267555Smsmith */ 60367555Smsmithstatic int 60467555Smsmithtwed_open(dev_t dev, int flags, int fmt, struct proc *p) 60567555Smsmith{ 60667555Smsmith struct twed_softc *sc = (struct twed_softc *)dev->si_drv1; 60767555Smsmith struct disklabel *label; 60867555Smsmith 60967555Smsmith debug_called(4); 61067555Smsmith 61167555Smsmith if (sc == NULL) 61267555Smsmith return (ENXIO); 61367555Smsmith 61467555Smsmith /* check that the controller is up and running */ 61567555Smsmith if (sc->twed_controller->twe_state & TWE_STATE_SHUTDOWN) 61667555Smsmith return(ENXIO); 61767555Smsmith 61867555Smsmith /* build synthetic label */ 61967555Smsmith label = &sc->twed_disk.d_label; 62067555Smsmith bzero(label, sizeof(*label)); 62167555Smsmith label->d_type = DTYPE_ESDI; 62267555Smsmith label->d_secsize = TWE_BLOCK_SIZE; 62367555Smsmith label->d_nsectors = sc->twed_drive->td_sectors; 62467555Smsmith label->d_ntracks = sc->twed_drive->td_heads; 62567555Smsmith label->d_ncylinders = sc->twed_drive->td_cylinders; 62667555Smsmith label->d_secpercyl = sc->twed_drive->td_sectors * sc->twed_drive->td_heads; 62767555Smsmith label->d_secperunit = sc->twed_drive->td_size; 62867555Smsmith 62967555Smsmith sc->twed_flags |= TWED_OPEN; 63067555Smsmith return (0); 63167555Smsmith} 63267555Smsmith 63367555Smsmith/******************************************************************************** 63467555Smsmith * Handle last close of the disk device. 63567555Smsmith */ 63667555Smsmithstatic int 63767555Smsmithtwed_close(dev_t dev, int flags, int fmt, struct proc *p) 63867555Smsmith{ 63967555Smsmith struct twed_softc *sc = (struct twed_softc *)dev->si_drv1; 64067555Smsmith 64167555Smsmith debug_called(4); 64267555Smsmith 64367555Smsmith if (sc == NULL) 64467555Smsmith return (ENXIO); 64567555Smsmith 64667555Smsmith sc->twed_flags &= ~TWED_OPEN; 64767555Smsmith return (0); 64867555Smsmith} 64967555Smsmith 65067555Smsmith/******************************************************************************** 65167555Smsmith * Handle an I/O request. 65267555Smsmith */ 65367555Smsmithstatic void 65467555Smsmithtwed_strategy(twe_bio *bp) 65567555Smsmith{ 65667555Smsmith struct twed_softc *sc = (struct twed_softc *)TWE_BIO_SOFTC(bp); 65767555Smsmith 65867555Smsmith debug_called(4); 65967555Smsmith 66069543Smsmith TWED_BIO_IN; 66169543Smsmith 66267555Smsmith /* bogus disk? */ 66367555Smsmith if (sc == NULL) { 66467555Smsmith TWE_BIO_SET_ERROR(bp, EINVAL); 66569543Smsmith printf("twe: bio for invalid disk!\n"); 66669543Smsmith TWE_BIO_DONE(bp); 66769543Smsmith TWED_BIO_OUT; 66867555Smsmith return; 66967555Smsmith } 67067555Smsmith 67167555Smsmith /* do-nothing operation? */ 67267555Smsmith if (TWE_BIO_LENGTH(bp) == 0) { 67367555Smsmith TWE_BIO_RESID(bp) = 0; 67467555Smsmith TWE_BIO_DONE(bp); 67569543Smsmith TWED_BIO_OUT; 67667555Smsmith return; 67767555Smsmith } 67867555Smsmith 67967555Smsmith /* perform accounting */ 68067555Smsmith TWE_BIO_STATS_START(bp); 68167555Smsmith 68269543Smsmith /* queue the bio on the controller */ 68369543Smsmith twe_enqueue_bio(sc->twed_controller, bp); 68469543Smsmith 68569543Smsmith /* poke the controller to start I/O */ 68669543Smsmith twe_startio(sc->twed_controller); 68767555Smsmith return; 68867555Smsmith} 68967555Smsmith 69067555Smsmith/******************************************************************************** 69169543Smsmith * System crashdump support 69269543Smsmith */ 69369543Smsmithint 69469543Smsmithtwed_dump(dev_t dev) 69569543Smsmith{ 69669543Smsmith struct twed_softc *twed_sc = (struct twed_softc *)dev->si_drv1; 69769543Smsmith struct twe_softc *twe_sc = (struct twe_softc *)twed_sc->twed_controller; 69869543Smsmith u_int count, blkno, secsize; 69969543Smsmith vm_offset_t addr = 0; 70069543Smsmith long blkcnt; 70169543Smsmith int dumppages = MAXDUMPPGS; 70269543Smsmith int error; 70369543Smsmith int i; 70469543Smsmith 70569543Smsmith if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize))) 70669543Smsmith return(error); 70769543Smsmith 70869543Smsmith if (!twed_sc || !twe_sc) 70969543Smsmith return(ENXIO); 71069543Smsmith 71169543Smsmith blkcnt = howmany(PAGE_SIZE, secsize); 71269543Smsmith 71369543Smsmith while (count > 0) { 71469543Smsmith caddr_t va = NULL; 71569543Smsmith 71669543Smsmith if ((count / blkcnt) < dumppages) 71769543Smsmith dumppages = count / blkcnt; 71869543Smsmith 71969543Smsmith for (i = 0; i < dumppages; ++i) { 72069543Smsmith vm_offset_t a = addr + (i * PAGE_SIZE); 72169543Smsmith if (is_physical_memory(a)) 72269543Smsmith va = pmap_kenter_temporary(trunc_page(a), i); 72369543Smsmith else 72469543Smsmith va = pmap_kenter_temporary(trunc_page(0), i); 72569543Smsmith } 72669543Smsmith 72769543Smsmith if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_unit, blkno, va, 72869543Smsmith (PAGE_SIZE * dumppages) / TWE_BLOCK_SIZE)) != 0) 72969543Smsmith return(error); 73069543Smsmith 73169543Smsmith 73269543Smsmith if (addr % (1024 * 1024) == 0) { 73369543Smsmith#ifdef HW_WDOG 73469543Smsmith if (wdog_tickler) 73569543Smsmith (*wdog_tickler)(); 73669543Smsmith#endif 73769543Smsmith printf("%ld ", (long)(count * DEV_BSIZE) / (1024 * 1024)); 73869543Smsmith } 73969543Smsmith 74069543Smsmith blkno += blkcnt * dumppages; 74169543Smsmith count -= blkcnt * dumppages; 74269543Smsmith addr += PAGE_SIZE * dumppages; 74369543Smsmith 74469543Smsmith if (cncheckc() != -1) 74569543Smsmith return(EINTR); 74669543Smsmith } 74769543Smsmith return(0); 74869543Smsmith} 74969543Smsmith 75069543Smsmith/******************************************************************************** 75167555Smsmith * Handle completion of an I/O request. 75267555Smsmith */ 75367555Smsmithvoid 75467555Smsmithtwed_intr(twe_bio *bp) 75567555Smsmith{ 75667555Smsmith debug_called(4); 75767555Smsmith 75867555Smsmith /* if no error, transfer completed */ 75967555Smsmith if (!TWE_BIO_HAS_ERROR(bp)) 76067555Smsmith TWE_BIO_RESID(bp) = 0; 76167555Smsmith 76267555Smsmith TWE_BIO_STATS_END(bp); 76367555Smsmith TWE_BIO_DONE(bp); 76469543Smsmith TWED_BIO_OUT; 76567555Smsmith} 76667555Smsmith 76767555Smsmith/******************************************************************************** 76867555Smsmith * Default probe stub. 76967555Smsmith */ 77067555Smsmithstatic int 77167555Smsmithtwed_probe(device_t dev) 77267555Smsmith{ 77367555Smsmith return (0); 77467555Smsmith} 77567555Smsmith 77667555Smsmith/******************************************************************************** 77767555Smsmith * Attach a unit to the controller. 77867555Smsmith */ 77967555Smsmithstatic int 78067555Smsmithtwed_attach(device_t dev) 78167555Smsmith{ 78267555Smsmith struct twed_softc *sc; 78367555Smsmith device_t parent; 78467555Smsmith dev_t dsk; 78567555Smsmith 78667555Smsmith debug_called(4); 78767555Smsmith 78867555Smsmith /* initialise our softc */ 78967555Smsmith sc = device_get_softc(dev); 79067555Smsmith parent = device_get_parent(dev); 79167555Smsmith sc->twed_controller = (struct twe_softc *)device_get_softc(parent); 79267555Smsmith sc->twed_drive = device_get_ivars(dev); 79367555Smsmith sc->twed_dev = dev; 79467555Smsmith 79567555Smsmith /* report the drive */ 79667555Smsmith twed_printf(sc, "%uMB (%u sectors)\n", 79767555Smsmith sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE), 79867555Smsmith sc->twed_drive->td_size); 79967555Smsmith 80067555Smsmith devstat_add_entry(&sc->twed_stats, "twed", device_get_unit(dev), TWE_BLOCK_SIZE, 80167555Smsmith DEVSTAT_NO_ORDERED_TAGS, 80267555Smsmith DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 80367555Smsmith DEVSTAT_PRIORITY_ARRAY); 80467555Smsmith 80567555Smsmith /* attach a generic disk device to ourselves */ 80667555Smsmith dsk = disk_create(device_get_unit(dev), &sc->twed_disk, 0, &twed_cdevsw, &tweddisk_cdevsw); 80767555Smsmith dsk->si_drv1 = sc; 80867555Smsmith dsk->si_drv2 = &sc->twed_drive->td_unit; 80967555Smsmith sc->twed_dev_t = dsk; 81067555Smsmith#ifdef FREEBSD_4 81167555Smsmith disks_registered++; 81267555Smsmith#endif 81367555Smsmith 81467555Smsmith /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */ 81567555Smsmith dsk->si_iosize_max = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE; 81667555Smsmith 81767555Smsmith return (0); 81867555Smsmith} 81967555Smsmith 82067555Smsmith/******************************************************************************** 82167555Smsmith * Disconnect ourselves from the system. 82267555Smsmith */ 82367555Smsmithstatic int 82467555Smsmithtwed_detach(device_t dev) 82567555Smsmith{ 82667555Smsmith struct twed_softc *sc = (struct twed_softc *)device_get_softc(dev); 82767555Smsmith 82867555Smsmith debug_called(4); 82967555Smsmith 83067555Smsmith if (sc->twed_flags & TWED_OPEN) 83167555Smsmith return(EBUSY); 83267555Smsmith 83367555Smsmith devstat_remove_entry(&sc->twed_stats); 83467555Smsmith#ifdef FREEBSD_4 83567555Smsmith if (--disks_registered == 0) 83667555Smsmith cdevsw_remove(&tweddisk_cdevsw); 83767555Smsmith#else 83867555Smsmith disk_destroy(sc->twed_dev_t); 83967555Smsmith#endif 84067555Smsmith 84167555Smsmith return(0); 84267555Smsmith} 84367555Smsmith 84467555Smsmith/******************************************************************************** 84567555Smsmith ******************************************************************************** 84667555Smsmith Misc 84767555Smsmith ******************************************************************************** 84867555Smsmith ********************************************************************************/ 84967555Smsmith 85067555Smsmithstatic void twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 85167555Smsmithstatic void twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 85267555Smsmith 85367555Smsmith/******************************************************************************** 85467555Smsmith * Allocate a command buffer 85567555Smsmith */ 85667555SmsmithMALLOC_DEFINE(TWE_MALLOC_CLASS, "twe commands", "twe commands"); 85767555Smsmith 85867555Smsmithstruct twe_request * 85967555Smsmithtwe_allocate_request(struct twe_softc *sc) 86067555Smsmith{ 86167555Smsmith struct twe_request *tr; 86267555Smsmith 86367555Smsmith if ((tr = malloc(sizeof(struct twe_request), TWE_MALLOC_CLASS, M_NOWAIT)) == NULL) 86467555Smsmith return(NULL); 86567555Smsmith bzero(tr, sizeof(*tr)); 86667555Smsmith tr->tr_sc = sc; 86767555Smsmith if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_cmdmap)) { 86867555Smsmith twe_free_request(tr); 86967555Smsmith return(NULL); 87067555Smsmith } 87167555Smsmith if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) { 87267555Smsmith bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap); 87367555Smsmith twe_free_request(tr); 87467555Smsmith return(NULL); 87567555Smsmith } 87667555Smsmith return(tr); 87767555Smsmith} 87867555Smsmith 87967555Smsmith/******************************************************************************** 88067555Smsmith * Permanently discard a command buffer. 88167555Smsmith */ 88267555Smsmithvoid 88367555Smsmithtwe_free_request(struct twe_request *tr) 88467555Smsmith{ 88567555Smsmith struct twe_softc *sc = tr->tr_sc; 88667555Smsmith 88767555Smsmith debug_called(4); 88867555Smsmith 88967555Smsmith bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap); 89067555Smsmith bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap); 89167555Smsmith free(tr, TWE_MALLOC_CLASS); 89267555Smsmith} 89367555Smsmith 89467555Smsmith/******************************************************************************** 89567555Smsmith * Map/unmap (tr)'s command and data in the controller's addressable space. 89667555Smsmith * 89767555Smsmith * These routines ensure that the data which the controller is going to try to 89867555Smsmith * access is actually visible to the controller, in a machine-independant 89967555Smsmith * fasion. Due to a hardware limitation, I/O buffers must be 512-byte aligned 90067555Smsmith * and we take care of that here as well. 90167555Smsmith */ 90267555Smsmithstatic void 90367555Smsmithtwe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 90467555Smsmith{ 90567555Smsmith struct twe_request *tr = (struct twe_request *)arg; 90667555Smsmith TWE_Command *cmd = &tr->tr_command; 90767555Smsmith int i; 90867555Smsmith 90967555Smsmith debug_called(4); 91067555Smsmith 91167555Smsmith /* save base of first segment in command (applicable if there only one segment) */ 91267555Smsmith tr->tr_dataphys = segs[0].ds_addr; 91367555Smsmith 91467555Smsmith /* correct command size for s/g list size */ 91567555Smsmith tr->tr_command.generic.size += 2 * nsegments; 91667555Smsmith 91767555Smsmith /* 91867555Smsmith * Due to the fact that parameter and I/O commands have the scatter/gather list in 91967555Smsmith * different places, we need to determine which sort of command this actually is 92067555Smsmith * before we can populate it correctly. 92167555Smsmith */ 92267555Smsmith switch(cmd->generic.opcode) { 92367555Smsmith case TWE_OP_GET_PARAM: 92467555Smsmith case TWE_OP_SET_PARAM: 92567555Smsmith cmd->generic.sgl_offset = 2; 92667555Smsmith for (i = 0; i < nsegments; i++) { 92767555Smsmith cmd->param.sgl[i].address = segs[i].ds_addr; 92867555Smsmith cmd->param.sgl[i].length = segs[i].ds_len; 92967555Smsmith } 93067555Smsmith for (; i < TWE_MAX_SGL_LENGTH; i++) { /* XXX necessary? */ 93167555Smsmith cmd->param.sgl[i].address = 0; 93267555Smsmith cmd->param.sgl[i].length = 0; 93367555Smsmith } 93467555Smsmith break; 93567555Smsmith case TWE_OP_READ: 93667555Smsmith case TWE_OP_WRITE: 93767555Smsmith cmd->generic.sgl_offset = 3; 93867555Smsmith for (i = 0; i < nsegments; i++) { 93967555Smsmith cmd->io.sgl[i].address = segs[i].ds_addr; 94067555Smsmith cmd->io.sgl[i].length = segs[i].ds_len; 94167555Smsmith } 94267555Smsmith for (; i < TWE_MAX_SGL_LENGTH; i++) { /* XXX necessary? */ 94367555Smsmith cmd->io.sgl[i].address = 0; 94467555Smsmith cmd->io.sgl[i].length = 0; 94567555Smsmith } 94667555Smsmith break; 94767555Smsmith default: 94867555Smsmith /* no s/g list, nothing to do */ 94967555Smsmith } 95067555Smsmith} 95167555Smsmith 95267555Smsmithstatic void 95367555Smsmithtwe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 95467555Smsmith{ 95567555Smsmith struct twe_request *tr = (struct twe_request *)arg; 95667555Smsmith 95767555Smsmith debug_called(4); 95867555Smsmith 95967555Smsmith /* command can't cross a page boundary */ 96067555Smsmith tr->tr_cmdphys = segs[0].ds_addr; 96167555Smsmith} 96267555Smsmith 96367555Smsmithvoid 96467555Smsmithtwe_map_request(struct twe_request *tr) 96567555Smsmith{ 96667555Smsmith struct twe_softc *sc = tr->tr_sc; 96767555Smsmith 96867555Smsmith debug_called(4); 96967555Smsmith 97067555Smsmith 97167555Smsmith /* 97267555Smsmith * Map the command into bus space. 97367555Smsmith */ 97467555Smsmith bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_cmdmap, &tr->tr_command, sizeof(tr->tr_command), 97567555Smsmith twe_setup_request_dmamap, tr, 0); 97667555Smsmith bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_PREWRITE); 97767555Smsmith 97867555Smsmith /* 97967555Smsmith * If the command involves data, map that too. 98067555Smsmith */ 98167555Smsmith if (tr->tr_data != NULL) { 98267555Smsmith 98367555Smsmith /* 98467555Smsmith * Data must be 64-byte aligned; allocate a fixup buffer if it's not. 98567555Smsmith */ 98667555Smsmith if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) { 98767555Smsmith tr->tr_realdata = tr->tr_data; /* save pointer to 'real' data */ 98867555Smsmith tr->tr_flags |= TWE_CMD_ALIGNBUF; 98967555Smsmith tr->tr_data = malloc(tr->tr_length, TWE_MALLOC_CLASS, M_NOWAIT); /* XXX check result here */ 99067555Smsmith } 99167555Smsmith 99267555Smsmith /* 99367555Smsmith * Map the data buffer into bus space and build the s/g list. 99467555Smsmith */ 99567555Smsmith bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length, 99667555Smsmith twe_setup_data_dmamap, tr, 0); 99767555Smsmith if (tr->tr_flags & TWE_CMD_DATAIN) 99867555Smsmith bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREREAD); 99967555Smsmith if (tr->tr_flags & TWE_CMD_DATAOUT) { 100067555Smsmith /* if we're using an alignment buffer, and we're writing data, copy the real data out */ 100167555Smsmith if (tr->tr_flags & TWE_CMD_ALIGNBUF) 100267555Smsmith bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length); 100367555Smsmith bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREWRITE); 100467555Smsmith } 100567555Smsmith } 100667555Smsmith} 100767555Smsmith 100867555Smsmithvoid 100967555Smsmithtwe_unmap_request(struct twe_request *tr) 101067555Smsmith{ 101167555Smsmith struct twe_softc *sc = tr->tr_sc; 101267555Smsmith 101367555Smsmith debug_called(4); 101467555Smsmith 101567555Smsmith /* 101667555Smsmith * Unmap the command from bus space. 101767555Smsmith */ 101867555Smsmith bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_POSTWRITE); 101967555Smsmith bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_cmdmap); 102067555Smsmith 102167555Smsmith /* 102267555Smsmith * If the command involved data, unmap that too. 102367555Smsmith */ 102467555Smsmith if (tr->tr_data != NULL) { 102567555Smsmith 102667555Smsmith if (tr->tr_flags & TWE_CMD_DATAIN) { 102767555Smsmith bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTREAD); 102867555Smsmith /* if we're using an alignment buffer, and we're reading data, copy the real data in */ 102967555Smsmith if (tr->tr_flags & TWE_CMD_ALIGNBUF) 103067555Smsmith bcopy(tr->tr_data, tr->tr_realdata, tr->tr_length); 103167555Smsmith } 103267555Smsmith if (tr->tr_flags & TWE_CMD_DATAOUT) 103367555Smsmith bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTWRITE); 103467555Smsmith 103567555Smsmith bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap); 103667555Smsmith } 103767555Smsmith 103867555Smsmith /* free alignment buffer if it was used */ 103967555Smsmith if (tr->tr_flags & TWE_CMD_ALIGNBUF) { 104067555Smsmith free(tr->tr_data, TWE_MALLOC_CLASS); 104167555Smsmith tr->tr_data = tr->tr_realdata; /* restore 'real' data pointer */ 104267555Smsmith } 104367555Smsmith} 104467555Smsmith 104567555Smsmith#ifdef TWE_DEBUG 104667555Smsmith/******************************************************************************** 104767555Smsmith * Print current controller status, call from DDB. 104867555Smsmith */ 104967555Smsmithvoid 105067555Smsmithtwe_report(void) 105167555Smsmith{ 105267555Smsmith struct twe_softc *sc; 105367555Smsmith int i, s; 105467555Smsmith 105567555Smsmith s = splbio(); 105667555Smsmith for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++) 105767555Smsmith twe_print_controller(sc); 105869543Smsmith printf("twed: total bio count in %u out %u\n", twed_bio_in, twed_bio_out); 105967555Smsmith splx(s); 106067555Smsmith} 106167555Smsmith#endif 1062