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: stable/11/sys/dev/mly/mly.c 335138 2018-06-14 14:46:20Z 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); 91274677Sjhbstatic void mly_complete(struct mly_softc *sc); 92274677Sjhbstatic void mly_complete_handler(void *context, int pending); 9364987Smsmith 9479695Smsmithstatic int mly_alloc_command(struct mly_softc *sc, struct mly_command **mcp); 9579695Smsmithstatic void mly_release_command(struct mly_command *mc); 9673050Smsmithstatic void mly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error); 9773050Smsmithstatic int mly_alloc_commands(struct mly_softc *sc); 9879695Smsmithstatic void mly_release_commands(struct mly_softc *sc); 9964987Smsmithstatic void mly_map_command(struct mly_command *mc); 10064987Smsmithstatic void mly_unmap_command(struct mly_command *mc); 10164987Smsmith 10279695Smsmithstatic int mly_cam_attach(struct mly_softc *sc); 10379695Smsmithstatic void mly_cam_detach(struct mly_softc *sc); 10479695Smsmithstatic void mly_cam_rescan_btl(struct mly_softc *sc, int bus, int target); 10579695Smsmithstatic void mly_cam_action(struct cam_sim *sim, union ccb *ccb); 10679695Smsmithstatic int mly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio); 10779695Smsmithstatic void mly_cam_poll(struct cam_sim *sim); 10879695Smsmithstatic void mly_cam_complete(struct mly_command *mc); 10979695Smsmithstatic struct cam_periph *mly_find_periph(struct mly_softc *sc, int bus, int target); 11079695Smsmithstatic int mly_name_device(struct mly_softc *sc, int bus, int target); 11179695Smsmith 11264987Smsmithstatic int mly_fwhandshake(struct mly_softc *sc); 11364987Smsmith 11464987Smsmithstatic void mly_describe_controller(struct mly_softc *sc); 11564987Smsmith#ifdef MLY_DEBUG 11664987Smsmithstatic void mly_printstate(struct mly_softc *sc); 11764987Smsmithstatic void mly_print_command(struct mly_command *mc); 11864987Smsmithstatic void mly_print_packet(struct mly_command *mc); 11964987Smsmithstatic void mly_panic(struct mly_softc *sc, char *reason); 120274677Sjhbstatic void mly_timeout(void *arg); 12164987Smsmith#endif 12273050Smsmithvoid mly_print_controller(int controller); 12364987Smsmith 12479695Smsmith 12573050Smsmithstatic d_open_t mly_user_open; 12673050Smsmithstatic d_close_t mly_user_close; 12773050Smsmithstatic d_ioctl_t mly_user_ioctl; 12873050Smsmithstatic int mly_user_command(struct mly_softc *sc, struct mly_user_command *uc); 12973050Smsmithstatic int mly_user_health(struct mly_softc *sc, struct mly_user_health *uh); 13073050Smsmith 131110479Sscottl#define MLY_CMD_TIMEOUT 20 13279695Smsmith 13379695Smsmithstatic device_method_t mly_methods[] = { 13479695Smsmith /* Device interface */ 13579695Smsmith DEVMETHOD(device_probe, mly_probe), 13679695Smsmith DEVMETHOD(device_attach, mly_attach), 13779695Smsmith DEVMETHOD(device_detach, mly_detach), 13879695Smsmith DEVMETHOD(device_shutdown, mly_shutdown), 13979695Smsmith { 0, 0 } 14079695Smsmith}; 14179695Smsmith 14279695Smsmithstatic driver_t mly_pci_driver = { 14379695Smsmith "mly", 14479695Smsmith mly_methods, 14579695Smsmith sizeof(struct mly_softc) 14679695Smsmith}; 14779695Smsmith 14879695Smsmithstatic devclass_t mly_devclass; 14979695SmsmithDRIVER_MODULE(mly, pci, mly_pci_driver, mly_devclass, 0, 0); 150165102SmjacobMODULE_DEPEND(mly, pci, 1, 1, 1); 151165102SmjacobMODULE_DEPEND(mly, cam, 1, 1, 1); 15279695Smsmith 15373050Smsmithstatic struct cdevsw mly_cdevsw = { 154126080Sphk .d_version = D_VERSION, 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; 219274677Sjhb mtx_init(&sc->mly_lock, "mly", NULL, MTX_DEF); 220274677Sjhb callout_init_mtx(&sc->mly_periodic, &sc->mly_lock, 0); 22179695Smsmith 22279695Smsmith#ifdef MLY_DEBUG 223274677Sjhb callout_init_mtx(&sc->mly_timeout, &sc->mly_lock, 0); 22479695Smsmith if (device_get_unit(sc->mly_dev) == 0) 22579695Smsmith mly_softc0 = sc; 22679695Smsmith#endif 22779695Smsmith 22864987Smsmith /* 22979695Smsmith * Do PCI-specific initialisation. 23079695Smsmith */ 23179695Smsmith if ((error = mly_pci_attach(sc)) != 0) 23279695Smsmith goto out; 23379695Smsmith 23479695Smsmith /* 23564987Smsmith * Initialise per-controller queues. 23664987Smsmith */ 23773050Smsmith mly_initq_free(sc); 23873050Smsmith mly_initq_busy(sc); 23973050Smsmith mly_initq_complete(sc); 24064987Smsmith 24164987Smsmith /* 24264987Smsmith * Initialise command-completion task. 24364987Smsmith */ 244274677Sjhb TASK_INIT(&sc->mly_task_complete, 0, mly_complete_handler, sc); 24564987Smsmith 24664987Smsmith /* disable interrupts before we start talking to the controller */ 24764987Smsmith MLY_MASK_INTERRUPTS(sc); 24864987Smsmith 24964987Smsmith /* 25064987Smsmith * Wait for the controller to come ready, handshake with the firmware if required. 25164987Smsmith * This is typically only necessary on platforms where the controller BIOS does not 25264987Smsmith * run. 25364987Smsmith */ 25464987Smsmith if ((error = mly_fwhandshake(sc))) 25579695Smsmith goto out; 25664987Smsmith 25764987Smsmith /* 25879695Smsmith * Allocate initial command buffers. 25964987Smsmith */ 26073050Smsmith if ((error = mly_alloc_commands(sc))) 26179695Smsmith goto out; 26264987Smsmith 26364987Smsmith /* 26464987Smsmith * Obtain controller feature information 26564987Smsmith */ 266274677Sjhb MLY_LOCK(sc); 267274677Sjhb error = mly_get_controllerinfo(sc); 268274677Sjhb MLY_UNLOCK(sc); 269274677Sjhb if (error) 27079695Smsmith goto out; 27164987Smsmith 27264987Smsmith /* 27379695Smsmith * Reallocate command buffers now we know how many we want. 27479695Smsmith */ 27579695Smsmith mly_release_commands(sc); 27679695Smsmith if ((error = mly_alloc_commands(sc))) 27779695Smsmith goto out; 27879695Smsmith 27979695Smsmith /* 28064987Smsmith * Get the current event counter for health purposes, populate the initial 28164987Smsmith * health status buffer. 28264987Smsmith */ 283274677Sjhb MLY_LOCK(sc); 284274677Sjhb error = mly_get_eventstatus(sc); 28564987Smsmith 28664987Smsmith /* 28779695Smsmith * Enable memory-mailbox mode. 28864987Smsmith */ 289274677Sjhb if (error == 0) 290274677Sjhb error = mly_enable_mmbox(sc); 291274677Sjhb MLY_UNLOCK(sc); 292274677Sjhb if (error) 29379695Smsmith goto out; 29464987Smsmith 29564987Smsmith /* 29664987Smsmith * Attach to CAM. 29764987Smsmith */ 29864987Smsmith if ((error = mly_cam_attach(sc))) 29979695Smsmith goto out; 30064987Smsmith 30164987Smsmith /* 30264987Smsmith * Print a little information about the controller 30364987Smsmith */ 30464987Smsmith mly_describe_controller(sc); 30564987Smsmith 30664987Smsmith /* 30779695Smsmith * Mark all attached devices for rescan. 30864987Smsmith */ 309274677Sjhb MLY_LOCK(sc); 31064987Smsmith mly_scan_devices(sc); 31164987Smsmith 31264987Smsmith /* 31364987Smsmith * Instigate the first status poll immediately. Rescan completions won't 31464987Smsmith * happen until interrupts are enabled, which should still be before 31579695Smsmith * the SCSI subsystem gets to us, courtesy of the "SCSI settling delay". 31664987Smsmith */ 31764987Smsmith mly_periodic((void *)sc); 318274677Sjhb MLY_UNLOCK(sc); 31964987Smsmith 32073050Smsmith /* 32173050Smsmith * Create the control device. 32273050Smsmith */ 323191242Sed sc->mly_dev_t = make_dev(&mly_cdevsw, 0, UID_ROOT, GID_OPERATOR, 32473050Smsmith S_IRUSR | S_IWUSR, "mly%d", device_get_unit(sc->mly_dev)); 32573050Smsmith sc->mly_dev_t->si_drv1 = sc; 32673050Smsmith 32764987Smsmith /* enable interrupts now */ 32864987Smsmith MLY_UNMASK_INTERRUPTS(sc); 32964987Smsmith 330110479Sscottl#ifdef MLY_DEBUG 331274677Sjhb callout_reset(&sc->mly_timeout, MLY_CMD_TIMEOUT * hz, mly_timeout, sc); 332110479Sscottl#endif 333110479Sscottl 33479695Smsmith out: 33579695Smsmith if (error != 0) 33679695Smsmith mly_free(sc); 33779695Smsmith return(error); 33879695Smsmith} 33979695Smsmith 34079695Smsmith/******************************************************************************** 34179695Smsmith * Perform PCI-specific initialisation. 34279695Smsmith */ 34379695Smsmithstatic int 34479695Smsmithmly_pci_attach(struct mly_softc *sc) 34579695Smsmith{ 34679695Smsmith int i, error; 34779695Smsmith 34879695Smsmith debug_called(1); 34979695Smsmith 35079695Smsmith /* assume failure is 'not configured' */ 35179695Smsmith error = ENXIO; 35279695Smsmith 35379695Smsmith /* 35479695Smsmith * Verify that the adapter is correctly set up in PCI space. 35579695Smsmith */ 356254263Sscottl pci_enable_busmaster(sc->mly_dev); 35779695Smsmith 35879695Smsmith /* 35979695Smsmith * Allocate the PCI register window. 36079695Smsmith */ 361119690Sjhb sc->mly_regs_rid = PCIR_BAR(0); /* first base address register */ 362127135Snjl if ((sc->mly_regs_resource = bus_alloc_resource_any(sc->mly_dev, 363127135Snjl SYS_RES_MEMORY, &sc->mly_regs_rid, RF_ACTIVE)) == NULL) { 36479695Smsmith mly_printf(sc, "can't allocate register window\n"); 36579695Smsmith goto fail; 36679695Smsmith } 36779695Smsmith 36879695Smsmith /* 36979695Smsmith * Allocate and connect our interrupt. 37079695Smsmith */ 37179695Smsmith sc->mly_irq_rid = 0; 372127135Snjl if ((sc->mly_irq = bus_alloc_resource_any(sc->mly_dev, SYS_RES_IRQ, 373127135Snjl &sc->mly_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 37479695Smsmith mly_printf(sc, "can't allocate interrupt\n"); 37579695Smsmith goto fail; 37679695Smsmith } 377274677Sjhb if (bus_setup_intr(sc->mly_dev, sc->mly_irq, INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, mly_intr, sc, &sc->mly_intr)) { 37879695Smsmith mly_printf(sc, "can't set up interrupt\n"); 37979695Smsmith goto fail; 38079695Smsmith } 38179695Smsmith 38279695Smsmith /* assume failure is 'out of memory' */ 38379695Smsmith error = ENOMEM; 38479695Smsmith 38579695Smsmith /* 38679695Smsmith * Allocate the parent bus DMA tag appropriate for our PCI interface. 38779695Smsmith * 38879695Smsmith * Note that all of these controllers are 64-bit capable. 38979695Smsmith */ 390232854Sscottl if (bus_dma_tag_create(bus_get_dma_tag(sc->mly_dev),/* PCI parent */ 39179695Smsmith 1, 0, /* alignment, boundary */ 39279695Smsmith BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 39379695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 39479695Smsmith NULL, NULL, /* filter, filterarg */ 395280347Smav BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 396280347Smav BUS_SPACE_UNRESTRICTED, /* nsegments */ 39779695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 39879695Smsmith BUS_DMA_ALLOCNOW, /* flags */ 399117126Sscottl NULL, /* lockfunc */ 400117126Sscottl NULL, /* lockarg */ 40179695Smsmith &sc->mly_parent_dmat)) { 40279695Smsmith mly_printf(sc, "can't allocate parent DMA tag\n"); 40379695Smsmith goto fail; 40479695Smsmith } 40579695Smsmith 40679695Smsmith /* 40779695Smsmith * Create DMA tag for mapping buffers into controller-addressable space. 40879695Smsmith */ 40979695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 41079695Smsmith 1, 0, /* alignment, boundary */ 41179695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 41279695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 41379695Smsmith NULL, NULL, /* filter, filterarg */ 414280347Smav DFLTPHYS, /* maxsize */ 415280347Smav MLY_MAX_SGENTRIES, /* nsegments */ 41679695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 41779695Smsmith 0, /* flags */ 418117126Sscottl busdma_lock_mutex, /* lockfunc */ 419274677Sjhb &sc->mly_lock, /* lockarg */ 42079695Smsmith &sc->mly_buffer_dmat)) { 42179695Smsmith mly_printf(sc, "can't allocate buffer DMA tag\n"); 42279695Smsmith goto fail; 42379695Smsmith } 42479695Smsmith 42579695Smsmith /* 42679695Smsmith * Initialise the DMA tag for command packets. 42779695Smsmith */ 42879695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 42979695Smsmith 1, 0, /* alignment, boundary */ 43079695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 43179695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 43279695Smsmith NULL, NULL, /* filter, filterarg */ 43379695Smsmith sizeof(union mly_command_packet) * MLY_MAX_COMMANDS, 1, /* maxsize, nsegments */ 43479695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 435118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 436118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 43779695Smsmith &sc->mly_packet_dmat)) { 43879695Smsmith mly_printf(sc, "can't allocate command packet DMA tag\n"); 43979695Smsmith goto fail; 44079695Smsmith } 44179695Smsmith 44279695Smsmith /* 44379695Smsmith * Detect the hardware interface version 44479695Smsmith */ 44579695Smsmith for (i = 0; mly_identifiers[i].vendor != 0; i++) { 44679695Smsmith if ((mly_identifiers[i].vendor == pci_get_vendor(sc->mly_dev)) && 44779695Smsmith (mly_identifiers[i].device == pci_get_device(sc->mly_dev))) { 44879695Smsmith sc->mly_hwif = mly_identifiers[i].hwif; 44979695Smsmith switch(sc->mly_hwif) { 45079695Smsmith case MLY_HWIF_I960RX: 45179695Smsmith debug(1, "set hardware up for i960RX"); 45279695Smsmith sc->mly_doorbell_true = 0x00; 45379695Smsmith sc->mly_command_mailbox = MLY_I960RX_COMMAND_MAILBOX; 45479695Smsmith sc->mly_status_mailbox = MLY_I960RX_STATUS_MAILBOX; 45579695Smsmith sc->mly_idbr = MLY_I960RX_IDBR; 45679695Smsmith sc->mly_odbr = MLY_I960RX_ODBR; 45779695Smsmith sc->mly_error_status = MLY_I960RX_ERROR_STATUS; 45879695Smsmith sc->mly_interrupt_status = MLY_I960RX_INTERRUPT_STATUS; 45979695Smsmith sc->mly_interrupt_mask = MLY_I960RX_INTERRUPT_MASK; 46079695Smsmith break; 46179695Smsmith case MLY_HWIF_STRONGARM: 46279695Smsmith debug(1, "set hardware up for StrongARM"); 46379695Smsmith sc->mly_doorbell_true = 0xff; /* doorbell 'true' is 0 */ 46479695Smsmith sc->mly_command_mailbox = MLY_STRONGARM_COMMAND_MAILBOX; 46579695Smsmith sc->mly_status_mailbox = MLY_STRONGARM_STATUS_MAILBOX; 46679695Smsmith sc->mly_idbr = MLY_STRONGARM_IDBR; 46779695Smsmith sc->mly_odbr = MLY_STRONGARM_ODBR; 46879695Smsmith sc->mly_error_status = MLY_STRONGARM_ERROR_STATUS; 46979695Smsmith sc->mly_interrupt_status = MLY_STRONGARM_INTERRUPT_STATUS; 47079695Smsmith sc->mly_interrupt_mask = MLY_STRONGARM_INTERRUPT_MASK; 47179695Smsmith break; 47279695Smsmith } 47379695Smsmith break; 47479695Smsmith } 47579695Smsmith } 47679695Smsmith 47779695Smsmith /* 47879695Smsmith * Create the scatter/gather mappings. 47979695Smsmith */ 48079695Smsmith if ((error = mly_sg_map(sc))) 48179695Smsmith goto fail; 48279695Smsmith 48379695Smsmith /* 48479695Smsmith * Allocate and map the memory mailbox 48579695Smsmith */ 48679695Smsmith if ((error = mly_mmbox_map(sc))) 48779695Smsmith goto fail; 48879695Smsmith 48979695Smsmith error = 0; 49079695Smsmith 49179695Smsmithfail: 49279695Smsmith return(error); 49379695Smsmith} 49479695Smsmith 49579695Smsmith/******************************************************************************** 49679695Smsmith * Shut the controller down and detach all our resources. 49779695Smsmith */ 49879695Smsmithstatic int 49979695Smsmithmly_detach(device_t dev) 50079695Smsmith{ 50179695Smsmith int error; 50279695Smsmith 50379695Smsmith if ((error = mly_shutdown(dev)) != 0) 50479695Smsmith return(error); 50579695Smsmith 50679695Smsmith mly_free(device_get_softc(dev)); 50764987Smsmith return(0); 50864987Smsmith} 50964987Smsmith 51064987Smsmith/******************************************************************************** 51164987Smsmith * Bring the controller to a state where it can be safely left alone. 51279695Smsmith * 51379695Smsmith * Note that it should not be necessary to wait for any outstanding commands, 51479695Smsmith * as they should be completed prior to calling here. 51579695Smsmith * 51679695Smsmith * XXX this applies for I/O, but not status polls; we should beware of 51779695Smsmith * the case where a status command is running while we detach. 51864987Smsmith */ 51979695Smsmithstatic int 52079695Smsmithmly_shutdown(device_t dev) 52164987Smsmith{ 52279695Smsmith struct mly_softc *sc = device_get_softc(dev); 52364987Smsmith 52464987Smsmith debug_called(1); 525274677Sjhb 526274677Sjhb MLY_LOCK(sc); 527274677Sjhb if (sc->mly_state & MLY_STATE_OPEN) { 528274677Sjhb MLY_UNLOCK(sc); 52979695Smsmith return(EBUSY); 530274677Sjhb } 53164987Smsmith 53264987Smsmith /* kill the periodic event */ 533274677Sjhb callout_stop(&sc->mly_periodic); 534274677Sjhb#ifdef MLY_DEBUG 535274677Sjhb callout_stop(&sc->mly_timeout); 536274677Sjhb#endif 53764987Smsmith 53864987Smsmith /* flush controller */ 53964987Smsmith mly_printf(sc, "flushing cache..."); 54064987Smsmith printf("%s\n", mly_flush(sc) ? "failed" : "done"); 54164987Smsmith 54264987Smsmith MLY_MASK_INTERRUPTS(sc); 543274677Sjhb MLY_UNLOCK(sc); 54479695Smsmith 54579695Smsmith return(0); 54664987Smsmith} 54764987Smsmith 54879695Smsmith/******************************************************************************* 54979695Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 55079695Smsmith * status. 55179695Smsmith */ 55279695Smsmithstatic void 55379695Smsmithmly_intr(void *arg) 55479695Smsmith{ 55579695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 55679695Smsmith 55779695Smsmith debug_called(2); 55879695Smsmith 559274677Sjhb MLY_LOCK(sc); 56079695Smsmith mly_done(sc); 561274677Sjhb MLY_UNLOCK(sc); 56279695Smsmith}; 56379695Smsmith 56464987Smsmith/******************************************************************************** 56564987Smsmith ******************************************************************************** 56679695Smsmith Bus-dependant Resource Management 56779695Smsmith ******************************************************************************** 56879695Smsmith ********************************************************************************/ 56979695Smsmith 57079695Smsmith/******************************************************************************** 57179695Smsmith * Allocate memory for the scatter/gather tables 57279695Smsmith */ 57379695Smsmithstatic int 57479695Smsmithmly_sg_map(struct mly_softc *sc) 57579695Smsmith{ 57679695Smsmith size_t segsize; 57779695Smsmith 57879695Smsmith debug_called(1); 57979695Smsmith 58079695Smsmith /* 58179695Smsmith * Create a single tag describing a region large enough to hold all of 58279695Smsmith * the s/g lists we will need. 58379695Smsmith */ 584118762Sscottl segsize = sizeof(struct mly_sg_entry) * MLY_MAX_COMMANDS *MLY_MAX_SGENTRIES; 58579695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 586118762Sscottl 1, 0, /* alignment,boundary */ 58779695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 58879695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 58979695Smsmith NULL, NULL, /* filter, filterarg */ 59079695Smsmith segsize, 1, /* maxsize, nsegments */ 59179695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 592118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 593118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 59479695Smsmith &sc->mly_sg_dmat)) { 59579695Smsmith mly_printf(sc, "can't allocate scatter/gather DMA tag\n"); 59679695Smsmith return(ENOMEM); 59779695Smsmith } 59879695Smsmith 59979695Smsmith /* 60079695Smsmith * Allocate enough s/g maps for all commands and permanently map them into 60179695Smsmith * controller-visible space. 60279695Smsmith * 60379695Smsmith * XXX this assumes we can get enough space for all the s/g maps in one 60479695Smsmith * contiguous slab. 60579695Smsmith */ 606118762Sscottl if (bus_dmamem_alloc(sc->mly_sg_dmat, (void **)&sc->mly_sg_table, 607118762Sscottl BUS_DMA_NOWAIT, &sc->mly_sg_dmamap)) { 60879695Smsmith mly_printf(sc, "can't allocate s/g table\n"); 60979695Smsmith return(ENOMEM); 61079695Smsmith } 611118762Sscottl if (bus_dmamap_load(sc->mly_sg_dmat, sc->mly_sg_dmamap, sc->mly_sg_table, 612118762Sscottl segsize, mly_sg_map_helper, sc, BUS_DMA_NOWAIT) != 0) 613118762Sscottl return (ENOMEM); 61479695Smsmith return(0); 61579695Smsmith} 61679695Smsmith 61779695Smsmith/******************************************************************************** 61879695Smsmith * Save the physical address of the base of the s/g table. 61979695Smsmith */ 62079695Smsmithstatic void 62179695Smsmithmly_sg_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 62279695Smsmith{ 62379695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 62479695Smsmith 62579695Smsmith debug_called(1); 62679695Smsmith 62779695Smsmith /* save base of s/g table's address in bus space */ 62879695Smsmith sc->mly_sg_busaddr = segs->ds_addr; 62979695Smsmith} 63079695Smsmith 63179695Smsmith/******************************************************************************** 63279695Smsmith * Allocate memory for the memory-mailbox interface 63379695Smsmith */ 63479695Smsmithstatic int 63579695Smsmithmly_mmbox_map(struct mly_softc *sc) 63679695Smsmith{ 63779695Smsmith 63879695Smsmith /* 63979695Smsmith * Create a DMA tag for a single contiguous region large enough for the 64079695Smsmith * memory mailbox structure. 64179695Smsmith */ 64279695Smsmith if (bus_dma_tag_create(sc->mly_parent_dmat, /* parent */ 643118762Sscottl 1, 0, /* alignment,boundary */ 64479695Smsmith BUS_SPACE_MAXADDR, /* lowaddr */ 64579695Smsmith BUS_SPACE_MAXADDR, /* highaddr */ 64679695Smsmith NULL, NULL, /* filter, filterarg */ 64779695Smsmith sizeof(struct mly_mmbox), 1, /* maxsize, nsegments */ 64879695Smsmith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 649118762Sscottl BUS_DMA_ALLOCNOW, /* flags */ 650118762Sscottl NULL, NULL, /* lockfunc, lockarg */ 65179695Smsmith &sc->mly_mmbox_dmat)) { 65279695Smsmith mly_printf(sc, "can't allocate memory mailbox DMA tag\n"); 65379695Smsmith return(ENOMEM); 65479695Smsmith } 65579695Smsmith 65679695Smsmith /* 65779695Smsmith * Allocate the buffer 65879695Smsmith */ 65979695Smsmith if (bus_dmamem_alloc(sc->mly_mmbox_dmat, (void **)&sc->mly_mmbox, BUS_DMA_NOWAIT, &sc->mly_mmbox_dmamap)) { 66079695Smsmith mly_printf(sc, "can't allocate memory mailbox\n"); 66179695Smsmith return(ENOMEM); 66279695Smsmith } 663118762Sscottl if (bus_dmamap_load(sc->mly_mmbox_dmat, sc->mly_mmbox_dmamap, sc->mly_mmbox, 664118762Sscottl sizeof(struct mly_mmbox), mly_mmbox_map_helper, sc, 665118762Sscottl BUS_DMA_NOWAIT) != 0) 666118762Sscottl return (ENOMEM); 66779695Smsmith bzero(sc->mly_mmbox, sizeof(*sc->mly_mmbox)); 66879695Smsmith return(0); 66979695Smsmith 67079695Smsmith} 67179695Smsmith 67279695Smsmith/******************************************************************************** 67379695Smsmith * Save the physical address of the memory mailbox 67479695Smsmith */ 67579695Smsmithstatic void 67679695Smsmithmly_mmbox_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 67779695Smsmith{ 67879695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 67979695Smsmith 68079695Smsmith debug_called(1); 68179695Smsmith 68279695Smsmith sc->mly_mmbox_busaddr = segs->ds_addr; 68379695Smsmith} 68479695Smsmith 68579695Smsmith/******************************************************************************** 68679695Smsmith * Free all of the resources associated with (sc) 68779695Smsmith * 68879695Smsmith * Should not be called if the controller is active. 68979695Smsmith */ 690105215Sphkstatic void 69179695Smsmithmly_free(struct mly_softc *sc) 69279695Smsmith{ 69379695Smsmith 69479695Smsmith debug_called(1); 69579695Smsmith 696108926Sscottl /* Remove the management device */ 697108926Sscottl destroy_dev(sc->mly_dev_t); 698108926Sscottl 699274677Sjhb if (sc->mly_intr) 700274677Sjhb bus_teardown_intr(sc->mly_dev, sc->mly_irq, sc->mly_intr); 701274677Sjhb callout_drain(&sc->mly_periodic); 702274677Sjhb#ifdef MLY_DEBUG 703274677Sjhb callout_drain(&sc->mly_timeout); 704274677Sjhb#endif 705274677Sjhb 70679695Smsmith /* detach from CAM */ 70779695Smsmith mly_cam_detach(sc); 70879695Smsmith 70979695Smsmith /* release command memory */ 71079695Smsmith mly_release_commands(sc); 71179695Smsmith 71279695Smsmith /* throw away the controllerinfo structure */ 71379695Smsmith if (sc->mly_controllerinfo != NULL) 71479695Smsmith free(sc->mly_controllerinfo, M_DEVBUF); 71579695Smsmith 71679695Smsmith /* throw away the controllerparam structure */ 71779695Smsmith if (sc->mly_controllerparam != NULL) 71879695Smsmith free(sc->mly_controllerparam, M_DEVBUF); 71979695Smsmith 72079695Smsmith /* destroy data-transfer DMA tag */ 72179695Smsmith if (sc->mly_buffer_dmat) 72279695Smsmith bus_dma_tag_destroy(sc->mly_buffer_dmat); 72379695Smsmith 72479695Smsmith /* free and destroy DMA memory and tag for s/g lists */ 72579695Smsmith if (sc->mly_sg_table) { 72679695Smsmith bus_dmamap_unload(sc->mly_sg_dmat, sc->mly_sg_dmamap); 72779695Smsmith bus_dmamem_free(sc->mly_sg_dmat, sc->mly_sg_table, sc->mly_sg_dmamap); 72879695Smsmith } 72979695Smsmith if (sc->mly_sg_dmat) 73079695Smsmith bus_dma_tag_destroy(sc->mly_sg_dmat); 73179695Smsmith 73279695Smsmith /* free and destroy DMA memory and tag for memory mailbox */ 73379695Smsmith if (sc->mly_mmbox) { 73479695Smsmith bus_dmamap_unload(sc->mly_mmbox_dmat, sc->mly_mmbox_dmamap); 73579695Smsmith bus_dmamem_free(sc->mly_mmbox_dmat, sc->mly_mmbox, sc->mly_mmbox_dmamap); 73679695Smsmith } 73779695Smsmith if (sc->mly_mmbox_dmat) 73879695Smsmith bus_dma_tag_destroy(sc->mly_mmbox_dmat); 73979695Smsmith 74079695Smsmith /* disconnect the interrupt handler */ 74179695Smsmith if (sc->mly_irq != NULL) 74279695Smsmith bus_release_resource(sc->mly_dev, SYS_RES_IRQ, sc->mly_irq_rid, sc->mly_irq); 74379695Smsmith 74479695Smsmith /* destroy the parent DMA tag */ 74579695Smsmith if (sc->mly_parent_dmat) 74679695Smsmith bus_dma_tag_destroy(sc->mly_parent_dmat); 74779695Smsmith 74879695Smsmith /* release the register window mapping */ 74979695Smsmith if (sc->mly_regs_resource != NULL) 75079695Smsmith bus_release_resource(sc->mly_dev, SYS_RES_MEMORY, sc->mly_regs_rid, sc->mly_regs_resource); 751274677Sjhb 752274677Sjhb mtx_destroy(&sc->mly_lock); 75379695Smsmith} 75479695Smsmith 75579695Smsmith/******************************************************************************** 75679695Smsmith ******************************************************************************** 75764987Smsmith Command Wrappers 75864987Smsmith ******************************************************************************** 75964987Smsmith ********************************************************************************/ 76064987Smsmith 76164987Smsmith/******************************************************************************** 76264987Smsmith * Fill in the mly_controllerinfo and mly_controllerparam fields in the softc. 76364987Smsmith */ 76464987Smsmithstatic int 76564987Smsmithmly_get_controllerinfo(struct mly_softc *sc) 76664987Smsmith{ 76764987Smsmith struct mly_command_ioctl mci; 76864987Smsmith u_int8_t status; 76964987Smsmith int error; 77064987Smsmith 77164987Smsmith debug_called(1); 77264987Smsmith 77364987Smsmith if (sc->mly_controllerinfo != NULL) 77464987Smsmith free(sc->mly_controllerinfo, M_DEVBUF); 77564987Smsmith 77664987Smsmith /* build the getcontrollerinfo ioctl and send it */ 77764987Smsmith bzero(&mci, sizeof(mci)); 77864987Smsmith sc->mly_controllerinfo = NULL; 77964987Smsmith mci.sub_ioctl = MDACIOCTL_GETCONTROLLERINFO; 78064987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerinfo, sizeof(*sc->mly_controllerinfo), 78164987Smsmith &status, NULL, NULL))) 78264987Smsmith return(error); 78364987Smsmith if (status != 0) 78464987Smsmith return(EIO); 78564987Smsmith 78664987Smsmith if (sc->mly_controllerparam != NULL) 78764987Smsmith free(sc->mly_controllerparam, M_DEVBUF); 78864987Smsmith 78964987Smsmith /* build the getcontrollerparameter ioctl and send it */ 79064987Smsmith bzero(&mci, sizeof(mci)); 79164987Smsmith sc->mly_controllerparam = NULL; 79264987Smsmith mci.sub_ioctl = MDACIOCTL_GETCONTROLLERPARAMETER; 79364987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&sc->mly_controllerparam, sizeof(*sc->mly_controllerparam), 79464987Smsmith &status, NULL, NULL))) 79564987Smsmith return(error); 79664987Smsmith if (status != 0) 79764987Smsmith return(EIO); 79864987Smsmith 79964987Smsmith return(0); 80064987Smsmith} 80164987Smsmith 80264987Smsmith/******************************************************************************** 80364987Smsmith * Schedule all possible devices for a rescan. 80464987Smsmith * 80564987Smsmith */ 80664987Smsmithstatic void 80764987Smsmithmly_scan_devices(struct mly_softc *sc) 80864987Smsmith{ 80979695Smsmith int bus, target; 81064987Smsmith 81164987Smsmith debug_called(1); 81264987Smsmith 81364987Smsmith /* 81464987Smsmith * Clear any previous BTL information. 81564987Smsmith */ 81664987Smsmith bzero(&sc->mly_btl, sizeof(sc->mly_btl)); 81764987Smsmith 81864987Smsmith /* 81979695Smsmith * Mark all devices as requiring a rescan, and let the next 82079695Smsmith * periodic scan collect them. 82164987Smsmith */ 82279695Smsmith for (bus = 0; bus < sc->mly_cam_channels; bus++) 82379695Smsmith if (MLY_BUS_IS_VALID(sc, bus)) 82479695Smsmith for (target = 0; target < MLY_MAX_TARGETS; target++) 82579695Smsmith sc->mly_btl[bus][target].mb_flags = MLY_BTL_RESCAN; 82664987Smsmith 82764987Smsmith} 82864987Smsmith 82964987Smsmith/******************************************************************************** 83064987Smsmith * Rescan a device, possibly as a consequence of getting an event which suggests 83164987Smsmith * that it may have changed. 83279695Smsmith * 83379695Smsmith * If we suffer resource starvation, we can abandon the rescan as we'll be 83479695Smsmith * retried. 83564987Smsmith */ 83664987Smsmithstatic void 83764987Smsmithmly_rescan_btl(struct mly_softc *sc, int bus, int target) 83864987Smsmith{ 83964987Smsmith struct mly_command *mc; 84064987Smsmith struct mly_command_ioctl *mci; 84164987Smsmith 84279695Smsmith debug_called(1); 84364987Smsmith 84479695Smsmith /* check that this bus is valid */ 84579695Smsmith if (!MLY_BUS_IS_VALID(sc, bus)) 84679695Smsmith return; 84779695Smsmith 84864987Smsmith /* get a command */ 84964987Smsmith if (mly_alloc_command(sc, &mc)) 85079695Smsmith return; 85164987Smsmith 85264987Smsmith /* set up the data buffer */ 85368877Sdwmalone if ((mc->mc_data = malloc(sizeof(union mly_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 85464987Smsmith mly_release_command(mc); 85579695Smsmith return; 85664987Smsmith } 85764987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 85864987Smsmith mc->mc_complete = mly_complete_rescan; 85964987Smsmith 86064987Smsmith /* 86164987Smsmith * Build the ioctl. 86264987Smsmith */ 86364987Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 86464987Smsmith mci->opcode = MDACMD_IOCTL; 86564987Smsmith mci->addr.phys.controller = 0; 86664987Smsmith mci->timeout.value = 30; 86764987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 86885324Smsmith if (MLY_BUS_IS_VIRTUAL(sc, bus)) { 86964987Smsmith mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getlogdevinfovalid); 87064987Smsmith mci->sub_ioctl = MDACIOCTL_GETLOGDEVINFOVALID; 87179695Smsmith mci->addr.log.logdev = MLY_LOGDEV_ID(sc, bus, target); 87279695Smsmith debug(1, "logical device %d", mci->addr.log.logdev); 87364987Smsmith } else { 87464987Smsmith mc->mc_length = mci->data_size = sizeof(struct mly_ioctl_getphysdevinfovalid); 87564987Smsmith mci->sub_ioctl = MDACIOCTL_GETPHYSDEVINFOVALID; 87664987Smsmith mci->addr.phys.lun = 0; 87764987Smsmith mci->addr.phys.target = target; 87864987Smsmith mci->addr.phys.channel = bus; 87979695Smsmith debug(1, "physical device %d:%d", mci->addr.phys.channel, mci->addr.phys.target); 88064987Smsmith } 88164987Smsmith 88264987Smsmith /* 88379695Smsmith * Dispatch the command. If we successfully send the command, clear the rescan 88479695Smsmith * bit. 88564987Smsmith */ 88679695Smsmith if (mly_start(mc) != 0) { 88779695Smsmith mly_release_command(mc); 88879695Smsmith } else { 88979695Smsmith sc->mly_btl[bus][target].mb_flags &= ~MLY_BTL_RESCAN; /* success */ 89079695Smsmith } 89164987Smsmith} 89264987Smsmith 89364987Smsmith/******************************************************************************** 89464987Smsmith * Handle the completion of a rescan operation 89564987Smsmith */ 89664987Smsmithstatic void 89764987Smsmithmly_complete_rescan(struct mly_command *mc) 89864987Smsmith{ 89964987Smsmith struct mly_softc *sc = mc->mc_sc; 90064987Smsmith struct mly_ioctl_getlogdevinfovalid *ldi; 90164987Smsmith struct mly_ioctl_getphysdevinfovalid *pdi; 90279695Smsmith struct mly_command_ioctl *mci; 90379695Smsmith struct mly_btl btl, *btlp; 90479695Smsmith int bus, target, rescan; 90564987Smsmith 90679695Smsmith debug_called(1); 90764987Smsmith 90879695Smsmith /* 90979695Smsmith * Recover the bus and target from the command. We need these even in 91079695Smsmith * the case where we don't have a useful response. 91179695Smsmith */ 91279695Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 91379695Smsmith if (mci->sub_ioctl == MDACIOCTL_GETLOGDEVINFOVALID) { 91479695Smsmith bus = MLY_LOGDEV_BUS(sc, mci->addr.log.logdev); 91579695Smsmith target = MLY_LOGDEV_TARGET(sc, mci->addr.log.logdev); 91679695Smsmith } else { 91779695Smsmith bus = mci->addr.phys.channel; 91879695Smsmith target = mci->addr.phys.target; 91979695Smsmith } 92079695Smsmith /* XXX validate bus/target? */ 92179695Smsmith 92279695Smsmith /* the default result is 'no device' */ 92379695Smsmith bzero(&btl, sizeof(btl)); 92479695Smsmith 92579695Smsmith /* if the rescan completed OK, we have possibly-new BTL data */ 92664987Smsmith if (mc->mc_status == 0) { 92764987Smsmith if (mc->mc_length == sizeof(*ldi)) { 92864987Smsmith ldi = (struct mly_ioctl_getlogdevinfovalid *)mc->mc_data; 92979695Smsmith if ((MLY_LOGDEV_BUS(sc, ldi->logical_device_number) != bus) || 93079695Smsmith (MLY_LOGDEV_TARGET(sc, ldi->logical_device_number) != target)) { 93179695Smsmith mly_printf(sc, "WARNING: BTL rescan for %d:%d returned data for %d:%d instead\n", 93279695Smsmith bus, target, MLY_LOGDEV_BUS(sc, ldi->logical_device_number), 93379695Smsmith MLY_LOGDEV_TARGET(sc, ldi->logical_device_number)); 93479695Smsmith /* XXX what can we do about this? */ 93579695Smsmith } 93679695Smsmith btl.mb_flags = MLY_BTL_LOGICAL; 93779695Smsmith btl.mb_type = ldi->raid_level; 93879695Smsmith btl.mb_state = ldi->state; 93979695Smsmith debug(1, "BTL rescan for %d returns %s, %s", ldi->logical_device_number, 94064987Smsmith mly_describe_code(mly_table_device_type, ldi->raid_level), 94164987Smsmith mly_describe_code(mly_table_device_state, ldi->state)); 94264987Smsmith } else if (mc->mc_length == sizeof(*pdi)) { 94364987Smsmith pdi = (struct mly_ioctl_getphysdevinfovalid *)mc->mc_data; 94479695Smsmith if ((pdi->channel != bus) || (pdi->target != target)) { 94579695Smsmith mly_printf(sc, "WARNING: BTL rescan for %d:%d returned data for %d:%d instead\n", 94679695Smsmith bus, target, pdi->channel, pdi->target); 94779695Smsmith /* XXX what can we do about this? */ 94879695Smsmith } 94979695Smsmith btl.mb_flags = MLY_BTL_PHYSICAL; 95079695Smsmith btl.mb_type = MLY_DEVICE_TYPE_PHYSICAL; 95179695Smsmith btl.mb_state = pdi->state; 95279695Smsmith btl.mb_speed = pdi->speed; 95379695Smsmith btl.mb_width = pdi->width; 95464987Smsmith if (pdi->state != MLY_DEVICE_STATE_UNCONFIGURED) 95564987Smsmith sc->mly_btl[bus][target].mb_flags |= MLY_BTL_PROTECTED; 95679695Smsmith debug(1, "BTL rescan for %d:%d returns %s", bus, target, 95764987Smsmith mly_describe_code(mly_table_device_state, pdi->state)); 95864987Smsmith } else { 95979695Smsmith mly_printf(sc, "BTL rescan result invalid\n"); 96064987Smsmith } 96164987Smsmith } 96279695Smsmith 96364987Smsmith free(mc->mc_data, M_DEVBUF); 96464987Smsmith mly_release_command(mc); 96579695Smsmith 96679695Smsmith /* 96779695Smsmith * Decide whether we need to rescan the device. 96879695Smsmith */ 96979695Smsmith rescan = 0; 97079695Smsmith 97179695Smsmith /* device type changes (usually between 'nothing' and 'something') */ 97279695Smsmith btlp = &sc->mly_btl[bus][target]; 97379695Smsmith if (btl.mb_flags != btlp->mb_flags) { 97479695Smsmith debug(1, "flags changed, rescanning"); 97579695Smsmith rescan = 1; 97679695Smsmith } 97779695Smsmith 97879695Smsmith /* XXX other reasons? */ 97979695Smsmith 98079695Smsmith /* 98179695Smsmith * Update BTL information. 98279695Smsmith */ 98379695Smsmith *btlp = btl; 98479695Smsmith 98579695Smsmith /* 98679695Smsmith * Perform CAM rescan if required. 98779695Smsmith */ 98879695Smsmith if (rescan) 98979695Smsmith mly_cam_rescan_btl(sc, bus, target); 99064987Smsmith} 99164987Smsmith 99264987Smsmith/******************************************************************************** 99364987Smsmith * Get the current health status and set the 'next event' counter to suit. 99464987Smsmith */ 99564987Smsmithstatic int 99664987Smsmithmly_get_eventstatus(struct mly_softc *sc) 99764987Smsmith{ 99864987Smsmith struct mly_command_ioctl mci; 99964987Smsmith struct mly_health_status *mh; 100064987Smsmith u_int8_t status; 100164987Smsmith int error; 100264987Smsmith 100364987Smsmith /* build the gethealthstatus ioctl and send it */ 100464987Smsmith bzero(&mci, sizeof(mci)); 100564987Smsmith mh = NULL; 100664987Smsmith mci.sub_ioctl = MDACIOCTL_GETHEALTHSTATUS; 100764987Smsmith 100864987Smsmith if ((error = mly_ioctl(sc, &mci, (void **)&mh, sizeof(*mh), &status, NULL, NULL))) 100964987Smsmith return(error); 101064987Smsmith if (status != 0) 101164987Smsmith return(EIO); 101264987Smsmith 101364987Smsmith /* get the event counter */ 101464987Smsmith sc->mly_event_change = mh->change_counter; 101564987Smsmith sc->mly_event_waiting = mh->next_event; 101664987Smsmith sc->mly_event_counter = mh->next_event; 101764987Smsmith 101864987Smsmith /* save the health status into the memory mailbox */ 101964987Smsmith bcopy(mh, &sc->mly_mmbox->mmm_health.status, sizeof(*mh)); 102064987Smsmith 102164987Smsmith debug(1, "initial change counter %d, event counter %d", mh->change_counter, mh->next_event); 102264987Smsmith 102364987Smsmith free(mh, M_DEVBUF); 102464987Smsmith return(0); 102564987Smsmith} 102664987Smsmith 102764987Smsmith/******************************************************************************** 102864987Smsmith * Enable the memory mailbox mode. 102964987Smsmith */ 103064987Smsmithstatic int 103164987Smsmithmly_enable_mmbox(struct mly_softc *sc) 103264987Smsmith{ 103364987Smsmith struct mly_command_ioctl mci; 103464987Smsmith u_int8_t *sp, status; 103564987Smsmith int error; 103664987Smsmith 103764987Smsmith debug_called(1); 103864987Smsmith 103964987Smsmith /* build the ioctl and send it */ 104064987Smsmith bzero(&mci, sizeof(mci)); 104164987Smsmith mci.sub_ioctl = MDACIOCTL_SETMEMORYMAILBOX; 104264987Smsmith /* set buffer addresses */ 104373050Smsmith mci.param.setmemorymailbox.command_mailbox_physaddr = 104473050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_command); 104573050Smsmith mci.param.setmemorymailbox.status_mailbox_physaddr = 104673050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_status); 104773050Smsmith mci.param.setmemorymailbox.health_buffer_physaddr = 104873050Smsmith sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_health); 104964987Smsmith 105064987Smsmith /* set buffer sizes - abuse of data_size field is revolting */ 105164987Smsmith sp = (u_int8_t *)&mci.data_size; 105264987Smsmith sp[0] = ((sizeof(union mly_command_packet) * MLY_MMBOX_COMMANDS) / 1024); 105364987Smsmith sp[1] = (sizeof(union mly_status_packet) * MLY_MMBOX_STATUS) / 1024; 105464987Smsmith mci.param.setmemorymailbox.health_buffer_size = sizeof(union mly_health_region) / 1024; 105564987Smsmith 105664987Smsmith debug(1, "memory mailbox at %p (0x%llx/%d 0x%llx/%d 0x%llx/%d", sc->mly_mmbox, 105764987Smsmith mci.param.setmemorymailbox.command_mailbox_physaddr, sp[0], 105864987Smsmith mci.param.setmemorymailbox.status_mailbox_physaddr, sp[1], 105973050Smsmith mci.param.setmemorymailbox.health_buffer_physaddr, 106073050Smsmith mci.param.setmemorymailbox.health_buffer_size); 106164987Smsmith 106264987Smsmith if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) 106364987Smsmith return(error); 106464987Smsmith if (status != 0) 106564987Smsmith return(EIO); 106664987Smsmith sc->mly_state |= MLY_STATE_MMBOX_ACTIVE; 106764987Smsmith debug(1, "memory mailbox active"); 106864987Smsmith return(0); 106964987Smsmith} 107064987Smsmith 107164987Smsmith/******************************************************************************** 107264987Smsmith * Flush all pending I/O from the controller. 107364987Smsmith */ 107464987Smsmithstatic int 107564987Smsmithmly_flush(struct mly_softc *sc) 107664987Smsmith{ 107764987Smsmith struct mly_command_ioctl mci; 107864987Smsmith u_int8_t status; 107964987Smsmith int error; 108064987Smsmith 108164987Smsmith debug_called(1); 108264987Smsmith 108364987Smsmith /* build the ioctl */ 108464987Smsmith bzero(&mci, sizeof(mci)); 108564987Smsmith mci.sub_ioctl = MDACIOCTL_FLUSHDEVICEDATA; 108664987Smsmith mci.param.deviceoperation.operation_device = MLY_OPDEVICE_PHYSICAL_CONTROLLER; 108764987Smsmith 108864987Smsmith /* pass it off to the controller */ 108964987Smsmith if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL))) 109064987Smsmith return(error); 109164987Smsmith 109264987Smsmith return((status == 0) ? 0 : EIO); 109364987Smsmith} 109464987Smsmith 109564987Smsmith/******************************************************************************** 109664987Smsmith * Perform an ioctl command. 109764987Smsmith * 109864987Smsmith * If (data) is not NULL, the command requires data transfer. If (*data) is NULL 109964987Smsmith * the command requires data transfer from the controller, and we will allocate 110064987Smsmith * a buffer for it. If (*data) is not NULL, the command requires data transfer 110164987Smsmith * to the controller. 110264987Smsmith * 110364987Smsmith * XXX passing in the whole ioctl structure is ugly. Better ideas? 110464987Smsmith * 110564987Smsmith * XXX we don't even try to handle the case where datasize > 4k. We should. 110664987Smsmith */ 110764987Smsmithstatic int 110864987Smsmithmly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, size_t datasize, 110964987Smsmith u_int8_t *status, void *sense_buffer, size_t *sense_length) 111064987Smsmith{ 111164987Smsmith struct mly_command *mc; 111264987Smsmith struct mly_command_ioctl *mci; 111364987Smsmith int error; 111464987Smsmith 111564987Smsmith debug_called(1); 1116274677Sjhb MLY_ASSERT_LOCKED(sc); 111764987Smsmith 111864987Smsmith mc = NULL; 111964987Smsmith if (mly_alloc_command(sc, &mc)) { 112064987Smsmith error = ENOMEM; 112164987Smsmith goto out; 112264987Smsmith } 112364987Smsmith 112464987Smsmith /* copy the ioctl structure, but save some important fields and then fixup */ 112564987Smsmith mci = &mc->mc_packet->ioctl; 112664987Smsmith ioctl->sense_buffer_address = mci->sense_buffer_address; 112764987Smsmith ioctl->maximum_sense_size = mci->maximum_sense_size; 112864987Smsmith *mci = *ioctl; 112964987Smsmith mci->opcode = MDACMD_IOCTL; 113064987Smsmith mci->timeout.value = 30; 113164987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 113264987Smsmith 113364987Smsmith /* handle the data buffer */ 113464987Smsmith if (data != NULL) { 113564987Smsmith if (*data == NULL) { 113664987Smsmith /* allocate data buffer */ 113764987Smsmith if ((mc->mc_data = malloc(datasize, M_DEVBUF, M_NOWAIT)) == NULL) { 113864987Smsmith error = ENOMEM; 113964987Smsmith goto out; 114064987Smsmith } 114164987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 114264987Smsmith } else { 114364987Smsmith mc->mc_data = *data; 114464987Smsmith mc->mc_flags |= MLY_CMD_DATAOUT; 114564987Smsmith } 114664987Smsmith mc->mc_length = datasize; 114764987Smsmith mc->mc_packet->generic.data_size = datasize; 114864987Smsmith } 114964987Smsmith 115064987Smsmith /* run the command */ 115164987Smsmith if ((error = mly_immediate_command(mc))) 115264987Smsmith goto out; 115364987Smsmith 115464987Smsmith /* clean up and return any data */ 115564987Smsmith *status = mc->mc_status; 115664987Smsmith if ((mc->mc_sense > 0) && (sense_buffer != NULL)) { 115764987Smsmith bcopy(mc->mc_packet, sense_buffer, mc->mc_sense); 115864987Smsmith *sense_length = mc->mc_sense; 115964987Smsmith goto out; 116064987Smsmith } 116164987Smsmith 116264987Smsmith /* should we return a data pointer? */ 116364987Smsmith if ((data != NULL) && (*data == NULL)) 116464987Smsmith *data = mc->mc_data; 116564987Smsmith 116664987Smsmith /* command completed OK */ 116764987Smsmith error = 0; 116864987Smsmith 116964987Smsmithout: 117064987Smsmith if (mc != NULL) { 117164987Smsmith /* do we need to free a data buffer we allocated? */ 117264987Smsmith if (error && (mc->mc_data != NULL) && (*data == NULL)) 117364987Smsmith free(mc->mc_data, M_DEVBUF); 117464987Smsmith mly_release_command(mc); 117564987Smsmith } 117664987Smsmith return(error); 117764987Smsmith} 117864987Smsmith 117964987Smsmith/******************************************************************************** 118079695Smsmith * Check for event(s) outstanding in the controller. 118179695Smsmith */ 118279695Smsmithstatic void 118379695Smsmithmly_check_event(struct mly_softc *sc) 118479695Smsmith{ 118579695Smsmith 118679695Smsmith /* 118779695Smsmith * The controller may have updated the health status information, 118879695Smsmith * so check for it here. Note that the counters are all in host memory, 118979695Smsmith * so this check is very cheap. Also note that we depend on checking on 119079695Smsmith * completion 119179695Smsmith */ 119279695Smsmith if (sc->mly_mmbox->mmm_health.status.change_counter != sc->mly_event_change) { 119379695Smsmith sc->mly_event_change = sc->mly_mmbox->mmm_health.status.change_counter; 119479695Smsmith debug(1, "event change %d, event status update, %d -> %d", sc->mly_event_change, 119579695Smsmith sc->mly_event_waiting, sc->mly_mmbox->mmm_health.status.next_event); 119679695Smsmith sc->mly_event_waiting = sc->mly_mmbox->mmm_health.status.next_event; 119779695Smsmith 119879695Smsmith /* wake up anyone that might be interested in this */ 119979695Smsmith wakeup(&sc->mly_event_change); 120079695Smsmith } 120179695Smsmith if (sc->mly_event_counter != sc->mly_event_waiting) 120279695Smsmith mly_fetch_event(sc); 120379695Smsmith} 120479695Smsmith 120579695Smsmith/******************************************************************************** 120664987Smsmith * Fetch one event from the controller. 120779695Smsmith * 120879695Smsmith * If we fail due to resource starvation, we'll be retried the next time a 120979695Smsmith * command completes. 121064987Smsmith */ 121164987Smsmithstatic void 121264987Smsmithmly_fetch_event(struct mly_softc *sc) 121364987Smsmith{ 121464987Smsmith struct mly_command *mc; 121564987Smsmith struct mly_command_ioctl *mci; 121664987Smsmith int s; 121764987Smsmith u_int32_t event; 121864987Smsmith 121979695Smsmith debug_called(1); 122064987Smsmith 122164987Smsmith /* get a command */ 122264987Smsmith if (mly_alloc_command(sc, &mc)) 122379695Smsmith return; 122464987Smsmith 122564987Smsmith /* set up the data buffer */ 122668877Sdwmalone if ((mc->mc_data = malloc(sizeof(struct mly_event), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 122764987Smsmith mly_release_command(mc); 122879695Smsmith return; 122964987Smsmith } 123064987Smsmith mc->mc_length = sizeof(struct mly_event); 123164987Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 123264987Smsmith mc->mc_complete = mly_complete_event; 123364987Smsmith 123464987Smsmith /* 123564987Smsmith * Get an event number to fetch. It's possible that we've raced with another 123664987Smsmith * context for the last event, in which case there will be no more events. 123764987Smsmith */ 123864987Smsmith s = splcam(); 123964987Smsmith if (sc->mly_event_counter == sc->mly_event_waiting) { 124064987Smsmith mly_release_command(mc); 124164987Smsmith splx(s); 124264987Smsmith return; 124364987Smsmith } 124464987Smsmith event = sc->mly_event_counter++; 124564987Smsmith splx(s); 124664987Smsmith 124764987Smsmith /* 124864987Smsmith * Build the ioctl. 124964987Smsmith * 125064987Smsmith * At this point we are committed to sending this request, as it 125164987Smsmith * will be the only one constructed for this particular event number. 125264987Smsmith */ 125364987Smsmith mci = (struct mly_command_ioctl *)&mc->mc_packet->ioctl; 125464987Smsmith mci->opcode = MDACMD_IOCTL; 125564987Smsmith mci->data_size = sizeof(struct mly_event); 125664987Smsmith mci->addr.phys.lun = (event >> 16) & 0xff; 125764987Smsmith mci->addr.phys.target = (event >> 24) & 0xff; 125864987Smsmith mci->addr.phys.channel = 0; 125964987Smsmith mci->addr.phys.controller = 0; 126064987Smsmith mci->timeout.value = 30; 126164987Smsmith mci->timeout.scale = MLY_TIMEOUT_SECONDS; 126264987Smsmith mci->sub_ioctl = MDACIOCTL_GETEVENT; 126364987Smsmith mci->param.getevent.sequence_number_low = event & 0xffff; 126464987Smsmith 126579695Smsmith debug(1, "fetch event %u", event); 126664987Smsmith 126764987Smsmith /* 126879695Smsmith * Submit the command. 126979695Smsmith * 127079695Smsmith * Note that failure of mly_start() will result in this event never being 127179695Smsmith * fetched. 127264987Smsmith */ 127379695Smsmith if (mly_start(mc) != 0) { 127479695Smsmith mly_printf(sc, "couldn't fetch event %u\n", event); 127579695Smsmith mly_release_command(mc); 127679695Smsmith } 127764987Smsmith} 127864987Smsmith 127964987Smsmith/******************************************************************************** 128064987Smsmith * Handle the completion of an event poll. 128164987Smsmith */ 128264987Smsmithstatic void 128364987Smsmithmly_complete_event(struct mly_command *mc) 128464987Smsmith{ 128564987Smsmith struct mly_softc *sc = mc->mc_sc; 128664987Smsmith struct mly_event *me = (struct mly_event *)mc->mc_data; 128764987Smsmith 128879695Smsmith debug_called(1); 128964987Smsmith 129064987Smsmith /* 129164987Smsmith * If the event was successfully fetched, process it. 129264987Smsmith */ 129364987Smsmith if (mc->mc_status == SCSI_STATUS_OK) { 129464987Smsmith mly_process_event(sc, me); 129564987Smsmith free(me, M_DEVBUF); 129664987Smsmith } 129764987Smsmith mly_release_command(mc); 129879695Smsmith 129979695Smsmith /* 130079695Smsmith * Check for another event. 130179695Smsmith */ 130279695Smsmith mly_check_event(sc); 130364987Smsmith} 130464987Smsmith 130564987Smsmith/******************************************************************************** 130664987Smsmith * Process a controller event. 130764987Smsmith */ 130864987Smsmithstatic void 130964987Smsmithmly_process_event(struct mly_softc *sc, struct mly_event *me) 131064987Smsmith{ 1311225950Sken struct scsi_sense_data_fixed *ssd; 1312225950Sken char *fp, *tp; 1313225950Sken int bus, target, event, class, action; 131464987Smsmith 1315225950Sken ssd = (struct scsi_sense_data_fixed *)&me->sense[0]; 1316225950Sken 131764987Smsmith /* 131864987Smsmith * Errors can be reported using vendor-unique sense data. In this case, the 131964987Smsmith * event code will be 0x1c (Request sense data present), the sense key will 132064987Smsmith * be 0x09 (vendor specific), the MSB of the ASC will be set, and the 132164987Smsmith * actual event code will be a 16-bit value comprised of the ASCQ (low byte) 132264987Smsmith * and low seven bits of the ASC (low seven bits of the high byte). 132364987Smsmith */ 132464987Smsmith if ((me->code == 0x1c) && 132564987Smsmith ((ssd->flags & SSD_KEY) == SSD_KEY_Vendor_Specific) && 132664987Smsmith (ssd->add_sense_code & 0x80)) { 132764987Smsmith event = ((int)(ssd->add_sense_code & ~0x80) << 8) + ssd->add_sense_code_qual; 132864987Smsmith } else { 132964987Smsmith event = me->code; 133064987Smsmith } 133164987Smsmith 133264987Smsmith /* look up event, get codes */ 133364987Smsmith fp = mly_describe_code(mly_table_event, event); 133464987Smsmith 133579695Smsmith debug(1, "Event %d code 0x%x", me->sequence_number, me->code); 133664987Smsmith 133764987Smsmith /* quiet event? */ 133864987Smsmith class = fp[0]; 133964987Smsmith if (isupper(class) && bootverbose) 134064987Smsmith class = tolower(class); 134164987Smsmith 134264987Smsmith /* get action code, text string */ 134364987Smsmith action = fp[1]; 134464987Smsmith tp = &fp[2]; 134564987Smsmith 134664987Smsmith /* 134764987Smsmith * Print some information about the event. 134864987Smsmith * 134964987Smsmith * This code uses a table derived from the corresponding portion of the Linux 135064987Smsmith * driver, and thus the parser is very similar. 135164987Smsmith */ 135264987Smsmith switch(class) { 135364987Smsmith case 'p': /* error on physical device */ 135464987Smsmith mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); 135564987Smsmith if (action == 'r') 135664987Smsmith sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; 135764987Smsmith break; 135864987Smsmith case 'l': /* error on logical unit */ 135964987Smsmith case 'm': /* message about logical unit */ 136064987Smsmith bus = MLY_LOGDEV_BUS(sc, me->lun); 136179695Smsmith target = MLY_LOGDEV_TARGET(sc, me->lun); 136264987Smsmith mly_name_device(sc, bus, target); 136364987Smsmith mly_printf(sc, "logical device %d (%s) %s\n", me->lun, sc->mly_btl[bus][target].mb_name, tp); 136464987Smsmith if (action == 'r') 136564987Smsmith sc->mly_btl[bus][target].mb_flags |= MLY_BTL_RESCAN; 136664987Smsmith break; 136764987Smsmith case 's': /* report of sense data */ 136864987Smsmith if (((ssd->flags & SSD_KEY) == SSD_KEY_NO_SENSE) || 136964987Smsmith (((ssd->flags & SSD_KEY) == SSD_KEY_NOT_READY) && 137064987Smsmith (ssd->add_sense_code == 0x04) && 137164987Smsmith ((ssd->add_sense_code_qual == 0x01) || (ssd->add_sense_code_qual == 0x02)))) 137264987Smsmith break; /* ignore NO_SENSE or NOT_READY in one case */ 137364987Smsmith 137464987Smsmith mly_printf(sc, "physical device %d:%d %s\n", me->channel, me->target, tp); 137564987Smsmith mly_printf(sc, " sense key %d asc %02x ascq %02x\n", 137664987Smsmith ssd->flags & SSD_KEY, ssd->add_sense_code, ssd->add_sense_code_qual); 137764987Smsmith mly_printf(sc, " info %4D csi %4D\n", ssd->info, "", ssd->cmd_spec_info, ""); 137864987Smsmith if (action == 'r') 137964987Smsmith sc->mly_btl[me->channel][me->target].mb_flags |= MLY_BTL_RESCAN; 138064987Smsmith break; 138164987Smsmith case 'e': 138264987Smsmith mly_printf(sc, tp, me->target, me->lun); 1383110680Salfred printf("\n"); 138464987Smsmith break; 138564987Smsmith case 'c': 138664987Smsmith mly_printf(sc, "controller %s\n", tp); 138764987Smsmith break; 138864987Smsmith case '?': 138964987Smsmith mly_printf(sc, "%s - %d\n", tp, me->code); 139064987Smsmith break; 139164987Smsmith default: /* probably a 'noisy' event being ignored */ 139264987Smsmith break; 139364987Smsmith } 139464987Smsmith} 139564987Smsmith 139664987Smsmith/******************************************************************************** 139764987Smsmith * Perform periodic activities. 139864987Smsmith */ 139964987Smsmithstatic void 140064987Smsmithmly_periodic(void *data) 140164987Smsmith{ 140264987Smsmith struct mly_softc *sc = (struct mly_softc *)data; 140379695Smsmith int bus, target; 140464987Smsmith 140564987Smsmith debug_called(2); 1406274677Sjhb MLY_ASSERT_LOCKED(sc); 140764987Smsmith 140864987Smsmith /* 140964987Smsmith * Scan devices. 141064987Smsmith */ 141179695Smsmith for (bus = 0; bus < sc->mly_cam_channels; bus++) { 141279695Smsmith if (MLY_BUS_IS_VALID(sc, bus)) { 141379695Smsmith for (target = 0; target < MLY_MAX_TARGETS; target++) { 141464987Smsmith 141579695Smsmith /* ignore the controller in this scan */ 141679695Smsmith if (target == sc->mly_controllerparam->initiator_id) 141779695Smsmith continue; 141864987Smsmith 141979695Smsmith /* perform device rescan? */ 142079695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_RESCAN) 142179695Smsmith mly_rescan_btl(sc, bus, target); 142279695Smsmith } 142364987Smsmith } 142464987Smsmith } 142579695Smsmith 142679695Smsmith /* check for controller events */ 142779695Smsmith mly_check_event(sc); 142864987Smsmith 142979695Smsmith /* reschedule ourselves */ 1430274677Sjhb callout_schedule(&sc->mly_periodic, MLY_PERIODIC_INTERVAL * hz); 143164987Smsmith} 143264987Smsmith 143364987Smsmith/******************************************************************************** 143464987Smsmith ******************************************************************************** 143564987Smsmith Command Processing 143664987Smsmith ******************************************************************************** 143764987Smsmith ********************************************************************************/ 143864987Smsmith 143964987Smsmith/******************************************************************************** 144064987Smsmith * Run a command and wait for it to complete. 144164987Smsmith * 144264987Smsmith */ 144364987Smsmithstatic int 144464987Smsmithmly_immediate_command(struct mly_command *mc) 144564987Smsmith{ 144664987Smsmith struct mly_softc *sc = mc->mc_sc; 1447274677Sjhb int error; 144864987Smsmith 144979695Smsmith debug_called(1); 145064987Smsmith 1451274677Sjhb MLY_ASSERT_LOCKED(sc); 145279695Smsmith if ((error = mly_start(mc))) { 145364987Smsmith return(error); 145479695Smsmith } 145564987Smsmith 145664987Smsmith if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) { 145764987Smsmith /* sleep on the command */ 145873050Smsmith while(!(mc->mc_flags & MLY_CMD_COMPLETE)) { 1459274677Sjhb mtx_sleep(mc, &sc->mly_lock, PRIBIO, "mlywait", 0); 146064987Smsmith } 146164987Smsmith } else { 146264987Smsmith /* spin and collect status while we do */ 146373050Smsmith while(!(mc->mc_flags & MLY_CMD_COMPLETE)) { 146464987Smsmith mly_done(mc->mc_sc); 146573050Smsmith } 146664987Smsmith } 146764987Smsmith return(0); 146864987Smsmith} 146964987Smsmith 147064987Smsmith/******************************************************************************** 147179695Smsmith * Deliver a command to the controller. 147279695Smsmith * 147379695Smsmith * XXX it would be good to just queue commands that we can't submit immediately 147479695Smsmith * and send them later, but we probably want a wrapper for that so that 147579695Smsmith * we don't hang on a failed submission for an immediate command. 147664987Smsmith */ 147764987Smsmithstatic int 147864987Smsmithmly_start(struct mly_command *mc) 147964987Smsmith{ 148064987Smsmith struct mly_softc *sc = mc->mc_sc; 148164987Smsmith union mly_command_packet *pkt; 148264987Smsmith 148364987Smsmith debug_called(2); 1484274677Sjhb MLY_ASSERT_LOCKED(sc); 148564987Smsmith 148664987Smsmith /* 148773050Smsmith * Set the command up for delivery to the controller. 148864987Smsmith */ 148964987Smsmith mly_map_command(mc); 149073050Smsmith mc->mc_packet->generic.command_id = mc->mc_slot; 149164987Smsmith 1492110479Sscottl#ifdef MLY_DEBUG 1493110479Sscottl mc->mc_timestamp = time_second; 1494110479Sscottl#endif 1495110479Sscottl 149664987Smsmith /* 149764987Smsmith * Do we have to use the hardware mailbox? 149864987Smsmith */ 149964987Smsmith if (!(sc->mly_state & MLY_STATE_MMBOX_ACTIVE)) { 150064987Smsmith /* 150164987Smsmith * Check to see if the controller is ready for us. 150264987Smsmith */ 150364987Smsmith if (MLY_IDBR_TRUE(sc, MLY_HM_CMDSENT)) { 150464987Smsmith return(EBUSY); 150564987Smsmith } 150673050Smsmith mc->mc_flags |= MLY_CMD_BUSY; 150773050Smsmith 150864987Smsmith /* 150964987Smsmith * It's ready, send the command. 151064987Smsmith */ 151164987Smsmith MLY_SET_MBOX(sc, sc->mly_command_mailbox, &mc->mc_packetphys); 151264987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_CMDSENT); 151364987Smsmith 151464987Smsmith } else { /* use memory-mailbox mode */ 151564987Smsmith 151664987Smsmith pkt = &sc->mly_mmbox->mmm_command[sc->mly_mmbox_command_index]; 151764987Smsmith 151873050Smsmith /* check to see if the next index is free yet */ 151964987Smsmith if (pkt->mmbox.flag != 0) { 152064987Smsmith return(EBUSY); 152164987Smsmith } 152273050Smsmith mc->mc_flags |= MLY_CMD_BUSY; 152364987Smsmith 152464987Smsmith /* copy in new command */ 152564987Smsmith bcopy(mc->mc_packet->mmbox.data, pkt->mmbox.data, sizeof(pkt->mmbox.data)); 152664987Smsmith /* barrier to ensure completion of previous write before we write the flag */ 1527274677Sjhb bus_barrier(sc->mly_regs_resource, 0, 0, BUS_SPACE_BARRIER_WRITE); 152864987Smsmith /* copy flag last */ 152964987Smsmith pkt->mmbox.flag = mc->mc_packet->mmbox.flag; 153064987Smsmith /* barrier to ensure completion of previous write before we notify the controller */ 1531274677Sjhb bus_barrier(sc->mly_regs_resource, 0, 0, BUS_SPACE_BARRIER_WRITE); 153264987Smsmith 153364987Smsmith /* signal controller, update index */ 153464987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_AM_CMDSENT); 153564987Smsmith sc->mly_mmbox_command_index = (sc->mly_mmbox_command_index + 1) % MLY_MMBOX_COMMANDS; 153664987Smsmith } 153764987Smsmith 153873050Smsmith mly_enqueue_busy(mc); 153964987Smsmith return(0); 154064987Smsmith} 154164987Smsmith 154264987Smsmith/******************************************************************************** 154364987Smsmith * Pick up command status from the controller, schedule a completion event 154464987Smsmith */ 1545105215Sphkstatic void 154664987Smsmithmly_done(struct mly_softc *sc) 154764987Smsmith{ 154864987Smsmith struct mly_command *mc; 154964987Smsmith union mly_status_packet *sp; 155064987Smsmith u_int16_t slot; 1551274677Sjhb int worked; 155264987Smsmith 1553274677Sjhb MLY_ASSERT_LOCKED(sc); 155464987Smsmith worked = 0; 155564987Smsmith 155664987Smsmith /* pick up hardware-mailbox commands */ 155764987Smsmith if (MLY_ODBR_TRUE(sc, MLY_HM_STSREADY)) { 155864987Smsmith slot = MLY_GET_REG2(sc, sc->mly_status_mailbox); 155964987Smsmith if (slot < MLY_SLOT_MAX) { 156073050Smsmith mc = &sc->mly_command[slot - MLY_SLOT_START]; 156173050Smsmith mc->mc_status = MLY_GET_REG(sc, sc->mly_status_mailbox + 2); 156273050Smsmith mc->mc_sense = MLY_GET_REG(sc, sc->mly_status_mailbox + 3); 156373050Smsmith mc->mc_resid = MLY_GET_REG4(sc, sc->mly_status_mailbox + 4); 156473050Smsmith mly_remove_busy(mc); 156573050Smsmith mc->mc_flags &= ~MLY_CMD_BUSY; 156673050Smsmith mly_enqueue_complete(mc); 156773050Smsmith worked = 1; 156864987Smsmith } else { 156964987Smsmith /* slot 0xffff may mean "extremely bogus command" */ 157064987Smsmith mly_printf(sc, "got HM completion for illegal slot %u\n", slot); 157164987Smsmith } 157264987Smsmith /* unconditionally acknowledge status */ 157364987Smsmith MLY_SET_REG(sc, sc->mly_odbr, MLY_HM_STSREADY); 157464987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); 157564987Smsmith } 157664987Smsmith 157764987Smsmith /* pick up memory-mailbox commands */ 157864987Smsmith if (MLY_ODBR_TRUE(sc, MLY_AM_STSREADY)) { 157964987Smsmith for (;;) { 158064987Smsmith sp = &sc->mly_mmbox->mmm_status[sc->mly_mmbox_status_index]; 158164987Smsmith 158264987Smsmith /* check for more status */ 158364987Smsmith if (sp->mmbox.flag == 0) 158464987Smsmith break; 158564987Smsmith 158664987Smsmith /* get slot number */ 158764987Smsmith slot = sp->status.command_id; 158864987Smsmith if (slot < MLY_SLOT_MAX) { 158973050Smsmith mc = &sc->mly_command[slot - MLY_SLOT_START]; 159073050Smsmith mc->mc_status = sp->status.status; 159173050Smsmith mc->mc_sense = sp->status.sense_length; 159273050Smsmith mc->mc_resid = sp->status.residue; 159373050Smsmith mly_remove_busy(mc); 159473050Smsmith mc->mc_flags &= ~MLY_CMD_BUSY; 159573050Smsmith mly_enqueue_complete(mc); 159673050Smsmith worked = 1; 159764987Smsmith } else { 159864987Smsmith /* slot 0xffff may mean "extremely bogus command" */ 159973050Smsmith mly_printf(sc, "got AM completion for illegal slot %u at %d\n", 160073050Smsmith slot, sc->mly_mmbox_status_index); 160164987Smsmith } 160264987Smsmith 160373050Smsmith /* clear and move to next index */ 160464987Smsmith sp->mmbox.flag = 0; 160564987Smsmith sc->mly_mmbox_status_index = (sc->mly_mmbox_status_index + 1) % MLY_MMBOX_STATUS; 160664987Smsmith } 160764987Smsmith /* acknowledge that we have collected status value(s) */ 160864987Smsmith MLY_SET_REG(sc, sc->mly_odbr, MLY_AM_STSREADY); 160964987Smsmith } 161064987Smsmith 161164987Smsmith if (worked) { 161264987Smsmith if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) 1613274677Sjhb taskqueue_enqueue(taskqueue_thread, &sc->mly_task_complete); 161464987Smsmith else 1615274677Sjhb mly_complete(sc); 161664987Smsmith } 161764987Smsmith} 161864987Smsmith 161964987Smsmith/******************************************************************************** 162064987Smsmith * Process completed commands 162164987Smsmith */ 162264987Smsmithstatic void 1623274677Sjhbmly_complete_handler(void *context, int pending) 162464987Smsmith{ 162564987Smsmith struct mly_softc *sc = (struct mly_softc *)context; 1626274677Sjhb 1627274677Sjhb MLY_LOCK(sc); 1628274677Sjhb mly_complete(sc); 1629274677Sjhb MLY_UNLOCK(sc); 1630274677Sjhb} 1631274677Sjhb 1632274677Sjhbstatic void 1633274677Sjhbmly_complete(struct mly_softc *sc) 1634274677Sjhb{ 163564987Smsmith struct mly_command *mc; 163664987Smsmith void (* mc_complete)(struct mly_command *mc); 163764987Smsmith 163864987Smsmith debug_called(2); 163964987Smsmith 164064987Smsmith /* 164164987Smsmith * Spin pulling commands off the completed queue and processing them. 164264987Smsmith */ 164373050Smsmith while ((mc = mly_dequeue_complete(sc)) != NULL) { 164464987Smsmith 164564987Smsmith /* 164664987Smsmith * Free controller resources, mark command complete. 164764987Smsmith * 164864987Smsmith * Note that as soon as we mark the command complete, it may be freed 164964987Smsmith * out from under us, so we need to save the mc_complete field in 165064987Smsmith * order to later avoid dereferencing mc. (We would not expect to 165164987Smsmith * have a polling/sleeping consumer with mc_complete != NULL). 165264987Smsmith */ 165364987Smsmith mly_unmap_command(mc); 165464987Smsmith mc_complete = mc->mc_complete; 165573050Smsmith mc->mc_flags |= MLY_CMD_COMPLETE; 165664987Smsmith 165764987Smsmith /* 165864987Smsmith * Call completion handler or wake up sleeping consumer. 165964987Smsmith */ 166064987Smsmith if (mc_complete != NULL) { 166164987Smsmith mc_complete(mc); 166264987Smsmith } else { 166364987Smsmith wakeup(mc); 166464987Smsmith } 166564987Smsmith } 166679695Smsmith 166764987Smsmith /* 166879695Smsmith * XXX if we are deferring commands due to controller-busy status, we should 166979695Smsmith * retry submitting them here. 167064987Smsmith */ 167164987Smsmith} 167264987Smsmith 167364987Smsmith/******************************************************************************** 167464987Smsmith ******************************************************************************** 167564987Smsmith Command Buffer Management 167664987Smsmith ******************************************************************************** 167764987Smsmith ********************************************************************************/ 167864987Smsmith 167964987Smsmith/******************************************************************************** 168064987Smsmith * Allocate a command. 168164987Smsmith */ 1682105215Sphkstatic int 168364987Smsmithmly_alloc_command(struct mly_softc *sc, struct mly_command **mcp) 168464987Smsmith{ 168564987Smsmith struct mly_command *mc; 168664987Smsmith 168764987Smsmith debug_called(3); 168864987Smsmith 168973050Smsmith if ((mc = mly_dequeue_free(sc)) == NULL) 169064987Smsmith return(ENOMEM); 169164987Smsmith 169264987Smsmith *mcp = mc; 169364987Smsmith return(0); 169464987Smsmith} 169564987Smsmith 169664987Smsmith/******************************************************************************** 169764987Smsmith * Release a command back to the freelist. 169864987Smsmith */ 1699105215Sphkstatic void 170064987Smsmithmly_release_command(struct mly_command *mc) 170164987Smsmith{ 170264987Smsmith debug_called(3); 170364987Smsmith 170464987Smsmith /* 170564987Smsmith * Fill in parts of the command that may cause confusion if 170664987Smsmith * a consumer doesn't when we are later allocated. 170764987Smsmith */ 170864987Smsmith mc->mc_data = NULL; 170964987Smsmith mc->mc_flags = 0; 171064987Smsmith mc->mc_complete = NULL; 171164987Smsmith mc->mc_private = NULL; 171264987Smsmith 171364987Smsmith /* 171464987Smsmith * By default, we set up to overwrite the command packet with 171564987Smsmith * sense information. 171664987Smsmith */ 171764987Smsmith mc->mc_packet->generic.sense_buffer_address = mc->mc_packetphys; 171864987Smsmith mc->mc_packet->generic.maximum_sense_size = sizeof(union mly_command_packet); 171964987Smsmith 172064987Smsmith mly_enqueue_free(mc); 172164987Smsmith} 172264987Smsmith 172364987Smsmith/******************************************************************************** 172473050Smsmith * Map helper for command allocation. 172564987Smsmith */ 172664987Smsmithstatic void 172773050Smsmithmly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 172864987Smsmith{ 172979695Smsmith struct mly_softc *sc = (struct mly_softc *)arg; 173064987Smsmith 173179695Smsmith debug_called(1); 173264987Smsmith 173373050Smsmith sc->mly_packetphys = segs[0].ds_addr; 173464987Smsmith} 173564987Smsmith 173664987Smsmith/******************************************************************************** 173773050Smsmith * Allocate and initialise command and packet structures. 173879695Smsmith * 173979695Smsmith * If the controller supports fewer than MLY_MAX_COMMANDS commands, limit our 174079695Smsmith * allocation to that number. If we don't yet know how many commands the 174179695Smsmith * controller supports, allocate a very small set (suitable for initialisation 174279695Smsmith * purposes only). 174364987Smsmith */ 174473050Smsmithstatic int 174573050Smsmithmly_alloc_commands(struct mly_softc *sc) 174664987Smsmith{ 174764987Smsmith struct mly_command *mc; 174879695Smsmith int i, ncmd; 174964987Smsmith 175079695Smsmith if (sc->mly_controllerinfo == NULL) { 175179695Smsmith ncmd = 4; 175279695Smsmith } else { 175379695Smsmith ncmd = min(MLY_MAX_COMMANDS, sc->mly_controllerinfo->maximum_parallel_commands); 175479695Smsmith } 175579695Smsmith 175673050Smsmith /* 175773050Smsmith * Allocate enough space for all the command packets in one chunk and 175873050Smsmith * map them permanently into controller-visible space. 175973050Smsmith */ 176073050Smsmith if (bus_dmamem_alloc(sc->mly_packet_dmat, (void **)&sc->mly_packet, 176173050Smsmith BUS_DMA_NOWAIT, &sc->mly_packetmap)) { 176273050Smsmith return(ENOMEM); 176373050Smsmith } 1764118762Sscottl if (bus_dmamap_load(sc->mly_packet_dmat, sc->mly_packetmap, sc->mly_packet, 1765118762Sscottl ncmd * sizeof(union mly_command_packet), 1766118762Sscottl mly_alloc_commands_map, sc, BUS_DMA_NOWAIT) != 0) 1767118762Sscottl return (ENOMEM); 176864987Smsmith 176979695Smsmith for (i = 0; i < ncmd; i++) { 177073050Smsmith mc = &sc->mly_command[i]; 177173050Smsmith bzero(mc, sizeof(*mc)); 177273050Smsmith mc->mc_sc = sc; 177373050Smsmith mc->mc_slot = MLY_SLOT_START + i; 177473050Smsmith mc->mc_packet = sc->mly_packet + i; 177573050Smsmith mc->mc_packetphys = sc->mly_packetphys + (i * sizeof(union mly_command_packet)); 177673050Smsmith if (!bus_dmamap_create(sc->mly_buffer_dmat, 0, &mc->mc_datamap)) 177773050Smsmith mly_release_command(mc); 177864987Smsmith } 177973050Smsmith return(0); 178064987Smsmith} 178164987Smsmith 178264987Smsmith/******************************************************************************** 178379695Smsmith * Free all the storage held by commands. 178479695Smsmith * 178579695Smsmith * Must be called with all commands on the free list. 178679695Smsmith */ 178779695Smsmithstatic void 178879695Smsmithmly_release_commands(struct mly_softc *sc) 178979695Smsmith{ 179079695Smsmith struct mly_command *mc; 179179695Smsmith 179279695Smsmith /* throw away command buffer DMA maps */ 179379695Smsmith while (mly_alloc_command(sc, &mc) == 0) 179479695Smsmith bus_dmamap_destroy(sc->mly_buffer_dmat, mc->mc_datamap); 179579695Smsmith 179679695Smsmith /* release the packet storage */ 179779695Smsmith if (sc->mly_packet != NULL) { 179879695Smsmith bus_dmamap_unload(sc->mly_packet_dmat, sc->mly_packetmap); 179979695Smsmith bus_dmamem_free(sc->mly_packet_dmat, sc->mly_packet, sc->mly_packetmap); 180079695Smsmith sc->mly_packet = NULL; 180179695Smsmith } 180279695Smsmith} 180379695Smsmith 180479695Smsmith 180579695Smsmith/******************************************************************************** 180673050Smsmith * Command-mapping helper function - populate this command's s/g table 180773050Smsmith * with the s/g entries for its data. 180864987Smsmith */ 180964987Smsmithstatic void 181064987Smsmithmly_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 181164987Smsmith{ 181264987Smsmith struct mly_command *mc = (struct mly_command *)arg; 181364987Smsmith struct mly_softc *sc = mc->mc_sc; 181464987Smsmith struct mly_command_generic *gen = &(mc->mc_packet->generic); 181564987Smsmith struct mly_sg_entry *sg; 181664987Smsmith int i, tabofs; 181764987Smsmith 181879695Smsmith debug_called(2); 181964987Smsmith 182064987Smsmith /* can we use the transfer structure directly? */ 182164987Smsmith if (nseg <= 2) { 182264987Smsmith sg = &gen->transfer.direct.sg[0]; 182364987Smsmith gen->command_control.extended_sg_table = 0; 182464987Smsmith } else { 182579695Smsmith tabofs = ((mc->mc_slot - MLY_SLOT_START) * MLY_MAX_SGENTRIES); 182664987Smsmith sg = sc->mly_sg_table + tabofs; 182764987Smsmith gen->transfer.indirect.entries[0] = nseg; 182864987Smsmith gen->transfer.indirect.table_physaddr[0] = sc->mly_sg_busaddr + (tabofs * sizeof(struct mly_sg_entry)); 182964987Smsmith gen->command_control.extended_sg_table = 1; 183064987Smsmith } 183164987Smsmith 183264987Smsmith /* copy the s/g table */ 183364987Smsmith for (i = 0; i < nseg; i++) { 183464987Smsmith sg[i].physaddr = segs[i].ds_addr; 183564987Smsmith sg[i].length = segs[i].ds_len; 183664987Smsmith } 183764987Smsmith 183864987Smsmith} 183964987Smsmith 184064987Smsmith#if 0 184164987Smsmith/******************************************************************************** 184264987Smsmith * Command-mapping helper function - save the cdb's physical address. 184364987Smsmith * 184464987Smsmith * We don't support 'large' SCSI commands at this time, so this is unused. 184564987Smsmith */ 184664987Smsmithstatic void 184764987Smsmithmly_map_command_cdb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 184864987Smsmith{ 184964987Smsmith struct mly_command *mc = (struct mly_command *)arg; 185064987Smsmith 185179695Smsmith debug_called(2); 185264987Smsmith 185364987Smsmith /* XXX can we safely assume that a CDB will never cross a page boundary? */ 185464987Smsmith if ((segs[0].ds_addr % PAGE_SIZE) > 185564987Smsmith ((segs[0].ds_addr + mc->mc_packet->scsi_large.cdb_length) % PAGE_SIZE)) 185664987Smsmith panic("cdb crosses page boundary"); 185764987Smsmith 185864987Smsmith /* fix up fields in the command packet */ 185964987Smsmith mc->mc_packet->scsi_large.cdb_physaddr = segs[0].ds_addr; 186064987Smsmith} 186164987Smsmith#endif 186264987Smsmith 186364987Smsmith/******************************************************************************** 186464987Smsmith * Map a command into controller-visible space 186564987Smsmith */ 186664987Smsmithstatic void 186764987Smsmithmly_map_command(struct mly_command *mc) 186864987Smsmith{ 186964987Smsmith struct mly_softc *sc = mc->mc_sc; 187064987Smsmith 187164987Smsmith debug_called(2); 187264987Smsmith 187364987Smsmith /* don't map more than once */ 187464987Smsmith if (mc->mc_flags & MLY_CMD_MAPPED) 187564987Smsmith return; 187664987Smsmith 187764987Smsmith /* does the command have a data buffer? */ 187879695Smsmith if (mc->mc_data != NULL) { 1879246713Skib if (mc->mc_flags & MLY_CMD_CCB) 1880246713Skib bus_dmamap_load_ccb(sc->mly_buffer_dmat, mc->mc_datamap, 1881246713Skib mc->mc_data, mly_map_command_sg, mc, 0); 1882246713Skib else 1883246713Skib bus_dmamap_load(sc->mly_buffer_dmat, mc->mc_datamap, 1884246713Skib mc->mc_data, mc->mc_length, 1885246713Skib mly_map_command_sg, mc, 0); 188679695Smsmith if (mc->mc_flags & MLY_CMD_DATAIN) 188779695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREREAD); 188879695Smsmith if (mc->mc_flags & MLY_CMD_DATAOUT) 188979695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_PREWRITE); 189079695Smsmith } 189164987Smsmith mc->mc_flags |= MLY_CMD_MAPPED; 189264987Smsmith} 189364987Smsmith 189464987Smsmith/******************************************************************************** 189564987Smsmith * Unmap a command from controller-visible space 189664987Smsmith */ 189764987Smsmithstatic void 189864987Smsmithmly_unmap_command(struct mly_command *mc) 189964987Smsmith{ 190064987Smsmith struct mly_softc *sc = mc->mc_sc; 190164987Smsmith 190264987Smsmith debug_called(2); 190364987Smsmith 190464987Smsmith if (!(mc->mc_flags & MLY_CMD_MAPPED)) 190564987Smsmith return; 190664987Smsmith 190779695Smsmith /* does the command have a data buffer? */ 190879695Smsmith if (mc->mc_data != NULL) { 190979695Smsmith if (mc->mc_flags & MLY_CMD_DATAIN) 191079695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTREAD); 191179695Smsmith if (mc->mc_flags & MLY_CMD_DATAOUT) 191279695Smsmith bus_dmamap_sync(sc->mly_buffer_dmat, mc->mc_datamap, BUS_DMASYNC_POSTWRITE); 191364987Smsmith 191464987Smsmith bus_dmamap_unload(sc->mly_buffer_dmat, mc->mc_datamap); 191579695Smsmith } 191664987Smsmith mc->mc_flags &= ~MLY_CMD_MAPPED; 191764987Smsmith} 191864987Smsmith 191979695Smsmith 192064987Smsmith/******************************************************************************** 192164987Smsmith ******************************************************************************** 192279695Smsmith CAM interface 192379695Smsmith ******************************************************************************** 192479695Smsmith ********************************************************************************/ 192579695Smsmith 192679695Smsmith/******************************************************************************** 192779695Smsmith * Attach the physical and virtual SCSI busses to CAM. 192879695Smsmith * 192979695Smsmith * Physical bus numbering starts from 0, virtual bus numbering from one greater 193079695Smsmith * than the highest physical bus. Physical busses are only registered if 193179695Smsmith * the kernel environment variable "hw.mly.register_physical_channels" is set. 193279695Smsmith * 193379695Smsmith * When we refer to a "bus", we are referring to the bus number registered with 1934298955Spfg * the SIM, whereas a "channel" is a channel number given to the adapter. In order 193579695Smsmith * to keep things simple, we map these 1:1, so "bus" and "channel" may be used 193679695Smsmith * interchangeably. 193779695Smsmith */ 1938105215Sphkstatic int 193979695Smsmithmly_cam_attach(struct mly_softc *sc) 194079695Smsmith{ 194179695Smsmith struct cam_devq *devq; 194279695Smsmith int chn, i; 194379695Smsmith 194479695Smsmith debug_called(1); 194579695Smsmith 194679695Smsmith /* 194779695Smsmith * Allocate a devq for all our channels combined. 194879695Smsmith */ 194979695Smsmith if ((devq = cam_simq_alloc(sc->mly_controllerinfo->maximum_parallel_commands)) == NULL) { 195079695Smsmith mly_printf(sc, "can't allocate CAM SIM queue\n"); 195179695Smsmith return(ENOMEM); 195279695Smsmith } 195379695Smsmith 195479695Smsmith /* 195579695Smsmith * If physical channel registration has been requested, register these first. 195679695Smsmith * Note that we enable tagged command queueing for physical channels. 195779695Smsmith */ 195894936Smux if (testenv("hw.mly.register_physical_channels")) { 195979695Smsmith chn = 0; 196079695Smsmith for (i = 0; i < sc->mly_controllerinfo->physical_channels_present; i++, chn++) { 196179695Smsmith 196279695Smsmith if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, 196379695Smsmith device_get_unit(sc->mly_dev), 1964274677Sjhb &sc->mly_lock, 196579695Smsmith sc->mly_controllerinfo->maximum_parallel_commands, 196679695Smsmith 1, devq)) == NULL) { 196779695Smsmith return(ENOMEM); 196879695Smsmith } 1969274677Sjhb MLY_LOCK(sc); 1970170872Sscottl if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) { 1971274677Sjhb MLY_UNLOCK(sc); 197279695Smsmith mly_printf(sc, "CAM XPT phsyical channel registration failed\n"); 197379695Smsmith return(ENXIO); 197479695Smsmith } 1975274677Sjhb MLY_UNLOCK(sc); 197679695Smsmith debug(1, "registered physical channel %d", chn); 197779695Smsmith } 197879695Smsmith } 197979695Smsmith 198079695Smsmith /* 198179695Smsmith * Register our virtual channels, with bus numbers matching channel numbers. 198279695Smsmith */ 198379695Smsmith chn = sc->mly_controllerinfo->physical_channels_present; 198479695Smsmith for (i = 0; i < sc->mly_controllerinfo->virtual_channels_present; i++, chn++) { 198579695Smsmith if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, 198679695Smsmith device_get_unit(sc->mly_dev), 1987274677Sjhb &sc->mly_lock, 198879695Smsmith sc->mly_controllerinfo->maximum_parallel_commands, 198979695Smsmith 0, devq)) == NULL) { 199079695Smsmith return(ENOMEM); 199179695Smsmith } 1992274677Sjhb MLY_LOCK(sc); 1993170872Sscottl if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) { 1994274677Sjhb MLY_UNLOCK(sc); 199579695Smsmith mly_printf(sc, "CAM XPT virtual channel registration failed\n"); 199679695Smsmith return(ENXIO); 199779695Smsmith } 1998274677Sjhb MLY_UNLOCK(sc); 199979695Smsmith debug(1, "registered virtual channel %d", chn); 200079695Smsmith } 200179695Smsmith 200279695Smsmith /* 200379695Smsmith * This is the total number of channels that (might have been) registered with 200479695Smsmith * CAM. Some may not have been; check the mly_cam_sim array to be certain. 200579695Smsmith */ 200679695Smsmith sc->mly_cam_channels = sc->mly_controllerinfo->physical_channels_present + 200779695Smsmith sc->mly_controllerinfo->virtual_channels_present; 200879695Smsmith 200979695Smsmith return(0); 201079695Smsmith} 201179695Smsmith 201279695Smsmith/******************************************************************************** 201379695Smsmith * Detach from CAM 201479695Smsmith */ 2015105215Sphkstatic void 201679695Smsmithmly_cam_detach(struct mly_softc *sc) 201779695Smsmith{ 201879695Smsmith int i; 201979695Smsmith 202079695Smsmith debug_called(1); 202179695Smsmith 2022274677Sjhb MLY_LOCK(sc); 202379695Smsmith for (i = 0; i < sc->mly_cam_channels; i++) { 202479695Smsmith if (sc->mly_cam_sim[i] != NULL) { 202579695Smsmith xpt_bus_deregister(cam_sim_path(sc->mly_cam_sim[i])); 202679695Smsmith cam_sim_free(sc->mly_cam_sim[i], 0); 202779695Smsmith } 202879695Smsmith } 2029274677Sjhb MLY_UNLOCK(sc); 203079695Smsmith if (sc->mly_cam_devq != NULL) 203179695Smsmith cam_simq_free(sc->mly_cam_devq); 203279695Smsmith} 203379695Smsmith 203479695Smsmith/************************************************************************ 203579695Smsmith * Rescan a device. 203679695Smsmith */ 203779695Smsmithstatic void 203879695Smsmithmly_cam_rescan_btl(struct mly_softc *sc, int bus, int target) 203979695Smsmith{ 204079695Smsmith union ccb *ccb; 204179695Smsmith 204279695Smsmith debug_called(1); 204379695Smsmith 2044203108Smav if ((ccb = xpt_alloc_ccb()) == NULL) { 204579695Smsmith mly_printf(sc, "rescan failed (can't allocate CCB)\n"); 204679695Smsmith return; 204779695Smsmith } 2048249468Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, 2049203108Smav cam_sim_path(sc->mly_cam_sim[bus]), target, 0) != CAM_REQ_CMP) { 205079695Smsmith mly_printf(sc, "rescan failed (can't create path)\n"); 2051203108Smav xpt_free_ccb(ccb); 205279695Smsmith return; 205379695Smsmith } 205479695Smsmith debug(1, "rescan target %d:%d", bus, target); 2055203108Smav xpt_rescan(ccb); 205679695Smsmith} 205779695Smsmith 205879695Smsmith/******************************************************************************** 205979695Smsmith * Handle an action requested by CAM 206079695Smsmith */ 206179695Smsmithstatic void 206279695Smsmithmly_cam_action(struct cam_sim *sim, union ccb *ccb) 206379695Smsmith{ 206479695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 206579695Smsmith 206679695Smsmith debug_called(2); 2067274677Sjhb MLY_ASSERT_LOCKED(sc); 206879695Smsmith 206979695Smsmith switch (ccb->ccb_h.func_code) { 207079695Smsmith 207179695Smsmith /* perform SCSI I/O */ 207279695Smsmith case XPT_SCSI_IO: 207379695Smsmith if (!mly_cam_action_io(sim, (struct ccb_scsiio *)&ccb->csio)) 207479695Smsmith return; 207579695Smsmith break; 207679695Smsmith 207779695Smsmith /* perform geometry calculations */ 207879695Smsmith case XPT_CALC_GEOMETRY: 207979695Smsmith { 208079695Smsmith struct ccb_calc_geometry *ccg = &ccb->ccg; 208179695Smsmith u_int32_t secs_per_cylinder; 208279695Smsmith 208379695Smsmith debug(2, "XPT_CALC_GEOMETRY %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 208479695Smsmith 208579695Smsmith if (sc->mly_controllerparam->bios_geometry == MLY_BIOSGEOM_8G) { 208679695Smsmith ccg->heads = 255; 208779695Smsmith ccg->secs_per_track = 63; 208879695Smsmith } else { /* MLY_BIOSGEOM_2G */ 208979695Smsmith ccg->heads = 128; 209079695Smsmith ccg->secs_per_track = 32; 209179695Smsmith } 209279695Smsmith secs_per_cylinder = ccg->heads * ccg->secs_per_track; 209379695Smsmith ccg->cylinders = ccg->volume_size / secs_per_cylinder; 209479695Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 209579695Smsmith break; 209679695Smsmith } 209779695Smsmith 209879695Smsmith /* handle path attribute inquiry */ 209979695Smsmith case XPT_PATH_INQ: 210079695Smsmith { 210179695Smsmith struct ccb_pathinq *cpi = &ccb->cpi; 210279695Smsmith 210379695Smsmith debug(2, "XPT_PATH_INQ %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 210479695Smsmith 210579695Smsmith cpi->version_num = 1; 210679695Smsmith cpi->hba_inquiry = PI_TAG_ABLE; /* XXX extra flags for physical channels? */ 210779695Smsmith cpi->target_sprt = 0; 210879695Smsmith cpi->hba_misc = 0; 210979695Smsmith cpi->max_target = MLY_MAX_TARGETS - 1; 211079695Smsmith cpi->max_lun = MLY_MAX_LUNS - 1; 211179695Smsmith cpi->initiator_id = sc->mly_controllerparam->initiator_id; 2112315812Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2113335138Smav strlcpy(cpi->hba_vid, "Mylex", HBA_IDLEN); 2114335138Smav strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2115335138Smav cpi->unit_number = cam_sim_unit(sim); 2116335138Smav cpi->bus_id = cam_sim_bus(sim); 211779695Smsmith cpi->base_transfer_speed = 132 * 1024; /* XXX what to set this to? */ 2118163816Smjacob cpi->transport = XPORT_SPI; 2119163816Smjacob cpi->transport_version = 2; 2120163816Smjacob cpi->protocol = PROTO_SCSI; 2121163816Smjacob cpi->protocol_version = SCSI_REV_2; 212279695Smsmith ccb->ccb_h.status = CAM_REQ_CMP; 212379695Smsmith break; 212479695Smsmith } 212579695Smsmith 212679695Smsmith case XPT_GET_TRAN_SETTINGS: 212779695Smsmith { 212879695Smsmith struct ccb_trans_settings *cts = &ccb->cts; 212979695Smsmith int bus, target; 2130163816Smjacob struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 2131163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 213279695Smsmith 2133163816Smjacob cts->protocol = PROTO_SCSI; 2134163816Smjacob cts->protocol_version = SCSI_REV_2; 2135163816Smjacob cts->transport = XPORT_SPI; 2136163816Smjacob cts->transport_version = 2; 2137163816Smjacob 2138163816Smjacob scsi->flags = 0; 2139163816Smjacob scsi->valid = 0; 2140163816Smjacob spi->flags = 0; 2141163816Smjacob spi->valid = 0; 2142163816Smjacob 214379695Smsmith bus = cam_sim_bus(sim); 214479695Smsmith target = cts->ccb_h.target_id; 2145163816Smjacob debug(2, "XPT_GET_TRAN_SETTINGS %d:%d", bus, target); 2146163816Smjacob /* logical device? */ 2147163816Smjacob if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) { 2148163816Smjacob /* nothing special for these */ 2149163816Smjacob /* physical device? */ 2150163816Smjacob } else if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_PHYSICAL) { 2151163816Smjacob /* allow CAM to try tagged transactions */ 2152163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 2153163816Smjacob scsi->valid |= CTS_SCSI_VALID_TQ; 2154163816Smjacob 2155163816Smjacob /* convert speed (MHz) to usec */ 2156163816Smjacob if (sc->mly_btl[bus][target].mb_speed == 0) { 2157163816Smjacob spi->sync_period = 1000000 / 5; 2158163816Smjacob } else { 2159163816Smjacob spi->sync_period = 1000000 / sc->mly_btl[bus][target].mb_speed; 2160163816Smjacob } 2161163816Smjacob 2162163816Smjacob /* convert bus width to CAM internal encoding */ 2163163816Smjacob switch (sc->mly_btl[bus][target].mb_width) { 2164163816Smjacob case 32: 2165163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT; 2166163816Smjacob break; 2167163816Smjacob case 16: 2168163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2169163816Smjacob break; 2170163816Smjacob case 8: 2171163816Smjacob default: 2172163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 2173163816Smjacob break; 2174163816Smjacob } 2175163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_BUS_WIDTH; 2176163816Smjacob 2177163816Smjacob /* not a device, bail out */ 2178163816Smjacob } else { 2179163816Smjacob cts->ccb_h.status = CAM_REQ_CMP_ERR; 2180163816Smjacob break; 2181163816Smjacob } 2182163816Smjacob 2183163816Smjacob /* disconnect always OK */ 2184163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 2185163816Smjacob spi->valid |= CTS_SPI_VALID_DISC; 2186163816Smjacob 218779695Smsmith cts->ccb_h.status = CAM_REQ_CMP; 218879695Smsmith break; 218979695Smsmith } 219079695Smsmith 219179695Smsmith default: /* we can't do this */ 219279695Smsmith debug(2, "unspported func_code = 0x%x", ccb->ccb_h.func_code); 219379695Smsmith ccb->ccb_h.status = CAM_REQ_INVALID; 219479695Smsmith break; 219579695Smsmith } 219679695Smsmith 219779695Smsmith xpt_done(ccb); 219879695Smsmith} 219979695Smsmith 220079695Smsmith/******************************************************************************** 220179695Smsmith * Handle an I/O operation requested by CAM 220279695Smsmith */ 220379695Smsmithstatic int 220479695Smsmithmly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio) 220579695Smsmith{ 220679695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 220779695Smsmith struct mly_command *mc; 220879695Smsmith struct mly_command_scsi_small *ss; 220979695Smsmith int bus, target; 221079695Smsmith int error; 221179695Smsmith 221279695Smsmith bus = cam_sim_bus(sim); 221379695Smsmith target = csio->ccb_h.target_id; 221479695Smsmith 221579695Smsmith debug(2, "XPT_SCSI_IO %d:%d:%d", bus, target, csio->ccb_h.target_lun); 221679695Smsmith 221779695Smsmith /* validate bus number */ 221879695Smsmith if (!MLY_BUS_IS_VALID(sc, bus)) { 221979695Smsmith debug(0, " invalid bus %d", bus); 222079695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 222179695Smsmith } 222279695Smsmith 222379695Smsmith /* check for I/O attempt to a protected device */ 222479695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_PROTECTED) { 222579695Smsmith debug(2, " device protected"); 222679695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 222779695Smsmith } 222879695Smsmith 222979695Smsmith /* check for I/O attempt to nonexistent device */ 223079695Smsmith if (!(sc->mly_btl[bus][target].mb_flags & (MLY_BTL_LOGICAL | MLY_BTL_PHYSICAL))) { 223179695Smsmith debug(2, " device %d:%d does not exist", bus, target); 223279695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 223379695Smsmith } 223479695Smsmith 223579695Smsmith /* XXX increase if/when we support large SCSI commands */ 223679695Smsmith if (csio->cdb_len > MLY_CMD_SCSI_SMALL_CDB) { 223779695Smsmith debug(0, " command too large (%d > %d)", csio->cdb_len, MLY_CMD_SCSI_SMALL_CDB); 223879695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 223979695Smsmith } 224079695Smsmith 224179695Smsmith /* check that the CDB pointer is not to a physical address */ 224279695Smsmith if ((csio->ccb_h.flags & CAM_CDB_POINTER) && (csio->ccb_h.flags & CAM_CDB_PHYS)) { 224379695Smsmith debug(0, " CDB pointer is to physical address"); 224479695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 224579695Smsmith } 224679695Smsmith 224779695Smsmith /* abandon aborted ccbs or those that have failed validation */ 224879695Smsmith if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 224979695Smsmith debug(2, "abandoning CCB due to abort/validation failure"); 225079695Smsmith return(EINVAL); 225179695Smsmith } 225279695Smsmith 225379695Smsmith /* 225479695Smsmith * Get a command, or push the ccb back to CAM and freeze the queue. 225579695Smsmith */ 225679695Smsmith if ((error = mly_alloc_command(sc, &mc))) { 225779695Smsmith xpt_freeze_simq(sim, 1); 225879695Smsmith csio->ccb_h.status |= CAM_REQUEUE_REQ; 2259110479Sscottl sc->mly_qfrzn_cnt++; 226079695Smsmith return(error); 226179695Smsmith } 226279695Smsmith 226379695Smsmith /* build the command */ 2264246713Skib mc->mc_data = csio; 226579695Smsmith mc->mc_length = csio->dxfer_len; 226679695Smsmith mc->mc_complete = mly_cam_complete; 226779695Smsmith mc->mc_private = csio; 2268246713Skib mc->mc_flags |= MLY_CMD_CCB; 2269246713Skib /* XXX This code doesn't set the data direction in mc_flags. */ 227079695Smsmith 227179695Smsmith /* save the bus number in the ccb for later recovery XXX should be a better way */ 227279695Smsmith csio->ccb_h.sim_priv.entries[0].field = bus; 227379695Smsmith 227479695Smsmith /* build the packet for the controller */ 227579695Smsmith ss = &mc->mc_packet->scsi_small; 227679695Smsmith ss->opcode = MDACMD_SCSI; 227780365Smsmith if (csio->ccb_h.flags & CAM_DIS_DISCONNECT) 227879695Smsmith ss->command_control.disable_disconnect = 1; 227979695Smsmith if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 228079695Smsmith ss->command_control.data_direction = MLY_CCB_WRITE; 228179695Smsmith ss->data_size = csio->dxfer_len; 228279695Smsmith ss->addr.phys.lun = csio->ccb_h.target_lun; 228379695Smsmith ss->addr.phys.target = csio->ccb_h.target_id; 228479695Smsmith ss->addr.phys.channel = bus; 228579695Smsmith if (csio->ccb_h.timeout < (60 * 1000)) { 228679695Smsmith ss->timeout.value = csio->ccb_h.timeout / 1000; 228779695Smsmith ss->timeout.scale = MLY_TIMEOUT_SECONDS; 228879695Smsmith } else if (csio->ccb_h.timeout < (60 * 60 * 1000)) { 228979695Smsmith ss->timeout.value = csio->ccb_h.timeout / (60 * 1000); 229079695Smsmith ss->timeout.scale = MLY_TIMEOUT_MINUTES; 229179695Smsmith } else { 229279695Smsmith ss->timeout.value = csio->ccb_h.timeout / (60 * 60 * 1000); /* overflow? */ 229379695Smsmith ss->timeout.scale = MLY_TIMEOUT_HOURS; 229479695Smsmith } 229579695Smsmith ss->maximum_sense_size = csio->sense_len; 229679695Smsmith ss->cdb_length = csio->cdb_len; 229779695Smsmith if (csio->ccb_h.flags & CAM_CDB_POINTER) { 229879695Smsmith bcopy(csio->cdb_io.cdb_ptr, ss->cdb, csio->cdb_len); 229979695Smsmith } else { 230079695Smsmith bcopy(csio->cdb_io.cdb_bytes, ss->cdb, csio->cdb_len); 230179695Smsmith } 230279695Smsmith 230379695Smsmith /* give the command to the controller */ 230479695Smsmith if ((error = mly_start(mc))) { 230579695Smsmith xpt_freeze_simq(sim, 1); 230679695Smsmith csio->ccb_h.status |= CAM_REQUEUE_REQ; 2307110479Sscottl sc->mly_qfrzn_cnt++; 230879695Smsmith return(error); 230979695Smsmith } 231079695Smsmith 231179695Smsmith return(0); 231279695Smsmith} 231379695Smsmith 231479695Smsmith/******************************************************************************** 231579695Smsmith * Check for possibly-completed commands. 231679695Smsmith */ 231779695Smsmithstatic void 231879695Smsmithmly_cam_poll(struct cam_sim *sim) 231979695Smsmith{ 232079695Smsmith struct mly_softc *sc = cam_sim_softc(sim); 232179695Smsmith 232279695Smsmith debug_called(2); 232379695Smsmith 232479695Smsmith mly_done(sc); 232579695Smsmith} 232679695Smsmith 232779695Smsmith/******************************************************************************** 232879695Smsmith * Handle completion of a command - pass results back through the CCB 232979695Smsmith */ 233079695Smsmithstatic void 233179695Smsmithmly_cam_complete(struct mly_command *mc) 233279695Smsmith{ 233379695Smsmith struct mly_softc *sc = mc->mc_sc; 233479695Smsmith struct ccb_scsiio *csio = (struct ccb_scsiio *)mc->mc_private; 233579695Smsmith struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)csio->data_ptr; 233679695Smsmith struct mly_btl *btl; 233779695Smsmith u_int8_t cmd; 233879695Smsmith int bus, target; 233979695Smsmith 234079695Smsmith debug_called(2); 234179695Smsmith 234279695Smsmith csio->scsi_status = mc->mc_status; 234379695Smsmith switch(mc->mc_status) { 234479695Smsmith case SCSI_STATUS_OK: 234579695Smsmith /* 234679695Smsmith * In order to report logical device type and status, we overwrite 234779695Smsmith * the result of the INQUIRY command to logical devices. 234879695Smsmith */ 234979695Smsmith bus = csio->ccb_h.sim_priv.entries[0].field; 235079695Smsmith target = csio->ccb_h.target_id; 235179695Smsmith /* XXX validate bus/target? */ 235279695Smsmith if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) { 235379695Smsmith if (csio->ccb_h.flags & CAM_CDB_POINTER) { 235479695Smsmith cmd = *csio->cdb_io.cdb_ptr; 235579695Smsmith } else { 235679695Smsmith cmd = csio->cdb_io.cdb_bytes[0]; 235779695Smsmith } 235879695Smsmith if (cmd == INQUIRY) { 235979695Smsmith btl = &sc->mly_btl[bus][target]; 236079695Smsmith padstr(inq->vendor, mly_describe_code(mly_table_device_type, btl->mb_type), 8); 236179695Smsmith padstr(inq->product, mly_describe_code(mly_table_device_state, btl->mb_state), 16); 236279695Smsmith padstr(inq->revision, "", 4); 236379695Smsmith } 236479695Smsmith } 236579695Smsmith 236679695Smsmith debug(2, "SCSI_STATUS_OK"); 236779695Smsmith csio->ccb_h.status = CAM_REQ_CMP; 236879695Smsmith break; 236979695Smsmith 237079695Smsmith case SCSI_STATUS_CHECK_COND: 237179695Smsmith debug(1, "SCSI_STATUS_CHECK_COND sense %d resid %d", mc->mc_sense, mc->mc_resid); 237279695Smsmith csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; 237379695Smsmith bzero(&csio->sense_data, SSD_FULL_SIZE); 237479695Smsmith bcopy(mc->mc_packet, &csio->sense_data, mc->mc_sense); 237579695Smsmith csio->sense_len = mc->mc_sense; 237679695Smsmith csio->ccb_h.status |= CAM_AUTOSNS_VALID; 237779695Smsmith csio->resid = mc->mc_resid; /* XXX this is a signed value... */ 237879695Smsmith break; 237979695Smsmith 238079695Smsmith case SCSI_STATUS_BUSY: 238179695Smsmith debug(1, "SCSI_STATUS_BUSY"); 238279695Smsmith csio->ccb_h.status = CAM_SCSI_BUSY; 238379695Smsmith break; 238479695Smsmith 238579695Smsmith default: 238679695Smsmith debug(1, "unknown status 0x%x", csio->scsi_status); 238779695Smsmith csio->ccb_h.status = CAM_REQ_CMP_ERR; 238879695Smsmith break; 238979695Smsmith } 2390110479Sscottl 2391110479Sscottl if (sc->mly_qfrzn_cnt) { 2392110479Sscottl csio->ccb_h.status |= CAM_RELEASE_SIMQ; 2393110479Sscottl sc->mly_qfrzn_cnt--; 2394110479Sscottl } 2395110479Sscottl 239679695Smsmith xpt_done((union ccb *)csio); 239779695Smsmith mly_release_command(mc); 239879695Smsmith} 239979695Smsmith 240079695Smsmith/******************************************************************************** 240179695Smsmith * Find a peripheral attahed at (bus),(target) 240279695Smsmith */ 240379695Smsmithstatic struct cam_periph * 240479695Smsmithmly_find_periph(struct mly_softc *sc, int bus, int target) 240579695Smsmith{ 240679695Smsmith struct cam_periph *periph; 240779695Smsmith struct cam_path *path; 240879695Smsmith int status; 240979695Smsmith 241079695Smsmith status = xpt_create_path(&path, NULL, cam_sim_path(sc->mly_cam_sim[bus]), target, 0); 241179695Smsmith if (status == CAM_REQ_CMP) { 241279695Smsmith periph = cam_periph_find(path, NULL); 241379695Smsmith xpt_free_path(path); 241479695Smsmith } else { 241579695Smsmith periph = NULL; 241679695Smsmith } 241779695Smsmith return(periph); 241879695Smsmith} 241979695Smsmith 242079695Smsmith/******************************************************************************** 242179695Smsmith * Name the device at (bus)(target) 242279695Smsmith */ 2423105215Sphkstatic int 242479695Smsmithmly_name_device(struct mly_softc *sc, int bus, int target) 242579695Smsmith{ 242679695Smsmith struct cam_periph *periph; 242779695Smsmith 242879695Smsmith if ((periph = mly_find_periph(sc, bus, target)) != NULL) { 242979695Smsmith sprintf(sc->mly_btl[bus][target].mb_name, "%s%d", periph->periph_name, periph->unit_number); 243079695Smsmith return(0); 243179695Smsmith } 243279695Smsmith sc->mly_btl[bus][target].mb_name[0] = 0; 243379695Smsmith return(ENOENT); 243479695Smsmith} 243579695Smsmith 243679695Smsmith/******************************************************************************** 243779695Smsmith ******************************************************************************** 243864987Smsmith Hardware Control 243964987Smsmith ******************************************************************************** 244064987Smsmith ********************************************************************************/ 244164987Smsmith 244264987Smsmith/******************************************************************************** 244364987Smsmith * Handshake with the firmware while the card is being initialised. 244464987Smsmith */ 244564987Smsmithstatic int 244664987Smsmithmly_fwhandshake(struct mly_softc *sc) 244764987Smsmith{ 244864987Smsmith u_int8_t error, param0, param1; 244964987Smsmith int spinup = 0; 245064987Smsmith 245164987Smsmith debug_called(1); 245264987Smsmith 245364987Smsmith /* set HM_STSACK and let the firmware initialise */ 245464987Smsmith MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK); 245564987Smsmith DELAY(1000); /* too short? */ 245664987Smsmith 245764987Smsmith /* if HM_STSACK is still true, the controller is initialising */ 245864987Smsmith if (!MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) 245964987Smsmith return(0); 246064987Smsmith mly_printf(sc, "controller initialisation started\n"); 246164987Smsmith 246264987Smsmith /* spin waiting for initialisation to finish, or for a message to be delivered */ 246364987Smsmith while (MLY_IDBR_TRUE(sc, MLY_HM_STSACK)) { 246464987Smsmith /* check for a message */ 246564987Smsmith if (MLY_ERROR_VALID(sc)) { 246664987Smsmith error = MLY_GET_REG(sc, sc->mly_error_status) & ~MLY_MSG_EMPTY; 246764987Smsmith param0 = MLY_GET_REG(sc, sc->mly_command_mailbox); 246864987Smsmith param1 = MLY_GET_REG(sc, sc->mly_command_mailbox + 1); 246964987Smsmith 247064987Smsmith switch(error) { 247164987Smsmith case MLY_MSG_SPINUP: 247264987Smsmith if (!spinup) { 247364987Smsmith mly_printf(sc, "drive spinup in progress\n"); 247464987Smsmith spinup = 1; /* only print this once (should print drive being spun?) */ 247564987Smsmith } 247664987Smsmith break; 247764987Smsmith case MLY_MSG_RACE_RECOVERY_FAIL: 247864987Smsmith mly_printf(sc, "mirror race recovery failed, one or more drives offline\n"); 247964987Smsmith break; 248064987Smsmith case MLY_MSG_RACE_IN_PROGRESS: 248164987Smsmith mly_printf(sc, "mirror race recovery in progress\n"); 248264987Smsmith break; 248364987Smsmith case MLY_MSG_RACE_ON_CRITICAL: 248464987Smsmith mly_printf(sc, "mirror race recovery on a critical drive\n"); 248564987Smsmith break; 248664987Smsmith case MLY_MSG_PARITY_ERROR: 248764987Smsmith mly_printf(sc, "FATAL MEMORY PARITY ERROR\n"); 248864987Smsmith return(ENXIO); 248964987Smsmith default: 249064987Smsmith mly_printf(sc, "unknown initialisation code 0x%x\n", error); 249164987Smsmith } 249264987Smsmith } 249364987Smsmith } 249464987Smsmith return(0); 249564987Smsmith} 249664987Smsmith 249764987Smsmith/******************************************************************************** 249864987Smsmith ******************************************************************************** 249964987Smsmith Debugging and Diagnostics 250064987Smsmith ******************************************************************************** 250164987Smsmith ********************************************************************************/ 250264987Smsmith 250364987Smsmith/******************************************************************************** 250464987Smsmith * Print some information about the controller. 250564987Smsmith */ 250664987Smsmithstatic void 250764987Smsmithmly_describe_controller(struct mly_softc *sc) 250864987Smsmith{ 250964987Smsmith struct mly_ioctl_getcontrollerinfo *mi = sc->mly_controllerinfo; 251064987Smsmith 251164987Smsmith mly_printf(sc, "%16s, %d channel%s, firmware %d.%02d-%d-%02d (%02d%02d%02d%02d), %dMB RAM\n", 251264987Smsmith mi->controller_name, mi->physical_channels_present, (mi->physical_channels_present) > 1 ? "s" : "", 251364987Smsmith mi->fw_major, mi->fw_minor, mi->fw_turn, mi->fw_build, /* XXX turn encoding? */ 251464987Smsmith mi->fw_century, mi->fw_year, mi->fw_month, mi->fw_day, 251564987Smsmith mi->memory_size); 251664987Smsmith 251764987Smsmith if (bootverbose) { 251864987Smsmith mly_printf(sc, "%s %s (%x), %dMHz %d-bit %.16s\n", 251964987Smsmith mly_describe_code(mly_table_oemname, mi->oem_information), 252064987Smsmith mly_describe_code(mly_table_controllertype, mi->controller_type), mi->controller_type, 252164987Smsmith mi->interface_speed, mi->interface_width, mi->interface_name); 252264987Smsmith mly_printf(sc, "%dMB %dMHz %d-bit %s%s%s, cache %dMB\n", 252364987Smsmith mi->memory_size, mi->memory_speed, mi->memory_width, 252464987Smsmith mly_describe_code(mly_table_memorytype, mi->memory_type), 252564987Smsmith mi->memory_parity ? "+parity": "",mi->memory_ecc ? "+ECC": "", 252664987Smsmith mi->cache_size); 2527202161Sgavin mly_printf(sc, "CPU: %s @ %dMHz\n", 252864987Smsmith mly_describe_code(mly_table_cputype, mi->cpu[0].type), mi->cpu[0].speed); 252964987Smsmith if (mi->l2cache_size != 0) 253064987Smsmith mly_printf(sc, "%dKB L2 cache\n", mi->l2cache_size); 253164987Smsmith if (mi->exmemory_size != 0) 253264987Smsmith mly_printf(sc, "%dMB %dMHz %d-bit private %s%s%s\n", 253364987Smsmith mi->exmemory_size, mi->exmemory_speed, mi->exmemory_width, 253464987Smsmith mly_describe_code(mly_table_memorytype, mi->exmemory_type), 253564987Smsmith mi->exmemory_parity ? "+parity": "",mi->exmemory_ecc ? "+ECC": ""); 253664987Smsmith mly_printf(sc, "battery backup %s\n", mi->bbu_present ? "present" : "not installed"); 253764987Smsmith mly_printf(sc, "maximum data transfer %d blocks, maximum sg entries/command %d\n", 253864987Smsmith mi->maximum_block_count, mi->maximum_sg_entries); 253964987Smsmith mly_printf(sc, "logical devices present/critical/offline %d/%d/%d\n", 254064987Smsmith mi->logical_devices_present, mi->logical_devices_critical, mi->logical_devices_offline); 254164987Smsmith mly_printf(sc, "physical devices present %d\n", 254264987Smsmith mi->physical_devices_present); 254364987Smsmith mly_printf(sc, "physical disks present/offline %d/%d\n", 254464987Smsmith mi->physical_disks_present, mi->physical_disks_offline); 254564987Smsmith mly_printf(sc, "%d physical channel%s, %d virtual channel%s of %d possible\n", 254664987Smsmith mi->physical_channels_present, mi->physical_channels_present == 1 ? "" : "s", 254764987Smsmith mi->virtual_channels_present, mi->virtual_channels_present == 1 ? "" : "s", 254864987Smsmith mi->virtual_channels_possible); 254964987Smsmith mly_printf(sc, "%d parallel commands supported\n", mi->maximum_parallel_commands); 255064987Smsmith mly_printf(sc, "%dMB flash ROM, %d of %d maximum cycles\n", 255164987Smsmith mi->flash_size, mi->flash_age, mi->flash_maximum_age); 255264987Smsmith } 255364987Smsmith} 255464987Smsmith 255564987Smsmith#ifdef MLY_DEBUG 255664987Smsmith/******************************************************************************** 255764987Smsmith * Print some controller state 255864987Smsmith */ 255964987Smsmithstatic void 256064987Smsmithmly_printstate(struct mly_softc *sc) 256164987Smsmith{ 256264987Smsmith mly_printf(sc, "IDBR %02x ODBR %02x ERROR %02x (%x %x %x)\n", 256364987Smsmith MLY_GET_REG(sc, sc->mly_idbr), 256464987Smsmith MLY_GET_REG(sc, sc->mly_odbr), 256564987Smsmith MLY_GET_REG(sc, sc->mly_error_status), 256664987Smsmith sc->mly_idbr, 256764987Smsmith sc->mly_odbr, 256864987Smsmith sc->mly_error_status); 256964987Smsmith mly_printf(sc, "IMASK %02x ISTATUS %02x\n", 257064987Smsmith MLY_GET_REG(sc, sc->mly_interrupt_mask), 257164987Smsmith MLY_GET_REG(sc, sc->mly_interrupt_status)); 257264987Smsmith mly_printf(sc, "COMMAND %02x %02x %02x %02x %02x %02x %02x %02x\n", 257364987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox), 257464987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 1), 257564987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 2), 257664987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 3), 257764987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 4), 257864987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 5), 257964987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 6), 258064987Smsmith MLY_GET_REG(sc, sc->mly_command_mailbox + 7)); 258164987Smsmith mly_printf(sc, "STATUS %02x %02x %02x %02x %02x %02x %02x %02x\n", 258264987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox), 258364987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 1), 258464987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 2), 258564987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 3), 258664987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 4), 258764987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 5), 258864987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 6), 258964987Smsmith MLY_GET_REG(sc, sc->mly_status_mailbox + 7)); 259064987Smsmith mly_printf(sc, " %04x %08x\n", 259164987Smsmith MLY_GET_REG2(sc, sc->mly_status_mailbox), 259264987Smsmith MLY_GET_REG4(sc, sc->mly_status_mailbox + 4)); 259364987Smsmith} 259464987Smsmith 259564987Smsmithstruct mly_softc *mly_softc0 = NULL; 259664987Smsmithvoid 259764987Smsmithmly_printstate0(void) 259864987Smsmith{ 259964987Smsmith if (mly_softc0 != NULL) 260064987Smsmith mly_printstate(mly_softc0); 260164987Smsmith} 260264987Smsmith 260364987Smsmith/******************************************************************************** 260464987Smsmith * Print a command 260564987Smsmith */ 260664987Smsmithstatic void 260764987Smsmithmly_print_command(struct mly_command *mc) 260864987Smsmith{ 260964987Smsmith struct mly_softc *sc = mc->mc_sc; 261064987Smsmith 261164987Smsmith mly_printf(sc, "COMMAND @ %p\n", mc); 261264987Smsmith mly_printf(sc, " slot %d\n", mc->mc_slot); 261364987Smsmith mly_printf(sc, " status 0x%x\n", mc->mc_status); 261464987Smsmith mly_printf(sc, " sense len %d\n", mc->mc_sense); 261564987Smsmith mly_printf(sc, " resid %d\n", mc->mc_resid); 261664987Smsmith mly_printf(sc, " packet %p/0x%llx\n", mc->mc_packet, mc->mc_packetphys); 261764987Smsmith if (mc->mc_packet != NULL) 261864987Smsmith mly_print_packet(mc); 261964987Smsmith mly_printf(sc, " data %p/%d\n", mc->mc_data, mc->mc_length); 262073050Smsmith mly_printf(sc, " flags %b\n", mc->mc_flags, "\20\1busy\2complete\3slotted\4mapped\5datain\6dataout\n"); 262164987Smsmith mly_printf(sc, " complete %p\n", mc->mc_complete); 262264987Smsmith mly_printf(sc, " private %p\n", mc->mc_private); 262364987Smsmith} 262464987Smsmith 262564987Smsmith/******************************************************************************** 262664987Smsmith * Print a command packet 262764987Smsmith */ 262864987Smsmithstatic void 262964987Smsmithmly_print_packet(struct mly_command *mc) 263064987Smsmith{ 263164987Smsmith struct mly_softc *sc = mc->mc_sc; 263264987Smsmith struct mly_command_generic *ge = (struct mly_command_generic *)mc->mc_packet; 263364987Smsmith struct mly_command_scsi_small *ss = (struct mly_command_scsi_small *)mc->mc_packet; 263464987Smsmith struct mly_command_scsi_large *sl = (struct mly_command_scsi_large *)mc->mc_packet; 263564987Smsmith struct mly_command_ioctl *io = (struct mly_command_ioctl *)mc->mc_packet; 263664987Smsmith int transfer; 263764987Smsmith 263864987Smsmith mly_printf(sc, " command_id %d\n", ge->command_id); 263964987Smsmith mly_printf(sc, " opcode %d\n", ge->opcode); 264064987Smsmith mly_printf(sc, " command_control fua %d dpo %d est %d dd %s nas %d ddis %d\n", 264164987Smsmith ge->command_control.force_unit_access, 264264987Smsmith ge->command_control.disable_page_out, 264364987Smsmith ge->command_control.extended_sg_table, 264464987Smsmith (ge->command_control.data_direction == MLY_CCB_WRITE) ? "WRITE" : "READ", 264564987Smsmith ge->command_control.no_auto_sense, 264664987Smsmith ge->command_control.disable_disconnect); 264764987Smsmith mly_printf(sc, " data_size %d\n", ge->data_size); 264864987Smsmith mly_printf(sc, " sense_buffer_address 0x%llx\n", ge->sense_buffer_address); 264964987Smsmith mly_printf(sc, " lun %d\n", ge->addr.phys.lun); 265064987Smsmith mly_printf(sc, " target %d\n", ge->addr.phys.target); 265164987Smsmith mly_printf(sc, " channel %d\n", ge->addr.phys.channel); 265264987Smsmith mly_printf(sc, " logical device %d\n", ge->addr.log.logdev); 265364987Smsmith mly_printf(sc, " controller %d\n", ge->addr.phys.controller); 265464987Smsmith mly_printf(sc, " timeout %d %s\n", 265564987Smsmith ge->timeout.value, 265664987Smsmith (ge->timeout.scale == MLY_TIMEOUT_SECONDS) ? "seconds" : 265764987Smsmith ((ge->timeout.scale == MLY_TIMEOUT_MINUTES) ? "minutes" : "hours")); 265864987Smsmith mly_printf(sc, " maximum_sense_size %d\n", ge->maximum_sense_size); 265964987Smsmith switch(ge->opcode) { 266064987Smsmith case MDACMD_SCSIPT: 266164987Smsmith case MDACMD_SCSI: 266264987Smsmith mly_printf(sc, " cdb length %d\n", ss->cdb_length); 266364987Smsmith mly_printf(sc, " cdb %*D\n", ss->cdb_length, ss->cdb, " "); 266464987Smsmith transfer = 1; 266564987Smsmith break; 266664987Smsmith case MDACMD_SCSILC: 266764987Smsmith case MDACMD_SCSILCPT: 266864987Smsmith mly_printf(sc, " cdb length %d\n", sl->cdb_length); 266964987Smsmith mly_printf(sc, " cdb 0x%llx\n", sl->cdb_physaddr); 267064987Smsmith transfer = 1; 267164987Smsmith break; 267264987Smsmith case MDACMD_IOCTL: 267364987Smsmith mly_printf(sc, " sub_ioctl 0x%x\n", io->sub_ioctl); 267464987Smsmith switch(io->sub_ioctl) { 267564987Smsmith case MDACIOCTL_SETMEMORYMAILBOX: 267664987Smsmith mly_printf(sc, " health_buffer_size %d\n", 267764987Smsmith io->param.setmemorymailbox.health_buffer_size); 267864987Smsmith mly_printf(sc, " health_buffer_phys 0x%llx\n", 267964987Smsmith io->param.setmemorymailbox.health_buffer_physaddr); 268064987Smsmith mly_printf(sc, " command_mailbox 0x%llx\n", 268164987Smsmith io->param.setmemorymailbox.command_mailbox_physaddr); 268264987Smsmith mly_printf(sc, " status_mailbox 0x%llx\n", 268364987Smsmith io->param.setmemorymailbox.status_mailbox_physaddr); 268464987Smsmith transfer = 0; 268564987Smsmith break; 268664987Smsmith 268764987Smsmith case MDACIOCTL_SETREALTIMECLOCK: 268864987Smsmith case MDACIOCTL_GETHEALTHSTATUS: 268964987Smsmith case MDACIOCTL_GETCONTROLLERINFO: 269064987Smsmith case MDACIOCTL_GETLOGDEVINFOVALID: 269164987Smsmith case MDACIOCTL_GETPHYSDEVINFOVALID: 269264987Smsmith case MDACIOCTL_GETPHYSDEVSTATISTICS: 269364987Smsmith case MDACIOCTL_GETLOGDEVSTATISTICS: 269464987Smsmith case MDACIOCTL_GETCONTROLLERSTATISTICS: 269564987Smsmith case MDACIOCTL_GETBDT_FOR_SYSDRIVE: 269664987Smsmith case MDACIOCTL_CREATENEWCONF: 269764987Smsmith case MDACIOCTL_ADDNEWCONF: 269864987Smsmith case MDACIOCTL_GETDEVCONFINFO: 269964987Smsmith case MDACIOCTL_GETFREESPACELIST: 270064987Smsmith case MDACIOCTL_MORE: 270164987Smsmith case MDACIOCTL_SETPHYSDEVPARAMETER: 270264987Smsmith case MDACIOCTL_GETPHYSDEVPARAMETER: 270364987Smsmith case MDACIOCTL_GETLOGDEVPARAMETER: 270464987Smsmith case MDACIOCTL_SETLOGDEVPARAMETER: 270564987Smsmith mly_printf(sc, " param %10D\n", io->param.data.param, " "); 270664987Smsmith transfer = 1; 270764987Smsmith break; 270864987Smsmith 270964987Smsmith case MDACIOCTL_GETEVENT: 271064987Smsmith mly_printf(sc, " event %d\n", 271164987Smsmith io->param.getevent.sequence_number_low + ((u_int32_t)io->addr.log.logdev << 16)); 271264987Smsmith transfer = 1; 271364987Smsmith break; 271464987Smsmith 271564987Smsmith case MDACIOCTL_SETRAIDDEVSTATE: 271664987Smsmith mly_printf(sc, " state %d\n", io->param.setraiddevstate.state); 271764987Smsmith transfer = 0; 271864987Smsmith break; 271964987Smsmith 272064987Smsmith case MDACIOCTL_XLATEPHYSDEVTORAIDDEV: 272164987Smsmith mly_printf(sc, " raid_device %d\n", io->param.xlatephysdevtoraiddev.raid_device); 272264987Smsmith mly_printf(sc, " controller %d\n", io->param.xlatephysdevtoraiddev.controller); 272364987Smsmith mly_printf(sc, " channel %d\n", io->param.xlatephysdevtoraiddev.channel); 272464987Smsmith mly_printf(sc, " target %d\n", io->param.xlatephysdevtoraiddev.target); 272564987Smsmith mly_printf(sc, " lun %d\n", io->param.xlatephysdevtoraiddev.lun); 272664987Smsmith transfer = 0; 272764987Smsmith break; 272864987Smsmith 272964987Smsmith case MDACIOCTL_GETGROUPCONFINFO: 273064987Smsmith mly_printf(sc, " group %d\n", io->param.getgroupconfinfo.group); 273164987Smsmith transfer = 1; 273264987Smsmith break; 273364987Smsmith 273464987Smsmith case MDACIOCTL_GET_SUBSYSTEM_DATA: 273564987Smsmith case MDACIOCTL_SET_SUBSYSTEM_DATA: 273664987Smsmith case MDACIOCTL_STARTDISOCVERY: 273764987Smsmith case MDACIOCTL_INITPHYSDEVSTART: 273864987Smsmith case MDACIOCTL_INITPHYSDEVSTOP: 273964987Smsmith case MDACIOCTL_INITRAIDDEVSTART: 274064987Smsmith case MDACIOCTL_INITRAIDDEVSTOP: 274164987Smsmith case MDACIOCTL_REBUILDRAIDDEVSTART: 274264987Smsmith case MDACIOCTL_REBUILDRAIDDEVSTOP: 274364987Smsmith case MDACIOCTL_MAKECONSISTENTDATASTART: 274464987Smsmith case MDACIOCTL_MAKECONSISTENTDATASTOP: 274564987Smsmith case MDACIOCTL_CONSISTENCYCHECKSTART: 274664987Smsmith case MDACIOCTL_CONSISTENCYCHECKSTOP: 274764987Smsmith case MDACIOCTL_RESETDEVICE: 274864987Smsmith case MDACIOCTL_FLUSHDEVICEDATA: 274964987Smsmith case MDACIOCTL_PAUSEDEVICE: 275064987Smsmith case MDACIOCTL_UNPAUSEDEVICE: 275164987Smsmith case MDACIOCTL_LOCATEDEVICE: 275264987Smsmith case MDACIOCTL_SETMASTERSLAVEMODE: 275364987Smsmith case MDACIOCTL_DELETERAIDDEV: 275464987Smsmith case MDACIOCTL_REPLACEINTERNALDEV: 275564987Smsmith case MDACIOCTL_CLEARCONF: 275664987Smsmith case MDACIOCTL_GETCONTROLLERPARAMETER: 275764987Smsmith case MDACIOCTL_SETCONTRLLERPARAMETER: 275864987Smsmith case MDACIOCTL_CLEARCONFSUSPMODE: 275964987Smsmith case MDACIOCTL_STOREIMAGE: 276064987Smsmith case MDACIOCTL_READIMAGE: 276164987Smsmith case MDACIOCTL_FLASHIMAGES: 276264987Smsmith case MDACIOCTL_RENAMERAIDDEV: 276364987Smsmith default: /* no idea what to print */ 276464987Smsmith transfer = 0; 276564987Smsmith break; 276664987Smsmith } 276764987Smsmith break; 276864987Smsmith 276964987Smsmith case MDACMD_IOCTLCHECK: 277064987Smsmith case MDACMD_MEMCOPY: 277164987Smsmith default: 277264987Smsmith transfer = 0; 277364987Smsmith break; /* print nothing */ 277464987Smsmith } 277564987Smsmith if (transfer) { 277664987Smsmith if (ge->command_control.extended_sg_table) { 277764987Smsmith mly_printf(sc, " sg table 0x%llx/%d\n", 277864987Smsmith ge->transfer.indirect.table_physaddr[0], ge->transfer.indirect.entries[0]); 277964987Smsmith } else { 278064987Smsmith mly_printf(sc, " 0000 0x%llx/%lld\n", 278164987Smsmith ge->transfer.direct.sg[0].physaddr, ge->transfer.direct.sg[0].length); 278264987Smsmith mly_printf(sc, " 0001 0x%llx/%lld\n", 278364987Smsmith ge->transfer.direct.sg[1].physaddr, ge->transfer.direct.sg[1].length); 278464987Smsmith } 278564987Smsmith } 278664987Smsmith} 278764987Smsmith 278864987Smsmith/******************************************************************************** 278964987Smsmith * Panic in a slightly informative fashion 279064987Smsmith */ 279164987Smsmithstatic void 279264987Smsmithmly_panic(struct mly_softc *sc, char *reason) 279364987Smsmith{ 279464987Smsmith mly_printstate(sc); 279564987Smsmith panic(reason); 279664987Smsmith} 279773050Smsmith 279873050Smsmith/******************************************************************************** 279973050Smsmith * Print queue statistics, callable from DDB. 280073050Smsmith */ 280173050Smsmithvoid 280273050Smsmithmly_print_controller(int controller) 280373050Smsmith{ 280473050Smsmith struct mly_softc *sc; 280573050Smsmith 280673050Smsmith if ((sc = devclass_get_softc(devclass_find("mly"), controller)) == NULL) { 280773050Smsmith printf("mly: controller %d invalid\n", controller); 280873050Smsmith } else { 280973050Smsmith device_printf(sc->mly_dev, "queue curr max\n"); 281073050Smsmith device_printf(sc->mly_dev, "free %04d/%04d\n", 281173050Smsmith sc->mly_qstat[MLYQ_FREE].q_length, sc->mly_qstat[MLYQ_FREE].q_max); 281273050Smsmith device_printf(sc->mly_dev, "busy %04d/%04d\n", 281373050Smsmith sc->mly_qstat[MLYQ_BUSY].q_length, sc->mly_qstat[MLYQ_BUSY].q_max); 281473050Smsmith device_printf(sc->mly_dev, "complete %04d/%04d\n", 281573050Smsmith sc->mly_qstat[MLYQ_COMPLETE].q_length, sc->mly_qstat[MLYQ_COMPLETE].q_max); 281673050Smsmith } 281773050Smsmith} 281879695Smsmith#endif 281973050Smsmith 282073050Smsmith 282173050Smsmith/******************************************************************************** 282273050Smsmith ******************************************************************************** 282373050Smsmith Control device interface 282473050Smsmith ******************************************************************************** 282573050Smsmith ********************************************************************************/ 282673050Smsmith 282773050Smsmith/******************************************************************************** 282873050Smsmith * Accept an open operation on the control device. 282973050Smsmith */ 283073050Smsmithstatic int 2831130585Sphkmly_user_open(struct cdev *dev, int flags, int fmt, struct thread *td) 283273050Smsmith{ 2833191242Sed struct mly_softc *sc = dev->si_drv1; 283473050Smsmith 2835274677Sjhb MLY_LOCK(sc); 283673050Smsmith sc->mly_state |= MLY_STATE_OPEN; 2837274677Sjhb MLY_UNLOCK(sc); 283873050Smsmith return(0); 283973050Smsmith} 284073050Smsmith 284173050Smsmith/******************************************************************************** 284273050Smsmith * Accept the last close on the control device. 284373050Smsmith */ 284473050Smsmithstatic int 2845130585Sphkmly_user_close(struct cdev *dev, int flags, int fmt, struct thread *td) 284673050Smsmith{ 2847191242Sed struct mly_softc *sc = dev->si_drv1; 284873050Smsmith 2849274677Sjhb MLY_LOCK(sc); 285073050Smsmith sc->mly_state &= ~MLY_STATE_OPEN; 2851274677Sjhb MLY_UNLOCK(sc); 285273050Smsmith return (0); 285373050Smsmith} 285473050Smsmith 285573050Smsmith/******************************************************************************** 285673050Smsmith * Handle controller-specific control operations. 285773050Smsmith */ 285873050Smsmithstatic int 2859130585Sphkmly_user_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 286083366Sjulian int32_t flag, struct thread *td) 286173050Smsmith{ 286273050Smsmith struct mly_softc *sc = (struct mly_softc *)dev->si_drv1; 286373050Smsmith struct mly_user_command *uc = (struct mly_user_command *)addr; 286473050Smsmith struct mly_user_health *uh = (struct mly_user_health *)addr; 286573050Smsmith 286673050Smsmith switch(cmd) { 286773050Smsmith case MLYIO_COMMAND: 286873050Smsmith return(mly_user_command(sc, uc)); 286973050Smsmith case MLYIO_HEALTH: 287073050Smsmith return(mly_user_health(sc, uh)); 287173050Smsmith default: 287273050Smsmith return(ENOIOCTL); 287373050Smsmith } 287473050Smsmith} 287573050Smsmith 287673050Smsmith/******************************************************************************** 287773050Smsmith * Execute a command passed in from userspace. 287873050Smsmith * 287973050Smsmith * The control structure contains the actual command for the controller, as well 288073050Smsmith * as the user-space data pointer and data size, and an optional sense buffer 288173050Smsmith * size/pointer. On completion, the data size is adjusted to the command 288273050Smsmith * residual, and the sense buffer size to the size of the returned sense data. 288373050Smsmith * 288473050Smsmith */ 288573050Smsmithstatic int 288673050Smsmithmly_user_command(struct mly_softc *sc, struct mly_user_command *uc) 288773050Smsmith{ 288879695Smsmith struct mly_command *mc; 2889274677Sjhb int error; 289073050Smsmith 289173050Smsmith /* allocate a command */ 2892274677Sjhb MLY_LOCK(sc); 289373050Smsmith if (mly_alloc_command(sc, &mc)) { 2894274677Sjhb MLY_UNLOCK(sc); 2895323826Sjhb return (ENOMEM); /* XXX Linux version will wait for a command */ 289673050Smsmith } 2897274677Sjhb MLY_UNLOCK(sc); 289873050Smsmith 289973050Smsmith /* handle data size/direction */ 290073050Smsmith mc->mc_length = (uc->DataTransferLength >= 0) ? uc->DataTransferLength : -uc->DataTransferLength; 290173050Smsmith if (mc->mc_length > 0) { 290273050Smsmith if ((mc->mc_data = malloc(mc->mc_length, M_DEVBUF, M_NOWAIT)) == NULL) { 290373050Smsmith error = ENOMEM; 290473050Smsmith goto out; 290573050Smsmith } 290673050Smsmith } 290773050Smsmith if (uc->DataTransferLength > 0) { 290873050Smsmith mc->mc_flags |= MLY_CMD_DATAIN; 290973050Smsmith bzero(mc->mc_data, mc->mc_length); 291073050Smsmith } 291173050Smsmith if (uc->DataTransferLength < 0) { 291273050Smsmith mc->mc_flags |= MLY_CMD_DATAOUT; 291373050Smsmith if ((error = copyin(uc->DataTransferBuffer, mc->mc_data, mc->mc_length)) != 0) 291473050Smsmith goto out; 291573050Smsmith } 291673050Smsmith 291773050Smsmith /* copy the controller command */ 291873050Smsmith bcopy(&uc->CommandMailbox, mc->mc_packet, sizeof(uc->CommandMailbox)); 291973050Smsmith 292073050Smsmith /* clear command completion handler so that we get woken up */ 292173050Smsmith mc->mc_complete = NULL; 292273050Smsmith 292373050Smsmith /* execute the command */ 2924274677Sjhb MLY_LOCK(sc); 2925274677Sjhb if ((error = mly_start(mc)) != 0) { 2926274677Sjhb MLY_UNLOCK(sc); 292779695Smsmith goto out; 2928274677Sjhb } 292973050Smsmith while (!(mc->mc_flags & MLY_CMD_COMPLETE)) 2930274677Sjhb mtx_sleep(mc, &sc->mly_lock, PRIBIO, "mlyioctl", 0); 2931274677Sjhb MLY_UNLOCK(sc); 293273050Smsmith 293373050Smsmith /* return the data to userspace */ 293473050Smsmith if (uc->DataTransferLength > 0) 293573050Smsmith if ((error = copyout(mc->mc_data, uc->DataTransferBuffer, mc->mc_length)) != 0) 293673050Smsmith goto out; 293773050Smsmith 293873050Smsmith /* return the sense buffer to userspace */ 293973050Smsmith if ((uc->RequestSenseLength > 0) && (mc->mc_sense > 0)) { 294073050Smsmith if ((error = copyout(mc->mc_packet, uc->RequestSenseBuffer, 294173050Smsmith min(uc->RequestSenseLength, mc->mc_sense))) != 0) 294273050Smsmith goto out; 294373050Smsmith } 294473050Smsmith 294573050Smsmith /* return command results to userspace (caller will copy out) */ 294673050Smsmith uc->DataTransferLength = mc->mc_resid; 294773050Smsmith uc->RequestSenseLength = min(uc->RequestSenseLength, mc->mc_sense); 294873050Smsmith uc->CommandStatus = mc->mc_status; 294973050Smsmith error = 0; 295073050Smsmith 295173050Smsmith out: 295273050Smsmith if (mc->mc_data != NULL) 295373050Smsmith free(mc->mc_data, M_DEVBUF); 2954323826Sjhb MLY_LOCK(sc); 2955323826Sjhb mly_release_command(mc); 2956323826Sjhb MLY_UNLOCK(sc); 295773050Smsmith return(error); 295873050Smsmith} 295973050Smsmith 296073050Smsmith/******************************************************************************** 296173050Smsmith * Return health status to userspace. If the health change index in the user 296273050Smsmith * structure does not match that currently exported by the controller, we 296373050Smsmith * return the current status immediately. Otherwise, we block until either 296473050Smsmith * interrupted or new status is delivered. 296573050Smsmith */ 296673050Smsmithstatic int 296773050Smsmithmly_user_health(struct mly_softc *sc, struct mly_user_health *uh) 296873050Smsmith{ 296973050Smsmith struct mly_health_status mh; 2970274677Sjhb int error; 297173050Smsmith 297273050Smsmith /* fetch the current health status from userspace */ 297373050Smsmith if ((error = copyin(uh->HealthStatusBuffer, &mh, sizeof(mh))) != 0) 297473050Smsmith return(error); 297573050Smsmith 297673050Smsmith /* spin waiting for a status update */ 2977274677Sjhb MLY_LOCK(sc); 297873050Smsmith error = EWOULDBLOCK; 297973050Smsmith while ((error != 0) && (sc->mly_event_change == mh.change_counter)) 2980274677Sjhb error = mtx_sleep(&sc->mly_event_change, &sc->mly_lock, PRIBIO | PCATCH, 2981274677Sjhb "mlyhealth", 0); 2982274677Sjhb mh = sc->mly_mmbox->mmm_health.status; 2983274677Sjhb MLY_UNLOCK(sc); 298473050Smsmith 2985274677Sjhb /* copy the controller's health status buffer out */ 2986274677Sjhb error = copyout(&mh, uh->HealthStatusBuffer, sizeof(mh)); 298773050Smsmith return(error); 298873050Smsmith} 2989110479Sscottl 2990201795Strasz#ifdef MLY_DEBUG 2991274677Sjhbstatic void 2992274677Sjhbmly_timeout(void *arg) 2993110479Sscottl{ 2994274677Sjhb struct mly_softc *sc; 2995110479Sscottl struct mly_command *mc; 2996110479Sscottl int deadline; 2997110479Sscottl 2998274677Sjhb sc = arg; 2999274677Sjhb MLY_ASSERT_LOCKED(sc); 3000110479Sscottl deadline = time_second - MLY_CMD_TIMEOUT; 3001110479Sscottl TAILQ_FOREACH(mc, &sc->mly_busy, mc_link) { 3002110479Sscottl if ((mc->mc_timestamp < deadline)) { 3003110479Sscottl device_printf(sc->mly_dev, 3004110479Sscottl "COMMAND %p TIMEOUT AFTER %d SECONDS\n", mc, 3005110479Sscottl (int)(time_second - mc->mc_timestamp)); 3006110479Sscottl } 3007110479Sscottl } 3008110479Sscottl 3009274677Sjhb callout_reset(&sc->mly_timeout, MLY_CMD_TIMEOUT * hz, mly_timeout, sc); 3010110479Sscottl} 3011201795Strasz#endif 3012