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 3635863739SMike Smith #include <sys/param.h> 3735863739SMike Smith #include <sys/systm.h> 3835863739SMike Smith #include <sys/malloc.h> 3935863739SMike Smith #include <sys/kernel.h> 4035863739SMike Smith 4135863739SMike Smith #include <dev/aac/aac_compat.h> 4235863739SMike Smith 4335863739SMike Smith #include <sys/bus.h> 4435863739SMike Smith #include <sys/conf.h> 4535863739SMike Smith #include <sys/devicestat.h> 4635863739SMike Smith #include <sys/disk.h> 4735863739SMike Smith #include <sys/file.h> 4835863739SMike Smith #include <sys/signalvar.h> 490b94a66eSMike Smith #include <sys/time.h> 5035863739SMike Smith 5135863739SMike Smith #include <machine/bus_memio.h> 5235863739SMike Smith #include <machine/bus.h> 5335863739SMike Smith #include <machine/resource.h> 5435863739SMike Smith 5535863739SMike Smith #include <dev/aac/aacreg.h> 560b94a66eSMike Smith #include <dev/aac/aac_ioctl.h> 5735863739SMike Smith #include <dev/aac/aacvar.h> 5835863739SMike Smith #include <dev/aac/aac_tables.h> 5935863739SMike Smith 6035863739SMike Smith devclass_t aac_devclass; 6135863739SMike Smith 6235863739SMike Smith static void aac_startup(void *arg); 6335863739SMike Smith 6435863739SMike Smith /* Command Processing */ 6535863739SMike Smith static void aac_startio(struct aac_softc *sc); 660b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 6735863739SMike Smith static int aac_start(struct aac_command *cm); 6835863739SMike Smith static void aac_complete(void *context, int pending); 6935863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7035863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 7135863739SMike Smith static int aac_wait_command(struct aac_command *cm, int timeout); 7235863739SMike Smith static void aac_host_command(struct aac_softc *sc); 7335863739SMike Smith static void aac_host_response(struct aac_softc *sc); 7435863739SMike Smith 7535863739SMike Smith /* Command Buffer Management */ 7635863739SMike Smith static int aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp); 7735863739SMike Smith static void aac_release_command(struct aac_command *cm); 78c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 79c6eafcf2SScott Long int nseg, int error); 800b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 810b94a66eSMike Smith static void aac_free_commands(struct aac_softc *sc); 8235863739SMike Smith static void aac_map_command(struct aac_command *cm); 8335863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 8435863739SMike Smith 8535863739SMike Smith /* Hardware Interface */ 86c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 87c6eafcf2SScott Long int error); 8835863739SMike Smith static int aac_init(struct aac_softc *sc); 8935863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 90c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 91c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 92c6eafcf2SScott Long static int aac_sync_fib(struct aac_softc *sc, u_int32_t command, 93c6eafcf2SScott Long u_int32_t xferstate, void *data, 94c6eafcf2SScott Long u_int16_t datasize, void *result, 95c6eafcf2SScott Long u_int16_t *resultsize); 96c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 97c6eafcf2SScott Long u_int32_t fib_size, u_int32_t fib_addr); 98c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 99c6eafcf2SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10035863739SMike Smith 10135863739SMike Smith /* StrongARM interface */ 10235863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 10335863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 10435863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 10535863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 10635863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 107c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 108c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 10935863739SMike Smith static int aac_sa_get_mailboxstatus(struct aac_softc *sc); 11035863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 11135863739SMike Smith 11235863739SMike Smith struct aac_interface aac_sa_interface = { 11335863739SMike Smith aac_sa_get_fwstatus, 11435863739SMike Smith aac_sa_qnotify, 11535863739SMike Smith aac_sa_get_istatus, 11635863739SMike Smith aac_sa_clear_istatus, 11735863739SMike Smith aac_sa_set_mailbox, 11835863739SMike Smith aac_sa_get_mailboxstatus, 11935863739SMike Smith aac_sa_set_interrupts 12035863739SMike Smith }; 12135863739SMike Smith 12235863739SMike Smith /* i960Rx interface */ 12335863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 12435863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 12535863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 12635863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 12735863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 128c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 129c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 13035863739SMike Smith static int aac_rx_get_mailboxstatus(struct aac_softc *sc); 13135863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 13235863739SMike Smith 13335863739SMike Smith struct aac_interface aac_rx_interface = { 13435863739SMike Smith aac_rx_get_fwstatus, 13535863739SMike Smith aac_rx_qnotify, 13635863739SMike Smith aac_rx_get_istatus, 13735863739SMike Smith aac_rx_clear_istatus, 13835863739SMike Smith aac_rx_set_mailbox, 13935863739SMike Smith aac_rx_get_mailboxstatus, 14035863739SMike Smith aac_rx_set_interrupts 14135863739SMike Smith }; 14235863739SMike Smith 14335863739SMike Smith /* Debugging and Diagnostics */ 14435863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 145c6eafcf2SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 146c6eafcf2SScott Long u_int32_t code); 14735863739SMike Smith 14835863739SMike Smith /* Management Interface */ 14935863739SMike Smith static d_open_t aac_open; 15035863739SMike Smith static d_close_t aac_close; 15135863739SMike Smith static d_ioctl_t aac_ioctl; 152c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 153c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 154c6eafcf2SScott Long struct aac_aif_command *aif); 15535863739SMike Smith #ifdef AAC_COMPAT_LINUX 156c6eafcf2SScott Long static int aac_linux_rev_check(struct aac_softc *sc, 157c6eafcf2SScott Long caddr_t udata); 158c6eafcf2SScott Long static int aac_linux_getnext_aif(struct aac_softc *sc, 159c6eafcf2SScott Long caddr_t arg); 160c6eafcf2SScott Long static int aac_linux_return_aif(struct aac_softc *sc, 161c6eafcf2SScott Long caddr_t uptr); 16235863739SMike Smith #endif 16335863739SMike Smith 16435863739SMike Smith #define AAC_CDEV_MAJOR 150 16535863739SMike Smith 16635863739SMike Smith static struct cdevsw aac_cdevsw = { 16735863739SMike Smith aac_open, /* open */ 16835863739SMike Smith aac_close, /* close */ 16935863739SMike Smith noread, /* read */ 17035863739SMike Smith nowrite, /* write */ 17135863739SMike Smith aac_ioctl, /* ioctl */ 17235863739SMike Smith nopoll, /* poll */ 17335863739SMike Smith nommap, /* mmap */ 17435863739SMike Smith nostrategy, /* strategy */ 17535863739SMike Smith "aac", /* name */ 17635863739SMike Smith AAC_CDEV_MAJOR, /* major */ 17735863739SMike Smith nodump, /* dump */ 17835863739SMike Smith nopsize, /* psize */ 17935863739SMike Smith 0, /* flags */ 18035863739SMike Smith }; 18135863739SMike Smith 182c6eafcf2SScott Long /****************************************************************************** 183c6eafcf2SScott Long ****************************************************************************** 18435863739SMike Smith Device Interface 185c6eafcf2SScott Long ****************************************************************************** 186c6eafcf2SScott Long ******************************************************************************/ 18735863739SMike Smith 188c6eafcf2SScott Long /****************************************************************************** 18935863739SMike Smith * Initialise the controller and softc 19035863739SMike Smith */ 19135863739SMike Smith int 19235863739SMike Smith aac_attach(struct aac_softc *sc) 19335863739SMike Smith { 19435863739SMike Smith int error, unit; 19535863739SMike Smith 19635863739SMike Smith debug_called(1); 19735863739SMike Smith 19835863739SMike Smith /* 19935863739SMike Smith * Initialise per-controller queues. 20035863739SMike Smith */ 2010b94a66eSMike Smith aac_initq_free(sc); 2020b94a66eSMike Smith aac_initq_ready(sc); 2030b94a66eSMike Smith aac_initq_busy(sc); 2040b94a66eSMike Smith aac_initq_complete(sc); 2050b94a66eSMike Smith aac_initq_bio(sc); 20635863739SMike Smith 20735863739SMike Smith #if __FreeBSD_version >= 500005 20835863739SMike Smith /* 20935863739SMike Smith * Initialise command-completion task. 21035863739SMike Smith */ 21135863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 21235863739SMike Smith #endif 21335863739SMike Smith 21435863739SMike Smith /* disable interrupts before we enable anything */ 21535863739SMike Smith AAC_MASK_INTERRUPTS(sc); 21635863739SMike Smith 21735863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 21835863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 21935863739SMike Smith 22035863739SMike Smith /* 2210b94a66eSMike Smith * Allocate command structures. 2220b94a66eSMike Smith */ 2230b94a66eSMike Smith if ((error = aac_alloc_commands(sc)) != 0) 2240b94a66eSMike Smith return(error); 2250b94a66eSMike Smith 2260b94a66eSMike Smith /* 22735863739SMike Smith * Initialise the adapter. 22835863739SMike Smith */ 2290b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 23035863739SMike Smith return(error); 23135863739SMike Smith 23235863739SMike Smith /* 23335863739SMike Smith * Print a little information about the controller. 23435863739SMike Smith */ 23535863739SMike Smith aac_describe_controller(sc); 23635863739SMike Smith 23735863739SMike Smith /* 23835863739SMike Smith * Register to probe our containers later. 23935863739SMike Smith */ 24035863739SMike Smith sc->aac_ich.ich_func = aac_startup; 24135863739SMike Smith sc->aac_ich.ich_arg = sc; 24235863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 24335863739SMike Smith device_printf(sc->aac_dev, "can't establish configuration hook\n"); 24435863739SMike Smith return(ENXIO); 24535863739SMike Smith } 24635863739SMike Smith 24735863739SMike Smith /* 24835863739SMike Smith * Make the control device. 24935863739SMike Smith */ 25035863739SMike Smith unit = device_get_unit(sc->aac_dev); 251c6eafcf2SScott Long sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644, 252c6eafcf2SScott Long "aac%d", unit); 253157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 2544aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 255157fbb2eSScott Long 25635863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 25735863739SMike Smith 25835863739SMike Smith return(0); 25935863739SMike Smith } 26035863739SMike Smith 261c6eafcf2SScott Long /****************************************************************************** 26235863739SMike Smith * Probe for containers, create disks. 26335863739SMike Smith */ 26435863739SMike Smith static void 26535863739SMike Smith aac_startup(void *arg) 26635863739SMike Smith { 26735863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 26835863739SMike Smith struct aac_mntinfo mi; 26935863739SMike Smith struct aac_mntinforesponse mir; 27035863739SMike Smith device_t child; 27135863739SMike Smith u_int16_t rsize; 27235863739SMike Smith int i; 27335863739SMike Smith 27435863739SMike Smith debug_called(1); 27535863739SMike Smith 27635863739SMike Smith /* disconnect ourselves from the intrhook chain */ 27735863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 27835863739SMike Smith 27935863739SMike Smith /* loop over possible containers */ 28035863739SMike Smith mi.Command = VM_NameServe; 28135863739SMike Smith mi.MntType = FT_FILESYS; 28235863739SMike Smith for (i = 0; i < AAC_MAX_CONTAINERS; i++) { 28335863739SMike Smith /* request information on this container */ 28435863739SMike Smith mi.MntCount = i; 285c6eafcf2SScott Long if (aac_sync_fib(sc, ContainerCommand, 0, &mi, 286c6eafcf2SScott Long sizeof(struct aac_mntinfo), &mir, &rsize)) { 28735863739SMike Smith debug(2, "error probing container %d", i); 28835863739SMike Smith continue; 28935863739SMike Smith } 29035863739SMike Smith /* check response size */ 29135863739SMike Smith if (rsize != sizeof(mir)) { 292c6eafcf2SScott Long debug(2, "container info response wrong size (%d should be %d)", 293c6eafcf2SScott Long rsize, sizeof(mir)); 29435863739SMike Smith continue; 29535863739SMike Smith } 29635863739SMike Smith /* 297c6eafcf2SScott Long * Check container volume type for validity. Note that many of the 298c6eafcf2SScott Long * possible types may never show up. 29935863739SMike Smith */ 30035863739SMike Smith if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) { 30135863739SMike Smith debug(1, "%d: id %x name '%.16s' size %u type %d", 30235863739SMike Smith i, mir.MntTable[0].ObjectId, 30335863739SMike Smith mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity, 30435863739SMike Smith mir.MntTable[0].VolType); 30535863739SMike Smith 30635863739SMike Smith if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) { 30735863739SMike Smith device_printf(sc->aac_dev, "device_add_child failed\n"); 30835863739SMike Smith } else { 30935863739SMike Smith device_set_ivars(child, &sc->aac_container[i]); 31035863739SMike Smith } 311c6eafcf2SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 312c6eafcf2SScott Long mir.MntTable[0].VolType)); 31335863739SMike Smith sc->aac_container[i].co_disk = child; 31435863739SMike Smith sc->aac_container[i].co_mntobj = mir.MntTable[0]; 31535863739SMike Smith } 31635863739SMike Smith } 31735863739SMike Smith 31835863739SMike Smith /* poke the bus to actually attach the child devices */ 31935863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 32035863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 32135863739SMike Smith 32235863739SMike Smith /* mark the controller up */ 32335863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 32435863739SMike Smith 32535863739SMike Smith /* enable interrupts now */ 32635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 3270b94a66eSMike Smith 3280b94a66eSMike Smith /* enable the timeout watchdog */ 3290b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 33035863739SMike Smith } 33135863739SMike Smith 332c6eafcf2SScott Long /****************************************************************************** 33335863739SMike Smith * Free all of the resources associated with (sc) 33435863739SMike Smith * 33535863739SMike Smith * Should not be called if the controller is active. 33635863739SMike Smith */ 33735863739SMike Smith void 33835863739SMike Smith aac_free(struct aac_softc *sc) 33935863739SMike Smith { 34035863739SMike Smith debug_called(1); 34135863739SMike Smith 34235863739SMike Smith /* remove the control device */ 34335863739SMike Smith if (sc->aac_dev_t != NULL) 34435863739SMike Smith destroy_dev(sc->aac_dev_t); 34535863739SMike Smith 3460b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 3470b94a66eSMike Smith if (sc->aac_fibs != NULL) 3480b94a66eSMike Smith aac_free_commands(sc); 3490b94a66eSMike Smith if (sc->aac_fib_dmat) 3500b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 35135863739SMike Smith 35235863739SMike Smith /* destroy the common area */ 35335863739SMike Smith if (sc->aac_common) { 35435863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 355c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 356c6eafcf2SScott Long sc->aac_common_dmamap); 35735863739SMike Smith } 3580b94a66eSMike Smith if (sc->aac_common_dmat) 3590b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 36035863739SMike Smith 36135863739SMike Smith /* disconnect the interrupt handler */ 36235863739SMike Smith if (sc->aac_intr) 36335863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 36435863739SMike Smith if (sc->aac_irq != NULL) 365c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 366c6eafcf2SScott Long sc->aac_irq); 36735863739SMike Smith 36835863739SMike Smith /* destroy data-transfer DMA tag */ 36935863739SMike Smith if (sc->aac_buffer_dmat) 37035863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 37135863739SMike Smith 37235863739SMike Smith /* destroy the parent DMA tag */ 37335863739SMike Smith if (sc->aac_parent_dmat) 37435863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 37535863739SMike Smith 37635863739SMike Smith /* release the register window mapping */ 37735863739SMike Smith if (sc->aac_regs_resource != NULL) 378c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid, 379c6eafcf2SScott Long sc->aac_regs_resource); 38035863739SMike Smith } 38135863739SMike Smith 382c6eafcf2SScott Long /****************************************************************************** 38335863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 38435863739SMike Smith */ 38535863739SMike Smith int 38635863739SMike Smith aac_detach(device_t dev) 38735863739SMike Smith { 38835863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 38935863739SMike Smith int error; 39035863739SMike Smith 39135863739SMike Smith debug_called(1); 39235863739SMike Smith 39335863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 39435863739SMike Smith return(EBUSY); 39535863739SMike Smith 39635863739SMike Smith if ((error = aac_shutdown(dev))) 39735863739SMike Smith return(error); 39835863739SMike Smith 39935863739SMike Smith aac_free(sc); 40035863739SMike Smith 40135863739SMike Smith return(0); 40235863739SMike Smith } 40335863739SMike Smith 404c6eafcf2SScott Long /****************************************************************************** 40535863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 40635863739SMike Smith * 40735863739SMike Smith * This function is called before detach or system shutdown. 40835863739SMike Smith * 4090b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 41035863739SMike Smith * allow shutdown if any device is open. 41135863739SMike Smith */ 41235863739SMike Smith int 41335863739SMike Smith aac_shutdown(device_t dev) 41435863739SMike Smith { 41535863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 41635863739SMike Smith struct aac_close_command cc; 41735863739SMike Smith int s, i; 41835863739SMike Smith 41935863739SMike Smith debug_called(1); 42035863739SMike Smith 42135863739SMike Smith s = splbio(); 42235863739SMike Smith 42335863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 42435863739SMike Smith 42535863739SMike Smith /* 42635863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 42735863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 42835863739SMike Smith * We've been closed and all I/O completed already 42935863739SMike Smith */ 43035863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 43135863739SMike Smith 43235863739SMike Smith cc.Command = VM_CloseAll; 43335863739SMike Smith cc.ContainerId = 0xffffffff; 43435863739SMike Smith if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) { 43535863739SMike Smith printf("FAILED.\n"); 43635863739SMike Smith } else { 43735863739SMike Smith i = 0; 438c6eafcf2SScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i, 439c6eafcf2SScott Long sizeof(i), NULL, NULL)) { 44035863739SMike Smith printf("FAILED.\n"); 44135863739SMike Smith } else { 44235863739SMike Smith printf("done.\n"); 44335863739SMike Smith } 44435863739SMike Smith } 44535863739SMike Smith 44635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 44735863739SMike Smith 44835863739SMike Smith splx(s); 44935863739SMike Smith return(0); 45035863739SMike Smith } 45135863739SMike Smith 452c6eafcf2SScott Long /****************************************************************************** 45335863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 45435863739SMike Smith */ 45535863739SMike Smith int 45635863739SMike Smith aac_suspend(device_t dev) 45735863739SMike Smith { 45835863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 45935863739SMike Smith int s; 46035863739SMike Smith 46135863739SMike Smith debug_called(1); 46235863739SMike Smith s = splbio(); 46335863739SMike Smith 46435863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 46535863739SMike Smith 46635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 46735863739SMike Smith splx(s); 46835863739SMike Smith return(0); 46935863739SMike Smith } 47035863739SMike Smith 471c6eafcf2SScott Long /****************************************************************************** 47235863739SMike Smith * Bring the controller back to a state ready for operation. 47335863739SMike Smith */ 47435863739SMike Smith int 47535863739SMike Smith aac_resume(device_t dev) 47635863739SMike Smith { 47735863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 47835863739SMike Smith 47935863739SMike Smith debug_called(1); 48035863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 48135863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 48235863739SMike Smith return(0); 48335863739SMike Smith } 48435863739SMike Smith 485c6eafcf2SScott Long /****************************************************************************** 48635863739SMike Smith * Take an interrupt. 48735863739SMike Smith */ 48835863739SMike Smith void 48935863739SMike Smith aac_intr(void *arg) 49035863739SMike Smith { 49135863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 49235863739SMike Smith u_int16_t reason; 49335863739SMike Smith 49435863739SMike Smith debug_called(2); 49535863739SMike Smith 49635863739SMike Smith reason = AAC_GET_ISTATUS(sc); 49735863739SMike Smith 49835863739SMike Smith /* controller wants to talk to the log? XXX should we defer this? */ 49935863739SMike Smith if (reason & AAC_DB_PRINTF) { 50035863739SMike Smith if (sc->aac_common->ac_printf[0]) { 501c6eafcf2SScott Long device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE, 502c6eafcf2SScott Long sc->aac_common->ac_printf); 50335863739SMike Smith sc->aac_common->ac_printf[0] = 0; 50435863739SMike Smith } 50535863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF); 50635863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_PRINTF); 50735863739SMike Smith } 50835863739SMike Smith 50935863739SMike Smith /* controller has a message for us? */ 51035863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 51135863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY); 512da4c1ce3SJustin T. Gibbs aac_host_command(sc); 51335863739SMike Smith } 51435863739SMike Smith 51535863739SMike Smith /* controller has a response for us? */ 51635863739SMike Smith if (reason & AAC_DB_RESPONSE_READY) { 51735863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 518da4c1ce3SJustin T. Gibbs aac_host_response(sc); 51935863739SMike Smith } 52035863739SMike Smith 521c6eafcf2SScott Long /* 522c6eafcf2SScott Long * spurious interrupts that we don't use - reset the mask and clear the 523c6eafcf2SScott Long * interrupts 524c6eafcf2SScott Long */ 52535863739SMike Smith if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) { 52635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 527c6eafcf2SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL | 528c6eafcf2SScott Long AAC_DB_RESPONSE_NOT_FULL); 52935863739SMike Smith } 53035863739SMike Smith }; 53135863739SMike Smith 532c6eafcf2SScott Long /****************************************************************************** 533c6eafcf2SScott Long ****************************************************************************** 53435863739SMike Smith Command Processing 535c6eafcf2SScott Long ****************************************************************************** 536c6eafcf2SScott Long ******************************************************************************/ 53735863739SMike Smith 538c6eafcf2SScott Long /****************************************************************************** 53935863739SMike Smith * Start as much queued I/O as possible on the controller 54035863739SMike Smith */ 54135863739SMike Smith static void 54235863739SMike Smith aac_startio(struct aac_softc *sc) 54335863739SMike Smith { 54435863739SMike Smith struct aac_command *cm; 54535863739SMike Smith 54635863739SMike Smith debug_called(2); 54735863739SMike Smith 54835863739SMike Smith for(;;) { 54935863739SMike Smith /* try to get a command that's been put off for lack of resources */ 55035863739SMike Smith cm = aac_dequeue_ready(sc); 55135863739SMike Smith 55235863739SMike Smith /* try to build a command off the bio queue (ignore error return) */ 5530b94a66eSMike Smith if (cm == NULL) 55435863739SMike Smith aac_bio_command(sc, &cm); 55535863739SMike Smith 55635863739SMike Smith /* nothing to do? */ 55735863739SMike Smith if (cm == NULL) 55835863739SMike Smith break; 55935863739SMike Smith 56035863739SMike Smith /* try to give the command to the controller */ 56135863739SMike Smith if (aac_start(cm) == EBUSY) { 56235863739SMike Smith /* put it on the ready queue for later */ 56335863739SMike Smith aac_requeue_ready(cm); 56435863739SMike Smith break; 56535863739SMike Smith } 56635863739SMike Smith } 56735863739SMike Smith } 56835863739SMike Smith 569c6eafcf2SScott Long /****************************************************************************** 57035863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 57135863739SMike Smith * last moment when possible. 57235863739SMike Smith */ 57335863739SMike Smith static int 57435863739SMike Smith aac_start(struct aac_command *cm) 57535863739SMike Smith { 57635863739SMike Smith struct aac_softc *sc = cm->cm_sc; 577ed5c5fb4SMike Smith int error; 57835863739SMike Smith 57935863739SMike Smith debug_called(2); 58035863739SMike Smith 58135863739SMike Smith /* get the command mapped */ 58235863739SMike Smith aac_map_command(cm); 58335863739SMike Smith 5840b94a66eSMike Smith /* fix up the address values in the FIB */ 58535863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 58635863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 58735863739SMike Smith 58835863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 589c6eafcf2SScott Long cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical 590c6eafcf2SScott Long * address issue */ 59135863739SMike Smith 59235863739SMike Smith /* put the FIB on the outbound queue */ 59335863739SMike Smith if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm->cm_fib->Header.Size, 5940b94a66eSMike Smith cm->cm_fib->Header.ReceiverFibAddress)) { 5950b94a66eSMike Smith error = EBUSY; 5960b94a66eSMike Smith } else { 5970b94a66eSMike Smith aac_enqueue_busy(cm); 5980b94a66eSMike Smith error = 0; 5990b94a66eSMike Smith } 6000b94a66eSMike Smith return(error); 60135863739SMike Smith } 60235863739SMike Smith 603c6eafcf2SScott Long /****************************************************************************** 60435863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 60535863739SMike Smith */ 60635863739SMike Smith static void 60735863739SMike Smith aac_host_command(struct aac_softc *sc) 60835863739SMike Smith { 60935863739SMike Smith struct aac_fib *fib; 61035863739SMike Smith u_int32_t fib_size; 61135863739SMike Smith 61235863739SMike Smith debug_called(1); 61335863739SMike Smith 61435863739SMike Smith for (;;) { 61535863739SMike Smith if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib)) 61635863739SMike Smith break; /* nothing to do */ 61735863739SMike Smith 61835863739SMike Smith switch(fib->Header.Command) { 61935863739SMike Smith case AifRequest: 62035863739SMike Smith aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]); 62135863739SMike Smith break; 62235863739SMike Smith default: 62335863739SMike Smith device_printf(sc->aac_dev, "unknown command from controller\n"); 62435863739SMike Smith AAC_PRINT_FIB(sc, fib); 62535863739SMike Smith break; 62635863739SMike Smith } 62735863739SMike Smith 62835863739SMike Smith /* XXX reply to FIBs requesting responses ?? */ 62935863739SMike Smith /* XXX how do we return these FIBs to the controller? */ 63035863739SMike Smith } 63135863739SMike Smith } 63235863739SMike Smith 633c6eafcf2SScott Long /****************************************************************************** 63435863739SMike Smith * Handle notification of one or more FIBs completed by the controller 63535863739SMike Smith */ 63635863739SMike Smith static void 63735863739SMike Smith aac_host_response(struct aac_softc *sc) 63835863739SMike Smith { 63935863739SMike Smith struct aac_command *cm; 64035863739SMike Smith struct aac_fib *fib; 64135863739SMike Smith u_int32_t fib_size; 64235863739SMike Smith 64335863739SMike Smith debug_called(2); 64435863739SMike Smith 64535863739SMike Smith for (;;) { 64635863739SMike Smith /* look for completed FIBs on our queue */ 64735863739SMike Smith if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib)) 64835863739SMike Smith break; /* nothing to do */ 64935863739SMike Smith 65035863739SMike Smith /* get the command, unmap and queue for later processing */ 65135863739SMike Smith cm = (struct aac_command *)fib->Header.SenderData; 65235863739SMike Smith if (cm == NULL) { 65335863739SMike Smith AAC_PRINT_FIB(sc, fib); 65435863739SMike Smith } else { 6550b94a66eSMike Smith aac_remove_busy(cm); 65635863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 6570b94a66eSMike Smith aac_enqueue_complete(cm); 65835863739SMike Smith } 65935863739SMike Smith } 66035863739SMike Smith 66135863739SMike Smith /* handle completion processing */ 66235863739SMike Smith #if __FreeBSD_version >= 500005 66335863739SMike Smith taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 66435863739SMike Smith #else 66535863739SMike Smith aac_complete(sc, 0); 66635863739SMike Smith #endif 66735863739SMike Smith } 66835863739SMike Smith 669c6eafcf2SScott Long /****************************************************************************** 67035863739SMike Smith * Process completed commands. 67135863739SMike Smith */ 67235863739SMike Smith static void 67335863739SMike Smith aac_complete(void *context, int pending) 67435863739SMike Smith { 67535863739SMike Smith struct aac_softc *sc = (struct aac_softc *)context; 67635863739SMike Smith struct aac_command *cm; 67735863739SMike Smith 67835863739SMike Smith debug_called(2); 67935863739SMike Smith 68035863739SMike Smith /* pull completed commands off the queue */ 68135863739SMike Smith for (;;) { 6820b94a66eSMike Smith cm = aac_dequeue_complete(sc); 68335863739SMike Smith if (cm == NULL) 6840b94a66eSMike Smith break; 68535863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 68635863739SMike Smith 68735863739SMike Smith /* is there a completion handler? */ 68835863739SMike Smith if (cm->cm_complete != NULL) { 68935863739SMike Smith cm->cm_complete(cm); 69035863739SMike Smith } else { 69135863739SMike Smith /* assume that someone is sleeping on this command */ 69235863739SMike Smith wakeup(cm); 69335863739SMike Smith } 69435863739SMike Smith } 6950b94a66eSMike Smith 6960b94a66eSMike Smith /* see if we can start some more I/O */ 6970b94a66eSMike Smith aac_startio(sc); 69835863739SMike Smith } 69935863739SMike Smith 700c6eafcf2SScott Long /****************************************************************************** 70135863739SMike Smith * Handle a bio submitted from a disk device. 70235863739SMike Smith */ 70335863739SMike Smith void 70435863739SMike Smith aac_submit_bio(struct bio *bp) 70535863739SMike Smith { 70635863739SMike Smith struct aac_disk *ad = (struct aac_disk *)bp->bio_dev->si_drv1; 70735863739SMike Smith struct aac_softc *sc = ad->ad_controller; 70835863739SMike Smith 70935863739SMike Smith debug_called(2); 71035863739SMike Smith 71135863739SMike Smith /* queue the BIO and try to get some work done */ 7120b94a66eSMike Smith aac_enqueue_bio(sc, bp); 71335863739SMike Smith aac_startio(sc); 71435863739SMike Smith } 71535863739SMike Smith 716c6eafcf2SScott Long /****************************************************************************** 71735863739SMike Smith * Get a bio and build a command to go with it. 71835863739SMike Smith */ 71935863739SMike Smith static int 72035863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 72135863739SMike Smith { 72235863739SMike Smith struct aac_command *cm; 72335863739SMike Smith struct aac_fib *fib; 72435863739SMike Smith struct aac_blockread *br; 72535863739SMike Smith struct aac_blockwrite *bw; 72635863739SMike Smith struct aac_disk *ad; 72735863739SMike Smith struct bio *bp; 72835863739SMike Smith 72935863739SMike Smith debug_called(2); 73035863739SMike Smith 73135863739SMike Smith /* get the resources we will need */ 73235863739SMike Smith cm = NULL; 7330b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 73435863739SMike Smith goto fail; 73535863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 73635863739SMike Smith goto fail; 73735863739SMike Smith 73835863739SMike Smith /* fill out the command */ 7390b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 7400b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 7410b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 74235863739SMike Smith cm->cm_private = bp; 7430b94a66eSMike Smith cm->cm_timestamp = time_second; 74435863739SMike Smith 74535863739SMike Smith /* build the FIB */ 74635863739SMike Smith fib = cm->cm_fib; 74735863739SMike Smith fib->Header.XferState = 74835863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 74935863739SMike Smith AAC_FIBSTATE_INITIALISED | 75035863739SMike Smith AAC_FIBSTATE_FROMHOST | 75135863739SMike Smith AAC_FIBSTATE_REXPECTED | 75235863739SMike Smith AAC_FIBSTATE_NORM; 75335863739SMike Smith fib->Header.Command = ContainerCommand; 75435863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 75535863739SMike Smith 75635863739SMike Smith /* build the read/write request */ 75735863739SMike Smith ad = (struct aac_disk *)bp->bio_dev->si_drv1; 75835863739SMike Smith if (BIO_IS_READ(bp)) { 75935863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 76035863739SMike Smith br->Command = VM_CtBlockRead; 76135863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 76235863739SMike Smith br->BlockNumber = bp->bio_pblkno; 76335863739SMike Smith br->ByteCount = bp->bio_bcount; 76435863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 76535863739SMike Smith cm->cm_sgtable = &br->SgMap; 76635863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 76735863739SMike Smith } else { 76835863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 76935863739SMike Smith bw->Command = VM_CtBlockWrite; 77035863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 77135863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 77235863739SMike Smith bw->ByteCount = bp->bio_bcount; 77335863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 77435863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 77535863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 77635863739SMike Smith cm->cm_sgtable = &bw->SgMap; 77735863739SMike Smith } 77835863739SMike Smith 77935863739SMike Smith *cmp = cm; 78035863739SMike Smith return(0); 78135863739SMike Smith 78235863739SMike Smith fail: 78335863739SMike Smith if (bp != NULL) 7840b94a66eSMike Smith aac_enqueue_bio(sc, bp); 78535863739SMike Smith if (cm != NULL) 78635863739SMike Smith aac_release_command(cm); 78735863739SMike Smith return(ENOMEM); 78835863739SMike Smith } 78935863739SMike Smith 790c6eafcf2SScott Long /****************************************************************************** 79135863739SMike Smith * Handle a bio-instigated command that has been completed. 79235863739SMike Smith */ 79335863739SMike Smith static void 79435863739SMike Smith aac_bio_complete(struct aac_command *cm) 79535863739SMike Smith { 79635863739SMike Smith struct aac_blockread_response *brr; 79735863739SMike Smith struct aac_blockwrite_response *bwr; 79835863739SMike Smith struct bio *bp; 79935863739SMike Smith AAC_FSAStatus status; 80035863739SMike Smith 80135863739SMike Smith /* fetch relevant status and then release the command */ 80235863739SMike Smith bp = (struct bio *)cm->cm_private; 80335863739SMike Smith if (BIO_IS_READ(bp)) { 80435863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 80535863739SMike Smith status = brr->Status; 80635863739SMike Smith } else { 80735863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 80835863739SMike Smith status = bwr->Status; 80935863739SMike Smith } 81035863739SMike Smith aac_release_command(cm); 81135863739SMike Smith 81235863739SMike Smith /* fix up the bio based on status */ 81335863739SMike Smith if (status == ST_OK) { 81435863739SMike Smith bp->bio_resid = 0; 81535863739SMike Smith } else { 81635863739SMike Smith bp->bio_error = EIO; 81735863739SMike Smith bp->bio_flags |= BIO_ERROR; 8180b94a66eSMike Smith /* pass an error string out to the disk layer */ 8190b94a66eSMike Smith bp->bio_driver1 = aac_describe_code(aac_command_status_table, status); 82035863739SMike Smith } 8210b94a66eSMike Smith aac_biodone(bp); 82235863739SMike Smith } 82335863739SMike Smith 824c6eafcf2SScott Long /****************************************************************************** 82535863739SMike Smith * Submit a command to the controller, return when it completes. 82635863739SMike Smith */ 82735863739SMike Smith static int 82835863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 82935863739SMike Smith { 83035863739SMike Smith int s, error = 0; 83135863739SMike Smith 83235863739SMike Smith debug_called(2); 83335863739SMike Smith 83435863739SMike Smith /* Put the command on the ready queue and get things going */ 83535863739SMike Smith aac_enqueue_ready(cm); 83635863739SMike Smith aac_startio(cm->cm_sc); 83735863739SMike Smith s = splbio(); 83835863739SMike Smith while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 83935863739SMike Smith error = tsleep(cm, PRIBIO, "aacwait", timeout * hz); 84035863739SMike Smith } 84135863739SMike Smith splx(s); 84235863739SMike Smith return(error); 84335863739SMike Smith } 84435863739SMike Smith 845c6eafcf2SScott Long /****************************************************************************** 846c6eafcf2SScott Long ****************************************************************************** 84735863739SMike Smith Command Buffer Management 848c6eafcf2SScott Long ****************************************************************************** 849c6eafcf2SScott Long ******************************************************************************/ 85035863739SMike Smith 851c6eafcf2SScott Long /****************************************************************************** 85235863739SMike Smith * Allocate a command. 85335863739SMike Smith */ 85435863739SMike Smith static int 85535863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 85635863739SMike Smith { 85735863739SMike Smith struct aac_command *cm; 85835863739SMike Smith 85935863739SMike Smith debug_called(3); 86035863739SMike Smith 8610b94a66eSMike Smith if ((cm = aac_dequeue_free(sc)) == NULL) 86235863739SMike Smith return(ENOMEM); 86335863739SMike Smith 8640b94a66eSMike Smith *cmp = cm; 8650b94a66eSMike Smith return(0); 8660b94a66eSMike Smith } 8670b94a66eSMike Smith 868c6eafcf2SScott Long /****************************************************************************** 8690b94a66eSMike Smith * Release a command back to the freelist. 8700b94a66eSMike Smith */ 8710b94a66eSMike Smith static void 8720b94a66eSMike Smith aac_release_command(struct aac_command *cm) 8730b94a66eSMike Smith { 8740b94a66eSMike Smith debug_called(3); 8750b94a66eSMike Smith 8760b94a66eSMike Smith /* (re)initialise the command/FIB */ 87735863739SMike Smith cm->cm_sgtable = NULL; 87835863739SMike Smith cm->cm_flags = 0; 87935863739SMike Smith cm->cm_complete = NULL; 88035863739SMike Smith cm->cm_private = NULL; 88135863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 88235863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 88335863739SMike Smith cm->cm_fib->Header.Flags = 0; 88435863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 88535863739SMike Smith 88635863739SMike Smith /* 88735863739SMike Smith * These are duplicated in aac_start to cover the case where an 88835863739SMike Smith * intermediate stage may have destroyed them. They're left 88935863739SMike Smith * initialised here for debugging purposes only. 89035863739SMike Smith */ 89135863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 89235863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 89335863739SMike Smith 89435863739SMike Smith aac_enqueue_free(cm); 89535863739SMike Smith } 89635863739SMike Smith 897c6eafcf2SScott Long /****************************************************************************** 8980b94a66eSMike Smith * Map helper for command/FIB allocation. 89935863739SMike Smith */ 90035863739SMike Smith static void 9010b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 90235863739SMike Smith { 9030b94a66eSMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 90435863739SMike Smith 90535863739SMike Smith debug_called(3); 90635863739SMike Smith 9070b94a66eSMike Smith sc->aac_fibphys = segs[0].ds_addr; 90835863739SMike Smith } 90935863739SMike Smith 910c6eafcf2SScott Long /****************************************************************************** 9110b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 91235863739SMike Smith */ 9130b94a66eSMike Smith static int 9140b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 91535863739SMike Smith { 91635863739SMike Smith struct aac_command *cm; 91735863739SMike Smith int i; 91835863739SMike Smith 91935863739SMike Smith debug_called(1); 92035863739SMike Smith 9210b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 922c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, 923c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_fibmap)) { 9240b94a66eSMike Smith return(ENOMEM); 92535863739SMike Smith } 9260b94a66eSMike Smith bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 927c6eafcf2SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 928c6eafcf2SScott Long aac_map_command_helper, sc, 0); 92935863739SMike Smith 9300b94a66eSMike Smith /* initialise constant fields in the command structure */ 9310b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 9320b94a66eSMike Smith cm = &sc->aac_command[i]; 93335863739SMike Smith cm->cm_sc = sc; 9340b94a66eSMike Smith cm->cm_fib = sc->aac_fibs + i; 9350b94a66eSMike Smith cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); 93635863739SMike Smith 93735863739SMike Smith if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) 93835863739SMike Smith aac_release_command(cm); 93935863739SMike Smith } 9400b94a66eSMike Smith return(0); 94135863739SMike Smith } 94235863739SMike Smith 943c6eafcf2SScott Long /****************************************************************************** 9440b94a66eSMike Smith * Free FIBs owned by this adapter. 94535863739SMike Smith */ 94635863739SMike Smith static void 9470b94a66eSMike Smith aac_free_commands(struct aac_softc *sc) 94835863739SMike Smith { 94935863739SMike Smith int i; 95035863739SMike Smith 95135863739SMike Smith debug_called(1); 95235863739SMike Smith 9530b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) 9540b94a66eSMike Smith bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap); 9550b94a66eSMike Smith bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); 9560b94a66eSMike Smith bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); 95735863739SMike Smith } 95835863739SMike Smith 959c6eafcf2SScott Long /****************************************************************************** 96035863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 96135863739SMike Smith */ 96235863739SMike Smith static void 96335863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 96435863739SMike Smith { 96535863739SMike Smith struct aac_command *cm = (struct aac_command *)arg; 96635863739SMike Smith struct aac_fib *fib = cm->cm_fib; 96735863739SMike Smith struct aac_sg_table *sg; 96835863739SMike Smith int i; 96935863739SMike Smith 97035863739SMike Smith debug_called(3); 97135863739SMike Smith 97235863739SMike Smith /* find the s/g table */ 97335863739SMike Smith sg = cm->cm_sgtable; 97435863739SMike Smith 97535863739SMike Smith /* copy into the FIB */ 97635863739SMike Smith if (sg != NULL) { 97735863739SMike Smith sg->SgCount = nseg; 97835863739SMike Smith for (i = 0; i < nseg; i++) { 97935863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 98035863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 98135863739SMike Smith } 98235863739SMike Smith /* update the FIB size for the s/g count */ 98335863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 98435863739SMike Smith } 98535863739SMike Smith 98635863739SMike Smith } 98735863739SMike Smith 988c6eafcf2SScott Long /****************************************************************************** 98935863739SMike Smith * Map a command into controller-visible space. 99035863739SMike Smith */ 99135863739SMike Smith static void 99235863739SMike Smith aac_map_command(struct aac_command *cm) 99335863739SMike Smith { 99435863739SMike Smith struct aac_softc *sc = cm->cm_sc; 99535863739SMike Smith 99635863739SMike Smith debug_called(2); 99735863739SMike Smith 99835863739SMike Smith /* don't map more than once */ 99935863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 100035863739SMike Smith return; 100135863739SMike Smith 100235863739SMike Smith if (cm->cm_datalen != 0) { 100335863739SMike Smith bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data, 100435863739SMike Smith cm->cm_datalen, aac_map_command_sg, cm, 0); 100535863739SMike Smith 100635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1007c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1008c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 100935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1010c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1011c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 101235863739SMike Smith } 101335863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 101435863739SMike Smith } 101535863739SMike Smith 1016c6eafcf2SScott Long /****************************************************************************** 101735863739SMike Smith * Unmap a command from controller-visible space. 101835863739SMike Smith */ 101935863739SMike Smith static void 102035863739SMike Smith aac_unmap_command(struct aac_command *cm) 102135863739SMike Smith { 102235863739SMike Smith struct aac_softc *sc = cm->cm_sc; 102335863739SMike Smith 102435863739SMike Smith debug_called(2); 102535863739SMike Smith 102635863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 102735863739SMike Smith return; 102835863739SMike Smith 102935863739SMike Smith if (cm->cm_datalen != 0) { 103035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1031c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1032c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 103335863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1034c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1035c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 103635863739SMike Smith 103735863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 103835863739SMike Smith } 103935863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 104035863739SMike Smith } 104135863739SMike Smith 1042c6eafcf2SScott Long /****************************************************************************** 1043c6eafcf2SScott Long ****************************************************************************** 104435863739SMike Smith Hardware Interface 1045c6eafcf2SScott Long ****************************************************************************** 1046c6eafcf2SScott Long ******************************************************************************/ 104735863739SMike Smith 1048c6eafcf2SScott Long /****************************************************************************** 104935863739SMike Smith * Initialise the adapter. 105035863739SMike Smith */ 105135863739SMike Smith static void 105235863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 105335863739SMike Smith { 105435863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 105535863739SMike Smith 105635863739SMike Smith debug_called(1); 105735863739SMike Smith 105835863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 105935863739SMike Smith } 106035863739SMike Smith 106135863739SMike Smith static int 106235863739SMike Smith aac_init(struct aac_softc *sc) 106335863739SMike Smith { 106435863739SMike Smith struct aac_adapter_init *ip; 106535863739SMike Smith time_t then; 106635863739SMike Smith u_int32_t code; 106735863739SMike Smith u_int8_t *qaddr; 106835863739SMike Smith 106935863739SMike Smith debug_called(1); 107035863739SMike Smith 107135863739SMike Smith /* 107235863739SMike Smith * First wait for the adapter to come ready. 107335863739SMike Smith */ 107435863739SMike Smith then = time_second; 107535863739SMike Smith do { 107635863739SMike Smith code = AAC_GET_FWSTATUS(sc); 107735863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 107835863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 107935863739SMike Smith return(ENXIO); 108035863739SMike Smith } 108135863739SMike Smith if (code & AAC_KERNEL_PANIC) { 108235863739SMike Smith device_printf(sc->aac_dev, "FATAL: controller kernel panic\n"); 108335863739SMike Smith return(ENXIO); 108435863739SMike Smith } 108535863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1086c6eafcf2SScott Long device_printf(sc->aac_dev, "FATAL: controller not coming ready, " 1087c6eafcf2SScott Long "status %x\n", code); 108835863739SMike Smith return(ENXIO); 108935863739SMike Smith } 109035863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 109135863739SMike Smith 109235863739SMike Smith /* 109335863739SMike Smith * Create DMA tag for the common structure and allocate it. 109435863739SMike Smith */ 109535863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1096c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 109735863739SMike Smith BUS_SPACE_MAXADDR, /* lowaddr */ 109835863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 109935863739SMike Smith NULL, NULL, /* filter, filterarg */ 110035863739SMike Smith sizeof(struct aac_common), 1,/* maxsize, nsegments */ 110135863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 110235863739SMike Smith 0, /* flags */ 110335863739SMike Smith &sc->aac_common_dmat)) { 110435863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n"); 110535863739SMike Smith return(ENOMEM); 110635863739SMike Smith } 1107c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1108c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 110935863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 111035863739SMike Smith return(ENOMEM); 111135863739SMike Smith } 1112c6eafcf2SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common, 1113c6eafcf2SScott Long sizeof(*sc->aac_common), aac_common_map, sc, 0); 111435863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 111535863739SMike Smith 111635863739SMike Smith /* 1117c6eafcf2SScott Long * Fill in the init structure. This tells the adapter about the physical 1118c6eafcf2SScott Long * location of various important shared data structures. 111935863739SMike Smith */ 112035863739SMike Smith ip = &sc->aac_common->ac_init; 112135863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 112235863739SMike Smith 1123c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1124c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 112535863739SMike Smith ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0]; 112635863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 112735863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 112835863739SMike Smith 1129c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1130c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 113135863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 113235863739SMike Smith 113335863739SMike Smith ip->HostPhysMemPages = 0; /* not used? */ 113435863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 113535863739SMike Smith 113635863739SMike Smith /* 1137c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1138c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1139c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 114035863739SMike Smith * 114135863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1142c6eafcf2SScott Long * of the sizes of the respective queues, and theoretically it could work 1143c6eafcf2SScott Long * out the entire layout of the queue structures from this. We take the 1144c6eafcf2SScott Long * easy route and just lay this area out like everyone else does. 114535863739SMike Smith * 114635863739SMike Smith * The Linux driver uses a much more complex scheme whereby several header 1147c6eafcf2SScott Long * records are kept for each queue. We use a couple of generic list 1148c6eafcf2SScott Long * manipulation functions which 'know' the size of each list by virtue of a 1149c6eafcf2SScott Long * table. 115035863739SMike Smith */ 115135863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 115235863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 115335863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1154c6eafcf2SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues 1155c6eafcf2SScott Long - (u_int32_t)sc->aac_common); 115635863739SMike Smith bzero(sc->aac_queues, sizeof(struct aac_queue_table)); 115735863739SMike Smith 1158c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1159c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1160c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1161c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1162c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1163c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1164c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1165c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1166c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1167c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1168c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1169c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1170c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1171c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1172c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1173c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1174c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1175c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1176c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1177c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1178c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1179c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1180c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1181c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1182c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1183c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1184c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1185c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1186c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = 1187c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1188c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = 1189c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1190c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1191c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1192c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1193c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1194c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1195c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1196c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1197c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1198c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1199c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1200c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1201c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1202c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1203c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1204c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1205c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 120635863739SMike Smith 120735863739SMike Smith /* 120835863739SMike Smith * Do controller-type-specific initialisation 120935863739SMike Smith */ 121035863739SMike Smith switch (sc->aac_hwif) { 121135863739SMike Smith case AAC_HWIF_I960RX: 121235863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 121335863739SMike Smith break; 121435863739SMike Smith } 121535863739SMike Smith 121635863739SMike Smith /* 121735863739SMike Smith * Give the init structure to the controller. 121835863739SMike Smith */ 121935863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1220c6eafcf2SScott Long sc->aac_common_busaddr + offsetof(struct aac_common, 1221c6eafcf2SScott Long ac_init), 0, 0, 0, NULL)) { 122235863739SMike Smith device_printf(sc->aac_dev, "error establishing init structure\n"); 122335863739SMike Smith return(EIO); 122435863739SMike Smith } 122535863739SMike Smith 122635863739SMike Smith return(0); 122735863739SMike Smith } 122835863739SMike Smith 1229c6eafcf2SScott Long /****************************************************************************** 123035863739SMike Smith * Send a synchronous command to the controller and wait for a result. 123135863739SMike Smith */ 123235863739SMike Smith static int 123335863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 123435863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 123535863739SMike Smith u_int32_t *sp) 123635863739SMike Smith { 123735863739SMike Smith time_t then; 123835863739SMike Smith u_int32_t status; 123935863739SMike Smith 124035863739SMike Smith debug_called(3); 124135863739SMike Smith 124235863739SMike Smith /* populate the mailbox */ 124335863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 124435863739SMike Smith 124535863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 124635863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 124735863739SMike Smith 124835863739SMike Smith /* then set it to signal the adapter */ 124935863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 125035863739SMike Smith 125135863739SMike Smith /* spin waiting for the command to complete */ 125235863739SMike Smith then = time_second; 125335863739SMike Smith do { 125435863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 125535863739SMike Smith debug(2, "timed out"); 125635863739SMike Smith return(EIO); 125735863739SMike Smith } 125835863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 125935863739SMike Smith 126035863739SMike Smith /* clear the completion flag */ 126135863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 126235863739SMike Smith 126335863739SMike Smith /* get the command status */ 126435863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 126535863739SMike Smith if (sp != NULL) 126635863739SMike Smith *sp = status; 12670b94a66eSMike Smith return(0); 126835863739SMike Smith } 126935863739SMike Smith 1270c6eafcf2SScott Long /****************************************************************************** 127135863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 127235863739SMike Smith */ 127335863739SMike Smith static int 127435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 127535863739SMike Smith void *data, u_int16_t datasize, 127635863739SMike Smith void *result, u_int16_t *resultsize) 127735863739SMike Smith { 127835863739SMike Smith struct aac_fib *fib = &sc->aac_common->ac_sync_fib; 127935863739SMike Smith 128035863739SMike Smith debug_called(3); 128135863739SMike Smith 128235863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 128335863739SMike Smith return(EINVAL); 128435863739SMike Smith 128535863739SMike Smith /* 128635863739SMike Smith * Set up the sync FIB 128735863739SMike Smith */ 1288c6eafcf2SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED | 1289c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 129035863739SMike Smith fib->Header.XferState |= xferstate; 129135863739SMike Smith fib->Header.Command = command; 129235863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 129335863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 129435863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 129535863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1296c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1297c6eafcf2SScott Long offsetof(struct aac_common, ac_sync_fib); 129835863739SMike Smith 129935863739SMike Smith /* 130035863739SMike Smith * Copy in data. 130135863739SMike Smith */ 130235863739SMike Smith if (data != NULL) { 130335863739SMike Smith bcopy(data, fib->data, datasize); 130435863739SMike Smith fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM; 130535863739SMike Smith } 130635863739SMike Smith 130735863739SMike Smith /* 130835863739SMike Smith * Give the FIB to the controller, wait for a response. 130935863739SMike Smith */ 131035863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress, 131135863739SMike Smith 0, 0, 0, NULL)) { 131235863739SMike Smith debug(2, "IO error"); 131335863739SMike Smith return(EIO); 131435863739SMike Smith } 131535863739SMike Smith 131635863739SMike Smith /* 131735863739SMike Smith * Copy out the result 131835863739SMike Smith */ 131935863739SMike Smith if (result != NULL) { 132035863739SMike Smith *resultsize = fib->Header.Size - sizeof(struct aac_fib_header); 132135863739SMike Smith bcopy(fib->data, result, *resultsize); 132235863739SMike Smith } 132335863739SMike Smith return(0); 132435863739SMike Smith } 132535863739SMike Smith 132635863739SMike Smith /******************************************************************************** 132735863739SMike Smith * Adapter-space FIB queue manipulation 132835863739SMike Smith * 132935863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 133035863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 133135863739SMike Smith */ 133235863739SMike Smith static struct { 133335863739SMike Smith int size; 133435863739SMike Smith int notify; 133535863739SMike Smith } aac_qinfo[] = { 133635863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 133735863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 133835863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 133935863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 134035863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 134135863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 134235863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 134335863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 134435863739SMike Smith }; 134535863739SMike Smith 134635863739SMike Smith /* 1347c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1348c6eafcf2SScott Long * EBUSY if the queue is full. 134935863739SMike Smith * 13500b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1351c6eafcf2SScott Long * the case where we may be inserting several entries in rapid succession, 1352c6eafcf2SScott Long * but implementing this usefully may be difficult (it would involve a 1353c6eafcf2SScott Long * separate queue/notify interface). 135435863739SMike Smith */ 135535863739SMike Smith static int 1356c6eafcf2SScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size, 1357c6eafcf2SScott Long u_int32_t fib_addr) 135835863739SMike Smith { 135935863739SMike Smith u_int32_t pi, ci; 136035863739SMike Smith int s, error; 136135863739SMike Smith 136235863739SMike Smith debug_called(3); 136335863739SMike Smith 136435863739SMike Smith s = splbio(); 136535863739SMike Smith 136635863739SMike Smith /* get the producer/consumer indices */ 136735863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 136835863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 136935863739SMike Smith 137035863739SMike Smith /* wrap the queue? */ 137135863739SMike Smith if (pi >= aac_qinfo[queue].size) 137235863739SMike Smith pi = 0; 137335863739SMike Smith 137435863739SMike Smith /* check for queue full */ 137535863739SMike Smith if ((pi + 1) == ci) { 137635863739SMike Smith error = EBUSY; 137735863739SMike Smith goto out; 137835863739SMike Smith } 137935863739SMike Smith 138035863739SMike Smith /* populate queue entry */ 138135863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 138235863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 138335863739SMike Smith 138435863739SMike Smith /* update producer index */ 138535863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 138635863739SMike Smith 138735863739SMike Smith /* notify the adapter if we know how */ 138835863739SMike Smith if (aac_qinfo[queue].notify != 0) 138935863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 139035863739SMike Smith 139135863739SMike Smith error = 0; 139235863739SMike Smith 139335863739SMike Smith out: 139435863739SMike Smith splx(s); 139535863739SMike Smith return(error); 139635863739SMike Smith } 139735863739SMike Smith 139835863739SMike Smith /* 1399c6eafcf2SScott Long * Atomically remove one entry from the nominated queue, returns 0 on success or 1400c6eafcf2SScott Long * ENOENT if the queue is empty. 140135863739SMike Smith */ 140235863739SMike Smith static int 1403c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1404c6eafcf2SScott Long struct aac_fib **fib_addr) 140535863739SMike Smith { 140635863739SMike Smith u_int32_t pi, ci; 140735863739SMike Smith int s, error; 140835863739SMike Smith 140935863739SMike Smith debug_called(3); 141035863739SMike Smith 141135863739SMike Smith s = splbio(); 141235863739SMike Smith 141335863739SMike Smith /* get the producer/consumer indices */ 141435863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 141535863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 141635863739SMike Smith 141735863739SMike Smith /* check for queue empty */ 141835863739SMike Smith if (ci == pi) { 141935863739SMike Smith error = ENOENT; 142035863739SMike Smith goto out; 142135863739SMike Smith } 142235863739SMike Smith 142335863739SMike Smith /* wrap the queue? */ 142435863739SMike Smith if (ci >= aac_qinfo[queue].size) 142535863739SMike Smith ci = 0; 142635863739SMike Smith 142735863739SMike Smith /* fetch the entry */ 142835863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 142935863739SMike Smith *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr; 143035863739SMike Smith 143135863739SMike Smith /* update consumer index */ 143235863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 143335863739SMike Smith 143435863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 143535863739SMike Smith if (((pi + 1) == ci) && (aac_qinfo[queue].notify != 0)) 143635863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 143735863739SMike Smith error = 0; 143835863739SMike Smith 143935863739SMike Smith out: 144035863739SMike Smith splx(s); 144135863739SMike Smith return(error); 144235863739SMike Smith } 144335863739SMike Smith 1444c6eafcf2SScott Long /****************************************************************************** 14450b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 14460b94a66eSMike Smith * and complain about them. 14470b94a66eSMike Smith */ 14480b94a66eSMike Smith static void 14490b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 14500b94a66eSMike Smith { 14510b94a66eSMike Smith int s; 14520b94a66eSMike Smith struct aac_command *cm; 14530b94a66eSMike Smith time_t deadline; 14540b94a66eSMike Smith 14550b94a66eSMike Smith /* simulate an interrupt to handle possibly-missed interrupts */ 14560b94a66eSMike Smith aac_intr(sc); 14570b94a66eSMike Smith 14580b94a66eSMike Smith /* kick the I/O queue to restart it in the case of deadlock */ 14590b94a66eSMike Smith aac_startio(sc); 14600b94a66eSMike Smith 14610b94a66eSMike Smith /* traverse the busy command list, bitch about late commands once only */ 14620b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 14630b94a66eSMike Smith s = splbio(); 14640b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1465c6eafcf2SScott Long if ((cm->cm_timestamp < deadline) && 1466c6eafcf2SScott Long !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { 14670b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 14680b94a66eSMike Smith device_printf(sc->aac_dev, "COMMAND TIMED OUT AFTER %d SECONDS\n", 14690b94a66eSMike Smith (int)(time_second - cm->cm_timestamp)); 14700b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 14710b94a66eSMike Smith } 14720b94a66eSMike Smith } 14730b94a66eSMike Smith splx(s); 14740b94a66eSMike Smith 14750b94a66eSMike Smith /* reset the timer for next time */ 14760b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 14770b94a66eSMike Smith return; 14780b94a66eSMike Smith } 14790b94a66eSMike Smith 1480c6eafcf2SScott Long /****************************************************************************** 1481c6eafcf2SScott Long ****************************************************************************** 148235863739SMike Smith Interface Function Vectors 1483c6eafcf2SScott Long ****************************************************************************** 1484c6eafcf2SScott Long ******************************************************************************/ 148535863739SMike Smith 1486c6eafcf2SScott Long /****************************************************************************** 148735863739SMike Smith * Read the current firmware status word. 148835863739SMike Smith */ 148935863739SMike Smith static int 149035863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 149135863739SMike Smith { 149235863739SMike Smith debug_called(3); 149335863739SMike Smith 149435863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 149535863739SMike Smith } 149635863739SMike Smith 149735863739SMike Smith static int 149835863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 149935863739SMike Smith { 150035863739SMike Smith debug_called(3); 150135863739SMike Smith 150235863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 150335863739SMike Smith } 150435863739SMike Smith 1505c6eafcf2SScott Long /****************************************************************************** 150635863739SMike Smith * Notify the controller of a change in a given queue 150735863739SMike Smith */ 150835863739SMike Smith 150935863739SMike Smith static void 151035863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 151135863739SMike Smith { 151235863739SMike Smith debug_called(3); 151335863739SMike Smith 151435863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 151535863739SMike Smith } 151635863739SMike Smith 151735863739SMike Smith static void 151835863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 151935863739SMike Smith { 152035863739SMike Smith debug_called(3); 152135863739SMike Smith 152235863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 152335863739SMike Smith } 152435863739SMike Smith 1525c6eafcf2SScott Long /****************************************************************************** 152635863739SMike Smith * Get the interrupt reason bits 152735863739SMike Smith */ 152835863739SMike Smith static int 152935863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 153035863739SMike Smith { 153135863739SMike Smith debug_called(3); 153235863739SMike Smith 153335863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 153435863739SMike Smith } 153535863739SMike Smith 153635863739SMike Smith static int 153735863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 153835863739SMike Smith { 153935863739SMike Smith debug_called(3); 154035863739SMike Smith 154135863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 154235863739SMike Smith } 154335863739SMike Smith 1544c6eafcf2SScott Long /****************************************************************************** 154535863739SMike Smith * Clear some interrupt reason bits 154635863739SMike Smith */ 154735863739SMike Smith static void 154835863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 154935863739SMike Smith { 155035863739SMike Smith debug_called(3); 155135863739SMike Smith 155235863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 155335863739SMike Smith } 155435863739SMike Smith 155535863739SMike Smith static void 155635863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 155735863739SMike Smith { 155835863739SMike Smith debug_called(3); 155935863739SMike Smith 156035863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 156135863739SMike Smith } 156235863739SMike Smith 1563c6eafcf2SScott Long /****************************************************************************** 156435863739SMike Smith * Populate the mailbox and set the command word 156535863739SMike Smith */ 156635863739SMike Smith static void 156735863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 156835863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 156935863739SMike Smith { 157035863739SMike Smith debug_called(4); 157135863739SMike Smith 157235863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 157335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 157435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 157535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 157635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 157735863739SMike Smith } 157835863739SMike Smith 157935863739SMike Smith static void 158035863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 158135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 158235863739SMike Smith { 158335863739SMike Smith debug_called(4); 158435863739SMike Smith 158535863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 158635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 158735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 158835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 158935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 159035863739SMike Smith } 159135863739SMike Smith 1592c6eafcf2SScott Long /****************************************************************************** 159335863739SMike Smith * Fetch the immediate command status word 159435863739SMike Smith */ 159535863739SMike Smith static int 159635863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 159735863739SMike Smith { 159835863739SMike Smith debug_called(4); 159935863739SMike Smith 160035863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 160135863739SMike Smith } 160235863739SMike Smith 160335863739SMike Smith static int 160435863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 160535863739SMike Smith { 160635863739SMike Smith debug_called(4); 160735863739SMike Smith 160835863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 160935863739SMike Smith } 161035863739SMike Smith 1611c6eafcf2SScott Long /****************************************************************************** 161235863739SMike Smith * Set/clear interrupt masks 161335863739SMike Smith */ 161435863739SMike Smith static void 161535863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 161635863739SMike Smith { 161735863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 161835863739SMike Smith 161935863739SMike Smith if (enable) { 162035863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 162135863739SMike Smith } else { 162235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 162335863739SMike Smith } 162435863739SMike Smith } 162535863739SMike Smith 162635863739SMike Smith static void 162735863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 162835863739SMike Smith { 162935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 163035863739SMike Smith 163135863739SMike Smith if (enable) { 163235863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 163335863739SMike Smith } else { 163435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 163535863739SMike Smith } 163635863739SMike Smith } 163735863739SMike Smith 1638c6eafcf2SScott Long /****************************************************************************** 1639c6eafcf2SScott Long ****************************************************************************** 164035863739SMike Smith Debugging and Diagnostics 1641c6eafcf2SScott Long ****************************************************************************** 1642c6eafcf2SScott Long ******************************************************************************/ 164335863739SMike Smith 1644c6eafcf2SScott Long /****************************************************************************** 164535863739SMike Smith * Print some information about the controller. 164635863739SMike Smith */ 164735863739SMike Smith static void 164835863739SMike Smith aac_describe_controller(struct aac_softc *sc) 164935863739SMike Smith { 1650c6eafcf2SScott Long u_int8_t buf[AAC_FIB_DATASIZE]; /* XXX really a bit big 1651c6eafcf2SScott Long * for the stack */ 165235863739SMike Smith u_int16_t bufsize; 165335863739SMike Smith struct aac_adapter_info *info; 165435863739SMike Smith u_int8_t arg; 165535863739SMike Smith 165635863739SMike Smith debug_called(2); 165735863739SMike Smith 165835863739SMike Smith arg = 0; 1659c6eafcf2SScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf, 1660c6eafcf2SScott Long &bufsize)) { 166135863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 166235863739SMike Smith return; 166335863739SMike Smith } 166435863739SMike Smith if (bufsize != sizeof(*info)) { 1665c6eafcf2SScott Long device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data " 1666c6eafcf2SScott Long "size (%d != %d)\n", bufsize, sizeof(*info)); 16670b94a66eSMike Smith /*return;*/ 166835863739SMike Smith } 166935863739SMike Smith info = (struct aac_adapter_info *)&buf[0]; 167035863739SMike Smith 167135863739SMike Smith device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n", 1672c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 1673c6eafcf2SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 1674c6eafcf2SScott Long aac_describe_code(aac_battery_platform, 1675c6eafcf2SScott Long info->batteryPlatform), info->batteryPlatform); 167635863739SMike Smith 167735863739SMike Smith /* save the kernel revision structure for later use */ 167835863739SMike Smith sc->aac_revision = info->KernelRevision; 167935863739SMike Smith device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n", 168035863739SMike Smith info->KernelRevision.external.comp.major, 168135863739SMike Smith info->KernelRevision.external.comp.minor, 168235863739SMike Smith info->KernelRevision.external.comp.dash, 1683c6eafcf2SScott Long info->SerialNumber); /* XXX format? */ 168435863739SMike Smith } 168535863739SMike Smith 1686c6eafcf2SScott Long /****************************************************************************** 168735863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 168835863739SMike Smith * same. 168935863739SMike Smith */ 169035863739SMike Smith static char * 169135863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 169235863739SMike Smith { 169335863739SMike Smith int i; 169435863739SMike Smith 169535863739SMike Smith for (i = 0; table[i].string != NULL; i++) 169635863739SMike Smith if (table[i].code == code) 169735863739SMike Smith return(table[i].string); 169835863739SMike Smith return(table[i + 1].string); 169935863739SMike Smith } 170035863739SMike Smith 170135863739SMike Smith /***************************************************************************** 170235863739SMike Smith ***************************************************************************** 170335863739SMike Smith Management Interface 170435863739SMike Smith ***************************************************************************** 170535863739SMike Smith *****************************************************************************/ 170635863739SMike Smith 170735863739SMike Smith static int 170835863739SMike Smith aac_open(dev_t dev, int flags, int fmt, struct proc *p) 170935863739SMike Smith { 171035863739SMike Smith struct aac_softc *sc = dev->si_drv1; 171135863739SMike Smith 171235863739SMike Smith debug_called(2); 171335863739SMike Smith 171435863739SMike Smith /* Check to make sure the device isn't already open */ 171535863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 171635863739SMike Smith return EBUSY; 171735863739SMike Smith } 171835863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 171935863739SMike Smith 172035863739SMike Smith return 0; 172135863739SMike Smith } 172235863739SMike Smith 172335863739SMike Smith static int 172435863739SMike Smith aac_close(dev_t dev, int flags, int fmt, struct proc *p) 172535863739SMike Smith { 172635863739SMike Smith struct aac_softc *sc = dev->si_drv1; 172735863739SMike Smith 172835863739SMike Smith debug_called(2); 172935863739SMike Smith 173035863739SMike Smith /* Mark this unit as no longer open */ 173135863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 173235863739SMike Smith 173335863739SMike Smith return 0; 173435863739SMike Smith } 173535863739SMike Smith 173635863739SMike Smith static int 173735863739SMike Smith aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 173835863739SMike Smith { 17390b94a66eSMike Smith union aac_statrequest *as = (union aac_statrequest *)arg; 174035863739SMike Smith struct aac_softc *sc = dev->si_drv1; 17410b94a66eSMike Smith int error = 0; 17420b94a66eSMike Smith #ifdef AAC_COMPAT_LINUX 17430b94a66eSMike Smith int i; 17440b94a66eSMike Smith #endif 174535863739SMike Smith 174635863739SMike Smith debug_called(2); 174735863739SMike Smith 174835863739SMike Smith switch (cmd) { 17490b94a66eSMike Smith case AACIO_STATS: 17500b94a66eSMike Smith switch (as->as_item) { 17510b94a66eSMike Smith case AACQ_FREE: 17520b94a66eSMike Smith case AACQ_BIO: 17530b94a66eSMike Smith case AACQ_READY: 17540b94a66eSMike Smith case AACQ_BUSY: 17550b94a66eSMike Smith case AACQ_COMPLETE: 1756c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 1757c6eafcf2SScott Long sizeof(struct aac_qstat)); 17580b94a66eSMike Smith break; 17590b94a66eSMike Smith default: 17600b94a66eSMike Smith error = ENOENT; 17610b94a66eSMike Smith break; 17620b94a66eSMike Smith } 17630b94a66eSMike Smith break; 17640b94a66eSMike Smith 176535863739SMike Smith #ifdef AAC_COMPAT_LINUX 176635863739SMike Smith case FSACTL_SENDFIB: 17670b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 176835863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 176935863739SMike Smith break; 177035863739SMike Smith case FSACTL_AIF_THREAD: 17710b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 177235863739SMike Smith error = EINVAL; 177335863739SMike Smith break; 177435863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 17750b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 177635863739SMike Smith /* 177735863739SMike Smith * Pass the caller out an AdapterFibContext. 177835863739SMike Smith * 177935863739SMike Smith * Note that because we only support one opener, we 178035863739SMike Smith * basically ignore this. Set the caller's context to a magic 178135863739SMike Smith * number just in case. 17820b94a66eSMike Smith * 17830b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 17840b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 178535863739SMike Smith */ 178635863739SMike Smith i = AAC_AIF_SILLYMAGIC; 178735863739SMike Smith error = copyout(&i, arg, sizeof(i)); 178835863739SMike Smith break; 178935863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 17900b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 179135863739SMike Smith error = aac_linux_getnext_aif(sc, arg); 179235863739SMike Smith break; 179335863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 17940b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 179535863739SMike Smith /* don't do anything here */ 179635863739SMike Smith break; 179735863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 17980b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 179935863739SMike Smith error = aac_linux_rev_check(sc, arg); 180035863739SMike Smith break; 180135863739SMike Smith #endif 180235863739SMike Smith default: 180335863739SMike Smith device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd); 180435863739SMike Smith error = EINVAL; 180535863739SMike Smith break; 180635863739SMike Smith } 180735863739SMike Smith return(error); 180835863739SMike Smith } 180935863739SMike Smith 1810c6eafcf2SScott Long /****************************************************************************** 181135863739SMike Smith * Send a FIB supplied from userspace 181235863739SMike Smith */ 181335863739SMike Smith static int 181435863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 181535863739SMike Smith { 181635863739SMike Smith struct aac_command *cm; 181735863739SMike Smith int size, error; 181835863739SMike Smith 181935863739SMike Smith debug_called(2); 182035863739SMike Smith 182135863739SMike Smith cm = NULL; 182235863739SMike Smith 182335863739SMike Smith /* 182435863739SMike Smith * Get a command 182535863739SMike Smith */ 182635863739SMike Smith if (aac_alloc_command(sc, &cm)) { 182735863739SMike Smith error = EBUSY; 182835863739SMike Smith goto out; 182935863739SMike Smith } 183035863739SMike Smith 183135863739SMike Smith /* 183235863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 183335863739SMike Smith */ 183435863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0) 183535863739SMike Smith goto out; 183635863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 183735863739SMike Smith if (size > sizeof(struct aac_fib)) { 1838c6eafcf2SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size, 1839c6eafcf2SScott Long sizeof(struct aac_fib)); 184035863739SMike Smith size = sizeof(struct aac_fib); 184135863739SMike Smith } 184235863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 184335863739SMike Smith goto out; 184435863739SMike Smith cm->cm_fib->Header.Size = size; 184535863739SMike Smith 184635863739SMike Smith /* 184735863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 184835863739SMike Smith */ 184935863739SMike Smith if ((error = aac_wait_command(cm, 30)) != 0) /* XXX user timeout? */ 185035863739SMike Smith goto out; 185135863739SMike Smith 185235863739SMike Smith /* 185335863739SMike Smith * Copy the FIB and data back out to the caller. 185435863739SMike Smith */ 185535863739SMike Smith size = cm->cm_fib->Header.Size; 185635863739SMike Smith if (size > sizeof(struct aac_fib)) { 1857c6eafcf2SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size, 1858c6eafcf2SScott Long sizeof(struct aac_fib)); 185935863739SMike Smith size = sizeof(struct aac_fib); 186035863739SMike Smith } 186135863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 186235863739SMike Smith 186335863739SMike Smith out: 186435863739SMike Smith if (cm != NULL) 186535863739SMike Smith aac_release_command(cm); 186635863739SMike Smith return(error); 186735863739SMike Smith } 186835863739SMike Smith 1869c6eafcf2SScott Long /****************************************************************************** 187035863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 187135863739SMike Smith * 187235863739SMike Smith * XXX what's the right thing to do here when the queue is full? Drop the older 187335863739SMike Smith * or newer entries? 187435863739SMike Smith */ 187535863739SMike Smith static void 187635863739SMike Smith aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif) 187735863739SMike Smith { 187835863739SMike Smith int next, s; 187935863739SMike Smith 188035863739SMike Smith debug_called(2); 188135863739SMike Smith 188235863739SMike Smith s = splbio(); 188335863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 188435863739SMike Smith if (next != sc->aac_aifq_tail) { 188535863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 188635863739SMike Smith sc->aac_aifq_head = next; 188735863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 188835863739SMike Smith wakeup(sc->aac_aifq); 188935863739SMike Smith } 189035863739SMike Smith splx(s); 189135863739SMike Smith aac_print_aif(sc, aif); 189235863739SMike Smith } 189335863739SMike Smith 1894c6eafcf2SScott Long /****************************************************************************** 1895c6eafcf2SScott Long ****************************************************************************** 189635863739SMike Smith Linux Management Interface 1897c6eafcf2SScott Long ****************************************************************************** 1898c6eafcf2SScott Long ******************************************************************************/ 189935863739SMike Smith 190035863739SMike Smith #ifdef AAC_COMPAT_LINUX 190135863739SMike Smith 190230d57611SMike Smith #include <sys/proc.h> 190335863739SMike Smith #include <machine/../linux/linux.h> 190435863739SMike Smith #include <machine/../linux/linux_proto.h> 190535863739SMike Smith #include <compat/linux/linux_ioctl.h> 190635863739SMike Smith 190735863739SMike Smith #define AAC_LINUX_IOCTL_MIN 0x2000 190835863739SMike Smith #define AAC_LINUX_IOCTL_MAX 0x21ff 190935863739SMike Smith 191035863739SMike Smith static linux_ioctl_function_t aac_linux_ioctl; 1911c6eafcf2SScott Long static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl, 1912c6eafcf2SScott Long AAC_LINUX_IOCTL_MIN, 1913c6eafcf2SScott Long AAC_LINUX_IOCTL_MAX}; 191435863739SMike Smith 1915c6eafcf2SScott Long SYSINIT (aac_register, SI_SUB_KLD, SI_ORDER_MIDDLE, 1916c6eafcf2SScott Long linux_ioctl_register_handler, &aac_handler); 1917c6eafcf2SScott Long SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, 1918c6eafcf2SScott Long linux_ioctl_unregister_handler, &aac_handler); 191935863739SMike Smith 192035863739SMike Smith MODULE_DEPEND(aac, linux, 1, 1, 1); 192135863739SMike Smith 192235863739SMike Smith static int 192335863739SMike Smith aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args) 192435863739SMike Smith { 192535863739SMike Smith struct file *fp = p->p_fd->fd_ofiles[args->fd]; 192635863739SMike Smith u_long cmd = args->cmd; 192735863739SMike Smith 192835863739SMike Smith /* 192935863739SMike Smith * Pass the ioctl off to our standard handler. 193035863739SMike Smith */ 193135863739SMike Smith return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p)); 193235863739SMike Smith } 193335863739SMike Smith 1934c6eafcf2SScott Long /****************************************************************************** 19350b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 193635863739SMike Smith * userspace app is possibly compatible. This is extremely bogus right now 193735863739SMike Smith * because I have no idea how to handle the versioning of this driver. It is 193835863739SMike Smith * needed, though, to get aaccli working. 193935863739SMike Smith */ 194035863739SMike Smith static int 194135863739SMike Smith aac_linux_rev_check(struct aac_softc *sc, caddr_t udata) 194235863739SMike Smith { 194335863739SMike Smith struct aac_rev_check rev_check; 194435863739SMike Smith struct aac_rev_check_resp rev_check_resp; 194535863739SMike Smith int error = 0; 194635863739SMike Smith 194735863739SMike Smith debug_called(2); 194835863739SMike Smith 194935863739SMike Smith /* 195035863739SMike Smith * Copyin the revision struct from userspace 195135863739SMike Smith */ 1952c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 1953c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 195435863739SMike Smith return error; 195535863739SMike Smith } 195635863739SMike Smith 195735863739SMike Smith debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber); 195835863739SMike Smith 195935863739SMike Smith /* 196035863739SMike Smith * Doctor up the response struct. 196135863739SMike Smith */ 196235863739SMike Smith rev_check_resp.possiblyCompatible = 1; 196335863739SMike Smith rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul; 196435863739SMike Smith rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber; 196535863739SMike Smith 1966c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 1967c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 196835863739SMike Smith } 196935863739SMike Smith 1970c6eafcf2SScott Long /****************************************************************************** 197135863739SMike Smith * Pass the caller the next AIF in their queue 197235863739SMike Smith */ 197335863739SMike Smith static int 197435863739SMike Smith aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg) 197535863739SMike Smith { 197635863739SMike Smith struct get_adapter_fib_ioctl agf; 197735863739SMike Smith int error, s; 197835863739SMike Smith 197935863739SMike Smith debug_called(2); 198035863739SMike Smith 198135863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 198235863739SMike Smith 198335863739SMike Smith /* 198435863739SMike Smith * Check the magic number that we gave the caller. 198535863739SMike Smith */ 198635863739SMike Smith if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) { 198735863739SMike Smith error = EFAULT; 198835863739SMike Smith } else { 198935863739SMike Smith 199035863739SMike Smith s = splbio(); 19910b94a66eSMike Smith error = aac_linux_return_aif(sc, agf.AifFib); 199235863739SMike Smith 199335863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 199435863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 199535863739SMike Smith while (error == EAGAIN) { 199635863739SMike Smith error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0); 199735863739SMike Smith if (error == 0) 19980b94a66eSMike Smith error = aac_linux_return_aif(sc, agf.AifFib); 199935863739SMike Smith } 200035863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 200135863739SMike Smith } 200235863739SMike Smith splx(s); 200335863739SMike Smith } 200435863739SMike Smith } 200535863739SMike Smith return(error); 200635863739SMike Smith } 200735863739SMike Smith 2008c6eafcf2SScott Long /****************************************************************************** 20090b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 20100b94a66eSMike Smith */ 20110b94a66eSMike Smith static int 20120b94a66eSMike Smith aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr) 20130b94a66eSMike Smith { 20140b94a66eSMike Smith int error, s; 20150b94a66eSMike Smith 20160b94a66eSMike Smith debug_called(2); 20170b94a66eSMike Smith 20180b94a66eSMike Smith s = splbio(); 20190b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 20200b94a66eSMike Smith error = EAGAIN; 20210b94a66eSMike Smith } else { 2022c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2023c6eafcf2SScott Long sizeof(struct aac_aif_command)); 20240b94a66eSMike Smith if (!error) 20250b94a66eSMike Smith sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 20260b94a66eSMike Smith } 20270b94a66eSMike Smith splx(s); 20280b94a66eSMike Smith return(error); 20290b94a66eSMike Smith } 20300b94a66eSMike Smith 20310b94a66eSMike Smith 203235863739SMike Smith #endif /* AAC_COMPAT_LINUX */ 2033