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: releng/10.3/sys/dev/mly/mly.c 281826 2015-04-21 11:27:50Z mav $ 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 */ 386281826Smav BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 387281826Smav BUS_SPACE_UNRESTRICTED, /* nsegments */ 38879695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 38979695Smsmith BUS_DMA_ALLOCNOW, /* flags */ 390117126Sscottl NULL, /* lockfunc */ 391117126Sscottl NULL, /* lockarg */ 39279695Smsmith &sc->mly_parent_dmat)) { 39379695Smsmith mly_printf(sc, "can't allocate parent DMA tag\n"); 39479695Smsmith goto fail; 39579695Smsmith } 39679695Smsmith 39779695Smsmith /* 39879695Smsmith * Create DMA tag for mapping buffers into controller-addressable space. 39979695Smsmith */ 40079695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 40179695Smsmith 1, 0, /* alignment, boundary */ 40279695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 40379695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 40479695Smsmith NULL, NULL, /* filter, filterarg */ 405281826Smav DFLTPHYS, /* maxsize */ 406281826Smav MLY_MAX_SGENTRIES, /* nsegments */ 40779695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 40879695Smsmith 0, /* flags */ 409117126Sscottl busdma_lock_mutex, /* lockfunc */ 410117126Sscottl &Giant, /* lockarg */ 41179695Smsmith &sc->mly_buffer_dmat)) { 41279695Smsmith mly_printf(sc, "can't allocate buffer DMA tag\n"); 41379695Smsmith goto fail; 41479695Smsmith } 41579695Smsmith 41679695Smsmith /* 41779695Smsmith * Initialise the DMA tag for command packets. 41879695Smsmith */ 41979695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 42079695Smsmith 1, 0, /* alignment, boundary */ 42179695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 42279695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 42379695Smsmith NULL, NULL, /* filter, filterarg */ 42479695Smsmith sizeof(union mly_command_packet) * MLY_MAX_COMMANDS, 1, /* maxsize, nsegments */ 42579695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 426118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 427118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 42879695Smsmith &sc->mly_packet_dmat)) { 42979695Smsmith mly_printf(sc, "can't allocate command packet DMA tag\n"); 43079695Smsmith goto fail; 43179695Smsmith } 43279695Smsmith 43379695Smsmith /* 43479695Smsmith * Detect the hardware interface version 43579695Smsmith */ 43679695Smsmith for (i = 0; mly_identifiers[i].vendor != 0; i++) { 43779695Smsmith if ((mly_identifiers[i].vendor == pci_get_vendor(sc->mly_dev)) && 43879695Smsmith (mly_identifiers[i].device == pci_get_device(sc->mly_dev))) { 43979695Smsmith sc->mly_hwif = mly_identifiers[i].hwif; 44079695Smsmith switch(sc->mly_hwif) { 44179695Smsmith case MLY_HWIF_I960RX: 44279695Smsmith debug(1, "set hardware up for i960RX"); 44379695Smsmith sc->mly_doorbell_true = 0x00; 44479695Smsmith sc->mly_command_mailbox = MLY_I960RX_COMMAND_MAILBOX; 44579695Smsmith sc->mly_status_mailbox = MLY_I960RX_STATUS_MAILBOX; 44679695Smsmith sc->mly_idbr = MLY_I960RX_IDBR; 44779695Smsmith sc->mly_odbr = MLY_I960RX_ODBR; 44879695Smsmith sc->mly_error_status = MLY_I960RX_ERROR_STATUS; 44979695Smsmith sc->mly_interrupt_status = MLY_I960RX_INTERRUPT_STATUS; 45079695Smsmith sc->mly_interrupt_mask = MLY_I960RX_INTERRUPT_MASK; 45179695Smsmith break; 45279695Smsmith case MLY_HWIF_STRONGARM: 45379695Smsmith debug(1, "set hardware up for StrongARM"); 45479695Smsmith sc->mly_doorbell_true = 0xff; /* doorbell 'true' is 0 */ 45579695Smsmith sc->mly_command_mailbox = MLY_STRONGARM_COMMAND_MAILBOX; 45679695Smsmith sc->mly_status_mailbox = MLY_STRONGARM_STATUS_MAILBOX; 45779695Smsmith sc->mly_idbr = MLY_STRONGARM_IDBR; 45879695Smsmith sc->mly_odbr = MLY_STRONGARM_ODBR; 45979695Smsmith sc->mly_error_status = MLY_STRONGARM_ERROR_STATUS; 46079695Smsmith sc->mly_interrupt_status = MLY_STRONGARM_INTERRUPT_STATUS; 46179695Smsmith sc->mly_interrupt_mask = MLY_STRONGARM_INTERRUPT_MASK; 46279695Smsmith break; 46379695Smsmith } 46479695Smsmith break; 46579695Smsmith } 46679695Smsmith } 46779695Smsmith 46879695Smsmith /* 46979695Smsmith * Create the scatter/gather mappings. 47079695Smsmith */ 47179695Smsmith if ((error = mly_sg_map(sc))) 47279695Smsmith goto fail; 47379695Smsmith 47479695Smsmith /* 47579695Smsmith * Allocate and map the memory mailbox 47679695Smsmith */ 47779695Smsmith if ((error = mly_mmbox_map(sc))) 47879695Smsmith goto fail; 47979695Smsmith 48079695Smsmith error = 0; 48179695Smsmith 48279695Smsmithfail: 48379695Smsmith return(error); 48479695Smsmith} 48579695Smsmith 48679695Smsmith/******************************************************************************** 48779695Smsmith * Shut the controller down and detach all our resources. 48879695Smsmith */ 48979695Smsmithstatic int 49079695Smsmithmly_detach(device_t dev) 49179695Smsmith{ 49279695Smsmith int error; 49379695Smsmith 49479695Smsmith if ((error = mly_shutdown(dev)) != 0) 49579695Smsmith return(error); 49679695Smsmith 49779695Smsmith mly_free(device_get_softc(dev)); 49864987Smsmith return(0); 49964987Smsmith} 50064987Smsmith 50164987Smsmith/******************************************************************************** 50264987Smsmith * Bring the controller to a state where it can be safely left alone. 50379695Smsmith * 50479695Smsmith * Note that it should not be necessary to wait for any outstanding commands, 50579695Smsmith * as they should be completed prior to calling here. 50679695Smsmith * 50779695Smsmith * XXX this applies for I/O, but not status polls; we should beware of 50879695Smsmith * the case where a status command is running while we detach. 50964987Smsmith */ 51079695Smsmithstatic int 51179695Smsmithmly_shutdown(device_t dev) 51264987Smsmith{ 51379695Smsmith struct mly_softc *sc = device_get_softc(dev); 51464987Smsmith 51564987Smsmith debug_called(1); 51679695Smsmith 51779695Smsmith if (sc->mly_state & MLY_STATE_OPEN) 51879695Smsmith return(EBUSY); 51964987Smsmith 52064987Smsmith /* kill the periodic event */ 52164987Smsmith untimeout(mly_periodic, sc, sc->mly_periodic); 52264987Smsmith 52364987Smsmith /* flush controller */ 52464987Smsmith mly_printf(sc, "flushing cache..."); 52564987Smsmith printf("%s\n", mly_flush(sc) ? "failed" : "done"); 52664987Smsmith 52764987Smsmith MLY_MASK_INTERRUPTS(sc); 52879695Smsmith 52979695Smsmith return(0); 53064987Smsmith} 53164987Smsmith 53279695Smsmith/******************************************************************************* 53379695Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 53479695Smsmith * status. 53579695Smsmith */ 53679695Smsmithstatic void 53779695Smsmithmly_intr(void *arg) 53879695Smsmith{ 53979695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 54079695Smsmith 54179695Smsmith debug_called(2); 54279695Smsmith 54379695Smsmith mly_done(sc); 54479695Smsmith}; 54579695Smsmith 54664987Smsmith/******************************************************************************** 54764987Smsmith ******************************************************************************** 54879695Smsmith Bus-dependant Resource Management 54979695Smsmith ******************************************************************************** 55079695Smsmith ********************************************************************************/ 55179695Smsmith 55279695Smsmith/******************************************************************************** 55379695Smsmith * Allocate memory for the scatter/gather tables 55479695Smsmith */ 55579695Smsmithstatic int 55679695Smsmithmly_sg_map(struct mly_softc *sc) 55779695Smsmith{ 55879695Smsmith size_t segsize; 55979695Smsmith 56079695Smsmith debug_called(1); 56179695Smsmith 56279695Smsmith /* 56379695Smsmith * Create a single tag describing a region large enough to hold all of 56479695Smsmith * the s/g lists we will need. 56579695Smsmith */ 566118762Sscottl segsize = sizeof(struct mly_sg_entry) * MLY_MAX_COMMANDS *MLY_MAX_SGENTRIES; 56779695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 568118762Sscottl 1, 0, /* alignment,boundary */ 56979695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 57079695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 57179695Smsmith NULL, NULL, /* filter, filterarg */ 57279695Smsmith segsize, 1, /* maxsize, nsegments */ 57379695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 574118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 575118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 57679695Smsmith &sc->mly_sg_dmat)) { 57779695Smsmith mly_printf(sc, "can't allocate scatter/gather DMA tag\n"); 57879695Smsmith return(ENOMEM); 57979695Smsmith } 58079695Smsmith 58179695Smsmith /* 58279695Smsmith * Allocate enough s/g maps for all commands and permanently map them into 58379695Smsmith * controller-visible space. 58479695Smsmith * 58579695Smsmith * XXX this assumes we can get enough space for all the s/g maps in one 58679695Smsmith * contiguous slab. 58779695Smsmith */ 588118762Sscottl if (bus_dmamem_alloc(sc->mly_sg_dmat, (void **)&sc->mly_sg_table, 589118762Sscottl BUS_DMA_NOWAIT, &sc->mly_sg_dmamap)) { 59079695Smsmith mly_printf(sc, "can't allocate s/g table\n"); 59179695Smsmith return(ENOMEM); 59279695Smsmith } 593118762Sscottl if (bus_dmamap_load(sc->mly_sg_dmat, sc->mly_sg_dmamap, sc->mly_sg_table, 594118762Sscottl segsize, mly_sg_map_helper, sc, BUS_DMA_NOWAIT) != 0) 595118762Sscottl return (ENOMEM); 59679695Smsmith return(0); 59779695Smsmith} 59879695Smsmith 59979695Smsmith/******************************************************************************** 60079695Smsmith * Save the physical address of the base of the s/g table. 60179695Smsmith */ 60279695Smsmithstatic void 60379695Smsmithmly_sg_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 60479695Smsmith{ 60579695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 60679695Smsmith 60779695Smsmith debug_called(1); 60879695Smsmith 60979695Smsmith /* save base of s/g table's address in bus space */ 61079695Smsmith sc->mly_sg_busaddr = segs->ds_addr; 61179695Smsmith} 61279695Smsmith 61379695Smsmith/******************************************************************************** 61479695Smsmith * Allocate memory for the memory-mailbox interface 61579695Smsmith */ 61679695Smsmithstatic int 61779695Smsmithmly_mmbox_map(struct mly_softc *sc) 61879695Smsmith{ 61979695Smsmith 62079695Smsmith /* 62179695Smsmith * Create a DMA tag for a single contiguous region large enough for the 62279695Smsmith * memory mailbox structure. 62379695Smsmith */ 62479695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 625118762Sscottl 1, 0, /* alignment,boundary */ 62679695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 62779695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 62879695Smsmith NULL, NULL, /* filter, filterarg */ 62979695Smsmith sizeof(struct mly_mmbox), 1, /* maxsize, nsegments */ 63079695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 631118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 632118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 63379695Smsmith &sc->mly_mmbox_dmat)) { 63479695Smsmith mly_printf(sc, "can't allocate memory mailbox DMA tag\n"); 63579695Smsmith return(ENOMEM); 63679695Smsmith } 63779695Smsmith 63879695Smsmith /* 63979695Smsmith * Allocate the buffer 64079695Smsmith */ 64179695Smsmith if (bus_dmamem_alloc(sc->mly_mmbox_dmat, (void **)&sc->mly_mmbox, BUS_DMA_NOWAIT, &sc->mly_mmbox_dmamap)) { 64279695Smsmith mly_printf(sc, "can't allocate memory mailbox\n"); 64379695Smsmith return(ENOMEM); 64479695Smsmith } 645118762Sscottl if (bus_dmamap_load(sc->mly_mmbox_dmat, sc->mly_mmbox_dmamap, sc->mly_mmbox, 646118762Sscottl sizeof(struct mly_mmbox), mly_mmbox_map_helper, sc, 647118762Sscottl BUS_DMA_NOWAIT) != 0) 648118762Sscottl return (ENOMEM); 64979695Smsmith bzero(sc->mly_mmbox, sizeof(*sc->mly_mmbox)); 65079695Smsmith return(0); 65179695Smsmith 65279695Smsmith} 65379695Smsmith 65479695Smsmith/******************************************************************************** 65579695Smsmith * Save the physical address of the memory mailbox 65679695Smsmith */ 65779695Smsmithstatic void 65879695Smsmithmly_mmbox_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 65979695Smsmith{ 66079695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 66179695Smsmith 66279695Smsmith debug_called(1); 66379695Smsmith 66479695Smsmith sc->mly_mmbox_busaddr = segs->ds_addr; 66579695Smsmith} 66679695Smsmith 66779695Smsmith/******************************************************************************** 66879695Smsmith * Free all of the resources associated with (sc) 66979695Smsmith * 67079695Smsmith * Should not be called if the controller is active. 67179695Smsmith */ 672105215Sphkstatic void 67379695Smsmithmly_free(struct mly_softc *sc) 67479695Smsmith{ 67579695Smsmith 67679695Smsmith debug_called(1); 67779695Smsmith 678108926Sscottl /* Remove the management device */ 679108926Sscottl destroy_dev(sc->mly_dev_t); 680108926Sscottl 68179695Smsmith /* detach from CAM */ 68279695Smsmith mly_cam_detach(sc); 68379695Smsmith 68479695Smsmith /* release command memory */ 68579695Smsmith mly_release_commands(sc); 68679695Smsmith 68779695Smsmith /* throw away the controllerinfo structure */ 68879695Smsmith if (sc->mly_controllerinfo != NULL) 68979695Smsmith free(sc->mly_controllerinfo, M_DEVBUF); 69079695Smsmith 69179695Smsmith /* throw away the controllerparam structure */ 69279695Smsmith if (sc->mly_controllerparam != NULL) 69379695Smsmith free(sc->mly_controllerparam, M_DEVBUF); 69479695Smsmith 69579695Smsmith /* destroy data-transfer DMA tag */ 69679695Smsmith if (sc->mly_buffer_dmat) 69779695Smsmith bus_dma_tag_destroy(sc->mly_buffer_dmat); 69879695Smsmith 69979695Smsmith /* free and destroy DMA memory and tag for s/g lists */ 70079695Smsmith if (sc->mly_sg_table) { 70179695Smsmith bus_dmamap_unload(sc->mly_sg_dmat, sc->mly_sg_dmamap); 70279695Smsmith bus_dmamem_free(sc->mly_sg_dmat, sc->mly_sg_table, sc->mly_sg_dmamap); 70379695Smsmith } 70479695Smsmith if (sc->mly_sg_dmat) 70579695Smsmith bus_dma_tag_destroy(sc->mly_sg_dmat); 70679695Smsmith 70779695Smsmith /* free and destroy DMA memory and tag for memory mailbox */ 70879695Smsmith if (sc->mly_mmbox) { 70979695Smsmith bus_dmamap_unload(sc->mly_mmbox_dmat, sc->mly_mmbox_dmamap); 71079695Smsmith bus_dmamem_free(sc->mly_mmbox_dmat, sc->mly_mmbox, sc->mly_mmbox_dmamap); 71179695Smsmith } 71279695Smsmith if (sc->mly_mmbox_dmat) 71379695Smsmith bus_dma_tag_destroy(sc->mly_mmbox_dmat); 71479695Smsmith 71579695Smsmith /* disconnect the interrupt handler */ 71679695Smsmith if (sc->mly_intr) 71779695Smsmith bus_teardown_intr(sc->mly_dev, sc->mly_irq, sc->mly_intr); 71879695Smsmith if (sc->mly_irq != NULL) 71979695Smsmith bus_release_resource(sc->mly_dev, SYS_RES_IRQ, sc->mly_irq_rid, sc->mly_irq); 72079695Smsmith 72179695Smsmith /* destroy the parent DMA tag */ 72279695Smsmith if (sc->mly_parent_dmat) 72379695Smsmith bus_dma_tag_destroy(sc->mly_parent_dmat); 72479695Smsmith 72579695Smsmith /* release the register window mapping */ 72679695Smsmith if (sc->mly_regs_resource != NULL) 72779695Smsmith bus_release_resource(sc->mly_dev, SYS_RES_MEMORY, sc->mly_regs_rid, sc->mly_regs_resource); 72879695Smsmith} 72979695Smsmith 73079695Smsmith/******************************************************************************** 73179695Smsmith ******************************************************************************** 73264987Smsmith Command Wrappers 73364987Smsmith ******************************************************************************** 73464987Smsmith ********************************************************************************/ 73564987Smsmith 73664987Smsmith/******************************************************************************** 73764987Smsmith * Fill in the mly_controllerinfo and mly_controllerparam fields in the softc. 73864987Smsmith */ 73964987Smsmithstatic int 74064987Smsmithmly_get_controllerinfo(struct mly_softc *sc) 74164987Smsmith{ 74264987Smsmith struct mly_command_ioctl mci; 74364987Smsmith u_int8_t status; 74464987Smsmith int error; 74564987Smsmith 74664987Smsmith debug_called(1); 74764987Smsmith 74864987Smsmith if (sc->mly_controllerinfo != NULL) 74964987Smsmith free(sc->mly_controllerinfo, M_DEVBUF); 75064987Smsmith 75164987Smsmith /* build the getcontrollerinfo ioctl and send it */ 75264987Smsmith bzero(&mci, sizeof(mci)); 75364987Smsmith sc->mly_controllerinfo = NULL; 75464987Smsmith mci.sub_ioctl = MDACIOCTL_GETCONTROLLERINFO; 75564987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerinfo, sizeof(*sc->mly_controllerinfo), 75664987Smsmith &status, NULL, NULL))) 75764987Smsmith return(error); 75864987Smsmith if (status != 0) 75964987Smsmith return(EIO); 76064987Smsmith 76164987Smsmith if (sc->mly_controllerparam != NULL) 76264987Smsmith free(sc->mly_controllerparam, M_DEVBUF); 76364987Smsmith 76464987Smsmith /* build the getcontrollerparameter ioctl and send it */ 76564987Smsmith bzero(&mci, sizeof(mci)); 76664987Smsmith sc->mly_controllerparam = NULL; 76764987Smsmith mci.sub_ioctl = MDACIOCTL_GETCONTROLLERPARAMETER; 76864987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerparam, sizeof(*sc->mly_controllerparam), 76964987Smsmith &status, NULL, NULL))) 77064987Smsmith return(error); 77164987Smsmith if (status != 0) 77264987Smsmith return(EIO); 77364987Smsmith 77464987Smsmith return(0); 77564987Smsmith} 77664987Smsmith 77764987Smsmith/******************************************************************************** 77864987Smsmith * Schedule all possible devices for a rescan. 77964987Smsmith * 78064987Smsmith */ 78164987Smsmithstatic void 78264987Smsmithmly_scan_devices(struct mly_softc *sc) 78364987Smsmith{ 78479695Smsmith int bus, target; 78564987Smsmith 78664987Smsmith debug_called(1); 78764987Smsmith 78864987Smsmith /* 78964987Smsmith * Clear any previous BTL information. 79064987Smsmith */ 79164987Smsmith bzero(&sc->mly_btl, sizeof(sc->mly_btl)); 79264987Smsmith 79364987Smsmith /* 79479695Smsmith * Mark all devices as requiring a rescan, and let the next 79579695Smsmith * periodic scan collect them. 79664987Smsmith */ 79779695Smsmith for (bus = 0; bus < sc->mly_cam_channels; bus++) 79879695Smsmith if (MLY_BUS_IS_VALID(sc, bus)) 79979695Smsmith for (target = 0; target < MLY_MAX_TARGETS; target++) 80079695Smsmith sc->mly_btl[bus][target].mb_flags = MLY_BTL_RESCAN; 80164987Smsmith 80264987Smsmith} 80364987Smsmith 80464987Smsmith/******************************************************************************** 80564987Smsmith * Rescan a device, possibly as a consequence of getting an event which suggests 80664987Smsmith * that it may have changed. 80779695Smsmith * 80879695Smsmith * If we suffer resource starvation, we can abandon the rescan as we'll be 80979695Smsmith * retried. 81064987Smsmith */ 81164987Smsmithstatic void 81264987Smsmithmly_rescan_btl(struct mly_softc *sc, int bus, int target) 81364987Smsmith{ 81464987Smsmith struct mly_command *mc; 81564987Smsmith struct mly_command_ioctl *mci; 81664987Smsmith 81779695Smsmith debug_called(1); 81864987Smsmith 81979695Smsmith /* check that this bus is valid */ 82079695Smsmith if (!MLY_BUS_IS_VALID(sc, bus)) 82179695Smsmith return; 82279695Smsmith 82364987Smsmith /* get a command */ 82464987Smsmith if (mly_alloc_command(sc, &mc)) 82579695Smsmith return; 82664987Smsmith 82764987Smsmith /* set up the data buffer */ 82868877Sdwmalone if ((mc->mc_data = malloc(sizeof(union mly_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 82964987Smsmith mly_release_command(mc); 83079695Smsmith return; 83164987Smsmith } 83264987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 83364987Smsmith mc->mc_complete = mly_complete_rescan; 83464987Smsmith 83564987Smsmith /* 83664987Smsmith * Build the ioctl. 83764987Smsmith */ 83864987Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 83964987Smsmith mci->opcode = MDACMD_IOCTL; 84064987Smsmith mci->addr.phys.controller = 0; 84164987Smsmith mci->timeout.value = 30; 84264987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 84385324Smsmith if (MLY_BUS_IS_VIRTUAL(sc, bus)) { 84464987Smsmith mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getlogdevinfovalid); 84564987Smsmith mci->sub_ioctl = MDACIOCTL_GETLOGDEVINFOVALID; 84679695Smsmith mci->addr.log.logdev = MLY_LOGDEV_ID(sc, bus, target); 84779695Smsmith debug(1, "logical device %d", mci->addr.log.logdev); 84864987Smsmith } else { 84964987Smsmith mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getphysdevinfovalid); 85064987Smsmith mci->sub_ioctl = MDACIOCTL_GETPHYSDEVINFOVALID; 85164987Smsmith mci->addr.phys.lun = 0; 85264987Smsmith mci->addr.phys.target = target; 85364987Smsmith mci->addr.phys.channel = bus; 85479695Smsmith debug(1, "physical device %d:%d", mci->addr.phys.channel, mci->addr.phys.target); 85564987Smsmith } 85664987Smsmith 85764987Smsmith /* 85879695Smsmith * Dispatch the command. If we successfully send the command, clear the rescan 85979695Smsmith * bit. 86064987Smsmith */ 86179695Smsmith if (mly_start(mc) != 0) { 86279695Smsmith mly_release_command(mc); 86379695Smsmith } else { 86479695Smsmith sc->mly_btl[bus][target].mb_flags &= ~MLY_BTL_RESCAN; /* success */ 86579695Smsmith } 86664987Smsmith} 86764987Smsmith 86864987Smsmith/******************************************************************************** 86964987Smsmith * Handle the completion of a rescan operation 87064987Smsmith */ 87164987Smsmithstatic void 87264987Smsmithmly_complete_rescan(struct mly_command *mc) 87364987Smsmith{ 87464987Smsmith struct mly_softc *sc = mc->mc_sc; 87564987Smsmith struct mly_ioctl_getlogdevinfovalid *ldi; 87664987Smsmith struct mly_ioctl_getphysdevinfovalid *pdi; 87779695Smsmith struct mly_command_ioctl *mci; 87879695Smsmith struct mly_btl btl, *btlp; 87979695Smsmith int bus, target, rescan; 88064987Smsmith 88179695Smsmith debug_called(1); 88264987Smsmith 88379695Smsmith /* 88479695Smsmith * Recover the bus and target from the command. We need these even in 88579695Smsmith * the case where we don't have a useful response. 88679695Smsmith */ 88779695Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 88879695Smsmith if (mci->sub_ioctl == MDACIOCTL_GETLOGDEVINFOVALID) { 88979695Smsmith bus = MLY_LOGDEV_BUS(sc, mci->addr.log.logdev); 89079695Smsmith target = MLY_LOGDEV_TARGET(sc, mci->addr.log.logdev); 89179695Smsmith } else { 89279695Smsmith bus = mci->addr.phys.channel; 89379695Smsmith target = mci->addr.phys.target; 89479695Smsmith } 89579695Smsmith /* XXX validate bus/target? */ 89679695Smsmith 89779695Smsmith /* the default result is 'no device' */ 89879695Smsmith bzero(&btl, sizeof(btl)); 89979695Smsmith 90079695Smsmith /* if the rescan completed OK, we have possibly-new BTL data */ 90164987Smsmith if (mc->mc_status == 0) { 90264987Smsmith if (mc->mc_length == sizeof(*ldi)) { 90364987Smsmith ldi = (struct mly_ioctl_getlogdevinfovalid *)mc->mc_data; 90479695Smsmith if ((MLY_LOGDEV_BUS(sc, ldi->logical_device_number) != bus) || 90579695Smsmith (MLY_LOGDEV_TARGET(sc, ldi->logical_device_number) != target)) { 90679695Smsmith mly_printf(sc, "WARNING: BTL rescan for %d:%d returned data for %d:%d instead\n", 90779695Smsmith bus, target, MLY_LOGDEV_BUS(sc, ldi->logical_device_number), 90879695Smsmith MLY_LOGDEV_TARGET(sc, ldi->logical_device_number)); 90979695Smsmith /* XXX what can we do about this? */ 91079695Smsmith } 91179695Smsmith btl.mb_flags = MLY_BTL_LOGICAL; 91279695Smsmith btl.mb_type = ldi->raid_level; 91379695Smsmith btl.mb_state = ldi->state; 91479695Smsmith debug(1, "BTL rescan for %d returns %s, %s", ldi->logical_device_number, 91564987Smsmith mly_describe_code(mly_table_device_type, ldi->raid_level), 91664987Smsmith mly_describe_code(mly_table_device_state, ldi->state)); 91764987Smsmith } else if (mc->mc_length == sizeof(*pdi)) { 91864987Smsmith pdi = (struct mly_ioctl_getphysdevinfovalid *)mc->mc_data; 91979695Smsmith if ((pdi->channel != bus) || (pdi->target != target)) { 92079695Smsmith mly_printf(sc, "WARNING: BTL rescan for %d:%d returned data for %d:%d instead\n", 92179695Smsmith bus, target, pdi->channel, pdi->target); 92279695Smsmith /* XXX what can we do about this? */ 92379695Smsmith } 92479695Smsmith btl.mb_flags = MLY_BTL_PHYSICAL; 92579695Smsmith btl.mb_type = MLY_DEVICE_TYPE_PHYSICAL; 92679695Smsmith btl.mb_state = pdi->state; 92779695Smsmith btl.mb_speed = pdi->speed; 92879695Smsmith btl.mb_width = pdi->width; 92964987Smsmith if (pdi->state != MLY_DEVICE_STATE_UNCONFIGURED) 93064987Smsmith sc->mly_btl[bus][target].mb_flags |= MLY_BTL_PROTECTED; 93179695Smsmith debug(1, "BTL rescan for %d:%d returns %s", bus, target, 93264987Smsmith mly_describe_code(mly_table_device_state, pdi->state)); 93364987Smsmith } else { 93479695Smsmith mly_printf(sc, "BTL rescan result invalid\n"); 93564987Smsmith } 93664987Smsmith } 93779695Smsmith 93864987Smsmith free(mc->mc_data, M_DEVBUF); 93964987Smsmith mly_release_command(mc); 94079695Smsmith 94179695Smsmith /* 94279695Smsmith * Decide whether we need to rescan the device. 94379695Smsmith */ 94479695Smsmith rescan = 0; 94579695Smsmith 94679695Smsmith /* device type changes (usually between 'nothing' and 'something') */ 94779695Smsmith btlp = &sc->mly_btl[bus][target]; 94879695Smsmith if (btl.mb_flags != btlp->mb_flags) { 94979695Smsmith debug(1, "flags changed, rescanning"); 95079695Smsmith rescan = 1; 95179695Smsmith } 95279695Smsmith 95379695Smsmith /* XXX other reasons? */ 95479695Smsmith 95579695Smsmith /* 95679695Smsmith * Update BTL information. 95779695Smsmith */ 95879695Smsmith *btlp = btl; 95979695Smsmith 96079695Smsmith /* 96179695Smsmith * Perform CAM rescan if required. 96279695Smsmith */ 96379695Smsmith if (rescan) 96479695Smsmith mly_cam_rescan_btl(sc, bus, target); 96564987Smsmith} 96664987Smsmith 96764987Smsmith/******************************************************************************** 96864987Smsmith * Get the current health status and set the 'next event' counter to suit. 96964987Smsmith */ 97064987Smsmithstatic int 97164987Smsmithmly_get_eventstatus(struct mly_softc *sc) 97264987Smsmith{ 97364987Smsmith struct mly_command_ioctl mci; 97464987Smsmith struct mly_health_status *mh; 97564987Smsmith u_int8_t status; 97664987Smsmith int error; 97764987Smsmith 97864987Smsmith /* build the gethealthstatus ioctl and send it */ 97964987Smsmith bzero(&mci, sizeof(mci)); 98064987Smsmith mh = NULL; 98164987Smsmith mci.sub_ioctl = MDACIOCTL_GETHEALTHSTATUS; 98264987Smsmith 98364987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&mh, sizeof(*mh), &status, NULL, NULL))) 98464987Smsmith return(error); 98564987Smsmith if (status != 0) 98664987Smsmith return(EIO); 98764987Smsmith 98864987Smsmith /* get the event counter */ 98964987Smsmith sc->mly_event_change = mh->change_counter; 99064987Smsmith sc->mly_event_waiting = mh->next_event; 99164987Smsmith sc->mly_event_counter = mh->next_event; 99264987Smsmith 99364987Smsmith /* save the health status into the memory mailbox */ 99464987Smsmith bcopy(mh, &sc->mly_mmbox->mmm_health.status, sizeof(*mh)); 99564987Smsmith 99664987Smsmith debug(1, "initial change counter %d, event counter %d", mh->change_counter, mh->next_event); 99764987Smsmith 99864987Smsmith free(mh, M_DEVBUF); 99964987Smsmith return(0); 100064987Smsmith} 100164987Smsmith 100264987Smsmith/******************************************************************************** 100364987Smsmith * Enable the memory mailbox mode. 100464987Smsmith */ 100564987Smsmithstatic int 100664987Smsmithmly_enable_mmbox(struct mly_softc *sc) 100764987Smsmith{ 100864987Smsmith struct mly_command_ioctl mci; 100964987Smsmith u_int8_t *sp, status; 101064987Smsmith int error; 101164987Smsmith 101264987Smsmith debug_called(1); 101364987Smsmith 101464987Smsmith /* build the ioctl and send it */ 101564987Smsmith bzero(&mci, sizeof(mci)); 101664987Smsmith mci.sub_ioctl = MDACIOCTL_SETMEMORYMAILBOX; 101764987Smsmith /* set buffer addresses */ 101873050Smsmith mci.param.setmemorymailbox.command_mailbox_physaddr = 101973050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_command); 102073050Smsmith mci.param.setmemorymailbox.status_mailbox_physaddr = 102173050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_status); 102273050Smsmith mci.param.setmemorymailbox.health_buffer_physaddr = 102373050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_health); 102464987Smsmith 102564987Smsmith /* set buffer sizes - abuse of data_size field is revolting */ 102664987Smsmith sp = (u_int8_t *)&mci.data_size; 102764987Smsmith sp[0] = ((sizeof(union mly_command_packet) * MLY_MMBOX_COMMANDS) / 1024); 102864987Smsmith sp[1] = (sizeof(union mly_status_packet) * MLY_MMBOX_STATUS) / 1024; 102964987Smsmith mci.param.setmemorymailbox.health_buffer_size = sizeof(union mly_health_region) / 1024; 103064987Smsmith 103164987Smsmith debug(1, "memory mailbox at %p (0x%llx/%d 0x%llx/%d 0x%llx/%d", sc->mly_mmbox, 103264987Smsmith mci.param.setmemorymailbox.command_mailbox_physaddr, sp[0], 103364987Smsmith mci.param.setmemorymailbox.status_mailbox_physaddr, sp[1], 103473050Smsmith mci.param.setmemorymailbox.health_buffer_physaddr, 103573050Smsmith mci.param.setmemorymailbox.health_buffer_size); 103664987Smsmith 103764987Smsmith if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) 103864987Smsmith return(error); 103964987Smsmith if (status != 0) 104064987Smsmith return(EIO); 104164987Smsmith sc->mly_state |= MLY_STATE_MMBOX_ACTIVE; 104264987Smsmith debug(1, "memory mailbox active"); 104364987Smsmith return(0); 104464987Smsmith} 104564987Smsmith 104664987Smsmith/******************************************************************************** 104764987Smsmith * Flush all pending I/O from the controller. 104864987Smsmith */ 104964987Smsmithstatic int 105064987Smsmithmly_flush(struct mly_softc *sc) 105164987Smsmith{ 105264987Smsmith struct mly_command_ioctl mci; 105364987Smsmith u_int8_t status; 105464987Smsmith int error; 105564987Smsmith 105664987Smsmith debug_called(1); 105764987Smsmith 105864987Smsmith /* build the ioctl */ 105964987Smsmith bzero(&mci, sizeof(mci)); 106064987Smsmith mci.sub_ioctl = MDACIOCTL_FLUSHDEVICEDATA; 106164987Smsmith mci.param.deviceoperation.operation_device = MLY_OPDEVICE_PHYSICAL_CONTROLLER; 106264987Smsmith 106364987Smsmith /* pass it off to the controller */ 106464987Smsmith if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) 106564987Smsmith return(error); 106664987Smsmith 106764987Smsmith return((status == 0) ? 0 : EIO); 106864987Smsmith} 106964987Smsmith 107064987Smsmith/******************************************************************************** 107164987Smsmith * Perform an ioctl command. 107264987Smsmith * 107364987Smsmith * If (data) is not NULL, the command requires data transfer. If (*data) is NULL 107464987Smsmith * the command requires data transfer from the controller, and we will allocate 107564987Smsmith * a buffer for it. If (*data) is not NULL, the command requires data transfer 107664987Smsmith * to the controller. 107764987Smsmith * 107864987Smsmith * XXX passing in the whole ioctl structure is ugly. Better ideas? 107964987Smsmith * 108064987Smsmith * XXX we don't even try to handle the case where datasize > 4k. We should. 108164987Smsmith */ 108264987Smsmithstatic int 108364987Smsmithmly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, size_t datasize, 108464987Smsmith u_int8_t *status, void *sense_buffer, size_t *sense_length) 108564987Smsmith{ 108664987Smsmith struct mly_command *mc; 108764987Smsmith struct mly_command_ioctl *mci; 108864987Smsmith int error; 108964987Smsmith 109064987Smsmith debug_called(1); 109164987Smsmith 109264987Smsmith mc = NULL; 109364987Smsmith if (mly_alloc_command(sc, &mc)) { 109464987Smsmith error = ENOMEM; 109564987Smsmith goto out; 109664987Smsmith } 109764987Smsmith 109864987Smsmith /* copy the ioctl structure, but save some important fields and then fixup */ 109964987Smsmith mci = &mc->mc_packet->ioctl; 110064987Smsmith ioctl->sense_buffer_address = mci->sense_buffer_address; 110164987Smsmith ioctl->maximum_sense_size = mci->maximum_sense_size; 110264987Smsmith *mci = *ioctl; 110364987Smsmith mci->opcode = MDACMD_IOCTL; 110464987Smsmith mci->timeout.value = 30; 110564987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 110664987Smsmith 110764987Smsmith /* handle the data buffer */ 110864987Smsmith if (data != NULL) { 110964987Smsmith if (*data == NULL) { 111064987Smsmith /* allocate data buffer */ 111164987Smsmith if ((mc->mc_data = malloc(datasize, M_DEVBUF, M_NOWAIT)) == NULL) { 111264987Smsmith error = ENOMEM; 111364987Smsmith goto out; 111464987Smsmith } 111564987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 111664987Smsmith } else { 111764987Smsmith mc->mc_data = *data; 111864987Smsmith mc->mc_flags |= MLY_CMD_DATAOUT; 111964987Smsmith } 112064987Smsmith mc->mc_length = datasize; 112164987Smsmith mc->mc_packet->generic.data_size = datasize; 112264987Smsmith } 112364987Smsmith 112464987Smsmith /* run the command */ 112564987Smsmith if ((error = mly_immediate_command(mc))) 112664987Smsmith goto out; 112764987Smsmith 112864987Smsmith /* clean up and return any data */ 112964987Smsmith *status = mc->mc_status; 113064987Smsmith if ((mc->mc_sense > 0) && (sense_buffer != NULL)) { 113164987Smsmith bcopy(mc->mc_packet, sense_buffer, mc->mc_sense); 113264987Smsmith *sense_length = mc->mc_sense; 113364987Smsmith goto out; 113464987Smsmith } 113564987Smsmith 113664987Smsmith /* should we return a data pointer? */ 113764987Smsmith if ((data != NULL) && (*data == NULL)) 113864987Smsmith *data = mc->mc_data; 113964987Smsmith 114064987Smsmith /* command completed OK */ 114164987Smsmith error = 0; 114264987Smsmith 114364987Smsmithout: 114464987Smsmith if (mc != NULL) { 114564987Smsmith /* do we need to free a data buffer we allocated? */ 114664987Smsmith if (error && (mc->mc_data != NULL) && (*data == NULL)) 114764987Smsmith free(mc->mc_data, M_DEVBUF); 114864987Smsmith mly_release_command(mc); 114964987Smsmith } 115064987Smsmith return(error); 115164987Smsmith} 115264987Smsmith 115364987Smsmith/******************************************************************************** 115479695Smsmith * Check for event(s) outstanding in the controller. 115579695Smsmith */ 115679695Smsmithstatic void 115779695Smsmithmly_check_event(struct mly_softc *sc) 115879695Smsmith{ 115979695Smsmith 116079695Smsmith /* 116179695Smsmith * The controller may have updated the health status information, 116279695Smsmith * so check for it here. Note that the counters are all in host memory, 116379695Smsmith * so this check is very cheap. Also note that we depend on checking on 116479695Smsmith * completion 116579695Smsmith */ 116679695Smsmith if (sc->mly_mmbox->mmm_health.status.change_counter != sc->mly_event_change) { 116779695Smsmith sc->mly_event_change = sc->mly_mmbox->mmm_health.status.change_counter; 116879695Smsmith debug(1, "event change %d, event status update, %d -> %d", sc->mly_event_change, 116979695Smsmith sc->mly_event_waiting, sc->mly_mmbox->mmm_health.status.next_event); 117079695Smsmith sc->mly_event_waiting = sc->mly_mmbox->mmm_health.status.next_event; 117179695Smsmith 117279695Smsmith /* wake up anyone that might be interested in this */ 117379695Smsmith wakeup(&sc->mly_event_change); 117479695Smsmith } 117579695Smsmith if (sc->mly_event_counter != sc->mly_event_waiting) 117679695Smsmith mly_fetch_event(sc); 117779695Smsmith} 117879695Smsmith 117979695Smsmith/******************************************************************************** 118064987Smsmith * Fetch one event from the controller. 118179695Smsmith * 118279695Smsmith * If we fail due to resource starvation, we'll be retried the next time a 118379695Smsmith * command completes. 118464987Smsmith */ 118564987Smsmithstatic void 118664987Smsmithmly_fetch_event(struct mly_softc *sc) 118764987Smsmith{ 118864987Smsmith struct mly_command *mc; 118964987Smsmith struct mly_command_ioctl *mci; 119064987Smsmith int s; 119164987Smsmith u_int32_t event; 119264987Smsmith 119379695Smsmith debug_called(1); 119464987Smsmith 119564987Smsmith /* get a command */ 119664987Smsmith if (mly_alloc_command(sc, &mc)) 119779695Smsmith return; 119864987Smsmith 119964987Smsmith /* set up the data buffer */ 120068877Sdwmalone if ((mc->mc_data = malloc(sizeof(struct mly_event), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 120164987Smsmith mly_release_command(mc); 120279695Smsmith return; 120364987Smsmith } 120464987Smsmith mc->mc_length = sizeof(struct mly_event); 120564987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 120664987Smsmith mc->mc_complete = mly_complete_event; 120764987Smsmith 120864987Smsmith /* 120964987Smsmith * Get an event number to fetch. It's possible that we've raced with another 121064987Smsmith * context for the last event, in which case there will be no more events. 121164987Smsmith */ 121264987Smsmith s = splcam(); 121364987Smsmith if (sc->mly_event_counter == sc->mly_event_waiting) { 121464987Smsmith mly_release_command(mc); 121564987Smsmith splx(s); 121664987Smsmith return; 121764987Smsmith } 121864987Smsmith event = sc->mly_event_counter++; 121964987Smsmith splx(s); 122064987Smsmith 122164987Smsmith /* 122264987Smsmith * Build the ioctl. 122364987Smsmith * 122464987Smsmith * At this point we are committed to sending this request, as it 122564987Smsmith * will be the only one constructed for this particular event number. 122664987Smsmith */ 122764987Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 122864987Smsmith mci->opcode = MDACMD_IOCTL; 122964987Smsmith mci->data_size = sizeof(struct mly_event); 123064987Smsmith mci->addr.phys.lun = (event >> 16) & 0xff; 123164987Smsmith mci->addr.phys.target = (event >> 24) & 0xff; 123264987Smsmith mci->addr.phys.channel = 0; 123364987Smsmith mci->addr.phys.controller = 0; 123464987Smsmith mci->timeout.value = 30; 123564987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 123664987Smsmith mci->sub_ioctl = MDACIOCTL_GETEVENT; 123764987Smsmith mci->param.getevent.sequence_number_low = event & 0xffff; 123864987Smsmith 123979695Smsmith debug(1, "fetch event %u", event); 124064987Smsmith 124164987Smsmith /* 124279695Smsmith * Submit the command. 124379695Smsmith * 124479695Smsmith * Note that failure of mly_start() will result in this event never being 124579695Smsmith * fetched. 124664987Smsmith */ 124779695Smsmith if (mly_start(mc) != 0) { 124879695Smsmith mly_printf(sc, "couldn't fetch event %u\n", event); 124979695Smsmith mly_release_command(mc); 125079695Smsmith } 125164987Smsmith} 125264987Smsmith 125364987Smsmith/******************************************************************************** 125464987Smsmith * Handle the completion of an event poll. 125564987Smsmith */ 125664987Smsmithstatic void 125764987Smsmithmly_complete_event(struct mly_command *mc) 125864987Smsmith{ 125964987Smsmith struct mly_softc *sc = mc->mc_sc; 126064987Smsmith struct mly_event *me = (struct mly_event *)mc->mc_data; 126164987Smsmith 126279695Smsmith debug_called(1); 126364987Smsmith 126464987Smsmith /* 126564987Smsmith * If the event was successfully fetched, process it. 126664987Smsmith */ 126764987Smsmith if (mc->mc_status == SCSI_STATUS_OK) { 126864987Smsmith mly_process_event(sc, me); 126964987Smsmith free(me, M_DEVBUF); 127064987Smsmith } 127164987Smsmith mly_release_command(mc); 127279695Smsmith 127379695Smsmith /* 127479695Smsmith * Check for another event. 127579695Smsmith */ 127679695Smsmith mly_check_event(sc); 127764987Smsmith} 127864987Smsmith 127964987Smsmith/******************************************************************************** 128064987Smsmith * Process a controller event. 128164987Smsmith */ 128264987Smsmithstatic void 128364987Smsmithmly_process_event(struct mly_softc *sc, struct mly_event *me) 128464987Smsmith{ 1285225950Sken struct scsi_sense_data_fixed *ssd; 1286225950Sken char *fp, *tp; 1287225950Sken int bus, target, event, class, action; 128864987Smsmith 1289225950Sken ssd = (struct scsi_sense_data_fixed *)&me->sense[0]; 1290225950Sken 129164987Smsmith /* 129264987Smsmith * Errors can be reported using vendor-unique sense data. In this case, the 129364987Smsmith * event code will be 0x1c (Request sense data present), the sense key will 129464987Smsmith * be 0x09 (vendor specific), the MSB of the ASC will be set, and the 129564987Smsmith * actual event code will be a 16-bit value comprised of the ASCQ (low byte) 129664987Smsmith * and low seven bits of the ASC (low seven bits of the high byte). 129764987Smsmith */ 129864987Smsmith if ((me->code == 0x1c) && 129964987Smsmith ((ssd->flags & SSD_KEY) == SSD_KEY_Vendor_Specific) && 130064987Smsmith (ssd->add_sense_code & 0x80)) { 130164987Smsmith event = ((int)(ssd->add_sense_code & ~0x80) << 8) + ssd->add_sense_code_qual; 130264987Smsmith } else { 130364987Smsmith event = me->code; 130464987Smsmith } 130564987Smsmith 130664987Smsmith /* look up event, get codes */ 130764987Smsmith fp = mly_describe_code(mly_table_event, event); 130864987Smsmith 130979695Smsmith debug(1, "Event %d code 0x%x", me->sequence_number, me->code); 131064987Smsmith 131164987Smsmith /* quiet event? */ 131264987Smsmith class = fp[0]; 131364987Smsmith if (isupper(class) && bootverbose) 131464987Smsmith class = tolower(class); 131564987Smsmith 131664987Smsmith /* get action code, text string */ 131764987Smsmith action = fp[1]; 131864987Smsmith tp = &fp[2]; 131964987Smsmith 132064987Smsmith /* 132164987Smsmith * Print some information about the event. 132264987Smsmith * 132364987Smsmith * This code uses a table derived from the corresponding portion of the Linux 132464987Smsmith * driver, and thus the parser is very similar. 132564987Smsmith */ 132664987Smsmith switch(class) { 132764987Smsmith case 'p': /* error on physical device */ 132864987Smsmith mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); 132964987Smsmith if (action == 'r') 133064987Smsmith sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; 133164987Smsmith break; 133264987Smsmith case 'l': /* error on logical unit */ 133364987Smsmith case 'm': /* message about logical unit */ 133464987Smsmith bus = MLY_LOGDEV_BUS(sc, me->lun); 133579695Smsmith target = MLY_LOGDEV_TARGET(sc, me->lun); 133664987Smsmith mly_name_device(sc, bus, target); 133764987Smsmith mly_printf(sc, "logical device %d (%s) %s\n", me->lun, sc->mly_btl[bus][target].mb_name, tp); 133864987Smsmith if (action == 'r') 133964987Smsmith sc->mly_btl[bus][target].mb_flags |= MLY_BTL_RESCAN; 134064987Smsmith break; 134164987Smsmith case 's': /* report of sense data */ 134264987Smsmith if (((ssd->flags & SSD_KEY) == SSD_KEY_NO_SENSE) || 134364987Smsmith (((ssd->flags & SSD_KEY) == SSD_KEY_NOT_READY) && 134464987Smsmith (ssd->add_sense_code == 0x04) && 134564987Smsmith ((ssd->add_sense_code_qual == 0x01) || (ssd->add_sense_code_qual == 0x02)))) 134664987Smsmith break; /* ignore NO_SENSE or NOT_READY in one case */ 134764987Smsmith 134864987Smsmith mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); 134964987Smsmith mly_printf(sc, " sense key %d asc %02x ascq %02x\n", 135064987Smsmith ssd->flags & SSD_KEY, ssd->add_sense_code, ssd->add_sense_code_qual); 135164987Smsmith mly_printf(sc, " info %4D csi %4D\n", ssd->info, "", ssd->cmd_spec_info, ""); 135264987Smsmith if (action == 'r') 135364987Smsmith sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; 135464987Smsmith break; 135564987Smsmith case 'e': 135664987Smsmith mly_printf(sc, tp, me->target, me->lun); 1357110680Salfred printf("\n"); 135864987Smsmith break; 135964987Smsmith case 'c': 136064987Smsmith mly_printf(sc, "controller %s\n", tp); 136164987Smsmith break; 136264987Smsmith case '?': 136364987Smsmith mly_printf(sc, "%s - %d\n", tp, me->code); 136464987Smsmith break; 136564987Smsmith default: /* probably a 'noisy' event being ignored */ 136664987Smsmith break; 136764987Smsmith } 136864987Smsmith} 136964987Smsmith 137064987Smsmith/******************************************************************************** 137164987Smsmith * Perform periodic activities. 137264987Smsmith */ 137364987Smsmithstatic void 137464987Smsmithmly_periodic(void *data) 137564987Smsmith{ 137664987Smsmith struct mly_softc *sc = (struct mly_softc *)data; 137779695Smsmith int bus, target; 137864987Smsmith 137964987Smsmith debug_called(2); 138064987Smsmith 138164987Smsmith /* 138264987Smsmith * Scan devices. 138364987Smsmith */ 138479695Smsmith for (bus = 0; bus < sc->mly_cam_channels; bus++) { 138579695Smsmith if (MLY_BUS_IS_VALID(sc, bus)) { 138679695Smsmith for (target = 0; target < MLY_MAX_TARGETS; target++) { 138764987Smsmith 138879695Smsmith /* ignore the controller in this scan */ 138979695Smsmith if (target == sc->mly_controllerparam->initiator_id) 139079695Smsmith continue; 139164987Smsmith 139279695Smsmith /* perform device rescan? */ 139379695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_RESCAN) 139479695Smsmith mly_rescan_btl(sc, bus, target); 139579695Smsmith } 139664987Smsmith } 139764987Smsmith } 139879695Smsmith 139979695Smsmith /* check for controller events */ 140079695Smsmith mly_check_event(sc); 140164987Smsmith 140279695Smsmith /* reschedule ourselves */ 140379695Smsmith sc->mly_periodic = timeout(mly_periodic, sc, MLY_PERIODIC_INTERVAL * hz); 140464987Smsmith} 140564987Smsmith 140664987Smsmith/******************************************************************************** 140764987Smsmith ******************************************************************************** 140864987Smsmith Command Processing 140964987Smsmith ******************************************************************************** 141064987Smsmith ********************************************************************************/ 141164987Smsmith 141264987Smsmith/******************************************************************************** 141364987Smsmith * Run a command and wait for it to complete. 141464987Smsmith * 141564987Smsmith */ 141664987Smsmithstatic int 141764987Smsmithmly_immediate_command(struct mly_command *mc) 141864987Smsmith{ 141964987Smsmith struct mly_softc *sc = mc->mc_sc; 142064987Smsmith int error, s; 142164987Smsmith 142279695Smsmith debug_called(1); 142364987Smsmith 142464987Smsmith /* spinning at splcam is ugly, but we're only used during controller init */ 142564987Smsmith s = splcam(); 142679695Smsmith if ((error = mly_start(mc))) { 142779695Smsmith splx(s); 142864987Smsmith return(error); 142979695Smsmith } 143064987Smsmith 143164987Smsmith if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) { 143264987Smsmith /* sleep on the command */ 143373050Smsmith while(!(mc->mc_flags & MLY_CMD_COMPLETE)) { 143464987Smsmith tsleep(mc, PRIBIO, "mlywait", 0); 143564987Smsmith } 143664987Smsmith } else { 143764987Smsmith /* spin and collect status while we do */ 143873050Smsmith while(!(mc->mc_flags & MLY_CMD_COMPLETE)) { 143964987Smsmith mly_done(mc->mc_sc); 144073050Smsmith } 144164987Smsmith } 144264987Smsmith splx(s); 144364987Smsmith return(0); 144464987Smsmith} 144564987Smsmith 144664987Smsmith/******************************************************************************** 144779695Smsmith * Deliver a command to the controller. 144879695Smsmith * 144979695Smsmith * XXX it would be good to just queue commands that we can't submit immediately 145079695Smsmith * and send them later, but we probably want a wrapper for that so that 145179695Smsmith * we don't hang on a failed submission for an immediate command. 145264987Smsmith */ 145364987Smsmithstatic int 145464987Smsmithmly_start(struct mly_command *mc) 145564987Smsmith{ 145664987Smsmith struct mly_softc *sc = mc->mc_sc; 145764987Smsmith union mly_command_packet *pkt; 145864987Smsmith int s; 145964987Smsmith 146064987Smsmith debug_called(2); 146164987Smsmith 146264987Smsmith /* 146373050Smsmith * Set the command up for delivery to the controller. 146464987Smsmith */ 146564987Smsmith mly_map_command(mc); 146673050Smsmith mc->mc_packet->generic.command_id = mc->mc_slot; 146764987Smsmith 1468110479Sscottl#ifdef MLY_DEBUG 1469110479Sscottl mc->mc_timestamp = time_second; 1470110479Sscottl#endif 1471110479Sscottl 147264987Smsmith s = splcam(); 147373050Smsmith 147464987Smsmith /* 147564987Smsmith * Do we have to use the hardware mailbox? 147664987Smsmith */ 147764987Smsmith if (!(sc->mly_state & MLY_STATE_MMBOX_ACTIVE)) { 147864987Smsmith /* 147964987Smsmith * Check to see if the controller is ready for us. 148064987Smsmith */ 148164987Smsmith if (MLY_IDBR_TRUE(sc, MLY_HM_CMDSENT)) { 148264987Smsmith splx(s); 148364987Smsmith return(EBUSY); 148464987Smsmith } 148573050Smsmith mc->mc_flags |= MLY_CMD_BUSY; 148673050Smsmith 148764987Smsmith /* 148864987Smsmith * It's ready, send the command. 148964987Smsmith */ 149064987Smsmith MLY_SET_MBOX(sc, sc->mly_command_mailbox, &mc->mc_packetphys); 149164987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_CMDSENT); 149264987Smsmith 149364987Smsmith } else { /* use memory-mailbox mode */ 149464987Smsmith 149564987Smsmith pkt = &sc->mly_mmbox->mmm_command[sc->mly_mmbox_command_index]; 149664987Smsmith 149773050Smsmith /* check to see if the next index is free yet */ 149864987Smsmith if (pkt->mmbox.flag != 0) { 149964987Smsmith splx(s); 150064987Smsmith return(EBUSY); 150164987Smsmith } 150273050Smsmith mc->mc_flags |= MLY_CMD_BUSY; 150364987Smsmith 150464987Smsmith /* copy in new command */ 150564987Smsmith bcopy(mc->mc_packet->mmbox.data, pkt->mmbox.data, sizeof(pkt->mmbox.data)); 150664987Smsmith /* barrier to ensure completion of previous write before we write the flag */ 1507106912Smux bus_space_barrier(sc->mly_btag, sc->mly_bhandle, 0, 0, 1508106912Smux BUS_SPACE_BARRIER_WRITE); 150964987Smsmith /* copy flag last */ 151064987Smsmith pkt->mmbox.flag = mc->mc_packet->mmbox.flag; 151164987Smsmith /* barrier to ensure completion of previous write before we notify the controller */ 1512106912Smux bus_space_barrier(sc->mly_btag, sc->mly_bhandle, 0, 0, 1513106912Smux BUS_SPACE_BARRIER_WRITE); 151464987Smsmith 151564987Smsmith /* signal controller, update index */ 151664987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_AM_CMDSENT); 151764987Smsmith sc->mly_mmbox_command_index = (sc->mly_mmbox_command_index + 1) % MLY_MMBOX_COMMANDS; 151864987Smsmith } 151964987Smsmith 152073050Smsmith mly_enqueue_busy(mc); 152164987Smsmith splx(s); 152264987Smsmith return(0); 152364987Smsmith} 152464987Smsmith 152564987Smsmith/******************************************************************************** 152664987Smsmith * Pick up command status from the controller, schedule a completion event 152764987Smsmith */ 1528105215Sphkstatic void 152964987Smsmithmly_done(struct mly_softc *sc) 153064987Smsmith{ 153164987Smsmith struct mly_command *mc; 153264987Smsmith union mly_status_packet *sp; 153364987Smsmith u_int16_t slot; 153464987Smsmith int s, worked; 153564987Smsmith 153664987Smsmith s = splcam(); 153764987Smsmith worked = 0; 153864987Smsmith 153964987Smsmith /* pick up hardware-mailbox commands */ 154064987Smsmith if (MLY_ODBR_TRUE(sc, MLY_HM_STSREADY)) { 154164987Smsmith slot = MLY_GET_REG2(sc, sc->mly_status_mailbox); 154264987Smsmith if (slot < MLY_SLOT_MAX) { 154373050Smsmith mc = &sc->mly_command[slot - MLY_SLOT_START]; 154473050Smsmith mc->mc_status = MLY_GET_REG(sc, sc->mly_status_mailbox + 2); 154573050Smsmith mc->mc_sense = MLY_GET_REG(sc, sc->mly_status_mailbox + 3); 154673050Smsmith mc->mc_resid = MLY_GET_REG4(sc, sc->mly_status_mailbox + 4); 154773050Smsmith mly_remove_busy(mc); 154873050Smsmith mc->mc_flags &= ~MLY_CMD_BUSY; 154973050Smsmith mly_enqueue_complete(mc); 155073050Smsmith worked = 1; 155164987Smsmith } else { 155264987Smsmith /* slot 0xffff may mean "extremely bogus command" */ 155364987Smsmith mly_printf(sc, "got HM completion for illegal slot %u\n", slot); 155464987Smsmith } 155564987Smsmith /* unconditionally acknowledge status */ 155664987Smsmith MLY_SET_REG(sc, sc->mly_odbr, MLY_HM_STSREADY); 155764987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); 155864987Smsmith } 155964987Smsmith 156064987Smsmith /* pick up memory-mailbox commands */ 156164987Smsmith if (MLY_ODBR_TRUE(sc, MLY_AM_STSREADY)) { 156264987Smsmith for (;;) { 156364987Smsmith sp = &sc->mly_mmbox->mmm_status[sc->mly_mmbox_status_index]; 156464987Smsmith 156564987Smsmith /* check for more status */ 156664987Smsmith if (sp->mmbox.flag == 0) 156764987Smsmith break; 156864987Smsmith 156964987Smsmith /* get slot number */ 157064987Smsmith slot = sp->status.command_id; 157164987Smsmith if (slot < MLY_SLOT_MAX) { 157273050Smsmith mc = &sc->mly_command[slot - MLY_SLOT_START]; 157373050Smsmith mc->mc_status = sp->status.status; 157473050Smsmith mc->mc_sense = sp->status.sense_length; 157573050Smsmith mc->mc_resid = sp->status.residue; 157673050Smsmith mly_remove_busy(mc); 157773050Smsmith mc->mc_flags &= ~MLY_CMD_BUSY; 157873050Smsmith mly_enqueue_complete(mc); 157973050Smsmith worked = 1; 158064987Smsmith } else { 158164987Smsmith /* slot 0xffff may mean "extremely bogus command" */ 158273050Smsmith mly_printf(sc, "got AM completion for illegal slot %u at %d\n", 158373050Smsmith slot, sc->mly_mmbox_status_index); 158464987Smsmith } 158564987Smsmith 158673050Smsmith /* clear and move to next index */ 158764987Smsmith sp->mmbox.flag = 0; 158864987Smsmith sc->mly_mmbox_status_index = (sc->mly_mmbox_status_index + 1) % MLY_MMBOX_STATUS; 158964987Smsmith } 159064987Smsmith /* acknowledge that we have collected status value(s) */ 159164987Smsmith MLY_SET_REG(sc, sc->mly_odbr, MLY_AM_STSREADY); 159264987Smsmith } 159364987Smsmith 159464987Smsmith splx(s); 159564987Smsmith if (worked) { 159664987Smsmith if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) 1597111528Sscottl taskqueue_enqueue(taskqueue_swi_giant, &sc->mly_task_complete); 159864987Smsmith else 159964987Smsmith mly_complete(sc, 0); 160064987Smsmith } 160164987Smsmith} 160264987Smsmith 160364987Smsmith/******************************************************************************** 160464987Smsmith * Process completed commands 160564987Smsmith */ 160664987Smsmithstatic void 160764987Smsmithmly_complete(void *context, int pending) 160864987Smsmith{ 160964987Smsmith struct mly_softc *sc = (struct mly_softc *)context; 161064987Smsmith struct mly_command *mc; 161164987Smsmith void (* mc_complete)(struct mly_command *mc); 161264987Smsmith 161364987Smsmith 161464987Smsmith debug_called(2); 161564987Smsmith 161664987Smsmith /* 161764987Smsmith * Spin pulling commands off the completed queue and processing them. 161864987Smsmith */ 161973050Smsmith while ((mc = mly_dequeue_complete(sc)) != NULL) { 162064987Smsmith 162164987Smsmith /* 162264987Smsmith * Free controller resources, mark command complete. 162364987Smsmith * 162464987Smsmith * Note that as soon as we mark the command complete, it may be freed 162564987Smsmith * out from under us, so we need to save the mc_complete field in 162664987Smsmith * order to later avoid dereferencing mc. (We would not expect to 162764987Smsmith * have a polling/sleeping consumer with mc_complete != NULL). 162864987Smsmith */ 162964987Smsmith mly_unmap_command(mc); 163064987Smsmith mc_complete = mc->mc_complete; 163173050Smsmith mc->mc_flags |= MLY_CMD_COMPLETE; 163264987Smsmith 163364987Smsmith /* 163464987Smsmith * Call completion handler or wake up sleeping consumer. 163564987Smsmith */ 163664987Smsmith if (mc_complete != NULL) { 163764987Smsmith mc_complete(mc); 163864987Smsmith } else { 163964987Smsmith wakeup(mc); 164064987Smsmith } 164164987Smsmith } 164279695Smsmith 164364987Smsmith /* 164479695Smsmith * XXX if we are deferring commands due to controller-busy status, we should 164579695Smsmith * retry submitting them here. 164664987Smsmith */ 164764987Smsmith} 164864987Smsmith 164964987Smsmith/******************************************************************************** 165064987Smsmith ******************************************************************************** 165164987Smsmith Command Buffer Management 165264987Smsmith ******************************************************************************** 165364987Smsmith ********************************************************************************/ 165464987Smsmith 165564987Smsmith/******************************************************************************** 165664987Smsmith * Allocate a command. 165764987Smsmith */ 1658105215Sphkstatic int 165964987Smsmithmly_alloc_command(struct mly_softc *sc, struct mly_command **mcp) 166064987Smsmith{ 166164987Smsmith struct mly_command *mc; 166264987Smsmith 166364987Smsmith debug_called(3); 166464987Smsmith 166573050Smsmith if ((mc = mly_dequeue_free(sc)) == NULL) 166664987Smsmith return(ENOMEM); 166764987Smsmith 166864987Smsmith *mcp = mc; 166964987Smsmith return(0); 167064987Smsmith} 167164987Smsmith 167264987Smsmith/******************************************************************************** 167364987Smsmith * Release a command back to the freelist. 167464987Smsmith */ 1675105215Sphkstatic void 167664987Smsmithmly_release_command(struct mly_command *mc) 167764987Smsmith{ 167864987Smsmith debug_called(3); 167964987Smsmith 168064987Smsmith /* 168164987Smsmith * Fill in parts of the command that may cause confusion if 168264987Smsmith * a consumer doesn't when we are later allocated. 168364987Smsmith */ 168464987Smsmith mc->mc_data = NULL; 168564987Smsmith mc->mc_flags = 0; 168664987Smsmith mc->mc_complete = NULL; 168764987Smsmith mc->mc_private = NULL; 168864987Smsmith 168964987Smsmith /* 169064987Smsmith * By default, we set up to overwrite the command packet with 169164987Smsmith * sense information. 169264987Smsmith */ 169364987Smsmith mc->mc_packet->generic.sense_buffer_address = mc->mc_packetphys; 169464987Smsmith mc->mc_packet->generic.maximum_sense_size = sizeof(union mly_command_packet); 169564987Smsmith 169664987Smsmith mly_enqueue_free(mc); 169764987Smsmith} 169864987Smsmith 169964987Smsmith/******************************************************************************** 170073050Smsmith * Map helper for command allocation. 170164987Smsmith */ 170264987Smsmithstatic void 170373050Smsmithmly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 170464987Smsmith{ 170579695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 170664987Smsmith 170779695Smsmith debug_called(1); 170864987Smsmith 170973050Smsmith sc->mly_packetphys = segs[0].ds_addr; 171064987Smsmith} 171164987Smsmith 171264987Smsmith/******************************************************************************** 171373050Smsmith * Allocate and initialise command and packet structures. 171479695Smsmith * 171579695Smsmith * If the controller supports fewer than MLY_MAX_COMMANDS commands, limit our 171679695Smsmith * allocation to that number. If we don't yet know how many commands the 171779695Smsmith * controller supports, allocate a very small set (suitable for initialisation 171879695Smsmith * purposes only). 171964987Smsmith */ 172073050Smsmithstatic int 172173050Smsmithmly_alloc_commands(struct mly_softc *sc) 172264987Smsmith{ 172364987Smsmith struct mly_command *mc; 172479695Smsmith int i, ncmd; 172564987Smsmith 172679695Smsmith if (sc->mly_controllerinfo == NULL) { 172779695Smsmith ncmd = 4; 172879695Smsmith } else { 172979695Smsmith ncmd = min(MLY_MAX_COMMANDS, sc->mly_controllerinfo->maximum_parallel_commands); 173079695Smsmith } 173179695Smsmith 173273050Smsmith /* 173373050Smsmith * Allocate enough space for all the command packets in one chunk and 173473050Smsmith * map them permanently into controller-visible space. 173573050Smsmith */ 173673050Smsmith if (bus_dmamem_alloc(sc->mly_packet_dmat, (void **)&sc->mly_packet, 173773050Smsmith BUS_DMA_NOWAIT, &sc->mly_packetmap)) { 173873050Smsmith return(ENOMEM); 173973050Smsmith } 1740118762Sscottl if (bus_dmamap_load(sc->mly_packet_dmat, sc->mly_packetmap, sc->mly_packet, 1741118762Sscottl ncmd * sizeof(union mly_command_packet), 1742118762Sscottl mly_alloc_commands_map, sc, BUS_DMA_NOWAIT) != 0) 1743118762Sscottl return (ENOMEM); 174464987Smsmith 174579695Smsmith for (i = 0; i < ncmd; i++) { 174673050Smsmith mc = &sc->mly_command[i]; 174773050Smsmith bzero(mc, sizeof(*mc)); 174873050Smsmith mc->mc_sc = sc; 174973050Smsmith mc->mc_slot = MLY_SLOT_START + i; 175073050Smsmith mc->mc_packet = sc->mly_packet + i; 175173050Smsmith mc->mc_packetphys = sc->mly_packetphys + (i * sizeof(union mly_command_packet)); 175273050Smsmith if (!bus_dmamap_create(sc->mly_buffer_dmat, 0, &mc->mc_datamap)) 175373050Smsmith mly_release_command(mc); 175464987Smsmith } 175573050Smsmith return(0); 175664987Smsmith} 175764987Smsmith 175864987Smsmith/******************************************************************************** 175979695Smsmith * Free all the storage held by commands. 176079695Smsmith * 176179695Smsmith * Must be called with all commands on the free list. 176279695Smsmith */ 176379695Smsmithstatic void 176479695Smsmithmly_release_commands(struct mly_softc *sc) 176579695Smsmith{ 176679695Smsmith struct mly_command *mc; 176779695Smsmith 176879695Smsmith /* throw away command buffer DMA maps */ 176979695Smsmith while (mly_alloc_command(sc, &mc) == 0) 177079695Smsmith bus_dmamap_destroy(sc->mly_buffer_dmat, mc->mc_datamap); 177179695Smsmith 177279695Smsmith /* release the packet storage */ 177379695Smsmith if (sc->mly_packet != NULL) { 177479695Smsmith bus_dmamap_unload(sc->mly_packet_dmat, sc->mly_packetmap); 177579695Smsmith bus_dmamem_free(sc->mly_packet_dmat, sc->mly_packet, sc->mly_packetmap); 177679695Smsmith sc->mly_packet = NULL; 177779695Smsmith } 177879695Smsmith} 177979695Smsmith 178079695Smsmith 178179695Smsmith/******************************************************************************** 178273050Smsmith * Command-mapping helper function - populate this command's s/g table 178373050Smsmith * with the s/g entries for its data. 178464987Smsmith */ 178564987Smsmithstatic void 178664987Smsmithmly_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 178764987Smsmith{ 178864987Smsmith struct mly_command *mc = (struct mly_command *)arg; 178964987Smsmith struct mly_softc *sc = mc->mc_sc; 179064987Smsmith struct mly_command_generic *gen = &(mc->mc_packet->generic); 179164987Smsmith struct mly_sg_entry *sg; 179264987Smsmith int i, tabofs; 179364987Smsmith 179479695Smsmith debug_called(2); 179564987Smsmith 179664987Smsmith /* can we use the transfer structure directly? */ 179764987Smsmith if (nseg <= 2) { 179864987Smsmith sg = &gen->transfer.direct.sg[0]; 179964987Smsmith gen->command_control.extended_sg_table = 0; 180064987Smsmith } else { 180179695Smsmith tabofs = ((mc->mc_slot - MLY_SLOT_START) * MLY_MAX_SGENTRIES); 180264987Smsmith sg = sc->mly_sg_table + tabofs; 180364987Smsmith gen->transfer.indirect.entries[0] = nseg; 180464987Smsmith gen->transfer.indirect.table_physaddr[0] = sc->mly_sg_busaddr + (tabofs * sizeof(struct mly_sg_entry)); 180564987Smsmith gen->command_control.extended_sg_table = 1; 180664987Smsmith } 180764987Smsmith 180864987Smsmith /* copy the s/g table */ 180964987Smsmith for (i = 0; i < nseg; i++) { 181064987Smsmith sg[i].physaddr = segs[i].ds_addr; 181164987Smsmith sg[i].length = segs[i].ds_len; 181264987Smsmith } 181364987Smsmith 181464987Smsmith} 181564987Smsmith 181664987Smsmith#if 0 181764987Smsmith/******************************************************************************** 181864987Smsmith * Command-mapping helper function - save the cdb's physical address. 181964987Smsmith * 182064987Smsmith * We don't support 'large' SCSI commands at this time, so this is unused. 182164987Smsmith */ 182264987Smsmithstatic void 182364987Smsmithmly_map_command_cdb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 182464987Smsmith{ 182564987Smsmith struct mly_command *mc = (struct mly_command *)arg; 182664987Smsmith 182779695Smsmith debug_called(2); 182864987Smsmith 182964987Smsmith /* XXX can we safely assume that a CDB will never cross a page boundary? */ 183064987Smsmith if ((segs[0].ds_addr % PAGE_SIZE) > 183164987Smsmith ((segs[0].ds_addr + mc->mc_packet->scsi_large.cdb_length) % PAGE_SIZE)) 183264987Smsmith panic("cdb crosses page boundary"); 183364987Smsmith 183464987Smsmith /* fix up fields in the command packet */ 183564987Smsmith mc->mc_packet->scsi_large.cdb_physaddr = segs[0].ds_addr; 183664987Smsmith} 183764987Smsmith#endif 183864987Smsmith 183964987Smsmith/******************************************************************************** 184064987Smsmith * Map a command into controller-visible space 184164987Smsmith */ 184264987Smsmithstatic void 184364987Smsmithmly_map_command(struct mly_command *mc) 184464987Smsmith{ 184564987Smsmith struct mly_softc *sc = mc->mc_sc; 184664987Smsmith 184764987Smsmith debug_called(2); 184864987Smsmith 184964987Smsmith /* don't map more than once */ 185064987Smsmith if (mc->mc_flags & MLY_CMD_MAPPED) 185164987Smsmith return; 185264987Smsmith 185364987Smsmith /* does the command have a data buffer? */ 185479695Smsmith if (mc->mc_data != NULL) { 1855246713Skib if (mc->mc_flags & MLY_CMD_CCB) 1856246713Skib bus_dmamap_load_ccb(sc->mly_buffer_dmat, mc->mc_datamap, 1857246713Skib mc->mc_data, mly_map_command_sg, mc, 0); 1858246713Skib else 1859246713Skib bus_dmamap_load(sc->mly_buffer_dmat, mc->mc_datamap, 1860246713Skib mc->mc_data, mc->mc_length, 1861246713Skib mly_map_command_sg, mc, 0); 186279695Smsmith if (mc->mc_flags & MLY_CMD_DATAIN) 186379695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREREAD); 186479695Smsmith if (mc->mc_flags & MLY_CMD_DATAOUT) 186579695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREWRITE); 186679695Smsmith } 186764987Smsmith mc->mc_flags |= MLY_CMD_MAPPED; 186864987Smsmith} 186964987Smsmith 187064987Smsmith/******************************************************************************** 187164987Smsmith * Unmap a command from controller-visible space 187264987Smsmith */ 187364987Smsmithstatic void 187464987Smsmithmly_unmap_command(struct mly_command *mc) 187564987Smsmith{ 187664987Smsmith struct mly_softc *sc = mc->mc_sc; 187764987Smsmith 187864987Smsmith debug_called(2); 187964987Smsmith 188064987Smsmith if (!(mc->mc_flags & MLY_CMD_MAPPED)) 188164987Smsmith return; 188264987Smsmith 188379695Smsmith /* does the command have a data buffer? */ 188479695Smsmith if (mc->mc_data != NULL) { 188579695Smsmith if (mc->mc_flags & MLY_CMD_DATAIN) 188679695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTREAD); 188779695Smsmith if (mc->mc_flags & MLY_CMD_DATAOUT) 188879695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTWRITE); 188964987Smsmith 189064987Smsmith bus_dmamap_unload(sc->mly_buffer_dmat, mc->mc_datamap); 189179695Smsmith } 189264987Smsmith mc->mc_flags &= ~MLY_CMD_MAPPED; 189364987Smsmith} 189464987Smsmith 189579695Smsmith 189664987Smsmith/******************************************************************************** 189764987Smsmith ******************************************************************************** 189879695Smsmith CAM interface 189979695Smsmith ******************************************************************************** 190079695Smsmith ********************************************************************************/ 190179695Smsmith 190279695Smsmith/******************************************************************************** 190379695Smsmith * Attach the physical and virtual SCSI busses to CAM. 190479695Smsmith * 190579695Smsmith * Physical bus numbering starts from 0, virtual bus numbering from one greater 190679695Smsmith * than the highest physical bus. Physical busses are only registered if 190779695Smsmith * the kernel environment variable "hw.mly.register_physical_channels" is set. 190879695Smsmith * 190979695Smsmith * When we refer to a "bus", we are referring to the bus number registered with 191079695Smsmith * the SIM, wheras a "channel" is a channel number given to the adapter. In order 191179695Smsmith * to keep things simple, we map these 1:1, so "bus" and "channel" may be used 191279695Smsmith * interchangeably. 191379695Smsmith */ 1914105215Sphkstatic int 191579695Smsmithmly_cam_attach(struct mly_softc *sc) 191679695Smsmith{ 191779695Smsmith struct cam_devq *devq; 191879695Smsmith int chn, i; 191979695Smsmith 192079695Smsmith debug_called(1); 192179695Smsmith 192279695Smsmith /* 192379695Smsmith * Allocate a devq for all our channels combined. 192479695Smsmith */ 192579695Smsmith if ((devq = cam_simq_alloc(sc->mly_controllerinfo->maximum_parallel_commands)) == NULL) { 192679695Smsmith mly_printf(sc, "can't allocate CAM SIM queue\n"); 192779695Smsmith return(ENOMEM); 192879695Smsmith } 192979695Smsmith 193079695Smsmith /* 193179695Smsmith * If physical channel registration has been requested, register these first. 193279695Smsmith * Note that we enable tagged command queueing for physical channels. 193379695Smsmith */ 193494936Smux if (testenv("hw.mly.register_physical_channels")) { 193579695Smsmith chn = 0; 193679695Smsmith for (i = 0; i < sc->mly_controllerinfo->physical_channels_present; i++, chn++) { 193779695Smsmith 193879695Smsmith if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, 193979695Smsmith device_get_unit(sc->mly_dev), 1940168752Sscottl &Giant, 194179695Smsmith sc->mly_controllerinfo->maximum_parallel_commands, 194279695Smsmith 1, devq)) == NULL) { 194379695Smsmith return(ENOMEM); 194479695Smsmith } 1945170872Sscottl if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) { 194679695Smsmith mly_printf(sc, "CAM XPT phsyical channel registration failed\n"); 194779695Smsmith return(ENXIO); 194879695Smsmith } 194979695Smsmith debug(1, "registered physical channel %d", chn); 195079695Smsmith } 195179695Smsmith } 195279695Smsmith 195379695Smsmith /* 195479695Smsmith * Register our virtual channels, with bus numbers matching channel numbers. 195579695Smsmith */ 195679695Smsmith chn = sc->mly_controllerinfo->physical_channels_present; 195779695Smsmith for (i = 0; i < sc->mly_controllerinfo->virtual_channels_present; i++, chn++) { 195879695Smsmith if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, 195979695Smsmith device_get_unit(sc->mly_dev), 1960168752Sscottl &Giant, 196179695Smsmith sc->mly_controllerinfo->maximum_parallel_commands, 196279695Smsmith 0, devq)) == NULL) { 196379695Smsmith return(ENOMEM); 196479695Smsmith } 1965170872Sscottl if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) { 196679695Smsmith mly_printf(sc, "CAM XPT virtual channel registration failed\n"); 196779695Smsmith return(ENXIO); 196879695Smsmith } 196979695Smsmith debug(1, "registered virtual channel %d", chn); 197079695Smsmith } 197179695Smsmith 197279695Smsmith /* 197379695Smsmith * This is the total number of channels that (might have been) registered with 197479695Smsmith * CAM. Some may not have been; check the mly_cam_sim array to be certain. 197579695Smsmith */ 197679695Smsmith sc->mly_cam_channels = sc->mly_controllerinfo->physical_channels_present + 197779695Smsmith sc->mly_controllerinfo->virtual_channels_present; 197879695Smsmith 197979695Smsmith return(0); 198079695Smsmith} 198179695Smsmith 198279695Smsmith/******************************************************************************** 198379695Smsmith * Detach from CAM 198479695Smsmith */ 1985105215Sphkstatic void 198679695Smsmithmly_cam_detach(struct mly_softc *sc) 198779695Smsmith{ 198879695Smsmith int i; 198979695Smsmith 199079695Smsmith debug_called(1); 199179695Smsmith 199279695Smsmith for (i = 0; i < sc->mly_cam_channels; i++) { 199379695Smsmith if (sc->mly_cam_sim[i] != NULL) { 199479695Smsmith xpt_bus_deregister(cam_sim_path(sc->mly_cam_sim[i])); 199579695Smsmith cam_sim_free(sc->mly_cam_sim[i], 0); 199679695Smsmith } 199779695Smsmith } 199879695Smsmith if (sc->mly_cam_devq != NULL) 199979695Smsmith cam_simq_free(sc->mly_cam_devq); 200079695Smsmith} 200179695Smsmith 200279695Smsmith/************************************************************************ 200379695Smsmith * Rescan a device. 200479695Smsmith */ 200579695Smsmithstatic void 200679695Smsmithmly_cam_rescan_btl(struct mly_softc *sc, int bus, int target) 200779695Smsmith{ 200879695Smsmith union ccb *ccb; 200979695Smsmith 201079695Smsmith debug_called(1); 201179695Smsmith 2012203108Smav if ((ccb = xpt_alloc_ccb()) == NULL) { 201379695Smsmith mly_printf(sc, "rescan failed (can't allocate CCB)\n"); 201479695Smsmith return; 201579695Smsmith } 2016249468Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, 2017203108Smav cam_sim_path(sc->mly_cam_sim[bus]), target, 0) != CAM_REQ_CMP) { 201879695Smsmith mly_printf(sc, "rescan failed (can't create path)\n"); 2019203108Smav xpt_free_ccb(ccb); 202079695Smsmith return; 202179695Smsmith } 202279695Smsmith debug(1, "rescan target %d:%d", bus, target); 2023203108Smav xpt_rescan(ccb); 202479695Smsmith} 202579695Smsmith 202679695Smsmith/******************************************************************************** 202779695Smsmith * Handle an action requested by CAM 202879695Smsmith */ 202979695Smsmithstatic void 203079695Smsmithmly_cam_action(struct cam_sim *sim, union ccb *ccb) 203179695Smsmith{ 203279695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 203379695Smsmith 203479695Smsmith debug_called(2); 203579695Smsmith 203679695Smsmith switch (ccb->ccb_h.func_code) { 203779695Smsmith 203879695Smsmith /* perform SCSI I/O */ 203979695Smsmith case XPT_SCSI_IO: 204079695Smsmith if (!mly_cam_action_io(sim, (struct ccb_scsiio *)&ccb->csio)) 204179695Smsmith return; 204279695Smsmith break; 204379695Smsmith 204479695Smsmith /* perform geometry calculations */ 204579695Smsmith case XPT_CALC_GEOMETRY: 204679695Smsmith { 204779695Smsmith struct ccb_calc_geometry *ccg = &ccb->ccg; 204879695Smsmith u_int32_t secs_per_cylinder; 204979695Smsmith 205079695Smsmith debug(2, "XPT_CALC_GEOMETRY %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 205179695Smsmith 205279695Smsmith if (sc->mly_controllerparam->bios_geometry == MLY_BIOSGEOM_8G) { 205379695Smsmith ccg->heads = 255; 205479695Smsmith ccg->secs_per_track = 63; 205579695Smsmith } else { /* MLY_BIOSGEOM_2G */ 205679695Smsmith ccg->heads = 128; 205779695Smsmith ccg->secs_per_track = 32; 205879695Smsmith } 205979695Smsmith secs_per_cylinder = ccg->heads * ccg->secs_per_track; 206079695Smsmith ccg->cylinders = ccg->volume_size / secs_per_cylinder; 206179695Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 206279695Smsmith break; 206379695Smsmith } 206479695Smsmith 206579695Smsmith /* handle path attribute inquiry */ 206679695Smsmith case XPT_PATH_INQ: 206779695Smsmith { 206879695Smsmith struct ccb_pathinq *cpi = &ccb->cpi; 206979695Smsmith 207079695Smsmith debug(2, "XPT_PATH_INQ %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 207179695Smsmith 207279695Smsmith cpi->version_num = 1; 207379695Smsmith cpi->hba_inquiry = PI_TAG_ABLE; /* XXX extra flags for physical channels? */ 207479695Smsmith cpi->target_sprt = 0; 207579695Smsmith cpi->hba_misc = 0; 207679695Smsmith cpi->max_target = MLY_MAX_TARGETS - 1; 207779695Smsmith cpi->max_lun = MLY_MAX_LUNS - 1; 207879695Smsmith cpi->initiator_id = sc->mly_controllerparam->initiator_id; 207979695Smsmith strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 208079695Smsmith strncpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN); 208179695Smsmith strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 208279695Smsmith cpi->unit_number = cam_sim_unit(sim); 208379695Smsmith cpi->bus_id = cam_sim_bus(sim); 208479695Smsmith cpi->base_transfer_speed = 132 * 1024; /* XXX what to set this to? */ 2085163816Smjacob cpi->transport = XPORT_SPI; 2086163816Smjacob cpi->transport_version = 2; 2087163816Smjacob cpi->protocol = PROTO_SCSI; 2088163816Smjacob cpi->protocol_version = SCSI_REV_2; 208979695Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 209079695Smsmith break; 209179695Smsmith } 209279695Smsmith 209379695Smsmith case XPT_GET_TRAN_SETTINGS: 209479695Smsmith { 209579695Smsmith struct ccb_trans_settings *cts = &ccb->cts; 209679695Smsmith int bus, target; 2097163816Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 2098163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 209979695Smsmith 2100163816Smjacob cts->protocol = PROTO_SCSI; 2101163816Smjacob cts->protocol_version = SCSI_REV_2; 2102163816Smjacob cts->transport = XPORT_SPI; 2103163816Smjacob cts->transport_version = 2; 2104163816Smjacob 2105163816Smjacob scsi->flags = 0; 2106163816Smjacob scsi->valid = 0; 2107163816Smjacob spi->flags = 0; 2108163816Smjacob spi->valid = 0; 2109163816Smjacob 211079695Smsmith bus = cam_sim_bus(sim); 211179695Smsmith target = cts->ccb_h.target_id; 2112163816Smjacob debug(2, "XPT_GET_TRAN_SETTINGS %d:%d", bus, target); 2113163816Smjacob /* logical device? */ 2114163816Smjacob if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) { 2115163816Smjacob /* nothing special for these */ 2116163816Smjacob /* physical device? */ 2117163816Smjacob } else if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_PHYSICAL) { 2118163816Smjacob /* allow CAM to try tagged transactions */ 2119163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2120163816Smjacob scsi->valid |= CTS_SCSI_VALID_TQ; 2121163816Smjacob 2122163816Smjacob /* convert speed (MHz) to usec */ 2123163816Smjacob if (sc->mly_btl[bus][target].mb_speed == 0) { 2124163816Smjacob spi->sync_period = 1000000 / 5; 2125163816Smjacob } else { 2126163816Smjacob spi->sync_period = 1000000 / sc->mly_btl[bus][target].mb_speed; 2127163816Smjacob } 2128163816Smjacob 2129163816Smjacob /* convert bus width to CAM internal encoding */ 2130163816Smjacob switch (sc->mly_btl[bus][target].mb_width) { 2131163816Smjacob case 32: 2132163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT; 2133163816Smjacob break; 2134163816Smjacob case 16: 2135163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2136163816Smjacob break; 2137163816Smjacob case 8: 2138163816Smjacob default: 2139163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2140163816Smjacob break; 2141163816Smjacob } 2142163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_BUS_WIDTH; 2143163816Smjacob 2144163816Smjacob /* not a device, bail out */ 2145163816Smjacob } else { 2146163816Smjacob cts->ccb_h.status = CAM_REQ_CMP_ERR; 2147163816Smjacob break; 2148163816Smjacob } 2149163816Smjacob 2150163816Smjacob /* disconnect always OK */ 2151163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2152163816Smjacob spi->valid |= CTS_SPI_VALID_DISC; 2153163816Smjacob 215479695Smsmith cts->ccb_h.status = CAM_REQ_CMP; 215579695Smsmith break; 215679695Smsmith } 215779695Smsmith 215879695Smsmith default: /* we can't do this */ 215979695Smsmith debug(2, "unspported func_code = 0x%x", ccb->ccb_h.func_code); 216079695Smsmith ccb->ccb_h.status = CAM_REQ_INVALID; 216179695Smsmith break; 216279695Smsmith } 216379695Smsmith 216479695Smsmith xpt_done(ccb); 216579695Smsmith} 216679695Smsmith 216779695Smsmith/******************************************************************************** 216879695Smsmith * Handle an I/O operation requested by CAM 216979695Smsmith */ 217079695Smsmithstatic int 217179695Smsmithmly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio) 217279695Smsmith{ 217379695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 217479695Smsmith struct mly_command *mc; 217579695Smsmith struct mly_command_scsi_small *ss; 217679695Smsmith int bus, target; 217779695Smsmith int error; 2178110479Sscottl int s; 217979695Smsmith 218079695Smsmith bus = cam_sim_bus(sim); 218179695Smsmith target = csio->ccb_h.target_id; 218279695Smsmith 218379695Smsmith debug(2, "XPT_SCSI_IO %d:%d:%d", bus, target, csio->ccb_h.target_lun); 218479695Smsmith 218579695Smsmith /* validate bus number */ 218679695Smsmith if (!MLY_BUS_IS_VALID(sc, bus)) { 218779695Smsmith debug(0, " invalid bus %d", bus); 218879695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 218979695Smsmith } 219079695Smsmith 219179695Smsmith /* check for I/O attempt to a protected device */ 219279695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_PROTECTED) { 219379695Smsmith debug(2, " device protected"); 219479695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 219579695Smsmith } 219679695Smsmith 219779695Smsmith /* check for I/O attempt to nonexistent device */ 219879695Smsmith if (!(sc->mly_btl[bus][target].mb_flags & (MLY_BTL_LOGICAL | MLY_BTL_PHYSICAL))) { 219979695Smsmith debug(2, " device %d:%d does not exist", bus, target); 220079695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 220179695Smsmith } 220279695Smsmith 220379695Smsmith /* XXX increase if/when we support large SCSI commands */ 220479695Smsmith if (csio->cdb_len > MLY_CMD_SCSI_SMALL_CDB) { 220579695Smsmith debug(0, " command too large (%d > %d)", csio->cdb_len, MLY_CMD_SCSI_SMALL_CDB); 220679695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 220779695Smsmith } 220879695Smsmith 220979695Smsmith /* check that the CDB pointer is not to a physical address */ 221079695Smsmith if ((csio->ccb_h.flags & CAM_CDB_POINTER) && (csio->ccb_h.flags & CAM_CDB_PHYS)) { 221179695Smsmith debug(0, " CDB pointer is to physical address"); 221279695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 221379695Smsmith } 221479695Smsmith 221579695Smsmith /* abandon aborted ccbs or those that have failed validation */ 221679695Smsmith if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 221779695Smsmith debug(2, "abandoning CCB due to abort/validation failure"); 221879695Smsmith return(EINVAL); 221979695Smsmith } 222079695Smsmith 222179695Smsmith /* 222279695Smsmith * Get a command, or push the ccb back to CAM and freeze the queue. 222379695Smsmith */ 222479695Smsmith if ((error = mly_alloc_command(sc, &mc))) { 2225110479Sscottl s = splcam(); 222679695Smsmith xpt_freeze_simq(sim, 1); 222779695Smsmith csio->ccb_h.status |= CAM_REQUEUE_REQ; 2228110479Sscottl sc->mly_qfrzn_cnt++; 2229110479Sscottl splx(s); 223079695Smsmith return(error); 223179695Smsmith } 223279695Smsmith 223379695Smsmith /* build the command */ 2234246713Skib mc->mc_data = csio; 223579695Smsmith mc->mc_length = csio->dxfer_len; 223679695Smsmith mc->mc_complete = mly_cam_complete; 223779695Smsmith mc->mc_private = csio; 2238246713Skib mc->mc_flags |= MLY_CMD_CCB; 2239246713Skib /* XXX This code doesn't set the data direction in mc_flags. */ 224079695Smsmith 224179695Smsmith /* save the bus number in the ccb for later recovery XXX should be a better way */ 224279695Smsmith csio->ccb_h.sim_priv.entries[0].field = bus; 224379695Smsmith 224479695Smsmith /* build the packet for the controller */ 224579695Smsmith ss = &mc->mc_packet->scsi_small; 224679695Smsmith ss->opcode = MDACMD_SCSI; 224780365Smsmith if (csio->ccb_h.flags & CAM_DIS_DISCONNECT) 224879695Smsmith ss->command_control.disable_disconnect = 1; 224979695Smsmith if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 225079695Smsmith ss->command_control.data_direction = MLY_CCB_WRITE; 225179695Smsmith ss->data_size = csio->dxfer_len; 225279695Smsmith ss->addr.phys.lun = csio->ccb_h.target_lun; 225379695Smsmith ss->addr.phys.target = csio->ccb_h.target_id; 225479695Smsmith ss->addr.phys.channel = bus; 225579695Smsmith if (csio->ccb_h.timeout < (60 * 1000)) { 225679695Smsmith ss->timeout.value = csio->ccb_h.timeout / 1000; 225779695Smsmith ss->timeout.scale = MLY_TIMEOUT_SECONDS; 225879695Smsmith } else if (csio->ccb_h.timeout < (60 * 60 * 1000)) { 225979695Smsmith ss->timeout.value = csio->ccb_h.timeout / (60 * 1000); 226079695Smsmith ss->timeout.scale = MLY_TIMEOUT_MINUTES; 226179695Smsmith } else { 226279695Smsmith ss->timeout.value = csio->ccb_h.timeout / (60 * 60 * 1000); /* overflow? */ 226379695Smsmith ss->timeout.scale = MLY_TIMEOUT_HOURS; 226479695Smsmith } 226579695Smsmith ss->maximum_sense_size = csio->sense_len; 226679695Smsmith ss->cdb_length = csio->cdb_len; 226779695Smsmith if (csio->ccb_h.flags & CAM_CDB_POINTER) { 226879695Smsmith bcopy(csio->cdb_io.cdb_ptr, ss->cdb, csio->cdb_len); 226979695Smsmith } else { 227079695Smsmith bcopy(csio->cdb_io.cdb_bytes, ss->cdb, csio->cdb_len); 227179695Smsmith } 227279695Smsmith 227379695Smsmith /* give the command to the controller */ 227479695Smsmith if ((error = mly_start(mc))) { 2275110479Sscottl s = splcam(); 227679695Smsmith xpt_freeze_simq(sim, 1); 227779695Smsmith csio->ccb_h.status |= CAM_REQUEUE_REQ; 2278110479Sscottl sc->mly_qfrzn_cnt++; 2279110479Sscottl splx(s); 228079695Smsmith return(error); 228179695Smsmith } 228279695Smsmith 228379695Smsmith return(0); 228479695Smsmith} 228579695Smsmith 228679695Smsmith/******************************************************************************** 228779695Smsmith * Check for possibly-completed commands. 228879695Smsmith */ 228979695Smsmithstatic void 229079695Smsmithmly_cam_poll(struct cam_sim *sim) 229179695Smsmith{ 229279695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 229379695Smsmith 229479695Smsmith debug_called(2); 229579695Smsmith 229679695Smsmith mly_done(sc); 229779695Smsmith} 229879695Smsmith 229979695Smsmith/******************************************************************************** 230079695Smsmith * Handle completion of a command - pass results back through the CCB 230179695Smsmith */ 230279695Smsmithstatic void 230379695Smsmithmly_cam_complete(struct mly_command *mc) 230479695Smsmith{ 230579695Smsmith struct mly_softc *sc = mc->mc_sc; 230679695Smsmith struct ccb_scsiio *csio = (struct ccb_scsiio *)mc->mc_private; 230779695Smsmith struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr; 230879695Smsmith struct mly_btl *btl; 230979695Smsmith u_int8_t cmd; 231079695Smsmith int bus, target; 2311110479Sscottl int s; 231279695Smsmith 231379695Smsmith debug_called(2); 231479695Smsmith 231579695Smsmith csio->scsi_status = mc->mc_status; 231679695Smsmith switch(mc->mc_status) { 231779695Smsmith case SCSI_STATUS_OK: 231879695Smsmith /* 231979695Smsmith * In order to report logical device type and status, we overwrite 232079695Smsmith * the result of the INQUIRY command to logical devices. 232179695Smsmith */ 232279695Smsmith bus = csio->ccb_h.sim_priv.entries[0].field; 232379695Smsmith target = csio->ccb_h.target_id; 232479695Smsmith /* XXX validate bus/target? */ 232579695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) { 232679695Smsmith if (csio->ccb_h.flags & CAM_CDB_POINTER) { 232779695Smsmith cmd = *csio->cdb_io.cdb_ptr; 232879695Smsmith } else { 232979695Smsmith cmd = csio->cdb_io.cdb_bytes[0]; 233079695Smsmith } 233179695Smsmith if (cmd == INQUIRY) { 233279695Smsmith btl = &sc->mly_btl[bus][target]; 233379695Smsmith padstr(inq->vendor, mly_describe_code(mly_table_device_type, btl->mb_type), 8); 233479695Smsmith padstr(inq->product, mly_describe_code(mly_table_device_state, btl->mb_state), 16); 233579695Smsmith padstr(inq->revision, "", 4); 233679695Smsmith } 233779695Smsmith } 233879695Smsmith 233979695Smsmith debug(2, "SCSI_STATUS_OK"); 234079695Smsmith csio->ccb_h.status = CAM_REQ_CMP; 234179695Smsmith break; 234279695Smsmith 234379695Smsmith case SCSI_STATUS_CHECK_COND: 234479695Smsmith debug(1, "SCSI_STATUS_CHECK_COND sense %d resid %d", mc->mc_sense, mc->mc_resid); 234579695Smsmith csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; 234679695Smsmith bzero(&csio->sense_data, SSD_FULL_SIZE); 234779695Smsmith bcopy(mc->mc_packet, &csio->sense_data, mc->mc_sense); 234879695Smsmith csio->sense_len = mc->mc_sense; 234979695Smsmith csio->ccb_h.status |= CAM_AUTOSNS_VALID; 235079695Smsmith csio->resid = mc->mc_resid; /* XXX this is a signed value... */ 235179695Smsmith break; 235279695Smsmith 235379695Smsmith case SCSI_STATUS_BUSY: 235479695Smsmith debug(1, "SCSI_STATUS_BUSY"); 235579695Smsmith csio->ccb_h.status = CAM_SCSI_BUSY; 235679695Smsmith break; 235779695Smsmith 235879695Smsmith default: 235979695Smsmith debug(1, "unknown status 0x%x", csio->scsi_status); 236079695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 236179695Smsmith break; 236279695Smsmith } 2363110479Sscottl 2364110479Sscottl s = splcam(); 2365110479Sscottl if (sc->mly_qfrzn_cnt) { 2366110479Sscottl csio->ccb_h.status |= CAM_RELEASE_SIMQ; 2367110479Sscottl sc->mly_qfrzn_cnt--; 2368110479Sscottl } 2369110479Sscottl splx(s); 2370110479Sscottl 237179695Smsmith xpt_done((union ccb *)csio); 237279695Smsmith mly_release_command(mc); 237379695Smsmith} 237479695Smsmith 237579695Smsmith/******************************************************************************** 237679695Smsmith * Find a peripheral attahed at (bus),(target) 237779695Smsmith */ 237879695Smsmithstatic struct cam_periph * 237979695Smsmithmly_find_periph(struct mly_softc *sc, int bus, int target) 238079695Smsmith{ 238179695Smsmith struct cam_periph *periph; 238279695Smsmith struct cam_path *path; 238379695Smsmith int status; 238479695Smsmith 238579695Smsmith status = xpt_create_path(&path, NULL, cam_sim_path(sc->mly_cam_sim[bus]), target, 0); 238679695Smsmith if (status == CAM_REQ_CMP) { 238779695Smsmith periph = cam_periph_find(path, NULL); 238879695Smsmith xpt_free_path(path); 238979695Smsmith } else { 239079695Smsmith periph = NULL; 239179695Smsmith } 239279695Smsmith return(periph); 239379695Smsmith} 239479695Smsmith 239579695Smsmith/******************************************************************************** 239679695Smsmith * Name the device at (bus)(target) 239779695Smsmith */ 2398105215Sphkstatic int 239979695Smsmithmly_name_device(struct mly_softc *sc, int bus, int target) 240079695Smsmith{ 240179695Smsmith struct cam_periph *periph; 240279695Smsmith 240379695Smsmith if ((periph = mly_find_periph(sc, bus, target)) != NULL) { 240479695Smsmith sprintf(sc->mly_btl[bus][target].mb_name, "%s%d", periph->periph_name, periph->unit_number); 240579695Smsmith return(0); 240679695Smsmith } 240779695Smsmith sc->mly_btl[bus][target].mb_name[0] = 0; 240879695Smsmith return(ENOENT); 240979695Smsmith} 241079695Smsmith 241179695Smsmith/******************************************************************************** 241279695Smsmith ******************************************************************************** 241364987Smsmith Hardware Control 241464987Smsmith ******************************************************************************** 241564987Smsmith ********************************************************************************/ 241664987Smsmith 241764987Smsmith/******************************************************************************** 241864987Smsmith * Handshake with the firmware while the card is being initialised. 241964987Smsmith */ 242064987Smsmithstatic int 242164987Smsmithmly_fwhandshake(struct mly_softc *sc) 242264987Smsmith{ 242364987Smsmith u_int8_t error, param0, param1; 242464987Smsmith int spinup = 0; 242564987Smsmith 242664987Smsmith debug_called(1); 242764987Smsmith 242864987Smsmith /* set HM_STSACK and let the firmware initialise */ 242964987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); 243064987Smsmith DELAY(1000); /* too short? */ 243164987Smsmith 243264987Smsmith /* if HM_STSACK is still true, the controller is initialising */ 243364987Smsmith if (!MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) 243464987Smsmith return(0); 243564987Smsmith mly_printf(sc, "controller initialisation started\n"); 243664987Smsmith 243764987Smsmith /* spin waiting for initialisation to finish, or for a message to be delivered */ 243864987Smsmith while (MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) { 243964987Smsmith /* check for a message */ 244064987Smsmith if (MLY_ERROR_VALID(sc)) { 244164987Smsmith error = MLY_GET_REG(sc, sc->mly_error_status) & ~MLY_MSG_EMPTY; 244264987Smsmith param0 = MLY_GET_REG(sc, sc->mly_command_mailbox); 244364987Smsmith param1 = MLY_GET_REG(sc, sc->mly_command_mailbox + 1); 244464987Smsmith 244564987Smsmith switch(error) { 244664987Smsmith case MLY_MSG_SPINUP: 244764987Smsmith if (!spinup) { 244864987Smsmith mly_printf(sc, "drive spinup in progress\n"); 244964987Smsmith spinup = 1; /* only print this once (should print drive being spun?) */ 245064987Smsmith } 245164987Smsmith break; 245264987Smsmith case MLY_MSG_RACE_RECOVERY_FAIL: 245364987Smsmith mly_printf(sc, "mirror race recovery failed, one or more drives offline\n"); 245464987Smsmith break; 245564987Smsmith case MLY_MSG_RACE_IN_PROGRESS: 245664987Smsmith mly_printf(sc, "mirror race recovery in progress\n"); 245764987Smsmith break; 245864987Smsmith case MLY_MSG_RACE_ON_CRITICAL: 245964987Smsmith mly_printf(sc, "mirror race recovery on a critical drive\n"); 246064987Smsmith break; 246164987Smsmith case MLY_MSG_PARITY_ERROR: 246264987Smsmith mly_printf(sc, "FATAL MEMORY PARITY ERROR\n"); 246364987Smsmith return(ENXIO); 246464987Smsmith default: 246564987Smsmith mly_printf(sc, "unknown initialisation code 0x%x\n", error); 246664987Smsmith } 246764987Smsmith } 246864987Smsmith } 246964987Smsmith return(0); 247064987Smsmith} 247164987Smsmith 247264987Smsmith/******************************************************************************** 247364987Smsmith ******************************************************************************** 247464987Smsmith Debugging and Diagnostics 247564987Smsmith ******************************************************************************** 247664987Smsmith ********************************************************************************/ 247764987Smsmith 247864987Smsmith/******************************************************************************** 247964987Smsmith * Print some information about the controller. 248064987Smsmith */ 248164987Smsmithstatic void 248264987Smsmithmly_describe_controller(struct mly_softc *sc) 248364987Smsmith{ 248464987Smsmith struct mly_ioctl_getcontrollerinfo *mi = sc->mly_controllerinfo; 248564987Smsmith 248664987Smsmith mly_printf(sc, "%16s, %d channel%s, firmware %d.%02d-%d-%02d (%02d%02d%02d%02d), %dMB RAM\n", 248764987Smsmith mi->controller_name, mi->physical_channels_present, (mi->physical_channels_present) > 1 ? "s" : "", 248864987Smsmith mi->fw_major, mi->fw_minor, mi->fw_turn, mi->fw_build, /* XXX turn encoding? */ 248964987Smsmith mi->fw_century, mi->fw_year, mi->fw_month, mi->fw_day, 249064987Smsmith mi->memory_size); 249164987Smsmith 249264987Smsmith if (bootverbose) { 249364987Smsmith mly_printf(sc, "%s %s (%x), %dMHz %d-bit %.16s\n", 249464987Smsmith mly_describe_code(mly_table_oemname, mi->oem_information), 249564987Smsmith mly_describe_code(mly_table_controllertype, mi->controller_type), mi->controller_type, 249664987Smsmith mi->interface_speed, mi->interface_width, mi->interface_name); 249764987Smsmith mly_printf(sc, "%dMB %dMHz %d-bit %s%s%s, cache %dMB\n", 249864987Smsmith mi->memory_size, mi->memory_speed, mi->memory_width, 249964987Smsmith mly_describe_code(mly_table_memorytype, mi->memory_type), 250064987Smsmith mi->memory_parity ? "+parity": "",mi->memory_ecc ? "+ECC": "", 250164987Smsmith mi->cache_size); 2502202161Sgavin mly_printf(sc, "CPU: %s @ %dMHz\n", 250364987Smsmith mly_describe_code(mly_table_cputype, mi->cpu[0].type), mi->cpu[0].speed); 250464987Smsmith if (mi->l2cache_size != 0) 250564987Smsmith mly_printf(sc, "%dKB L2 cache\n", mi->l2cache_size); 250664987Smsmith if (mi->exmemory_size != 0) 250764987Smsmith mly_printf(sc, "%dMB %dMHz %d-bit private %s%s%s\n", 250864987Smsmith mi->exmemory_size, mi->exmemory_speed, mi->exmemory_width, 250964987Smsmith mly_describe_code(mly_table_memorytype, mi->exmemory_type), 251064987Smsmith mi->exmemory_parity ? "+parity": "",mi->exmemory_ecc ? "+ECC": ""); 251164987Smsmith mly_printf(sc, "battery backup %s\n", mi->bbu_present ? "present" : "not installed"); 251264987Smsmith mly_printf(sc, "maximum data transfer %d blocks, maximum sg entries/command %d\n", 251364987Smsmith mi->maximum_block_count, mi->maximum_sg_entries); 251464987Smsmith mly_printf(sc, "logical devices present/critical/offline %d/%d/%d\n", 251564987Smsmith mi->logical_devices_present, mi->logical_devices_critical, mi->logical_devices_offline); 251664987Smsmith mly_printf(sc, "physical devices present %d\n", 251764987Smsmith mi->physical_devices_present); 251864987Smsmith mly_printf(sc, "physical disks present/offline %d/%d\n", 251964987Smsmith mi->physical_disks_present, mi->physical_disks_offline); 252064987Smsmith mly_printf(sc, "%d physical channel%s, %d virtual channel%s of %d possible\n", 252164987Smsmith mi->physical_channels_present, mi->physical_channels_present == 1 ? "" : "s", 252264987Smsmith mi->virtual_channels_present, mi->virtual_channels_present == 1 ? "" : "s", 252364987Smsmith mi->virtual_channels_possible); 252464987Smsmith mly_printf(sc, "%d parallel commands supported\n", mi->maximum_parallel_commands); 252564987Smsmith mly_printf(sc, "%dMB flash ROM, %d of %d maximum cycles\n", 252664987Smsmith mi->flash_size, mi->flash_age, mi->flash_maximum_age); 252764987Smsmith } 252864987Smsmith} 252964987Smsmith 253064987Smsmith#ifdef MLY_DEBUG 253164987Smsmith/******************************************************************************** 253264987Smsmith * Print some controller state 253364987Smsmith */ 253464987Smsmithstatic void 253564987Smsmithmly_printstate(struct mly_softc *sc) 253664987Smsmith{ 253764987Smsmith mly_printf(sc, "IDBR %02x ODBR %02x ERROR %02x (%x %x %x)\n", 253864987Smsmith MLY_GET_REG(sc, sc->mly_idbr), 253964987Smsmith MLY_GET_REG(sc, sc->mly_odbr), 254064987Smsmith MLY_GET_REG(sc, sc->mly_error_status), 254164987Smsmith sc->mly_idbr, 254264987Smsmith sc->mly_odbr, 254364987Smsmith sc->mly_error_status); 254464987Smsmith mly_printf(sc, "IMASK %02x ISTATUS %02x\n", 254564987Smsmith MLY_GET_REG(sc, sc->mly_interrupt_mask), 254664987Smsmith MLY_GET_REG(sc, sc->mly_interrupt_status)); 254764987Smsmith mly_printf(sc, "COMMAND %02x %02x %02x %02x %02x %02x %02x %02x\n", 254864987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox), 254964987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 1), 255064987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 2), 255164987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 3), 255264987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 4), 255364987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 5), 255464987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 6), 255564987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 7)); 255664987Smsmith mly_printf(sc, "STATUS %02x %02x %02x %02x %02x %02x %02x %02x\n", 255764987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox), 255864987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 1), 255964987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 2), 256064987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 3), 256164987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 4), 256264987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 5), 256364987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 6), 256464987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 7)); 256564987Smsmith mly_printf(sc, " %04x %08x\n", 256664987Smsmith MLY_GET_REG2(sc, sc->mly_status_mailbox), 256764987Smsmith MLY_GET_REG4(sc, sc->mly_status_mailbox + 4)); 256864987Smsmith} 256964987Smsmith 257064987Smsmithstruct mly_softc *mly_softc0 = NULL; 257164987Smsmithvoid 257264987Smsmithmly_printstate0(void) 257364987Smsmith{ 257464987Smsmith if (mly_softc0 != NULL) 257564987Smsmith mly_printstate(mly_softc0); 257664987Smsmith} 257764987Smsmith 257864987Smsmith/******************************************************************************** 257964987Smsmith * Print a command 258064987Smsmith */ 258164987Smsmithstatic void 258264987Smsmithmly_print_command(struct mly_command *mc) 258364987Smsmith{ 258464987Smsmith struct mly_softc *sc = mc->mc_sc; 258564987Smsmith 258664987Smsmith mly_printf(sc, "COMMAND @ %p\n", mc); 258764987Smsmith mly_printf(sc, " slot %d\n", mc->mc_slot); 258864987Smsmith mly_printf(sc, " status 0x%x\n", mc->mc_status); 258964987Smsmith mly_printf(sc, " sense len %d\n", mc->mc_sense); 259064987Smsmith mly_printf(sc, " resid %d\n", mc->mc_resid); 259164987Smsmith mly_printf(sc, " packet %p/0x%llx\n", mc->mc_packet, mc->mc_packetphys); 259264987Smsmith if (mc->mc_packet != NULL) 259364987Smsmith mly_print_packet(mc); 259464987Smsmith mly_printf(sc, " data %p/%d\n", mc->mc_data, mc->mc_length); 259573050Smsmith mly_printf(sc, " flags %b\n", mc->mc_flags, "\20\1busy\2complete\3slotted\4mapped\5datain\6dataout\n"); 259664987Smsmith mly_printf(sc, " complete %p\n", mc->mc_complete); 259764987Smsmith mly_printf(sc, " private %p\n", mc->mc_private); 259864987Smsmith} 259964987Smsmith 260064987Smsmith/******************************************************************************** 260164987Smsmith * Print a command packet 260264987Smsmith */ 260364987Smsmithstatic void 260464987Smsmithmly_print_packet(struct mly_command *mc) 260564987Smsmith{ 260664987Smsmith struct mly_softc *sc = mc->mc_sc; 260764987Smsmith struct mly_command_generic *ge = (struct mly_command_generic *)mc->mc_packet; 260864987Smsmith struct mly_command_scsi_small *ss = (struct mly_command_scsi_small *)mc->mc_packet; 260964987Smsmith struct mly_command_scsi_large *sl = (struct mly_command_scsi_large *)mc->mc_packet; 261064987Smsmith struct mly_command_ioctl *io = (struct mly_command_ioctl *)mc->mc_packet; 261164987Smsmith int transfer; 261264987Smsmith 261364987Smsmith mly_printf(sc, " command_id %d\n", ge->command_id); 261464987Smsmith mly_printf(sc, " opcode %d\n", ge->opcode); 261564987Smsmith mly_printf(sc, " command_control fua %d dpo %d est %d dd %s nas %d ddis %d\n", 261664987Smsmith ge->command_control.force_unit_access, 261764987Smsmith ge->command_control.disable_page_out, 261864987Smsmith ge->command_control.extended_sg_table, 261964987Smsmith (ge->command_control.data_direction == MLY_CCB_WRITE) ? "WRITE" : "READ", 262064987Smsmith ge->command_control.no_auto_sense, 262164987Smsmith ge->command_control.disable_disconnect); 262264987Smsmith mly_printf(sc, " data_size %d\n", ge->data_size); 262364987Smsmith mly_printf(sc, " sense_buffer_address 0x%llx\n", ge->sense_buffer_address); 262464987Smsmith mly_printf(sc, " lun %d\n", ge->addr.phys.lun); 262564987Smsmith mly_printf(sc, " target %d\n", ge->addr.phys.target); 262664987Smsmith mly_printf(sc, " channel %d\n", ge->addr.phys.channel); 262764987Smsmith mly_printf(sc, " logical device %d\n", ge->addr.log.logdev); 262864987Smsmith mly_printf(sc, " controller %d\n", ge->addr.phys.controller); 262964987Smsmith mly_printf(sc, " timeout %d %s\n", 263064987Smsmith ge->timeout.value, 263164987Smsmith (ge->timeout.scale == MLY_TIMEOUT_SECONDS) ? "seconds" : 263264987Smsmith ((ge->timeout.scale == MLY_TIMEOUT_MINUTES) ? "minutes" : "hours")); 263364987Smsmith mly_printf(sc, " maximum_sense_size %d\n", ge->maximum_sense_size); 263464987Smsmith switch(ge->opcode) { 263564987Smsmith case MDACMD_SCSIPT: 263664987Smsmith case MDACMD_SCSI: 263764987Smsmith mly_printf(sc, " cdb length %d\n", ss->cdb_length); 263864987Smsmith mly_printf(sc, " cdb %*D\n", ss->cdb_length, ss->cdb, " "); 263964987Smsmith transfer = 1; 264064987Smsmith break; 264164987Smsmith case MDACMD_SCSILC: 264264987Smsmith case MDACMD_SCSILCPT: 264364987Smsmith mly_printf(sc, " cdb length %d\n", sl->cdb_length); 264464987Smsmith mly_printf(sc, " cdb 0x%llx\n", sl->cdb_physaddr); 264564987Smsmith transfer = 1; 264664987Smsmith break; 264764987Smsmith case MDACMD_IOCTL: 264864987Smsmith mly_printf(sc, " sub_ioctl 0x%x\n", io->sub_ioctl); 264964987Smsmith switch(io->sub_ioctl) { 265064987Smsmith case MDACIOCTL_SETMEMORYMAILBOX: 265164987Smsmith mly_printf(sc, " health_buffer_size %d\n", 265264987Smsmith io->param.setmemorymailbox.health_buffer_size); 265364987Smsmith mly_printf(sc, " health_buffer_phys 0x%llx\n", 265464987Smsmith io->param.setmemorymailbox.health_buffer_physaddr); 265564987Smsmith mly_printf(sc, " command_mailbox 0x%llx\n", 265664987Smsmith io->param.setmemorymailbox.command_mailbox_physaddr); 265764987Smsmith mly_printf(sc, " status_mailbox 0x%llx\n", 265864987Smsmith io->param.setmemorymailbox.status_mailbox_physaddr); 265964987Smsmith transfer = 0; 266064987Smsmith break; 266164987Smsmith 266264987Smsmith case MDACIOCTL_SETREALTIMECLOCK: 266364987Smsmith case MDACIOCTL_GETHEALTHSTATUS: 266464987Smsmith case MDACIOCTL_GETCONTROLLERINFO: 266564987Smsmith case MDACIOCTL_GETLOGDEVINFOVALID: 266664987Smsmith case MDACIOCTL_GETPHYSDEVINFOVALID: 266764987Smsmith case MDACIOCTL_GETPHYSDEVSTATISTICS: 266864987Smsmith case MDACIOCTL_GETLOGDEVSTATISTICS: 266964987Smsmith case MDACIOCTL_GETCONTROLLERSTATISTICS: 267064987Smsmith case MDACIOCTL_GETBDT_FOR_SYSDRIVE: 267164987Smsmith case MDACIOCTL_CREATENEWCONF: 267264987Smsmith case MDACIOCTL_ADDNEWCONF: 267364987Smsmith case MDACIOCTL_GETDEVCONFINFO: 267464987Smsmith case MDACIOCTL_GETFREESPACELIST: 267564987Smsmith case MDACIOCTL_MORE: 267664987Smsmith case MDACIOCTL_SETPHYSDEVPARAMETER: 267764987Smsmith case MDACIOCTL_GETPHYSDEVPARAMETER: 267864987Smsmith case MDACIOCTL_GETLOGDEVPARAMETER: 267964987Smsmith case MDACIOCTL_SETLOGDEVPARAMETER: 268064987Smsmith mly_printf(sc, " param %10D\n", io->param.data.param, " "); 268164987Smsmith transfer = 1; 268264987Smsmith break; 268364987Smsmith 268464987Smsmith case MDACIOCTL_GETEVENT: 268564987Smsmith mly_printf(sc, " event %d\n", 268664987Smsmith io->param.getevent.sequence_number_low + ((u_int32_t)io->addr.log.logdev << 16)); 268764987Smsmith transfer = 1; 268864987Smsmith break; 268964987Smsmith 269064987Smsmith case MDACIOCTL_SETRAIDDEVSTATE: 269164987Smsmith mly_printf(sc, " state %d\n", io->param.setraiddevstate.state); 269264987Smsmith transfer = 0; 269364987Smsmith break; 269464987Smsmith 269564987Smsmith case MDACIOCTL_XLATEPHYSDEVTORAIDDEV: 269664987Smsmith mly_printf(sc, " raid_device %d\n", io->param.xlatephysdevtoraiddev.raid_device); 269764987Smsmith mly_printf(sc, " controller %d\n", io->param.xlatephysdevtoraiddev.controller); 269864987Smsmith mly_printf(sc, " channel %d\n", io->param.xlatephysdevtoraiddev.channel); 269964987Smsmith mly_printf(sc, " target %d\n", io->param.xlatephysdevtoraiddev.target); 270064987Smsmith mly_printf(sc, " lun %d\n", io->param.xlatephysdevtoraiddev.lun); 270164987Smsmith transfer = 0; 270264987Smsmith break; 270364987Smsmith 270464987Smsmith case MDACIOCTL_GETGROUPCONFINFO: 270564987Smsmith mly_printf(sc, " group %d\n", io->param.getgroupconfinfo.group); 270664987Smsmith transfer = 1; 270764987Smsmith break; 270864987Smsmith 270964987Smsmith case MDACIOCTL_GET_SUBSYSTEM_DATA: 271064987Smsmith case MDACIOCTL_SET_SUBSYSTEM_DATA: 271164987Smsmith case MDACIOCTL_STARTDISOCVERY: 271264987Smsmith case MDACIOCTL_INITPHYSDEVSTART: 271364987Smsmith case MDACIOCTL_INITPHYSDEVSTOP: 271464987Smsmith case MDACIOCTL_INITRAIDDEVSTART: 271564987Smsmith case MDACIOCTL_INITRAIDDEVSTOP: 271664987Smsmith case MDACIOCTL_REBUILDRAIDDEVSTART: 271764987Smsmith case MDACIOCTL_REBUILDRAIDDEVSTOP: 271864987Smsmith case MDACIOCTL_MAKECONSISTENTDATASTART: 271964987Smsmith case MDACIOCTL_MAKECONSISTENTDATASTOP: 272064987Smsmith case MDACIOCTL_CONSISTENCYCHECKSTART: 272164987Smsmith case MDACIOCTL_CONSISTENCYCHECKSTOP: 272264987Smsmith case MDACIOCTL_RESETDEVICE: 272364987Smsmith case MDACIOCTL_FLUSHDEVICEDATA: 272464987Smsmith case MDACIOCTL_PAUSEDEVICE: 272564987Smsmith case MDACIOCTL_UNPAUSEDEVICE: 272664987Smsmith case MDACIOCTL_LOCATEDEVICE: 272764987Smsmith case MDACIOCTL_SETMASTERSLAVEMODE: 272864987Smsmith case MDACIOCTL_DELETERAIDDEV: 272964987Smsmith case MDACIOCTL_REPLACEINTERNALDEV: 273064987Smsmith case MDACIOCTL_CLEARCONF: 273164987Smsmith case MDACIOCTL_GETCONTROLLERPARAMETER: 273264987Smsmith case MDACIOCTL_SETCONTRLLERPARAMETER: 273364987Smsmith case MDACIOCTL_CLEARCONFSUSPMODE: 273464987Smsmith case MDACIOCTL_STOREIMAGE: 273564987Smsmith case MDACIOCTL_READIMAGE: 273664987Smsmith case MDACIOCTL_FLASHIMAGES: 273764987Smsmith case MDACIOCTL_RENAMERAIDDEV: 273864987Smsmith default: /* no idea what to print */ 273964987Smsmith transfer = 0; 274064987Smsmith break; 274164987Smsmith } 274264987Smsmith break; 274364987Smsmith 274464987Smsmith case MDACMD_IOCTLCHECK: 274564987Smsmith case MDACMD_MEMCOPY: 274664987Smsmith default: 274764987Smsmith transfer = 0; 274864987Smsmith break; /* print nothing */ 274964987Smsmith } 275064987Smsmith if (transfer) { 275164987Smsmith if (ge->command_control.extended_sg_table) { 275264987Smsmith mly_printf(sc, " sg table 0x%llx/%d\n", 275364987Smsmith ge->transfer.indirect.table_physaddr[0], ge->transfer.indirect.entries[0]); 275464987Smsmith } else { 275564987Smsmith mly_printf(sc, " 0000 0x%llx/%lld\n", 275664987Smsmith ge->transfer.direct.sg[0].physaddr, ge->transfer.direct.sg[0].length); 275764987Smsmith mly_printf(sc, " 0001 0x%llx/%lld\n", 275864987Smsmith ge->transfer.direct.sg[1].physaddr, ge->transfer.direct.sg[1].length); 275964987Smsmith } 276064987Smsmith } 276164987Smsmith} 276264987Smsmith 276364987Smsmith/******************************************************************************** 276464987Smsmith * Panic in a slightly informative fashion 276564987Smsmith */ 276664987Smsmithstatic void 276764987Smsmithmly_panic(struct mly_softc *sc, char *reason) 276864987Smsmith{ 276964987Smsmith mly_printstate(sc); 277064987Smsmith panic(reason); 277164987Smsmith} 277273050Smsmith 277373050Smsmith/******************************************************************************** 277473050Smsmith * Print queue statistics, callable from DDB. 277573050Smsmith */ 277673050Smsmithvoid 277773050Smsmithmly_print_controller(int controller) 277873050Smsmith{ 277973050Smsmith struct mly_softc *sc; 278073050Smsmith 278173050Smsmith if ((sc = devclass_get_softc(devclass_find("mly"), controller)) == NULL) { 278273050Smsmith printf("mly: controller %d invalid\n", controller); 278373050Smsmith } else { 278473050Smsmith device_printf(sc->mly_dev, "queue curr max\n"); 278573050Smsmith device_printf(sc->mly_dev, "free %04d/%04d\n", 278673050Smsmith sc->mly_qstat[MLYQ_FREE].q_length, sc->mly_qstat[MLYQ_FREE].q_max); 278773050Smsmith device_printf(sc->mly_dev, "busy %04d/%04d\n", 278873050Smsmith sc->mly_qstat[MLYQ_BUSY].q_length, sc->mly_qstat[MLYQ_BUSY].q_max); 278973050Smsmith device_printf(sc->mly_dev, "complete %04d/%04d\n", 279073050Smsmith sc->mly_qstat[MLYQ_COMPLETE].q_length, sc->mly_qstat[MLYQ_COMPLETE].q_max); 279173050Smsmith } 279273050Smsmith} 279379695Smsmith#endif 279473050Smsmith 279573050Smsmith 279673050Smsmith/******************************************************************************** 279773050Smsmith ******************************************************************************** 279873050Smsmith Control device interface 279973050Smsmith ******************************************************************************** 280073050Smsmith ********************************************************************************/ 280173050Smsmith 280273050Smsmith/******************************************************************************** 280373050Smsmith * Accept an open operation on the control device. 280473050Smsmith */ 280573050Smsmithstatic int 2806130585Sphkmly_user_open(struct cdev *dev, int flags, int fmt, struct thread *td) 280773050Smsmith{ 2808191242Sed struct mly_softc *sc = dev->si_drv1; 280973050Smsmith 281073050Smsmith sc->mly_state |= MLY_STATE_OPEN; 281173050Smsmith return(0); 281273050Smsmith} 281373050Smsmith 281473050Smsmith/******************************************************************************** 281573050Smsmith * Accept the last close on the control device. 281673050Smsmith */ 281773050Smsmithstatic int 2818130585Sphkmly_user_close(struct cdev *dev, int flags, int fmt, struct thread *td) 281973050Smsmith{ 2820191242Sed struct mly_softc *sc = dev->si_drv1; 282173050Smsmith 282273050Smsmith sc->mly_state &= ~MLY_STATE_OPEN; 282373050Smsmith return (0); 282473050Smsmith} 282573050Smsmith 282673050Smsmith/******************************************************************************** 282773050Smsmith * Handle controller-specific control operations. 282873050Smsmith */ 282973050Smsmithstatic int 2830130585Sphkmly_user_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 283183366Sjulian int32_t flag, struct thread *td) 283273050Smsmith{ 283373050Smsmith struct mly_softc *sc = (struct mly_softc *)dev->si_drv1; 283473050Smsmith struct mly_user_command *uc = (struct mly_user_command *)addr; 283573050Smsmith struct mly_user_health *uh = (struct mly_user_health *)addr; 283673050Smsmith 283773050Smsmith switch(cmd) { 283873050Smsmith case MLYIO_COMMAND: 283973050Smsmith return(mly_user_command(sc, uc)); 284073050Smsmith case MLYIO_HEALTH: 284173050Smsmith return(mly_user_health(sc, uh)); 284273050Smsmith default: 284373050Smsmith return(ENOIOCTL); 284473050Smsmith } 284573050Smsmith} 284673050Smsmith 284773050Smsmith/******************************************************************************** 284873050Smsmith * Execute a command passed in from userspace. 284973050Smsmith * 285073050Smsmith * The control structure contains the actual command for the controller, as well 285173050Smsmith * as the user-space data pointer and data size, and an optional sense buffer 285273050Smsmith * size/pointer. On completion, the data size is adjusted to the command 285373050Smsmith * residual, and the sense buffer size to the size of the returned sense data. 285473050Smsmith * 285573050Smsmith */ 285673050Smsmithstatic int 285773050Smsmithmly_user_command(struct mly_softc *sc, struct mly_user_command *uc) 285873050Smsmith{ 285979695Smsmith struct mly_command *mc; 286079695Smsmith int error, s; 286173050Smsmith 286273050Smsmith /* allocate a command */ 286373050Smsmith if (mly_alloc_command(sc, &mc)) { 286473050Smsmith error = ENOMEM; 286573050Smsmith goto out; /* XXX Linux version will wait for a command */ 286673050Smsmith } 286773050Smsmith 286873050Smsmith /* handle data size/direction */ 286973050Smsmith mc->mc_length = (uc->DataTransferLength >= 0) ? uc->DataTransferLength : -uc->DataTransferLength; 287073050Smsmith if (mc->mc_length > 0) { 287173050Smsmith if ((mc->mc_data = malloc(mc->mc_length, M_DEVBUF, M_NOWAIT)) == NULL) { 287273050Smsmith error = ENOMEM; 287373050Smsmith goto out; 287473050Smsmith } 287573050Smsmith } 287673050Smsmith if (uc->DataTransferLength > 0) { 287773050Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 287873050Smsmith bzero(mc->mc_data, mc->mc_length); 287973050Smsmith } 288073050Smsmith if (uc->DataTransferLength < 0) { 288173050Smsmith mc->mc_flags |= MLY_CMD_DATAOUT; 288273050Smsmith if ((error = copyin(uc->DataTransferBuffer, mc->mc_data, mc->mc_length)) != 0) 288373050Smsmith goto out; 288473050Smsmith } 288573050Smsmith 288673050Smsmith /* copy the controller command */ 288773050Smsmith bcopy(&uc->CommandMailbox, mc->mc_packet, sizeof(uc->CommandMailbox)); 288873050Smsmith 288973050Smsmith /* clear command completion handler so that we get woken up */ 289073050Smsmith mc->mc_complete = NULL; 289173050Smsmith 289273050Smsmith /* execute the command */ 289379695Smsmith if ((error = mly_start(mc)) != 0) 289479695Smsmith goto out; 289573050Smsmith s = splcam(); 289673050Smsmith while (!(mc->mc_flags & MLY_CMD_COMPLETE)) 289773050Smsmith tsleep(mc, PRIBIO, "mlyioctl", 0); 289873050Smsmith splx(s); 289973050Smsmith 290073050Smsmith /* return the data to userspace */ 290173050Smsmith if (uc->DataTransferLength > 0) 290273050Smsmith if ((error = copyout(mc->mc_data, uc->DataTransferBuffer, mc->mc_length)) != 0) 290373050Smsmith goto out; 290473050Smsmith 290573050Smsmith /* return the sense buffer to userspace */ 290673050Smsmith if ((uc->RequestSenseLength > 0) && (mc->mc_sense > 0)) { 290773050Smsmith if ((error = copyout(mc->mc_packet, uc->RequestSenseBuffer, 290873050Smsmith min(uc->RequestSenseLength, mc->mc_sense))) != 0) 290973050Smsmith goto out; 291073050Smsmith } 291173050Smsmith 291273050Smsmith /* return command results to userspace (caller will copy out) */ 291373050Smsmith uc->DataTransferLength = mc->mc_resid; 291473050Smsmith uc->RequestSenseLength = min(uc->RequestSenseLength, mc->mc_sense); 291573050Smsmith uc->CommandStatus = mc->mc_status; 291673050Smsmith error = 0; 291773050Smsmith 291873050Smsmith out: 291973050Smsmith if (mc->mc_data != NULL) 292073050Smsmith free(mc->mc_data, M_DEVBUF); 292173050Smsmith if (mc != NULL) 292273050Smsmith mly_release_command(mc); 292373050Smsmith return(error); 292473050Smsmith} 292573050Smsmith 292673050Smsmith/******************************************************************************** 292773050Smsmith * Return health status to userspace. If the health change index in the user 292873050Smsmith * structure does not match that currently exported by the controller, we 292973050Smsmith * return the current status immediately. Otherwise, we block until either 293073050Smsmith * interrupted or new status is delivered. 293173050Smsmith */ 293273050Smsmithstatic int 293373050Smsmithmly_user_health(struct mly_softc *sc, struct mly_user_health *uh) 293473050Smsmith{ 293573050Smsmith struct mly_health_status mh; 293673050Smsmith int error, s; 293773050Smsmith 293873050Smsmith /* fetch the current health status from userspace */ 293973050Smsmith if ((error = copyin(uh->HealthStatusBuffer, &mh, sizeof(mh))) != 0) 294073050Smsmith return(error); 294173050Smsmith 294273050Smsmith /* spin waiting for a status update */ 294373050Smsmith s = splcam(); 294473050Smsmith error = EWOULDBLOCK; 294573050Smsmith while ((error != 0) && (sc->mly_event_change == mh.change_counter)) 294673050Smsmith error = tsleep(&sc->mly_event_change, PRIBIO | PCATCH, "mlyhealth", 0); 294773050Smsmith splx(s); 294873050Smsmith 294973050Smsmith /* copy the controller's health status buffer out (there is a race here if it changes again) */ 295073050Smsmith error = copyout(&sc->mly_mmbox->mmm_health.status, uh->HealthStatusBuffer, 295173050Smsmith sizeof(uh->HealthStatusBuffer)); 295273050Smsmith return(error); 295373050Smsmith} 2954110479Sscottl 2955201795Strasz#ifdef MLY_DEBUG 2956110479Sscottlstatic int 2957110479Sscottlmly_timeout(struct mly_softc *sc) 2958110479Sscottl{ 2959110479Sscottl struct mly_command *mc; 2960110479Sscottl int deadline; 2961110479Sscottl 2962110479Sscottl deadline = time_second - MLY_CMD_TIMEOUT; 2963110479Sscottl TAILQ_FOREACH(mc, &sc->mly_busy, mc_link) { 2964110479Sscottl if ((mc->mc_timestamp < deadline)) { 2965110479Sscottl device_printf(sc->mly_dev, 2966110479Sscottl "COMMAND %p TIMEOUT AFTER %d SECONDS\n", mc, 2967110479Sscottl (int)(time_second - mc->mc_timestamp)); 2968110479Sscottl } 2969110479Sscottl } 2970110479Sscottl 2971110479Sscottl timeout((timeout_t *)mly_timeout, sc, MLY_CMD_TIMEOUT * hz); 2972110479Sscottl 2973110479Sscottl return (0); 2974110479Sscottl} 2975201795Strasz#endif 2976