135863739SMike Smith /*- 235863739SMike Smith * Copyright (c) 2000 Michael Smith 335863739SMike Smith * Copyright (c) 2000 BSDi 435863739SMike Smith * All rights reserved. 535863739SMike Smith * 635863739SMike Smith * Redistribution and use in source and binary forms, with or without 735863739SMike Smith * modification, are permitted provided that the following conditions 835863739SMike Smith * are met: 935863739SMike Smith * 1. Redistributions of source code must retain the above copyright 1035863739SMike Smith * notice, this list of conditions and the following disclaimer. 1135863739SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1235863739SMike Smith * notice, this list of conditions and the following disclaimer in the 1335863739SMike Smith * documentation and/or other materials provided with the distribution. 1435863739SMike Smith * 1535863739SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1635863739SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1735863739SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1835863739SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1935863739SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2035863739SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2135863739SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2235863739SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2335863739SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2435863739SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2535863739SMike Smith * SUCH DAMAGE. 2635863739SMike Smith * 2735863739SMike Smith * $FreeBSD$ 2835863739SMike Smith */ 2935863739SMike Smith 3035863739SMike Smith /* 3135863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3235863739SMike Smith */ 3335863739SMike Smith 3435863739SMike Smith #include <sys/param.h> 3535863739SMike Smith #include <sys/systm.h> 3635863739SMike Smith #include <sys/malloc.h> 3735863739SMike Smith #include <sys/kernel.h> 3835863739SMike Smith 3935863739SMike Smith #include <dev/aac/aac_compat.h> 4035863739SMike Smith 4135863739SMike Smith #include <sys/bus.h> 4235863739SMike Smith #include <sys/conf.h> 4335863739SMike Smith #include <sys/devicestat.h> 4435863739SMike Smith #include <sys/disk.h> 4535863739SMike Smith #include <sys/file.h> 4635863739SMike Smith #include <sys/signalvar.h> 470b94a66eSMike Smith #include <sys/time.h> 4835863739SMike Smith 4935863739SMike Smith #include <machine/bus_memio.h> 5035863739SMike Smith #include <machine/bus.h> 5135863739SMike Smith #include <machine/resource.h> 5235863739SMike Smith 5335863739SMike Smith #include <dev/aac/aacreg.h> 540b94a66eSMike Smith #include <dev/aac/aac_ioctl.h> 5535863739SMike Smith #include <dev/aac/aacvar.h> 5635863739SMike Smith #include <dev/aac/aac_tables.h> 5735863739SMike Smith 5835863739SMike Smith devclass_t aac_devclass; 5935863739SMike Smith 6035863739SMike Smith static void aac_startup(void *arg); 6135863739SMike Smith 6235863739SMike Smith /* Command Processing */ 6335863739SMike Smith static void aac_startio(struct aac_softc *sc); 640b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 6535863739SMike Smith static int aac_start(struct aac_command *cm); 6635863739SMike Smith static void aac_complete(void *context, int pending); 6735863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 6835863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 6935863739SMike Smith static int aac_wait_command(struct aac_command *cm, int timeout); 7035863739SMike Smith static void aac_host_command(struct aac_softc *sc); 7135863739SMike Smith static void aac_host_response(struct aac_softc *sc); 7235863739SMike Smith 7335863739SMike Smith /* Command Buffer Management */ 7435863739SMike Smith static int aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp); 7535863739SMike Smith static void aac_release_command(struct aac_command *cm); 760b94a66eSMike Smith static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); 770b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 780b94a66eSMike Smith static void aac_free_commands(struct aac_softc *sc); 7935863739SMike Smith static void aac_map_command(struct aac_command *cm); 8035863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 8135863739SMike Smith 8235863739SMike Smith /* Hardware Interface */ 8335863739SMike Smith static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error); 8435863739SMike Smith static int aac_init(struct aac_softc *sc); 8535863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 8635863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 8735863739SMike Smith u_int32_t *sp); 8835863739SMike Smith static int aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 8935863739SMike Smith void *data, u_int16_t datasize, 9035863739SMike Smith void *result, u_int16_t *resultsize); 9135863739SMike Smith static int aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size, u_int32_t fib_addr); 9235863739SMike Smith static int aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, struct aac_fib **fib_addr); 9335863739SMike Smith 9435863739SMike Smith /* StrongARM interface */ 9535863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 9635863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 9735863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 9835863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 9935863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 10035863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3); 10135863739SMike Smith static int aac_sa_get_mailboxstatus(struct aac_softc *sc); 10235863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 10335863739SMike Smith 10435863739SMike Smith struct aac_interface aac_sa_interface = { 10535863739SMike Smith aac_sa_get_fwstatus, 10635863739SMike Smith aac_sa_qnotify, 10735863739SMike Smith aac_sa_get_istatus, 10835863739SMike Smith aac_sa_clear_istatus, 10935863739SMike Smith aac_sa_set_mailbox, 11035863739SMike Smith aac_sa_get_mailboxstatus, 11135863739SMike Smith aac_sa_set_interrupts 11235863739SMike Smith }; 11335863739SMike Smith 11435863739SMike Smith /* i960Rx interface */ 11535863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 11635863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 11735863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 11835863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 11935863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 12035863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3); 12135863739SMike Smith static int aac_rx_get_mailboxstatus(struct aac_softc *sc); 12235863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 12335863739SMike Smith 12435863739SMike Smith struct aac_interface aac_rx_interface = { 12535863739SMike Smith aac_rx_get_fwstatus, 12635863739SMike Smith aac_rx_qnotify, 12735863739SMike Smith aac_rx_get_istatus, 12835863739SMike Smith aac_rx_clear_istatus, 12935863739SMike Smith aac_rx_set_mailbox, 13035863739SMike Smith aac_rx_get_mailboxstatus, 13135863739SMike Smith aac_rx_set_interrupts 13235863739SMike Smith }; 13335863739SMike Smith 13435863739SMike Smith /* Debugging and Diagnostics */ 13535863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 13635863739SMike Smith static char *aac_describe_code(struct aac_code_lookup *table, u_int32_t code); 13735863739SMike Smith 13835863739SMike Smith /* Management Interface */ 13935863739SMike Smith static d_open_t aac_open; 14035863739SMike Smith static d_close_t aac_close; 14135863739SMike Smith static d_ioctl_t aac_ioctl; 14235863739SMike Smith static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 14335863739SMike Smith static void aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif); 14435863739SMike Smith #ifdef AAC_COMPAT_LINUX 14535863739SMike Smith static int aac_linux_rev_check(struct aac_softc *sc, caddr_t udata); 14635863739SMike Smith static int aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg); 1470b94a66eSMike Smith static int aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr); 14835863739SMike Smith #endif 14935863739SMike Smith 15035863739SMike Smith #define AAC_CDEV_MAJOR 150 15135863739SMike Smith 15235863739SMike Smith static struct cdevsw aac_cdevsw = { 15335863739SMike Smith aac_open, /* open */ 15435863739SMike Smith aac_close, /* close */ 15535863739SMike Smith noread, /* read */ 15635863739SMike Smith nowrite, /* write */ 15735863739SMike Smith aac_ioctl, /* ioctl */ 15835863739SMike Smith nopoll, /* poll */ 15935863739SMike Smith nommap, /* mmap */ 16035863739SMike Smith nostrategy, /* strategy */ 16135863739SMike Smith "aac", /* name */ 16235863739SMike Smith AAC_CDEV_MAJOR, /* major */ 16335863739SMike Smith nodump, /* dump */ 16435863739SMike Smith nopsize, /* psize */ 16535863739SMike Smith 0, /* flags */ 16635863739SMike Smith -1, /* bmaj */ 16735863739SMike Smith }; 16835863739SMike Smith 16935863739SMike Smith /******************************************************************************** 17035863739SMike Smith ******************************************************************************** 17135863739SMike Smith Device Interface 17235863739SMike Smith ******************************************************************************** 17335863739SMike Smith ********************************************************************************/ 17435863739SMike Smith 17535863739SMike Smith /******************************************************************************** 17635863739SMike Smith * Initialise the controller and softc 17735863739SMike Smith */ 17835863739SMike Smith int 17935863739SMike Smith aac_attach(struct aac_softc *sc) 18035863739SMike Smith { 18135863739SMike Smith int error, unit; 18235863739SMike Smith 18335863739SMike Smith debug_called(1); 18435863739SMike Smith 18535863739SMike Smith /* 18635863739SMike Smith * Initialise per-controller queues. 18735863739SMike Smith */ 1880b94a66eSMike Smith aac_initq_free(sc); 1890b94a66eSMike Smith aac_initq_ready(sc); 1900b94a66eSMike Smith aac_initq_busy(sc); 1910b94a66eSMike Smith aac_initq_complete(sc); 1920b94a66eSMike Smith aac_initq_bio(sc); 19335863739SMike Smith 19435863739SMike Smith #if __FreeBSD_version >= 500005 19535863739SMike Smith /* 19635863739SMike Smith * Initialise command-completion task. 19735863739SMike Smith */ 19835863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 19935863739SMike Smith #endif 20035863739SMike Smith 20135863739SMike Smith /* disable interrupts before we enable anything */ 20235863739SMike Smith AAC_MASK_INTERRUPTS(sc); 20335863739SMike Smith 20435863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 20535863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 20635863739SMike Smith 20735863739SMike Smith /* 2080b94a66eSMike Smith * Allocate command structures. 2090b94a66eSMike Smith */ 2100b94a66eSMike Smith if ((error = aac_alloc_commands(sc)) != 0) 2110b94a66eSMike Smith return(error); 2120b94a66eSMike Smith 2130b94a66eSMike Smith /* 21435863739SMike Smith * Initialise the adapter. 21535863739SMike Smith */ 2160b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 21735863739SMike Smith return(error); 21835863739SMike Smith 21935863739SMike Smith /* 22035863739SMike Smith * Print a little information about the controller. 22135863739SMike Smith */ 22235863739SMike Smith aac_describe_controller(sc); 22335863739SMike Smith 22435863739SMike Smith /* 22535863739SMike Smith * Register to probe our containers later. 22635863739SMike Smith */ 22735863739SMike Smith sc->aac_ich.ich_func = aac_startup; 22835863739SMike Smith sc->aac_ich.ich_arg = sc; 22935863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 23035863739SMike Smith device_printf(sc->aac_dev, "can't establish configuration hook\n"); 23135863739SMike Smith return(ENXIO); 23235863739SMike Smith } 23335863739SMike Smith 23435863739SMike Smith /* 23535863739SMike Smith * Make the control device. 23635863739SMike Smith */ 23735863739SMike Smith unit = device_get_unit(sc->aac_dev); 23835863739SMike Smith sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644, "aac%d", unit); 23935863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 24035863739SMike Smith 24135863739SMike Smith return(0); 24235863739SMike Smith } 24335863739SMike Smith 24435863739SMike Smith /******************************************************************************** 24535863739SMike Smith * Probe for containers, create disks. 24635863739SMike Smith */ 24735863739SMike Smith static void 24835863739SMike Smith aac_startup(void *arg) 24935863739SMike Smith { 25035863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 25135863739SMike Smith struct aac_mntinfo mi; 25235863739SMike Smith struct aac_mntinforesponse mir; 25335863739SMike Smith device_t child; 25435863739SMike Smith u_int16_t rsize; 25535863739SMike Smith int i; 25635863739SMike Smith 25735863739SMike Smith debug_called(1); 25835863739SMike Smith 25935863739SMike Smith /* disconnect ourselves from the intrhook chain */ 26035863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 26135863739SMike Smith 26235863739SMike Smith /* loop over possible containers */ 26335863739SMike Smith mi.Command = VM_NameServe; 26435863739SMike Smith mi.MntType = FT_FILESYS; 26535863739SMike Smith for (i = 0; i < AAC_MAX_CONTAINERS; i++) { 26635863739SMike Smith /* request information on this container */ 26735863739SMike Smith mi.MntCount = i; 26835863739SMike Smith if (aac_sync_fib(sc, ContainerCommand, 0, &mi, sizeof(struct aac_mntinfo), &mir, &rsize)) { 26935863739SMike Smith debug(2, "error probing container %d", i); 27035863739SMike Smith continue; 27135863739SMike Smith } 27235863739SMike Smith /* check response size */ 27335863739SMike Smith if (rsize != sizeof(mir)) { 274bb9f4664SScott Long debug(2, "container info response wrong size (%d should be %d)", rsize, sizeof(mir)); 27535863739SMike Smith continue; 27635863739SMike Smith } 27735863739SMike Smith /* 27835863739SMike Smith * Check container volume type for validity. Note that many of the possible types 27935863739SMike Smith * may never show up. 28035863739SMike Smith */ 28135863739SMike Smith if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) { 28235863739SMike Smith debug(1, "%d: id %x name '%.16s' size %u type %d", 28335863739SMike Smith i, mir.MntTable[0].ObjectId, 28435863739SMike Smith mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity, 28535863739SMike Smith mir.MntTable[0].VolType); 28635863739SMike Smith 28735863739SMike Smith if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) { 28835863739SMike Smith device_printf(sc->aac_dev, "device_add_child failed\n"); 28935863739SMike Smith } else { 29035863739SMike Smith device_set_ivars(child, &sc->aac_container[i]); 29135863739SMike Smith } 29235863739SMike Smith device_set_desc(child, aac_describe_code(aac_container_types, mir.MntTable[0].VolType)); 29335863739SMike Smith sc->aac_container[i].co_disk = child; 29435863739SMike Smith sc->aac_container[i].co_mntobj = mir.MntTable[0]; 29535863739SMike Smith } 29635863739SMike Smith } 29735863739SMike Smith 29835863739SMike Smith /* poke the bus to actually attach the child devices */ 29935863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 30035863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 30135863739SMike Smith 30235863739SMike Smith /* mark the controller up */ 30335863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 30435863739SMike Smith 30535863739SMike Smith /* enable interrupts now */ 30635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 3070b94a66eSMike Smith 3080b94a66eSMike Smith /* enable the timeout watchdog */ 3090b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 31035863739SMike Smith } 31135863739SMike Smith 31235863739SMike Smith /******************************************************************************** 31335863739SMike Smith * Free all of the resources associated with (sc) 31435863739SMike Smith * 31535863739SMike Smith * Should not be called if the controller is active. 31635863739SMike Smith */ 31735863739SMike Smith void 31835863739SMike Smith aac_free(struct aac_softc *sc) 31935863739SMike Smith { 32035863739SMike Smith debug_called(1); 32135863739SMike Smith 32235863739SMike Smith /* remove the control device */ 32335863739SMike Smith if (sc->aac_dev_t != NULL) 32435863739SMike Smith destroy_dev(sc->aac_dev_t); 32535863739SMike Smith 3260b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 3270b94a66eSMike Smith if (sc->aac_fibs != NULL) 3280b94a66eSMike Smith aac_free_commands(sc); 3290b94a66eSMike Smith if (sc->aac_fib_dmat) 3300b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 33135863739SMike Smith 33235863739SMike Smith /* destroy the common area */ 33335863739SMike Smith if (sc->aac_common) { 33435863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 33535863739SMike Smith bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, sc->aac_common_dmamap); 33635863739SMike Smith } 3370b94a66eSMike Smith if (sc->aac_common_dmat) 3380b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 33935863739SMike Smith 34035863739SMike Smith /* disconnect the interrupt handler */ 34135863739SMike Smith if (sc->aac_intr) 34235863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 34335863739SMike Smith if (sc->aac_irq != NULL) 34435863739SMike Smith bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, sc->aac_irq); 34535863739SMike Smith 34635863739SMike Smith /* destroy data-transfer DMA tag */ 34735863739SMike Smith if (sc->aac_buffer_dmat) 34835863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 34935863739SMike Smith 35035863739SMike Smith /* destroy the parent DMA tag */ 35135863739SMike Smith if (sc->aac_parent_dmat) 35235863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 35335863739SMike Smith 35435863739SMike Smith /* release the register window mapping */ 35535863739SMike Smith if (sc->aac_regs_resource != NULL) 35635863739SMike Smith bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid, sc->aac_regs_resource); 35735863739SMike Smith } 35835863739SMike Smith 35935863739SMike Smith /******************************************************************************** 36035863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 36135863739SMike Smith */ 36235863739SMike Smith int 36335863739SMike Smith aac_detach(device_t dev) 36435863739SMike Smith { 36535863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 36635863739SMike Smith int error; 36735863739SMike Smith 36835863739SMike Smith debug_called(1); 36935863739SMike Smith 37035863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 37135863739SMike Smith return(EBUSY); 37235863739SMike Smith 37335863739SMike Smith if ((error = aac_shutdown(dev))) 37435863739SMike Smith return(error); 37535863739SMike Smith 37635863739SMike Smith aac_free(sc); 37735863739SMike Smith 37835863739SMike Smith return(0); 37935863739SMike Smith } 38035863739SMike Smith 38135863739SMike Smith /******************************************************************************** 38235863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 38335863739SMike Smith * 38435863739SMike Smith * This function is called before detach or system shutdown. 38535863739SMike Smith * 3860b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 38735863739SMike Smith * allow shutdown if any device is open. 38835863739SMike Smith */ 38935863739SMike Smith int 39035863739SMike Smith aac_shutdown(device_t dev) 39135863739SMike Smith { 39235863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 39335863739SMike Smith struct aac_close_command cc; 39435863739SMike Smith int s, i; 39535863739SMike Smith 39635863739SMike Smith debug_called(1); 39735863739SMike Smith 39835863739SMike Smith s = splbio(); 39935863739SMike Smith 40035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 40135863739SMike Smith 40235863739SMike Smith /* 40335863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 40435863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 40535863739SMike Smith * We've been closed and all I/O completed already 40635863739SMike Smith */ 40735863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 40835863739SMike Smith 40935863739SMike Smith cc.Command = VM_CloseAll; 41035863739SMike Smith cc.ContainerId = 0xffffffff; 41135863739SMike Smith if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) { 41235863739SMike Smith printf("FAILED.\n"); 41335863739SMike Smith } else { 41435863739SMike Smith i = 0; 41535863739SMike Smith if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i, sizeof(i), NULL, NULL)) { 41635863739SMike Smith printf("FAILED.\n"); 41735863739SMike Smith } else { 41835863739SMike Smith printf("done.\n"); 41935863739SMike Smith } 42035863739SMike Smith } 42135863739SMike Smith 42235863739SMike Smith AAC_MASK_INTERRUPTS(sc); 42335863739SMike Smith 42435863739SMike Smith splx(s); 42535863739SMike Smith return(0); 42635863739SMike Smith } 42735863739SMike Smith 42835863739SMike Smith /******************************************************************************** 42935863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 43035863739SMike Smith */ 43135863739SMike Smith int 43235863739SMike Smith aac_suspend(device_t dev) 43335863739SMike Smith { 43435863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 43535863739SMike Smith int s; 43635863739SMike Smith 43735863739SMike Smith debug_called(1); 43835863739SMike Smith s = splbio(); 43935863739SMike Smith 44035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 44135863739SMike Smith 44235863739SMike Smith AAC_MASK_INTERRUPTS(sc); 44335863739SMike Smith splx(s); 44435863739SMike Smith return(0); 44535863739SMike Smith } 44635863739SMike Smith 44735863739SMike Smith /******************************************************************************** 44835863739SMike Smith * Bring the controller back to a state ready for operation. 44935863739SMike Smith */ 45035863739SMike Smith int 45135863739SMike Smith aac_resume(device_t dev) 45235863739SMike Smith { 45335863739SMike Smith struct aac_softc *sc = device_get_softc(dev); 45435863739SMike Smith 45535863739SMike Smith debug_called(1); 45635863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 45735863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 45835863739SMike Smith return(0); 45935863739SMike Smith } 46035863739SMike Smith 46135863739SMike Smith /******************************************************************************* 46235863739SMike Smith * Take an interrupt. 46335863739SMike Smith */ 46435863739SMike Smith void 46535863739SMike Smith aac_intr(void *arg) 46635863739SMike Smith { 46735863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 46835863739SMike Smith u_int16_t reason; 46935863739SMike Smith 47035863739SMike Smith debug_called(2); 47135863739SMike Smith 47235863739SMike Smith reason = AAC_GET_ISTATUS(sc); 47335863739SMike Smith 47435863739SMike Smith /* controller wants to talk to the log? XXX should we defer this? */ 47535863739SMike Smith if (reason & AAC_DB_PRINTF) { 47635863739SMike Smith if (sc->aac_common->ac_printf[0]) { 47735863739SMike Smith device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE, sc->aac_common->ac_printf); 47835863739SMike Smith sc->aac_common->ac_printf[0] = 0; 47935863739SMike Smith } 48035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF); 48135863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_PRINTF); 48235863739SMike Smith } 48335863739SMike Smith 48435863739SMike Smith /* controller has a message for us? */ 48535863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 48635863739SMike Smith aac_host_command(sc); 48735863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY); 48835863739SMike Smith } 48935863739SMike Smith 49035863739SMike Smith /* controller has a response for us? */ 49135863739SMike Smith if (reason & AAC_DB_RESPONSE_READY) { 49235863739SMike Smith aac_host_response(sc); 49335863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 49435863739SMike Smith } 49535863739SMike Smith 49635863739SMike Smith /* spurious interrupts that we don't use - reset the mask and clear the interrupts */ 49735863739SMike Smith if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) { 49835863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 49935863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL); 50035863739SMike Smith } 50135863739SMike Smith }; 50235863739SMike Smith 50335863739SMike Smith /******************************************************************************** 50435863739SMike Smith ******************************************************************************** 50535863739SMike Smith Command Processing 50635863739SMike Smith ******************************************************************************** 50735863739SMike Smith ********************************************************************************/ 50835863739SMike Smith 50935863739SMike Smith /******************************************************************************** 51035863739SMike Smith * Start as much queued I/O as possible on the controller 51135863739SMike Smith */ 51235863739SMike Smith static void 51335863739SMike Smith aac_startio(struct aac_softc *sc) 51435863739SMike Smith { 51535863739SMike Smith struct aac_command *cm; 51635863739SMike Smith 51735863739SMike Smith debug_called(2); 51835863739SMike Smith 51935863739SMike Smith for(;;) { 52035863739SMike Smith /* try to get a command that's been put off for lack of resources */ 52135863739SMike Smith cm = aac_dequeue_ready(sc); 52235863739SMike Smith 52335863739SMike Smith /* try to build a command off the bio queue (ignore error return) */ 5240b94a66eSMike Smith if (cm == NULL) 52535863739SMike Smith aac_bio_command(sc, &cm); 52635863739SMike Smith 52735863739SMike Smith /* nothing to do? */ 52835863739SMike Smith if (cm == NULL) 52935863739SMike Smith break; 53035863739SMike Smith 53135863739SMike Smith /* try to give the command to the controller */ 53235863739SMike Smith if (aac_start(cm) == EBUSY) { 53335863739SMike Smith /* put it on the ready queue for later */ 53435863739SMike Smith aac_requeue_ready(cm); 53535863739SMike Smith break; 53635863739SMike Smith } 53735863739SMike Smith } 53835863739SMike Smith } 53935863739SMike Smith 54035863739SMike Smith /******************************************************************************** 54135863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 54235863739SMike Smith * last moment when possible. 54335863739SMike Smith */ 54435863739SMike Smith static int 54535863739SMike Smith aac_start(struct aac_command *cm) 54635863739SMike Smith { 54735863739SMike Smith struct aac_softc *sc = cm->cm_sc; 5480b94a66eSMike Smith int s, error; 54935863739SMike Smith 55035863739SMike Smith debug_called(2); 55135863739SMike Smith 55235863739SMike Smith /* get the command mapped */ 55335863739SMike Smith aac_map_command(cm); 55435863739SMike Smith 5550b94a66eSMike Smith /* fix up the address values in the FIB */ 55635863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 55735863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 55835863739SMike Smith 55935863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 5600b94a66eSMike Smith cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical address issue */ 56135863739SMike Smith 56235863739SMike Smith /* put the FIB on the outbound queue */ 5630b94a66eSMike Smith s = splbio(); 56435863739SMike Smith if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm->cm_fib->Header.Size, 5650b94a66eSMike Smith cm->cm_fib->Header.ReceiverFibAddress)) { 5660b94a66eSMike Smith error = EBUSY; 5670b94a66eSMike Smith } else { 5680b94a66eSMike Smith aac_enqueue_busy(cm); 5690b94a66eSMike Smith error = 0; 5700b94a66eSMike Smith } 5710b94a66eSMike Smith return(error); 57235863739SMike Smith } 57335863739SMike Smith 57435863739SMike Smith /******************************************************************************** 57535863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 57635863739SMike Smith */ 57735863739SMike Smith static void 57835863739SMike Smith aac_host_command(struct aac_softc *sc) 57935863739SMike Smith { 58035863739SMike Smith struct aac_fib *fib; 58135863739SMike Smith u_int32_t fib_size; 58235863739SMike Smith 58335863739SMike Smith debug_called(1); 58435863739SMike Smith 58535863739SMike Smith for (;;) { 58635863739SMike Smith if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib)) 58735863739SMike Smith break; /* nothing to do */ 58835863739SMike Smith 58935863739SMike Smith switch(fib->Header.Command) { 59035863739SMike Smith case AifRequest: 59135863739SMike Smith aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]); 59235863739SMike Smith break; 59335863739SMike Smith default: 59435863739SMike Smith device_printf(sc->aac_dev, "unknown command from controller\n"); 59535863739SMike Smith AAC_PRINT_FIB(sc, fib); 59635863739SMike Smith break; 59735863739SMike Smith } 59835863739SMike Smith 59935863739SMike Smith /* XXX reply to FIBs requesting responses ?? */ 60035863739SMike Smith /* XXX how do we return these FIBs to the controller? */ 60135863739SMike Smith } 60235863739SMike Smith } 60335863739SMike Smith 60435863739SMike Smith /******************************************************************************** 60535863739SMike Smith * Handle notification of one or more FIBs completed by the controller 60635863739SMike Smith */ 60735863739SMike Smith static void 60835863739SMike Smith aac_host_response(struct aac_softc *sc) 60935863739SMike Smith { 61035863739SMike Smith struct aac_command *cm; 61135863739SMike Smith struct aac_fib *fib; 61235863739SMike Smith u_int32_t fib_size; 61335863739SMike Smith 61435863739SMike Smith debug_called(2); 61535863739SMike Smith 61635863739SMike Smith for (;;) { 61735863739SMike Smith /* look for completed FIBs on our queue */ 61835863739SMike Smith if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib)) 61935863739SMike Smith break; /* nothing to do */ 62035863739SMike Smith 62135863739SMike Smith /* get the command, unmap and queue for later processing */ 62235863739SMike Smith cm = (struct aac_command *)fib->Header.SenderData; 62335863739SMike Smith if (cm == NULL) { 62435863739SMike Smith AAC_PRINT_FIB(sc, fib); 62535863739SMike Smith } else { 6260b94a66eSMike Smith aac_remove_busy(cm); 62735863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 6280b94a66eSMike Smith aac_enqueue_complete(cm); 62935863739SMike Smith } 63035863739SMike Smith } 63135863739SMike Smith 63235863739SMike Smith /* handle completion processing */ 63335863739SMike Smith #if __FreeBSD_version >= 500005 63435863739SMike Smith taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 63535863739SMike Smith #else 63635863739SMike Smith aac_complete(sc, 0); 63735863739SMike Smith #endif 63835863739SMike Smith } 63935863739SMike Smith 64035863739SMike Smith /******************************************************************************** 64135863739SMike Smith * Process completed commands. 64235863739SMike Smith */ 64335863739SMike Smith static void 64435863739SMike Smith aac_complete(void *context, int pending) 64535863739SMike Smith { 64635863739SMike Smith struct aac_softc *sc = (struct aac_softc *)context; 64735863739SMike Smith struct aac_command *cm; 64835863739SMike Smith 64935863739SMike Smith debug_called(2); 65035863739SMike Smith 65135863739SMike Smith /* pull completed commands off the queue */ 65235863739SMike Smith for (;;) { 6530b94a66eSMike Smith cm = aac_dequeue_complete(sc); 65435863739SMike Smith if (cm == NULL) 6550b94a66eSMike Smith break; 65635863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 65735863739SMike Smith 65835863739SMike Smith /* is there a completion handler? */ 65935863739SMike Smith if (cm->cm_complete != NULL) { 66035863739SMike Smith cm->cm_complete(cm); 66135863739SMike Smith } else { 66235863739SMike Smith /* assume that someone is sleeping on this command */ 66335863739SMike Smith wakeup(cm); 66435863739SMike Smith } 66535863739SMike Smith } 6660b94a66eSMike Smith 6670b94a66eSMike Smith /* see if we can start some more I/O */ 6680b94a66eSMike Smith aac_startio(sc); 66935863739SMike Smith } 67035863739SMike Smith 67135863739SMike Smith /******************************************************************************** 67235863739SMike Smith * Handle a bio submitted from a disk device. 67335863739SMike Smith */ 67435863739SMike Smith void 67535863739SMike Smith aac_submit_bio(struct bio *bp) 67635863739SMike Smith { 67735863739SMike Smith struct aac_disk *ad = (struct aac_disk *)bp->bio_dev->si_drv1; 67835863739SMike Smith struct aac_softc *sc = ad->ad_controller; 67935863739SMike Smith 68035863739SMike Smith debug_called(2); 68135863739SMike Smith 68235863739SMike Smith /* queue the BIO and try to get some work done */ 6830b94a66eSMike Smith aac_enqueue_bio(sc, bp); 68435863739SMike Smith aac_startio(sc); 68535863739SMike Smith } 68635863739SMike Smith 68735863739SMike Smith /******************************************************************************** 68835863739SMike Smith * Get a bio and build a command to go with it. 68935863739SMike Smith */ 69035863739SMike Smith static int 69135863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 69235863739SMike Smith { 69335863739SMike Smith struct aac_command *cm; 69435863739SMike Smith struct aac_fib *fib; 69535863739SMike Smith struct aac_blockread *br; 69635863739SMike Smith struct aac_blockwrite *bw; 69735863739SMike Smith struct aac_disk *ad; 69835863739SMike Smith struct bio *bp; 69935863739SMike Smith 70035863739SMike Smith debug_called(2); 70135863739SMike Smith 70235863739SMike Smith /* get the resources we will need */ 70335863739SMike Smith cm = NULL; 7040b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 70535863739SMike Smith goto fail; 70635863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 70735863739SMike Smith goto fail; 70835863739SMike Smith 70935863739SMike Smith /* fill out the command */ 7100b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 7110b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 7120b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 71335863739SMike Smith cm->cm_private = bp; 7140b94a66eSMike Smith cm->cm_timestamp = time_second; 71535863739SMike Smith 71635863739SMike Smith /* build the FIB */ 71735863739SMike Smith fib = cm->cm_fib; 71835863739SMike Smith fib->Header.XferState = 71935863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 72035863739SMike Smith AAC_FIBSTATE_INITIALISED | 72135863739SMike Smith AAC_FIBSTATE_FROMHOST | 72235863739SMike Smith AAC_FIBSTATE_REXPECTED | 72335863739SMike Smith AAC_FIBSTATE_NORM; 72435863739SMike Smith fib->Header.Command = ContainerCommand; 72535863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 72635863739SMike Smith 72735863739SMike Smith /* build the read/write request */ 72835863739SMike Smith ad = (struct aac_disk *)bp->bio_dev->si_drv1; 72935863739SMike Smith if (BIO_IS_READ(bp)) { 73035863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 73135863739SMike Smith br->Command = VM_CtBlockRead; 73235863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 73335863739SMike Smith br->BlockNumber = bp->bio_pblkno; 73435863739SMike Smith br->ByteCount = bp->bio_bcount; 73535863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 73635863739SMike Smith cm->cm_sgtable = &br->SgMap; 73735863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 73835863739SMike Smith } else { 73935863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 74035863739SMike Smith bw->Command = VM_CtBlockWrite; 74135863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 74235863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 74335863739SMike Smith bw->ByteCount = bp->bio_bcount; 74435863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 74535863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 74635863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 74735863739SMike Smith cm->cm_sgtable = &bw->SgMap; 74835863739SMike Smith } 74935863739SMike Smith 75035863739SMike Smith *cmp = cm; 75135863739SMike Smith return(0); 75235863739SMike Smith 75335863739SMike Smith fail: 75435863739SMike Smith if (bp != NULL) 7550b94a66eSMike Smith aac_enqueue_bio(sc, bp); 75635863739SMike Smith if (cm != NULL) 75735863739SMike Smith aac_release_command(cm); 75835863739SMike Smith return(ENOMEM); 75935863739SMike Smith } 76035863739SMike Smith 76135863739SMike Smith /******************************************************************************** 76235863739SMike Smith * Handle a bio-instigated command that has been completed. 76335863739SMike Smith */ 76435863739SMike Smith static void 76535863739SMike Smith aac_bio_complete(struct aac_command *cm) 76635863739SMike Smith { 76735863739SMike Smith struct aac_blockread_response *brr; 76835863739SMike Smith struct aac_blockwrite_response *bwr; 76935863739SMike Smith struct bio *bp; 77035863739SMike Smith AAC_FSAStatus status; 77135863739SMike Smith 77235863739SMike Smith /* fetch relevant status and then release the command */ 77335863739SMike Smith bp = (struct bio *)cm->cm_private; 77435863739SMike Smith if (BIO_IS_READ(bp)) { 77535863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 77635863739SMike Smith status = brr->Status; 77735863739SMike Smith } else { 77835863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 77935863739SMike Smith status = bwr->Status; 78035863739SMike Smith } 78135863739SMike Smith aac_release_command(cm); 78235863739SMike Smith 78335863739SMike Smith /* fix up the bio based on status */ 78435863739SMike Smith if (status == ST_OK) { 78535863739SMike Smith bp->bio_resid = 0; 78635863739SMike Smith } else { 78735863739SMike Smith bp->bio_error = EIO; 78835863739SMike Smith bp->bio_flags |= BIO_ERROR; 7890b94a66eSMike Smith /* pass an error string out to the disk layer */ 7900b94a66eSMike Smith bp->bio_driver1 = aac_describe_code(aac_command_status_table, status); 79135863739SMike Smith } 7920b94a66eSMike Smith aac_biodone(bp); 79335863739SMike Smith } 79435863739SMike Smith 79535863739SMike Smith /******************************************************************************** 79635863739SMike Smith * Submit a command to the controller, return when it completes. 79735863739SMike Smith */ 79835863739SMike Smith static int 79935863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 80035863739SMike Smith { 80135863739SMike Smith int s, error = 0; 80235863739SMike Smith 80335863739SMike Smith debug_called(2); 80435863739SMike Smith 80535863739SMike Smith /* Put the command on the ready queue and get things going */ 80635863739SMike Smith aac_enqueue_ready(cm); 80735863739SMike Smith aac_startio(cm->cm_sc); 80835863739SMike Smith s = splbio(); 80935863739SMike Smith while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 81035863739SMike Smith error = tsleep(cm, PRIBIO, "aacwait", timeout * hz); 81135863739SMike Smith } 81235863739SMike Smith splx(s); 81335863739SMike Smith return(error); 81435863739SMike Smith } 81535863739SMike Smith 81635863739SMike Smith /******************************************************************************** 81735863739SMike Smith ******************************************************************************** 81835863739SMike Smith Command Buffer Management 81935863739SMike Smith ******************************************************************************** 82035863739SMike Smith ********************************************************************************/ 82135863739SMike Smith 82235863739SMike Smith /******************************************************************************** 82335863739SMike Smith * Allocate a command. 82435863739SMike Smith */ 82535863739SMike Smith static int 82635863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 82735863739SMike Smith { 82835863739SMike Smith struct aac_command *cm; 82935863739SMike Smith 83035863739SMike Smith debug_called(3); 83135863739SMike Smith 8320b94a66eSMike Smith if ((cm = aac_dequeue_free(sc)) == NULL) 83335863739SMike Smith return(ENOMEM); 83435863739SMike Smith 8350b94a66eSMike Smith *cmp = cm; 8360b94a66eSMike Smith return(0); 8370b94a66eSMike Smith } 8380b94a66eSMike Smith 8390b94a66eSMike Smith /******************************************************************************** 8400b94a66eSMike Smith * Release a command back to the freelist. 8410b94a66eSMike Smith */ 8420b94a66eSMike Smith static void 8430b94a66eSMike Smith aac_release_command(struct aac_command *cm) 8440b94a66eSMike Smith { 8450b94a66eSMike Smith debug_called(3); 8460b94a66eSMike Smith 8470b94a66eSMike Smith /* (re)initialise the command/FIB */ 84835863739SMike Smith cm->cm_sgtable = NULL; 84935863739SMike Smith cm->cm_flags = 0; 85035863739SMike Smith cm->cm_complete = NULL; 85135863739SMike Smith cm->cm_private = NULL; 85235863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 85335863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 85435863739SMike Smith cm->cm_fib->Header.Flags = 0; 85535863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 85635863739SMike Smith 85735863739SMike Smith /* 85835863739SMike Smith * These are duplicated in aac_start to cover the case where an 85935863739SMike Smith * intermediate stage may have destroyed them. They're left 86035863739SMike Smith * initialised here for debugging purposes only. 86135863739SMike Smith */ 86235863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 86335863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 86435863739SMike Smith 86535863739SMike Smith aac_enqueue_free(cm); 86635863739SMike Smith } 86735863739SMike Smith 86835863739SMike Smith /******************************************************************************** 8690b94a66eSMike Smith * Map helper for command/FIB allocation. 87035863739SMike Smith */ 87135863739SMike Smith static void 8720b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 87335863739SMike Smith { 8740b94a66eSMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 87535863739SMike Smith 87635863739SMike Smith debug_called(3); 87735863739SMike Smith 8780b94a66eSMike Smith sc->aac_fibphys = segs[0].ds_addr; 87935863739SMike Smith } 88035863739SMike Smith 88135863739SMike Smith /******************************************************************************** 8820b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 88335863739SMike Smith */ 8840b94a66eSMike Smith static int 8850b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 88635863739SMike Smith { 88735863739SMike Smith struct aac_command *cm; 88835863739SMike Smith int i; 88935863739SMike Smith 89035863739SMike Smith debug_called(1); 89135863739SMike Smith 8920b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 8930b94a66eSMike Smith if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, BUS_DMA_NOWAIT, &sc->aac_fibmap)) { 8940b94a66eSMike Smith return(ENOMEM); 89535863739SMike Smith } 8960b94a66eSMike Smith bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 8970b94a66eSMike Smith AAC_FIB_COUNT * sizeof(struct aac_fib), aac_map_command_helper, sc, 0); 89835863739SMike Smith 8990b94a66eSMike Smith /* initialise constant fields in the command structure */ 9000b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 9010b94a66eSMike Smith cm = &sc->aac_command[i]; 90235863739SMike Smith cm->cm_sc = sc; 9030b94a66eSMike Smith cm->cm_fib = sc->aac_fibs + i; 9040b94a66eSMike Smith cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); 90535863739SMike Smith 90635863739SMike Smith if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) 90735863739SMike Smith aac_release_command(cm); 90835863739SMike Smith } 9090b94a66eSMike Smith return(0); 91035863739SMike Smith } 91135863739SMike Smith 91235863739SMike Smith /******************************************************************************** 9130b94a66eSMike Smith * Free FIBs owned by this adapter. 91435863739SMike Smith */ 91535863739SMike Smith static void 9160b94a66eSMike Smith aac_free_commands(struct aac_softc *sc) 91735863739SMike Smith { 91835863739SMike Smith int i; 91935863739SMike Smith 92035863739SMike Smith debug_called(1); 92135863739SMike Smith 9220b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) 9230b94a66eSMike Smith bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap); 9240b94a66eSMike Smith bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); 9250b94a66eSMike Smith bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); 92635863739SMike Smith } 92735863739SMike Smith 92835863739SMike Smith /******************************************************************************** 92935863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 93035863739SMike Smith */ 93135863739SMike Smith static void 93235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 93335863739SMike Smith { 93435863739SMike Smith struct aac_command *cm = (struct aac_command *)arg; 93535863739SMike Smith struct aac_fib *fib = cm->cm_fib; 93635863739SMike Smith struct aac_sg_table *sg; 93735863739SMike Smith int i; 93835863739SMike Smith 93935863739SMike Smith debug_called(3); 94035863739SMike Smith 94135863739SMike Smith /* find the s/g table */ 94235863739SMike Smith sg = cm->cm_sgtable; 94335863739SMike Smith 94435863739SMike Smith /* copy into the FIB */ 94535863739SMike Smith if (sg != NULL) { 94635863739SMike Smith sg->SgCount = nseg; 94735863739SMike Smith for (i = 0; i < nseg; i++) { 94835863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 94935863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 95035863739SMike Smith } 95135863739SMike Smith /* update the FIB size for the s/g count */ 95235863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 95335863739SMike Smith } 95435863739SMike Smith 95535863739SMike Smith } 95635863739SMike Smith 95735863739SMike Smith /******************************************************************************** 95835863739SMike Smith * Map a command into controller-visible space. 95935863739SMike Smith */ 96035863739SMike Smith static void 96135863739SMike Smith aac_map_command(struct aac_command *cm) 96235863739SMike Smith { 96335863739SMike Smith struct aac_softc *sc = cm->cm_sc; 96435863739SMike Smith 96535863739SMike Smith debug_called(2); 96635863739SMike Smith 96735863739SMike Smith /* don't map more than once */ 96835863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 96935863739SMike Smith return; 97035863739SMike Smith 97135863739SMike Smith if (cm->cm_datalen != 0) { 97235863739SMike Smith bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data, 97335863739SMike Smith cm->cm_datalen, aac_map_command_sg, cm, 0); 97435863739SMike Smith 97535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 97635863739SMike Smith bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_PREREAD); 97735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 97835863739SMike Smith bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_PREWRITE); 97935863739SMike Smith } 98035863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 98135863739SMike Smith } 98235863739SMike Smith 98335863739SMike Smith /******************************************************************************** 98435863739SMike Smith * Unmap a command from controller-visible space. 98535863739SMike Smith */ 98635863739SMike Smith static void 98735863739SMike Smith aac_unmap_command(struct aac_command *cm) 98835863739SMike Smith { 98935863739SMike Smith struct aac_softc *sc = cm->cm_sc; 99035863739SMike Smith 99135863739SMike Smith debug_called(2); 99235863739SMike Smith 99335863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 99435863739SMike Smith return; 99535863739SMike Smith 99635863739SMike Smith if (cm->cm_datalen != 0) { 99735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 99835863739SMike Smith bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_POSTREAD); 99935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 100035863739SMike Smith bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_POSTWRITE); 100135863739SMike Smith 100235863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 100335863739SMike Smith } 100435863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 100535863739SMike Smith } 100635863739SMike Smith 100735863739SMike Smith /******************************************************************************** 100835863739SMike Smith ******************************************************************************** 100935863739SMike Smith Hardware Interface 101035863739SMike Smith ******************************************************************************** 101135863739SMike Smith ********************************************************************************/ 101235863739SMike Smith 101335863739SMike Smith /******************************************************************************** 101435863739SMike Smith * Initialise the adapter. 101535863739SMike Smith */ 101635863739SMike Smith static void 101735863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 101835863739SMike Smith { 101935863739SMike Smith struct aac_softc *sc = (struct aac_softc *)arg; 102035863739SMike Smith 102135863739SMike Smith debug_called(1); 102235863739SMike Smith 102335863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 102435863739SMike Smith } 102535863739SMike Smith 102635863739SMike Smith static int 102735863739SMike Smith aac_init(struct aac_softc *sc) 102835863739SMike Smith { 102935863739SMike Smith struct aac_adapter_init *ip; 103035863739SMike Smith time_t then; 103135863739SMike Smith u_int32_t code; 103235863739SMike Smith u_int8_t *qaddr; 103335863739SMike Smith 103435863739SMike Smith debug_called(1); 103535863739SMike Smith 103635863739SMike Smith /* 103735863739SMike Smith * First wait for the adapter to come ready. 103835863739SMike Smith */ 103935863739SMike Smith then = time_second; 104035863739SMike Smith do { 104135863739SMike Smith code = AAC_GET_FWSTATUS(sc); 104235863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 104335863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 104435863739SMike Smith return(ENXIO); 104535863739SMike Smith } 104635863739SMike Smith if (code & AAC_KERNEL_PANIC) { 104735863739SMike Smith device_printf(sc->aac_dev, "FATAL: controller kernel panic\n"); 104835863739SMike Smith return(ENXIO); 104935863739SMike Smith } 105035863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 105135863739SMike Smith device_printf(sc->aac_dev, "FATAL: controller not coming ready, status %x\n", code); 105235863739SMike Smith return(ENXIO); 105335863739SMike Smith } 105435863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 105535863739SMike Smith 105635863739SMike Smith /* 105735863739SMike Smith * Create DMA tag for the common structure and allocate it. 105835863739SMike Smith */ 105935863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 106035863739SMike Smith 1, 0, /* alignment, boundary */ 106135863739SMike Smith BUS_SPACE_MAXADDR, /* lowaddr */ 106235863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 106335863739SMike Smith NULL, NULL, /* filter, filterarg */ 106435863739SMike Smith sizeof(struct aac_common), 1,/* maxsize, nsegments */ 106535863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 106635863739SMike Smith 0, /* flags */ 106735863739SMike Smith &sc->aac_common_dmat)) { 106835863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n"); 106935863739SMike Smith return(ENOMEM); 107035863739SMike Smith } 107135863739SMike Smith if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 107235863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 107335863739SMike Smith return(ENOMEM); 107435863739SMike Smith } 107535863739SMike Smith bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common, sizeof(*sc->aac_common), 107635863739SMike Smith aac_common_map, sc, 0); 107735863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 107835863739SMike Smith 107935863739SMike Smith /* 108035863739SMike Smith * Fill in the init structure. This tells the adapter about the physical location 108135863739SMike Smith * of various important shared data structures. 108235863739SMike Smith */ 108335863739SMike Smith ip = &sc->aac_common->ac_init; 108435863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 108535863739SMike Smith 108646aa3347SPoul-Henning Kamp ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_fibs); 108735863739SMike Smith ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0]; 108835863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 108935863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 109035863739SMike Smith 109146aa3347SPoul-Henning Kamp ip->PrintfBufferAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_printf); 109235863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 109335863739SMike Smith 109435863739SMike Smith ip->HostPhysMemPages = 0; /* not used? */ 109535863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 109635863739SMike Smith 109735863739SMike Smith /* 109835863739SMike Smith * Initialise FIB queues. Note that it appears that the layout of the indexes 10990b94a66eSMike Smith * and the segmentation of the entries may be mandated by the adapter, which is 110035863739SMike Smith * only told about the base of the queue index fields. 110135863739SMike Smith * 110235863739SMike Smith * The initial values of the indices are assumed to inform the adapter 11030b94a66eSMike Smith * of the sizes of the respective queues, and theoretically it could work out 11040b94a66eSMike Smith * the entire layout of the queue structures from this. We take the easy 11050b94a66eSMike Smith * route and just lay this area out like everyone else does. 110635863739SMike Smith * 110735863739SMike Smith * The Linux driver uses a much more complex scheme whereby several header 110835863739SMike Smith * records are kept for each queue. We use a couple of generic list manipulation 110935863739SMike Smith * functions which 'know' the size of each list by virtue of a table. 111035863739SMike Smith */ 111135863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 111235863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 111335863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 111435863739SMike Smith ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues - (u_int32_t)sc->aac_common); 111535863739SMike Smith bzero(sc->aac_queues, sizeof(struct aac_queue_table)); 111635863739SMike Smith 111735863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_NORM_CMD_ENTRIES; 111835863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = AAC_HOST_NORM_CMD_ENTRIES; 111935863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_HIGH_CMD_ENTRIES; 112035863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = AAC_HOST_HIGH_CMD_ENTRIES; 112135863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = AAC_ADAP_NORM_CMD_ENTRIES; 112235863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = AAC_ADAP_NORM_CMD_ENTRIES; 112335863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = AAC_ADAP_HIGH_CMD_ENTRIES; 112435863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = AAC_ADAP_HIGH_CMD_ENTRIES; 112535863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_NORM_RESP_ENTRIES; 112635863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_HOST_NORM_RESP_ENTRIES; 112735863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_HIGH_RESP_ENTRIES; 112835863739SMike Smith sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_HOST_HIGH_RESP_ENTRIES; 112935863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_ADAP_NORM_RESP_ENTRIES; 113035863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_ADAP_NORM_RESP_ENTRIES; 113135863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_ADAP_HIGH_RESP_ENTRIES; 113235863739SMike Smith sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_ADAP_HIGH_RESP_ENTRIES; 113335863739SMike Smith sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = &sc->aac_queues->qt_HostNormCmdQueue[0]; 113435863739SMike Smith sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = &sc->aac_queues->qt_HostHighCmdQueue[0]; 113535863739SMike Smith sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = &sc->aac_queues->qt_AdapNormCmdQueue[0]; 113635863739SMike Smith sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = &sc->aac_queues->qt_AdapHighCmdQueue[0]; 113735863739SMike Smith sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = &sc->aac_queues->qt_HostNormRespQueue[0]; 113835863739SMike Smith sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = &sc->aac_queues->qt_HostHighRespQueue[0]; 113935863739SMike Smith sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = &sc->aac_queues->qt_AdapNormRespQueue[0]; 114035863739SMike Smith sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = &sc->aac_queues->qt_AdapHighRespQueue[0]; 114135863739SMike Smith 114235863739SMike Smith /* 114335863739SMike Smith * Do controller-type-specific initialisation 114435863739SMike Smith */ 114535863739SMike Smith switch (sc->aac_hwif) { 114635863739SMike Smith case AAC_HWIF_I960RX: 114735863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 114835863739SMike Smith break; 114935863739SMike Smith } 115035863739SMike Smith 115135863739SMike Smith /* 115235863739SMike Smith * Give the init structure to the controller. 115335863739SMike Smith */ 115435863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 115546aa3347SPoul-Henning Kamp sc->aac_common_busaddr + offsetof(struct aac_common, ac_init), 115635863739SMike Smith 0, 0, 0, NULL)) { 115735863739SMike Smith device_printf(sc->aac_dev, "error establishing init structure\n"); 115835863739SMike Smith return(EIO); 115935863739SMike Smith } 116035863739SMike Smith 116135863739SMike Smith return(0); 116235863739SMike Smith } 116335863739SMike Smith 116435863739SMike Smith /******************************************************************************** 116535863739SMike Smith * Send a synchronous command to the controller and wait for a result. 116635863739SMike Smith */ 116735863739SMike Smith static int 116835863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 116935863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 117035863739SMike Smith u_int32_t *sp) 117135863739SMike Smith { 117235863739SMike Smith time_t then; 117335863739SMike Smith u_int32_t status; 117435863739SMike Smith 117535863739SMike Smith debug_called(3); 117635863739SMike Smith 117735863739SMike Smith /* populate the mailbox */ 117835863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 117935863739SMike Smith 118035863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 118135863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 118235863739SMike Smith 118335863739SMike Smith /* then set it to signal the adapter */ 118435863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 118535863739SMike Smith 118635863739SMike Smith /* spin waiting for the command to complete */ 118735863739SMike Smith then = time_second; 118835863739SMike Smith do { 118935863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 119035863739SMike Smith debug(2, "timed out"); 119135863739SMike Smith return(EIO); 119235863739SMike Smith } 119335863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 119435863739SMike Smith 119535863739SMike Smith /* clear the completion flag */ 119635863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 119735863739SMike Smith 119835863739SMike Smith /* get the command status */ 119935863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 120035863739SMike Smith if (sp != NULL) 120135863739SMike Smith *sp = status; 12020b94a66eSMike Smith return(0); 120335863739SMike Smith } 120435863739SMike Smith 120535863739SMike Smith /******************************************************************************** 120635863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 120735863739SMike Smith */ 120835863739SMike Smith static int 120935863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 121035863739SMike Smith void *data, u_int16_t datasize, 121135863739SMike Smith void *result, u_int16_t *resultsize) 121235863739SMike Smith { 121335863739SMike Smith struct aac_fib *fib = &sc->aac_common->ac_sync_fib; 121435863739SMike Smith 121535863739SMike Smith debug_called(3); 121635863739SMike Smith 121735863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 121835863739SMike Smith return(EINVAL); 121935863739SMike Smith 122035863739SMike Smith /* 122135863739SMike Smith * Set up the sync FIB 122235863739SMike Smith */ 122335863739SMike Smith fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_EMPTY; 122435863739SMike Smith fib->Header.XferState |= xferstate; 122535863739SMike Smith fib->Header.Command = command; 122635863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 122735863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 122835863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 122935863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 123046aa3347SPoul-Henning Kamp fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_sync_fib); 123135863739SMike Smith 123235863739SMike Smith /* 123335863739SMike Smith * Copy in data. 123435863739SMike Smith */ 123535863739SMike Smith if (data != NULL) { 123635863739SMike Smith bcopy(data, fib->data, datasize); 123735863739SMike Smith fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM; 123835863739SMike Smith } 123935863739SMike Smith 124035863739SMike Smith /* 124135863739SMike Smith * Give the FIB to the controller, wait for a response. 124235863739SMike Smith */ 124335863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress, 124435863739SMike Smith 0, 0, 0, NULL)) { 124535863739SMike Smith debug(2, "IO error"); 124635863739SMike Smith return(EIO); 124735863739SMike Smith } 124835863739SMike Smith 124935863739SMike Smith /* 125035863739SMike Smith * Copy out the result 125135863739SMike Smith */ 125235863739SMike Smith if (result != NULL) { 125335863739SMike Smith *resultsize = fib->Header.Size - sizeof(struct aac_fib_header); 125435863739SMike Smith bcopy(fib->data, result, *resultsize); 125535863739SMike Smith } 125635863739SMike Smith return(0); 125735863739SMike Smith } 125835863739SMike Smith 125935863739SMike Smith /******************************************************************************** 126035863739SMike Smith * Adapter-space FIB queue manipulation 126135863739SMike Smith * 126235863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 126335863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 126435863739SMike Smith */ 126535863739SMike Smith static struct { 126635863739SMike Smith int size; 126735863739SMike Smith int notify; 126835863739SMike Smith } aac_qinfo[] = { 126935863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 127035863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 127135863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 127235863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 127335863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 127435863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 127535863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 127635863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 127735863739SMike Smith }; 127835863739SMike Smith 127935863739SMike Smith /* 128035863739SMike Smith * Atomically insert an entry into the nominated queue, returns 0 on success or EBUSY 128135863739SMike Smith * if the queue is full. 128235863739SMike Smith * 12830b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 128435863739SMike Smith * the case where we may be inserting several entries in rapid succession, but 12850b94a66eSMike Smith * implementing this usefully may be difficult (it would involve a separate 12860b94a66eSMike Smith * queue/notify interface). 128735863739SMike Smith */ 128835863739SMike Smith static int 128935863739SMike Smith aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size, u_int32_t fib_addr) 129035863739SMike Smith { 129135863739SMike Smith u_int32_t pi, ci; 129235863739SMike Smith int s, error; 129335863739SMike Smith 129435863739SMike Smith debug_called(3); 129535863739SMike Smith 129635863739SMike Smith s = splbio(); 129735863739SMike Smith 129835863739SMike Smith /* get the producer/consumer indices */ 129935863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 130035863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 130135863739SMike Smith 130235863739SMike Smith /* wrap the queue? */ 130335863739SMike Smith if (pi >= aac_qinfo[queue].size) 130435863739SMike Smith pi = 0; 130535863739SMike Smith 130635863739SMike Smith /* check for queue full */ 130735863739SMike Smith if ((pi + 1) == ci) { 130835863739SMike Smith error = EBUSY; 130935863739SMike Smith goto out; 131035863739SMike Smith } 131135863739SMike Smith 131235863739SMike Smith /* populate queue entry */ 131335863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 131435863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 131535863739SMike Smith 131635863739SMike Smith /* update producer index */ 131735863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 131835863739SMike Smith 131935863739SMike Smith /* notify the adapter if we know how */ 132035863739SMike Smith if (aac_qinfo[queue].notify != 0) 132135863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 132235863739SMike Smith 132335863739SMike Smith error = 0; 132435863739SMike Smith 132535863739SMike Smith out: 132635863739SMike Smith splx(s); 132735863739SMike Smith return(error); 132835863739SMike Smith } 132935863739SMike Smith 133035863739SMike Smith /* 133135863739SMike Smith * Atomically remove one entry from the nominated queue, returns 0 on success or ENOENT 133235863739SMike Smith * if the queue is empty. 133335863739SMike Smith */ 133435863739SMike Smith static int 133535863739SMike Smith aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, struct aac_fib **fib_addr) 133635863739SMike Smith { 133735863739SMike Smith u_int32_t pi, ci; 133835863739SMike Smith int s, error; 133935863739SMike Smith 134035863739SMike Smith debug_called(3); 134135863739SMike Smith 134235863739SMike Smith s = splbio(); 134335863739SMike Smith 134435863739SMike Smith /* get the producer/consumer indices */ 134535863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 134635863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 134735863739SMike Smith 134835863739SMike Smith /* check for queue empty */ 134935863739SMike Smith if (ci == pi) { 135035863739SMike Smith error = ENOENT; 135135863739SMike Smith goto out; 135235863739SMike Smith } 135335863739SMike Smith 135435863739SMike Smith /* wrap the queue? */ 135535863739SMike Smith if (ci >= aac_qinfo[queue].size) 135635863739SMike Smith ci = 0; 135735863739SMike Smith 135835863739SMike Smith /* fetch the entry */ 135935863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 136035863739SMike Smith *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr; 136135863739SMike Smith 136235863739SMike Smith /* update consumer index */ 136335863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 136435863739SMike Smith 136535863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 136635863739SMike Smith if (((pi + 1) == ci) && (aac_qinfo[queue].notify != 0)) 136735863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 136835863739SMike Smith error = 0; 136935863739SMike Smith 137035863739SMike Smith out: 137135863739SMike Smith splx(s); 137235863739SMike Smith return(error); 137335863739SMike Smith } 137435863739SMike Smith 137535863739SMike Smith /******************************************************************************** 13760b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 13770b94a66eSMike Smith * and complain about them. 13780b94a66eSMike Smith */ 13790b94a66eSMike Smith static void 13800b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 13810b94a66eSMike Smith { 13820b94a66eSMike Smith int s; 13830b94a66eSMike Smith struct aac_command *cm; 13840b94a66eSMike Smith time_t deadline; 13850b94a66eSMike Smith 13860b94a66eSMike Smith /* simulate an interrupt to handle possibly-missed interrupts */ 13870b94a66eSMike Smith aac_intr(sc); 13880b94a66eSMike Smith 13890b94a66eSMike Smith /* kick the I/O queue to restart it in the case of deadlock */ 13900b94a66eSMike Smith aac_startio(sc); 13910b94a66eSMike Smith 13920b94a66eSMike Smith /* traverse the busy command list, bitch about late commands once only */ 13930b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 13940b94a66eSMike Smith s = splbio(); 13950b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 13960b94a66eSMike Smith if ((cm->cm_timestamp < deadline) && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { 13970b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 13980b94a66eSMike Smith device_printf(sc->aac_dev, "COMMAND TIMED OUT AFTER %d SECONDS\n", 13990b94a66eSMike Smith (int)(time_second - cm->cm_timestamp)); 14000b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 14010b94a66eSMike Smith } 14020b94a66eSMike Smith } 14030b94a66eSMike Smith splx(s); 14040b94a66eSMike Smith 14050b94a66eSMike Smith /* reset the timer for next time */ 14060b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 14070b94a66eSMike Smith return; 14080b94a66eSMike Smith } 14090b94a66eSMike Smith 14100b94a66eSMike Smith /******************************************************************************** 141135863739SMike Smith ******************************************************************************** 141235863739SMike Smith Interface Function Vectors 141335863739SMike Smith ******************************************************************************** 141435863739SMike Smith ********************************************************************************/ 141535863739SMike Smith 141635863739SMike Smith /******************************************************************************** 141735863739SMike Smith * Read the current firmware status word. 141835863739SMike Smith */ 141935863739SMike Smith static int 142035863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 142135863739SMike Smith { 142235863739SMike Smith debug_called(3); 142335863739SMike Smith 142435863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 142535863739SMike Smith } 142635863739SMike Smith 142735863739SMike Smith static int 142835863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 142935863739SMike Smith { 143035863739SMike Smith debug_called(3); 143135863739SMike Smith 143235863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 143335863739SMike Smith } 143435863739SMike Smith 143535863739SMike Smith /******************************************************************************** 143635863739SMike Smith * Notify the controller of a change in a given queue 143735863739SMike Smith */ 143835863739SMike Smith 143935863739SMike Smith static void 144035863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 144135863739SMike Smith { 144235863739SMike Smith debug_called(3); 144335863739SMike Smith 144435863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 144535863739SMike Smith } 144635863739SMike Smith 144735863739SMike Smith static void 144835863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 144935863739SMike Smith { 145035863739SMike Smith debug_called(3); 145135863739SMike Smith 145235863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 145335863739SMike Smith } 145435863739SMike Smith 145535863739SMike Smith /******************************************************************************** 145635863739SMike Smith * Get the interrupt reason bits 145735863739SMike Smith */ 145835863739SMike Smith static int 145935863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 146035863739SMike Smith { 146135863739SMike Smith debug_called(3); 146235863739SMike Smith 146335863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 146435863739SMike Smith } 146535863739SMike Smith 146635863739SMike Smith static int 146735863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 146835863739SMike Smith { 146935863739SMike Smith debug_called(3); 147035863739SMike Smith 147135863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 147235863739SMike Smith } 147335863739SMike Smith 147435863739SMike Smith /******************************************************************************** 147535863739SMike Smith * Clear some interrupt reason bits 147635863739SMike Smith */ 147735863739SMike Smith static void 147835863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 147935863739SMike Smith { 148035863739SMike Smith debug_called(3); 148135863739SMike Smith 148235863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 148335863739SMike Smith } 148435863739SMike Smith 148535863739SMike Smith static void 148635863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 148735863739SMike Smith { 148835863739SMike Smith debug_called(3); 148935863739SMike Smith 149035863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 149135863739SMike Smith } 149235863739SMike Smith 149335863739SMike Smith /******************************************************************************** 149435863739SMike Smith * Populate the mailbox and set the command word 149535863739SMike Smith */ 149635863739SMike Smith static void 149735863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 149835863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 149935863739SMike Smith { 150035863739SMike Smith debug_called(4); 150135863739SMike Smith 150235863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 150335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 150435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 150535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 150635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 150735863739SMike Smith } 150835863739SMike Smith 150935863739SMike Smith static void 151035863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 151135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 151235863739SMike Smith { 151335863739SMike Smith debug_called(4); 151435863739SMike Smith 151535863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 151635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 151735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 151835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 151935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 152035863739SMike Smith } 152135863739SMike Smith 152235863739SMike Smith /******************************************************************************** 152335863739SMike Smith * Fetch the immediate command status word 152435863739SMike Smith */ 152535863739SMike Smith static int 152635863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 152735863739SMike Smith { 152835863739SMike Smith debug_called(4); 152935863739SMike Smith 153035863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 153135863739SMike Smith } 153235863739SMike Smith 153335863739SMike Smith static int 153435863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 153535863739SMike Smith { 153635863739SMike Smith debug_called(4); 153735863739SMike Smith 153835863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 153935863739SMike Smith } 154035863739SMike Smith 154135863739SMike Smith /******************************************************************************** 154235863739SMike Smith * Set/clear interrupt masks 154335863739SMike Smith */ 154435863739SMike Smith static void 154535863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 154635863739SMike Smith { 154735863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 154835863739SMike Smith 154935863739SMike Smith if (enable) { 155035863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 155135863739SMike Smith } else { 155235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 155335863739SMike Smith } 155435863739SMike Smith } 155535863739SMike Smith 155635863739SMike Smith static void 155735863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 155835863739SMike Smith { 155935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 156035863739SMike Smith 156135863739SMike Smith if (enable) { 156235863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 156335863739SMike Smith } else { 156435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 156535863739SMike Smith } 156635863739SMike Smith } 156735863739SMike Smith 156835863739SMike Smith /******************************************************************************** 156935863739SMike Smith ******************************************************************************** 157035863739SMike Smith Debugging and Diagnostics 157135863739SMike Smith ******************************************************************************** 157235863739SMike Smith ********************************************************************************/ 157335863739SMike Smith 157435863739SMike Smith /******************************************************************************** 157535863739SMike Smith * Print some information about the controller. 157635863739SMike Smith */ 157735863739SMike Smith static void 157835863739SMike Smith aac_describe_controller(struct aac_softc *sc) 157935863739SMike Smith { 158035863739SMike Smith u_int8_t buf[AAC_FIB_DATASIZE]; /* XXX really a bit big for the stack */ 158135863739SMike Smith u_int16_t bufsize; 158235863739SMike Smith struct aac_adapter_info *info; 158335863739SMike Smith u_int8_t arg; 158435863739SMike Smith 158535863739SMike Smith debug_called(2); 158635863739SMike Smith 158735863739SMike Smith arg = 0; 158835863739SMike Smith if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf, &bufsize)) { 158935863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 159035863739SMike Smith return; 159135863739SMike Smith } 159235863739SMike Smith if (bufsize != sizeof(*info)) { 159335863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data size (%d != %d)\n", 159435863739SMike Smith bufsize, sizeof(*info)); 15950b94a66eSMike Smith /*return;*/ 159635863739SMike Smith } 159735863739SMike Smith info = (struct aac_adapter_info *)&buf[0]; 159835863739SMike Smith 159935863739SMike Smith device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n", 160035863739SMike Smith aac_describe_code(aac_cpu_variant, info->CpuVariant), info->ClockSpeed, 160135863739SMike Smith info->TotalMem / (1024 * 1024), 160235863739SMike Smith aac_describe_code(aac_battery_platform, info->batteryPlatform), info->batteryPlatform); 160335863739SMike Smith 160435863739SMike Smith /* save the kernel revision structure for later use */ 160535863739SMike Smith sc->aac_revision = info->KernelRevision; 160635863739SMike Smith device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n", 160735863739SMike Smith info->KernelRevision.external.comp.major, 160835863739SMike Smith info->KernelRevision.external.comp.minor, 160935863739SMike Smith info->KernelRevision.external.comp.dash, 161035863739SMike Smith info->SerialNumber); /* XXX how is this meant to be formatted? */ 161135863739SMike Smith } 161235863739SMike Smith 161335863739SMike Smith /******************************************************************************** 161435863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 161535863739SMike Smith * same. 161635863739SMike Smith */ 161735863739SMike Smith static char * 161835863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 161935863739SMike Smith { 162035863739SMike Smith int i; 162135863739SMike Smith 162235863739SMike Smith for (i = 0; table[i].string != NULL; i++) 162335863739SMike Smith if (table[i].code == code) 162435863739SMike Smith return(table[i].string); 162535863739SMike Smith return(table[i + 1].string); 162635863739SMike Smith } 162735863739SMike Smith 162835863739SMike Smith /***************************************************************************** 162935863739SMike Smith ***************************************************************************** 163035863739SMike Smith Management Interface 163135863739SMike Smith ***************************************************************************** 163235863739SMike Smith *****************************************************************************/ 163335863739SMike Smith 163435863739SMike Smith static int 163535863739SMike Smith aac_open(dev_t dev, int flags, int fmt, struct proc *p) 163635863739SMike Smith { 163735863739SMike Smith struct aac_softc *sc = dev->si_drv1; 163835863739SMike Smith 163935863739SMike Smith debug_called(2); 164035863739SMike Smith 164135863739SMike Smith /* Check to make sure the device isn't already open */ 164235863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 164335863739SMike Smith return EBUSY; 164435863739SMike Smith } 164535863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 164635863739SMike Smith 164735863739SMike Smith return 0; 164835863739SMike Smith } 164935863739SMike Smith 165035863739SMike Smith static int 165135863739SMike Smith aac_close(dev_t dev, int flags, int fmt, struct proc *p) 165235863739SMike Smith { 165335863739SMike Smith struct aac_softc *sc = dev->si_drv1; 165435863739SMike Smith 165535863739SMike Smith debug_called(2); 165635863739SMike Smith 165735863739SMike Smith /* Mark this unit as no longer open */ 165835863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 165935863739SMike Smith 166035863739SMike Smith return 0; 166135863739SMike Smith } 166235863739SMike Smith 166335863739SMike Smith static int 166435863739SMike Smith aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 166535863739SMike Smith { 16660b94a66eSMike Smith union aac_statrequest *as = (union aac_statrequest *)arg; 166735863739SMike Smith struct aac_softc *sc = dev->si_drv1; 16680b94a66eSMike Smith int error = 0; 16690b94a66eSMike Smith #ifdef AAC_COMPAT_LINUX 16700b94a66eSMike Smith int i; 16710b94a66eSMike Smith #endif 167235863739SMike Smith 167335863739SMike Smith debug_called(2); 167435863739SMike Smith 167535863739SMike Smith switch (cmd) { 16760b94a66eSMike Smith case AACIO_STATS: 16770b94a66eSMike Smith switch (as->as_item) { 16780b94a66eSMike Smith case AACQ_FREE: 16790b94a66eSMike Smith case AACQ_BIO: 16800b94a66eSMike Smith case AACQ_READY: 16810b94a66eSMike Smith case AACQ_BUSY: 16820b94a66eSMike Smith case AACQ_COMPLETE: 16830b94a66eSMike Smith bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, sizeof(struct aac_qstat)); 16840b94a66eSMike Smith break; 16850b94a66eSMike Smith default: 16860b94a66eSMike Smith error = ENOENT; 16870b94a66eSMike Smith break; 16880b94a66eSMike Smith } 16890b94a66eSMike Smith break; 16900b94a66eSMike Smith 169135863739SMike Smith #ifdef AAC_COMPAT_LINUX 169235863739SMike Smith case FSACTL_SENDFIB: 16930b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 169435863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 169535863739SMike Smith break; 169635863739SMike Smith case FSACTL_AIF_THREAD: 16970b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 169835863739SMike Smith error = EINVAL; 169935863739SMike Smith break; 170035863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 17010b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 170235863739SMike Smith /* 170335863739SMike Smith * Pass the caller out an AdapterFibContext. 170435863739SMike Smith * 170535863739SMike Smith * Note that because we only support one opener, we 170635863739SMike Smith * basically ignore this. Set the caller's context to a magic 170735863739SMike Smith * number just in case. 17080b94a66eSMike Smith * 17090b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 17100b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 171135863739SMike Smith */ 171235863739SMike Smith i = AAC_AIF_SILLYMAGIC; 171335863739SMike Smith error = copyout(&i, arg, sizeof(i)); 171435863739SMike Smith break; 171535863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 17160b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 171735863739SMike Smith error = aac_linux_getnext_aif(sc, arg); 171835863739SMike Smith break; 171935863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 17200b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 172135863739SMike Smith /* don't do anything here */ 172235863739SMike Smith break; 172335863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 17240b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 172535863739SMike Smith error = aac_linux_rev_check(sc, arg); 172635863739SMike Smith break; 172735863739SMike Smith #endif 172835863739SMike Smith default: 172935863739SMike Smith device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd); 173035863739SMike Smith error = EINVAL; 173135863739SMike Smith break; 173235863739SMike Smith } 173335863739SMike Smith return(error); 173435863739SMike Smith } 173535863739SMike Smith 173635863739SMike Smith /******************************************************************************** 173735863739SMike Smith * Send a FIB supplied from userspace 173835863739SMike Smith */ 173935863739SMike Smith static int 174035863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 174135863739SMike Smith { 174235863739SMike Smith struct aac_command *cm; 174335863739SMike Smith int size, error; 174435863739SMike Smith 174535863739SMike Smith debug_called(2); 174635863739SMike Smith 174735863739SMike Smith cm = NULL; 174835863739SMike Smith 174935863739SMike Smith /* 175035863739SMike Smith * Get a command 175135863739SMike Smith */ 175235863739SMike Smith if (aac_alloc_command(sc, &cm)) { 175335863739SMike Smith error = EBUSY; 175435863739SMike Smith goto out; 175535863739SMike Smith } 175635863739SMike Smith 175735863739SMike Smith /* 175835863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 175935863739SMike Smith */ 176035863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0) 176135863739SMike Smith goto out; 176235863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 176335863739SMike Smith if (size > sizeof(struct aac_fib)) { 176435863739SMike Smith device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size, sizeof(struct aac_fib)); 176535863739SMike Smith size = sizeof(struct aac_fib); 176635863739SMike Smith } 176735863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 176835863739SMike Smith goto out; 176935863739SMike Smith cm->cm_fib->Header.Size = size; 177035863739SMike Smith 177135863739SMike Smith /* 177235863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 177335863739SMike Smith */ 177435863739SMike Smith if ((error = aac_wait_command(cm, 30)) != 0) /* XXX user timeout? */ 177535863739SMike Smith goto out; 177635863739SMike Smith 177735863739SMike Smith /* 177835863739SMike Smith * Copy the FIB and data back out to the caller. 177935863739SMike Smith */ 178035863739SMike Smith size = cm->cm_fib->Header.Size; 178135863739SMike Smith if (size > sizeof(struct aac_fib)) { 178235863739SMike Smith device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size, sizeof(struct aac_fib)); 178335863739SMike Smith size = sizeof(struct aac_fib); 178435863739SMike Smith } 178535863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 178635863739SMike Smith 178735863739SMike Smith out: 178835863739SMike Smith if (cm != NULL) 178935863739SMike Smith aac_release_command(cm); 179035863739SMike Smith return(error); 179135863739SMike Smith } 179235863739SMike Smith 179335863739SMike Smith /******************************************************************************** 179435863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 179535863739SMike Smith * 179635863739SMike Smith * XXX what's the right thing to do here when the queue is full? Drop the older 179735863739SMike Smith * or newer entries? 179835863739SMike Smith */ 179935863739SMike Smith static void 180035863739SMike Smith aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif) 180135863739SMike Smith { 180235863739SMike Smith int next, s; 180335863739SMike Smith 180435863739SMike Smith debug_called(2); 180535863739SMike Smith 180635863739SMike Smith s = splbio(); 180735863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 180835863739SMike Smith if (next != sc->aac_aifq_tail) { 180935863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 181035863739SMike Smith sc->aac_aifq_head = next; 181135863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 181235863739SMike Smith wakeup(sc->aac_aifq); 181335863739SMike Smith } 181435863739SMike Smith splx(s); 181535863739SMike Smith aac_print_aif(sc, aif); 181635863739SMike Smith } 181735863739SMike Smith 181835863739SMike Smith /******************************************************************************** 181935863739SMike Smith ******************************************************************************** 182035863739SMike Smith Linux Management Interface 182135863739SMike Smith ******************************************************************************** 182235863739SMike Smith ********************************************************************************/ 182335863739SMike Smith 182435863739SMike Smith #ifdef AAC_COMPAT_LINUX 182535863739SMike Smith 182630d57611SMike Smith #include <sys/proc.h> 182735863739SMike Smith #include <machine/../linux/linux.h> 182835863739SMike Smith #include <machine/../linux/linux_proto.h> 182935863739SMike Smith #include <compat/linux/linux_ioctl.h> 183035863739SMike Smith 183135863739SMike Smith #define AAC_LINUX_IOCTL_MIN 0x2000 183235863739SMike Smith #define AAC_LINUX_IOCTL_MAX 0x21ff 183335863739SMike Smith 183435863739SMike Smith static linux_ioctl_function_t aac_linux_ioctl; 183535863739SMike Smith static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl, AAC_LINUX_IOCTL_MIN, AAC_LINUX_IOCTL_MAX}; 183635863739SMike Smith 183735863739SMike Smith SYSINIT (aac_register, SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_register_handler, &aac_handler); 183835863739SMike Smith SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_unregister_handler, &aac_handler); 183935863739SMike Smith 184035863739SMike Smith MODULE_DEPEND(aac, linux, 1, 1, 1); 184135863739SMike Smith 184235863739SMike Smith static int 184335863739SMike Smith aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args) 184435863739SMike Smith { 184535863739SMike Smith struct file *fp = p->p_fd->fd_ofiles[args->fd]; 184635863739SMike Smith u_long cmd = args->cmd; 184735863739SMike Smith 184835863739SMike Smith /* 184935863739SMike Smith * Pass the ioctl off to our standard handler. 185035863739SMike Smith */ 185135863739SMike Smith return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p)); 185235863739SMike Smith } 185335863739SMike Smith 185435863739SMike Smith /******************************************************************************** 18550b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 185635863739SMike Smith * userspace app is possibly compatible. This is extremely bogus right now 185735863739SMike Smith * because I have no idea how to handle the versioning of this driver. It is 185835863739SMike Smith * needed, though, to get aaccli working. 185935863739SMike Smith */ 186035863739SMike Smith static int 186135863739SMike Smith aac_linux_rev_check(struct aac_softc *sc, caddr_t udata) 186235863739SMike Smith { 186335863739SMike Smith struct aac_rev_check rev_check; 186435863739SMike Smith struct aac_rev_check_resp rev_check_resp; 186535863739SMike Smith int error = 0; 186635863739SMike Smith 186735863739SMike Smith debug_called(2); 186835863739SMike Smith 186935863739SMike Smith /* 187035863739SMike Smith * Copyin the revision struct from userspace 187135863739SMike Smith */ 187235863739SMike Smith if ((error = copyin(udata, (caddr_t)&rev_check, sizeof(struct aac_rev_check))) != 0) { 187335863739SMike Smith return error; 187435863739SMike Smith } 187535863739SMike Smith 187635863739SMike Smith debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber); 187735863739SMike Smith 187835863739SMike Smith /* 187935863739SMike Smith * Doctor up the response struct. 188035863739SMike Smith */ 188135863739SMike Smith rev_check_resp.possiblyCompatible = 1; 188235863739SMike Smith rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul; 188335863739SMike Smith rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber; 188435863739SMike Smith 188535863739SMike Smith return(copyout((caddr_t)&rev_check_resp, udata, sizeof(struct aac_rev_check_resp))); 188635863739SMike Smith } 188735863739SMike Smith 188835863739SMike Smith /******************************************************************************** 188935863739SMike Smith * Pass the caller the next AIF in their queue 189035863739SMike Smith */ 189135863739SMike Smith static int 189235863739SMike Smith aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg) 189335863739SMike Smith { 189435863739SMike Smith struct get_adapter_fib_ioctl agf; 189535863739SMike Smith int error, s; 189635863739SMike Smith 189735863739SMike Smith debug_called(2); 189835863739SMike Smith 189935863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 190035863739SMike Smith 190135863739SMike Smith /* 190235863739SMike Smith * Check the magic number that we gave the caller. 190335863739SMike Smith */ 190435863739SMike Smith if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) { 190535863739SMike Smith error = EFAULT; 190635863739SMike Smith } else { 190735863739SMike Smith 190835863739SMike Smith s = splbio(); 19090b94a66eSMike Smith error = aac_linux_return_aif(sc, agf.AifFib); 191035863739SMike Smith 191135863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 191235863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 191335863739SMike Smith while (error == EAGAIN) { 191435863739SMike Smith error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0); 191535863739SMike Smith if (error == 0) 19160b94a66eSMike Smith error = aac_linux_return_aif(sc, agf.AifFib); 191735863739SMike Smith } 191835863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 191935863739SMike Smith } 192035863739SMike Smith splx(s); 192135863739SMike Smith } 192235863739SMike Smith } 192335863739SMike Smith return(error); 192435863739SMike Smith } 192535863739SMike Smith 19260b94a66eSMike Smith /******************************************************************************** 19270b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 19280b94a66eSMike Smith */ 19290b94a66eSMike Smith static int 19300b94a66eSMike Smith aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr) 19310b94a66eSMike Smith { 19320b94a66eSMike Smith int error, s; 19330b94a66eSMike Smith 19340b94a66eSMike Smith debug_called(2); 19350b94a66eSMike Smith 19360b94a66eSMike Smith s = splbio(); 19370b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 19380b94a66eSMike Smith error = EAGAIN; 19390b94a66eSMike Smith } else { 19400b94a66eSMike Smith error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, sizeof(struct aac_aif_command)); 19410b94a66eSMike Smith if (!error) 19420b94a66eSMike Smith sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 19430b94a66eSMike Smith } 19440b94a66eSMike Smith splx(s); 19450b94a66eSMike Smith return(error); 19460b94a66eSMike Smith } 19470b94a66eSMike Smith 19480b94a66eSMike Smith 194935863739SMike Smith #endif /* AAC_COMPAT_LINUX */ 1950