135863739SMike Smith /*- 235863739SMike Smith * Copyright (c) 2000 Michael Smith 3c6eafcf2SScott Long * Copyright (c) 2001 Scott Long 435863739SMike Smith * Copyright (c) 2000 BSDi 5c6eafcf2SScott Long * Copyright (c) 2001 Adaptec, Inc. 635863739SMike Smith * All rights reserved. 735863739SMike Smith * 835863739SMike Smith * Redistribution and use in source and binary forms, with or without 935863739SMike Smith * modification, are permitted provided that the following conditions 1035863739SMike Smith * are met: 1135863739SMike Smith * 1. Redistributions of source code must retain the above copyright 1235863739SMike Smith * notice, this list of conditions and the following disclaimer. 1335863739SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1435863739SMike Smith * notice, this list of conditions and the following disclaimer in the 1535863739SMike Smith * documentation and/or other materials provided with the distribution. 1635863739SMike Smith * 1735863739SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1835863739SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1935863739SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2035863739SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2135863739SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2235863739SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2335863739SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2435863739SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2535863739SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2635863739SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2735863739SMike Smith * SUCH DAMAGE. 2835863739SMike Smith * 2935863739SMike Smith * $FreeBSD$ 3035863739SMike Smith */ 3135863739SMike Smith 3235863739SMike Smith /* 3335863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3435863739SMike Smith */ 3535863739SMike Smith 36f6c4dd3fSScott Long #include "opt_aac.h" 37f6c4dd3fSScott Long 38f6c4dd3fSScott Long /* include <stddef.h> */ 3935863739SMike Smith #include <sys/param.h> 4035863739SMike Smith #include <sys/systm.h> 4135863739SMike Smith #include <sys/malloc.h> 4235863739SMike Smith #include <sys/kernel.h> 4335863739SMike Smith 4435863739SMike Smith #include <dev/aac/aac_compat.h> 4535863739SMike Smith 4635863739SMike Smith #include <sys/bus.h> 4735863739SMike Smith #include <sys/conf.h> 4835863739SMike Smith #include <sys/devicestat.h> 4935863739SMike Smith #include <sys/disk.h> 5035863739SMike Smith #include <sys/file.h> 5135863739SMike Smith #include <sys/signalvar.h> 520b94a66eSMike Smith #include <sys/time.h> 5335863739SMike Smith 5435863739SMike Smith #include <machine/bus_memio.h> 5535863739SMike Smith #include <machine/bus.h> 5635863739SMike Smith #include <machine/resource.h> 5735863739SMike Smith 5835863739SMike Smith #include <dev/aac/aacreg.h> 590b94a66eSMike Smith #include <dev/aac/aac_ioctl.h> 6035863739SMike Smith #include <dev/aac/aacvar.h> 6135863739SMike Smith #include <dev/aac/aac_tables.h> 6235863739SMike Smith 6335863739SMike Smith devclass_t aac_devclass; 6435863739SMike Smith 6535863739SMike Smith static void aac_startup(void *arg); 6635863739SMike Smith 6735863739SMike Smith /* Command Processing */ 6835863739SMike Smith static void aac_startio(struct aac_softc *sc); 690b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7035863739SMike Smith static int aac_start(struct aac_command *cm); 7135863739SMike Smith static void aac_complete(void *context, int pending); 7235863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7335863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 7435863739SMike Smith static int aac_wait_command(struct aac_command *cm, int timeout); 7535863739SMike Smith static void aac_host_command(struct aac_softc *sc); 7635863739SMike Smith static void aac_host_response(struct aac_softc *sc); 7735863739SMike Smith 7835863739SMike Smith /* Command Buffer Management */ 79fadfef89SScott Long static int aac_alloc_command(struct aac_softc *sc, 80fadfef89SScott Long struct aac_command **cmp); 8135863739SMike Smith static void aac_release_command(struct aac_command *cm); 82c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 83c6eafcf2SScott Long int nseg, int error); 840b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 850b94a66eSMike Smith static void aac_free_commands(struct aac_softc *sc); 8635863739SMike Smith static void aac_map_command(struct aac_command *cm); 8735863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 8835863739SMike Smith 8935863739SMike Smith /* Hardware Interface */ 90c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 91c6eafcf2SScott Long int error); 9235863739SMike Smith static int aac_init(struct aac_softc *sc); 9335863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 94c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 95c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 96c6eafcf2SScott Long static int aac_sync_fib(struct aac_softc *sc, u_int32_t command, 97c6eafcf2SScott Long u_int32_t xferstate, void *data, 98c6eafcf2SScott Long u_int16_t datasize, void *result, 99c6eafcf2SScott Long u_int16_t *resultsize); 100c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 101f6c4dd3fSScott Long struct aac_command *cm); 102c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 103c6eafcf2SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10435863739SMike Smith 10535863739SMike Smith /* StrongARM interface */ 10635863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 10735863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 10835863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 10935863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 11035863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 111c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 112c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 11335863739SMike Smith static int aac_sa_get_mailboxstatus(struct aac_softc *sc); 11435863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 11535863739SMike Smith 11635863739SMike Smith struct aac_interface aac_sa_interface = { 11735863739SMike Smith aac_sa_get_fwstatus, 11835863739SMike Smith aac_sa_qnotify, 11935863739SMike Smith aac_sa_get_istatus, 12035863739SMike Smith aac_sa_clear_istatus, 12135863739SMike Smith aac_sa_set_mailbox, 12235863739SMike Smith aac_sa_get_mailboxstatus, 12335863739SMike Smith aac_sa_set_interrupts 12435863739SMike Smith }; 12535863739SMike Smith 12635863739SMike Smith /* i960Rx interface */ 12735863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 12835863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 12935863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 13035863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 13135863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 132c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 133c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 13435863739SMike Smith static int aac_rx_get_mailboxstatus(struct aac_softc *sc); 13535863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 13635863739SMike Smith 13735863739SMike Smith struct aac_interface aac_rx_interface = { 13835863739SMike Smith aac_rx_get_fwstatus, 13935863739SMike Smith aac_rx_qnotify, 14035863739SMike Smith aac_rx_get_istatus, 14135863739SMike Smith aac_rx_clear_istatus, 14235863739SMike Smith aac_rx_set_mailbox, 14335863739SMike Smith aac_rx_get_mailboxstatus, 14435863739SMike Smith aac_rx_set_interrupts 14535863739SMike Smith }; 14635863739SMike Smith 14735863739SMike Smith /* Debugging and Diagnostics */ 14835863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 149c6eafcf2SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 150c6eafcf2SScott Long u_int32_t code); 15135863739SMike Smith 15235863739SMike Smith /* Management Interface */ 15335863739SMike Smith static d_open_t aac_open; 15435863739SMike Smith static d_close_t aac_close; 15535863739SMike Smith static d_ioctl_t aac_ioctl; 156c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 157c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 158c6eafcf2SScott Long struct aac_aif_command *aif); 15935863739SMike Smith #ifdef AAC_COMPAT_LINUX 160c6eafcf2SScott Long static int aac_linux_rev_check(struct aac_softc *sc, 161c6eafcf2SScott Long caddr_t udata); 162c6eafcf2SScott Long static int aac_linux_getnext_aif(struct aac_softc *sc, 163c6eafcf2SScott Long caddr_t arg); 164c6eafcf2SScott Long static int aac_linux_return_aif(struct aac_softc *sc, 165c6eafcf2SScott Long caddr_t uptr); 16635863739SMike Smith #endif 16735863739SMike Smith 16835863739SMike Smith #define AAC_CDEV_MAJOR 150 16935863739SMike Smith 17035863739SMike Smith static struct cdevsw aac_cdevsw = { 17135863739SMike Smith aac_open, /* open */ 17235863739SMike Smith aac_close, /* close */ 17335863739SMike Smith noread, /* read */ 17435863739SMike Smith nowrite, /* write */ 17535863739SMike Smith aac_ioctl, /* ioctl */ 17635863739SMike Smith nopoll, /* poll */ 17735863739SMike Smith nommap, /* mmap */ 17835863739SMike Smith nostrategy, /* strategy */ 17935863739SMike Smith "aac", /* name */ 18035863739SMike Smith AAC_CDEV_MAJOR, /* major */ 18135863739SMike Smith nodump, /* dump */ 18235863739SMike Smith nopsize, /* psize */ 18335863739SMike Smith 0, /* flags */ 18435863739SMike Smith }; 18535863739SMike Smith 186c6eafcf2SScott Long /****************************************************************************** 187c6eafcf2SScott Long ****************************************************************************** 18835863739SMike Smith Device Interface 189c6eafcf2SScott Long ****************************************************************************** 190c6eafcf2SScott Long ******************************************************************************/ 19135863739SMike Smith 192c6eafcf2SScott Long /****************************************************************************** 19335863739SMike Smith * Initialise the controller and softc 19435863739SMike Smith */ 19535863739SMike Smith int 19635863739SMike Smith aac_attach(struct aac_softc *sc) 19735863739SMike Smith { 19835863739SMike Smith int error, unit; 19935863739SMike Smith 20035863739SMike Smith debug_called(1); 20135863739SMike Smith 20235863739SMike Smith /* 20335863739SMike Smith * Initialise per-controller queues. 20435863739SMike Smith */ 2050b94a66eSMike Smith aac_initq_free(sc); 2060b94a66eSMike Smith aac_initq_ready(sc); 2070b94a66eSMike Smith aac_initq_busy(sc); 2080b94a66eSMike Smith aac_initq_complete(sc); 2090b94a66eSMike Smith aac_initq_bio(sc); 21035863739SMike Smith 21135863739SMike Smith #if __FreeBSD_version >= 500005 21235863739SMike Smith /* 21335863739SMike Smith * Initialise command-completion task. 21435863739SMike Smith */ 21535863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 21635863739SMike Smith #endif 21735863739SMike Smith 21835863739SMike Smith /* disable interrupts before we enable anything */ 21935863739SMike Smith AAC_MASK_INTERRUPTS(sc); 22035863739SMike Smith 22135863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 22235863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 22335863739SMike Smith 22435863739SMike Smith /* 2250b94a66eSMike Smith * Allocate command structures. 2260b94a66eSMike Smith */ 2270b94a66eSMike Smith if ((error = aac_alloc_commands(sc)) != 0) 2280b94a66eSMike Smith return(error); 2290b94a66eSMike Smith 2300b94a66eSMike Smith /* 23135863739SMike Smith * Initialise the adapter. 23235863739SMike Smith */ 2330b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 23435863739SMike Smith return(error); 23535863739SMike Smith 23635863739SMike Smith /* 23735863739SMike Smith * Print a little information about the controller. 23835863739SMike Smith */ 23935863739SMike Smith aac_describe_controller(sc); 24035863739SMike Smith 24135863739SMike Smith /* 24235863739SMike Smith * Register to probe our containers later. 24335863739SMike Smith */ 24435863739SMike Smith sc->aac_ich.ich_func = aac_startup; 24535863739SMike Smith sc->aac_ich.ich_arg = sc; 24635863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 24735863739SMike Smith device_printf(sc->aac_dev, "can't establish configuration hook\n"); 24835863739SMike Smith return(ENXIO); 24935863739SMike Smith } 25035863739SMike Smith 25135863739SMike Smith /* 25235863739SMike Smith * Make the control device. 25335863739SMike Smith */ 25435863739SMike Smith unit = device_get_unit(sc->aac_dev); 255c6eafcf2SScott Long sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644, 256c6eafcf2SScott Long "aac%d", unit); 257157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 2584aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 259157fbb2eSScott Long 26035863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 26135863739SMike Smith 26235863739SMike Smith return(0); 26335863739SMike Smith } 26435863739SMike Smith 265c6eafcf2SScott Long /****************************************************************************** 26635863739SMike Smith * Probe for containers, create disks. 26735863739SMike Smith */ 26835863739SMike Smith static void 26935863739SMike Smith aac_startup(void *arg) 27035863739SMike Smith { 27135863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 27235863739SMike Smith struct aac_mntinfo mi; 27335863739SMike Smith struct aac_mntinforesponse mir; 27435863739SMike Smith device_t child; 27535863739SMike Smith u_int16_t rsize; 27635863739SMike Smith int i; 27735863739SMike Smith 27835863739SMike Smith debug_called(1); 27935863739SMike Smith 28035863739SMike Smith /* disconnect ourselves from the intrhook chain */ 28135863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 28235863739SMike Smith 28335863739SMike Smith /* loop over possible containers */ 28435863739SMike Smith mi.Command = VM_NameServe; 28535863739SMike Smith mi.MntType = FT_FILESYS; 28635863739SMike Smith for (i = 0; i < AAC_MAX_CONTAINERS; i++) { 28735863739SMike Smith /* request information on this container */ 28835863739SMike Smith mi.MntCount = i; 289f6c4dd3fSScott Long rsize = sizeof(mir); 290c6eafcf2SScott Long if (aac_sync_fib(sc, ContainerCommand, 0, &mi, 291c6eafcf2SScott Long sizeof(struct aac_mntinfo), &mir, &rsize)) { 29235863739SMike Smith debug(2, "error probing container %d", i); 29335863739SMike Smith continue; 29435863739SMike Smith } 29535863739SMike Smith /* check response size */ 29635863739SMike Smith if (rsize != sizeof(mir)) { 297c6eafcf2SScott Long debug(2, "container info response wrong size (%d should be %d)", 298c6eafcf2SScott Long rsize, sizeof(mir)); 29935863739SMike Smith continue; 30035863739SMike Smith } 30135863739SMike Smith /* 302c6eafcf2SScott Long * Check container volume type for validity. Note that many of the 303c6eafcf2SScott Long * possible types may never show up. 30435863739SMike Smith */ 30535863739SMike Smith if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) { 30635863739SMike Smith debug(1, "%d: id %x name '%.16s' size %u type %d", 30735863739SMike Smith i, mir.MntTable[0].ObjectId, 30835863739SMike Smith mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity, 30935863739SMike Smith mir.MntTable[0].VolType); 31035863739SMike Smith 31135863739SMike Smith if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) { 31235863739SMike Smith device_printf(sc->aac_dev, "device_add_child failed\n"); 31335863739SMike Smith } else { 31435863739SMike Smith device_set_ivars(child, &sc->aac_container[i]); 31535863739SMike Smith } 316c6eafcf2SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 317c6eafcf2SScott Long mir.MntTable[0].VolType)); 31835863739SMike Smith sc->aac_container[i].co_disk = child; 31935863739SMike Smith sc->aac_container[i].co_mntobj = mir.MntTable[0]; 32035863739SMike Smith } 32135863739SMike Smith } 32235863739SMike Smith 32335863739SMike Smith /* poke the bus to actually attach the child devices */ 32435863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 32535863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 32635863739SMike Smith 32735863739SMike Smith /* mark the controller up */ 32835863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 32935863739SMike Smith 33035863739SMike Smith /* enable interrupts now */ 33135863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 3320b94a66eSMike Smith 3330b94a66eSMike Smith /* enable the timeout watchdog */ 3340b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 33535863739SMike Smith } 33635863739SMike Smith 337c6eafcf2SScott Long /****************************************************************************** 33835863739SMike Smith * Free all of the resources associated with (sc) 33935863739SMike Smith * 34035863739SMike Smith * Should not be called if the controller is active. 34135863739SMike Smith */ 34235863739SMike Smith void 34335863739SMike Smith aac_free(struct aac_softc *sc) 34435863739SMike Smith { 34535863739SMike Smith debug_called(1); 34635863739SMike Smith 34735863739SMike Smith /* remove the control device */ 34835863739SMike Smith if (sc->aac_dev_t != NULL) 34935863739SMike Smith destroy_dev(sc->aac_dev_t); 35035863739SMike Smith 3510b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 3520b94a66eSMike Smith if (sc->aac_fibs != NULL) 3530b94a66eSMike Smith aac_free_commands(sc); 3540b94a66eSMike Smith if (sc->aac_fib_dmat) 3550b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 35635863739SMike Smith 35735863739SMike Smith /* destroy the common area */ 35835863739SMike Smith if (sc->aac_common) { 35935863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 360c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 361c6eafcf2SScott Long sc->aac_common_dmamap); 36235863739SMike Smith } 3630b94a66eSMike Smith if (sc->aac_common_dmat) 3640b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 36535863739SMike Smith 36635863739SMike Smith /* disconnect the interrupt handler */ 36735863739SMike Smith if (sc->aac_intr) 36835863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 36935863739SMike Smith if (sc->aac_irq != NULL) 370c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 371c6eafcf2SScott Long sc->aac_irq); 37235863739SMike Smith 37335863739SMike Smith /* destroy data-transfer DMA tag */ 37435863739SMike Smith if (sc->aac_buffer_dmat) 37535863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 37635863739SMike Smith 37735863739SMike Smith /* destroy the parent DMA tag */ 37835863739SMike Smith if (sc->aac_parent_dmat) 37935863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 38035863739SMike Smith 38135863739SMike Smith /* release the register window mapping */ 38235863739SMike Smith if (sc->aac_regs_resource != NULL) 383c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid, 384c6eafcf2SScott Long sc->aac_regs_resource); 38535863739SMike Smith } 38635863739SMike Smith 387c6eafcf2SScott Long /****************************************************************************** 38835863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 38935863739SMike Smith */ 39035863739SMike Smith int 39135863739SMike Smith aac_detach(device_t dev) 39235863739SMike Smith { 39335863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 39435863739SMike Smith int error; 39535863739SMike Smith 39635863739SMike Smith debug_called(1); 39735863739SMike Smith 39835863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 39935863739SMike Smith return(EBUSY); 40035863739SMike Smith 40135863739SMike Smith if ((error = aac_shutdown(dev))) 40235863739SMike Smith return(error); 40335863739SMike Smith 40435863739SMike Smith aac_free(sc); 40535863739SMike Smith 40635863739SMike Smith return(0); 40735863739SMike Smith } 40835863739SMike Smith 409c6eafcf2SScott Long /****************************************************************************** 41035863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 41135863739SMike Smith * 41235863739SMike Smith * This function is called before detach or system shutdown. 41335863739SMike Smith * 4140b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 41535863739SMike Smith * allow shutdown if any device is open. 41635863739SMike Smith */ 41735863739SMike Smith int 41835863739SMike Smith aac_shutdown(device_t dev) 41935863739SMike Smith { 42035863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 42135863739SMike Smith struct aac_close_command cc; 42235863739SMike Smith int s, i; 42335863739SMike Smith 42435863739SMike Smith debug_called(1); 42535863739SMike Smith 42635863739SMike Smith s = splbio(); 42735863739SMike Smith 42835863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 42935863739SMike Smith 43035863739SMike Smith /* 43135863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 43235863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 43335863739SMike Smith * We've been closed and all I/O completed already 43435863739SMike Smith */ 43535863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 43635863739SMike Smith 43735863739SMike Smith cc.Command = VM_CloseAll; 43835863739SMike Smith cc.ContainerId = 0xffffffff; 43935863739SMike Smith if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) { 44035863739SMike Smith printf("FAILED.\n"); 44135863739SMike Smith } else { 44235863739SMike Smith i = 0; 443c6eafcf2SScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i, 444c6eafcf2SScott Long sizeof(i), NULL, NULL)) { 44535863739SMike Smith printf("FAILED.\n"); 44635863739SMike Smith } else { 44735863739SMike Smith printf("done.\n"); 44835863739SMike Smith } 44935863739SMike Smith } 45035863739SMike Smith 45135863739SMike Smith AAC_MASK_INTERRUPTS(sc); 45235863739SMike Smith 45335863739SMike Smith splx(s); 45435863739SMike Smith return(0); 45535863739SMike Smith } 45635863739SMike Smith 457c6eafcf2SScott Long /****************************************************************************** 45835863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 45935863739SMike Smith */ 46035863739SMike Smith int 46135863739SMike Smith aac_suspend(device_t dev) 46235863739SMike Smith { 46335863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 46435863739SMike Smith int s; 46535863739SMike Smith 46635863739SMike Smith debug_called(1); 46735863739SMike Smith s = splbio(); 46835863739SMike Smith 46935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 47035863739SMike Smith 47135863739SMike Smith AAC_MASK_INTERRUPTS(sc); 47235863739SMike Smith splx(s); 47335863739SMike Smith return(0); 47435863739SMike Smith } 47535863739SMike Smith 476c6eafcf2SScott Long /****************************************************************************** 47735863739SMike Smith * Bring the controller back to a state ready for operation. 47835863739SMike Smith */ 47935863739SMike Smith int 48035863739SMike Smith aac_resume(device_t dev) 48135863739SMike Smith { 48235863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 48335863739SMike Smith 48435863739SMike Smith debug_called(1); 48535863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 48635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 48735863739SMike Smith return(0); 48835863739SMike Smith } 48935863739SMike Smith 490c6eafcf2SScott Long /****************************************************************************** 49135863739SMike Smith * Take an interrupt. 49235863739SMike Smith */ 49335863739SMike Smith void 49435863739SMike Smith aac_intr(void *arg) 49535863739SMike Smith { 49635863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 49735863739SMike Smith u_int16_t reason; 49835863739SMike Smith 49935863739SMike Smith debug_called(2); 50035863739SMike Smith 50135863739SMike Smith reason = AAC_GET_ISTATUS(sc); 50235863739SMike Smith 50335863739SMike Smith /* controller wants to talk to the log? XXX should we defer this? */ 50435863739SMike Smith if (reason & AAC_DB_PRINTF) { 50535863739SMike Smith if (sc->aac_common->ac_printf[0]) { 506c6eafcf2SScott Long device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE, 507c6eafcf2SScott Long sc->aac_common->ac_printf); 50835863739SMike Smith sc->aac_common->ac_printf[0] = 0; 50935863739SMike Smith } 51035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF); 51135863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_PRINTF); 51235863739SMike Smith } 51335863739SMike Smith 51435863739SMike Smith /* controller has a message for us? */ 51535863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 51635863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY); 517da4c1ce3SJustin T. Gibbs aac_host_command(sc); 51835863739SMike Smith } 51935863739SMike Smith 52035863739SMike Smith /* controller has a response for us? */ 52135863739SMike Smith if (reason & AAC_DB_RESPONSE_READY) { 52235863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 523da4c1ce3SJustin T. Gibbs aac_host_response(sc); 52435863739SMike Smith } 52535863739SMike Smith 526c6eafcf2SScott Long /* 527c6eafcf2SScott Long * spurious interrupts that we don't use - reset the mask and clear the 528c6eafcf2SScott Long * interrupts 529c6eafcf2SScott Long */ 53035863739SMike Smith if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) { 53135863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 532c6eafcf2SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL | 533c6eafcf2SScott Long AAC_DB_RESPONSE_NOT_FULL); 53435863739SMike Smith } 53535863739SMike Smith }; 53635863739SMike Smith 537c6eafcf2SScott Long /****************************************************************************** 538c6eafcf2SScott Long ****************************************************************************** 53935863739SMike Smith Command Processing 540c6eafcf2SScott Long ****************************************************************************** 541c6eafcf2SScott Long ******************************************************************************/ 54235863739SMike Smith 543c6eafcf2SScott Long /****************************************************************************** 54435863739SMike Smith * Start as much queued I/O as possible on the controller 54535863739SMike Smith */ 54635863739SMike Smith static void 54735863739SMike Smith aac_startio(struct aac_softc *sc) 54835863739SMike Smith { 54935863739SMike Smith struct aac_command *cm; 55035863739SMike Smith 55135863739SMike Smith debug_called(2); 55235863739SMike Smith 55335863739SMike Smith for(;;) { 55435863739SMike Smith /* try to get a command that's been put off for lack of resources */ 55535863739SMike Smith cm = aac_dequeue_ready(sc); 55635863739SMike Smith 55735863739SMike Smith /* try to build a command off the bio queue (ignore error return) */ 5580b94a66eSMike Smith if (cm == NULL) 55935863739SMike Smith aac_bio_command(sc, &cm); 56035863739SMike Smith 56135863739SMike Smith /* nothing to do? */ 56235863739SMike Smith if (cm == NULL) 56335863739SMike Smith break; 56435863739SMike Smith 56535863739SMike Smith /* try to give the command to the controller */ 56635863739SMike Smith if (aac_start(cm) == EBUSY) { 56735863739SMike Smith /* put it on the ready queue for later */ 56835863739SMike Smith aac_requeue_ready(cm); 56935863739SMike Smith break; 57035863739SMike Smith } 57135863739SMike Smith } 57235863739SMike Smith } 57335863739SMike Smith 574c6eafcf2SScott Long /****************************************************************************** 57535863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 57635863739SMike Smith * last moment when possible. 57735863739SMike Smith */ 57835863739SMike Smith static int 57935863739SMike Smith aac_start(struct aac_command *cm) 58035863739SMike Smith { 58135863739SMike Smith struct aac_softc *sc = cm->cm_sc; 582ed5c5fb4SMike Smith int error; 58335863739SMike Smith 58435863739SMike Smith debug_called(2); 58535863739SMike Smith 58635863739SMike Smith /* get the command mapped */ 58735863739SMike Smith aac_map_command(cm); 58835863739SMike Smith 5890b94a66eSMike Smith /* fix up the address values in the FIB */ 59035863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 59135863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 59235863739SMike Smith 59335863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 594c6eafcf2SScott Long cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical 595c6eafcf2SScott Long * address issue */ 59635863739SMike Smith 59735863739SMike Smith /* put the FIB on the outbound queue */ 598f6c4dd3fSScott Long error = aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm); 5990b94a66eSMike Smith return(error); 60035863739SMike Smith } 60135863739SMike Smith 602c6eafcf2SScott Long /****************************************************************************** 60335863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 60435863739SMike Smith */ 60535863739SMike Smith static void 60635863739SMike Smith aac_host_command(struct aac_softc *sc) 60735863739SMike Smith { 60835863739SMike Smith struct aac_fib *fib; 60935863739SMike Smith u_int32_t fib_size; 61035863739SMike Smith 61135863739SMike Smith debug_called(1); 61235863739SMike Smith 61335863739SMike Smith for (;;) { 61435863739SMike Smith if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib)) 61535863739SMike Smith break; /* nothing to do */ 61635863739SMike Smith 61735863739SMike Smith switch(fib->Header.Command) { 61835863739SMike Smith case AifRequest: 61935863739SMike Smith aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]); 62035863739SMike Smith break; 62135863739SMike Smith default: 62235863739SMike Smith device_printf(sc->aac_dev, "unknown command from controller\n"); 62335863739SMike Smith AAC_PRINT_FIB(sc, fib); 62435863739SMike Smith break; 62535863739SMike Smith } 62635863739SMike Smith 62735863739SMike Smith /* XXX reply to FIBs requesting responses ?? */ 62835863739SMike Smith /* XXX how do we return these FIBs to the controller? */ 62935863739SMike Smith } 63035863739SMike Smith } 63135863739SMike Smith 632c6eafcf2SScott Long /****************************************************************************** 63335863739SMike Smith * Handle notification of one or more FIBs completed by the controller 63435863739SMike Smith */ 63535863739SMike Smith static void 63635863739SMike Smith aac_host_response(struct aac_softc *sc) 63735863739SMike Smith { 63835863739SMike Smith struct aac_command *cm; 63935863739SMike Smith struct aac_fib *fib; 64035863739SMike Smith u_int32_t fib_size; 64135863739SMike Smith 64235863739SMike Smith debug_called(2); 64335863739SMike Smith 64435863739SMike Smith for (;;) { 64535863739SMike Smith /* look for completed FIBs on our queue */ 64635863739SMike Smith if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib)) 64735863739SMike Smith break; /* nothing to do */ 64835863739SMike Smith 64935863739SMike Smith /* get the command, unmap and queue for later processing */ 65035863739SMike Smith cm = (struct aac_command *)fib->Header.SenderData; 65135863739SMike Smith if (cm == NULL) { 65235863739SMike Smith AAC_PRINT_FIB(sc, fib); 65335863739SMike Smith } else { 6540b94a66eSMike Smith aac_remove_busy(cm); 65535863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 6560b94a66eSMike Smith aac_enqueue_complete(cm); 65735863739SMike Smith } 65835863739SMike Smith } 65935863739SMike Smith 66035863739SMike Smith /* handle completion processing */ 66135863739SMike Smith #if __FreeBSD_version >= 500005 66235863739SMike Smith taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 66335863739SMike Smith #else 66435863739SMike Smith aac_complete(sc, 0); 66535863739SMike Smith #endif 66635863739SMike Smith } 66735863739SMike Smith 668c6eafcf2SScott Long /****************************************************************************** 66935863739SMike Smith * Process completed commands. 67035863739SMike Smith */ 67135863739SMike Smith static void 67235863739SMike Smith aac_complete(void *context, int pending) 67335863739SMike Smith { 67435863739SMike Smith struct aac_softc *sc = (struct aac_softc *)context; 67535863739SMike Smith struct aac_command *cm; 67635863739SMike Smith 67735863739SMike Smith debug_called(2); 67835863739SMike Smith 67935863739SMike Smith /* pull completed commands off the queue */ 68035863739SMike Smith for (;;) { 6810b94a66eSMike Smith cm = aac_dequeue_complete(sc); 68235863739SMike Smith if (cm == NULL) 6830b94a66eSMike Smith break; 68435863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 68535863739SMike Smith 68635863739SMike Smith /* is there a completion handler? */ 68735863739SMike Smith if (cm->cm_complete != NULL) { 68835863739SMike Smith cm->cm_complete(cm); 68935863739SMike Smith } else { 69035863739SMike Smith /* assume that someone is sleeping on this command */ 69135863739SMike Smith wakeup(cm); 69235863739SMike Smith } 69335863739SMike Smith } 6940b94a66eSMike Smith 6950b94a66eSMike Smith /* see if we can start some more I/O */ 6960b94a66eSMike Smith aac_startio(sc); 69735863739SMike Smith } 69835863739SMike Smith 699c6eafcf2SScott Long /****************************************************************************** 70035863739SMike Smith * Handle a bio submitted from a disk device. 70135863739SMike Smith */ 70235863739SMike Smith void 70335863739SMike Smith aac_submit_bio(struct bio *bp) 70435863739SMike Smith { 70535863739SMike Smith struct aac_disk *ad = (struct aac_disk *)bp->bio_dev->si_drv1; 70635863739SMike Smith struct aac_softc *sc = ad->ad_controller; 70735863739SMike Smith 70835863739SMike Smith debug_called(2); 70935863739SMike Smith 71035863739SMike Smith /* queue the BIO and try to get some work done */ 7110b94a66eSMike Smith aac_enqueue_bio(sc, bp); 71235863739SMike Smith aac_startio(sc); 71335863739SMike Smith } 71435863739SMike Smith 715c6eafcf2SScott Long /****************************************************************************** 71635863739SMike Smith * Get a bio and build a command to go with it. 71735863739SMike Smith */ 71835863739SMike Smith static int 71935863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 72035863739SMike Smith { 72135863739SMike Smith struct aac_command *cm; 72235863739SMike Smith struct aac_fib *fib; 72335863739SMike Smith struct aac_blockread *br; 72435863739SMike Smith struct aac_blockwrite *bw; 72535863739SMike Smith struct aac_disk *ad; 72635863739SMike Smith struct bio *bp; 72735863739SMike Smith 72835863739SMike Smith debug_called(2); 72935863739SMike Smith 73035863739SMike Smith /* get the resources we will need */ 73135863739SMike Smith cm = NULL; 7320b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 73335863739SMike Smith goto fail; 73435863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 73535863739SMike Smith goto fail; 73635863739SMike Smith 73735863739SMike Smith /* fill out the command */ 7380b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 7390b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 7400b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 74135863739SMike Smith cm->cm_private = bp; 7420b94a66eSMike Smith cm->cm_timestamp = time_second; 74335863739SMike Smith 74435863739SMike Smith /* build the FIB */ 74535863739SMike Smith fib = cm->cm_fib; 74635863739SMike Smith fib->Header.XferState = 74735863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 74835863739SMike Smith AAC_FIBSTATE_INITIALISED | 74935863739SMike Smith AAC_FIBSTATE_FROMHOST | 75035863739SMike Smith AAC_FIBSTATE_REXPECTED | 75135863739SMike Smith AAC_FIBSTATE_NORM; 75235863739SMike Smith fib->Header.Command = ContainerCommand; 75335863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 75435863739SMike Smith 75535863739SMike Smith /* build the read/write request */ 75635863739SMike Smith ad = (struct aac_disk *)bp->bio_dev->si_drv1; 75735863739SMike Smith if (BIO_IS_READ(bp)) { 75835863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 75935863739SMike Smith br->Command = VM_CtBlockRead; 76035863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 76135863739SMike Smith br->BlockNumber = bp->bio_pblkno; 76235863739SMike Smith br->ByteCount = bp->bio_bcount; 76335863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 76435863739SMike Smith cm->cm_sgtable = &br->SgMap; 76535863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 76635863739SMike Smith } else { 76735863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 76835863739SMike Smith bw->Command = VM_CtBlockWrite; 76935863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 77035863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 77135863739SMike Smith bw->ByteCount = bp->bio_bcount; 77235863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 77335863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 77435863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 77535863739SMike Smith cm->cm_sgtable = &bw->SgMap; 77635863739SMike Smith } 77735863739SMike Smith 77835863739SMike Smith *cmp = cm; 77935863739SMike Smith return(0); 78035863739SMike Smith 78135863739SMike Smith fail: 78235863739SMike Smith if (bp != NULL) 7830b94a66eSMike Smith aac_enqueue_bio(sc, bp); 78435863739SMike Smith if (cm != NULL) 78535863739SMike Smith aac_release_command(cm); 78635863739SMike Smith return(ENOMEM); 78735863739SMike Smith } 78835863739SMike Smith 789c6eafcf2SScott Long /****************************************************************************** 79035863739SMike Smith * Handle a bio-instigated command that has been completed. 79135863739SMike Smith */ 79235863739SMike Smith static void 79335863739SMike Smith aac_bio_complete(struct aac_command *cm) 79435863739SMike Smith { 79535863739SMike Smith struct aac_blockread_response *brr; 79635863739SMike Smith struct aac_blockwrite_response *bwr; 79735863739SMike Smith struct bio *bp; 79835863739SMike Smith AAC_FSAStatus status; 79935863739SMike Smith 80035863739SMike Smith /* fetch relevant status and then release the command */ 80135863739SMike Smith bp = (struct bio *)cm->cm_private; 80235863739SMike Smith if (BIO_IS_READ(bp)) { 80335863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 80435863739SMike Smith status = brr->Status; 80535863739SMike Smith } else { 80635863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 80735863739SMike Smith status = bwr->Status; 80835863739SMike Smith } 80935863739SMike Smith aac_release_command(cm); 81035863739SMike Smith 81135863739SMike Smith /* fix up the bio based on status */ 81235863739SMike Smith if (status == ST_OK) { 81335863739SMike Smith bp->bio_resid = 0; 81435863739SMike Smith } else { 81535863739SMike Smith bp->bio_error = EIO; 81635863739SMike Smith bp->bio_flags |= BIO_ERROR; 8170b94a66eSMike Smith /* pass an error string out to the disk layer */ 8180b94a66eSMike Smith bp->bio_driver1 = aac_describe_code(aac_command_status_table, status); 81935863739SMike Smith } 8200b94a66eSMike Smith aac_biodone(bp); 82135863739SMike Smith } 82235863739SMike Smith 823c6eafcf2SScott Long /****************************************************************************** 82435863739SMike Smith * Submit a command to the controller, return when it completes. 82535863739SMike Smith */ 82635863739SMike Smith static int 82735863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 82835863739SMike Smith { 82935863739SMike Smith int s, error = 0; 83035863739SMike Smith 83135863739SMike Smith debug_called(2); 83235863739SMike Smith 83335863739SMike Smith /* Put the command on the ready queue and get things going */ 83435863739SMike Smith aac_enqueue_ready(cm); 83535863739SMike Smith aac_startio(cm->cm_sc); 83635863739SMike Smith s = splbio(); 83735863739SMike Smith while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 838f6c4dd3fSScott Long error = tsleep(cm, PRIBIO, "aacwait", 0); 83935863739SMike Smith } 84035863739SMike Smith splx(s); 84135863739SMike Smith return(error); 84235863739SMike Smith } 84335863739SMike Smith 844c6eafcf2SScott Long /****************************************************************************** 845c6eafcf2SScott Long ****************************************************************************** 84635863739SMike Smith Command Buffer Management 847c6eafcf2SScott Long ****************************************************************************** 848c6eafcf2SScott Long ******************************************************************************/ 84935863739SMike Smith 850c6eafcf2SScott Long /****************************************************************************** 85135863739SMike Smith * Allocate a command. 85235863739SMike Smith */ 85335863739SMike Smith static int 85435863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 85535863739SMike Smith { 85635863739SMike Smith struct aac_command *cm; 85735863739SMike Smith 85835863739SMike Smith debug_called(3); 85935863739SMike Smith 8600b94a66eSMike Smith if ((cm = aac_dequeue_free(sc)) == NULL) 86135863739SMike Smith return(ENOMEM); 86235863739SMike Smith 8630b94a66eSMike Smith *cmp = cm; 8640b94a66eSMike Smith return(0); 8650b94a66eSMike Smith } 8660b94a66eSMike Smith 867c6eafcf2SScott Long /****************************************************************************** 8680b94a66eSMike Smith * Release a command back to the freelist. 8690b94a66eSMike Smith */ 8700b94a66eSMike Smith static void 8710b94a66eSMike Smith aac_release_command(struct aac_command *cm) 8720b94a66eSMike Smith { 8730b94a66eSMike Smith debug_called(3); 8740b94a66eSMike Smith 8750b94a66eSMike Smith /* (re)initialise the command/FIB */ 87635863739SMike Smith cm->cm_sgtable = NULL; 87735863739SMike Smith cm->cm_flags = 0; 87835863739SMike Smith cm->cm_complete = NULL; 87935863739SMike Smith cm->cm_private = NULL; 88035863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 88135863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 88235863739SMike Smith cm->cm_fib->Header.Flags = 0; 88335863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 88435863739SMike Smith 88535863739SMike Smith /* 88635863739SMike Smith * These are duplicated in aac_start to cover the case where an 88735863739SMike Smith * intermediate stage may have destroyed them. They're left 88835863739SMike Smith * initialised here for debugging purposes only. 88935863739SMike Smith */ 89035863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 89135863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 89235863739SMike Smith 89335863739SMike Smith aac_enqueue_free(cm); 89435863739SMike Smith } 89535863739SMike Smith 896c6eafcf2SScott Long /****************************************************************************** 8970b94a66eSMike Smith * Map helper for command/FIB allocation. 89835863739SMike Smith */ 89935863739SMike Smith static void 9000b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 90135863739SMike Smith { 9020b94a66eSMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 90335863739SMike Smith 90435863739SMike Smith debug_called(3); 90535863739SMike Smith 9060b94a66eSMike Smith sc->aac_fibphys = segs[0].ds_addr; 90735863739SMike Smith } 90835863739SMike Smith 909c6eafcf2SScott Long /****************************************************************************** 9100b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 91135863739SMike Smith */ 9120b94a66eSMike Smith static int 9130b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 91435863739SMike Smith { 91535863739SMike Smith struct aac_command *cm; 91635863739SMike Smith int i; 91735863739SMike Smith 91835863739SMike Smith debug_called(1); 91935863739SMike Smith 9200b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 921c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, 922c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_fibmap)) { 9230b94a66eSMike Smith return(ENOMEM); 92435863739SMike Smith } 9250b94a66eSMike Smith bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 926c6eafcf2SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 927c6eafcf2SScott Long aac_map_command_helper, sc, 0); 92835863739SMike Smith 9290b94a66eSMike Smith /* initialise constant fields in the command structure */ 9300b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 9310b94a66eSMike Smith cm = &sc->aac_command[i]; 93235863739SMike Smith cm->cm_sc = sc; 9330b94a66eSMike Smith cm->cm_fib = sc->aac_fibs + i; 9340b94a66eSMike Smith cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); 93535863739SMike Smith 93635863739SMike Smith if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) 93735863739SMike Smith aac_release_command(cm); 93835863739SMike Smith } 9390b94a66eSMike Smith return(0); 94035863739SMike Smith } 94135863739SMike Smith 942c6eafcf2SScott Long /****************************************************************************** 9430b94a66eSMike Smith * Free FIBs owned by this adapter. 94435863739SMike Smith */ 94535863739SMike Smith static void 9460b94a66eSMike Smith aac_free_commands(struct aac_softc *sc) 94735863739SMike Smith { 94835863739SMike Smith int i; 94935863739SMike Smith 95035863739SMike Smith debug_called(1); 95135863739SMike Smith 9520b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) 9530b94a66eSMike Smith bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap); 9540b94a66eSMike Smith bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); 9550b94a66eSMike Smith bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); 95635863739SMike Smith } 95735863739SMike Smith 958c6eafcf2SScott Long /****************************************************************************** 95935863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 96035863739SMike Smith */ 96135863739SMike Smith static void 96235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 96335863739SMike Smith { 96435863739SMike Smith struct aac_command *cm = (struct aac_command *)arg; 96535863739SMike Smith struct aac_fib *fib = cm->cm_fib; 96635863739SMike Smith struct aac_sg_table *sg; 96735863739SMike Smith int i; 96835863739SMike Smith 96935863739SMike Smith debug_called(3); 97035863739SMike Smith 97135863739SMike Smith /* find the s/g table */ 97235863739SMike Smith sg = cm->cm_sgtable; 97335863739SMike Smith 97435863739SMike Smith /* copy into the FIB */ 97535863739SMike Smith if (sg != NULL) { 97635863739SMike Smith sg->SgCount = nseg; 97735863739SMike Smith for (i = 0; i < nseg; i++) { 97835863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 97935863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 98035863739SMike Smith } 98135863739SMike Smith /* update the FIB size for the s/g count */ 98235863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 98335863739SMike Smith } 98435863739SMike Smith 98535863739SMike Smith } 98635863739SMike Smith 987c6eafcf2SScott Long /****************************************************************************** 98835863739SMike Smith * Map a command into controller-visible space. 98935863739SMike Smith */ 99035863739SMike Smith static void 99135863739SMike Smith aac_map_command(struct aac_command *cm) 99235863739SMike Smith { 99335863739SMike Smith struct aac_softc *sc = cm->cm_sc; 99435863739SMike Smith 99535863739SMike Smith debug_called(2); 99635863739SMike Smith 99735863739SMike Smith /* don't map more than once */ 99835863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 99935863739SMike Smith return; 100035863739SMike Smith 100135863739SMike Smith if (cm->cm_datalen != 0) { 100235863739SMike Smith bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data, 100335863739SMike Smith cm->cm_datalen, aac_map_command_sg, cm, 0); 100435863739SMike Smith 100535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1006c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1007c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 100835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1009c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1010c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 101135863739SMike Smith } 101235863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 101335863739SMike Smith } 101435863739SMike Smith 1015c6eafcf2SScott Long /****************************************************************************** 101635863739SMike Smith * Unmap a command from controller-visible space. 101735863739SMike Smith */ 101835863739SMike Smith static void 101935863739SMike Smith aac_unmap_command(struct aac_command *cm) 102035863739SMike Smith { 102135863739SMike Smith struct aac_softc *sc = cm->cm_sc; 102235863739SMike Smith 102335863739SMike Smith debug_called(2); 102435863739SMike Smith 102535863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 102635863739SMike Smith return; 102735863739SMike Smith 102835863739SMike Smith if (cm->cm_datalen != 0) { 102935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1030c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1031c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 103235863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1033c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1034c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 103535863739SMike Smith 103635863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 103735863739SMike Smith } 103835863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 103935863739SMike Smith } 104035863739SMike Smith 1041c6eafcf2SScott Long /****************************************************************************** 1042c6eafcf2SScott Long ****************************************************************************** 104335863739SMike Smith Hardware Interface 1044c6eafcf2SScott Long ****************************************************************************** 1045c6eafcf2SScott Long ******************************************************************************/ 104635863739SMike Smith 1047c6eafcf2SScott Long /****************************************************************************** 104835863739SMike Smith * Initialise the adapter. 104935863739SMike Smith */ 105035863739SMike Smith static void 105135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 105235863739SMike Smith { 105335863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 105435863739SMike Smith 105535863739SMike Smith debug_called(1); 105635863739SMike Smith 105735863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 105835863739SMike Smith } 105935863739SMike Smith 106035863739SMike Smith static int 106135863739SMike Smith aac_init(struct aac_softc *sc) 106235863739SMike Smith { 106335863739SMike Smith struct aac_adapter_init *ip; 106435863739SMike Smith time_t then; 106535863739SMike Smith u_int32_t code; 106635863739SMike Smith u_int8_t *qaddr; 106735863739SMike Smith 106835863739SMike Smith debug_called(1); 106935863739SMike Smith 107035863739SMike Smith /* 107135863739SMike Smith * First wait for the adapter to come ready. 107235863739SMike Smith */ 107335863739SMike Smith then = time_second; 107435863739SMike Smith do { 107535863739SMike Smith code = AAC_GET_FWSTATUS(sc); 107635863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 107735863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 107835863739SMike Smith return(ENXIO); 107935863739SMike Smith } 108035863739SMike Smith if (code & AAC_KERNEL_PANIC) { 108135863739SMike Smith device_printf(sc->aac_dev, "FATAL: controller kernel panic\n"); 108235863739SMike Smith return(ENXIO); 108335863739SMike Smith } 108435863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1085c6eafcf2SScott Long device_printf(sc->aac_dev, "FATAL: controller not coming ready, " 1086c6eafcf2SScott Long "status %x\n", code); 108735863739SMike Smith return(ENXIO); 108835863739SMike Smith } 108935863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 109035863739SMike Smith 109135863739SMike Smith /* 109235863739SMike Smith * Create DMA tag for the common structure and allocate it. 109335863739SMike Smith */ 109435863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1095c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 109635863739SMike Smith BUS_SPACE_MAXADDR, /* lowaddr */ 109735863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 109835863739SMike Smith NULL, NULL, /* filter, filterarg */ 109935863739SMike Smith sizeof(struct aac_common), 1,/* maxsize, nsegments */ 110035863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 110135863739SMike Smith 0, /* flags */ 110235863739SMike Smith &sc->aac_common_dmat)) { 110335863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n"); 110435863739SMike Smith return(ENOMEM); 110535863739SMike Smith } 1106c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1107c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 110835863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 110935863739SMike Smith return(ENOMEM); 111035863739SMike Smith } 1111c6eafcf2SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common, 1112c6eafcf2SScott Long sizeof(*sc->aac_common), aac_common_map, sc, 0); 111335863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 111435863739SMike Smith 111535863739SMike Smith /* 1116c6eafcf2SScott Long * Fill in the init structure. This tells the adapter about the physical 1117c6eafcf2SScott Long * location of various important shared data structures. 111835863739SMike Smith */ 111935863739SMike Smith ip = &sc->aac_common->ac_init; 112035863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 112135863739SMike Smith 1122c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1123c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 112435863739SMike Smith ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0]; 112535863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 112635863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 112735863739SMike Smith 1128c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1129c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 113035863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 113135863739SMike Smith 113235863739SMike Smith ip->HostPhysMemPages = 0; /* not used? */ 113335863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 113435863739SMike Smith 113535863739SMike Smith /* 1136c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1137c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1138c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 113935863739SMike Smith * 114035863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1141c6eafcf2SScott Long * of the sizes of the respective queues, and theoretically it could work 1142c6eafcf2SScott Long * out the entire layout of the queue structures from this. We take the 1143c6eafcf2SScott Long * easy route and just lay this area out like everyone else does. 114435863739SMike Smith * 114535863739SMike Smith * The Linux driver uses a much more complex scheme whereby several header 1146c6eafcf2SScott Long * records are kept for each queue. We use a couple of generic list 1147c6eafcf2SScott Long * manipulation functions which 'know' the size of each list by virtue of a 1148c6eafcf2SScott Long * table. 114935863739SMike Smith */ 115035863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 115135863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 115235863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1153c6eafcf2SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues 1154c6eafcf2SScott Long - (u_int32_t)sc->aac_common); 115535863739SMike Smith bzero(sc->aac_queues, sizeof(struct aac_queue_table)); 115635863739SMike Smith 1157c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1158c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1159c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1160c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1161c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1162c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1163c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1164c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1165c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1166c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1167c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1168c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1169c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1170c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1171c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1172c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1173c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1174c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1175c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1176c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1177c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1178c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1179c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1180c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1181c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1182c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1183c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1184c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1185c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1186c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1187c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1188c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1189c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1190c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1191c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1192c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1193c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1194c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1195c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1196c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1197c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1198c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1199c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1200c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1201c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1202c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1203c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1204c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 120535863739SMike Smith 120635863739SMike Smith /* 120735863739SMike Smith * Do controller-type-specific initialisation 120835863739SMike Smith */ 120935863739SMike Smith switch (sc->aac_hwif) { 121035863739SMike Smith case AAC_HWIF_I960RX: 121135863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 121235863739SMike Smith break; 121335863739SMike Smith } 121435863739SMike Smith 121535863739SMike Smith /* 121635863739SMike Smith * Give the init structure to the controller. 121735863739SMike Smith */ 121835863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1219c6eafcf2SScott Long sc->aac_common_busaddr + offsetof(struct aac_common, 1220c6eafcf2SScott Long ac_init), 0, 0, 0, NULL)) { 122135863739SMike Smith device_printf(sc->aac_dev, "error establishing init structure\n"); 122235863739SMike Smith return(EIO); 122335863739SMike Smith } 122435863739SMike Smith 122535863739SMike Smith return(0); 122635863739SMike Smith } 122735863739SMike Smith 1228c6eafcf2SScott Long /****************************************************************************** 122935863739SMike Smith * Send a synchronous command to the controller and wait for a result. 123035863739SMike Smith */ 123135863739SMike Smith static int 123235863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 123335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 123435863739SMike Smith u_int32_t *sp) 123535863739SMike Smith { 123635863739SMike Smith time_t then; 123735863739SMike Smith u_int32_t status; 123835863739SMike Smith 123935863739SMike Smith debug_called(3); 124035863739SMike Smith 124135863739SMike Smith /* populate the mailbox */ 124235863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 124335863739SMike Smith 124435863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 124535863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 124635863739SMike Smith 124735863739SMike Smith /* then set it to signal the adapter */ 124835863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 124935863739SMike Smith 125035863739SMike Smith /* spin waiting for the command to complete */ 125135863739SMike Smith then = time_second; 125235863739SMike Smith do { 125335863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 125435863739SMike Smith debug(2, "timed out"); 125535863739SMike Smith return(EIO); 125635863739SMike Smith } 125735863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 125835863739SMike Smith 125935863739SMike Smith /* clear the completion flag */ 126035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 126135863739SMike Smith 126235863739SMike Smith /* get the command status */ 126335863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 126435863739SMike Smith if (sp != NULL) 126535863739SMike Smith *sp = status; 12660b94a66eSMike Smith return(0); 126735863739SMike Smith } 126835863739SMike Smith 1269c6eafcf2SScott Long /****************************************************************************** 127035863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 127135863739SMike Smith */ 127235863739SMike Smith static int 127335863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 127435863739SMike Smith void *data, u_int16_t datasize, 127535863739SMike Smith void *result, u_int16_t *resultsize) 127635863739SMike Smith { 127735863739SMike Smith struct aac_fib *fib = &sc->aac_common->ac_sync_fib; 127835863739SMike Smith 127935863739SMike Smith debug_called(3); 128035863739SMike Smith 128135863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 128235863739SMike Smith return(EINVAL); 128335863739SMike Smith 128435863739SMike Smith /* 128535863739SMike Smith * Set up the sync FIB 128635863739SMike Smith */ 1287c6eafcf2SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED | 1288c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 128935863739SMike Smith fib->Header.XferState |= xferstate; 129035863739SMike Smith fib->Header.Command = command; 129135863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 129235863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 129335863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 129435863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1295c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1296c6eafcf2SScott Long offsetof(struct aac_common, ac_sync_fib); 129735863739SMike Smith 129835863739SMike Smith /* 129935863739SMike Smith * Copy in data. 130035863739SMike Smith */ 130135863739SMike Smith if (data != NULL) { 1302f6c4dd3fSScott Long KASSERT(datasize <= sizeof(fib->data), 1303f6c4dd3fSScott Long "aac_sync_fib: datasize to large"); 130435863739SMike Smith bcopy(data, fib->data, datasize); 130535863739SMike Smith fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM; 130635863739SMike Smith } 130735863739SMike Smith 130835863739SMike Smith /* 130935863739SMike Smith * Give the FIB to the controller, wait for a response. 131035863739SMike Smith */ 131135863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress, 131235863739SMike Smith 0, 0, 0, NULL)) { 131335863739SMike Smith debug(2, "IO error"); 131435863739SMike Smith return(EIO); 131535863739SMike Smith } 131635863739SMike Smith 131735863739SMike Smith /* 131835863739SMike Smith * Copy out the result 131935863739SMike Smith */ 132035863739SMike Smith if (result != NULL) { 1321f6c4dd3fSScott Long u_int copysize; 1322f6c4dd3fSScott Long 1323f6c4dd3fSScott Long copysize = fib->Header.Size - sizeof(struct aac_fib_header); 1324f6c4dd3fSScott Long if (copysize > *resultsize) 1325f6c4dd3fSScott Long copysize = *resultsize; 132635863739SMike Smith *resultsize = fib->Header.Size - sizeof(struct aac_fib_header); 1327f6c4dd3fSScott Long bcopy(fib->data, result, copysize); 132835863739SMike Smith } 132935863739SMike Smith return(0); 133035863739SMike Smith } 133135863739SMike Smith 133235863739SMike Smith /******************************************************************************** 133335863739SMike Smith * Adapter-space FIB queue manipulation 133435863739SMike Smith * 133535863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 133635863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 133735863739SMike Smith */ 133835863739SMike Smith static struct { 133935863739SMike Smith int size; 134035863739SMike Smith int notify; 134135863739SMike Smith } aac_qinfo[] = { 134235863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 134335863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 134435863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 134535863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 134635863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 134735863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 134835863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 134935863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 135035863739SMike Smith }; 135135863739SMike Smith 135235863739SMike Smith /* 1353c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1354c6eafcf2SScott Long * EBUSY if the queue is full. 135535863739SMike Smith * 13560b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1357c6eafcf2SScott Long * the case where we may be inserting several entries in rapid succession, 1358c6eafcf2SScott Long * but implementing this usefully may be difficult (it would involve a 1359c6eafcf2SScott Long * separate queue/notify interface). 136035863739SMike Smith */ 136135863739SMike Smith static int 1362f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 136335863739SMike Smith { 136435863739SMike Smith u_int32_t pi, ci; 136535863739SMike Smith int s, error; 1366f6c4dd3fSScott Long u_int32_t fib_size; 1367f6c4dd3fSScott Long u_int32_t fib_addr; 1368f6c4dd3fSScott Long 1369f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1370f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 137135863739SMike Smith 137235863739SMike Smith debug_called(3); 137335863739SMike Smith 137435863739SMike Smith s = splbio(); 137535863739SMike Smith 137635863739SMike Smith /* get the producer/consumer indices */ 137735863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 137835863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 137935863739SMike Smith 138035863739SMike Smith /* wrap the queue? */ 138135863739SMike Smith if (pi >= aac_qinfo[queue].size) 138235863739SMike Smith pi = 0; 138335863739SMike Smith 138435863739SMike Smith /* check for queue full */ 138535863739SMike Smith if ((pi + 1) == ci) { 138635863739SMike Smith error = EBUSY; 138735863739SMike Smith goto out; 138835863739SMike Smith } 138935863739SMike Smith 139035863739SMike Smith /* populate queue entry */ 139135863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 139235863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 139335863739SMike Smith 139435863739SMike Smith /* update producer index */ 139535863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 139635863739SMike Smith 1397f6c4dd3fSScott Long /* 1398f6c4dd3fSScott Long * To avoid a race with its completion interrupt, place this command on the 1399f6c4dd3fSScott Long * busy queue prior to advertising it to the controller. 1400f6c4dd3fSScott Long */ 1401f6c4dd3fSScott Long aac_enqueue_busy(cm); 1402f6c4dd3fSScott Long 140335863739SMike Smith /* notify the adapter if we know how */ 140435863739SMike Smith if (aac_qinfo[queue].notify != 0) 140535863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 140635863739SMike Smith 140735863739SMike Smith error = 0; 140835863739SMike Smith 140935863739SMike Smith out: 141035863739SMike Smith splx(s); 141135863739SMike Smith return(error); 141235863739SMike Smith } 141335863739SMike Smith 141435863739SMike Smith /* 1415c6eafcf2SScott Long * Atomically remove one entry from the nominated queue, returns 0 on success or 1416c6eafcf2SScott Long * ENOENT if the queue is empty. 141735863739SMike Smith */ 141835863739SMike Smith static int 1419c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1420c6eafcf2SScott Long struct aac_fib **fib_addr) 142135863739SMike Smith { 142235863739SMike Smith u_int32_t pi, ci; 142335863739SMike Smith int s, error; 1424f6c4dd3fSScott Long int notify; 142535863739SMike Smith 142635863739SMike Smith debug_called(3); 142735863739SMike Smith 142835863739SMike Smith s = splbio(); 142935863739SMike Smith 143035863739SMike Smith /* get the producer/consumer indices */ 143135863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 143235863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 143335863739SMike Smith 143435863739SMike Smith /* check for queue empty */ 143535863739SMike Smith if (ci == pi) { 143635863739SMike Smith error = ENOENT; 143735863739SMike Smith goto out; 143835863739SMike Smith } 143935863739SMike Smith 1440f6c4dd3fSScott Long notify = 0; 1441f6c4dd3fSScott Long if (ci == pi + 1) 1442f6c4dd3fSScott Long notify++; 1443f6c4dd3fSScott Long 144435863739SMike Smith /* wrap the queue? */ 144535863739SMike Smith if (ci >= aac_qinfo[queue].size) 144635863739SMike Smith ci = 0; 144735863739SMike Smith 144835863739SMike Smith /* fetch the entry */ 144935863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 145035863739SMike Smith *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr; 145135863739SMike Smith 145235863739SMike Smith /* update consumer index */ 145335863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 145435863739SMike Smith 145535863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1456f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 145735863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 145835863739SMike Smith error = 0; 145935863739SMike Smith 146035863739SMike Smith out: 146135863739SMike Smith splx(s); 146235863739SMike Smith return(error); 146335863739SMike Smith } 146435863739SMike Smith 1465c6eafcf2SScott Long /****************************************************************************** 14660b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 14670b94a66eSMike Smith * and complain about them. 14680b94a66eSMike Smith */ 14690b94a66eSMike Smith static void 14700b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 14710b94a66eSMike Smith { 14720b94a66eSMike Smith int s; 14730b94a66eSMike Smith struct aac_command *cm; 14740b94a66eSMike Smith time_t deadline; 14750b94a66eSMike Smith 1476f6c4dd3fSScott Long #if 0 14770b94a66eSMike Smith /* simulate an interrupt to handle possibly-missed interrupts */ 1478f6c4dd3fSScott Long /* 1479f6c4dd3fSScott Long * XXX This was done to work around another bug which has since been 1480f6c4dd3fSScott Long * fixed. It is dangerous anyways because you don't want multiple 1481f6c4dd3fSScott Long * threads in the interrupt handler at the same time! If calling 1482f6c4dd3fSScott Long * is deamed neccesary in the future, proper mutexes must be used. 1483f6c4dd3fSScott Long */ 1484f6c4dd3fSScott Long s = splbio(); 14850b94a66eSMike Smith aac_intr(sc); 1486f6c4dd3fSScott Long splx(s); 1487f6c4dd3fSScott Long #endif 14880b94a66eSMike Smith 14890b94a66eSMike Smith /* kick the I/O queue to restart it in the case of deadlock */ 14900b94a66eSMike Smith aac_startio(sc); 14910b94a66eSMike Smith 14920b94a66eSMike Smith /* traverse the busy command list, bitch about late commands once only */ 14930b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 14940b94a66eSMike Smith s = splbio(); 14950b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1496f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1497f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 14980b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1499f6c4dd3fSScott Long device_printf(sc->aac_dev, "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1500f6c4dd3fSScott Long cm, (int)(time_second - cm->cm_timestamp)); 15010b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 15020b94a66eSMike Smith } 15030b94a66eSMike Smith } 15040b94a66eSMike Smith splx(s); 15050b94a66eSMike Smith 15060b94a66eSMike Smith /* reset the timer for next time */ 15070b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 15080b94a66eSMike Smith return; 15090b94a66eSMike Smith } 15100b94a66eSMike Smith 1511c6eafcf2SScott Long /****************************************************************************** 1512c6eafcf2SScott Long ****************************************************************************** 151335863739SMike Smith Interface Function Vectors 1514c6eafcf2SScott Long ****************************************************************************** 1515c6eafcf2SScott Long ******************************************************************************/ 151635863739SMike Smith 1517c6eafcf2SScott Long /****************************************************************************** 151835863739SMike Smith * Read the current firmware status word. 151935863739SMike Smith */ 152035863739SMike Smith static int 152135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 152235863739SMike Smith { 152335863739SMike Smith debug_called(3); 152435863739SMike Smith 152535863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 152635863739SMike Smith } 152735863739SMike Smith 152835863739SMike Smith static int 152935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 153035863739SMike Smith { 153135863739SMike Smith debug_called(3); 153235863739SMike Smith 153335863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 153435863739SMike Smith } 153535863739SMike Smith 1536c6eafcf2SScott Long /****************************************************************************** 153735863739SMike Smith * Notify the controller of a change in a given queue 153835863739SMike Smith */ 153935863739SMike Smith 154035863739SMike Smith static void 154135863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 154235863739SMike Smith { 154335863739SMike Smith debug_called(3); 154435863739SMike Smith 154535863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 154635863739SMike Smith } 154735863739SMike Smith 154835863739SMike Smith static void 154935863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 155035863739SMike Smith { 155135863739SMike Smith debug_called(3); 155235863739SMike Smith 155335863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 155435863739SMike Smith } 155535863739SMike Smith 1556c6eafcf2SScott Long /****************************************************************************** 155735863739SMike Smith * Get the interrupt reason bits 155835863739SMike Smith */ 155935863739SMike Smith static int 156035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 156135863739SMike Smith { 156235863739SMike Smith debug_called(3); 156335863739SMike Smith 156435863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 156535863739SMike Smith } 156635863739SMike Smith 156735863739SMike Smith static int 156835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 156935863739SMike Smith { 157035863739SMike Smith debug_called(3); 157135863739SMike Smith 157235863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 157335863739SMike Smith } 157435863739SMike Smith 1575c6eafcf2SScott Long /****************************************************************************** 157635863739SMike Smith * Clear some interrupt reason bits 157735863739SMike Smith */ 157835863739SMike Smith static void 157935863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 158035863739SMike Smith { 158135863739SMike Smith debug_called(3); 158235863739SMike Smith 158335863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 158435863739SMike Smith } 158535863739SMike Smith 158635863739SMike Smith static void 158735863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 158835863739SMike Smith { 158935863739SMike Smith debug_called(3); 159035863739SMike Smith 159135863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 159235863739SMike Smith } 159335863739SMike Smith 1594c6eafcf2SScott Long /****************************************************************************** 159535863739SMike Smith * Populate the mailbox and set the command word 159635863739SMike Smith */ 159735863739SMike Smith static void 159835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 159935863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 160035863739SMike Smith { 160135863739SMike Smith debug_called(4); 160235863739SMike Smith 160335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 160435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 160535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 160635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 160735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 160835863739SMike Smith } 160935863739SMike Smith 161035863739SMike Smith static void 161135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 161235863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 161335863739SMike Smith { 161435863739SMike Smith debug_called(4); 161535863739SMike Smith 161635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 161735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 161835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 161935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 162035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 162135863739SMike Smith } 162235863739SMike Smith 1623c6eafcf2SScott Long /****************************************************************************** 162435863739SMike Smith * Fetch the immediate command status word 162535863739SMike Smith */ 162635863739SMike Smith static int 162735863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 162835863739SMike Smith { 162935863739SMike Smith debug_called(4); 163035863739SMike Smith 163135863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 163235863739SMike Smith } 163335863739SMike Smith 163435863739SMike Smith static int 163535863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 163635863739SMike Smith { 163735863739SMike Smith debug_called(4); 163835863739SMike Smith 163935863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 164035863739SMike Smith } 164135863739SMike Smith 1642c6eafcf2SScott Long /****************************************************************************** 164335863739SMike Smith * Set/clear interrupt masks 164435863739SMike Smith */ 164535863739SMike Smith static void 164635863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 164735863739SMike Smith { 164835863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 164935863739SMike Smith 165035863739SMike Smith if (enable) { 165135863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 165235863739SMike Smith } else { 165335863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 165435863739SMike Smith } 165535863739SMike Smith } 165635863739SMike Smith 165735863739SMike Smith static void 165835863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 165935863739SMike Smith { 166035863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 166135863739SMike Smith 166235863739SMike Smith if (enable) { 166335863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 166435863739SMike Smith } else { 166535863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 166635863739SMike Smith } 166735863739SMike Smith } 166835863739SMike Smith 1669c6eafcf2SScott Long /****************************************************************************** 1670c6eafcf2SScott Long ****************************************************************************** 167135863739SMike Smith Debugging and Diagnostics 1672c6eafcf2SScott Long ****************************************************************************** 1673c6eafcf2SScott Long ******************************************************************************/ 167435863739SMike Smith 1675c6eafcf2SScott Long /****************************************************************************** 167635863739SMike Smith * Print some information about the controller. 167735863739SMike Smith */ 167835863739SMike Smith static void 167935863739SMike Smith aac_describe_controller(struct aac_softc *sc) 168035863739SMike Smith { 1681c6eafcf2SScott Long u_int8_t buf[AAC_FIB_DATASIZE]; /* XXX really a bit big 1682c6eafcf2SScott Long * for the stack */ 168335863739SMike Smith u_int16_t bufsize; 168435863739SMike Smith struct aac_adapter_info *info; 168535863739SMike Smith u_int8_t arg; 168635863739SMike Smith 168735863739SMike Smith debug_called(2); 168835863739SMike Smith 168935863739SMike Smith arg = 0; 1690f6c4dd3fSScott Long bufsize = sizeof(buf); 1691c6eafcf2SScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf, 1692c6eafcf2SScott Long &bufsize)) { 169335863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 169435863739SMike Smith return; 169535863739SMike Smith } 169635863739SMike Smith if (bufsize != sizeof(*info)) { 1697c6eafcf2SScott Long device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data " 1698c6eafcf2SScott Long "size (%d != %d)\n", bufsize, sizeof(*info)); 16990b94a66eSMike Smith /*return;*/ 170035863739SMike Smith } 170135863739SMike Smith info = (struct aac_adapter_info *)&buf[0]; 170235863739SMike Smith 170335863739SMike Smith device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n", 1704c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 1705c6eafcf2SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 1706c6eafcf2SScott Long aac_describe_code(aac_battery_platform, 1707c6eafcf2SScott Long info->batteryPlatform), info->batteryPlatform); 170835863739SMike Smith 170935863739SMike Smith /* save the kernel revision structure for later use */ 171035863739SMike Smith sc->aac_revision = info->KernelRevision; 171135863739SMike Smith device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n", 171235863739SMike Smith info->KernelRevision.external.comp.major, 171335863739SMike Smith info->KernelRevision.external.comp.minor, 171435863739SMike Smith info->KernelRevision.external.comp.dash, 1715c6eafcf2SScott Long info->SerialNumber); /* XXX format? */ 171635863739SMike Smith } 171735863739SMike Smith 1718c6eafcf2SScott Long /****************************************************************************** 171935863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 172035863739SMike Smith * same. 172135863739SMike Smith */ 172235863739SMike Smith static char * 172335863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 172435863739SMike Smith { 172535863739SMike Smith int i; 172635863739SMike Smith 172735863739SMike Smith for (i = 0; table[i].string != NULL; i++) 172835863739SMike Smith if (table[i].code == code) 172935863739SMike Smith return(table[i].string); 173035863739SMike Smith return(table[i + 1].string); 173135863739SMike Smith } 173235863739SMike Smith 173335863739SMike Smith /***************************************************************************** 173435863739SMike Smith ***************************************************************************** 173535863739SMike Smith Management Interface 173635863739SMike Smith ***************************************************************************** 173735863739SMike Smith *****************************************************************************/ 173835863739SMike Smith 173935863739SMike Smith static int 174035863739SMike Smith aac_open(dev_t dev, int flags, int fmt, struct proc *p) 174135863739SMike Smith { 174235863739SMike Smith struct aac_softc *sc = dev->si_drv1; 174335863739SMike Smith 174435863739SMike Smith debug_called(2); 174535863739SMike Smith 174635863739SMike Smith /* Check to make sure the device isn't already open */ 174735863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 174835863739SMike Smith return EBUSY; 174935863739SMike Smith } 175035863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 175135863739SMike Smith 175235863739SMike Smith return 0; 175335863739SMike Smith } 175435863739SMike Smith 175535863739SMike Smith static int 175635863739SMike Smith aac_close(dev_t dev, int flags, int fmt, struct proc *p) 175735863739SMike Smith { 175835863739SMike Smith struct aac_softc *sc = dev->si_drv1; 175935863739SMike Smith 176035863739SMike Smith debug_called(2); 176135863739SMike Smith 176235863739SMike Smith /* Mark this unit as no longer open */ 176335863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 176435863739SMike Smith 176535863739SMike Smith return 0; 176635863739SMike Smith } 176735863739SMike Smith 176835863739SMike Smith static int 176935863739SMike Smith aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 177035863739SMike Smith { 17710b94a66eSMike Smith union aac_statrequest *as = (union aac_statrequest *)arg; 177235863739SMike Smith struct aac_softc *sc = dev->si_drv1; 17730b94a66eSMike Smith int error = 0; 17740b94a66eSMike Smith #ifdef AAC_COMPAT_LINUX 17750b94a66eSMike Smith int i; 17760b94a66eSMike Smith #endif 177735863739SMike Smith 177835863739SMike Smith debug_called(2); 177935863739SMike Smith 178035863739SMike Smith switch (cmd) { 17810b94a66eSMike Smith case AACIO_STATS: 17820b94a66eSMike Smith switch (as->as_item) { 17830b94a66eSMike Smith case AACQ_FREE: 17840b94a66eSMike Smith case AACQ_BIO: 17850b94a66eSMike Smith case AACQ_READY: 17860b94a66eSMike Smith case AACQ_BUSY: 17870b94a66eSMike Smith case AACQ_COMPLETE: 1788c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 1789c6eafcf2SScott Long sizeof(struct aac_qstat)); 17900b94a66eSMike Smith break; 17910b94a66eSMike Smith default: 17920b94a66eSMike Smith error = ENOENT; 17930b94a66eSMike Smith break; 17940b94a66eSMike Smith } 17950b94a66eSMike Smith break; 17960b94a66eSMike Smith 179735863739SMike Smith #ifdef AAC_COMPAT_LINUX 179835863739SMike Smith case FSACTL_SENDFIB: 17990b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 180035863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 180135863739SMike Smith break; 180235863739SMike Smith case FSACTL_AIF_THREAD: 18030b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 180435863739SMike Smith error = EINVAL; 180535863739SMike Smith break; 180635863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 18070b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 180835863739SMike Smith /* 180935863739SMike Smith * Pass the caller out an AdapterFibContext. 181035863739SMike Smith * 181135863739SMike Smith * Note that because we only support one opener, we 181235863739SMike Smith * basically ignore this. Set the caller's context to a magic 181335863739SMike Smith * number just in case. 18140b94a66eSMike Smith * 18150b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 18160b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 181735863739SMike Smith */ 181835863739SMike Smith i = AAC_AIF_SILLYMAGIC; 181935863739SMike Smith error = copyout(&i, arg, sizeof(i)); 182035863739SMike Smith break; 182135863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 18220b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 182335863739SMike Smith error = aac_linux_getnext_aif(sc, arg); 182435863739SMike Smith break; 182535863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 18260b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 182735863739SMike Smith /* don't do anything here */ 182835863739SMike Smith break; 182935863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 18300b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 183135863739SMike Smith error = aac_linux_rev_check(sc, arg); 183235863739SMike Smith break; 183335863739SMike Smith #endif 183435863739SMike Smith default: 183535863739SMike Smith device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd); 183635863739SMike Smith error = EINVAL; 183735863739SMike Smith break; 183835863739SMike Smith } 183935863739SMike Smith return(error); 184035863739SMike Smith } 184135863739SMike Smith 1842c6eafcf2SScott Long /****************************************************************************** 184335863739SMike Smith * Send a FIB supplied from userspace 184435863739SMike Smith */ 184535863739SMike Smith static int 184635863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 184735863739SMike Smith { 184835863739SMike Smith struct aac_command *cm; 184935863739SMike Smith int size, error; 185035863739SMike Smith 185135863739SMike Smith debug_called(2); 185235863739SMike Smith 185335863739SMike Smith cm = NULL; 185435863739SMike Smith 185535863739SMike Smith /* 185635863739SMike Smith * Get a command 185735863739SMike Smith */ 185835863739SMike Smith if (aac_alloc_command(sc, &cm)) { 185935863739SMike Smith error = EBUSY; 186035863739SMike Smith goto out; 186135863739SMike Smith } 186235863739SMike Smith 186335863739SMike Smith /* 186435863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 186535863739SMike Smith */ 186635863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0) 186735863739SMike Smith goto out; 186835863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 186935863739SMike Smith if (size > sizeof(struct aac_fib)) { 1870c6eafcf2SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size, 1871c6eafcf2SScott Long sizeof(struct aac_fib)); 187235863739SMike Smith size = sizeof(struct aac_fib); 187335863739SMike Smith } 187435863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 187535863739SMike Smith goto out; 187635863739SMike Smith cm->cm_fib->Header.Size = size; 1877f6c4dd3fSScott Long cm->cm_timestamp = time_second; 187835863739SMike Smith 187935863739SMike Smith /* 188035863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 188135863739SMike Smith */ 188235863739SMike Smith if ((error = aac_wait_command(cm, 30)) != 0) /* XXX user timeout? */ 188335863739SMike Smith goto out; 188435863739SMike Smith 188535863739SMike Smith /* 188635863739SMike Smith * Copy the FIB and data back out to the caller. 188735863739SMike Smith */ 188835863739SMike Smith size = cm->cm_fib->Header.Size; 188935863739SMike Smith if (size > sizeof(struct aac_fib)) { 1890c6eafcf2SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size, 1891c6eafcf2SScott Long sizeof(struct aac_fib)); 189235863739SMike Smith size = sizeof(struct aac_fib); 189335863739SMike Smith } 189435863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 189535863739SMike Smith 189635863739SMike Smith out: 1897f6c4dd3fSScott Long if (cm != NULL) { 189835863739SMike Smith aac_release_command(cm); 1899f6c4dd3fSScott Long } 190035863739SMike Smith return(error); 190135863739SMike Smith } 190235863739SMike Smith 1903c6eafcf2SScott Long /****************************************************************************** 190435863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 190535863739SMike Smith * 190635863739SMike Smith * XXX what's the right thing to do here when the queue is full? Drop the older 190735863739SMike Smith * or newer entries? 190835863739SMike Smith */ 190935863739SMike Smith static void 191035863739SMike Smith aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif) 191135863739SMike Smith { 191235863739SMike Smith int next, s; 191335863739SMike Smith 191435863739SMike Smith debug_called(2); 191535863739SMike Smith 191635863739SMike Smith s = splbio(); 191735863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 191835863739SMike Smith if (next != sc->aac_aifq_tail) { 191935863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 192035863739SMike Smith sc->aac_aifq_head = next; 192135863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 192235863739SMike Smith wakeup(sc->aac_aifq); 192335863739SMike Smith } 192435863739SMike Smith splx(s); 192535863739SMike Smith aac_print_aif(sc, aif); 192635863739SMike Smith } 192735863739SMike Smith 1928c6eafcf2SScott Long /****************************************************************************** 1929c6eafcf2SScott Long ****************************************************************************** 193035863739SMike Smith Linux Management Interface 1931c6eafcf2SScott Long ****************************************************************************** 1932c6eafcf2SScott Long ******************************************************************************/ 193335863739SMike Smith 193435863739SMike Smith #ifdef AAC_COMPAT_LINUX 193535863739SMike Smith 193630d57611SMike Smith #include <sys/proc.h> 193735863739SMike Smith #include <machine/../linux/linux.h> 193835863739SMike Smith #include <machine/../linux/linux_proto.h> 193935863739SMike Smith #include <compat/linux/linux_ioctl.h> 194035863739SMike Smith 194135863739SMike Smith #define AAC_LINUX_IOCTL_MIN 0x2000 194235863739SMike Smith #define AAC_LINUX_IOCTL_MAX 0x21ff 194335863739SMike Smith 194435863739SMike Smith static linux_ioctl_function_t aac_linux_ioctl; 1945c6eafcf2SScott Long static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl, 1946c6eafcf2SScott Long AAC_LINUX_IOCTL_MIN, 1947c6eafcf2SScott Long AAC_LINUX_IOCTL_MAX}; 194835863739SMike Smith 1949c6eafcf2SScott Long SYSINIT (aac_register, SI_SUB_KLD, SI_ORDER_MIDDLE, 1950c6eafcf2SScott Long linux_ioctl_register_handler, &aac_handler); 1951c6eafcf2SScott Long SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, 1952c6eafcf2SScott Long linux_ioctl_unregister_handler, &aac_handler); 195335863739SMike Smith 195435863739SMike Smith MODULE_DEPEND(aac, linux, 1, 1, 1); 195535863739SMike Smith 195635863739SMike Smith static int 195735863739SMike Smith aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args) 195835863739SMike Smith { 195935863739SMike Smith struct file *fp = p->p_fd->fd_ofiles[args->fd]; 196035863739SMike Smith u_long cmd = args->cmd; 196135863739SMike Smith 196235863739SMike Smith /* 196335863739SMike Smith * Pass the ioctl off to our standard handler. 196435863739SMike Smith */ 196535863739SMike Smith return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p)); 196635863739SMike Smith } 196735863739SMike Smith 1968c6eafcf2SScott Long /****************************************************************************** 19690b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 197035863739SMike Smith * userspace app is possibly compatible. This is extremely bogus right now 197135863739SMike Smith * because I have no idea how to handle the versioning of this driver. It is 197235863739SMike Smith * needed, though, to get aaccli working. 197335863739SMike Smith */ 197435863739SMike Smith static int 197535863739SMike Smith aac_linux_rev_check(struct aac_softc *sc, caddr_t udata) 197635863739SMike Smith { 197735863739SMike Smith struct aac_rev_check rev_check; 197835863739SMike Smith struct aac_rev_check_resp rev_check_resp; 197935863739SMike Smith int error = 0; 198035863739SMike Smith 198135863739SMike Smith debug_called(2); 198235863739SMike Smith 198335863739SMike Smith /* 198435863739SMike Smith * Copyin the revision struct from userspace 198535863739SMike Smith */ 1986c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 1987c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 198835863739SMike Smith return error; 198935863739SMike Smith } 199035863739SMike Smith 199135863739SMike Smith debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber); 199235863739SMike Smith 199335863739SMike Smith /* 199435863739SMike Smith * Doctor up the response struct. 199535863739SMike Smith */ 199635863739SMike Smith rev_check_resp.possiblyCompatible = 1; 199735863739SMike Smith rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul; 199835863739SMike Smith rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber; 199935863739SMike Smith 2000c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2001c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 200235863739SMike Smith } 200335863739SMike Smith 2004c6eafcf2SScott Long /****************************************************************************** 200535863739SMike Smith * Pass the caller the next AIF in their queue 200635863739SMike Smith */ 200735863739SMike Smith static int 200835863739SMike Smith aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg) 200935863739SMike Smith { 201035863739SMike Smith struct get_adapter_fib_ioctl agf; 201135863739SMike Smith int error, s; 201235863739SMike Smith 201335863739SMike Smith debug_called(2); 201435863739SMike Smith 201535863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 201635863739SMike Smith 201735863739SMike Smith /* 201835863739SMike Smith * Check the magic number that we gave the caller. 201935863739SMike Smith */ 202035863739SMike Smith if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) { 202135863739SMike Smith error = EFAULT; 202235863739SMike Smith } else { 202335863739SMike Smith 202435863739SMike Smith s = splbio(); 20250b94a66eSMike Smith error = aac_linux_return_aif(sc, agf.AifFib); 202635863739SMike Smith 202735863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 202835863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 202935863739SMike Smith while (error == EAGAIN) { 203035863739SMike Smith error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0); 203135863739SMike Smith if (error == 0) 20320b94a66eSMike Smith error = aac_linux_return_aif(sc, agf.AifFib); 203335863739SMike Smith } 203435863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 203535863739SMike Smith } 203635863739SMike Smith splx(s); 203735863739SMike Smith } 203835863739SMike Smith } 203935863739SMike Smith return(error); 204035863739SMike Smith } 204135863739SMike Smith 2042c6eafcf2SScott Long /****************************************************************************** 20430b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 20440b94a66eSMike Smith */ 20450b94a66eSMike Smith static int 20460b94a66eSMike Smith aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr) 20470b94a66eSMike Smith { 20480b94a66eSMike Smith int error, s; 20490b94a66eSMike Smith 20500b94a66eSMike Smith debug_called(2); 20510b94a66eSMike Smith 20520b94a66eSMike Smith s = splbio(); 20530b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 20540b94a66eSMike Smith error = EAGAIN; 20550b94a66eSMike Smith } else { 2056c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2057c6eafcf2SScott Long sizeof(struct aac_aif_command)); 20580b94a66eSMike Smith if (!error) 20590b94a66eSMike Smith sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 20600b94a66eSMike Smith } 20610b94a66eSMike Smith splx(s); 20620b94a66eSMike Smith return(error); 20630b94a66eSMike Smith } 20640b94a66eSMike Smith 20650b94a66eSMike Smith 206635863739SMike Smith #endif /* AAC_COMPAT_LINUX */ 2067