164987Smsmith/*- 273050Smsmith * Copyright (c) 2000, 2001 Michael Smith 364987Smsmith * Copyright (c) 2000 BSDi 464987Smsmith * All rights reserved. 564987Smsmith * 664987Smsmith * Redistribution and use in source and binary forms, with or without 764987Smsmith * modification, are permitted provided that the following conditions 864987Smsmith * are met: 964987Smsmith * 1. Redistributions of source code must retain the above copyright 1064987Smsmith * notice, this list of conditions and the following disclaimer. 1164987Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1264987Smsmith * notice, this list of conditions and the following disclaimer in the 1364987Smsmith * documentation and/or other materials provided with the distribution. 1464987Smsmith * 1564987Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1664987Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1764987Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1864987Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1964987Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2064987Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2164987Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2264987Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2364987Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2464987Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2564987Smsmith * SUCH DAMAGE. 2664987Smsmith * 2764987Smsmith * $FreeBSD$ 2864987Smsmith */ 2964987Smsmith 3064987Smsmith#include <sys/param.h> 3164987Smsmith#include <sys/systm.h> 3264987Smsmith#include <sys/malloc.h> 3364987Smsmith#include <sys/kernel.h> 3464987Smsmith#include <sys/bus.h> 3564987Smsmith#include <sys/conf.h> 3664987Smsmith#include <sys/ctype.h> 3773050Smsmith#include <sys/ioccom.h> 3873050Smsmith#include <sys/stat.h> 3964987Smsmith 4064987Smsmith#include <machine/bus.h> 4164987Smsmith#include <machine/resource.h> 4264987Smsmith#include <sys/rman.h> 4364987Smsmith 4479695Smsmith#include <cam/cam.h> 4579695Smsmith#include <cam/cam_ccb.h> 4679695Smsmith#include <cam/cam_periph.h> 4779695Smsmith#include <cam/cam_sim.h> 4879695Smsmith#include <cam/cam_xpt_sim.h> 4964987Smsmith#include <cam/scsi/scsi_all.h> 5079695Smsmith#include <cam/scsi/scsi_message.h> 5164987Smsmith 52119285Simp#include <dev/pci/pcireg.h> 53119285Simp#include <dev/pci/pcivar.h> 5479695Smsmith 5564987Smsmith#include <dev/mly/mlyreg.h> 5673050Smsmith#include <dev/mly/mlyio.h> 5764987Smsmith#include <dev/mly/mlyvar.h> 5864987Smsmith#include <dev/mly/mly_tables.h> 5964987Smsmith 6079695Smsmithstatic int mly_probe(device_t dev); 6179695Smsmithstatic int mly_attach(device_t dev); 6279695Smsmithstatic int mly_pci_attach(struct mly_softc *sc); 6379695Smsmithstatic int mly_detach(device_t dev); 6479695Smsmithstatic int mly_shutdown(device_t dev); 6579695Smsmithstatic void mly_intr(void *arg); 6679695Smsmith 6779695Smsmithstatic int mly_sg_map(struct mly_softc *sc); 6879695Smsmithstatic void mly_sg_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); 6979695Smsmithstatic int mly_mmbox_map(struct mly_softc *sc); 7079695Smsmithstatic void mly_mmbox_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); 7179695Smsmithstatic void mly_free(struct mly_softc *sc); 7279695Smsmith 7364987Smsmithstatic int mly_get_controllerinfo(struct mly_softc *sc); 7464987Smsmithstatic void mly_scan_devices(struct mly_softc *sc); 7564987Smsmithstatic void mly_rescan_btl(struct mly_softc *sc, int bus, int target); 7664987Smsmithstatic void mly_complete_rescan(struct mly_command *mc); 7764987Smsmithstatic int mly_get_eventstatus(struct mly_softc *sc); 7864987Smsmithstatic int mly_enable_mmbox(struct mly_softc *sc); 7964987Smsmithstatic int mly_flush(struct mly_softc *sc); 8064987Smsmithstatic int mly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, 8164987Smsmith size_t datasize, u_int8_t *status, void *sense_buffer, size_t *sense_length); 8279695Smsmithstatic void mly_check_event(struct mly_softc *sc); 8364987Smsmithstatic void mly_fetch_event(struct mly_softc *sc); 8464987Smsmithstatic void mly_complete_event(struct mly_command *mc); 8564987Smsmithstatic void mly_process_event(struct mly_softc *sc, struct mly_event *me); 8664987Smsmithstatic void mly_periodic(void *data); 8764987Smsmith 8864987Smsmithstatic int mly_immediate_command(struct mly_command *mc); 8964987Smsmithstatic int mly_start(struct mly_command *mc); 9079695Smsmithstatic void mly_done(struct mly_softc *sc); 9164987Smsmithstatic void mly_complete(void *context, int pending); 9264987Smsmith 9379695Smsmithstatic int mly_alloc_command(struct mly_softc *sc, struct mly_command **mcp); 9479695Smsmithstatic void mly_release_command(struct mly_command *mc); 9573050Smsmithstatic void mly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error); 9673050Smsmithstatic int mly_alloc_commands(struct mly_softc *sc); 9779695Smsmithstatic void mly_release_commands(struct mly_softc *sc); 9864987Smsmithstatic void mly_map_command(struct mly_command *mc); 9964987Smsmithstatic void mly_unmap_command(struct mly_command *mc); 10064987Smsmith 10179695Smsmithstatic int mly_cam_attach(struct mly_softc *sc); 10279695Smsmithstatic void mly_cam_detach(struct mly_softc *sc); 10379695Smsmithstatic void mly_cam_rescan_btl(struct mly_softc *sc, int bus, int target); 10479695Smsmithstatic void mly_cam_action(struct cam_sim *sim, union ccb *ccb); 10579695Smsmithstatic int mly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio); 10679695Smsmithstatic void mly_cam_poll(struct cam_sim *sim); 10779695Smsmithstatic void mly_cam_complete(struct mly_command *mc); 10879695Smsmithstatic struct cam_periph *mly_find_periph(struct mly_softc *sc, int bus, int target); 10979695Smsmithstatic int mly_name_device(struct mly_softc *sc, int bus, int target); 11079695Smsmith 11164987Smsmithstatic int mly_fwhandshake(struct mly_softc *sc); 11264987Smsmith 11364987Smsmithstatic void mly_describe_controller(struct mly_softc *sc); 11464987Smsmith#ifdef MLY_DEBUG 11564987Smsmithstatic void mly_printstate(struct mly_softc *sc); 11664987Smsmithstatic void mly_print_command(struct mly_command *mc); 11764987Smsmithstatic void mly_print_packet(struct mly_command *mc); 11864987Smsmithstatic void mly_panic(struct mly_softc *sc, char *reason); 119201795Straszstatic int mly_timeout(struct mly_softc *sc); 12064987Smsmith#endif 12173050Smsmithvoid mly_print_controller(int controller); 12264987Smsmith 12379695Smsmith 12473050Smsmithstatic d_open_t mly_user_open; 12573050Smsmithstatic d_close_t mly_user_close; 12673050Smsmithstatic d_ioctl_t mly_user_ioctl; 12773050Smsmithstatic int mly_user_command(struct mly_softc *sc, struct mly_user_command *uc); 12873050Smsmithstatic int mly_user_health(struct mly_softc *sc, struct mly_user_health *uh); 12973050Smsmith 130110479Sscottl#define MLY_CMD_TIMEOUT 20 13179695Smsmith 13279695Smsmithstatic device_method_t mly_methods[] = { 13379695Smsmith /* Device interface */ 13479695Smsmith DEVMETHOD(device_probe, mly_probe), 13579695Smsmith DEVMETHOD(device_attach, mly_attach), 13679695Smsmith DEVMETHOD(device_detach, mly_detach), 13779695Smsmith DEVMETHOD(device_shutdown, mly_shutdown), 13879695Smsmith { 0, 0 } 13979695Smsmith}; 14079695Smsmith 14179695Smsmithstatic driver_t mly_pci_driver = { 14279695Smsmith "mly", 14379695Smsmith mly_methods, 14479695Smsmith sizeof(struct mly_softc) 14579695Smsmith}; 14679695Smsmith 14779695Smsmithstatic devclass_t mly_devclass; 14879695SmsmithDRIVER_MODULE(mly, pci, mly_pci_driver, mly_devclass, 0, 0); 149165102SmjacobMODULE_DEPEND(mly, pci, 1, 1, 1); 150165102SmjacobMODULE_DEPEND(mly, cam, 1, 1, 1); 15179695Smsmith 15273050Smsmithstatic struct cdevsw mly_cdevsw = { 153126080Sphk .d_version = D_VERSION, 154126080Sphk .d_flags = D_NEEDGIANT, 155111815Sphk .d_open = mly_user_open, 156111815Sphk .d_close = mly_user_close, 157111815Sphk .d_ioctl = mly_user_ioctl, 158111815Sphk .d_name = "mly", 15973050Smsmith}; 16073050Smsmith 16164987Smsmith/******************************************************************************** 16264987Smsmith ******************************************************************************** 16364987Smsmith Device Interface 16464987Smsmith ******************************************************************************** 16564987Smsmith ********************************************************************************/ 16664987Smsmith 16779695Smsmithstatic struct mly_ident 16879695Smsmith{ 16979695Smsmith u_int16_t vendor; 17079695Smsmith u_int16_t device; 17179695Smsmith u_int16_t subvendor; 17279695Smsmith u_int16_t subdevice; 17379695Smsmith int hwif; 17479695Smsmith char *desc; 17579695Smsmith} mly_identifiers[] = { 17679695Smsmith {0x1069, 0xba56, 0x1069, 0x0040, MLY_HWIF_STRONGARM, "Mylex eXtremeRAID 2000"}, 17779695Smsmith {0x1069, 0xba56, 0x1069, 0x0030, MLY_HWIF_STRONGARM, "Mylex eXtremeRAID 3000"}, 17879695Smsmith {0x1069, 0x0050, 0x1069, 0x0050, MLY_HWIF_I960RX, "Mylex AcceleRAID 352"}, 17979695Smsmith {0x1069, 0x0050, 0x1069, 0x0052, MLY_HWIF_I960RX, "Mylex AcceleRAID 170"}, 18079695Smsmith {0x1069, 0x0050, 0x1069, 0x0054, MLY_HWIF_I960RX, "Mylex AcceleRAID 160"}, 18179695Smsmith {0, 0, 0, 0, 0, 0} 18279695Smsmith}; 18379695Smsmith 18464987Smsmith/******************************************************************************** 18579695Smsmith * Compare the provided PCI device with the list we support. 18679695Smsmith */ 18779695Smsmithstatic int 18879695Smsmithmly_probe(device_t dev) 18979695Smsmith{ 19079695Smsmith struct mly_ident *m; 19179695Smsmith 19279695Smsmith debug_called(1); 19379695Smsmith 19479695Smsmith for (m = mly_identifiers; m->vendor != 0; m++) { 19579695Smsmith if ((m->vendor == pci_get_vendor(dev)) && 19679695Smsmith (m->device == pci_get_device(dev)) && 19779695Smsmith ((m->subvendor == 0) || ((m->subvendor == pci_get_subvendor(dev)) && 19879695Smsmith (m->subdevice == pci_get_subdevice(dev))))) { 19979695Smsmith 20079695Smsmith device_set_desc(dev, m->desc); 201143158Simp return(BUS_PROBE_DEFAULT); /* allow room to be overridden */ 20279695Smsmith } 20379695Smsmith } 20479695Smsmith return(ENXIO); 20579695Smsmith} 20679695Smsmith 20779695Smsmith/******************************************************************************** 20864987Smsmith * Initialise the controller and softc 20964987Smsmith */ 210105215Sphkstatic int 21179695Smsmithmly_attach(device_t dev) 21264987Smsmith{ 21379695Smsmith struct mly_softc *sc = device_get_softc(dev); 21479695Smsmith int error; 21564987Smsmith 21664987Smsmith debug_called(1); 21764987Smsmith 21879695Smsmith sc->mly_dev = dev; 21979695Smsmith 22079695Smsmith#ifdef MLY_DEBUG 22179695Smsmith if (device_get_unit(sc->mly_dev) == 0) 22279695Smsmith mly_softc0 = sc; 22379695Smsmith#endif 22479695Smsmith 22564987Smsmith /* 22679695Smsmith * Do PCI-specific initialisation. 22779695Smsmith */ 22879695Smsmith if ((error = mly_pci_attach(sc)) != 0) 22979695Smsmith goto out; 23079695Smsmith 23179695Smsmith /* 23264987Smsmith * Initialise per-controller queues. 23364987Smsmith */ 23473050Smsmith mly_initq_free(sc); 23573050Smsmith mly_initq_busy(sc); 23673050Smsmith mly_initq_complete(sc); 23764987Smsmith 23864987Smsmith /* 23964987Smsmith * Initialise command-completion task. 24064987Smsmith */ 24164987Smsmith TASK_INIT(&sc->mly_task_complete, 0, mly_complete, sc); 24264987Smsmith 24364987Smsmith /* disable interrupts before we start talking to the controller */ 24464987Smsmith MLY_MASK_INTERRUPTS(sc); 24564987Smsmith 24664987Smsmith /* 24764987Smsmith * Wait for the controller to come ready, handshake with the firmware if required. 24864987Smsmith * This is typically only necessary on platforms where the controller BIOS does not 24964987Smsmith * run. 25064987Smsmith */ 25164987Smsmith if ((error = mly_fwhandshake(sc))) 25279695Smsmith goto out; 25364987Smsmith 25464987Smsmith /* 25579695Smsmith * Allocate initial command buffers. 25664987Smsmith */ 25773050Smsmith if ((error = mly_alloc_commands(sc))) 25879695Smsmith goto out; 25964987Smsmith 26064987Smsmith /* 26164987Smsmith * Obtain controller feature information 26264987Smsmith */ 26364987Smsmith if ((error = mly_get_controllerinfo(sc))) 26479695Smsmith goto out; 26564987Smsmith 26664987Smsmith /* 26779695Smsmith * Reallocate command buffers now we know how many we want. 26879695Smsmith */ 26979695Smsmith mly_release_commands(sc); 27079695Smsmith if ((error = mly_alloc_commands(sc))) 27179695Smsmith goto out; 27279695Smsmith 27379695Smsmith /* 27464987Smsmith * Get the current event counter for health purposes, populate the initial 27564987Smsmith * health status buffer. 27664987Smsmith */ 27764987Smsmith if ((error = mly_get_eventstatus(sc))) 27879695Smsmith goto out; 27964987Smsmith 28064987Smsmith /* 28179695Smsmith * Enable memory-mailbox mode. 28264987Smsmith */ 28364987Smsmith if ((error = mly_enable_mmbox(sc))) 28479695Smsmith goto out; 28564987Smsmith 28664987Smsmith /* 28764987Smsmith * Attach to CAM. 28864987Smsmith */ 28964987Smsmith if ((error = mly_cam_attach(sc))) 29079695Smsmith goto out; 29164987Smsmith 29264987Smsmith /* 29364987Smsmith * Print a little information about the controller 29464987Smsmith */ 29564987Smsmith mly_describe_controller(sc); 29664987Smsmith 29764987Smsmith /* 29879695Smsmith * Mark all attached devices for rescan. 29964987Smsmith */ 30064987Smsmith mly_scan_devices(sc); 30164987Smsmith 30264987Smsmith /* 30364987Smsmith * Instigate the first status poll immediately. Rescan completions won't 30464987Smsmith * happen until interrupts are enabled, which should still be before 30579695Smsmith * the SCSI subsystem gets to us, courtesy of the "SCSI settling delay". 30664987Smsmith */ 30764987Smsmith mly_periodic((void *)sc); 30864987Smsmith 30973050Smsmith /* 31073050Smsmith * Create the control device. 31173050Smsmith */ 312191242Sed sc->mly_dev_t = make_dev(&mly_cdevsw, 0, UID_ROOT, GID_OPERATOR, 31373050Smsmith S_IRUSR | S_IWUSR, "mly%d", device_get_unit(sc->mly_dev)); 31473050Smsmith sc->mly_dev_t->si_drv1 = sc; 31573050Smsmith 31664987Smsmith /* enable interrupts now */ 31764987Smsmith MLY_UNMASK_INTERRUPTS(sc); 31864987Smsmith 319110479Sscottl#ifdef MLY_DEBUG 320110479Sscottl timeout((timeout_t *)mly_timeout, sc, MLY_CMD_TIMEOUT * hz); 321110479Sscottl#endif 322110479Sscottl 32379695Smsmith out: 32479695Smsmith if (error != 0) 32579695Smsmith mly_free(sc); 32679695Smsmith return(error); 32779695Smsmith} 32879695Smsmith 32979695Smsmith/******************************************************************************** 33079695Smsmith * Perform PCI-specific initialisation. 33179695Smsmith */ 33279695Smsmithstatic int 33379695Smsmithmly_pci_attach(struct mly_softc *sc) 33479695Smsmith{ 33579695Smsmith int i, error; 33679695Smsmith 33779695Smsmith debug_called(1); 33879695Smsmith 33979695Smsmith /* assume failure is 'not configured' */ 34079695Smsmith error = ENXIO; 34179695Smsmith 34279695Smsmith /* 34379695Smsmith * Verify that the adapter is correctly set up in PCI space. 34479695Smsmith */ 345254263Sscottl pci_enable_busmaster(sc->mly_dev); 34679695Smsmith 34779695Smsmith /* 34879695Smsmith * Allocate the PCI register window. 34979695Smsmith */ 350119690Sjhb sc->mly_regs_rid = PCIR_BAR(0); /* first base address register */ 351127135Snjl if ((sc->mly_regs_resource = bus_alloc_resource_any(sc->mly_dev, 352127135Snjl SYS_RES_MEMORY, &sc->mly_regs_rid, RF_ACTIVE)) == NULL) { 35379695Smsmith mly_printf(sc, "can't allocate register window\n"); 35479695Smsmith goto fail; 35579695Smsmith } 35679695Smsmith sc->mly_btag = rman_get_bustag(sc->mly_regs_resource); 35779695Smsmith sc->mly_bhandle = rman_get_bushandle(sc->mly_regs_resource); 35879695Smsmith 35979695Smsmith /* 36079695Smsmith * Allocate and connect our interrupt. 36179695Smsmith */ 36279695Smsmith sc->mly_irq_rid = 0; 363127135Snjl if ((sc->mly_irq = bus_alloc_resource_any(sc->mly_dev, SYS_RES_IRQ, 364127135Snjl &sc->mly_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 36579695Smsmith mly_printf(sc, "can't allocate interrupt\n"); 36679695Smsmith goto fail; 36779695Smsmith } 368166901Spiso if (bus_setup_intr(sc->mly_dev, sc->mly_irq, INTR_TYPE_CAM | INTR_ENTROPY, NULL, mly_intr, sc, &sc->mly_intr)) { 36979695Smsmith mly_printf(sc, "can't set up interrupt\n"); 37079695Smsmith goto fail; 37179695Smsmith } 37279695Smsmith 37379695Smsmith /* assume failure is 'out of memory' */ 37479695Smsmith error = ENOMEM; 37579695Smsmith 37679695Smsmith /* 37779695Smsmith * Allocate the parent bus DMA tag appropriate for our PCI interface. 37879695Smsmith * 37979695Smsmith * Note that all of these controllers are 64-bit capable. 38079695Smsmith */ 381232854Sscottl if (bus_dma_tag_create(bus_get_dma_tag(sc->mly_dev),/* PCI parent */ 38279695Smsmith 1, 0, /* alignment, boundary */ 38379695Smsmith BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 38479695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 38579695Smsmith NULL, NULL, /* filter, filterarg */ 38679695Smsmith MAXBSIZE, MLY_MAX_SGENTRIES, /* maxsize, nsegments */ 38779695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 38879695Smsmith BUS_DMA_ALLOCNOW, /* flags */ 389117126Sscottl NULL, /* lockfunc */ 390117126Sscottl NULL, /* lockarg */ 39179695Smsmith &sc->mly_parent_dmat)) { 39279695Smsmith mly_printf(sc, "can't allocate parent DMA tag\n"); 39379695Smsmith goto fail; 39479695Smsmith } 39579695Smsmith 39679695Smsmith /* 39779695Smsmith * Create DMA tag for mapping buffers into controller-addressable space. 39879695Smsmith */ 39979695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 40079695Smsmith 1, 0, /* alignment, boundary */ 40179695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 40279695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 40379695Smsmith NULL, NULL, /* filter, filterarg */ 40479695Smsmith MAXBSIZE, MLY_MAX_SGENTRIES, /* maxsize, nsegments */ 40579695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 40679695Smsmith 0, /* flags */ 407117126Sscottl busdma_lock_mutex, /* lockfunc */ 408117126Sscottl &Giant, /* lockarg */ 40979695Smsmith &sc->mly_buffer_dmat)) { 41079695Smsmith mly_printf(sc, "can't allocate buffer DMA tag\n"); 41179695Smsmith goto fail; 41279695Smsmith } 41379695Smsmith 41479695Smsmith /* 41579695Smsmith * Initialise the DMA tag for command packets. 41679695Smsmith */ 41779695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 41879695Smsmith 1, 0, /* alignment, boundary */ 41979695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 42079695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 42179695Smsmith NULL, NULL, /* filter, filterarg */ 42279695Smsmith sizeof(union mly_command_packet) * MLY_MAX_COMMANDS, 1, /* maxsize, nsegments */ 42379695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 424118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 425118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 42679695Smsmith &sc->mly_packet_dmat)) { 42779695Smsmith mly_printf(sc, "can't allocate command packet DMA tag\n"); 42879695Smsmith goto fail; 42979695Smsmith } 43079695Smsmith 43179695Smsmith /* 43279695Smsmith * Detect the hardware interface version 43379695Smsmith */ 43479695Smsmith for (i = 0; mly_identifiers[i].vendor != 0; i++) { 43579695Smsmith if ((mly_identifiers[i].vendor == pci_get_vendor(sc->mly_dev)) && 43679695Smsmith (mly_identifiers[i].device == pci_get_device(sc->mly_dev))) { 43779695Smsmith sc->mly_hwif = mly_identifiers[i].hwif; 43879695Smsmith switch(sc->mly_hwif) { 43979695Smsmith case MLY_HWIF_I960RX: 44079695Smsmith debug(1, "set hardware up for i960RX"); 44179695Smsmith sc->mly_doorbell_true = 0x00; 44279695Smsmith sc->mly_command_mailbox = MLY_I960RX_COMMAND_MAILBOX; 44379695Smsmith sc->mly_status_mailbox = MLY_I960RX_STATUS_MAILBOX; 44479695Smsmith sc->mly_idbr = MLY_I960RX_IDBR; 44579695Smsmith sc->mly_odbr = MLY_I960RX_ODBR; 44679695Smsmith sc->mly_error_status = MLY_I960RX_ERROR_STATUS; 44779695Smsmith sc->mly_interrupt_status = MLY_I960RX_INTERRUPT_STATUS; 44879695Smsmith sc->mly_interrupt_mask = MLY_I960RX_INTERRUPT_MASK; 44979695Smsmith break; 45079695Smsmith case MLY_HWIF_STRONGARM: 45179695Smsmith debug(1, "set hardware up for StrongARM"); 45279695Smsmith sc->mly_doorbell_true = 0xff; /* doorbell 'true' is 0 */ 45379695Smsmith sc->mly_command_mailbox = MLY_STRONGARM_COMMAND_MAILBOX; 45479695Smsmith sc->mly_status_mailbox = MLY_STRONGARM_STATUS_MAILBOX; 45579695Smsmith sc->mly_idbr = MLY_STRONGARM_IDBR; 45679695Smsmith sc->mly_odbr = MLY_STRONGARM_ODBR; 45779695Smsmith sc->mly_error_status = MLY_STRONGARM_ERROR_STATUS; 45879695Smsmith sc->mly_interrupt_status = MLY_STRONGARM_INTERRUPT_STATUS; 45979695Smsmith sc->mly_interrupt_mask = MLY_STRONGARM_INTERRUPT_MASK; 46079695Smsmith break; 46179695Smsmith } 46279695Smsmith break; 46379695Smsmith } 46479695Smsmith } 46579695Smsmith 46679695Smsmith /* 46779695Smsmith * Create the scatter/gather mappings. 46879695Smsmith */ 46979695Smsmith if ((error = mly_sg_map(sc))) 47079695Smsmith goto fail; 47179695Smsmith 47279695Smsmith /* 47379695Smsmith * Allocate and map the memory mailbox 47479695Smsmith */ 47579695Smsmith if ((error = mly_mmbox_map(sc))) 47679695Smsmith goto fail; 47779695Smsmith 47879695Smsmith error = 0; 47979695Smsmith 48079695Smsmithfail: 48179695Smsmith return(error); 48279695Smsmith} 48379695Smsmith 48479695Smsmith/******************************************************************************** 48579695Smsmith * Shut the controller down and detach all our resources. 48679695Smsmith */ 48779695Smsmithstatic int 48879695Smsmithmly_detach(device_t dev) 48979695Smsmith{ 49079695Smsmith int error; 49179695Smsmith 49279695Smsmith if ((error = mly_shutdown(dev)) != 0) 49379695Smsmith return(error); 49479695Smsmith 49579695Smsmith mly_free(device_get_softc(dev)); 49664987Smsmith return(0); 49764987Smsmith} 49864987Smsmith 49964987Smsmith/******************************************************************************** 50064987Smsmith * Bring the controller to a state where it can be safely left alone. 50179695Smsmith * 50279695Smsmith * Note that it should not be necessary to wait for any outstanding commands, 50379695Smsmith * as they should be completed prior to calling here. 50479695Smsmith * 50579695Smsmith * XXX this applies for I/O, but not status polls; we should beware of 50679695Smsmith * the case where a status command is running while we detach. 50764987Smsmith */ 50879695Smsmithstatic int 50979695Smsmithmly_shutdown(device_t dev) 51064987Smsmith{ 51179695Smsmith struct mly_softc *sc = device_get_softc(dev); 51264987Smsmith 51364987Smsmith debug_called(1); 51479695Smsmith 51579695Smsmith if (sc->mly_state & MLY_STATE_OPEN) 51679695Smsmith return(EBUSY); 51764987Smsmith 51864987Smsmith /* kill the periodic event */ 51964987Smsmith untimeout(mly_periodic, sc, sc->mly_periodic); 52064987Smsmith 52164987Smsmith /* flush controller */ 52264987Smsmith mly_printf(sc, "flushing cache..."); 52364987Smsmith printf("%s\n", mly_flush(sc) ? "failed" : "done"); 52464987Smsmith 52564987Smsmith MLY_MASK_INTERRUPTS(sc); 52679695Smsmith 52779695Smsmith return(0); 52864987Smsmith} 52964987Smsmith 53079695Smsmith/******************************************************************************* 53179695Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 53279695Smsmith * status. 53379695Smsmith */ 53479695Smsmithstatic void 53579695Smsmithmly_intr(void *arg) 53679695Smsmith{ 53779695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 53879695Smsmith 53979695Smsmith debug_called(2); 54079695Smsmith 54179695Smsmith mly_done(sc); 54279695Smsmith}; 54379695Smsmith 54464987Smsmith/******************************************************************************** 54564987Smsmith ******************************************************************************** 54679695Smsmith Bus-dependant Resource Management 54779695Smsmith ******************************************************************************** 54879695Smsmith ********************************************************************************/ 54979695Smsmith 55079695Smsmith/******************************************************************************** 55179695Smsmith * Allocate memory for the scatter/gather tables 55279695Smsmith */ 55379695Smsmithstatic int 55479695Smsmithmly_sg_map(struct mly_softc *sc) 55579695Smsmith{ 55679695Smsmith size_t segsize; 55779695Smsmith 55879695Smsmith debug_called(1); 55979695Smsmith 56079695Smsmith /* 56179695Smsmith * Create a single tag describing a region large enough to hold all of 56279695Smsmith * the s/g lists we will need. 56379695Smsmith */ 564118762Sscottl segsize = sizeof(struct mly_sg_entry) * MLY_MAX_COMMANDS *MLY_MAX_SGENTRIES; 56579695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 566118762Sscottl 1, 0, /* alignment,boundary */ 56779695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 56879695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 56979695Smsmith NULL, NULL, /* filter, filterarg */ 57079695Smsmith segsize, 1, /* maxsize, nsegments */ 57179695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 572118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 573118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 57479695Smsmith &sc->mly_sg_dmat)) { 57579695Smsmith mly_printf(sc, "can't allocate scatter/gather DMA tag\n"); 57679695Smsmith return(ENOMEM); 57779695Smsmith } 57879695Smsmith 57979695Smsmith /* 58079695Smsmith * Allocate enough s/g maps for all commands and permanently map them into 58179695Smsmith * controller-visible space. 58279695Smsmith * 58379695Smsmith * XXX this assumes we can get enough space for all the s/g maps in one 58479695Smsmith * contiguous slab. 58579695Smsmith */ 586118762Sscottl if (bus_dmamem_alloc(sc->mly_sg_dmat, (void **)&sc->mly_sg_table, 587118762Sscottl BUS_DMA_NOWAIT, &sc->mly_sg_dmamap)) { 58879695Smsmith mly_printf(sc, "can't allocate s/g table\n"); 58979695Smsmith return(ENOMEM); 59079695Smsmith } 591118762Sscottl if (bus_dmamap_load(sc->mly_sg_dmat, sc->mly_sg_dmamap, sc->mly_sg_table, 592118762Sscottl segsize, mly_sg_map_helper, sc, BUS_DMA_NOWAIT) != 0) 593118762Sscottl return (ENOMEM); 59479695Smsmith return(0); 59579695Smsmith} 59679695Smsmith 59779695Smsmith/******************************************************************************** 59879695Smsmith * Save the physical address of the base of the s/g table. 59979695Smsmith */ 60079695Smsmithstatic void 60179695Smsmithmly_sg_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 60279695Smsmith{ 60379695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 60479695Smsmith 60579695Smsmith debug_called(1); 60679695Smsmith 60779695Smsmith /* save base of s/g table's address in bus space */ 60879695Smsmith sc->mly_sg_busaddr = segs->ds_addr; 60979695Smsmith} 61079695Smsmith 61179695Smsmith/******************************************************************************** 61279695Smsmith * Allocate memory for the memory-mailbox interface 61379695Smsmith */ 61479695Smsmithstatic int 61579695Smsmithmly_mmbox_map(struct mly_softc *sc) 61679695Smsmith{ 61779695Smsmith 61879695Smsmith /* 61979695Smsmith * Create a DMA tag for a single contiguous region large enough for the 62079695Smsmith * memory mailbox structure. 62179695Smsmith */ 62279695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 623118762Sscottl 1, 0, /* alignment,boundary */ 62479695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 62579695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 62679695Smsmith NULL, NULL, /* filter, filterarg */ 62779695Smsmith sizeof(struct mly_mmbox), 1, /* maxsize, nsegments */ 62879695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 629118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 630118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 63179695Smsmith &sc->mly_mmbox_dmat)) { 63279695Smsmith mly_printf(sc, "can't allocate memory mailbox DMA tag\n"); 63379695Smsmith return(ENOMEM); 63479695Smsmith } 63579695Smsmith 63679695Smsmith /* 63779695Smsmith * Allocate the buffer 63879695Smsmith */ 63979695Smsmith if (bus_dmamem_alloc(sc->mly_mmbox_dmat, (void **)&sc->mly_mmbox, BUS_DMA_NOWAIT, &sc->mly_mmbox_dmamap)) { 64079695Smsmith mly_printf(sc, "can't allocate memory mailbox\n"); 64179695Smsmith return(ENOMEM); 64279695Smsmith } 643118762Sscottl if (bus_dmamap_load(sc->mly_mmbox_dmat, sc->mly_mmbox_dmamap, sc->mly_mmbox, 644118762Sscottl sizeof(struct mly_mmbox), mly_mmbox_map_helper, sc, 645118762Sscottl BUS_DMA_NOWAIT) != 0) 646118762Sscottl return (ENOMEM); 64779695Smsmith bzero(sc->mly_mmbox, sizeof(*sc->mly_mmbox)); 64879695Smsmith return(0); 64979695Smsmith 65079695Smsmith} 65179695Smsmith 65279695Smsmith/******************************************************************************** 65379695Smsmith * Save the physical address of the memory mailbox 65479695Smsmith */ 65579695Smsmithstatic void 65679695Smsmithmly_mmbox_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 65779695Smsmith{ 65879695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 65979695Smsmith 66079695Smsmith debug_called(1); 66179695Smsmith 66279695Smsmith sc->mly_mmbox_busaddr = segs->ds_addr; 66379695Smsmith} 66479695Smsmith 66579695Smsmith/******************************************************************************** 66679695Smsmith * Free all of the resources associated with (sc) 66779695Smsmith * 66879695Smsmith * Should not be called if the controller is active. 66979695Smsmith */ 670105215Sphkstatic void 67179695Smsmithmly_free(struct mly_softc *sc) 67279695Smsmith{ 67379695Smsmith 67479695Smsmith debug_called(1); 67579695Smsmith 676108926Sscottl /* Remove the management device */ 677108926Sscottl destroy_dev(sc->mly_dev_t); 678108926Sscottl 67979695Smsmith /* detach from CAM */ 68079695Smsmith mly_cam_detach(sc); 68179695Smsmith 68279695Smsmith /* release command memory */ 68379695Smsmith mly_release_commands(sc); 68479695Smsmith 68579695Smsmith /* throw away the controllerinfo structure */ 68679695Smsmith if (sc->mly_controllerinfo != NULL) 68779695Smsmith free(sc->mly_controllerinfo, M_DEVBUF); 68879695Smsmith 68979695Smsmith /* throw away the controllerparam structure */ 69079695Smsmith if (sc->mly_controllerparam != NULL) 69179695Smsmith free(sc->mly_controllerparam, M_DEVBUF); 69279695Smsmith 69379695Smsmith /* destroy data-transfer DMA tag */ 69479695Smsmith if (sc->mly_buffer_dmat) 69579695Smsmith bus_dma_tag_destroy(sc->mly_buffer_dmat); 69679695Smsmith 69779695Smsmith /* free and destroy DMA memory and tag for s/g lists */ 69879695Smsmith if (sc->mly_sg_table) { 69979695Smsmith bus_dmamap_unload(sc->mly_sg_dmat, sc->mly_sg_dmamap); 70079695Smsmith bus_dmamem_free(sc->mly_sg_dmat, sc->mly_sg_table, sc->mly_sg_dmamap); 70179695Smsmith } 70279695Smsmith if (sc->mly_sg_dmat) 70379695Smsmith bus_dma_tag_destroy(sc->mly_sg_dmat); 70479695Smsmith 70579695Smsmith /* free and destroy DMA memory and tag for memory mailbox */ 70679695Smsmith if (sc->mly_mmbox) { 70779695Smsmith bus_dmamap_unload(sc->mly_mmbox_dmat, sc->mly_mmbox_dmamap); 70879695Smsmith bus_dmamem_free(sc->mly_mmbox_dmat, sc->mly_mmbox, sc->mly_mmbox_dmamap); 70979695Smsmith } 71079695Smsmith if (sc->mly_mmbox_dmat) 71179695Smsmith bus_dma_tag_destroy(sc->mly_mmbox_dmat); 71279695Smsmith 71379695Smsmith /* disconnect the interrupt handler */ 71479695Smsmith if (sc->mly_intr) 71579695Smsmith bus_teardown_intr(sc->mly_dev, sc->mly_irq, sc->mly_intr); 71679695Smsmith if (sc->mly_irq != NULL) 71779695Smsmith bus_release_resource(sc->mly_dev, SYS_RES_IRQ, sc->mly_irq_rid, sc->mly_irq); 71879695Smsmith 71979695Smsmith /* destroy the parent DMA tag */ 72079695Smsmith if (sc->mly_parent_dmat) 72179695Smsmith bus_dma_tag_destroy(sc->mly_parent_dmat); 72279695Smsmith 72379695Smsmith /* release the register window mapping */ 72479695Smsmith if (sc->mly_regs_resource != NULL) 72579695Smsmith bus_release_resource(sc->mly_dev, SYS_RES_MEMORY, sc->mly_regs_rid, sc->mly_regs_resource); 72679695Smsmith} 72779695Smsmith 72879695Smsmith/******************************************************************************** 72979695Smsmith ******************************************************************************** 73064987Smsmith Command Wrappers 73164987Smsmith ******************************************************************************** 73264987Smsmith ********************************************************************************/ 73364987Smsmith 73464987Smsmith/******************************************************************************** 73564987Smsmith * Fill in the mly_controllerinfo and mly_controllerparam fields in the softc. 73664987Smsmith */ 73764987Smsmithstatic int 73864987Smsmithmly_get_controllerinfo(struct mly_softc *sc) 73964987Smsmith{ 74064987Smsmith struct mly_command_ioctl mci; 74164987Smsmith u_int8_t status; 74264987Smsmith int error; 74364987Smsmith 74464987Smsmith debug_called(1); 74564987Smsmith 74664987Smsmith if (sc->mly_controllerinfo != NULL) 74764987Smsmith free(sc->mly_controllerinfo, M_DEVBUF); 74864987Smsmith 74964987Smsmith /* build the getcontrollerinfo ioctl and send it */ 75064987Smsmith bzero(&mci, sizeof(mci)); 75164987Smsmith sc->mly_controllerinfo = NULL; 75264987Smsmith mci.sub_ioctl = MDACIOCTL_GETCONTROLLERINFO; 75364987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerinfo, sizeof(*sc->mly_controllerinfo), 75464987Smsmith &status, NULL, NULL))) 75564987Smsmith return(error); 75664987Smsmith if (status != 0) 75764987Smsmith return(EIO); 75864987Smsmith 75964987Smsmith if (sc->mly_controllerparam != NULL) 76064987Smsmith free(sc->mly_controllerparam, M_DEVBUF); 76164987Smsmith 76264987Smsmith /* build the getcontrollerparameter ioctl and send it */ 76364987Smsmith bzero(&mci, sizeof(mci)); 76464987Smsmith sc->mly_controllerparam = NULL; 76564987Smsmith mci.sub_ioctl = MDACIOCTL_GETCONTROLLERPARAMETER; 76664987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerparam, sizeof(*sc->mly_controllerparam), 76764987Smsmith &status, NULL, NULL))) 76864987Smsmith return(error); 76964987Smsmith if (status != 0) 77064987Smsmith return(EIO); 77164987Smsmith 77264987Smsmith return(0); 77364987Smsmith} 77464987Smsmith 77564987Smsmith/******************************************************************************** 77664987Smsmith * Schedule all possible devices for a rescan. 77764987Smsmith * 77864987Smsmith */ 77964987Smsmithstatic void 78064987Smsmithmly_scan_devices(struct mly_softc *sc) 78164987Smsmith{ 78279695Smsmith int bus, target; 78364987Smsmith 78464987Smsmith debug_called(1); 78564987Smsmith 78664987Smsmith /* 78764987Smsmith * Clear any previous BTL information. 78864987Smsmith */ 78964987Smsmith bzero(&sc->mly_btl, sizeof(sc->mly_btl)); 79064987Smsmith 79164987Smsmith /* 79279695Smsmith * Mark all devices as requiring a rescan, and let the next 79379695Smsmith * periodic scan collect them. 79464987Smsmith */ 79579695Smsmith for (bus = 0; bus < sc->mly_cam_channels; bus++) 79679695Smsmith if (MLY_BUS_IS_VALID(sc, bus)) 79779695Smsmith for (target = 0; target < MLY_MAX_TARGETS; target++) 79879695Smsmith sc->mly_btl[bus][target].mb_flags = MLY_BTL_RESCAN; 79964987Smsmith 80064987Smsmith} 80164987Smsmith 80264987Smsmith/******************************************************************************** 80364987Smsmith * Rescan a device, possibly as a consequence of getting an event which suggests 80464987Smsmith * that it may have changed. 80579695Smsmith * 80679695Smsmith * If we suffer resource starvation, we can abandon the rescan as we'll be 80779695Smsmith * retried. 80864987Smsmith */ 80964987Smsmithstatic void 81064987Smsmithmly_rescan_btl(struct mly_softc *sc, int bus, int target) 81164987Smsmith{ 81264987Smsmith struct mly_command *mc; 81364987Smsmith struct mly_command_ioctl *mci; 81464987Smsmith 81579695Smsmith debug_called(1); 81664987Smsmith 81779695Smsmith /* check that this bus is valid */ 81879695Smsmith if (!MLY_BUS_IS_VALID(sc, bus)) 81979695Smsmith return; 82079695Smsmith 82164987Smsmith /* get a command */ 82264987Smsmith if (mly_alloc_command(sc, &mc)) 82379695Smsmith return; 82464987Smsmith 82564987Smsmith /* set up the data buffer */ 82668877Sdwmalone if ((mc->mc_data = malloc(sizeof(union mly_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 82764987Smsmith mly_release_command(mc); 82879695Smsmith return; 82964987Smsmith } 83064987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 83164987Smsmith mc->mc_complete = mly_complete_rescan; 83264987Smsmith 83364987Smsmith /* 83464987Smsmith * Build the ioctl. 83564987Smsmith */ 83664987Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 83764987Smsmith mci->opcode = MDACMD_IOCTL; 83864987Smsmith mci->addr.phys.controller = 0; 83964987Smsmith mci->timeout.value = 30; 84064987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 84185324Smsmith if (MLY_BUS_IS_VIRTUAL(sc, bus)) { 84264987Smsmith mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getlogdevinfovalid); 84364987Smsmith mci->sub_ioctl = MDACIOCTL_GETLOGDEVINFOVALID; 84479695Smsmith mci->addr.log.logdev = MLY_LOGDEV_ID(sc, bus, target); 84579695Smsmith debug(1, "logical device %d", mci->addr.log.logdev); 84664987Smsmith } else { 84764987Smsmith mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getphysdevinfovalid); 84864987Smsmith mci->sub_ioctl = MDACIOCTL_GETPHYSDEVINFOVALID; 84964987Smsmith mci->addr.phys.lun = 0; 85064987Smsmith mci->addr.phys.target = target; 85164987Smsmith mci->addr.phys.channel = bus; 85279695Smsmith debug(1, "physical device %d:%d", mci->addr.phys.channel, mci->addr.phys.target); 85364987Smsmith } 85464987Smsmith 85564987Smsmith /* 85679695Smsmith * Dispatch the command. If we successfully send the command, clear the rescan 85779695Smsmith * bit. 85864987Smsmith */ 85979695Smsmith if (mly_start(mc) != 0) { 86079695Smsmith mly_release_command(mc); 86179695Smsmith } else { 86279695Smsmith sc->mly_btl[bus][target].mb_flags &= ~MLY_BTL_RESCAN; /* success */ 86379695Smsmith } 86464987Smsmith} 86564987Smsmith 86664987Smsmith/******************************************************************************** 86764987Smsmith * Handle the completion of a rescan operation 86864987Smsmith */ 86964987Smsmithstatic void 87064987Smsmithmly_complete_rescan(struct mly_command *mc) 87164987Smsmith{ 87264987Smsmith struct mly_softc *sc = mc->mc_sc; 87364987Smsmith struct mly_ioctl_getlogdevinfovalid *ldi; 87464987Smsmith struct mly_ioctl_getphysdevinfovalid *pdi; 87579695Smsmith struct mly_command_ioctl *mci; 87679695Smsmith struct mly_btl btl, *btlp; 87779695Smsmith int bus, target, rescan; 87864987Smsmith 87979695Smsmith debug_called(1); 88064987Smsmith 88179695Smsmith /* 88279695Smsmith * Recover the bus and target from the command. We need these even in 88379695Smsmith * the case where we don't have a useful response. 88479695Smsmith */ 88579695Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 88679695Smsmith if (mci->sub_ioctl == MDACIOCTL_GETLOGDEVINFOVALID) { 88779695Smsmith bus = MLY_LOGDEV_BUS(sc, mci->addr.log.logdev); 88879695Smsmith target = MLY_LOGDEV_TARGET(sc, mci->addr.log.logdev); 88979695Smsmith } else { 89079695Smsmith bus = mci->addr.phys.channel; 89179695Smsmith target = mci->addr.phys.target; 89279695Smsmith } 89379695Smsmith /* XXX validate bus/target? */ 89479695Smsmith 89579695Smsmith /* the default result is 'no device' */ 89679695Smsmith bzero(&btl, sizeof(btl)); 89779695Smsmith 89879695Smsmith /* if the rescan completed OK, we have possibly-new BTL data */ 89964987Smsmith if (mc->mc_status == 0) { 90064987Smsmith if (mc->mc_length == sizeof(*ldi)) { 90164987Smsmith ldi = (struct mly_ioctl_getlogdevinfovalid *)mc->mc_data; 90279695Smsmith if ((MLY_LOGDEV_BUS(sc, ldi->logical_device_number) != bus) || 90379695Smsmith (MLY_LOGDEV_TARGET(sc, ldi->logical_device_number) != target)) { 90479695Smsmith mly_printf(sc, "WARNING: BTL rescan for %d:%d returned data for %d:%d instead\n", 90579695Smsmith bus, target, MLY_LOGDEV_BUS(sc, ldi->logical_device_number), 90679695Smsmith MLY_LOGDEV_TARGET(sc, ldi->logical_device_number)); 90779695Smsmith /* XXX what can we do about this? */ 90879695Smsmith } 90979695Smsmith btl.mb_flags = MLY_BTL_LOGICAL; 91079695Smsmith btl.mb_type = ldi->raid_level; 91179695Smsmith btl.mb_state = ldi->state; 91279695Smsmith debug(1, "BTL rescan for %d returns %s, %s", ldi->logical_device_number, 91364987Smsmith mly_describe_code(mly_table_device_type, ldi->raid_level), 91464987Smsmith mly_describe_code(mly_table_device_state, ldi->state)); 91564987Smsmith } else if (mc->mc_length == sizeof(*pdi)) { 91664987Smsmith pdi = (struct mly_ioctl_getphysdevinfovalid *)mc->mc_data; 91779695Smsmith if ((pdi->channel != bus) || (pdi->target != target)) { 91879695Smsmith mly_printf(sc, "WARNING: BTL rescan for %d:%d returned data for %d:%d instead\n", 91979695Smsmith bus, target, pdi->channel, pdi->target); 92079695Smsmith /* XXX what can we do about this? */ 92179695Smsmith } 92279695Smsmith btl.mb_flags = MLY_BTL_PHYSICAL; 92379695Smsmith btl.mb_type = MLY_DEVICE_TYPE_PHYSICAL; 92479695Smsmith btl.mb_state = pdi->state; 92579695Smsmith btl.mb_speed = pdi->speed; 92679695Smsmith btl.mb_width = pdi->width; 92764987Smsmith if (pdi->state != MLY_DEVICE_STATE_UNCONFIGURED) 92864987Smsmith sc->mly_btl[bus][target].mb_flags |= MLY_BTL_PROTECTED; 92979695Smsmith debug(1, "BTL rescan for %d:%d returns %s", bus, target, 93064987Smsmith mly_describe_code(mly_table_device_state, pdi->state)); 93164987Smsmith } else { 93279695Smsmith mly_printf(sc, "BTL rescan result invalid\n"); 93364987Smsmith } 93464987Smsmith } 93579695Smsmith 93664987Smsmith free(mc->mc_data, M_DEVBUF); 93764987Smsmith mly_release_command(mc); 93879695Smsmith 93979695Smsmith /* 94079695Smsmith * Decide whether we need to rescan the device. 94179695Smsmith */ 94279695Smsmith rescan = 0; 94379695Smsmith 94479695Smsmith /* device type changes (usually between 'nothing' and 'something') */ 94579695Smsmith btlp = &sc->mly_btl[bus][target]; 94679695Smsmith if (btl.mb_flags != btlp->mb_flags) { 94779695Smsmith debug(1, "flags changed, rescanning"); 94879695Smsmith rescan = 1; 94979695Smsmith } 95079695Smsmith 95179695Smsmith /* XXX other reasons? */ 95279695Smsmith 95379695Smsmith /* 95479695Smsmith * Update BTL information. 95579695Smsmith */ 95679695Smsmith *btlp = btl; 95779695Smsmith 95879695Smsmith /* 95979695Smsmith * Perform CAM rescan if required. 96079695Smsmith */ 96179695Smsmith if (rescan) 96279695Smsmith mly_cam_rescan_btl(sc, bus, target); 96364987Smsmith} 96464987Smsmith 96564987Smsmith/******************************************************************************** 96664987Smsmith * Get the current health status and set the 'next event' counter to suit. 96764987Smsmith */ 96864987Smsmithstatic int 96964987Smsmithmly_get_eventstatus(struct mly_softc *sc) 97064987Smsmith{ 97164987Smsmith struct mly_command_ioctl mci; 97264987Smsmith struct mly_health_status *mh; 97364987Smsmith u_int8_t status; 97464987Smsmith int error; 97564987Smsmith 97664987Smsmith /* build the gethealthstatus ioctl and send it */ 97764987Smsmith bzero(&mci, sizeof(mci)); 97864987Smsmith mh = NULL; 97964987Smsmith mci.sub_ioctl = MDACIOCTL_GETHEALTHSTATUS; 98064987Smsmith 98164987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&mh, sizeof(*mh), &status, NULL, NULL))) 98264987Smsmith return(error); 98364987Smsmith if (status != 0) 98464987Smsmith return(EIO); 98564987Smsmith 98664987Smsmith /* get the event counter */ 98764987Smsmith sc->mly_event_change = mh->change_counter; 98864987Smsmith sc->mly_event_waiting = mh->next_event; 98964987Smsmith sc->mly_event_counter = mh->next_event; 99064987Smsmith 99164987Smsmith /* save the health status into the memory mailbox */ 99264987Smsmith bcopy(mh, &sc->mly_mmbox->mmm_health.status, sizeof(*mh)); 99364987Smsmith 99464987Smsmith debug(1, "initial change counter %d, event counter %d", mh->change_counter, mh->next_event); 99564987Smsmith 99664987Smsmith free(mh, M_DEVBUF); 99764987Smsmith return(0); 99864987Smsmith} 99964987Smsmith 100064987Smsmith/******************************************************************************** 100164987Smsmith * Enable the memory mailbox mode. 100264987Smsmith */ 100364987Smsmithstatic int 100464987Smsmithmly_enable_mmbox(struct mly_softc *sc) 100564987Smsmith{ 100664987Smsmith struct mly_command_ioctl mci; 100764987Smsmith u_int8_t *sp, status; 100864987Smsmith int error; 100964987Smsmith 101064987Smsmith debug_called(1); 101164987Smsmith 101264987Smsmith /* build the ioctl and send it */ 101364987Smsmith bzero(&mci, sizeof(mci)); 101464987Smsmith mci.sub_ioctl = MDACIOCTL_SETMEMORYMAILBOX; 101564987Smsmith /* set buffer addresses */ 101673050Smsmith mci.param.setmemorymailbox.command_mailbox_physaddr = 101773050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_command); 101873050Smsmith mci.param.setmemorymailbox.status_mailbox_physaddr = 101973050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_status); 102073050Smsmith mci.param.setmemorymailbox.health_buffer_physaddr = 102173050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_health); 102264987Smsmith 102364987Smsmith /* set buffer sizes - abuse of data_size field is revolting */ 102464987Smsmith sp = (u_int8_t *)&mci.data_size; 102564987Smsmith sp[0] = ((sizeof(union mly_command_packet) * MLY_MMBOX_COMMANDS) / 1024); 102664987Smsmith sp[1] = (sizeof(union mly_status_packet) * MLY_MMBOX_STATUS) / 1024; 102764987Smsmith mci.param.setmemorymailbox.health_buffer_size = sizeof(union mly_health_region) / 1024; 102864987Smsmith 102964987Smsmith debug(1, "memory mailbox at %p (0x%llx/%d 0x%llx/%d 0x%llx/%d", sc->mly_mmbox, 103064987Smsmith mci.param.setmemorymailbox.command_mailbox_physaddr, sp[0], 103164987Smsmith mci.param.setmemorymailbox.status_mailbox_physaddr, sp[1], 103273050Smsmith mci.param.setmemorymailbox.health_buffer_physaddr, 103373050Smsmith mci.param.setmemorymailbox.health_buffer_size); 103464987Smsmith 103564987Smsmith if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) 103664987Smsmith return(error); 103764987Smsmith if (status != 0) 103864987Smsmith return(EIO); 103964987Smsmith sc->mly_state |= MLY_STATE_MMBOX_ACTIVE; 104064987Smsmith debug(1, "memory mailbox active"); 104164987Smsmith return(0); 104264987Smsmith} 104364987Smsmith 104464987Smsmith/******************************************************************************** 104564987Smsmith * Flush all pending I/O from the controller. 104664987Smsmith */ 104764987Smsmithstatic int 104864987Smsmithmly_flush(struct mly_softc *sc) 104964987Smsmith{ 105064987Smsmith struct mly_command_ioctl mci; 105164987Smsmith u_int8_t status; 105264987Smsmith int error; 105364987Smsmith 105464987Smsmith debug_called(1); 105564987Smsmith 105664987Smsmith /* build the ioctl */ 105764987Smsmith bzero(&mci, sizeof(mci)); 105864987Smsmith mci.sub_ioctl = MDACIOCTL_FLUSHDEVICEDATA; 105964987Smsmith mci.param.deviceoperation.operation_device = MLY_OPDEVICE_PHYSICAL_CONTROLLER; 106064987Smsmith 106164987Smsmith /* pass it off to the controller */ 106264987Smsmith if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) 106364987Smsmith return(error); 106464987Smsmith 106564987Smsmith return((status == 0) ? 0 : EIO); 106664987Smsmith} 106764987Smsmith 106864987Smsmith/******************************************************************************** 106964987Smsmith * Perform an ioctl command. 107064987Smsmith * 107164987Smsmith * If (data) is not NULL, the command requires data transfer. If (*data) is NULL 107264987Smsmith * the command requires data transfer from the controller, and we will allocate 107364987Smsmith * a buffer for it. If (*data) is not NULL, the command requires data transfer 107464987Smsmith * to the controller. 107564987Smsmith * 107664987Smsmith * XXX passing in the whole ioctl structure is ugly. Better ideas? 107764987Smsmith * 107864987Smsmith * XXX we don't even try to handle the case where datasize > 4k. We should. 107964987Smsmith */ 108064987Smsmithstatic int 108164987Smsmithmly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, size_t datasize, 108264987Smsmith u_int8_t *status, void *sense_buffer, size_t *sense_length) 108364987Smsmith{ 108464987Smsmith struct mly_command *mc; 108564987Smsmith struct mly_command_ioctl *mci; 108664987Smsmith int error; 108764987Smsmith 108864987Smsmith debug_called(1); 108964987Smsmith 109064987Smsmith mc = NULL; 109164987Smsmith if (mly_alloc_command(sc, &mc)) { 109264987Smsmith error = ENOMEM; 109364987Smsmith goto out; 109464987Smsmith } 109564987Smsmith 109664987Smsmith /* copy the ioctl structure, but save some important fields and then fixup */ 109764987Smsmith mci = &mc->mc_packet->ioctl; 109864987Smsmith ioctl->sense_buffer_address = mci->sense_buffer_address; 109964987Smsmith ioctl->maximum_sense_size = mci->maximum_sense_size; 110064987Smsmith *mci = *ioctl; 110164987Smsmith mci->opcode = MDACMD_IOCTL; 110264987Smsmith mci->timeout.value = 30; 110364987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 110464987Smsmith 110564987Smsmith /* handle the data buffer */ 110664987Smsmith if (data != NULL) { 110764987Smsmith if (*data == NULL) { 110864987Smsmith /* allocate data buffer */ 110964987Smsmith if ((mc->mc_data = malloc(datasize, M_DEVBUF, M_NOWAIT)) == NULL) { 111064987Smsmith error = ENOMEM; 111164987Smsmith goto out; 111264987Smsmith } 111364987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 111464987Smsmith } else { 111564987Smsmith mc->mc_data = *data; 111664987Smsmith mc->mc_flags |= MLY_CMD_DATAOUT; 111764987Smsmith } 111864987Smsmith mc->mc_length = datasize; 111964987Smsmith mc->mc_packet->generic.data_size = datasize; 112064987Smsmith } 112164987Smsmith 112264987Smsmith /* run the command */ 112364987Smsmith if ((error = mly_immediate_command(mc))) 112464987Smsmith goto out; 112564987Smsmith 112664987Smsmith /* clean up and return any data */ 112764987Smsmith *status = mc->mc_status; 112864987Smsmith if ((mc->mc_sense > 0) && (sense_buffer != NULL)) { 112964987Smsmith bcopy(mc->mc_packet, sense_buffer, mc->mc_sense); 113064987Smsmith *sense_length = mc->mc_sense; 113164987Smsmith goto out; 113264987Smsmith } 113364987Smsmith 113464987Smsmith /* should we return a data pointer? */ 113564987Smsmith if ((data != NULL) && (*data == NULL)) 113664987Smsmith *data = mc->mc_data; 113764987Smsmith 113864987Smsmith /* command completed OK */ 113964987Smsmith error = 0; 114064987Smsmith 114164987Smsmithout: 114264987Smsmith if (mc != NULL) { 114364987Smsmith /* do we need to free a data buffer we allocated? */ 114464987Smsmith if (error && (mc->mc_data != NULL) && (*data == NULL)) 114564987Smsmith free(mc->mc_data, M_DEVBUF); 114664987Smsmith mly_release_command(mc); 114764987Smsmith } 114864987Smsmith return(error); 114964987Smsmith} 115064987Smsmith 115164987Smsmith/******************************************************************************** 115279695Smsmith * Check for event(s) outstanding in the controller. 115379695Smsmith */ 115479695Smsmithstatic void 115579695Smsmithmly_check_event(struct mly_softc *sc) 115679695Smsmith{ 115779695Smsmith 115879695Smsmith /* 115979695Smsmith * The controller may have updated the health status information, 116079695Smsmith * so check for it here. Note that the counters are all in host memory, 116179695Smsmith * so this check is very cheap. Also note that we depend on checking on 116279695Smsmith * completion 116379695Smsmith */ 116479695Smsmith if (sc->mly_mmbox->mmm_health.status.change_counter != sc->mly_event_change) { 116579695Smsmith sc->mly_event_change = sc->mly_mmbox->mmm_health.status.change_counter; 116679695Smsmith debug(1, "event change %d, event status update, %d -> %d", sc->mly_event_change, 116779695Smsmith sc->mly_event_waiting, sc->mly_mmbox->mmm_health.status.next_event); 116879695Smsmith sc->mly_event_waiting = sc->mly_mmbox->mmm_health.status.next_event; 116979695Smsmith 117079695Smsmith /* wake up anyone that might be interested in this */ 117179695Smsmith wakeup(&sc->mly_event_change); 117279695Smsmith } 117379695Smsmith if (sc->mly_event_counter != sc->mly_event_waiting) 117479695Smsmith mly_fetch_event(sc); 117579695Smsmith} 117679695Smsmith 117779695Smsmith/******************************************************************************** 117864987Smsmith * Fetch one event from the controller. 117979695Smsmith * 118079695Smsmith * If we fail due to resource starvation, we'll be retried the next time a 118179695Smsmith * command completes. 118264987Smsmith */ 118364987Smsmithstatic void 118464987Smsmithmly_fetch_event(struct mly_softc *sc) 118564987Smsmith{ 118664987Smsmith struct mly_command *mc; 118764987Smsmith struct mly_command_ioctl *mci; 118864987Smsmith int s; 118964987Smsmith u_int32_t event; 119064987Smsmith 119179695Smsmith debug_called(1); 119264987Smsmith 119364987Smsmith /* get a command */ 119464987Smsmith if (mly_alloc_command(sc, &mc)) 119579695Smsmith return; 119664987Smsmith 119764987Smsmith /* set up the data buffer */ 119868877Sdwmalone if ((mc->mc_data = malloc(sizeof(struct mly_event), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 119964987Smsmith mly_release_command(mc); 120079695Smsmith return; 120164987Smsmith } 120264987Smsmith mc->mc_length = sizeof(struct mly_event); 120364987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 120464987Smsmith mc->mc_complete = mly_complete_event; 120564987Smsmith 120664987Smsmith /* 120764987Smsmith * Get an event number to fetch. It's possible that we've raced with another 120864987Smsmith * context for the last event, in which case there will be no more events. 120964987Smsmith */ 121064987Smsmith s = splcam(); 121164987Smsmith if (sc->mly_event_counter == sc->mly_event_waiting) { 121264987Smsmith mly_release_command(mc); 121364987Smsmith splx(s); 121464987Smsmith return; 121564987Smsmith } 121664987Smsmith event = sc->mly_event_counter++; 121764987Smsmith splx(s); 121864987Smsmith 121964987Smsmith /* 122064987Smsmith * Build the ioctl. 122164987Smsmith * 122264987Smsmith * At this point we are committed to sending this request, as it 122364987Smsmith * will be the only one constructed for this particular event number. 122464987Smsmith */ 122564987Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 122664987Smsmith mci->opcode = MDACMD_IOCTL; 122764987Smsmith mci->data_size = sizeof(struct mly_event); 122864987Smsmith mci->addr.phys.lun = (event >> 16) & 0xff; 122964987Smsmith mci->addr.phys.target = (event >> 24) & 0xff; 123064987Smsmith mci->addr.phys.channel = 0; 123164987Smsmith mci->addr.phys.controller = 0; 123264987Smsmith mci->timeout.value = 30; 123364987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 123464987Smsmith mci->sub_ioctl = MDACIOCTL_GETEVENT; 123564987Smsmith mci->param.getevent.sequence_number_low = event & 0xffff; 123664987Smsmith 123779695Smsmith debug(1, "fetch event %u", event); 123864987Smsmith 123964987Smsmith /* 124079695Smsmith * Submit the command. 124179695Smsmith * 124279695Smsmith * Note that failure of mly_start() will result in this event never being 124379695Smsmith * fetched. 124464987Smsmith */ 124579695Smsmith if (mly_start(mc) != 0) { 124679695Smsmith mly_printf(sc, "couldn't fetch event %u\n", event); 124779695Smsmith mly_release_command(mc); 124879695Smsmith } 124964987Smsmith} 125064987Smsmith 125164987Smsmith/******************************************************************************** 125264987Smsmith * Handle the completion of an event poll. 125364987Smsmith */ 125464987Smsmithstatic void 125564987Smsmithmly_complete_event(struct mly_command *mc) 125664987Smsmith{ 125764987Smsmith struct mly_softc *sc = mc->mc_sc; 125864987Smsmith struct mly_event *me = (struct mly_event *)mc->mc_data; 125964987Smsmith 126079695Smsmith debug_called(1); 126164987Smsmith 126264987Smsmith /* 126364987Smsmith * If the event was successfully fetched, process it. 126464987Smsmith */ 126564987Smsmith if (mc->mc_status == SCSI_STATUS_OK) { 126664987Smsmith mly_process_event(sc, me); 126764987Smsmith free(me, M_DEVBUF); 126864987Smsmith } 126964987Smsmith mly_release_command(mc); 127079695Smsmith 127179695Smsmith /* 127279695Smsmith * Check for another event. 127379695Smsmith */ 127479695Smsmith mly_check_event(sc); 127564987Smsmith} 127664987Smsmith 127764987Smsmith/******************************************************************************** 127864987Smsmith * Process a controller event. 127964987Smsmith */ 128064987Smsmithstatic void 128164987Smsmithmly_process_event(struct mly_softc *sc, struct mly_event *me) 128264987Smsmith{ 1283225950Sken struct scsi_sense_data_fixed *ssd; 1284225950Sken char *fp, *tp; 1285225950Sken int bus, target, event, class, action; 128664987Smsmith 1287225950Sken ssd = (struct scsi_sense_data_fixed *)&me->sense[0]; 1288225950Sken 128964987Smsmith /* 129064987Smsmith * Errors can be reported using vendor-unique sense data. In this case, the 129164987Smsmith * event code will be 0x1c (Request sense data present), the sense key will 129264987Smsmith * be 0x09 (vendor specific), the MSB of the ASC will be set, and the 129364987Smsmith * actual event code will be a 16-bit value comprised of the ASCQ (low byte) 129464987Smsmith * and low seven bits of the ASC (low seven bits of the high byte). 129564987Smsmith */ 129664987Smsmith if ((me->code == 0x1c) && 129764987Smsmith ((ssd->flags & SSD_KEY) == SSD_KEY_Vendor_Specific) && 129864987Smsmith (ssd->add_sense_code & 0x80)) { 129964987Smsmith event = ((int)(ssd->add_sense_code & ~0x80) << 8) + ssd->add_sense_code_qual; 130064987Smsmith } else { 130164987Smsmith event = me->code; 130264987Smsmith } 130364987Smsmith 130464987Smsmith /* look up event, get codes */ 130564987Smsmith fp = mly_describe_code(mly_table_event, event); 130664987Smsmith 130779695Smsmith debug(1, "Event %d code 0x%x", me->sequence_number, me->code); 130864987Smsmith 130964987Smsmith /* quiet event? */ 131064987Smsmith class = fp[0]; 131164987Smsmith if (isupper(class) && bootverbose) 131264987Smsmith class = tolower(class); 131364987Smsmith 131464987Smsmith /* get action code, text string */ 131564987Smsmith action = fp[1]; 131664987Smsmith tp = &fp[2]; 131764987Smsmith 131864987Smsmith /* 131964987Smsmith * Print some information about the event. 132064987Smsmith * 132164987Smsmith * This code uses a table derived from the corresponding portion of the Linux 132264987Smsmith * driver, and thus the parser is very similar. 132364987Smsmith */ 132464987Smsmith switch(class) { 132564987Smsmith case 'p': /* error on physical device */ 132664987Smsmith mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); 132764987Smsmith if (action == 'r') 132864987Smsmith sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; 132964987Smsmith break; 133064987Smsmith case 'l': /* error on logical unit */ 133164987Smsmith case 'm': /* message about logical unit */ 133264987Smsmith bus = MLY_LOGDEV_BUS(sc, me->lun); 133379695Smsmith target = MLY_LOGDEV_TARGET(sc, me->lun); 133464987Smsmith mly_name_device(sc, bus, target); 133564987Smsmith mly_printf(sc, "logical device %d (%s) %s\n", me->lun, sc->mly_btl[bus][target].mb_name, tp); 133664987Smsmith if (action == 'r') 133764987Smsmith sc->mly_btl[bus][target].mb_flags |= MLY_BTL_RESCAN; 133864987Smsmith break; 133964987Smsmith case 's': /* report of sense data */ 134064987Smsmith if (((ssd->flags & SSD_KEY) == SSD_KEY_NO_SENSE) || 134164987Smsmith (((ssd->flags & SSD_KEY) == SSD_KEY_NOT_READY) && 134264987Smsmith (ssd->add_sense_code == 0x04) && 134364987Smsmith ((ssd->add_sense_code_qual == 0x01) || (ssd->add_sense_code_qual == 0x02)))) 134464987Smsmith break; /* ignore NO_SENSE or NOT_READY in one case */ 134564987Smsmith 134664987Smsmith mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); 134764987Smsmith mly_printf(sc, " sense key %d asc %02x ascq %02x\n", 134864987Smsmith ssd->flags & SSD_KEY, ssd->add_sense_code, ssd->add_sense_code_qual); 134964987Smsmith mly_printf(sc, " info %4D csi %4D\n", ssd->info, "", ssd->cmd_spec_info, ""); 135064987Smsmith if (action == 'r') 135164987Smsmith sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; 135264987Smsmith break; 135364987Smsmith case 'e': 135464987Smsmith mly_printf(sc, tp, me->target, me->lun); 1355110680Salfred printf("\n"); 135664987Smsmith break; 135764987Smsmith case 'c': 135864987Smsmith mly_printf(sc, "controller %s\n", tp); 135964987Smsmith break; 136064987Smsmith case '?': 136164987Smsmith mly_printf(sc, "%s - %d\n", tp, me->code); 136264987Smsmith break; 136364987Smsmith default: /* probably a 'noisy' event being ignored */ 136464987Smsmith break; 136564987Smsmith } 136664987Smsmith} 136764987Smsmith 136864987Smsmith/******************************************************************************** 136964987Smsmith * Perform periodic activities. 137064987Smsmith */ 137164987Smsmithstatic void 137264987Smsmithmly_periodic(void *data) 137364987Smsmith{ 137464987Smsmith struct mly_softc *sc = (struct mly_softc *)data; 137579695Smsmith int bus, target; 137664987Smsmith 137764987Smsmith debug_called(2); 137864987Smsmith 137964987Smsmith /* 138064987Smsmith * Scan devices. 138164987Smsmith */ 138279695Smsmith for (bus = 0; bus < sc->mly_cam_channels; bus++) { 138379695Smsmith if (MLY_BUS_IS_VALID(sc, bus)) { 138479695Smsmith for (target = 0; target < MLY_MAX_TARGETS; target++) { 138564987Smsmith 138679695Smsmith /* ignore the controller in this scan */ 138779695Smsmith if (target == sc->mly_controllerparam->initiator_id) 138879695Smsmith continue; 138964987Smsmith 139079695Smsmith /* perform device rescan? */ 139179695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_RESCAN) 139279695Smsmith mly_rescan_btl(sc, bus, target); 139379695Smsmith } 139464987Smsmith } 139564987Smsmith } 139679695Smsmith 139779695Smsmith /* check for controller events */ 139879695Smsmith mly_check_event(sc); 139964987Smsmith 140079695Smsmith /* reschedule ourselves */ 140179695Smsmith sc->mly_periodic = timeout(mly_periodic, sc, MLY_PERIODIC_INTERVAL * hz); 140264987Smsmith} 140364987Smsmith 140464987Smsmith/******************************************************************************** 140564987Smsmith ******************************************************************************** 140664987Smsmith Command Processing 140764987Smsmith ******************************************************************************** 140864987Smsmith ********************************************************************************/ 140964987Smsmith 141064987Smsmith/******************************************************************************** 141164987Smsmith * Run a command and wait for it to complete. 141264987Smsmith * 141364987Smsmith */ 141464987Smsmithstatic int 141564987Smsmithmly_immediate_command(struct mly_command *mc) 141664987Smsmith{ 141764987Smsmith struct mly_softc *sc = mc->mc_sc; 141864987Smsmith int error, s; 141964987Smsmith 142079695Smsmith debug_called(1); 142164987Smsmith 142264987Smsmith /* spinning at splcam is ugly, but we're only used during controller init */ 142364987Smsmith s = splcam(); 142479695Smsmith if ((error = mly_start(mc))) { 142579695Smsmith splx(s); 142664987Smsmith return(error); 142779695Smsmith } 142864987Smsmith 142964987Smsmith if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) { 143064987Smsmith /* sleep on the command */ 143173050Smsmith while(!(mc->mc_flags & MLY_CMD_COMPLETE)) { 143264987Smsmith tsleep(mc, PRIBIO, "mlywait", 0); 143364987Smsmith } 143464987Smsmith } else { 143564987Smsmith /* spin and collect status while we do */ 143673050Smsmith while(!(mc->mc_flags & MLY_CMD_COMPLETE)) { 143764987Smsmith mly_done(mc->mc_sc); 143873050Smsmith } 143964987Smsmith } 144064987Smsmith splx(s); 144164987Smsmith return(0); 144264987Smsmith} 144364987Smsmith 144464987Smsmith/******************************************************************************** 144579695Smsmith * Deliver a command to the controller. 144679695Smsmith * 144779695Smsmith * XXX it would be good to just queue commands that we can't submit immediately 144879695Smsmith * and send them later, but we probably want a wrapper for that so that 144979695Smsmith * we don't hang on a failed submission for an immediate command. 145064987Smsmith */ 145164987Smsmithstatic int 145264987Smsmithmly_start(struct mly_command *mc) 145364987Smsmith{ 145464987Smsmith struct mly_softc *sc = mc->mc_sc; 145564987Smsmith union mly_command_packet *pkt; 145664987Smsmith int s; 145764987Smsmith 145864987Smsmith debug_called(2); 145964987Smsmith 146064987Smsmith /* 146173050Smsmith * Set the command up for delivery to the controller. 146264987Smsmith */ 146364987Smsmith mly_map_command(mc); 146473050Smsmith mc->mc_packet->generic.command_id = mc->mc_slot; 146564987Smsmith 1466110479Sscottl#ifdef MLY_DEBUG 1467110479Sscottl mc->mc_timestamp = time_second; 1468110479Sscottl#endif 1469110479Sscottl 147064987Smsmith s = splcam(); 147173050Smsmith 147264987Smsmith /* 147364987Smsmith * Do we have to use the hardware mailbox? 147464987Smsmith */ 147564987Smsmith if (!(sc->mly_state & MLY_STATE_MMBOX_ACTIVE)) { 147664987Smsmith /* 147764987Smsmith * Check to see if the controller is ready for us. 147864987Smsmith */ 147964987Smsmith if (MLY_IDBR_TRUE(sc, MLY_HM_CMDSENT)) { 148064987Smsmith splx(s); 148164987Smsmith return(EBUSY); 148264987Smsmith } 148373050Smsmith mc->mc_flags |= MLY_CMD_BUSY; 148473050Smsmith 148564987Smsmith /* 148664987Smsmith * It's ready, send the command. 148764987Smsmith */ 148864987Smsmith MLY_SET_MBOX(sc, sc->mly_command_mailbox, &mc->mc_packetphys); 148964987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_CMDSENT); 149064987Smsmith 149164987Smsmith } else { /* use memory-mailbox mode */ 149264987Smsmith 149364987Smsmith pkt = &sc->mly_mmbox->mmm_command[sc->mly_mmbox_command_index]; 149464987Smsmith 149573050Smsmith /* check to see if the next index is free yet */ 149664987Smsmith if (pkt->mmbox.flag != 0) { 149764987Smsmith splx(s); 149864987Smsmith return(EBUSY); 149964987Smsmith } 150073050Smsmith mc->mc_flags |= MLY_CMD_BUSY; 150164987Smsmith 150264987Smsmith /* copy in new command */ 150364987Smsmith bcopy(mc->mc_packet->mmbox.data, pkt->mmbox.data, sizeof(pkt->mmbox.data)); 150464987Smsmith /* barrier to ensure completion of previous write before we write the flag */ 1505106912Smux bus_space_barrier(sc->mly_btag, sc->mly_bhandle, 0, 0, 1506106912Smux BUS_SPACE_BARRIER_WRITE); 150764987Smsmith /* copy flag last */ 150864987Smsmith pkt->mmbox.flag = mc->mc_packet->mmbox.flag; 150964987Smsmith /* barrier to ensure completion of previous write before we notify the controller */ 1510106912Smux bus_space_barrier(sc->mly_btag, sc->mly_bhandle, 0, 0, 1511106912Smux BUS_SPACE_BARRIER_WRITE); 151264987Smsmith 151364987Smsmith /* signal controller, update index */ 151464987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_AM_CMDSENT); 151564987Smsmith sc->mly_mmbox_command_index = (sc->mly_mmbox_command_index + 1) % MLY_MMBOX_COMMANDS; 151664987Smsmith } 151764987Smsmith 151873050Smsmith mly_enqueue_busy(mc); 151964987Smsmith splx(s); 152064987Smsmith return(0); 152164987Smsmith} 152264987Smsmith 152364987Smsmith/******************************************************************************** 152464987Smsmith * Pick up command status from the controller, schedule a completion event 152564987Smsmith */ 1526105215Sphkstatic void 152764987Smsmithmly_done(struct mly_softc *sc) 152864987Smsmith{ 152964987Smsmith struct mly_command *mc; 153064987Smsmith union mly_status_packet *sp; 153164987Smsmith u_int16_t slot; 153264987Smsmith int s, worked; 153364987Smsmith 153464987Smsmith s = splcam(); 153564987Smsmith worked = 0; 153664987Smsmith 153764987Smsmith /* pick up hardware-mailbox commands */ 153864987Smsmith if (MLY_ODBR_TRUE(sc, MLY_HM_STSREADY)) { 153964987Smsmith slot = MLY_GET_REG2(sc, sc->mly_status_mailbox); 154064987Smsmith if (slot < MLY_SLOT_MAX) { 154173050Smsmith mc = &sc->mly_command[slot - MLY_SLOT_START]; 154273050Smsmith mc->mc_status = MLY_GET_REG(sc, sc->mly_status_mailbox + 2); 154373050Smsmith mc->mc_sense = MLY_GET_REG(sc, sc->mly_status_mailbox + 3); 154473050Smsmith mc->mc_resid = MLY_GET_REG4(sc, sc->mly_status_mailbox + 4); 154573050Smsmith mly_remove_busy(mc); 154673050Smsmith mc->mc_flags &= ~MLY_CMD_BUSY; 154773050Smsmith mly_enqueue_complete(mc); 154873050Smsmith worked = 1; 154964987Smsmith } else { 155064987Smsmith /* slot 0xffff may mean "extremely bogus command" */ 155164987Smsmith mly_printf(sc, "got HM completion for illegal slot %u\n", slot); 155264987Smsmith } 155364987Smsmith /* unconditionally acknowledge status */ 155464987Smsmith MLY_SET_REG(sc, sc->mly_odbr, MLY_HM_STSREADY); 155564987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); 155664987Smsmith } 155764987Smsmith 155864987Smsmith /* pick up memory-mailbox commands */ 155964987Smsmith if (MLY_ODBR_TRUE(sc, MLY_AM_STSREADY)) { 156064987Smsmith for (;;) { 156164987Smsmith sp = &sc->mly_mmbox->mmm_status[sc->mly_mmbox_status_index]; 156264987Smsmith 156364987Smsmith /* check for more status */ 156464987Smsmith if (sp->mmbox.flag == 0) 156564987Smsmith break; 156664987Smsmith 156764987Smsmith /* get slot number */ 156864987Smsmith slot = sp->status.command_id; 156964987Smsmith if (slot < MLY_SLOT_MAX) { 157073050Smsmith mc = &sc->mly_command[slot - MLY_SLOT_START]; 157173050Smsmith mc->mc_status = sp->status.status; 157273050Smsmith mc->mc_sense = sp->status.sense_length; 157373050Smsmith mc->mc_resid = sp->status.residue; 157473050Smsmith mly_remove_busy(mc); 157573050Smsmith mc->mc_flags &= ~MLY_CMD_BUSY; 157673050Smsmith mly_enqueue_complete(mc); 157773050Smsmith worked = 1; 157864987Smsmith } else { 157964987Smsmith /* slot 0xffff may mean "extremely bogus command" */ 158073050Smsmith mly_printf(sc, "got AM completion for illegal slot %u at %d\n", 158173050Smsmith slot, sc->mly_mmbox_status_index); 158264987Smsmith } 158364987Smsmith 158473050Smsmith /* clear and move to next index */ 158564987Smsmith sp->mmbox.flag = 0; 158664987Smsmith sc->mly_mmbox_status_index = (sc->mly_mmbox_status_index + 1) % MLY_MMBOX_STATUS; 158764987Smsmith } 158864987Smsmith /* acknowledge that we have collected status value(s) */ 158964987Smsmith MLY_SET_REG(sc, sc->mly_odbr, MLY_AM_STSREADY); 159064987Smsmith } 159164987Smsmith 159264987Smsmith splx(s); 159364987Smsmith if (worked) { 159464987Smsmith if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) 1595111528Sscottl taskqueue_enqueue(taskqueue_swi_giant, &sc->mly_task_complete); 159664987Smsmith else 159764987Smsmith mly_complete(sc, 0); 159864987Smsmith } 159964987Smsmith} 160064987Smsmith 160164987Smsmith/******************************************************************************** 160264987Smsmith * Process completed commands 160364987Smsmith */ 160464987Smsmithstatic void 160564987Smsmithmly_complete(void *context, int pending) 160664987Smsmith{ 160764987Smsmith struct mly_softc *sc = (struct mly_softc *)context; 160864987Smsmith struct mly_command *mc; 160964987Smsmith void (* mc_complete)(struct mly_command *mc); 161064987Smsmith 161164987Smsmith 161264987Smsmith debug_called(2); 161364987Smsmith 161464987Smsmith /* 161564987Smsmith * Spin pulling commands off the completed queue and processing them. 161664987Smsmith */ 161773050Smsmith while ((mc = mly_dequeue_complete(sc)) != NULL) { 161864987Smsmith 161964987Smsmith /* 162064987Smsmith * Free controller resources, mark command complete. 162164987Smsmith * 162264987Smsmith * Note that as soon as we mark the command complete, it may be freed 162364987Smsmith * out from under us, so we need to save the mc_complete field in 162464987Smsmith * order to later avoid dereferencing mc. (We would not expect to 162564987Smsmith * have a polling/sleeping consumer with mc_complete != NULL). 162664987Smsmith */ 162764987Smsmith mly_unmap_command(mc); 162864987Smsmith mc_complete = mc->mc_complete; 162973050Smsmith mc->mc_flags |= MLY_CMD_COMPLETE; 163064987Smsmith 163164987Smsmith /* 163264987Smsmith * Call completion handler or wake up sleeping consumer. 163364987Smsmith */ 163464987Smsmith if (mc_complete != NULL) { 163564987Smsmith mc_complete(mc); 163664987Smsmith } else { 163764987Smsmith wakeup(mc); 163864987Smsmith } 163964987Smsmith } 164079695Smsmith 164164987Smsmith /* 164279695Smsmith * XXX if we are deferring commands due to controller-busy status, we should 164379695Smsmith * retry submitting them here. 164464987Smsmith */ 164564987Smsmith} 164664987Smsmith 164764987Smsmith/******************************************************************************** 164864987Smsmith ******************************************************************************** 164964987Smsmith Command Buffer Management 165064987Smsmith ******************************************************************************** 165164987Smsmith ********************************************************************************/ 165264987Smsmith 165364987Smsmith/******************************************************************************** 165464987Smsmith * Allocate a command. 165564987Smsmith */ 1656105215Sphkstatic int 165764987Smsmithmly_alloc_command(struct mly_softc *sc, struct mly_command **mcp) 165864987Smsmith{ 165964987Smsmith struct mly_command *mc; 166064987Smsmith 166164987Smsmith debug_called(3); 166264987Smsmith 166373050Smsmith if ((mc = mly_dequeue_free(sc)) == NULL) 166464987Smsmith return(ENOMEM); 166564987Smsmith 166664987Smsmith *mcp = mc; 166764987Smsmith return(0); 166864987Smsmith} 166964987Smsmith 167064987Smsmith/******************************************************************************** 167164987Smsmith * Release a command back to the freelist. 167264987Smsmith */ 1673105215Sphkstatic void 167464987Smsmithmly_release_command(struct mly_command *mc) 167564987Smsmith{ 167664987Smsmith debug_called(3); 167764987Smsmith 167864987Smsmith /* 167964987Smsmith * Fill in parts of the command that may cause confusion if 168064987Smsmith * a consumer doesn't when we are later allocated. 168164987Smsmith */ 168264987Smsmith mc->mc_data = NULL; 168364987Smsmith mc->mc_flags = 0; 168464987Smsmith mc->mc_complete = NULL; 168564987Smsmith mc->mc_private = NULL; 168664987Smsmith 168764987Smsmith /* 168864987Smsmith * By default, we set up to overwrite the command packet with 168964987Smsmith * sense information. 169064987Smsmith */ 169164987Smsmith mc->mc_packet->generic.sense_buffer_address = mc->mc_packetphys; 169264987Smsmith mc->mc_packet->generic.maximum_sense_size = sizeof(union mly_command_packet); 169364987Smsmith 169464987Smsmith mly_enqueue_free(mc); 169564987Smsmith} 169664987Smsmith 169764987Smsmith/******************************************************************************** 169873050Smsmith * Map helper for command allocation. 169964987Smsmith */ 170064987Smsmithstatic void 170173050Smsmithmly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 170264987Smsmith{ 170379695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 170464987Smsmith 170579695Smsmith debug_called(1); 170664987Smsmith 170773050Smsmith sc->mly_packetphys = segs[0].ds_addr; 170864987Smsmith} 170964987Smsmith 171064987Smsmith/******************************************************************************** 171173050Smsmith * Allocate and initialise command and packet structures. 171279695Smsmith * 171379695Smsmith * If the controller supports fewer than MLY_MAX_COMMANDS commands, limit our 171479695Smsmith * allocation to that number. If we don't yet know how many commands the 171579695Smsmith * controller supports, allocate a very small set (suitable for initialisation 171679695Smsmith * purposes only). 171764987Smsmith */ 171873050Smsmithstatic int 171973050Smsmithmly_alloc_commands(struct mly_softc *sc) 172064987Smsmith{ 172164987Smsmith struct mly_command *mc; 172279695Smsmith int i, ncmd; 172364987Smsmith 172479695Smsmith if (sc->mly_controllerinfo == NULL) { 172579695Smsmith ncmd = 4; 172679695Smsmith } else { 172779695Smsmith ncmd = min(MLY_MAX_COMMANDS, sc->mly_controllerinfo->maximum_parallel_commands); 172879695Smsmith } 172979695Smsmith 173073050Smsmith /* 173173050Smsmith * Allocate enough space for all the command packets in one chunk and 173273050Smsmith * map them permanently into controller-visible space. 173373050Smsmith */ 173473050Smsmith if (bus_dmamem_alloc(sc->mly_packet_dmat, (void **)&sc->mly_packet, 173573050Smsmith BUS_DMA_NOWAIT, &sc->mly_packetmap)) { 173673050Smsmith return(ENOMEM); 173773050Smsmith } 1738118762Sscottl if (bus_dmamap_load(sc->mly_packet_dmat, sc->mly_packetmap, sc->mly_packet, 1739118762Sscottl ncmd * sizeof(union mly_command_packet), 1740118762Sscottl mly_alloc_commands_map, sc, BUS_DMA_NOWAIT) != 0) 1741118762Sscottl return (ENOMEM); 174264987Smsmith 174379695Smsmith for (i = 0; i < ncmd; i++) { 174473050Smsmith mc = &sc->mly_command[i]; 174573050Smsmith bzero(mc, sizeof(*mc)); 174673050Smsmith mc->mc_sc = sc; 174773050Smsmith mc->mc_slot = MLY_SLOT_START + i; 174873050Smsmith mc->mc_packet = sc->mly_packet + i; 174973050Smsmith mc->mc_packetphys = sc->mly_packetphys + (i * sizeof(union mly_command_packet)); 175073050Smsmith if (!bus_dmamap_create(sc->mly_buffer_dmat, 0, &mc->mc_datamap)) 175173050Smsmith mly_release_command(mc); 175264987Smsmith } 175373050Smsmith return(0); 175464987Smsmith} 175564987Smsmith 175664987Smsmith/******************************************************************************** 175779695Smsmith * Free all the storage held by commands. 175879695Smsmith * 175979695Smsmith * Must be called with all commands on the free list. 176079695Smsmith */ 176179695Smsmithstatic void 176279695Smsmithmly_release_commands(struct mly_softc *sc) 176379695Smsmith{ 176479695Smsmith struct mly_command *mc; 176579695Smsmith 176679695Smsmith /* throw away command buffer DMA maps */ 176779695Smsmith while (mly_alloc_command(sc, &mc) == 0) 176879695Smsmith bus_dmamap_destroy(sc->mly_buffer_dmat, mc->mc_datamap); 176979695Smsmith 177079695Smsmith /* release the packet storage */ 177179695Smsmith if (sc->mly_packet != NULL) { 177279695Smsmith bus_dmamap_unload(sc->mly_packet_dmat, sc->mly_packetmap); 177379695Smsmith bus_dmamem_free(sc->mly_packet_dmat, sc->mly_packet, sc->mly_packetmap); 177479695Smsmith sc->mly_packet = NULL; 177579695Smsmith } 177679695Smsmith} 177779695Smsmith 177879695Smsmith 177979695Smsmith/******************************************************************************** 178073050Smsmith * Command-mapping helper function - populate this command's s/g table 178173050Smsmith * with the s/g entries for its data. 178264987Smsmith */ 178364987Smsmithstatic void 178464987Smsmithmly_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 178564987Smsmith{ 178664987Smsmith struct mly_command *mc = (struct mly_command *)arg; 178764987Smsmith struct mly_softc *sc = mc->mc_sc; 178864987Smsmith struct mly_command_generic *gen = &(mc->mc_packet->generic); 178964987Smsmith struct mly_sg_entry *sg; 179064987Smsmith int i, tabofs; 179164987Smsmith 179279695Smsmith debug_called(2); 179364987Smsmith 179464987Smsmith /* can we use the transfer structure directly? */ 179564987Smsmith if (nseg <= 2) { 179664987Smsmith sg = &gen->transfer.direct.sg[0]; 179764987Smsmith gen->command_control.extended_sg_table = 0; 179864987Smsmith } else { 179979695Smsmith tabofs = ((mc->mc_slot - MLY_SLOT_START) * MLY_MAX_SGENTRIES); 180064987Smsmith sg = sc->mly_sg_table + tabofs; 180164987Smsmith gen->transfer.indirect.entries[0] = nseg; 180264987Smsmith gen->transfer.indirect.table_physaddr[0] = sc->mly_sg_busaddr + (tabofs * sizeof(struct mly_sg_entry)); 180364987Smsmith gen->command_control.extended_sg_table = 1; 180464987Smsmith } 180564987Smsmith 180664987Smsmith /* copy the s/g table */ 180764987Smsmith for (i = 0; i < nseg; i++) { 180864987Smsmith sg[i].physaddr = segs[i].ds_addr; 180964987Smsmith sg[i].length = segs[i].ds_len; 181064987Smsmith } 181164987Smsmith 181264987Smsmith} 181364987Smsmith 181464987Smsmith#if 0 181564987Smsmith/******************************************************************************** 181664987Smsmith * Command-mapping helper function - save the cdb's physical address. 181764987Smsmith * 181864987Smsmith * We don't support 'large' SCSI commands at this time, so this is unused. 181964987Smsmith */ 182064987Smsmithstatic void 182164987Smsmithmly_map_command_cdb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 182264987Smsmith{ 182364987Smsmith struct mly_command *mc = (struct mly_command *)arg; 182464987Smsmith 182579695Smsmith debug_called(2); 182664987Smsmith 182764987Smsmith /* XXX can we safely assume that a CDB will never cross a page boundary? */ 182864987Smsmith if ((segs[0].ds_addr % PAGE_SIZE) > 182964987Smsmith ((segs[0].ds_addr + mc->mc_packet->scsi_large.cdb_length) % PAGE_SIZE)) 183064987Smsmith panic("cdb crosses page boundary"); 183164987Smsmith 183264987Smsmith /* fix up fields in the command packet */ 183364987Smsmith mc->mc_packet->scsi_large.cdb_physaddr = segs[0].ds_addr; 183464987Smsmith} 183564987Smsmith#endif 183664987Smsmith 183764987Smsmith/******************************************************************************** 183864987Smsmith * Map a command into controller-visible space 183964987Smsmith */ 184064987Smsmithstatic void 184164987Smsmithmly_map_command(struct mly_command *mc) 184264987Smsmith{ 184364987Smsmith struct mly_softc *sc = mc->mc_sc; 184464987Smsmith 184564987Smsmith debug_called(2); 184664987Smsmith 184764987Smsmith /* don't map more than once */ 184864987Smsmith if (mc->mc_flags & MLY_CMD_MAPPED) 184964987Smsmith return; 185064987Smsmith 185164987Smsmith /* does the command have a data buffer? */ 185279695Smsmith if (mc->mc_data != NULL) { 1853246713Skib if (mc->mc_flags & MLY_CMD_CCB) 1854246713Skib bus_dmamap_load_ccb(sc->mly_buffer_dmat, mc->mc_datamap, 1855246713Skib mc->mc_data, mly_map_command_sg, mc, 0); 1856246713Skib else 1857246713Skib bus_dmamap_load(sc->mly_buffer_dmat, mc->mc_datamap, 1858246713Skib mc->mc_data, mc->mc_length, 1859246713Skib mly_map_command_sg, mc, 0); 186079695Smsmith if (mc->mc_flags & MLY_CMD_DATAIN) 186179695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREREAD); 186279695Smsmith if (mc->mc_flags & MLY_CMD_DATAOUT) 186379695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREWRITE); 186479695Smsmith } 186564987Smsmith mc->mc_flags |= MLY_CMD_MAPPED; 186664987Smsmith} 186764987Smsmith 186864987Smsmith/******************************************************************************** 186964987Smsmith * Unmap a command from controller-visible space 187064987Smsmith */ 187164987Smsmithstatic void 187264987Smsmithmly_unmap_command(struct mly_command *mc) 187364987Smsmith{ 187464987Smsmith struct mly_softc *sc = mc->mc_sc; 187564987Smsmith 187664987Smsmith debug_called(2); 187764987Smsmith 187864987Smsmith if (!(mc->mc_flags & MLY_CMD_MAPPED)) 187964987Smsmith return; 188064987Smsmith 188179695Smsmith /* does the command have a data buffer? */ 188279695Smsmith if (mc->mc_data != NULL) { 188379695Smsmith if (mc->mc_flags & MLY_CMD_DATAIN) 188479695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTREAD); 188579695Smsmith if (mc->mc_flags & MLY_CMD_DATAOUT) 188679695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTWRITE); 188764987Smsmith 188864987Smsmith bus_dmamap_unload(sc->mly_buffer_dmat, mc->mc_datamap); 188979695Smsmith } 189064987Smsmith mc->mc_flags &= ~MLY_CMD_MAPPED; 189164987Smsmith} 189264987Smsmith 189379695Smsmith 189464987Smsmith/******************************************************************************** 189564987Smsmith ******************************************************************************** 189679695Smsmith CAM interface 189779695Smsmith ******************************************************************************** 189879695Smsmith ********************************************************************************/ 189979695Smsmith 190079695Smsmith/******************************************************************************** 190179695Smsmith * Attach the physical and virtual SCSI busses to CAM. 190279695Smsmith * 190379695Smsmith * Physical bus numbering starts from 0, virtual bus numbering from one greater 190479695Smsmith * than the highest physical bus. Physical busses are only registered if 190579695Smsmith * the kernel environment variable "hw.mly.register_physical_channels" is set. 190679695Smsmith * 190779695Smsmith * When we refer to a "bus", we are referring to the bus number registered with 190879695Smsmith * the SIM, wheras a "channel" is a channel number given to the adapter. In order 190979695Smsmith * to keep things simple, we map these 1:1, so "bus" and "channel" may be used 191079695Smsmith * interchangeably. 191179695Smsmith */ 1912105215Sphkstatic int 191379695Smsmithmly_cam_attach(struct mly_softc *sc) 191479695Smsmith{ 191579695Smsmith struct cam_devq *devq; 191679695Smsmith int chn, i; 191779695Smsmith 191879695Smsmith debug_called(1); 191979695Smsmith 192079695Smsmith /* 192179695Smsmith * Allocate a devq for all our channels combined. 192279695Smsmith */ 192379695Smsmith if ((devq = cam_simq_alloc(sc->mly_controllerinfo->maximum_parallel_commands)) == NULL) { 192479695Smsmith mly_printf(sc, "can't allocate CAM SIM queue\n"); 192579695Smsmith return(ENOMEM); 192679695Smsmith } 192779695Smsmith 192879695Smsmith /* 192979695Smsmith * If physical channel registration has been requested, register these first. 193079695Smsmith * Note that we enable tagged command queueing for physical channels. 193179695Smsmith */ 193294936Smux if (testenv("hw.mly.register_physical_channels")) { 193379695Smsmith chn = 0; 193479695Smsmith for (i = 0; i < sc->mly_controllerinfo->physical_channels_present; i++, chn++) { 193579695Smsmith 193679695Smsmith if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, 193779695Smsmith device_get_unit(sc->mly_dev), 1938168752Sscottl &Giant, 193979695Smsmith sc->mly_controllerinfo->maximum_parallel_commands, 194079695Smsmith 1, devq)) == NULL) { 194179695Smsmith return(ENOMEM); 194279695Smsmith } 1943170872Sscottl if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) { 194479695Smsmith mly_printf(sc, "CAM XPT phsyical channel registration failed\n"); 194579695Smsmith return(ENXIO); 194679695Smsmith } 194779695Smsmith debug(1, "registered physical channel %d", chn); 194879695Smsmith } 194979695Smsmith } 195079695Smsmith 195179695Smsmith /* 195279695Smsmith * Register our virtual channels, with bus numbers matching channel numbers. 195379695Smsmith */ 195479695Smsmith chn = sc->mly_controllerinfo->physical_channels_present; 195579695Smsmith for (i = 0; i < sc->mly_controllerinfo->virtual_channels_present; i++, chn++) { 195679695Smsmith if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, 195779695Smsmith device_get_unit(sc->mly_dev), 1958168752Sscottl &Giant, 195979695Smsmith sc->mly_controllerinfo->maximum_parallel_commands, 196079695Smsmith 0, devq)) == NULL) { 196179695Smsmith return(ENOMEM); 196279695Smsmith } 1963170872Sscottl if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) { 196479695Smsmith mly_printf(sc, "CAM XPT virtual channel registration failed\n"); 196579695Smsmith return(ENXIO); 196679695Smsmith } 196779695Smsmith debug(1, "registered virtual channel %d", chn); 196879695Smsmith } 196979695Smsmith 197079695Smsmith /* 197179695Smsmith * This is the total number of channels that (might have been) registered with 197279695Smsmith * CAM. Some may not have been; check the mly_cam_sim array to be certain. 197379695Smsmith */ 197479695Smsmith sc->mly_cam_channels = sc->mly_controllerinfo->physical_channels_present + 197579695Smsmith sc->mly_controllerinfo->virtual_channels_present; 197679695Smsmith 197779695Smsmith return(0); 197879695Smsmith} 197979695Smsmith 198079695Smsmith/******************************************************************************** 198179695Smsmith * Detach from CAM 198279695Smsmith */ 1983105215Sphkstatic void 198479695Smsmithmly_cam_detach(struct mly_softc *sc) 198579695Smsmith{ 198679695Smsmith int i; 198779695Smsmith 198879695Smsmith debug_called(1); 198979695Smsmith 199079695Smsmith for (i = 0; i < sc->mly_cam_channels; i++) { 199179695Smsmith if (sc->mly_cam_sim[i] != NULL) { 199279695Smsmith xpt_bus_deregister(cam_sim_path(sc->mly_cam_sim[i])); 199379695Smsmith cam_sim_free(sc->mly_cam_sim[i], 0); 199479695Smsmith } 199579695Smsmith } 199679695Smsmith if (sc->mly_cam_devq != NULL) 199779695Smsmith cam_simq_free(sc->mly_cam_devq); 199879695Smsmith} 199979695Smsmith 200079695Smsmith/************************************************************************ 200179695Smsmith * Rescan a device. 200279695Smsmith */ 200379695Smsmithstatic void 200479695Smsmithmly_cam_rescan_btl(struct mly_softc *sc, int bus, int target) 200579695Smsmith{ 200679695Smsmith union ccb *ccb; 200779695Smsmith 200879695Smsmith debug_called(1); 200979695Smsmith 2010203108Smav if ((ccb = xpt_alloc_ccb()) == NULL) { 201179695Smsmith mly_printf(sc, "rescan failed (can't allocate CCB)\n"); 201279695Smsmith return; 201379695Smsmith } 2014249468Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, 2015203108Smav cam_sim_path(sc->mly_cam_sim[bus]), target, 0) != CAM_REQ_CMP) { 201679695Smsmith mly_printf(sc, "rescan failed (can't create path)\n"); 2017203108Smav xpt_free_ccb(ccb); 201879695Smsmith return; 201979695Smsmith } 202079695Smsmith debug(1, "rescan target %d:%d", bus, target); 2021203108Smav xpt_rescan(ccb); 202279695Smsmith} 202379695Smsmith 202479695Smsmith/******************************************************************************** 202579695Smsmith * Handle an action requested by CAM 202679695Smsmith */ 202779695Smsmithstatic void 202879695Smsmithmly_cam_action(struct cam_sim *sim, union ccb *ccb) 202979695Smsmith{ 203079695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 203179695Smsmith 203279695Smsmith debug_called(2); 203379695Smsmith 203479695Smsmith switch (ccb->ccb_h.func_code) { 203579695Smsmith 203679695Smsmith /* perform SCSI I/O */ 203779695Smsmith case XPT_SCSI_IO: 203879695Smsmith if (!mly_cam_action_io(sim, (struct ccb_scsiio *)&ccb->csio)) 203979695Smsmith return; 204079695Smsmith break; 204179695Smsmith 204279695Smsmith /* perform geometry calculations */ 204379695Smsmith case XPT_CALC_GEOMETRY: 204479695Smsmith { 204579695Smsmith struct ccb_calc_geometry *ccg = &ccb->ccg; 204679695Smsmith u_int32_t secs_per_cylinder; 204779695Smsmith 204879695Smsmith debug(2, "XPT_CALC_GEOMETRY %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 204979695Smsmith 205079695Smsmith if (sc->mly_controllerparam->bios_geometry == MLY_BIOSGEOM_8G) { 205179695Smsmith ccg->heads = 255; 205279695Smsmith ccg->secs_per_track = 63; 205379695Smsmith } else { /* MLY_BIOSGEOM_2G */ 205479695Smsmith ccg->heads = 128; 205579695Smsmith ccg->secs_per_track = 32; 205679695Smsmith } 205779695Smsmith secs_per_cylinder = ccg->heads * ccg->secs_per_track; 205879695Smsmith ccg->cylinders = ccg->volume_size / secs_per_cylinder; 205979695Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 206079695Smsmith break; 206179695Smsmith } 206279695Smsmith 206379695Smsmith /* handle path attribute inquiry */ 206479695Smsmith case XPT_PATH_INQ: 206579695Smsmith { 206679695Smsmith struct ccb_pathinq *cpi = &ccb->cpi; 206779695Smsmith 206879695Smsmith debug(2, "XPT_PATH_INQ %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 206979695Smsmith 207079695Smsmith cpi->version_num = 1; 207179695Smsmith cpi->hba_inquiry = PI_TAG_ABLE; /* XXX extra flags for physical channels? */ 207279695Smsmith cpi->target_sprt = 0; 207379695Smsmith cpi->hba_misc = 0; 207479695Smsmith cpi->max_target = MLY_MAX_TARGETS - 1; 207579695Smsmith cpi->max_lun = MLY_MAX_LUNS - 1; 207679695Smsmith cpi->initiator_id = sc->mly_controllerparam->initiator_id; 207779695Smsmith strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 207879695Smsmith strncpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN); 207979695Smsmith strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 208079695Smsmith cpi->unit_number = cam_sim_unit(sim); 208179695Smsmith cpi->bus_id = cam_sim_bus(sim); 208279695Smsmith cpi->base_transfer_speed = 132 * 1024; /* XXX what to set this to? */ 2083163816Smjacob cpi->transport = XPORT_SPI; 2084163816Smjacob cpi->transport_version = 2; 2085163816Smjacob cpi->protocol = PROTO_SCSI; 2086163816Smjacob cpi->protocol_version = SCSI_REV_2; 208779695Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 208879695Smsmith break; 208979695Smsmith } 209079695Smsmith 209179695Smsmith case XPT_GET_TRAN_SETTINGS: 209279695Smsmith { 209379695Smsmith struct ccb_trans_settings *cts = &ccb->cts; 209479695Smsmith int bus, target; 2095163816Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 2096163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 209779695Smsmith 2098163816Smjacob cts->protocol = PROTO_SCSI; 2099163816Smjacob cts->protocol_version = SCSI_REV_2; 2100163816Smjacob cts->transport = XPORT_SPI; 2101163816Smjacob cts->transport_version = 2; 2102163816Smjacob 2103163816Smjacob scsi->flags = 0; 2104163816Smjacob scsi->valid = 0; 2105163816Smjacob spi->flags = 0; 2106163816Smjacob spi->valid = 0; 2107163816Smjacob 210879695Smsmith bus = cam_sim_bus(sim); 210979695Smsmith target = cts->ccb_h.target_id; 2110163816Smjacob debug(2, "XPT_GET_TRAN_SETTINGS %d:%d", bus, target); 2111163816Smjacob /* logical device? */ 2112163816Smjacob if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) { 2113163816Smjacob /* nothing special for these */ 2114163816Smjacob /* physical device? */ 2115163816Smjacob } else if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_PHYSICAL) { 2116163816Smjacob /* allow CAM to try tagged transactions */ 2117163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2118163816Smjacob scsi->valid |= CTS_SCSI_VALID_TQ; 2119163816Smjacob 2120163816Smjacob /* convert speed (MHz) to usec */ 2121163816Smjacob if (sc->mly_btl[bus][target].mb_speed == 0) { 2122163816Smjacob spi->sync_period = 1000000 / 5; 2123163816Smjacob } else { 2124163816Smjacob spi->sync_period = 1000000 / sc->mly_btl[bus][target].mb_speed; 2125163816Smjacob } 2126163816Smjacob 2127163816Smjacob /* convert bus width to CAM internal encoding */ 2128163816Smjacob switch (sc->mly_btl[bus][target].mb_width) { 2129163816Smjacob case 32: 2130163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT; 2131163816Smjacob break; 2132163816Smjacob case 16: 2133163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2134163816Smjacob break; 2135163816Smjacob case 8: 2136163816Smjacob default: 2137163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2138163816Smjacob break; 2139163816Smjacob } 2140163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_BUS_WIDTH; 2141163816Smjacob 2142163816Smjacob /* not a device, bail out */ 2143163816Smjacob } else { 2144163816Smjacob cts->ccb_h.status = CAM_REQ_CMP_ERR; 2145163816Smjacob break; 2146163816Smjacob } 2147163816Smjacob 2148163816Smjacob /* disconnect always OK */ 2149163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2150163816Smjacob spi->valid |= CTS_SPI_VALID_DISC; 2151163816Smjacob 215279695Smsmith cts->ccb_h.status = CAM_REQ_CMP; 215379695Smsmith break; 215479695Smsmith } 215579695Smsmith 215679695Smsmith default: /* we can't do this */ 215779695Smsmith debug(2, "unspported func_code = 0x%x", ccb->ccb_h.func_code); 215879695Smsmith ccb->ccb_h.status = CAM_REQ_INVALID; 215979695Smsmith break; 216079695Smsmith } 216179695Smsmith 216279695Smsmith xpt_done(ccb); 216379695Smsmith} 216479695Smsmith 216579695Smsmith/******************************************************************************** 216679695Smsmith * Handle an I/O operation requested by CAM 216779695Smsmith */ 216879695Smsmithstatic int 216979695Smsmithmly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio) 217079695Smsmith{ 217179695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 217279695Smsmith struct mly_command *mc; 217379695Smsmith struct mly_command_scsi_small *ss; 217479695Smsmith int bus, target; 217579695Smsmith int error; 2176110479Sscottl int s; 217779695Smsmith 217879695Smsmith bus = cam_sim_bus(sim); 217979695Smsmith target = csio->ccb_h.target_id; 218079695Smsmith 218179695Smsmith debug(2, "XPT_SCSI_IO %d:%d:%d", bus, target, csio->ccb_h.target_lun); 218279695Smsmith 218379695Smsmith /* validate bus number */ 218479695Smsmith if (!MLY_BUS_IS_VALID(sc, bus)) { 218579695Smsmith debug(0, " invalid bus %d", bus); 218679695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 218779695Smsmith } 218879695Smsmith 218979695Smsmith /* check for I/O attempt to a protected device */ 219079695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_PROTECTED) { 219179695Smsmith debug(2, " device protected"); 219279695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 219379695Smsmith } 219479695Smsmith 219579695Smsmith /* check for I/O attempt to nonexistent device */ 219679695Smsmith if (!(sc->mly_btl[bus][target].mb_flags & (MLY_BTL_LOGICAL | MLY_BTL_PHYSICAL))) { 219779695Smsmith debug(2, " device %d:%d does not exist", bus, target); 219879695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 219979695Smsmith } 220079695Smsmith 220179695Smsmith /* XXX increase if/when we support large SCSI commands */ 220279695Smsmith if (csio->cdb_len > MLY_CMD_SCSI_SMALL_CDB) { 220379695Smsmith debug(0, " command too large (%d > %d)", csio->cdb_len, MLY_CMD_SCSI_SMALL_CDB); 220479695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 220579695Smsmith } 220679695Smsmith 220779695Smsmith /* check that the CDB pointer is not to a physical address */ 220879695Smsmith if ((csio->ccb_h.flags & CAM_CDB_POINTER) && (csio->ccb_h.flags & CAM_CDB_PHYS)) { 220979695Smsmith debug(0, " CDB pointer is to physical address"); 221079695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 221179695Smsmith } 221279695Smsmith 221379695Smsmith /* abandon aborted ccbs or those that have failed validation */ 221479695Smsmith if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 221579695Smsmith debug(2, "abandoning CCB due to abort/validation failure"); 221679695Smsmith return(EINVAL); 221779695Smsmith } 221879695Smsmith 221979695Smsmith /* 222079695Smsmith * Get a command, or push the ccb back to CAM and freeze the queue. 222179695Smsmith */ 222279695Smsmith if ((error = mly_alloc_command(sc, &mc))) { 2223110479Sscottl s = splcam(); 222479695Smsmith xpt_freeze_simq(sim, 1); 222579695Smsmith csio->ccb_h.status |= CAM_REQUEUE_REQ; 2226110479Sscottl sc->mly_qfrzn_cnt++; 2227110479Sscottl splx(s); 222879695Smsmith return(error); 222979695Smsmith } 223079695Smsmith 223179695Smsmith /* build the command */ 2232246713Skib mc->mc_data = csio; 223379695Smsmith mc->mc_length = csio->dxfer_len; 223479695Smsmith mc->mc_complete = mly_cam_complete; 223579695Smsmith mc->mc_private = csio; 2236246713Skib mc->mc_flags |= MLY_CMD_CCB; 2237246713Skib /* XXX This code doesn't set the data direction in mc_flags. */ 223879695Smsmith 223979695Smsmith /* save the bus number in the ccb for later recovery XXX should be a better way */ 224079695Smsmith csio->ccb_h.sim_priv.entries[0].field = bus; 224179695Smsmith 224279695Smsmith /* build the packet for the controller */ 224379695Smsmith ss = &mc->mc_packet->scsi_small; 224479695Smsmith ss->opcode = MDACMD_SCSI; 224580365Smsmith if (csio->ccb_h.flags & CAM_DIS_DISCONNECT) 224679695Smsmith ss->command_control.disable_disconnect = 1; 224779695Smsmith if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 224879695Smsmith ss->command_control.data_direction = MLY_CCB_WRITE; 224979695Smsmith ss->data_size = csio->dxfer_len; 225079695Smsmith ss->addr.phys.lun = csio->ccb_h.target_lun; 225179695Smsmith ss->addr.phys.target = csio->ccb_h.target_id; 225279695Smsmith ss->addr.phys.channel = bus; 225379695Smsmith if (csio->ccb_h.timeout < (60 * 1000)) { 225479695Smsmith ss->timeout.value = csio->ccb_h.timeout / 1000; 225579695Smsmith ss->timeout.scale = MLY_TIMEOUT_SECONDS; 225679695Smsmith } else if (csio->ccb_h.timeout < (60 * 60 * 1000)) { 225779695Smsmith ss->timeout.value = csio->ccb_h.timeout / (60 * 1000); 225879695Smsmith ss->timeout.scale = MLY_TIMEOUT_MINUTES; 225979695Smsmith } else { 226079695Smsmith ss->timeout.value = csio->ccb_h.timeout / (60 * 60 * 1000); /* overflow? */ 226179695Smsmith ss->timeout.scale = MLY_TIMEOUT_HOURS; 226279695Smsmith } 226379695Smsmith ss->maximum_sense_size = csio->sense_len; 226479695Smsmith ss->cdb_length = csio->cdb_len; 226579695Smsmith if (csio->ccb_h.flags & CAM_CDB_POINTER) { 226679695Smsmith bcopy(csio->cdb_io.cdb_ptr, ss->cdb, csio->cdb_len); 226779695Smsmith } else { 226879695Smsmith bcopy(csio->cdb_io.cdb_bytes, ss->cdb, csio->cdb_len); 226979695Smsmith } 227079695Smsmith 227179695Smsmith /* give the command to the controller */ 227279695Smsmith if ((error = mly_start(mc))) { 2273110479Sscottl s = splcam(); 227479695Smsmith xpt_freeze_simq(sim, 1); 227579695Smsmith csio->ccb_h.status |= CAM_REQUEUE_REQ; 2276110479Sscottl sc->mly_qfrzn_cnt++; 2277110479Sscottl splx(s); 227879695Smsmith return(error); 227979695Smsmith } 228079695Smsmith 228179695Smsmith return(0); 228279695Smsmith} 228379695Smsmith 228479695Smsmith/******************************************************************************** 228579695Smsmith * Check for possibly-completed commands. 228679695Smsmith */ 228779695Smsmithstatic void 228879695Smsmithmly_cam_poll(struct cam_sim *sim) 228979695Smsmith{ 229079695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 229179695Smsmith 229279695Smsmith debug_called(2); 229379695Smsmith 229479695Smsmith mly_done(sc); 229579695Smsmith} 229679695Smsmith 229779695Smsmith/******************************************************************************** 229879695Smsmith * Handle completion of a command - pass results back through the CCB 229979695Smsmith */ 230079695Smsmithstatic void 230179695Smsmithmly_cam_complete(struct mly_command *mc) 230279695Smsmith{ 230379695Smsmith struct mly_softc *sc = mc->mc_sc; 230479695Smsmith struct ccb_scsiio *csio = (struct ccb_scsiio *)mc->mc_private; 230579695Smsmith struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr; 230679695Smsmith struct mly_btl *btl; 230779695Smsmith u_int8_t cmd; 230879695Smsmith int bus, target; 2309110479Sscottl int s; 231079695Smsmith 231179695Smsmith debug_called(2); 231279695Smsmith 231379695Smsmith csio->scsi_status = mc->mc_status; 231479695Smsmith switch(mc->mc_status) { 231579695Smsmith case SCSI_STATUS_OK: 231679695Smsmith /* 231779695Smsmith * In order to report logical device type and status, we overwrite 231879695Smsmith * the result of the INQUIRY command to logical devices. 231979695Smsmith */ 232079695Smsmith bus = csio->ccb_h.sim_priv.entries[0].field; 232179695Smsmith target = csio->ccb_h.target_id; 232279695Smsmith /* XXX validate bus/target? */ 232379695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) { 232479695Smsmith if (csio->ccb_h.flags & CAM_CDB_POINTER) { 232579695Smsmith cmd = *csio->cdb_io.cdb_ptr; 232679695Smsmith } else { 232779695Smsmith cmd = csio->cdb_io.cdb_bytes[0]; 232879695Smsmith } 232979695Smsmith if (cmd == INQUIRY) { 233079695Smsmith btl = &sc->mly_btl[bus][target]; 233179695Smsmith padstr(inq->vendor, mly_describe_code(mly_table_device_type, btl->mb_type), 8); 233279695Smsmith padstr(inq->product, mly_describe_code(mly_table_device_state, btl->mb_state), 16); 233379695Smsmith padstr(inq->revision, "", 4); 233479695Smsmith } 233579695Smsmith } 233679695Smsmith 233779695Smsmith debug(2, "SCSI_STATUS_OK"); 233879695Smsmith csio->ccb_h.status = CAM_REQ_CMP; 233979695Smsmith break; 234079695Smsmith 234179695Smsmith case SCSI_STATUS_CHECK_COND: 234279695Smsmith debug(1, "SCSI_STATUS_CHECK_COND sense %d resid %d", mc->mc_sense, mc->mc_resid); 234379695Smsmith csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; 234479695Smsmith bzero(&csio->sense_data, SSD_FULL_SIZE); 234579695Smsmith bcopy(mc->mc_packet, &csio->sense_data, mc->mc_sense); 234679695Smsmith csio->sense_len = mc->mc_sense; 234779695Smsmith csio->ccb_h.status |= CAM_AUTOSNS_VALID; 234879695Smsmith csio->resid = mc->mc_resid; /* XXX this is a signed value... */ 234979695Smsmith break; 235079695Smsmith 235179695Smsmith case SCSI_STATUS_BUSY: 235279695Smsmith debug(1, "SCSI_STATUS_BUSY"); 235379695Smsmith csio->ccb_h.status = CAM_SCSI_BUSY; 235479695Smsmith break; 235579695Smsmith 235679695Smsmith default: 235779695Smsmith debug(1, "unknown status 0x%x", csio->scsi_status); 235879695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 235979695Smsmith break; 236079695Smsmith } 2361110479Sscottl 2362110479Sscottl s = splcam(); 2363110479Sscottl if (sc->mly_qfrzn_cnt) { 2364110479Sscottl csio->ccb_h.status |= CAM_RELEASE_SIMQ; 2365110479Sscottl sc->mly_qfrzn_cnt--; 2366110479Sscottl } 2367110479Sscottl splx(s); 2368110479Sscottl 236979695Smsmith xpt_done((union ccb *)csio); 237079695Smsmith mly_release_command(mc); 237179695Smsmith} 237279695Smsmith 237379695Smsmith/******************************************************************************** 237479695Smsmith * Find a peripheral attahed at (bus),(target) 237579695Smsmith */ 237679695Smsmithstatic struct cam_periph * 237779695Smsmithmly_find_periph(struct mly_softc *sc, int bus, int target) 237879695Smsmith{ 237979695Smsmith struct cam_periph *periph; 238079695Smsmith struct cam_path *path; 238179695Smsmith int status; 238279695Smsmith 238379695Smsmith status = xpt_create_path(&path, NULL, cam_sim_path(sc->mly_cam_sim[bus]), target, 0); 238479695Smsmith if (status == CAM_REQ_CMP) { 238579695Smsmith periph = cam_periph_find(path, NULL); 238679695Smsmith xpt_free_path(path); 238779695Smsmith } else { 238879695Smsmith periph = NULL; 238979695Smsmith } 239079695Smsmith return(periph); 239179695Smsmith} 239279695Smsmith 239379695Smsmith/******************************************************************************** 239479695Smsmith * Name the device at (bus)(target) 239579695Smsmith */ 2396105215Sphkstatic int 239779695Smsmithmly_name_device(struct mly_softc *sc, int bus, int target) 239879695Smsmith{ 239979695Smsmith struct cam_periph *periph; 240079695Smsmith 240179695Smsmith if ((periph = mly_find_periph(sc, bus, target)) != NULL) { 240279695Smsmith sprintf(sc->mly_btl[bus][target].mb_name, "%s%d", periph->periph_name, periph->unit_number); 240379695Smsmith return(0); 240479695Smsmith } 240579695Smsmith sc->mly_btl[bus][target].mb_name[0] = 0; 240679695Smsmith return(ENOENT); 240779695Smsmith} 240879695Smsmith 240979695Smsmith/******************************************************************************** 241079695Smsmith ******************************************************************************** 241164987Smsmith Hardware Control 241264987Smsmith ******************************************************************************** 241364987Smsmith ********************************************************************************/ 241464987Smsmith 241564987Smsmith/******************************************************************************** 241664987Smsmith * Handshake with the firmware while the card is being initialised. 241764987Smsmith */ 241864987Smsmithstatic int 241964987Smsmithmly_fwhandshake(struct mly_softc *sc) 242064987Smsmith{ 242164987Smsmith u_int8_t error, param0, param1; 242264987Smsmith int spinup = 0; 242364987Smsmith 242464987Smsmith debug_called(1); 242564987Smsmith 242664987Smsmith /* set HM_STSACK and let the firmware initialise */ 242764987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); 242864987Smsmith DELAY(1000); /* too short? */ 242964987Smsmith 243064987Smsmith /* if HM_STSACK is still true, the controller is initialising */ 243164987Smsmith if (!MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) 243264987Smsmith return(0); 243364987Smsmith mly_printf(sc, "controller initialisation started\n"); 243464987Smsmith 243564987Smsmith /* spin waiting for initialisation to finish, or for a message to be delivered */ 243664987Smsmith while (MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) { 243764987Smsmith /* check for a message */ 243864987Smsmith if (MLY_ERROR_VALID(sc)) { 243964987Smsmith error = MLY_GET_REG(sc, sc->mly_error_status) & ~MLY_MSG_EMPTY; 244064987Smsmith param0 = MLY_GET_REG(sc, sc->mly_command_mailbox); 244164987Smsmith param1 = MLY_GET_REG(sc, sc->mly_command_mailbox + 1); 244264987Smsmith 244364987Smsmith switch(error) { 244464987Smsmith case MLY_MSG_SPINUP: 244564987Smsmith if (!spinup) { 244664987Smsmith mly_printf(sc, "drive spinup in progress\n"); 244764987Smsmith spinup = 1; /* only print this once (should print drive being spun?) */ 244864987Smsmith } 244964987Smsmith break; 245064987Smsmith case MLY_MSG_RACE_RECOVERY_FAIL: 245164987Smsmith mly_printf(sc, "mirror race recovery failed, one or more drives offline\n"); 245264987Smsmith break; 245364987Smsmith case MLY_MSG_RACE_IN_PROGRESS: 245464987Smsmith mly_printf(sc, "mirror race recovery in progress\n"); 245564987Smsmith break; 245664987Smsmith case MLY_MSG_RACE_ON_CRITICAL: 245764987Smsmith mly_printf(sc, "mirror race recovery on a critical drive\n"); 245864987Smsmith break; 245964987Smsmith case MLY_MSG_PARITY_ERROR: 246064987Smsmith mly_printf(sc, "FATAL MEMORY PARITY ERROR\n"); 246164987Smsmith return(ENXIO); 246264987Smsmith default: 246364987Smsmith mly_printf(sc, "unknown initialisation code 0x%x\n", error); 246464987Smsmith } 246564987Smsmith } 246664987Smsmith } 246764987Smsmith return(0); 246864987Smsmith} 246964987Smsmith 247064987Smsmith/******************************************************************************** 247164987Smsmith ******************************************************************************** 247264987Smsmith Debugging and Diagnostics 247364987Smsmith ******************************************************************************** 247464987Smsmith ********************************************************************************/ 247564987Smsmith 247664987Smsmith/******************************************************************************** 247764987Smsmith * Print some information about the controller. 247864987Smsmith */ 247964987Smsmithstatic void 248064987Smsmithmly_describe_controller(struct mly_softc *sc) 248164987Smsmith{ 248264987Smsmith struct mly_ioctl_getcontrollerinfo *mi = sc->mly_controllerinfo; 248364987Smsmith 248464987Smsmith mly_printf(sc, "%16s, %d channel%s, firmware %d.%02d-%d-%02d (%02d%02d%02d%02d), %dMB RAM\n", 248564987Smsmith mi->controller_name, mi->physical_channels_present, (mi->physical_channels_present) > 1 ? "s" : "", 248664987Smsmith mi->fw_major, mi->fw_minor, mi->fw_turn, mi->fw_build, /* XXX turn encoding? */ 248764987Smsmith mi->fw_century, mi->fw_year, mi->fw_month, mi->fw_day, 248864987Smsmith mi->memory_size); 248964987Smsmith 249064987Smsmith if (bootverbose) { 249164987Smsmith mly_printf(sc, "%s %s (%x), %dMHz %d-bit %.16s\n", 249264987Smsmith mly_describe_code(mly_table_oemname, mi->oem_information), 249364987Smsmith mly_describe_code(mly_table_controllertype, mi->controller_type), mi->controller_type, 249464987Smsmith mi->interface_speed, mi->interface_width, mi->interface_name); 249564987Smsmith mly_printf(sc, "%dMB %dMHz %d-bit %s%s%s, cache %dMB\n", 249664987Smsmith mi->memory_size, mi->memory_speed, mi->memory_width, 249764987Smsmith mly_describe_code(mly_table_memorytype, mi->memory_type), 249864987Smsmith mi->memory_parity ? "+parity": "",mi->memory_ecc ? "+ECC": "", 249964987Smsmith mi->cache_size); 2500202161Sgavin mly_printf(sc, "CPU: %s @ %dMHz\n", 250164987Smsmith mly_describe_code(mly_table_cputype, mi->cpu[0].type), mi->cpu[0].speed); 250264987Smsmith if (mi->l2cache_size != 0) 250364987Smsmith mly_printf(sc, "%dKB L2 cache\n", mi->l2cache_size); 250464987Smsmith if (mi->exmemory_size != 0) 250564987Smsmith mly_printf(sc, "%dMB %dMHz %d-bit private %s%s%s\n", 250664987Smsmith mi->exmemory_size, mi->exmemory_speed, mi->exmemory_width, 250764987Smsmith mly_describe_code(mly_table_memorytype, mi->exmemory_type), 250864987Smsmith mi->exmemory_parity ? "+parity": "",mi->exmemory_ecc ? "+ECC": ""); 250964987Smsmith mly_printf(sc, "battery backup %s\n", mi->bbu_present ? "present" : "not installed"); 251064987Smsmith mly_printf(sc, "maximum data transfer %d blocks, maximum sg entries/command %d\n", 251164987Smsmith mi->maximum_block_count, mi->maximum_sg_entries); 251264987Smsmith mly_printf(sc, "logical devices present/critical/offline %d/%d/%d\n", 251364987Smsmith mi->logical_devices_present, mi->logical_devices_critical, mi->logical_devices_offline); 251464987Smsmith mly_printf(sc, "physical devices present %d\n", 251564987Smsmith mi->physical_devices_present); 251664987Smsmith mly_printf(sc, "physical disks present/offline %d/%d\n", 251764987Smsmith mi->physical_disks_present, mi->physical_disks_offline); 251864987Smsmith mly_printf(sc, "%d physical channel%s, %d virtual channel%s of %d possible\n", 251964987Smsmith mi->physical_channels_present, mi->physical_channels_present == 1 ? "" : "s", 252064987Smsmith mi->virtual_channels_present, mi->virtual_channels_present == 1 ? "" : "s", 252164987Smsmith mi->virtual_channels_possible); 252264987Smsmith mly_printf(sc, "%d parallel commands supported\n", mi->maximum_parallel_commands); 252364987Smsmith mly_printf(sc, "%dMB flash ROM, %d of %d maximum cycles\n", 252464987Smsmith mi->flash_size, mi->flash_age, mi->flash_maximum_age); 252564987Smsmith } 252664987Smsmith} 252764987Smsmith 252864987Smsmith#ifdef MLY_DEBUG 252964987Smsmith/******************************************************************************** 253064987Smsmith * Print some controller state 253164987Smsmith */ 253264987Smsmithstatic void 253364987Smsmithmly_printstate(struct mly_softc *sc) 253464987Smsmith{ 253564987Smsmith mly_printf(sc, "IDBR %02x ODBR %02x ERROR %02x (%x %x %x)\n", 253664987Smsmith MLY_GET_REG(sc, sc->mly_idbr), 253764987Smsmith MLY_GET_REG(sc, sc->mly_odbr), 253864987Smsmith MLY_GET_REG(sc, sc->mly_error_status), 253964987Smsmith sc->mly_idbr, 254064987Smsmith sc->mly_odbr, 254164987Smsmith sc->mly_error_status); 254264987Smsmith mly_printf(sc, "IMASK %02x ISTATUS %02x\n", 254364987Smsmith MLY_GET_REG(sc, sc->mly_interrupt_mask), 254464987Smsmith MLY_GET_REG(sc, sc->mly_interrupt_status)); 254564987Smsmith mly_printf(sc, "COMMAND %02x %02x %02x %02x %02x %02x %02x %02x\n", 254664987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox), 254764987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 1), 254864987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 2), 254964987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 3), 255064987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 4), 255164987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 5), 255264987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 6), 255364987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 7)); 255464987Smsmith mly_printf(sc, "STATUS %02x %02x %02x %02x %02x %02x %02x %02x\n", 255564987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox), 255664987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 1), 255764987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 2), 255864987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 3), 255964987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 4), 256064987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 5), 256164987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 6), 256264987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 7)); 256364987Smsmith mly_printf(sc, " %04x %08x\n", 256464987Smsmith MLY_GET_REG2(sc, sc->mly_status_mailbox), 256564987Smsmith MLY_GET_REG4(sc, sc->mly_status_mailbox + 4)); 256664987Smsmith} 256764987Smsmith 256864987Smsmithstruct mly_softc *mly_softc0 = NULL; 256964987Smsmithvoid 257064987Smsmithmly_printstate0(void) 257164987Smsmith{ 257264987Smsmith if (mly_softc0 != NULL) 257364987Smsmith mly_printstate(mly_softc0); 257464987Smsmith} 257564987Smsmith 257664987Smsmith/******************************************************************************** 257764987Smsmith * Print a command 257864987Smsmith */ 257964987Smsmithstatic void 258064987Smsmithmly_print_command(struct mly_command *mc) 258164987Smsmith{ 258264987Smsmith struct mly_softc *sc = mc->mc_sc; 258364987Smsmith 258464987Smsmith mly_printf(sc, "COMMAND @ %p\n", mc); 258564987Smsmith mly_printf(sc, " slot %d\n", mc->mc_slot); 258664987Smsmith mly_printf(sc, " status 0x%x\n", mc->mc_status); 258764987Smsmith mly_printf(sc, " sense len %d\n", mc->mc_sense); 258864987Smsmith mly_printf(sc, " resid %d\n", mc->mc_resid); 258964987Smsmith mly_printf(sc, " packet %p/0x%llx\n", mc->mc_packet, mc->mc_packetphys); 259064987Smsmith if (mc->mc_packet != NULL) 259164987Smsmith mly_print_packet(mc); 259264987Smsmith mly_printf(sc, " data %p/%d\n", mc->mc_data, mc->mc_length); 259373050Smsmith mly_printf(sc, " flags %b\n", mc->mc_flags, "\20\1busy\2complete\3slotted\4mapped\5datain\6dataout\n"); 259464987Smsmith mly_printf(sc, " complete %p\n", mc->mc_complete); 259564987Smsmith mly_printf(sc, " private %p\n", mc->mc_private); 259664987Smsmith} 259764987Smsmith 259864987Smsmith/******************************************************************************** 259964987Smsmith * Print a command packet 260064987Smsmith */ 260164987Smsmithstatic void 260264987Smsmithmly_print_packet(struct mly_command *mc) 260364987Smsmith{ 260464987Smsmith struct mly_softc *sc = mc->mc_sc; 260564987Smsmith struct mly_command_generic *ge = (struct mly_command_generic *)mc->mc_packet; 260664987Smsmith struct mly_command_scsi_small *ss = (struct mly_command_scsi_small *)mc->mc_packet; 260764987Smsmith struct mly_command_scsi_large *sl = (struct mly_command_scsi_large *)mc->mc_packet; 260864987Smsmith struct mly_command_ioctl *io = (struct mly_command_ioctl *)mc->mc_packet; 260964987Smsmith int transfer; 261064987Smsmith 261164987Smsmith mly_printf(sc, " command_id %d\n", ge->command_id); 261264987Smsmith mly_printf(sc, " opcode %d\n", ge->opcode); 261364987Smsmith mly_printf(sc, " command_control fua %d dpo %d est %d dd %s nas %d ddis %d\n", 261464987Smsmith ge->command_control.force_unit_access, 261564987Smsmith ge->command_control.disable_page_out, 261664987Smsmith ge->command_control.extended_sg_table, 261764987Smsmith (ge->command_control.data_direction == MLY_CCB_WRITE) ? "WRITE" : "READ", 261864987Smsmith ge->command_control.no_auto_sense, 261964987Smsmith ge->command_control.disable_disconnect); 262064987Smsmith mly_printf(sc, " data_size %d\n", ge->data_size); 262164987Smsmith mly_printf(sc, " sense_buffer_address 0x%llx\n", ge->sense_buffer_address); 262264987Smsmith mly_printf(sc, " lun %d\n", ge->addr.phys.lun); 262364987Smsmith mly_printf(sc, " target %d\n", ge->addr.phys.target); 262464987Smsmith mly_printf(sc, " channel %d\n", ge->addr.phys.channel); 262564987Smsmith mly_printf(sc, " logical device %d\n", ge->addr.log.logdev); 262664987Smsmith mly_printf(sc, " controller %d\n", ge->addr.phys.controller); 262764987Smsmith mly_printf(sc, " timeout %d %s\n", 262864987Smsmith ge->timeout.value, 262964987Smsmith (ge->timeout.scale == MLY_TIMEOUT_SECONDS) ? "seconds" : 263064987Smsmith ((ge->timeout.scale == MLY_TIMEOUT_MINUTES) ? "minutes" : "hours")); 263164987Smsmith mly_printf(sc, " maximum_sense_size %d\n", ge->maximum_sense_size); 263264987Smsmith switch(ge->opcode) { 263364987Smsmith case MDACMD_SCSIPT: 263464987Smsmith case MDACMD_SCSI: 263564987Smsmith mly_printf(sc, " cdb length %d\n", ss->cdb_length); 263664987Smsmith mly_printf(sc, " cdb %*D\n", ss->cdb_length, ss->cdb, " "); 263764987Smsmith transfer = 1; 263864987Smsmith break; 263964987Smsmith case MDACMD_SCSILC: 264064987Smsmith case MDACMD_SCSILCPT: 264164987Smsmith mly_printf(sc, " cdb length %d\n", sl->cdb_length); 264264987Smsmith mly_printf(sc, " cdb 0x%llx\n", sl->cdb_physaddr); 264364987Smsmith transfer = 1; 264464987Smsmith break; 264564987Smsmith case MDACMD_IOCTL: 264664987Smsmith mly_printf(sc, " sub_ioctl 0x%x\n", io->sub_ioctl); 264764987Smsmith switch(io->sub_ioctl) { 264864987Smsmith case MDACIOCTL_SETMEMORYMAILBOX: 264964987Smsmith mly_printf(sc, " health_buffer_size %d\n", 265064987Smsmith io->param.setmemorymailbox.health_buffer_size); 265164987Smsmith mly_printf(sc, " health_buffer_phys 0x%llx\n", 265264987Smsmith io->param.setmemorymailbox.health_buffer_physaddr); 265364987Smsmith mly_printf(sc, " command_mailbox 0x%llx\n", 265464987Smsmith io->param.setmemorymailbox.command_mailbox_physaddr); 265564987Smsmith mly_printf(sc, " status_mailbox 0x%llx\n", 265664987Smsmith io->param.setmemorymailbox.status_mailbox_physaddr); 265764987Smsmith transfer = 0; 265864987Smsmith break; 265964987Smsmith 266064987Smsmith case MDACIOCTL_SETREALTIMECLOCK: 266164987Smsmith case MDACIOCTL_GETHEALTHSTATUS: 266264987Smsmith case MDACIOCTL_GETCONTROLLERINFO: 266364987Smsmith case MDACIOCTL_GETLOGDEVINFOVALID: 266464987Smsmith case MDACIOCTL_GETPHYSDEVINFOVALID: 266564987Smsmith case MDACIOCTL_GETPHYSDEVSTATISTICS: 266664987Smsmith case MDACIOCTL_GETLOGDEVSTATISTICS: 266764987Smsmith case MDACIOCTL_GETCONTROLLERSTATISTICS: 266864987Smsmith case MDACIOCTL_GETBDT_FOR_SYSDRIVE: 266964987Smsmith case MDACIOCTL_CREATENEWCONF: 267064987Smsmith case MDACIOCTL_ADDNEWCONF: 267164987Smsmith case MDACIOCTL_GETDEVCONFINFO: 267264987Smsmith case MDACIOCTL_GETFREESPACELIST: 267364987Smsmith case MDACIOCTL_MORE: 267464987Smsmith case MDACIOCTL_SETPHYSDEVPARAMETER: 267564987Smsmith case MDACIOCTL_GETPHYSDEVPARAMETER: 267664987Smsmith case MDACIOCTL_GETLOGDEVPARAMETER: 267764987Smsmith case MDACIOCTL_SETLOGDEVPARAMETER: 267864987Smsmith mly_printf(sc, " param %10D\n", io->param.data.param, " "); 267964987Smsmith transfer = 1; 268064987Smsmith break; 268164987Smsmith 268264987Smsmith case MDACIOCTL_GETEVENT: 268364987Smsmith mly_printf(sc, " event %d\n", 268464987Smsmith io->param.getevent.sequence_number_low + ((u_int32_t)io->addr.log.logdev << 16)); 268564987Smsmith transfer = 1; 268664987Smsmith break; 268764987Smsmith 268864987Smsmith case MDACIOCTL_SETRAIDDEVSTATE: 268964987Smsmith mly_printf(sc, " state %d\n", io->param.setraiddevstate.state); 269064987Smsmith transfer = 0; 269164987Smsmith break; 269264987Smsmith 269364987Smsmith case MDACIOCTL_XLATEPHYSDEVTORAIDDEV: 269464987Smsmith mly_printf(sc, " raid_device %d\n", io->param.xlatephysdevtoraiddev.raid_device); 269564987Smsmith mly_printf(sc, " controller %d\n", io->param.xlatephysdevtoraiddev.controller); 269664987Smsmith mly_printf(sc, " channel %d\n", io->param.xlatephysdevtoraiddev.channel); 269764987Smsmith mly_printf(sc, " target %d\n", io->param.xlatephysdevtoraiddev.target); 269864987Smsmith mly_printf(sc, " lun %d\n", io->param.xlatephysdevtoraiddev.lun); 269964987Smsmith transfer = 0; 270064987Smsmith break; 270164987Smsmith 270264987Smsmith case MDACIOCTL_GETGROUPCONFINFO: 270364987Smsmith mly_printf(sc, " group %d\n", io->param.getgroupconfinfo.group); 270464987Smsmith transfer = 1; 270564987Smsmith break; 270664987Smsmith 270764987Smsmith case MDACIOCTL_GET_SUBSYSTEM_DATA: 270864987Smsmith case MDACIOCTL_SET_SUBSYSTEM_DATA: 270964987Smsmith case MDACIOCTL_STARTDISOCVERY: 271064987Smsmith case MDACIOCTL_INITPHYSDEVSTART: 271164987Smsmith case MDACIOCTL_INITPHYSDEVSTOP: 271264987Smsmith case MDACIOCTL_INITRAIDDEVSTART: 271364987Smsmith case MDACIOCTL_INITRAIDDEVSTOP: 271464987Smsmith case MDACIOCTL_REBUILDRAIDDEVSTART: 271564987Smsmith case MDACIOCTL_REBUILDRAIDDEVSTOP: 271664987Smsmith case MDACIOCTL_MAKECONSISTENTDATASTART: 271764987Smsmith case MDACIOCTL_MAKECONSISTENTDATASTOP: 271864987Smsmith case MDACIOCTL_CONSISTENCYCHECKSTART: 271964987Smsmith case MDACIOCTL_CONSISTENCYCHECKSTOP: 272064987Smsmith case MDACIOCTL_RESETDEVICE: 272164987Smsmith case MDACIOCTL_FLUSHDEVICEDATA: 272264987Smsmith case MDACIOCTL_PAUSEDEVICE: 272364987Smsmith case MDACIOCTL_UNPAUSEDEVICE: 272464987Smsmith case MDACIOCTL_LOCATEDEVICE: 272564987Smsmith case MDACIOCTL_SETMASTERSLAVEMODE: 272664987Smsmith case MDACIOCTL_DELETERAIDDEV: 272764987Smsmith case MDACIOCTL_REPLACEINTERNALDEV: 272864987Smsmith case MDACIOCTL_CLEARCONF: 272964987Smsmith case MDACIOCTL_GETCONTROLLERPARAMETER: 273064987Smsmith case MDACIOCTL_SETCONTRLLERPARAMETER: 273164987Smsmith case MDACIOCTL_CLEARCONFSUSPMODE: 273264987Smsmith case MDACIOCTL_STOREIMAGE: 273364987Smsmith case MDACIOCTL_READIMAGE: 273464987Smsmith case MDACIOCTL_FLASHIMAGES: 273564987Smsmith case MDACIOCTL_RENAMERAIDDEV: 273664987Smsmith default: /* no idea what to print */ 273764987Smsmith transfer = 0; 273864987Smsmith break; 273964987Smsmith } 274064987Smsmith break; 274164987Smsmith 274264987Smsmith case MDACMD_IOCTLCHECK: 274364987Smsmith case MDACMD_MEMCOPY: 274464987Smsmith default: 274564987Smsmith transfer = 0; 274664987Smsmith break; /* print nothing */ 274764987Smsmith } 274864987Smsmith if (transfer) { 274964987Smsmith if (ge->command_control.extended_sg_table) { 275064987Smsmith mly_printf(sc, " sg table 0x%llx/%d\n", 275164987Smsmith ge->transfer.indirect.table_physaddr[0], ge->transfer.indirect.entries[0]); 275264987Smsmith } else { 275364987Smsmith mly_printf(sc, " 0000 0x%llx/%lld\n", 275464987Smsmith ge->transfer.direct.sg[0].physaddr, ge->transfer.direct.sg[0].length); 275564987Smsmith mly_printf(sc, " 0001 0x%llx/%lld\n", 275664987Smsmith ge->transfer.direct.sg[1].physaddr, ge->transfer.direct.sg[1].length); 275764987Smsmith } 275864987Smsmith } 275964987Smsmith} 276064987Smsmith 276164987Smsmith/******************************************************************************** 276264987Smsmith * Panic in a slightly informative fashion 276364987Smsmith */ 276464987Smsmithstatic void 276564987Smsmithmly_panic(struct mly_softc *sc, char *reason) 276664987Smsmith{ 276764987Smsmith mly_printstate(sc); 276864987Smsmith panic(reason); 276964987Smsmith} 277073050Smsmith 277173050Smsmith/******************************************************************************** 277273050Smsmith * Print queue statistics, callable from DDB. 277373050Smsmith */ 277473050Smsmithvoid 277573050Smsmithmly_print_controller(int controller) 277673050Smsmith{ 277773050Smsmith struct mly_softc *sc; 277873050Smsmith 277973050Smsmith if ((sc = devclass_get_softc(devclass_find("mly"), controller)) == NULL) { 278073050Smsmith printf("mly: controller %d invalid\n", controller); 278173050Smsmith } else { 278273050Smsmith device_printf(sc->mly_dev, "queue curr max\n"); 278373050Smsmith device_printf(sc->mly_dev, "free %04d/%04d\n", 278473050Smsmith sc->mly_qstat[MLYQ_FREE].q_length, sc->mly_qstat[MLYQ_FREE].q_max); 278573050Smsmith device_printf(sc->mly_dev, "busy %04d/%04d\n", 278673050Smsmith sc->mly_qstat[MLYQ_BUSY].q_length, sc->mly_qstat[MLYQ_BUSY].q_max); 278773050Smsmith device_printf(sc->mly_dev, "complete %04d/%04d\n", 278873050Smsmith sc->mly_qstat[MLYQ_COMPLETE].q_length, sc->mly_qstat[MLYQ_COMPLETE].q_max); 278973050Smsmith } 279073050Smsmith} 279179695Smsmith#endif 279273050Smsmith 279373050Smsmith 279473050Smsmith/******************************************************************************** 279573050Smsmith ******************************************************************************** 279673050Smsmith Control device interface 279773050Smsmith ******************************************************************************** 279873050Smsmith ********************************************************************************/ 279973050Smsmith 280073050Smsmith/******************************************************************************** 280173050Smsmith * Accept an open operation on the control device. 280273050Smsmith */ 280373050Smsmithstatic int 2804130585Sphkmly_user_open(struct cdev *dev, int flags, int fmt, struct thread *td) 280573050Smsmith{ 2806191242Sed struct mly_softc *sc = dev->si_drv1; 280773050Smsmith 280873050Smsmith sc->mly_state |= MLY_STATE_OPEN; 280973050Smsmith return(0); 281073050Smsmith} 281173050Smsmith 281273050Smsmith/******************************************************************************** 281373050Smsmith * Accept the last close on the control device. 281473050Smsmith */ 281573050Smsmithstatic int 2816130585Sphkmly_user_close(struct cdev *dev, int flags, int fmt, struct thread *td) 281773050Smsmith{ 2818191242Sed struct mly_softc *sc = dev->si_drv1; 281973050Smsmith 282073050Smsmith sc->mly_state &= ~MLY_STATE_OPEN; 282173050Smsmith return (0); 282273050Smsmith} 282373050Smsmith 282473050Smsmith/******************************************************************************** 282573050Smsmith * Handle controller-specific control operations. 282673050Smsmith */ 282773050Smsmithstatic int 2828130585Sphkmly_user_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 282983366Sjulian int32_t flag, struct thread *td) 283073050Smsmith{ 283173050Smsmith struct mly_softc *sc = (struct mly_softc *)dev->si_drv1; 283273050Smsmith struct mly_user_command *uc = (struct mly_user_command *)addr; 283373050Smsmith struct mly_user_health *uh = (struct mly_user_health *)addr; 283473050Smsmith 283573050Smsmith switch(cmd) { 283673050Smsmith case MLYIO_COMMAND: 283773050Smsmith return(mly_user_command(sc, uc)); 283873050Smsmith case MLYIO_HEALTH: 283973050Smsmith return(mly_user_health(sc, uh)); 284073050Smsmith default: 284173050Smsmith return(ENOIOCTL); 284273050Smsmith } 284373050Smsmith} 284473050Smsmith 284573050Smsmith/******************************************************************************** 284673050Smsmith * Execute a command passed in from userspace. 284773050Smsmith * 284873050Smsmith * The control structure contains the actual command for the controller, as well 284973050Smsmith * as the user-space data pointer and data size, and an optional sense buffer 285073050Smsmith * size/pointer. On completion, the data size is adjusted to the command 285173050Smsmith * residual, and the sense buffer size to the size of the returned sense data. 285273050Smsmith * 285373050Smsmith */ 285473050Smsmithstatic int 285573050Smsmithmly_user_command(struct mly_softc *sc, struct mly_user_command *uc) 285673050Smsmith{ 285779695Smsmith struct mly_command *mc; 285879695Smsmith int error, s; 285973050Smsmith 286073050Smsmith /* allocate a command */ 286173050Smsmith if (mly_alloc_command(sc, &mc)) { 286273050Smsmith error = ENOMEM; 286373050Smsmith goto out; /* XXX Linux version will wait for a command */ 286473050Smsmith } 286573050Smsmith 286673050Smsmith /* handle data size/direction */ 286773050Smsmith mc->mc_length = (uc->DataTransferLength >= 0) ? uc->DataTransferLength : -uc->DataTransferLength; 286873050Smsmith if (mc->mc_length > 0) { 286973050Smsmith if ((mc->mc_data = malloc(mc->mc_length, M_DEVBUF, M_NOWAIT)) == NULL) { 287073050Smsmith error = ENOMEM; 287173050Smsmith goto out; 287273050Smsmith } 287373050Smsmith } 287473050Smsmith if (uc->DataTransferLength > 0) { 287573050Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 287673050Smsmith bzero(mc->mc_data, mc->mc_length); 287773050Smsmith } 287873050Smsmith if (uc->DataTransferLength < 0) { 287973050Smsmith mc->mc_flags |= MLY_CMD_DATAOUT; 288073050Smsmith if ((error = copyin(uc->DataTransferBuffer, mc->mc_data, mc->mc_length)) != 0) 288173050Smsmith goto out; 288273050Smsmith } 288373050Smsmith 288473050Smsmith /* copy the controller command */ 288573050Smsmith bcopy(&uc->CommandMailbox, mc->mc_packet, sizeof(uc->CommandMailbox)); 288673050Smsmith 288773050Smsmith /* clear command completion handler so that we get woken up */ 288873050Smsmith mc->mc_complete = NULL; 288973050Smsmith 289073050Smsmith /* execute the command */ 289179695Smsmith if ((error = mly_start(mc)) != 0) 289279695Smsmith goto out; 289373050Smsmith s = splcam(); 289473050Smsmith while (!(mc->mc_flags & MLY_CMD_COMPLETE)) 289573050Smsmith tsleep(mc, PRIBIO, "mlyioctl", 0); 289673050Smsmith splx(s); 289773050Smsmith 289873050Smsmith /* return the data to userspace */ 289973050Smsmith if (uc->DataTransferLength > 0) 290073050Smsmith if ((error = copyout(mc->mc_data, uc->DataTransferBuffer, mc->mc_length)) != 0) 290173050Smsmith goto out; 290273050Smsmith 290373050Smsmith /* return the sense buffer to userspace */ 290473050Smsmith if ((uc->RequestSenseLength > 0) && (mc->mc_sense > 0)) { 290573050Smsmith if ((error = copyout(mc->mc_packet, uc->RequestSenseBuffer, 290673050Smsmith min(uc->RequestSenseLength, mc->mc_sense))) != 0) 290773050Smsmith goto out; 290873050Smsmith } 290973050Smsmith 291073050Smsmith /* return command results to userspace (caller will copy out) */ 291173050Smsmith uc->DataTransferLength = mc->mc_resid; 291273050Smsmith uc->RequestSenseLength = min(uc->RequestSenseLength, mc->mc_sense); 291373050Smsmith uc->CommandStatus = mc->mc_status; 291473050Smsmith error = 0; 291573050Smsmith 291673050Smsmith out: 291773050Smsmith if (mc->mc_data != NULL) 291873050Smsmith free(mc->mc_data, M_DEVBUF); 291973050Smsmith if (mc != NULL) 292073050Smsmith mly_release_command(mc); 292173050Smsmith return(error); 292273050Smsmith} 292373050Smsmith 292473050Smsmith/******************************************************************************** 292573050Smsmith * Return health status to userspace. If the health change index in the user 292673050Smsmith * structure does not match that currently exported by the controller, we 292773050Smsmith * return the current status immediately. Otherwise, we block until either 292873050Smsmith * interrupted or new status is delivered. 292973050Smsmith */ 293073050Smsmithstatic int 293173050Smsmithmly_user_health(struct mly_softc *sc, struct mly_user_health *uh) 293273050Smsmith{ 293373050Smsmith struct mly_health_status mh; 293473050Smsmith int error, s; 293573050Smsmith 293673050Smsmith /* fetch the current health status from userspace */ 293773050Smsmith if ((error = copyin(uh->HealthStatusBuffer, &mh, sizeof(mh))) != 0) 293873050Smsmith return(error); 293973050Smsmith 294073050Smsmith /* spin waiting for a status update */ 294173050Smsmith s = splcam(); 294273050Smsmith error = EWOULDBLOCK; 294373050Smsmith while ((error != 0) && (sc->mly_event_change == mh.change_counter)) 294473050Smsmith error = tsleep(&sc->mly_event_change, PRIBIO | PCATCH, "mlyhealth", 0); 294573050Smsmith splx(s); 294673050Smsmith 294773050Smsmith /* copy the controller's health status buffer out (there is a race here if it changes again) */ 294873050Smsmith error = copyout(&sc->mly_mmbox->mmm_health.status, uh->HealthStatusBuffer, 294973050Smsmith sizeof(uh->HealthStatusBuffer)); 295073050Smsmith return(error); 295173050Smsmith} 2952110479Sscottl 2953201795Strasz#ifdef MLY_DEBUG 2954110479Sscottlstatic int 2955110479Sscottlmly_timeout(struct mly_softc *sc) 2956110479Sscottl{ 2957110479Sscottl struct mly_command *mc; 2958110479Sscottl int deadline; 2959110479Sscottl 2960110479Sscottl deadline = time_second - MLY_CMD_TIMEOUT; 2961110479Sscottl TAILQ_FOREACH(mc, &sc->mly_busy, mc_link) { 2962110479Sscottl if ((mc->mc_timestamp < deadline)) { 2963110479Sscottl device_printf(sc->mly_dev, 2964110479Sscottl "COMMAND %p TIMEOUT AFTER %d SECONDS\n", mc, 2965110479Sscottl (int)(time_second - mc->mc_timestamp)); 2966110479Sscottl } 2967110479Sscottl } 2968110479Sscottl 2969110479Sscottl timeout((timeout_t *)mly_timeout, sc, MLY_CMD_TIMEOUT * hz); 2970110479Sscottl 2971110479Sscottl return (0); 2972110479Sscottl} 2973201795Strasz#endif 2974