135863739SMike Smith /*- 235863739SMike Smith * Copyright (c) 2000 Michael Smith 3c6eafcf2SScott Long * Copyright (c) 2001 Scott Long 435863739SMike Smith * Copyright (c) 2000 BSDi 5c6eafcf2SScott Long * Copyright (c) 2001 Adaptec, Inc. 635863739SMike Smith * All rights reserved. 735863739SMike Smith * 835863739SMike Smith * Redistribution and use in source and binary forms, with or without 935863739SMike Smith * modification, are permitted provided that the following conditions 1035863739SMike Smith * are met: 1135863739SMike Smith * 1. Redistributions of source code must retain the above copyright 1235863739SMike Smith * notice, this list of conditions and the following disclaimer. 1335863739SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1435863739SMike Smith * notice, this list of conditions and the following disclaimer in the 1535863739SMike Smith * documentation and/or other materials provided with the distribution. 1635863739SMike Smith * 1735863739SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1835863739SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1935863739SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2035863739SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2135863739SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2235863739SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2335863739SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2435863739SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2535863739SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2635863739SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2735863739SMike Smith * SUCH DAMAGE. 2835863739SMike Smith * 2935863739SMike Smith * $FreeBSD$ 3035863739SMike Smith */ 3135863739SMike Smith 3235863739SMike Smith /* 3335863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3435863739SMike Smith */ 3535863739SMike Smith 36f6c4dd3fSScott Long #include "opt_aac.h" 37f6c4dd3fSScott Long 3836e0bf6eSScott Long /* #include <stddef.h> */ 3935863739SMike Smith #include <sys/param.h> 4035863739SMike Smith #include <sys/systm.h> 4135863739SMike Smith #include <sys/malloc.h> 4235863739SMike Smith #include <sys/kernel.h> 4336e0bf6eSScott Long #include <sys/kthread.h> 449e209b12SAlfred Perlstein #include <sys/lock.h> 459e209b12SAlfred Perlstein #include <sys/mutex.h> 463d04a9d7SScott Long #include <sys/sysctl.h> 47b3457b51SScott Long #include <sys/poll.h> 48c3d15322SScott Long #if __FreeBSD_version >= 500005 49b3457b51SScott Long #include <sys/selinfo.h> 50c3d15322SScott Long #else 51c3d15322SScott Long #include <sys/select.h> 52c3d15322SScott Long #endif 5335863739SMike Smith 5435863739SMike Smith #include <dev/aac/aac_compat.h> 5535863739SMike Smith 5635863739SMike Smith #include <sys/bus.h> 5735863739SMike Smith #include <sys/conf.h> 5835863739SMike Smith #include <sys/devicestat.h> 5935863739SMike Smith #include <sys/disk.h> 6035863739SMike Smith #include <sys/signalvar.h> 610b94a66eSMike Smith #include <sys/time.h> 6236e0bf6eSScott Long #include <sys/eventhandler.h> 6335863739SMike Smith 6435863739SMike Smith #include <machine/bus_memio.h> 6535863739SMike Smith #include <machine/bus.h> 6635863739SMike Smith #include <machine/resource.h> 6735863739SMike Smith 6835863739SMike Smith #include <dev/aac/aacreg.h> 690b94a66eSMike Smith #include <dev/aac/aac_ioctl.h> 7035863739SMike Smith #include <dev/aac/aacvar.h> 7135863739SMike Smith #include <dev/aac/aac_tables.h> 7235863739SMike Smith 7335863739SMike Smith static void aac_startup(void *arg); 74914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 75cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 76fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 7735863739SMike Smith 7835863739SMike Smith /* Command Processing */ 790b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 8035863739SMike Smith static int aac_start(struct aac_command *cm); 8135863739SMike Smith static void aac_complete(void *context, int pending); 8235863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8335863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 8435863739SMike Smith static int aac_wait_command(struct aac_command *cm, int timeout); 8570545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8635863739SMike Smith static void aac_host_response(struct aac_softc *sc); 8735863739SMike Smith 8835863739SMike Smith /* Command Buffer Management */ 89c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 90c6eafcf2SScott Long int nseg, int error); 910b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 920b94a66eSMike Smith static void aac_free_commands(struct aac_softc *sc); 9335863739SMike Smith static void aac_map_command(struct aac_command *cm); 9435863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9535863739SMike Smith 9635863739SMike Smith /* Hardware Interface */ 97c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 98c6eafcf2SScott Long int error); 99fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 10035863739SMike Smith static int aac_init(struct aac_softc *sc); 10135863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 102c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 103c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 104c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 105f6c4dd3fSScott Long struct aac_command *cm); 106c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 107914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10836e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10936e0bf6eSScott Long struct aac_fib *fib); 11035863739SMike Smith 111b3457b51SScott Long /* Falcon/PPC interface */ 112b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 113b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 114b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 115b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 116b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 117b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 118b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 119b3457b51SScott Long static int aac_fa_get_mailboxstatus(struct aac_softc *sc); 120b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 121b3457b51SScott Long 122b3457b51SScott Long struct aac_interface aac_fa_interface = { 123b3457b51SScott Long aac_fa_get_fwstatus, 124b3457b51SScott Long aac_fa_qnotify, 125b3457b51SScott Long aac_fa_get_istatus, 126b3457b51SScott Long aac_fa_clear_istatus, 127b3457b51SScott Long aac_fa_set_mailbox, 128b3457b51SScott Long aac_fa_get_mailboxstatus, 129b3457b51SScott Long aac_fa_set_interrupts 130b3457b51SScott Long }; 131b3457b51SScott Long 13235863739SMike Smith /* StrongARM interface */ 13335863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13435863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13535863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13635863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13735863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 138c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 139c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 14035863739SMike Smith static int aac_sa_get_mailboxstatus(struct aac_softc *sc); 14135863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 14235863739SMike Smith 14335863739SMike Smith struct aac_interface aac_sa_interface = { 14435863739SMike Smith aac_sa_get_fwstatus, 14535863739SMike Smith aac_sa_qnotify, 14635863739SMike Smith aac_sa_get_istatus, 14735863739SMike Smith aac_sa_clear_istatus, 14835863739SMike Smith aac_sa_set_mailbox, 14935863739SMike Smith aac_sa_get_mailboxstatus, 15035863739SMike Smith aac_sa_set_interrupts 15135863739SMike Smith }; 15235863739SMike Smith 15335863739SMike Smith /* i960Rx interface */ 15435863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15535863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15635863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15735863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15835863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 159c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 160c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 16135863739SMike Smith static int aac_rx_get_mailboxstatus(struct aac_softc *sc); 16235863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 16335863739SMike Smith 16435863739SMike Smith struct aac_interface aac_rx_interface = { 16535863739SMike Smith aac_rx_get_fwstatus, 16635863739SMike Smith aac_rx_qnotify, 16735863739SMike Smith aac_rx_get_istatus, 16835863739SMike Smith aac_rx_clear_istatus, 16935863739SMike Smith aac_rx_set_mailbox, 17035863739SMike Smith aac_rx_get_mailboxstatus, 17135863739SMike Smith aac_rx_set_interrupts 17235863739SMike Smith }; 17335863739SMike Smith 17435863739SMike Smith /* Debugging and Diagnostics */ 17535863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1766965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 177c6eafcf2SScott Long u_int32_t code); 17835863739SMike Smith 17935863739SMike Smith /* Management Interface */ 18035863739SMike Smith static d_open_t aac_open; 18135863739SMike Smith static d_close_t aac_close; 18235863739SMike Smith static d_ioctl_t aac_ioctl; 183b3457b51SScott Long static d_poll_t aac_poll; 184c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 185c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 18636e0bf6eSScott Long struct aac_fib *fib); 187fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 188fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 189fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 19036e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 19135863739SMike Smith 19235863739SMike Smith #define AAC_CDEV_MAJOR 150 19335863739SMike Smith 19435863739SMike Smith static struct cdevsw aac_cdevsw = { 19535863739SMike Smith aac_open, /* open */ 19635863739SMike Smith aac_close, /* close */ 19735863739SMike Smith noread, /* read */ 19835863739SMike Smith nowrite, /* write */ 19935863739SMike Smith aac_ioctl, /* ioctl */ 200b3457b51SScott Long aac_poll, /* poll */ 20135863739SMike Smith nommap, /* mmap */ 20235863739SMike Smith nostrategy, /* strategy */ 20335863739SMike Smith "aac", /* name */ 20435863739SMike Smith AAC_CDEV_MAJOR, /* major */ 20535863739SMike Smith nodump, /* dump */ 20635863739SMike Smith nopsize, /* psize */ 20735863739SMike Smith 0, /* flags */ 20836e0bf6eSScott Long #if __FreeBSD_version < 500005 20936e0bf6eSScott Long -1, /* bmaj */ 21036e0bf6eSScott Long #endif 21135863739SMike Smith }; 21235863739SMike Smith 21336e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 21436e0bf6eSScott Long 2153d04a9d7SScott Long /* sysctl node */ 2163d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2173d04a9d7SScott Long 218914da7d0SScott Long /* 219914da7d0SScott Long * Device Interface 220914da7d0SScott Long */ 22135863739SMike Smith 222914da7d0SScott Long /* 22335863739SMike Smith * Initialise the controller and softc 22435863739SMike Smith */ 22535863739SMike Smith int 22635863739SMike Smith aac_attach(struct aac_softc *sc) 22735863739SMike Smith { 22835863739SMike Smith int error, unit; 22935863739SMike Smith 23035863739SMike Smith debug_called(1); 23135863739SMike Smith 23235863739SMike Smith /* 23335863739SMike Smith * Initialise per-controller queues. 23435863739SMike Smith */ 2350b94a66eSMike Smith aac_initq_free(sc); 2360b94a66eSMike Smith aac_initq_ready(sc); 2370b94a66eSMike Smith aac_initq_busy(sc); 2380b94a66eSMike Smith aac_initq_complete(sc); 2390b94a66eSMike Smith aac_initq_bio(sc); 24035863739SMike Smith 24135863739SMike Smith #if __FreeBSD_version >= 500005 24235863739SMike Smith /* 24335863739SMike Smith * Initialise command-completion task. 24435863739SMike Smith */ 24535863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 24635863739SMike Smith #endif 24735863739SMike Smith 24835863739SMike Smith /* disable interrupts before we enable anything */ 24935863739SMike Smith AAC_MASK_INTERRUPTS(sc); 25035863739SMike Smith 25135863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25235863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25335863739SMike Smith 25435863739SMike Smith /* 255fe94b852SScott Long * Check that the firmware on the card is supported. 256fe94b852SScott Long */ 257fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 258fe94b852SScott Long return(error); 259fe94b852SScott Long 260fe94b852SScott Long /* 261128aa5a0SScott Long * Allocate command structures. This must be done before aac_init() 262128aa5a0SScott Long * in order to work around a 2120/2200 bug. 2630b94a66eSMike Smith */ 2640b94a66eSMike Smith if ((error = aac_alloc_commands(sc)) != 0) 2650b94a66eSMike Smith return(error); 2660b94a66eSMike Smith 267cbfd045bSScott Long /* Init the sync fib lock */ 268cbfd045bSScott Long AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 269cbfd045bSScott Long 2700b94a66eSMike Smith /* 27135863739SMike Smith * Initialise the adapter. 27235863739SMike Smith */ 2730b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 27435863739SMike Smith return(error); 27535863739SMike Smith 27635863739SMike Smith /* 27735863739SMike Smith * Print a little information about the controller. 27835863739SMike Smith */ 27935863739SMike Smith aac_describe_controller(sc); 28035863739SMike Smith 28135863739SMike Smith /* 28235863739SMike Smith * Register to probe our containers later. 28335863739SMike Smith */ 28436e0bf6eSScott Long TAILQ_INIT(&sc->aac_container_tqh); 285b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 286b3457b51SScott Long 287b3457b51SScott Long /* 288b3457b51SScott Long * Lock for the AIF queue 289b3457b51SScott Long */ 290b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 29136e0bf6eSScott Long 29235863739SMike Smith sc->aac_ich.ich_func = aac_startup; 29335863739SMike Smith sc->aac_ich.ich_arg = sc; 29435863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 295914da7d0SScott Long device_printf(sc->aac_dev, 296914da7d0SScott Long "can't establish configuration hook\n"); 29735863739SMike Smith return(ENXIO); 29835863739SMike Smith } 29935863739SMike Smith 30035863739SMike Smith /* 30135863739SMike Smith * Make the control device. 30235863739SMike Smith */ 30335863739SMike Smith unit = device_get_unit(sc->aac_dev); 3049e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3059e9466baSRobert Watson 0640, "aac%d", unit); 30636e0bf6eSScott Long #if __FreeBSD_version > 500005 307157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3084aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 30936e0bf6eSScott Long #endif 31035863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 31135863739SMike Smith 31236e0bf6eSScott Long /* Create the AIF thread */ 31336e0bf6eSScott Long #if __FreeBSD_version > 500005 31470545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 315316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 31636e0bf6eSScott Long #else 31770545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 318914da7d0SScott Long &sc->aifthread, "aac%daif", unit)) 31936e0bf6eSScott Long #endif 32036e0bf6eSScott Long panic("Could not create AIF thread\n"); 32136e0bf6eSScott Long 32236e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3235f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3245f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3255f54d522SScott Long device_printf(sc->aac_dev, 3265f54d522SScott Long "shutdown event registration failed\n"); 32736e0bf6eSScott Long 328fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 32970545d1aSScott Long if (!(sc->quirks & AAC_QUIRK_NOCAM)) { 33070545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 331fe3cb0e1SScott Long aac_get_bus_info(sc); 33270545d1aSScott Long } 333fe3cb0e1SScott Long 33435863739SMike Smith return(0); 33535863739SMike Smith } 33635863739SMike Smith 337914da7d0SScott Long /* 33835863739SMike Smith * Probe for containers, create disks. 33935863739SMike Smith */ 34035863739SMike Smith static void 34135863739SMike Smith aac_startup(void *arg) 34235863739SMike Smith { 343914da7d0SScott Long struct aac_softc *sc; 344cbfd045bSScott Long struct aac_fib *fib; 345cbfd045bSScott Long struct aac_mntinfo *mi; 346cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 34736e0bf6eSScott Long int i = 0; 34835863739SMike Smith 34935863739SMike Smith debug_called(1); 35035863739SMike Smith 351914da7d0SScott Long sc = (struct aac_softc *)arg; 352914da7d0SScott Long 35335863739SMike Smith /* disconnect ourselves from the intrhook chain */ 35435863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 35535863739SMike Smith 356fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 357cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 358cbfd045bSScott Long 35935863739SMike Smith /* loop over possible containers */ 36036e0bf6eSScott Long do { 36135863739SMike Smith /* request information on this container */ 36239ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 36339ee03c3SScott Long mi->Command = VM_NameServe; 36439ee03c3SScott Long mi->MntType = FT_FILESYS; 365cbfd045bSScott Long mi->MntCount = i; 366cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 367cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 36835863739SMike Smith debug(2, "error probing container %d", i); 36935863739SMike Smith continue; 37035863739SMike Smith } 37135863739SMike Smith 372cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 373cbfd045bSScott Long aac_add_container(sc, mir, 0); 37436e0bf6eSScott Long i++; 375cbfd045bSScott Long } while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS)); 376cbfd045bSScott Long 377cbfd045bSScott Long aac_release_sync_fib(sc); 37835863739SMike Smith 37935863739SMike Smith /* poke the bus to actually attach the child devices */ 38035863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 38135863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 38235863739SMike Smith 38335863739SMike Smith /* mark the controller up */ 38435863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 38535863739SMike Smith 38635863739SMike Smith /* enable interrupts now */ 38735863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 38835863739SMike Smith } 38935863739SMike Smith 390914da7d0SScott Long /* 391914da7d0SScott Long * Create a device to respresent a new container 392914da7d0SScott Long */ 393914da7d0SScott Long static void 394cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 395914da7d0SScott Long { 396914da7d0SScott Long struct aac_container *co; 397914da7d0SScott Long device_t child; 398914da7d0SScott Long 399914da7d0SScott Long /* 400914da7d0SScott Long * Check container volume type for validity. Note that many of 401914da7d0SScott Long * the possible types may never show up. 402914da7d0SScott Long */ 403914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 404a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 405a761a1caSScott Long M_NOWAIT | M_ZERO); 406914da7d0SScott Long if (co == NULL) 407914da7d0SScott Long panic("Out of memory?!\n"); 408914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 409914da7d0SScott Long mir->MntTable[0].ObjectId, 410914da7d0SScott Long mir->MntTable[0].FileSystemName, 411914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 412914da7d0SScott Long 413fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 414914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 415914da7d0SScott Long else 416914da7d0SScott Long device_set_ivars(child, co); 417914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 418914da7d0SScott Long mir->MntTable[0].VolType)); 419914da7d0SScott Long co->co_disk = child; 420914da7d0SScott Long co->co_found = f; 421914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 422914da7d0SScott Long sizeof(struct aac_mntobj)); 423c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 424914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 425914da7d0SScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 426914da7d0SScott Long } 427914da7d0SScott Long } 428914da7d0SScott Long 429914da7d0SScott Long /* 43035863739SMike Smith * Free all of the resources associated with (sc) 43135863739SMike Smith * 43235863739SMike Smith * Should not be called if the controller is active. 43335863739SMike Smith */ 43435863739SMike Smith void 43535863739SMike Smith aac_free(struct aac_softc *sc) 43635863739SMike Smith { 43735863739SMike Smith debug_called(1); 43835863739SMike Smith 43935863739SMike Smith /* remove the control device */ 44035863739SMike Smith if (sc->aac_dev_t != NULL) 44135863739SMike Smith destroy_dev(sc->aac_dev_t); 44235863739SMike Smith 4430b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 4440b94a66eSMike Smith if (sc->aac_fibs != NULL) 4450b94a66eSMike Smith aac_free_commands(sc); 4460b94a66eSMike Smith if (sc->aac_fib_dmat) 4470b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 44835863739SMike Smith 44935863739SMike Smith /* destroy the common area */ 45035863739SMike Smith if (sc->aac_common) { 45135863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 452c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 453c6eafcf2SScott Long sc->aac_common_dmamap); 45435863739SMike Smith } 4550b94a66eSMike Smith if (sc->aac_common_dmat) 4560b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 45735863739SMike Smith 45835863739SMike Smith /* disconnect the interrupt handler */ 45935863739SMike Smith if (sc->aac_intr) 46035863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 46135863739SMike Smith if (sc->aac_irq != NULL) 462c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 463c6eafcf2SScott Long sc->aac_irq); 46435863739SMike Smith 46535863739SMike Smith /* destroy data-transfer DMA tag */ 46635863739SMike Smith if (sc->aac_buffer_dmat) 46735863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 46835863739SMike Smith 46935863739SMike Smith /* destroy the parent DMA tag */ 47035863739SMike Smith if (sc->aac_parent_dmat) 47135863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 47235863739SMike Smith 47335863739SMike Smith /* release the register window mapping */ 47435863739SMike Smith if (sc->aac_regs_resource != NULL) 475914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 476914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 47735863739SMike Smith } 47835863739SMike Smith 479914da7d0SScott Long /* 48035863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 48135863739SMike Smith */ 48235863739SMike Smith int 48335863739SMike Smith aac_detach(device_t dev) 48435863739SMike Smith { 485914da7d0SScott Long struct aac_softc *sc; 48670545d1aSScott Long struct aac_container *co; 48770545d1aSScott Long struct aac_sim *sim; 48835863739SMike Smith int error; 48935863739SMike Smith 49035863739SMike Smith debug_called(1); 49135863739SMike Smith 492914da7d0SScott Long sc = device_get_softc(dev); 493914da7d0SScott Long 49435863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 49535863739SMike Smith return(EBUSY); 49635863739SMike Smith 49770545d1aSScott Long /* Remove the child containers */ 498a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 499a761a1caSScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 50070545d1aSScott Long error = device_delete_child(dev, co->co_disk); 50170545d1aSScott Long if (error) 50270545d1aSScott Long return (error); 503a761a1caSScott Long free(co, M_AACBUF); 50470545d1aSScott Long } 50570545d1aSScott Long 50670545d1aSScott Long /* Remove the CAM SIMs */ 507a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 508a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 50970545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 51070545d1aSScott Long if (error) 51170545d1aSScott Long return (error); 512a761a1caSScott Long free(sim, M_AACBUF); 51370545d1aSScott Long } 51470545d1aSScott Long 51536e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 51636e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 51736e0bf6eSScott Long wakeup(sc->aifthread); 51836e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 51936e0bf6eSScott Long } 52036e0bf6eSScott Long 52136e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 52236e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 52336e0bf6eSScott Long 52435863739SMike Smith if ((error = aac_shutdown(dev))) 52535863739SMike Smith return(error); 52635863739SMike Smith 5275f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 5285f54d522SScott Long 52935863739SMike Smith aac_free(sc); 53035863739SMike Smith 53135863739SMike Smith return(0); 53235863739SMike Smith } 53335863739SMike Smith 534914da7d0SScott Long /* 53535863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 53635863739SMike Smith * 53735863739SMike Smith * This function is called before detach or system shutdown. 53835863739SMike Smith * 5390b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 54035863739SMike Smith * allow shutdown if any device is open. 54135863739SMike Smith */ 54235863739SMike Smith int 54335863739SMike Smith aac_shutdown(device_t dev) 54435863739SMike Smith { 545914da7d0SScott Long struct aac_softc *sc; 546cbfd045bSScott Long struct aac_fib *fib; 547cbfd045bSScott Long struct aac_close_command *cc; 548cbfd045bSScott Long int s; 54935863739SMike Smith 55035863739SMike Smith debug_called(1); 55135863739SMike Smith 552914da7d0SScott Long sc = device_get_softc(dev); 553914da7d0SScott Long 55435863739SMike Smith s = splbio(); 55535863739SMike Smith 55635863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 55735863739SMike Smith 55835863739SMike Smith /* 55935863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 56035863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 56135863739SMike Smith * We've been closed and all I/O completed already 56235863739SMike Smith */ 56335863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 56435863739SMike Smith 565fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 566cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 567cbfd045bSScott Long 56839ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 569cbfd045bSScott Long cc->Command = VM_CloseAll; 570cbfd045bSScott Long cc->ContainerId = 0xffffffff; 571cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 572cbfd045bSScott Long sizeof(struct aac_close_command))) 57335863739SMike Smith printf("FAILED.\n"); 57470545d1aSScott Long else 57570545d1aSScott Long printf("done\n"); 57670545d1aSScott Long #if 0 577914da7d0SScott Long else { 578cbfd045bSScott Long fib->data[0] = 0; 57936e0bf6eSScott Long /* 580914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 58136e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 58236e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 58336e0bf6eSScott Long * driver module with the intent to reload it later. 58436e0bf6eSScott Long */ 585cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 586cbfd045bSScott Long fib, 1)) { 58735863739SMike Smith printf("FAILED.\n"); 58835863739SMike Smith } else { 58935863739SMike Smith printf("done.\n"); 59035863739SMike Smith } 59135863739SMike Smith } 59270545d1aSScott Long #endif 59335863739SMike Smith 59435863739SMike Smith AAC_MASK_INTERRUPTS(sc); 59535863739SMike Smith 59635863739SMike Smith splx(s); 59735863739SMike Smith return(0); 59835863739SMike Smith } 59935863739SMike Smith 600914da7d0SScott Long /* 60135863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 60235863739SMike Smith */ 60335863739SMike Smith int 60435863739SMike Smith aac_suspend(device_t dev) 60535863739SMike Smith { 606914da7d0SScott Long struct aac_softc *sc; 60735863739SMike Smith int s; 60835863739SMike Smith 60935863739SMike Smith debug_called(1); 610914da7d0SScott Long 611914da7d0SScott Long sc = device_get_softc(dev); 612914da7d0SScott Long 61335863739SMike Smith s = splbio(); 61435863739SMike Smith 61535863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 61635863739SMike Smith 61735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 61835863739SMike Smith splx(s); 61935863739SMike Smith return(0); 62035863739SMike Smith } 62135863739SMike Smith 622914da7d0SScott Long /* 62335863739SMike Smith * Bring the controller back to a state ready for operation. 62435863739SMike Smith */ 62535863739SMike Smith int 62635863739SMike Smith aac_resume(device_t dev) 62735863739SMike Smith { 628914da7d0SScott Long struct aac_softc *sc; 62935863739SMike Smith 63035863739SMike Smith debug_called(1); 631914da7d0SScott Long 632914da7d0SScott Long sc = device_get_softc(dev); 633914da7d0SScott Long 63435863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 63535863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 63635863739SMike Smith return(0); 63735863739SMike Smith } 63835863739SMike Smith 639914da7d0SScott Long /* 64035863739SMike Smith * Take an interrupt. 64135863739SMike Smith */ 64235863739SMike Smith void 64335863739SMike Smith aac_intr(void *arg) 64435863739SMike Smith { 645914da7d0SScott Long struct aac_softc *sc; 646f30ac74cSScott Long u_int32_t *resp_queue; 64770545d1aSScott Long u_int16_t reason; 64835863739SMike Smith 64935863739SMike Smith debug_called(2); 65035863739SMike Smith 651914da7d0SScott Long sc = (struct aac_softc *)arg; 652914da7d0SScott Long 653f30ac74cSScott Long /* 654f30ac74cSScott Long * Optimize the common case of adapter response interrupts. 655f30ac74cSScott Long * We must read from the card prior to processing the responses 656f30ac74cSScott Long * to ensure the clear is flushed prior to accessing the queues. 657f30ac74cSScott Long * Reading the queues from local memory might save us a PCI read. 658f30ac74cSScott Long */ 659f30ac74cSScott Long resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; 660f30ac74cSScott Long if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) 661f30ac74cSScott Long reason = AAC_DB_RESPONSE_READY; 662f30ac74cSScott Long else 66335863739SMike Smith reason = AAC_GET_ISTATUS(sc); 664f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 665f30ac74cSScott Long (void)AAC_GET_ISTATUS(sc); 666f30ac74cSScott Long 667f30ac74cSScott Long /* It's not ok to return here because of races with the previous step */ 668f30ac74cSScott Long if (reason & AAC_DB_RESPONSE_READY) 669f30ac74cSScott Long aac_host_response(sc); 67035863739SMike Smith 671b3457b51SScott Long /* controller wants to talk to the log */ 67270545d1aSScott Long if (reason & AAC_DB_PRINTF) { 67370545d1aSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 67470545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_PRINTF; 67570545d1aSScott Long } else 67636e0bf6eSScott Long aac_print_printf(sc); 67770545d1aSScott Long } 67835863739SMike Smith 67935863739SMike Smith /* controller has a message for us? */ 68035863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 68136e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 68270545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_AIF; 68370545d1aSScott Long } else { 68470545d1aSScott Long /* 68570545d1aSScott Long * XXX If the kthread is dead and we're at this point, 68670545d1aSScott Long * there are bigger problems than just figuring out 68770545d1aSScott Long * what to do with an AIF. 68870545d1aSScott Long */ 68970545d1aSScott Long } 69070545d1aSScott Long 69170545d1aSScott Long } 69270545d1aSScott Long 69370545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) != 0) 69470545d1aSScott Long /* XXX Should this be done with cv_signal? */ 69536e0bf6eSScott Long wakeup(sc->aifthread); 69636e0bf6eSScott Long } 69735863739SMike Smith 698c6eafcf2SScott Long /* 699914da7d0SScott Long * Command Processing 700914da7d0SScott Long */ 70135863739SMike Smith 702914da7d0SScott Long /* 70335863739SMike Smith * Start as much queued I/O as possible on the controller 70435863739SMike Smith */ 705fe3cb0e1SScott Long void 70635863739SMike Smith aac_startio(struct aac_softc *sc) 70735863739SMike Smith { 70835863739SMike Smith struct aac_command *cm; 70935863739SMike Smith 71035863739SMike Smith debug_called(2); 71135863739SMike Smith 71235863739SMike Smith for (;;) { 713914da7d0SScott Long /* 714914da7d0SScott Long * Try to get a command that's been put off for lack of 715914da7d0SScott Long * resources 716914da7d0SScott Long */ 71735863739SMike Smith cm = aac_dequeue_ready(sc); 71835863739SMike Smith 719914da7d0SScott Long /* 720914da7d0SScott Long * Try to build a command off the bio queue (ignore error 721914da7d0SScott Long * return) 722914da7d0SScott Long */ 7230b94a66eSMike Smith if (cm == NULL) 72435863739SMike Smith aac_bio_command(sc, &cm); 72535863739SMike Smith 72635863739SMike Smith /* nothing to do? */ 72735863739SMike Smith if (cm == NULL) 72835863739SMike Smith break; 72935863739SMike Smith 73035863739SMike Smith /* try to give the command to the controller */ 73135863739SMike Smith if (aac_start(cm) == EBUSY) { 73235863739SMike Smith /* put it on the ready queue for later */ 73335863739SMike Smith aac_requeue_ready(cm); 73435863739SMike Smith break; 73535863739SMike Smith } 73635863739SMike Smith } 73735863739SMike Smith } 73835863739SMike Smith 739914da7d0SScott Long /* 74035863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 74135863739SMike Smith * last moment when possible. 74235863739SMike Smith */ 74335863739SMike Smith static int 74435863739SMike Smith aac_start(struct aac_command *cm) 74535863739SMike Smith { 746914da7d0SScott Long struct aac_softc *sc; 747ed5c5fb4SMike Smith int error; 74835863739SMike Smith 74935863739SMike Smith debug_called(2); 75035863739SMike Smith 751914da7d0SScott Long sc = cm->cm_sc; 752914da7d0SScott Long 75335863739SMike Smith /* get the command mapped */ 75435863739SMike Smith aac_map_command(cm); 75535863739SMike Smith 7560b94a66eSMike Smith /* fix up the address values in the FIB */ 75735863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 75835863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 75935863739SMike Smith 76035863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 761c6eafcf2SScott Long cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical 762c6eafcf2SScott Long * address issue */ 76335863739SMike Smith /* put the FIB on the outbound queue */ 76436e0bf6eSScott Long error = aac_enqueue_fib(sc, cm->cm_queue, cm); 7650b94a66eSMike Smith return(error); 76635863739SMike Smith } 76735863739SMike Smith 768914da7d0SScott Long /* 76935863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 77035863739SMike Smith */ 77135863739SMike Smith static void 77270545d1aSScott Long aac_command_thread(struct aac_softc *sc) 77335863739SMike Smith { 77435863739SMike Smith struct aac_fib *fib; 77535863739SMike Smith u_int32_t fib_size; 77636e0bf6eSScott Long int size; 77735863739SMike Smith 77836e0bf6eSScott Long debug_called(2); 77935863739SMike Smith 78036e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_RUNNING; 78136e0bf6eSScott Long 78236e0bf6eSScott Long while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 78370545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 78470545d1aSScott Long tsleep(sc->aifthread, PRIBIO, "aifthd", 78570545d1aSScott Long AAC_PERIODIC_INTERVAL * hz); 78636e0bf6eSScott Long 78770545d1aSScott Long /* While we're here, check to see if any commands are stuck */ 78870545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 78970545d1aSScott Long aac_timeout(sc); 79070545d1aSScott Long 79170545d1aSScott Long /* Check the hardware printf message buffer */ 79270545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) { 79370545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_PRINTF; 79470545d1aSScott Long aac_print_printf(sc); 79570545d1aSScott Long } 79670545d1aSScott Long 79770545d1aSScott Long while (sc->aifflags & AAC_AIFFLAGS_AIF) { 79870545d1aSScott Long 799914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 80070545d1aSScott Long &fib_size, &fib)) { 80170545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_AIF; 80235863739SMike Smith break; /* nothing to do */ 80370545d1aSScott Long } 80435863739SMike Smith 80536e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 80636e0bf6eSScott Long 80735863739SMike Smith switch (fib->Header.Command) { 80835863739SMike Smith case AifRequest: 80936e0bf6eSScott Long aac_handle_aif(sc, fib); 81035863739SMike Smith break; 81135863739SMike Smith default: 812914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 813914da7d0SScott Long "from controller\n"); 81435863739SMike Smith break; 81535863739SMike Smith } 81635863739SMike Smith 81736e0bf6eSScott Long if ((fib->Header.XferState == 0) || 81836e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 81936e0bf6eSScott Long break; 82036e0bf6eSScott Long 82170545d1aSScott Long /* Return the AIF to the controller. */ 82236e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 82336e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 82436e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 82536e0bf6eSScott Long 82636e0bf6eSScott Long /* XXX Compute the Size field? */ 82736e0bf6eSScott Long size = fib->Header.Size; 82836e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 82936e0bf6eSScott Long size = sizeof(struct aac_fib); 83036e0bf6eSScott Long fib->Header.Size = size; 83136e0bf6eSScott Long } 83236e0bf6eSScott Long /* 833914da7d0SScott Long * Since we did not generate this command, it 834914da7d0SScott Long * cannot go through the normal 835914da7d0SScott Long * enqueue->startio chain. 83636e0bf6eSScott Long */ 837914da7d0SScott Long aac_enqueue_response(sc, 838914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 839914da7d0SScott Long fib); 84036e0bf6eSScott Long } 84136e0bf6eSScott Long } 84236e0bf6eSScott Long } 84336e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 84436e0bf6eSScott Long wakeup(sc->aac_dev); 84536e0bf6eSScott Long 84636e0bf6eSScott Long #if __FreeBSD_version > 500005 84736e0bf6eSScott Long mtx_lock(&Giant); 84836e0bf6eSScott Long #endif 84936e0bf6eSScott Long kthread_exit(0); 85035863739SMike Smith } 85135863739SMike Smith 852914da7d0SScott Long /* 85335863739SMike Smith * Handle notification of one or more FIBs completed by the controller 85435863739SMike Smith */ 85535863739SMike Smith static void 85635863739SMike Smith aac_host_response(struct aac_softc *sc) 85735863739SMike Smith { 85835863739SMike Smith struct aac_command *cm; 85935863739SMike Smith struct aac_fib *fib; 86035863739SMike Smith u_int32_t fib_size; 86135863739SMike Smith 86235863739SMike Smith debug_called(2); 86335863739SMike Smith 86435863739SMike Smith for (;;) { 86535863739SMike Smith /* look for completed FIBs on our queue */ 866914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 867914da7d0SScott Long &fib)) 86835863739SMike Smith break; /* nothing to do */ 86935863739SMike Smith 87035863739SMike Smith /* get the command, unmap and queue for later processing */ 87135863739SMike Smith cm = (struct aac_command *)fib->Header.SenderData; 87235863739SMike Smith if (cm == NULL) { 87335863739SMike Smith AAC_PRINT_FIB(sc, fib); 87435863739SMike Smith } else { 8750b94a66eSMike Smith aac_remove_busy(cm); 87635863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 8770b94a66eSMike Smith aac_enqueue_complete(cm); 87835863739SMike Smith } 87935863739SMike Smith } 88035863739SMike Smith 88135863739SMike Smith /* handle completion processing */ 88235863739SMike Smith #if __FreeBSD_version >= 500005 88335863739SMike Smith taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 88435863739SMike Smith #else 88535863739SMike Smith aac_complete(sc, 0); 88635863739SMike Smith #endif 88735863739SMike Smith } 88835863739SMike Smith 889914da7d0SScott Long /* 89035863739SMike Smith * Process completed commands. 89135863739SMike Smith */ 89235863739SMike Smith static void 89335863739SMike Smith aac_complete(void *context, int pending) 89435863739SMike Smith { 895914da7d0SScott Long struct aac_softc *sc; 89635863739SMike Smith struct aac_command *cm; 89735863739SMike Smith 89835863739SMike Smith debug_called(2); 89935863739SMike Smith 900914da7d0SScott Long sc = (struct aac_softc *)context; 901914da7d0SScott Long 90235863739SMike Smith /* pull completed commands off the queue */ 90335863739SMike Smith for (;;) { 9040b94a66eSMike Smith cm = aac_dequeue_complete(sc); 90535863739SMike Smith if (cm == NULL) 9060b94a66eSMike Smith break; 90735863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 90835863739SMike Smith 90935863739SMike Smith /* is there a completion handler? */ 91035863739SMike Smith if (cm->cm_complete != NULL) { 91135863739SMike Smith cm->cm_complete(cm); 91235863739SMike Smith } else { 91335863739SMike Smith /* assume that someone is sleeping on this command */ 91435863739SMike Smith wakeup(cm); 91535863739SMike Smith } 91635863739SMike Smith } 9170b94a66eSMike Smith 9180b94a66eSMike Smith /* see if we can start some more I/O */ 9190b94a66eSMike Smith aac_startio(sc); 92035863739SMike Smith } 92135863739SMike Smith 922914da7d0SScott Long /* 92335863739SMike Smith * Handle a bio submitted from a disk device. 92435863739SMike Smith */ 92535863739SMike Smith void 92635863739SMike Smith aac_submit_bio(struct bio *bp) 92735863739SMike Smith { 928914da7d0SScott Long struct aac_disk *ad; 929914da7d0SScott Long struct aac_softc *sc; 93035863739SMike Smith 93135863739SMike Smith debug_called(2); 93235863739SMike Smith 933914da7d0SScott Long ad = (struct aac_disk *)bp->bio_dev->si_drv1; 934914da7d0SScott Long sc = ad->ad_controller; 935914da7d0SScott Long 93635863739SMike Smith /* queue the BIO and try to get some work done */ 9370b94a66eSMike Smith aac_enqueue_bio(sc, bp); 93835863739SMike Smith aac_startio(sc); 93935863739SMike Smith } 94035863739SMike Smith 941914da7d0SScott Long /* 94235863739SMike Smith * Get a bio and build a command to go with it. 94335863739SMike Smith */ 94435863739SMike Smith static int 94535863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 94635863739SMike Smith { 94735863739SMike Smith struct aac_command *cm; 94835863739SMike Smith struct aac_fib *fib; 94935863739SMike Smith struct aac_blockread *br; 95035863739SMike Smith struct aac_blockwrite *bw; 95135863739SMike Smith struct aac_disk *ad; 95235863739SMike Smith struct bio *bp; 95335863739SMike Smith 95435863739SMike Smith debug_called(2); 95535863739SMike Smith 95635863739SMike Smith /* get the resources we will need */ 95735863739SMike Smith cm = NULL; 9580b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 95935863739SMike Smith goto fail; 96035863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 96135863739SMike Smith goto fail; 96235863739SMike Smith 96335863739SMike Smith /* fill out the command */ 9640b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9650b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9660b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 96735863739SMike Smith cm->cm_private = bp; 9680b94a66eSMike Smith cm->cm_timestamp = time_second; 96936e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 97035863739SMike Smith 97135863739SMike Smith /* build the FIB */ 97235863739SMike Smith fib = cm->cm_fib; 97335863739SMike Smith fib->Header.XferState = 97435863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 97535863739SMike Smith AAC_FIBSTATE_INITIALISED | 976f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 97735863739SMike Smith AAC_FIBSTATE_FROMHOST | 97835863739SMike Smith AAC_FIBSTATE_REXPECTED | 979f30ac74cSScott Long AAC_FIBSTATE_NORM | 980f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 981f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 98235863739SMike Smith fib->Header.Command = ContainerCommand; 98335863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 98435863739SMike Smith 98535863739SMike Smith /* build the read/write request */ 98635863739SMike Smith ad = (struct aac_disk *)bp->bio_dev->si_drv1; 98735863739SMike Smith if (BIO_IS_READ(bp)) { 98835863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 98935863739SMike Smith br->Command = VM_CtBlockRead; 99035863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 99135863739SMike Smith br->BlockNumber = bp->bio_pblkno; 99235863739SMike Smith br->ByteCount = bp->bio_bcount; 99335863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 99435863739SMike Smith cm->cm_sgtable = &br->SgMap; 99535863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 99635863739SMike Smith } else { 99735863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 99835863739SMike Smith bw->Command = VM_CtBlockWrite; 99935863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 100035863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 100135863739SMike Smith bw->ByteCount = bp->bio_bcount; 100235863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 100335863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 100435863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 100535863739SMike Smith cm->cm_sgtable = &bw->SgMap; 100635863739SMike Smith } 100735863739SMike Smith 100835863739SMike Smith *cmp = cm; 100935863739SMike Smith return(0); 101035863739SMike Smith 101135863739SMike Smith fail: 101235863739SMike Smith if (bp != NULL) 10130b94a66eSMike Smith aac_enqueue_bio(sc, bp); 101435863739SMike Smith if (cm != NULL) 101535863739SMike Smith aac_release_command(cm); 101635863739SMike Smith return(ENOMEM); 101735863739SMike Smith } 101835863739SMike Smith 1019914da7d0SScott Long /* 102035863739SMike Smith * Handle a bio-instigated command that has been completed. 102135863739SMike Smith */ 102235863739SMike Smith static void 102335863739SMike Smith aac_bio_complete(struct aac_command *cm) 102435863739SMike Smith { 102535863739SMike Smith struct aac_blockread_response *brr; 102635863739SMike Smith struct aac_blockwrite_response *bwr; 102735863739SMike Smith struct bio *bp; 102835863739SMike Smith AAC_FSAStatus status; 102935863739SMike Smith 103035863739SMike Smith /* fetch relevant status and then release the command */ 103135863739SMike Smith bp = (struct bio *)cm->cm_private; 103235863739SMike Smith if (BIO_IS_READ(bp)) { 103335863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 103435863739SMike Smith status = brr->Status; 103535863739SMike Smith } else { 103635863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 103735863739SMike Smith status = bwr->Status; 103835863739SMike Smith } 103935863739SMike Smith aac_release_command(cm); 104035863739SMike Smith 104135863739SMike Smith /* fix up the bio based on status */ 104235863739SMike Smith if (status == ST_OK) { 104335863739SMike Smith bp->bio_resid = 0; 104435863739SMike Smith } else { 104535863739SMike Smith bp->bio_error = EIO; 104635863739SMike Smith bp->bio_flags |= BIO_ERROR; 10470b94a66eSMike Smith /* pass an error string out to the disk layer */ 1048914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1049914da7d0SScott Long status); 105035863739SMike Smith } 10510b94a66eSMike Smith aac_biodone(bp); 105235863739SMike Smith } 105335863739SMike Smith 1054914da7d0SScott Long /* 105535863739SMike Smith * Submit a command to the controller, return when it completes. 1056b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1057b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1058b3457b51SScott Long * because there is a risk that a signal could wakeup the tsleep before 1059b3457b51SScott Long * the card has a chance to complete the command. The passed in timeout 1060b3457b51SScott Long * is ignored for the same reason. Since there is no way to cancel a 1061b3457b51SScott Long * command in progress, we should probably create a 'dead' queue where 1062b3457b51SScott Long * commands go that have been interrupted/timed-out/etc, that keeps them 1063b3457b51SScott Long * out of the free pool. That way, if the card is just slow, it won't 1064b3457b51SScott Long * spam the memory of a command that has been recycled. 106535863739SMike Smith */ 106635863739SMike Smith static int 106735863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 106835863739SMike Smith { 106935863739SMike Smith int s, error = 0; 107035863739SMike Smith 107135863739SMike Smith debug_called(2); 107235863739SMike Smith 107335863739SMike Smith /* Put the command on the ready queue and get things going */ 107436e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 107535863739SMike Smith aac_enqueue_ready(cm); 107635863739SMike Smith aac_startio(cm->cm_sc); 107735863739SMike Smith s = splbio(); 107835863739SMike Smith while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1079b3457b51SScott Long error = tsleep(cm, PRIBIO, "aacwait", 0); 108035863739SMike Smith } 108135863739SMike Smith splx(s); 108235863739SMike Smith return(error); 108335863739SMike Smith } 108435863739SMike Smith 1085914da7d0SScott Long /* 1086914da7d0SScott Long *Command Buffer Management 1087914da7d0SScott Long */ 108835863739SMike Smith 1089914da7d0SScott Long /* 109035863739SMike Smith * Allocate a command. 109135863739SMike Smith */ 1092fe3cb0e1SScott Long int 109335863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 109435863739SMike Smith { 109535863739SMike Smith struct aac_command *cm; 109635863739SMike Smith 109735863739SMike Smith debug_called(3); 109835863739SMike Smith 10990b94a66eSMike Smith if ((cm = aac_dequeue_free(sc)) == NULL) 110035863739SMike Smith return(ENOMEM); 110135863739SMike Smith 11020b94a66eSMike Smith *cmp = cm; 11030b94a66eSMike Smith return(0); 11040b94a66eSMike Smith } 11050b94a66eSMike Smith 1106914da7d0SScott Long /* 11070b94a66eSMike Smith * Release a command back to the freelist. 11080b94a66eSMike Smith */ 1109fe3cb0e1SScott Long void 11100b94a66eSMike Smith aac_release_command(struct aac_command *cm) 11110b94a66eSMike Smith { 11120b94a66eSMike Smith debug_called(3); 11130b94a66eSMike Smith 11140b94a66eSMike Smith /* (re)initialise the command/FIB */ 111535863739SMike Smith cm->cm_sgtable = NULL; 111635863739SMike Smith cm->cm_flags = 0; 111735863739SMike Smith cm->cm_complete = NULL; 111835863739SMike Smith cm->cm_private = NULL; 111935863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 112035863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 112135863739SMike Smith cm->cm_fib->Header.Flags = 0; 112235863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 112335863739SMike Smith 112435863739SMike Smith /* 112535863739SMike Smith * These are duplicated in aac_start to cover the case where an 112635863739SMike Smith * intermediate stage may have destroyed them. They're left 112735863739SMike Smith * initialised here for debugging purposes only. 112835863739SMike Smith */ 112935863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1130f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1131f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 113235863739SMike Smith 113335863739SMike Smith aac_enqueue_free(cm); 113435863739SMike Smith } 113535863739SMike Smith 1136914da7d0SScott Long /* 11370b94a66eSMike Smith * Map helper for command/FIB allocation. 113835863739SMike Smith */ 113935863739SMike Smith static void 11400b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 114135863739SMike Smith { 1142914da7d0SScott Long struct aac_softc *sc; 1143914da7d0SScott Long 1144914da7d0SScott Long sc = (struct aac_softc *)arg; 114535863739SMike Smith 114635863739SMike Smith debug_called(3); 114735863739SMike Smith 11480b94a66eSMike Smith sc->aac_fibphys = segs[0].ds_addr; 114935863739SMike Smith } 115035863739SMike Smith 1151914da7d0SScott Long /* 11520b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 115335863739SMike Smith */ 11540b94a66eSMike Smith static int 11550b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 115635863739SMike Smith { 115735863739SMike Smith struct aac_command *cm; 115835863739SMike Smith int i; 115935863739SMike Smith 116035863739SMike Smith debug_called(1); 116135863739SMike Smith 11620b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1163c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, 1164c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_fibmap)) { 116570545d1aSScott Long device_printf(sc->aac_dev, 116670545d1aSScott Long "Not enough contiguous memory available.\n"); 11670b94a66eSMike Smith return (ENOMEM); 116835863739SMike Smith } 1169128aa5a0SScott Long 1170128aa5a0SScott Long /* 1171128aa5a0SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1172128aa5a0SScott Long * below address 8192 in physical memory. 1173128aa5a0SScott Long * XXX If the padding is not needed, can it be put to use instead 1174128aa5a0SScott Long * of ignored? 1175128aa5a0SScott Long */ 11760b94a66eSMike Smith bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 1177128aa5a0SScott Long 8192 + AAC_FIB_COUNT * sizeof(struct aac_fib), 1178c6eafcf2SScott Long aac_map_command_helper, sc, 0); 1179128aa5a0SScott Long 1180128aa5a0SScott Long if (sc->aac_fibphys < 8192) { 1181128aa5a0SScott Long sc->aac_fibs += (8192 / sizeof(struct aac_fib)); 1182128aa5a0SScott Long sc->aac_fibphys += 8192; 1183128aa5a0SScott Long } 1184128aa5a0SScott Long 11850b94a66eSMike Smith /* initialise constant fields in the command structure */ 1186128aa5a0SScott Long bzero(sc->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11870b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11880b94a66eSMike Smith cm = &sc->aac_command[i]; 118935863739SMike Smith cm->cm_sc = sc; 11900b94a66eSMike Smith cm->cm_fib = sc->aac_fibs + i; 11910b94a66eSMike Smith cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); 119235863739SMike Smith 119335863739SMike Smith if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) 119435863739SMike Smith aac_release_command(cm); 119535863739SMike Smith } 11960b94a66eSMike Smith return (0); 119735863739SMike Smith } 119835863739SMike Smith 1199914da7d0SScott Long /* 12000b94a66eSMike Smith * Free FIBs owned by this adapter. 120135863739SMike Smith */ 120235863739SMike Smith static void 12030b94a66eSMike Smith aac_free_commands(struct aac_softc *sc) 120435863739SMike Smith { 120535863739SMike Smith int i; 120635863739SMike Smith 120735863739SMike Smith debug_called(1); 120835863739SMike Smith 12090b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) 1210914da7d0SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, 1211914da7d0SScott Long sc->aac_command[i].cm_datamap); 1212914da7d0SScott Long 12130b94a66eSMike Smith bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); 12140b94a66eSMike Smith bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); 121535863739SMike Smith } 121635863739SMike Smith 1217914da7d0SScott Long /* 121835863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 121935863739SMike Smith */ 122035863739SMike Smith static void 122135863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 122235863739SMike Smith { 1223914da7d0SScott Long struct aac_command *cm; 1224914da7d0SScott Long struct aac_fib *fib; 122535863739SMike Smith struct aac_sg_table *sg; 122635863739SMike Smith int i; 122735863739SMike Smith 122835863739SMike Smith debug_called(3); 122935863739SMike Smith 1230914da7d0SScott Long cm = (struct aac_command *)arg; 1231914da7d0SScott Long fib = cm->cm_fib; 1232914da7d0SScott Long 123335863739SMike Smith /* find the s/g table */ 123435863739SMike Smith sg = cm->cm_sgtable; 123535863739SMike Smith 123635863739SMike Smith /* copy into the FIB */ 123735863739SMike Smith if (sg != NULL) { 123835863739SMike Smith sg->SgCount = nseg; 123935863739SMike Smith for (i = 0; i < nseg; i++) { 124035863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 124135863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 124235863739SMike Smith } 124335863739SMike Smith /* update the FIB size for the s/g count */ 124435863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 124535863739SMike Smith } 124635863739SMike Smith 124735863739SMike Smith } 124835863739SMike Smith 1249914da7d0SScott Long /* 125035863739SMike Smith * Map a command into controller-visible space. 125135863739SMike Smith */ 125235863739SMike Smith static void 125335863739SMike Smith aac_map_command(struct aac_command *cm) 125435863739SMike Smith { 1255914da7d0SScott Long struct aac_softc *sc; 125635863739SMike Smith 125735863739SMike Smith debug_called(2); 125835863739SMike Smith 1259914da7d0SScott Long sc = cm->cm_sc; 1260914da7d0SScott Long 126135863739SMike Smith /* don't map more than once */ 126235863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 126335863739SMike Smith return; 126435863739SMike Smith 126535863739SMike Smith if (cm->cm_datalen != 0) { 1266914da7d0SScott Long bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 1267914da7d0SScott Long cm->cm_data, cm->cm_datalen, 1268914da7d0SScott Long aac_map_command_sg, cm, 0); 126935863739SMike Smith 127035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1271c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1272c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 127335863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1274c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1275c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 127635863739SMike Smith } 127735863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 127835863739SMike Smith } 127935863739SMike Smith 1280914da7d0SScott Long /* 128135863739SMike Smith * Unmap a command from controller-visible space. 128235863739SMike Smith */ 128335863739SMike Smith static void 128435863739SMike Smith aac_unmap_command(struct aac_command *cm) 128535863739SMike Smith { 1286914da7d0SScott Long struct aac_softc *sc; 128735863739SMike Smith 128835863739SMike Smith debug_called(2); 128935863739SMike Smith 1290914da7d0SScott Long sc = cm->cm_sc; 1291914da7d0SScott Long 129235863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 129335863739SMike Smith return; 129435863739SMike Smith 129535863739SMike Smith if (cm->cm_datalen != 0) { 129635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1297c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1298c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 129935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1300c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1301c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 130235863739SMike Smith 130335863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 130435863739SMike Smith } 130535863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 130635863739SMike Smith } 130735863739SMike Smith 1308914da7d0SScott Long /* 1309914da7d0SScott Long * Hardware Interface 1310914da7d0SScott Long */ 131135863739SMike Smith 1312914da7d0SScott Long /* 131335863739SMike Smith * Initialise the adapter. 131435863739SMike Smith */ 131535863739SMike Smith static void 131635863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 131735863739SMike Smith { 1318914da7d0SScott Long struct aac_softc *sc; 131935863739SMike Smith 132035863739SMike Smith debug_called(1); 132135863739SMike Smith 1322914da7d0SScott Long sc = (struct aac_softc *)arg; 1323914da7d0SScott Long 132435863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 132535863739SMike Smith } 132635863739SMike Smith 1327fe94b852SScott Long /* 1328fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1329fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1330fe94b852SScott Long */ 1331fe94b852SScott Long static int 1332fe94b852SScott Long aac_check_firmware(struct aac_softc *sc) 1333fe94b852SScott Long { 1334fe94b852SScott Long u_int32_t major, minor; 1335fe94b852SScott Long 1336fe94b852SScott Long debug_called(1); 1337fe94b852SScott Long 1338fe94b852SScott Long if (sc->quirks & AAC_QUIRK_PERC2QC) { 1339fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1340fe94b852SScott Long NULL)) { 1341fe94b852SScott Long device_printf(sc->aac_dev, 1342fe94b852SScott Long "Error reading firmware version\n"); 1343fe94b852SScott Long return (EIO); 1344fe94b852SScott Long } 1345fe94b852SScott Long 1346fe94b852SScott Long /* These numbers are stored as ASCII! */ 1347fe94b852SScott Long major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30; 1348fe94b852SScott Long minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30; 1349fe94b852SScott Long if (major == 1) { 1350fe94b852SScott Long device_printf(sc->aac_dev, 1351fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1352fe94b852SScott Long major, minor); 1353fe94b852SScott Long return (EINVAL); 1354fe94b852SScott Long } 1355fe94b852SScott Long } 1356fe94b852SScott Long 1357fe94b852SScott Long return (0); 1358fe94b852SScott Long } 1359fe94b852SScott Long 136035863739SMike Smith static int 136135863739SMike Smith aac_init(struct aac_softc *sc) 136235863739SMike Smith { 136335863739SMike Smith struct aac_adapter_init *ip; 136435863739SMike Smith time_t then; 136535863739SMike Smith u_int32_t code; 136635863739SMike Smith u_int8_t *qaddr; 136735863739SMike Smith 136835863739SMike Smith debug_called(1); 136935863739SMike Smith 137035863739SMike Smith /* 137135863739SMike Smith * First wait for the adapter to come ready. 137235863739SMike Smith */ 137335863739SMike Smith then = time_second; 137435863739SMike Smith do { 137535863739SMike Smith code = AAC_GET_FWSTATUS(sc); 137635863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 137735863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 137835863739SMike Smith return(ENXIO); 137935863739SMike Smith } 138035863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1381914da7d0SScott Long device_printf(sc->aac_dev, 1382914da7d0SScott Long "FATAL: controller kernel panic\n"); 138335863739SMike Smith return(ENXIO); 138435863739SMike Smith } 138535863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1386914da7d0SScott Long device_printf(sc->aac_dev, 1387914da7d0SScott Long "FATAL: controller not coming ready, " 1388c6eafcf2SScott Long "status %x\n", code); 138935863739SMike Smith return(ENXIO); 139035863739SMike Smith } 139135863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 139235863739SMike Smith 139335863739SMike Smith /* 139435863739SMike Smith * Create DMA tag for the common structure and allocate it. 139535863739SMike Smith */ 139635863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1397c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1398fe3cb0e1SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 139935863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 140035863739SMike Smith NULL, NULL, /* filter, filterarg */ 1401914da7d0SScott Long sizeof(struct aac_common), /* maxsize */ 1402914da7d0SScott Long 1, /* nsegments */ 140335863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 140435863739SMike Smith 0, /* flags */ 140535863739SMike Smith &sc->aac_common_dmat)) { 1406914da7d0SScott Long device_printf(sc->aac_dev, 1407914da7d0SScott Long "can't allocate common structure DMA tag\n"); 140835863739SMike Smith return(ENOMEM); 140935863739SMike Smith } 1410c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1411c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 141235863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 141335863739SMike Smith return(ENOMEM); 141435863739SMike Smith } 1415914da7d0SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1416914da7d0SScott Long sc->aac_common, sizeof(*sc->aac_common), aac_common_map, 1417914da7d0SScott Long sc, 0); 141835863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 141935863739SMike Smith 142035863739SMike Smith /* 1421914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1422914da7d0SScott Long * physical location of various important shared data structures. 142335863739SMike Smith */ 142435863739SMike Smith ip = &sc->aac_common->ac_init; 142535863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1426f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 142735863739SMike Smith 1428c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1429c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1430f30ac74cSScott Long ip->AdapterFibsVirtualAddress = (u_int32_t)&sc->aac_common->ac_fibs[0]; 143135863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 143235863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 143335863739SMike Smith 1434c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1435c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 143635863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 143735863739SMike Smith 1438f30ac74cSScott Long /* The adapter assumes that pages are 4K in size */ 1439f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 144035863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 144135863739SMike Smith 144235863739SMike Smith /* 1443c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1444c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1445c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 144635863739SMike Smith * 144735863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1448914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1449914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1450914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1451914da7d0SScott Long * does. 145235863739SMike Smith * 1453914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1454914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1455914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1456914da7d0SScott Long * virtue of a table. 145735863739SMike Smith */ 145835863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 145935863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 146035863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1461914da7d0SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + 1462914da7d0SScott Long ((u_int32_t)sc->aac_queues - 1463914da7d0SScott Long (u_int32_t)sc->aac_common); 146435863739SMike Smith 1465c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1466c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1467c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1468c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1469c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1470c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1471c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1472c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1473c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1474c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1475c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1476c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1477c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1478c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1479c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1480c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1481c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1482c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1483c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1484c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1485c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1486c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1487c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1488c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1489c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1490c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1491c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1492c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1493c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1494c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1495c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1496c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1497c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1498c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1499c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1500c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1501c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1502c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1503c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1504c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1505c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1506c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1507c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1508c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1509c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1510c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1511c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1512c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 151335863739SMike Smith 151435863739SMike Smith /* 151535863739SMike Smith * Do controller-type-specific initialisation 151635863739SMike Smith */ 151735863739SMike Smith switch (sc->aac_hwif) { 151835863739SMike Smith case AAC_HWIF_I960RX: 151935863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 152035863739SMike Smith break; 152135863739SMike Smith } 152235863739SMike Smith 152335863739SMike Smith /* 152435863739SMike Smith * Give the init structure to the controller. 152535863739SMike Smith */ 152635863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1527914da7d0SScott Long sc->aac_common_busaddr + 1528914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1529914da7d0SScott Long NULL)) { 1530914da7d0SScott Long device_printf(sc->aac_dev, 1531914da7d0SScott Long "error establishing init structure\n"); 153235863739SMike Smith return(EIO); 153335863739SMike Smith } 153435863739SMike Smith 153535863739SMike Smith return(0); 153635863739SMike Smith } 153735863739SMike Smith 1538914da7d0SScott Long /* 153935863739SMike Smith * Send a synchronous command to the controller and wait for a result. 154035863739SMike Smith */ 154135863739SMike Smith static int 154235863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 154335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 154435863739SMike Smith u_int32_t *sp) 154535863739SMike Smith { 154635863739SMike Smith time_t then; 154735863739SMike Smith u_int32_t status; 154835863739SMike Smith 154935863739SMike Smith debug_called(3); 155035863739SMike Smith 155135863739SMike Smith /* populate the mailbox */ 155235863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 155335863739SMike Smith 155435863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 155535863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 155635863739SMike Smith 155735863739SMike Smith /* then set it to signal the adapter */ 155835863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 155935863739SMike Smith 156035863739SMike Smith /* spin waiting for the command to complete */ 156135863739SMike Smith then = time_second; 156235863739SMike Smith do { 156335863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 156435863739SMike Smith debug(2, "timed out"); 156535863739SMike Smith return(EIO); 156635863739SMike Smith } 156735863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 156835863739SMike Smith 156935863739SMike Smith /* clear the completion flag */ 157035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 157135863739SMike Smith 157235863739SMike Smith /* get the command status */ 157335863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 157435863739SMike Smith if (sp != NULL) 157535863739SMike Smith *sp = status; 15760b94a66eSMike Smith return(0); 157735863739SMike Smith } 157835863739SMike Smith 1579914da7d0SScott Long /* 1580cbfd045bSScott Long * Grab the sync fib area. 1581cbfd045bSScott Long */ 1582cbfd045bSScott Long int 1583fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1584cbfd045bSScott Long { 1585cbfd045bSScott Long 1586cbfd045bSScott Long /* 1587cbfd045bSScott Long * If the force flag is set, the system is shutting down, or in 1588cbfd045bSScott Long * trouble. Ignore the mutex. 1589cbfd045bSScott Long */ 1590cbfd045bSScott Long if (!(flags & AAC_SYNC_LOCK_FORCE)) 1591cbfd045bSScott Long AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1592cbfd045bSScott Long 1593cbfd045bSScott Long *fib = &sc->aac_common->ac_sync_fib; 1594cbfd045bSScott Long 1595cbfd045bSScott Long return (1); 1596cbfd045bSScott Long } 1597cbfd045bSScott Long 1598cbfd045bSScott Long /* 1599cbfd045bSScott Long * Release the sync fib area. 1600cbfd045bSScott Long */ 1601cbfd045bSScott Long void 1602cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc) 1603cbfd045bSScott Long { 1604cbfd045bSScott Long 1605cbfd045bSScott Long AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1606cbfd045bSScott Long } 1607cbfd045bSScott Long 1608cbfd045bSScott Long /* 160935863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 161035863739SMike Smith */ 1611cbfd045bSScott Long int 161235863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1613cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 161435863739SMike Smith { 161535863739SMike Smith debug_called(3); 161635863739SMike Smith 161735863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 161835863739SMike Smith return(EINVAL); 161935863739SMike Smith 162035863739SMike Smith /* 162135863739SMike Smith * Set up the sync FIB 162235863739SMike Smith */ 1623914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1624914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1625c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 162635863739SMike Smith fib->Header.XferState |= xferstate; 162735863739SMike Smith fib->Header.Command = command; 162835863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 162935863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 163035863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 163135863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1632c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1633914da7d0SScott Long offsetof(struct aac_common, 1634914da7d0SScott Long ac_sync_fib); 163535863739SMike Smith 163635863739SMike Smith /* 163735863739SMike Smith * Give the FIB to the controller, wait for a response. 163835863739SMike Smith */ 1639914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1640914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 164135863739SMike Smith debug(2, "IO error"); 164235863739SMike Smith return(EIO); 164335863739SMike Smith } 164435863739SMike Smith 164535863739SMike Smith return (0); 164635863739SMike Smith } 164735863739SMike Smith 1648914da7d0SScott Long /* 164935863739SMike Smith * Adapter-space FIB queue manipulation 165035863739SMike Smith * 165135863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 165235863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 165335863739SMike Smith */ 165435863739SMike Smith static struct { 165535863739SMike Smith int size; 165635863739SMike Smith int notify; 165735863739SMike Smith } aac_qinfo[] = { 165835863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 165935863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 166035863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 166135863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 166235863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 166335863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 166435863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 166535863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 166635863739SMike Smith }; 166735863739SMike Smith 166835863739SMike Smith /* 1669c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1670c6eafcf2SScott Long * EBUSY if the queue is full. 167135863739SMike Smith * 16720b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1673914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1674914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1675c6eafcf2SScott Long * separate queue/notify interface). 167635863739SMike Smith */ 167735863739SMike Smith static int 1678f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 167935863739SMike Smith { 168035863739SMike Smith u_int32_t pi, ci; 168135863739SMike Smith int s, error; 1682f6c4dd3fSScott Long u_int32_t fib_size; 1683f6c4dd3fSScott Long u_int32_t fib_addr; 1684f6c4dd3fSScott Long 168536e0bf6eSScott Long debug_called(3); 168636e0bf6eSScott Long 1687f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1688f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 168935863739SMike Smith 169035863739SMike Smith s = splbio(); 169135863739SMike Smith 169235863739SMike Smith /* get the producer/consumer indices */ 169335863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 169435863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 169535863739SMike Smith 169635863739SMike Smith /* wrap the queue? */ 169735863739SMike Smith if (pi >= aac_qinfo[queue].size) 169835863739SMike Smith pi = 0; 169935863739SMike Smith 170035863739SMike Smith /* check for queue full */ 170135863739SMike Smith if ((pi + 1) == ci) { 170235863739SMike Smith error = EBUSY; 170335863739SMike Smith goto out; 170435863739SMike Smith } 170535863739SMike Smith 170635863739SMike Smith /* populate queue entry */ 170735863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 170835863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 170935863739SMike Smith 171035863739SMike Smith /* update producer index */ 171135863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 171235863739SMike Smith 1713f6c4dd3fSScott Long /* 1714914da7d0SScott Long * To avoid a race with its completion interrupt, place this command on 1715914da7d0SScott Long * the busy queue prior to advertising it to the controller. 1716f6c4dd3fSScott Long */ 1717f6c4dd3fSScott Long aac_enqueue_busy(cm); 1718f6c4dd3fSScott Long 171935863739SMike Smith /* notify the adapter if we know how */ 172035863739SMike Smith if (aac_qinfo[queue].notify != 0) 172135863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 172235863739SMike Smith 172335863739SMike Smith error = 0; 172435863739SMike Smith 172535863739SMike Smith out: 172635863739SMike Smith splx(s); 172735863739SMike Smith return(error); 172835863739SMike Smith } 172935863739SMike Smith 173035863739SMike Smith /* 173136e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 173236e0bf6eSScott Long * success or ENOENT if the queue is empty. 173335863739SMike Smith */ 173435863739SMike Smith static int 1735c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1736c6eafcf2SScott Long struct aac_fib **fib_addr) 173735863739SMike Smith { 173835863739SMike Smith u_int32_t pi, ci; 173935863739SMike Smith int s, error; 1740f6c4dd3fSScott Long int notify; 174135863739SMike Smith 174235863739SMike Smith debug_called(3); 174335863739SMike Smith 174435863739SMike Smith s = splbio(); 174535863739SMike Smith 174635863739SMike Smith /* get the producer/consumer indices */ 174735863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 174835863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 174935863739SMike Smith 175035863739SMike Smith /* check for queue empty */ 175135863739SMike Smith if (ci == pi) { 175235863739SMike Smith error = ENOENT; 175335863739SMike Smith goto out; 175435863739SMike Smith } 175535863739SMike Smith 1756f6c4dd3fSScott Long notify = 0; 1757f6c4dd3fSScott Long if (ci == pi + 1) 1758f6c4dd3fSScott Long notify++; 1759f6c4dd3fSScott Long 176035863739SMike Smith /* wrap the queue? */ 176135863739SMike Smith if (ci >= aac_qinfo[queue].size) 176235863739SMike Smith ci = 0; 176335863739SMike Smith 176435863739SMike Smith /* fetch the entry */ 176535863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1766914da7d0SScott Long *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + 1767914da7d0SScott Long ci)->aq_fib_addr; 176835863739SMike Smith 1769f30ac74cSScott Long /* 1770f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1771f30ac74cSScott Long * local memory so the whole fib doesn't have to be DMA'd back up. 1772f30ac74cSScott Long */ 1773f30ac74cSScott Long if (*(uintptr_t *)fib_addr & 0x01) { 1774f30ac74cSScott Long *(uintptr_t *)fib_addr &= ~0x01; 1775f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1776f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1777f30ac74cSScott Long } 177835863739SMike Smith /* update consumer index */ 177935863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 178035863739SMike Smith 178135863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1782f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 178335863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 178435863739SMike Smith error = 0; 178535863739SMike Smith 178635863739SMike Smith out: 178735863739SMike Smith splx(s); 178835863739SMike Smith return(error); 178935863739SMike Smith } 179035863739SMike Smith 1791914da7d0SScott Long /* 179236e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 179336e0bf6eSScott Long */ 179436e0bf6eSScott Long static int 179536e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 179636e0bf6eSScott Long { 179736e0bf6eSScott Long u_int32_t pi, ci; 179836e0bf6eSScott Long int s, error; 179936e0bf6eSScott Long u_int32_t fib_size; 180036e0bf6eSScott Long u_int32_t fib_addr; 180136e0bf6eSScott Long 180236e0bf6eSScott Long debug_called(1); 180336e0bf6eSScott Long 180436e0bf6eSScott Long /* Tell the adapter where the FIB is */ 180536e0bf6eSScott Long fib_size = fib->Header.Size; 180636e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 180736e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 180836e0bf6eSScott Long 180936e0bf6eSScott Long s = splbio(); 181036e0bf6eSScott Long 181136e0bf6eSScott Long /* get the producer/consumer indices */ 181236e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 181336e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 181436e0bf6eSScott Long 181536e0bf6eSScott Long /* wrap the queue? */ 181636e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 181736e0bf6eSScott Long pi = 0; 181836e0bf6eSScott Long 181936e0bf6eSScott Long /* check for queue full */ 182036e0bf6eSScott Long if ((pi + 1) == ci) { 182136e0bf6eSScott Long error = EBUSY; 182236e0bf6eSScott Long goto out; 182336e0bf6eSScott Long } 182436e0bf6eSScott Long 182536e0bf6eSScott Long /* populate queue entry */ 182636e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 182736e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 182836e0bf6eSScott Long 182936e0bf6eSScott Long /* update producer index */ 183036e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 183136e0bf6eSScott Long 183236e0bf6eSScott Long /* notify the adapter if we know how */ 183336e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 183436e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 183536e0bf6eSScott Long 183636e0bf6eSScott Long error = 0; 183736e0bf6eSScott Long 183836e0bf6eSScott Long out: 183936e0bf6eSScott Long splx(s); 184036e0bf6eSScott Long return(error); 184136e0bf6eSScott Long } 184236e0bf6eSScott Long 1843914da7d0SScott Long /* 18440b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 18450b94a66eSMike Smith * and complain about them. 18460b94a66eSMike Smith */ 18470b94a66eSMike Smith static void 18480b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 18490b94a66eSMike Smith { 18500b94a66eSMike Smith int s; 18510b94a66eSMike Smith struct aac_command *cm; 18520b94a66eSMike Smith time_t deadline; 18530b94a66eSMike Smith 1854f6c4dd3fSScott Long /* 185570545d1aSScott Long * Traverse the busy command list, bitch about late commands once 1856914da7d0SScott Long * only. 1857914da7d0SScott Long */ 18580b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 18590b94a66eSMike Smith s = splbio(); 18600b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1861f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1862f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 18630b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1864914da7d0SScott Long device_printf(sc->aac_dev, 1865914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1866f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 18670b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 18680b94a66eSMike Smith } 18690b94a66eSMike Smith } 18700b94a66eSMike Smith splx(s); 18710b94a66eSMike Smith 18720b94a66eSMike Smith return; 18730b94a66eSMike Smith } 18740b94a66eSMike Smith 1875914da7d0SScott Long /* 1876914da7d0SScott Long * Interface Function Vectors 1877914da7d0SScott Long */ 187835863739SMike Smith 1879914da7d0SScott Long /* 188035863739SMike Smith * Read the current firmware status word. 188135863739SMike Smith */ 188235863739SMike Smith static int 188335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 188435863739SMike Smith { 188535863739SMike Smith debug_called(3); 188635863739SMike Smith 188735863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 188835863739SMike Smith } 188935863739SMike Smith 189035863739SMike Smith static int 189135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 189235863739SMike Smith { 189335863739SMike Smith debug_called(3); 189435863739SMike Smith 189535863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 189635863739SMike Smith } 189735863739SMike Smith 1898b3457b51SScott Long static int 1899b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 1900b3457b51SScott Long { 1901b3457b51SScott Long int val; 1902b3457b51SScott Long 1903b3457b51SScott Long debug_called(3); 1904b3457b51SScott Long 1905b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 1906b3457b51SScott Long return (val); 1907b3457b51SScott Long } 1908b3457b51SScott Long 1909914da7d0SScott Long /* 191035863739SMike Smith * Notify the controller of a change in a given queue 191135863739SMike Smith */ 191235863739SMike Smith 191335863739SMike Smith static void 191435863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 191535863739SMike Smith { 191635863739SMike Smith debug_called(3); 191735863739SMike Smith 191835863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 191935863739SMike Smith } 192035863739SMike Smith 192135863739SMike Smith static void 192235863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 192335863739SMike Smith { 192435863739SMike Smith debug_called(3); 192535863739SMike Smith 192635863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 192735863739SMike Smith } 192835863739SMike Smith 1929b3457b51SScott Long static void 1930b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 1931b3457b51SScott Long { 1932b3457b51SScott Long debug_called(3); 1933b3457b51SScott Long 1934b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 1935b3457b51SScott Long AAC_FA_HACK(sc); 1936b3457b51SScott Long } 1937b3457b51SScott Long 1938914da7d0SScott Long /* 193935863739SMike Smith * Get the interrupt reason bits 194035863739SMike Smith */ 194135863739SMike Smith static int 194235863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 194335863739SMike Smith { 194435863739SMike Smith debug_called(3); 194535863739SMike Smith 194635863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 194735863739SMike Smith } 194835863739SMike Smith 194935863739SMike Smith static int 195035863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 195135863739SMike Smith { 195235863739SMike Smith debug_called(3); 195335863739SMike Smith 195435863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 195535863739SMike Smith } 195635863739SMike Smith 1957b3457b51SScott Long static int 1958b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 1959b3457b51SScott Long { 1960b3457b51SScott Long int val; 1961b3457b51SScott Long 1962b3457b51SScott Long debug_called(3); 1963b3457b51SScott Long 1964b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 1965b3457b51SScott Long return (val); 1966b3457b51SScott Long } 1967b3457b51SScott Long 1968914da7d0SScott Long /* 196935863739SMike Smith * Clear some interrupt reason bits 197035863739SMike Smith */ 197135863739SMike Smith static void 197235863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 197335863739SMike Smith { 197435863739SMike Smith debug_called(3); 197535863739SMike Smith 197635863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 197735863739SMike Smith } 197835863739SMike Smith 197935863739SMike Smith static void 198035863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 198135863739SMike Smith { 198235863739SMike Smith debug_called(3); 198335863739SMike Smith 198435863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 198535863739SMike Smith } 198635863739SMike Smith 1987b3457b51SScott Long static void 1988b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 1989b3457b51SScott Long { 1990b3457b51SScott Long debug_called(3); 1991b3457b51SScott Long 1992b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 1993b3457b51SScott Long AAC_FA_HACK(sc); 1994b3457b51SScott Long } 1995b3457b51SScott Long 1996914da7d0SScott Long /* 199735863739SMike Smith * Populate the mailbox and set the command word 199835863739SMike Smith */ 199935863739SMike Smith static void 200035863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 200135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 200235863739SMike Smith { 200335863739SMike Smith debug_called(4); 200435863739SMike Smith 200535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 200635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 200735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 200835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 200935863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 201035863739SMike Smith } 201135863739SMike Smith 201235863739SMike Smith static void 201335863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 201435863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 201535863739SMike Smith { 201635863739SMike Smith debug_called(4); 201735863739SMike Smith 201835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 201935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 202035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 202135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 202235863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 202335863739SMike Smith } 202435863739SMike Smith 2025b3457b51SScott Long static void 2026b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2027b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2028b3457b51SScott Long { 2029b3457b51SScott Long debug_called(4); 2030b3457b51SScott Long 2031b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2032b3457b51SScott Long AAC_FA_HACK(sc); 2033b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2034b3457b51SScott Long AAC_FA_HACK(sc); 2035b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2036b3457b51SScott Long AAC_FA_HACK(sc); 2037b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2038b3457b51SScott Long AAC_FA_HACK(sc); 2039b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2040b3457b51SScott Long AAC_FA_HACK(sc); 2041b3457b51SScott Long } 2042b3457b51SScott Long 2043914da7d0SScott Long /* 204435863739SMike Smith * Fetch the immediate command status word 204535863739SMike Smith */ 204635863739SMike Smith static int 204735863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 204835863739SMike Smith { 204935863739SMike Smith debug_called(4); 205035863739SMike Smith 205135863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 205235863739SMike Smith } 205335863739SMike Smith 205435863739SMike Smith static int 205535863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 205635863739SMike Smith { 205735863739SMike Smith debug_called(4); 205835863739SMike Smith 205935863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 206035863739SMike Smith } 206135863739SMike Smith 2062b3457b51SScott Long static int 2063b3457b51SScott Long aac_fa_get_mailboxstatus(struct aac_softc *sc) 2064b3457b51SScott Long { 2065b3457b51SScott Long int val; 2066b3457b51SScott Long 2067b3457b51SScott Long debug_called(4); 2068b3457b51SScott Long 2069b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX); 2070b3457b51SScott Long return (val); 2071b3457b51SScott Long } 2072b3457b51SScott Long 2073914da7d0SScott Long /* 207435863739SMike Smith * Set/clear interrupt masks 207535863739SMike Smith */ 207635863739SMike Smith static void 207735863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 207835863739SMike Smith { 207935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 208035863739SMike Smith 208135863739SMike Smith if (enable) { 208235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 208335863739SMike Smith } else { 208435863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 208535863739SMike Smith } 208635863739SMike Smith } 208735863739SMike Smith 208835863739SMike Smith static void 208935863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 209035863739SMike Smith { 209135863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 209235863739SMike Smith 209335863739SMike Smith if (enable) { 209435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 209535863739SMike Smith } else { 209635863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 209735863739SMike Smith } 209835863739SMike Smith } 209935863739SMike Smith 2100b3457b51SScott Long static void 2101b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2102b3457b51SScott Long { 2103b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2104b3457b51SScott Long 2105b3457b51SScott Long if (enable) { 2106b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2107b3457b51SScott Long AAC_FA_HACK(sc); 2108b3457b51SScott Long } else { 2109b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2110b3457b51SScott Long AAC_FA_HACK(sc); 2111b3457b51SScott Long } 2112b3457b51SScott Long } 2113b3457b51SScott Long 2114914da7d0SScott Long /* 2115914da7d0SScott Long * Debugging and Diagnostics 2116914da7d0SScott Long */ 211735863739SMike Smith 2118914da7d0SScott Long /* 211935863739SMike Smith * Print some information about the controller. 212035863739SMike Smith */ 212135863739SMike Smith static void 212235863739SMike Smith aac_describe_controller(struct aac_softc *sc) 212335863739SMike Smith { 2124cbfd045bSScott Long struct aac_fib *fib; 212535863739SMike Smith struct aac_adapter_info *info; 212635863739SMike Smith 212735863739SMike Smith debug_called(2); 212835863739SMike Smith 2129fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2130cbfd045bSScott Long 2131cbfd045bSScott Long fib->data[0] = 0; 2132cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 213335863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2134fe3cb0e1SScott Long aac_release_sync_fib(sc); 213535863739SMike Smith return; 213635863739SMike Smith } 2137cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 213835863739SMike Smith 213936e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2140c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 214136e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2142914da7d0SScott Long aac_describe_code(aac_battery_platform, 2143914da7d0SScott Long info->batteryPlatform)); 214435863739SMike Smith 214535863739SMike Smith /* save the kernel revision structure for later use */ 214635863739SMike Smith sc->aac_revision = info->KernelRevision; 214736e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 214835863739SMike Smith info->KernelRevision.external.comp.major, 214935863739SMike Smith info->KernelRevision.external.comp.minor, 215035863739SMike Smith info->KernelRevision.external.comp.dash, 215136e0bf6eSScott Long info->KernelRevision.buildNumber, 215236e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2153fe3cb0e1SScott Long 2154fe3cb0e1SScott Long aac_release_sync_fib(sc); 215535863739SMike Smith } 215635863739SMike Smith 2157914da7d0SScott Long /* 215835863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 215935863739SMike Smith * same. 216035863739SMike Smith */ 216135863739SMike Smith static char * 216235863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 216335863739SMike Smith { 216435863739SMike Smith int i; 216535863739SMike Smith 216635863739SMike Smith for (i = 0; table[i].string != NULL; i++) 216735863739SMike Smith if (table[i].code == code) 216835863739SMike Smith return(table[i].string); 216935863739SMike Smith return(table[i + 1].string); 217035863739SMike Smith } 217135863739SMike Smith 2172914da7d0SScott Long /* 2173914da7d0SScott Long * Management Interface 2174914da7d0SScott Long */ 217535863739SMike Smith 217635863739SMike Smith static int 2177c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 217835863739SMike Smith { 2179914da7d0SScott Long struct aac_softc *sc; 218035863739SMike Smith 218135863739SMike Smith debug_called(2); 218235863739SMike Smith 2183914da7d0SScott Long sc = dev->si_drv1; 2184914da7d0SScott Long 218535863739SMike Smith /* Check to make sure the device isn't already open */ 218635863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 218735863739SMike Smith return EBUSY; 218835863739SMike Smith } 218935863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 219035863739SMike Smith 219135863739SMike Smith return 0; 219235863739SMike Smith } 219335863739SMike Smith 219435863739SMike Smith static int 2195c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 219635863739SMike Smith { 2197914da7d0SScott Long struct aac_softc *sc; 219835863739SMike Smith 219935863739SMike Smith debug_called(2); 220035863739SMike Smith 2201914da7d0SScott Long sc = dev->si_drv1; 2202914da7d0SScott Long 220335863739SMike Smith /* Mark this unit as no longer open */ 220435863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 220535863739SMike Smith 220635863739SMike Smith return 0; 220735863739SMike Smith } 220835863739SMike Smith 220935863739SMike Smith static int 2210c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 221135863739SMike Smith { 2212914da7d0SScott Long union aac_statrequest *as; 2213914da7d0SScott Long struct aac_softc *sc; 22140b94a66eSMike Smith int error = 0; 22150b94a66eSMike Smith int i; 221635863739SMike Smith 221735863739SMike Smith debug_called(2); 221835863739SMike Smith 2219914da7d0SScott Long as = (union aac_statrequest *)arg; 2220914da7d0SScott Long sc = dev->si_drv1; 2221914da7d0SScott Long 222235863739SMike Smith switch (cmd) { 22230b94a66eSMike Smith case AACIO_STATS: 22240b94a66eSMike Smith switch (as->as_item) { 22250b94a66eSMike Smith case AACQ_FREE: 22260b94a66eSMike Smith case AACQ_BIO: 22270b94a66eSMike Smith case AACQ_READY: 22280b94a66eSMike Smith case AACQ_BUSY: 22290b94a66eSMike Smith case AACQ_COMPLETE: 2230c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2231c6eafcf2SScott Long sizeof(struct aac_qstat)); 22320b94a66eSMike Smith break; 22330b94a66eSMike Smith default: 22340b94a66eSMike Smith error = ENOENT; 22350b94a66eSMike Smith break; 22360b94a66eSMike Smith } 22370b94a66eSMike Smith break; 22380b94a66eSMike Smith 223935863739SMike Smith case FSACTL_SENDFIB: 2240fb0c27d7SScott Long arg = *(caddr_t*)arg; 2241fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 22420b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 224335863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 224435863739SMike Smith break; 224535863739SMike Smith case FSACTL_AIF_THREAD: 2246fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 22470b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 224835863739SMike Smith error = EINVAL; 224935863739SMike Smith break; 225035863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2251fb0c27d7SScott Long arg = *(caddr_t*)arg; 2252fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 22530b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 225435863739SMike Smith /* 225535863739SMike Smith * Pass the caller out an AdapterFibContext. 225635863739SMike Smith * 225735863739SMike Smith * Note that because we only support one opener, we 225835863739SMike Smith * basically ignore this. Set the caller's context to a magic 225935863739SMike Smith * number just in case. 22600b94a66eSMike Smith * 22610b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 22620b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2263914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2264914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 226535863739SMike Smith */ 226636e0bf6eSScott Long i = (int)sc->aifthread; 226735863739SMike Smith error = copyout(&i, arg, sizeof(i)); 226835863739SMike Smith break; 226935863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2270fb0c27d7SScott Long arg = *(caddr_t*)arg; 2271fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 22720b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2273fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 227435863739SMike Smith break; 227535863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2276fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 22770b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 227835863739SMike Smith /* don't do anything here */ 227935863739SMike Smith break; 228035863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2281fb0c27d7SScott Long arg = *(caddr_t*)arg; 2282fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 22830b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2284fb0c27d7SScott Long error = aac_rev_check(sc, arg); 228535863739SMike Smith break; 228636e0bf6eSScott Long case FSACTL_QUERY_DISK: 228736e0bf6eSScott Long arg = *(caddr_t*)arg; 228836e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 228936e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 229036e0bf6eSScott Long error = aac_query_disk(sc, arg); 229136e0bf6eSScott Long break; 229236e0bf6eSScott Long case FSACTL_DELETE_DISK: 229336e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2294914da7d0SScott Long /* 2295914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2296914da7d0SScott Long * container, rather we rely on an AIF coming from the 2297914da7d0SScott Long * controller 2298914da7d0SScott Long */ 229936e0bf6eSScott Long error = 0; 230036e0bf6eSScott Long break; 230135863739SMike Smith default: 2302b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 230335863739SMike Smith error = EINVAL; 230435863739SMike Smith break; 230535863739SMike Smith } 230635863739SMike Smith return(error); 230735863739SMike Smith } 230835863739SMike Smith 2309b3457b51SScott Long static int 2310c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td) 2311b3457b51SScott Long { 2312b3457b51SScott Long struct aac_softc *sc; 2313b3457b51SScott Long int revents; 2314b3457b51SScott Long 2315b3457b51SScott Long sc = dev->si_drv1; 2316b3457b51SScott Long revents = 0; 2317b3457b51SScott Long 2318c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2319b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2320b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2321b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2322b3457b51SScott Long } 2323b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2324b3457b51SScott Long 2325b3457b51SScott Long if (revents == 0) { 2326b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2327b3457b51SScott Long selrecord(td, &sc->rcv_select); 2328b3457b51SScott Long } 2329b3457b51SScott Long 2330b3457b51SScott Long return (revents); 2331b3457b51SScott Long } 2332b3457b51SScott Long 2333914da7d0SScott Long /* 233435863739SMike Smith * Send a FIB supplied from userspace 233535863739SMike Smith */ 233635863739SMike Smith static int 233735863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 233835863739SMike Smith { 233935863739SMike Smith struct aac_command *cm; 234035863739SMike Smith int size, error; 234135863739SMike Smith 234235863739SMike Smith debug_called(2); 234335863739SMike Smith 234435863739SMike Smith cm = NULL; 234535863739SMike Smith 234635863739SMike Smith /* 234735863739SMike Smith * Get a command 234835863739SMike Smith */ 234935863739SMike Smith if (aac_alloc_command(sc, &cm)) { 235035863739SMike Smith error = EBUSY; 235135863739SMike Smith goto out; 235235863739SMike Smith } 235335863739SMike Smith 235435863739SMike Smith /* 235535863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 235635863739SMike Smith */ 2357914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2358914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 235935863739SMike Smith goto out; 236035863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 236135863739SMike Smith if (size > sizeof(struct aac_fib)) { 2362914da7d0SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2363914da7d0SScott Long size, sizeof(struct aac_fib)); 236435863739SMike Smith size = sizeof(struct aac_fib); 236535863739SMike Smith } 236635863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 236735863739SMike Smith goto out; 236835863739SMike Smith cm->cm_fib->Header.Size = size; 2369f6c4dd3fSScott Long cm->cm_timestamp = time_second; 237035863739SMike Smith 237135863739SMike Smith /* 237235863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 237335863739SMike Smith */ 2374b3457b51SScott Long if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 237570545d1aSScott Long device_printf(sc->aac_dev, 237670545d1aSScott Long "aac_wait_command return %d\n", error); 237735863739SMike Smith goto out; 2378b3457b51SScott Long } 237935863739SMike Smith 238035863739SMike Smith /* 238135863739SMike Smith * Copy the FIB and data back out to the caller. 238235863739SMike Smith */ 238335863739SMike Smith size = cm->cm_fib->Header.Size; 238435863739SMike Smith if (size > sizeof(struct aac_fib)) { 2385914da7d0SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2386914da7d0SScott Long size, sizeof(struct aac_fib)); 238735863739SMike Smith size = sizeof(struct aac_fib); 238835863739SMike Smith } 238935863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 239035863739SMike Smith 239135863739SMike Smith out: 2392f6c4dd3fSScott Long if (cm != NULL) { 239335863739SMike Smith aac_release_command(cm); 2394f6c4dd3fSScott Long } 239535863739SMike Smith return(error); 239635863739SMike Smith } 239735863739SMike Smith 2398914da7d0SScott Long /* 239935863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 240036e0bf6eSScott Long * If the queue fills up, then drop the older entries. 240135863739SMike Smith */ 240235863739SMike Smith static void 240336e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 240435863739SMike Smith { 240536e0bf6eSScott Long struct aac_aif_command *aif; 240636e0bf6eSScott Long struct aac_container *co, *co_next; 2407cbfd045bSScott Long struct aac_mntinfo *mi; 2408cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 240936e0bf6eSScott Long u_int16_t rsize; 2410b3457b51SScott Long int next, found; 241136e0bf6eSScott Long int added = 0, i = 0; 241235863739SMike Smith 241335863739SMike Smith debug_called(2); 241435863739SMike Smith 241536e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 241636e0bf6eSScott Long aac_print_aif(sc, aif); 241736e0bf6eSScott Long 241836e0bf6eSScott Long /* Is it an event that we should care about? */ 241936e0bf6eSScott Long switch (aif->command) { 242036e0bf6eSScott Long case AifCmdEventNotify: 242136e0bf6eSScott Long switch (aif->data.EN.type) { 242236e0bf6eSScott Long case AifEnAddContainer: 242336e0bf6eSScott Long case AifEnDeleteContainer: 242436e0bf6eSScott Long /* 2425914da7d0SScott Long * A container was added or deleted, but the message 2426914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2427914da7d0SScott Long * containers and sort things out. 242836e0bf6eSScott Long */ 2429fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2430cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 243136e0bf6eSScott Long do { 243236e0bf6eSScott Long /* 2433914da7d0SScott Long * Ask the controller for its containers one at 2434914da7d0SScott Long * a time. 2435914da7d0SScott Long * XXX What if the controller's list changes 2436914da7d0SScott Long * midway through this enumaration? 243736e0bf6eSScott Long * XXX This should be done async. 243836e0bf6eSScott Long */ 243939ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 244039ee03c3SScott Long mi->Command = VM_NameServe; 244139ee03c3SScott Long mi->MntType = FT_FILESYS; 2442cbfd045bSScott Long mi->MntCount = i; 244336e0bf6eSScott Long rsize = sizeof(mir); 2444cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2445cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2446914da7d0SScott Long debug(2, "Error probing container %d\n", 2447914da7d0SScott Long i); 244836e0bf6eSScott Long continue; 244936e0bf6eSScott Long } 2450cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 245136e0bf6eSScott Long /* 2452914da7d0SScott Long * Check the container against our list. 2453914da7d0SScott Long * co->co_found was already set to 0 in a 2454914da7d0SScott Long * previous run. 245536e0bf6eSScott Long */ 2456cbfd045bSScott Long if ((mir->Status == ST_OK) && 2457cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 245836e0bf6eSScott Long found = 0; 2459914da7d0SScott Long TAILQ_FOREACH(co, 2460914da7d0SScott Long &sc->aac_container_tqh, 2461914da7d0SScott Long co_link) { 246236e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2463cbfd045bSScott Long mir->MntTable[0].ObjectId) { 246436e0bf6eSScott Long co->co_found = 1; 246536e0bf6eSScott Long found = 1; 246636e0bf6eSScott Long break; 246736e0bf6eSScott Long } 246836e0bf6eSScott Long } 2469914da7d0SScott Long /* 2470914da7d0SScott Long * If the container matched, continue 2471914da7d0SScott Long * in the list. 2472914da7d0SScott Long */ 247336e0bf6eSScott Long if (found) { 247436e0bf6eSScott Long i++; 247536e0bf6eSScott Long continue; 247636e0bf6eSScott Long } 247736e0bf6eSScott Long 247836e0bf6eSScott Long /* 2479914da7d0SScott Long * This is a new container. Do all the 248070545d1aSScott Long * appropriate things to set it up. 248170545d1aSScott Long */ 2482cbfd045bSScott Long aac_add_container(sc, mir, 1); 248336e0bf6eSScott Long added = 1; 248436e0bf6eSScott Long } 248536e0bf6eSScott Long i++; 2486cbfd045bSScott Long } while ((i < mir->MntRespCount) && 2487914da7d0SScott Long (i < AAC_MAX_CONTAINERS)); 2488cbfd045bSScott Long aac_release_sync_fib(sc); 248936e0bf6eSScott Long 249036e0bf6eSScott Long /* 2491914da7d0SScott Long * Go through our list of containers and see which ones 2492914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2493914da7d0SScott Long * list them they must have been deleted. Do the 2494914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2495914da7d0SScott Long * the co->co_found field. 249636e0bf6eSScott Long */ 249736e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 249836e0bf6eSScott Long while (co != NULL) { 249936e0bf6eSScott Long if (co->co_found == 0) { 2500914da7d0SScott Long device_delete_child(sc->aac_dev, 2501914da7d0SScott Long co->co_disk); 250236e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2503c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc-> 2504914da7d0SScott Long aac_container_lock); 2505914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2506914da7d0SScott Long co_link); 2507914da7d0SScott Long AAC_LOCK_RELEASE(&sc-> 2508914da7d0SScott Long aac_container_lock); 250936e0bf6eSScott Long FREE(co, M_AACBUF); 251036e0bf6eSScott Long co = co_next; 251136e0bf6eSScott Long } else { 251236e0bf6eSScott Long co->co_found = 0; 251336e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 251436e0bf6eSScott Long } 251536e0bf6eSScott Long } 251636e0bf6eSScott Long 251736e0bf6eSScott Long /* Attach the newly created containers */ 251836e0bf6eSScott Long if (added) 251936e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 252036e0bf6eSScott Long 252136e0bf6eSScott Long break; 252236e0bf6eSScott Long 252336e0bf6eSScott Long default: 252436e0bf6eSScott Long break; 252536e0bf6eSScott Long } 252636e0bf6eSScott Long 252736e0bf6eSScott Long default: 252836e0bf6eSScott Long break; 252936e0bf6eSScott Long } 253036e0bf6eSScott Long 253136e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2532c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 253335863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 253435863739SMike Smith if (next != sc->aac_aifq_tail) { 253535863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 253635863739SMike Smith sc->aac_aifq_head = next; 2537b3457b51SScott Long 2538b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 253935863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 254035863739SMike Smith wakeup(sc->aac_aifq); 2541b3457b51SScott Long /* Wakeup any poll()ers */ 2542b3457b51SScott Long selwakeup(&sc->rcv_select); 254335863739SMike Smith } 2544b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 254536e0bf6eSScott Long 254636e0bf6eSScott Long return; 254735863739SMike Smith } 254835863739SMike Smith 2549914da7d0SScott Long /* 25500b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 255136e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 255236e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 255336e0bf6eSScott Long * returning what the card reported. 255435863739SMike Smith */ 255535863739SMike Smith static int 2556fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 255735863739SMike Smith { 255835863739SMike Smith struct aac_rev_check rev_check; 255935863739SMike Smith struct aac_rev_check_resp rev_check_resp; 256035863739SMike Smith int error = 0; 256135863739SMike Smith 256235863739SMike Smith debug_called(2); 256335863739SMike Smith 256435863739SMike Smith /* 256535863739SMike Smith * Copyin the revision struct from userspace 256635863739SMike Smith */ 2567c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2568c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 256935863739SMike Smith return error; 257035863739SMike Smith } 257135863739SMike Smith 2572914da7d0SScott Long debug(2, "Userland revision= %d\n", 2573914da7d0SScott Long rev_check.callingRevision.buildNumber); 257435863739SMike Smith 257535863739SMike Smith /* 257635863739SMike Smith * Doctor up the response struct. 257735863739SMike Smith */ 257835863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2579914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2580914da7d0SScott Long sc->aac_revision.external.ul; 2581914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2582914da7d0SScott Long sc->aac_revision.buildNumber; 258335863739SMike Smith 2584c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2585c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 258635863739SMike Smith } 258735863739SMike Smith 2588914da7d0SScott Long /* 258935863739SMike Smith * Pass the caller the next AIF in their queue 259035863739SMike Smith */ 259135863739SMike Smith static int 2592fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 259335863739SMike Smith { 259435863739SMike Smith struct get_adapter_fib_ioctl agf; 259535863739SMike Smith int error, s; 259635863739SMike Smith 259735863739SMike Smith debug_called(2); 259835863739SMike Smith 259935863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 260035863739SMike Smith 260135863739SMike Smith /* 260235863739SMike Smith * Check the magic number that we gave the caller. 260335863739SMike Smith */ 260436e0bf6eSScott Long if (agf.AdapterFibContext != (int)sc->aifthread) { 260535863739SMike Smith error = EFAULT; 260635863739SMike Smith } else { 260735863739SMike Smith 260835863739SMike Smith s = splbio(); 2609fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 261035863739SMike Smith 261135863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 261235863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 261335863739SMike Smith while (error == EAGAIN) { 2614914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2615914da7d0SScott Long PCATCH, "aacaif", 0); 261635863739SMike Smith if (error == 0) 2617914da7d0SScott Long error = aac_return_aif(sc, 2618914da7d0SScott Long agf.AifFib); 261935863739SMike Smith } 262035863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 262135863739SMike Smith } 262235863739SMike Smith splx(s); 262335863739SMike Smith } 262435863739SMike Smith } 262535863739SMike Smith return(error); 262635863739SMike Smith } 262735863739SMike Smith 2628914da7d0SScott Long /* 26290b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 26300b94a66eSMike Smith */ 26310b94a66eSMike Smith static int 2632fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 26330b94a66eSMike Smith { 2634b3457b51SScott Long int error; 26350b94a66eSMike Smith 26360b94a66eSMike Smith debug_called(2); 26370b94a66eSMike Smith 2638c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 26390b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 26400b94a66eSMike Smith error = EAGAIN; 26410b94a66eSMike Smith } else { 2642c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2643c6eafcf2SScott Long sizeof(struct aac_aif_command)); 264436e0bf6eSScott Long if (error) 264570545d1aSScott Long device_printf(sc->aac_dev, 264670545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 26470b94a66eSMike Smith if (!error) 2648914da7d0SScott Long sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 2649914da7d0SScott Long AAC_AIFQ_LENGTH; 26500b94a66eSMike Smith } 2651b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 26520b94a66eSMike Smith return(error); 26530b94a66eSMike Smith } 265436e0bf6eSScott Long 2655914da7d0SScott Long /* 265636e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 265736e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 265836e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 265936e0bf6eSScott Long */ 266036e0bf6eSScott Long static int 266136e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 266236e0bf6eSScott Long { 266336e0bf6eSScott Long struct aac_query_disk query_disk; 266436e0bf6eSScott Long struct aac_container *co; 2665914da7d0SScott Long struct aac_disk *disk; 266636e0bf6eSScott Long int error, id; 266736e0bf6eSScott Long 266836e0bf6eSScott Long debug_called(2); 266936e0bf6eSScott Long 2670914da7d0SScott Long disk = NULL; 2671914da7d0SScott Long 2672914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2673914da7d0SScott Long sizeof(struct aac_query_disk)); 267436e0bf6eSScott Long if (error) 267536e0bf6eSScott Long return (error); 267636e0bf6eSScott Long 267736e0bf6eSScott Long id = query_disk.ContainerNumber; 267836e0bf6eSScott Long if (id == -1) 267936e0bf6eSScott Long return (EINVAL); 268036e0bf6eSScott Long 2681c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 268236e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 268336e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 268436e0bf6eSScott Long break; 268536e0bf6eSScott Long } 268636e0bf6eSScott Long 268736e0bf6eSScott Long if (co == NULL) { 268836e0bf6eSScott Long query_disk.Valid = 0; 268936e0bf6eSScott Long query_disk.Locked = 0; 269036e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 269136e0bf6eSScott Long } else { 269236e0bf6eSScott Long disk = device_get_softc(co->co_disk); 269336e0bf6eSScott Long query_disk.Valid = 1; 2694914da7d0SScott Long query_disk.Locked = 2695914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 269636e0bf6eSScott Long query_disk.Deleted = 0; 2697b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 269836e0bf6eSScott Long query_disk.Target = disk->unit; 269936e0bf6eSScott Long query_disk.Lun = 0; 270036e0bf6eSScott Long query_disk.UnMapped = 0; 2701914da7d0SScott Long bcopy(disk->ad_dev_t->si_name, 2702914da7d0SScott Long &query_disk.diskDeviceName[0], 10); 270336e0bf6eSScott Long } 270436e0bf6eSScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 270536e0bf6eSScott Long 2706914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2707914da7d0SScott Long sizeof(struct aac_query_disk)); 270836e0bf6eSScott Long 270936e0bf6eSScott Long return (error); 271036e0bf6eSScott Long } 271136e0bf6eSScott Long 2712fe3cb0e1SScott Long static void 2713fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2714fe3cb0e1SScott Long { 2715fe3cb0e1SScott Long struct aac_fib *fib; 2716fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2717fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2718fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2719fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2720fe3cb0e1SScott Long struct aac_getbusinf businfo; 272170545d1aSScott Long struct aac_sim *caminf; 2722fe3cb0e1SScott Long device_t child; 2723fe3cb0e1SScott Long int i, found, error; 2724fe3cb0e1SScott Long 2725fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2726fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 272739ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2728fe3cb0e1SScott Long 2729fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2730fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2731fe3cb0e1SScott Long c_cmd->param = 0; 2732fe3cb0e1SScott Long 2733fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2734fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2735fe3cb0e1SScott Long if (error) { 2736fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2737fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2738fe3cb0e1SScott Long aac_release_sync_fib(sc); 2739fe3cb0e1SScott Long return; 2740fe3cb0e1SScott Long } 2741fe3cb0e1SScott Long 2742fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2743fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2744fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2745fe3cb0e1SScott Long c_resp->Status); 2746fe3cb0e1SScott Long aac_release_sync_fib(sc); 2747fe3cb0e1SScott Long return; 2748fe3cb0e1SScott Long } 2749fe3cb0e1SScott Long 2750fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2751fe3cb0e1SScott Long 2752fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 275339ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 275439ee03c3SScott Long 2755fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2756fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2757fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2758fe3cb0e1SScott Long vmi->ObjId = 0; 2759fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2760fe3cb0e1SScott Long 2761fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2762fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2763fe3cb0e1SScott Long if (error) { 2764fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2765fe3cb0e1SScott Long error); 2766fe3cb0e1SScott Long aac_release_sync_fib(sc); 2767fe3cb0e1SScott Long return; 2768fe3cb0e1SScott Long } 2769fe3cb0e1SScott Long 2770fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2771fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2772fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2773fe3cb0e1SScott Long vmi_resp->Status); 2774fe3cb0e1SScott Long aac_release_sync_fib(sc); 2775fe3cb0e1SScott Long return; 2776fe3cb0e1SScott Long } 2777fe3cb0e1SScott Long 2778fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2779fe3cb0e1SScott Long aac_release_sync_fib(sc); 2780fe3cb0e1SScott Long 2781fe3cb0e1SScott Long found = 0; 2782fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2783fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2784fe3cb0e1SScott Long continue; 2785fe3cb0e1SScott Long 2786a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2787a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 2788fe3cb0e1SScott Long if (caminf == NULL) 2789fe3cb0e1SScott Long continue; 2790fe3cb0e1SScott Long 2791fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2792fe3cb0e1SScott Long if (child == NULL) { 2793fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2794fe3cb0e1SScott Long continue; 2795fe3cb0e1SScott Long } 2796fe3cb0e1SScott Long 2797fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2798fe3cb0e1SScott Long caminf->BusNumber = i; 2799fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2800fe3cb0e1SScott Long caminf->aac_sc = sc; 2801fe3cb0e1SScott Long 2802fe3cb0e1SScott Long device_set_ivars(child, caminf); 2803fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 280470545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2805fe3cb0e1SScott Long 2806fe3cb0e1SScott Long found = 1; 2807fe3cb0e1SScott Long } 2808fe3cb0e1SScott Long 2809fe3cb0e1SScott Long if (found) 2810fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2811fe3cb0e1SScott Long 2812fe3cb0e1SScott Long return; 2813fe3cb0e1SScott Long } 2814