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 8735863739SMike Smith /* Command Buffer Management */ 88c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 89c6eafcf2SScott Long int nseg, int error); 900b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 918480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9235863739SMike Smith static void aac_map_command(struct aac_command *cm); 9335863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9435863739SMike Smith 9535863739SMike Smith /* Hardware Interface */ 96c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 97c6eafcf2SScott Long int error); 98fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9935863739SMike Smith static int aac_init(struct aac_softc *sc); 10035863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 101c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 102c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 103c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 104f6c4dd3fSScott Long struct aac_command *cm); 105c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 106914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10736e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10836e0bf6eSScott Long struct aac_fib *fib); 10935863739SMike Smith 110b3457b51SScott Long /* Falcon/PPC interface */ 111b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 112b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 113b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 114b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 115b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 116b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 117b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 118b3457b51SScott Long static int aac_fa_get_mailboxstatus(struct aac_softc *sc); 119b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 120b3457b51SScott Long 121b3457b51SScott Long struct aac_interface aac_fa_interface = { 122b3457b51SScott Long aac_fa_get_fwstatus, 123b3457b51SScott Long aac_fa_qnotify, 124b3457b51SScott Long aac_fa_get_istatus, 125b3457b51SScott Long aac_fa_clear_istatus, 126b3457b51SScott Long aac_fa_set_mailbox, 127b3457b51SScott Long aac_fa_get_mailboxstatus, 128b3457b51SScott Long aac_fa_set_interrupts 129b3457b51SScott Long }; 130b3457b51SScott Long 13135863739SMike Smith /* StrongARM interface */ 13235863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13335863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13435863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13535863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13635863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 137c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 138c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 13935863739SMike Smith static int aac_sa_get_mailboxstatus(struct aac_softc *sc); 14035863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 14135863739SMike Smith 14235863739SMike Smith struct aac_interface aac_sa_interface = { 14335863739SMike Smith aac_sa_get_fwstatus, 14435863739SMike Smith aac_sa_qnotify, 14535863739SMike Smith aac_sa_get_istatus, 14635863739SMike Smith aac_sa_clear_istatus, 14735863739SMike Smith aac_sa_set_mailbox, 14835863739SMike Smith aac_sa_get_mailboxstatus, 14935863739SMike Smith aac_sa_set_interrupts 15035863739SMike Smith }; 15135863739SMike Smith 15235863739SMike Smith /* i960Rx interface */ 15335863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15435863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15535863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15635863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15735863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 158c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 159c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 16035863739SMike Smith static int aac_rx_get_mailboxstatus(struct aac_softc *sc); 16135863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 16235863739SMike Smith 16335863739SMike Smith struct aac_interface aac_rx_interface = { 16435863739SMike Smith aac_rx_get_fwstatus, 16535863739SMike Smith aac_rx_qnotify, 16635863739SMike Smith aac_rx_get_istatus, 16735863739SMike Smith aac_rx_clear_istatus, 16835863739SMike Smith aac_rx_set_mailbox, 16935863739SMike Smith aac_rx_get_mailboxstatus, 17035863739SMike Smith aac_rx_set_interrupts 17135863739SMike Smith }; 17235863739SMike Smith 17335863739SMike Smith /* Debugging and Diagnostics */ 17435863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1756965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 176c6eafcf2SScott Long u_int32_t code); 17735863739SMike Smith 17835863739SMike Smith /* Management Interface */ 17935863739SMike Smith static d_open_t aac_open; 18035863739SMike Smith static d_close_t aac_close; 18135863739SMike Smith static d_ioctl_t aac_ioctl; 182b3457b51SScott Long static d_poll_t aac_poll; 183c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 184c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 18536e0bf6eSScott Long struct aac_fib *fib); 186fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 187fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 188fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 18936e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 19035863739SMike Smith 19135863739SMike Smith #define AAC_CDEV_MAJOR 150 19235863739SMike Smith 19335863739SMike Smith static struct cdevsw aac_cdevsw = { 19435863739SMike Smith aac_open, /* open */ 19535863739SMike Smith aac_close, /* close */ 19635863739SMike Smith noread, /* read */ 19735863739SMike Smith nowrite, /* write */ 19835863739SMike Smith aac_ioctl, /* ioctl */ 199b3457b51SScott Long aac_poll, /* poll */ 20035863739SMike Smith nommap, /* mmap */ 20135863739SMike Smith nostrategy, /* strategy */ 20235863739SMike Smith "aac", /* name */ 20335863739SMike Smith AAC_CDEV_MAJOR, /* major */ 20435863739SMike Smith nodump, /* dump */ 20535863739SMike Smith nopsize, /* psize */ 20635863739SMike Smith 0, /* flags */ 20736e0bf6eSScott Long #if __FreeBSD_version < 500005 20836e0bf6eSScott Long -1, /* bmaj */ 20936e0bf6eSScott Long #endif 21035863739SMike Smith }; 21135863739SMike Smith 21236e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 21336e0bf6eSScott Long 2143d04a9d7SScott Long /* sysctl node */ 2153d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2163d04a9d7SScott Long 217914da7d0SScott Long /* 218914da7d0SScott Long * Device Interface 219914da7d0SScott Long */ 22035863739SMike Smith 221914da7d0SScott Long /* 22235863739SMike Smith * Initialise the controller and softc 22335863739SMike Smith */ 22435863739SMike Smith int 22535863739SMike Smith aac_attach(struct aac_softc *sc) 22635863739SMike Smith { 22735863739SMike Smith int error, unit; 22835863739SMike Smith 22935863739SMike Smith debug_called(1); 23035863739SMike Smith 23135863739SMike Smith /* 23235863739SMike Smith * Initialise per-controller queues. 23335863739SMike Smith */ 2340b94a66eSMike Smith aac_initq_free(sc); 2350b94a66eSMike Smith aac_initq_ready(sc); 2360b94a66eSMike Smith aac_initq_busy(sc); 2370b94a66eSMike Smith aac_initq_complete(sc); 2380b94a66eSMike Smith aac_initq_bio(sc); 23935863739SMike Smith 24035863739SMike Smith #if __FreeBSD_version >= 500005 24135863739SMike Smith /* 24235863739SMike Smith * Initialise command-completion task. 24335863739SMike Smith */ 24435863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 24535863739SMike Smith #endif 24635863739SMike Smith 24735863739SMike Smith /* disable interrupts before we enable anything */ 24835863739SMike Smith AAC_MASK_INTERRUPTS(sc); 24935863739SMike Smith 25035863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25135863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25235863739SMike Smith 25335863739SMike Smith /* 254fe94b852SScott Long * Check that the firmware on the card is supported. 255fe94b852SScott Long */ 256fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 257fe94b852SScott Long return(error); 258fe94b852SScott Long 259cbfd045bSScott Long /* Init the sync fib lock */ 260cbfd045bSScott Long AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 261cbfd045bSScott Long 2620b94a66eSMike Smith /* 26335863739SMike Smith * Initialise the adapter. 26435863739SMike Smith */ 2650b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 26635863739SMike Smith return(error); 26735863739SMike Smith 26835863739SMike Smith /* 26935863739SMike Smith * Print a little information about the controller. 27035863739SMike Smith */ 27135863739SMike Smith aac_describe_controller(sc); 27235863739SMike Smith 27335863739SMike Smith /* 27435863739SMike Smith * Register to probe our containers later. 27535863739SMike Smith */ 27636e0bf6eSScott Long TAILQ_INIT(&sc->aac_container_tqh); 277b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 278b3457b51SScott Long 279b3457b51SScott Long /* 280b3457b51SScott Long * Lock for the AIF queue 281b3457b51SScott Long */ 282b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 28336e0bf6eSScott Long 28435863739SMike Smith sc->aac_ich.ich_func = aac_startup; 28535863739SMike Smith sc->aac_ich.ich_arg = sc; 28635863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 287914da7d0SScott Long device_printf(sc->aac_dev, 288914da7d0SScott Long "can't establish configuration hook\n"); 28935863739SMike Smith return(ENXIO); 29035863739SMike Smith } 29135863739SMike Smith 29235863739SMike Smith /* 29335863739SMike Smith * Make the control device. 29435863739SMike Smith */ 29535863739SMike Smith unit = device_get_unit(sc->aac_dev); 2969e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 2979e9466baSRobert Watson 0640, "aac%d", unit); 29836e0bf6eSScott Long #if __FreeBSD_version > 500005 299157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3004aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 30136e0bf6eSScott Long #endif 30235863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 30335863739SMike Smith 30436e0bf6eSScott Long /* Create the AIF thread */ 30536e0bf6eSScott Long #if __FreeBSD_version > 500005 30670545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 307316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 30836e0bf6eSScott Long #else 30970545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 310914da7d0SScott Long &sc->aifthread, "aac%daif", unit)) 31136e0bf6eSScott Long #endif 31236e0bf6eSScott Long panic("Could not create AIF thread\n"); 31336e0bf6eSScott Long 31436e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3155f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3165f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3175f54d522SScott Long device_printf(sc->aac_dev, 3185f54d522SScott Long "shutdown event registration failed\n"); 31936e0bf6eSScott Long 320fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 32170545d1aSScott Long if (!(sc->quirks & AAC_QUIRK_NOCAM)) { 32270545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 323fe3cb0e1SScott Long aac_get_bus_info(sc); 32470545d1aSScott Long } 325fe3cb0e1SScott Long 32635863739SMike Smith return(0); 32735863739SMike Smith } 32835863739SMike Smith 329914da7d0SScott Long /* 33035863739SMike Smith * Probe for containers, create disks. 33135863739SMike Smith */ 33235863739SMike Smith static void 33335863739SMike Smith aac_startup(void *arg) 33435863739SMike Smith { 335914da7d0SScott Long struct aac_softc *sc; 336cbfd045bSScott Long struct aac_fib *fib; 337cbfd045bSScott Long struct aac_mntinfo *mi; 338cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 33936e0bf6eSScott Long int i = 0; 34035863739SMike Smith 34135863739SMike Smith debug_called(1); 34235863739SMike Smith 343914da7d0SScott Long sc = (struct aac_softc *)arg; 344914da7d0SScott Long 34535863739SMike Smith /* disconnect ourselves from the intrhook chain */ 34635863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 34735863739SMike Smith 348fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 349cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 350cbfd045bSScott Long 35135863739SMike Smith /* loop over possible containers */ 35236e0bf6eSScott Long do { 35335863739SMike Smith /* request information on this container */ 35439ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 35539ee03c3SScott Long mi->Command = VM_NameServe; 35639ee03c3SScott Long mi->MntType = FT_FILESYS; 357cbfd045bSScott Long mi->MntCount = i; 358cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 359cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 36035863739SMike Smith debug(2, "error probing container %d", i); 36135863739SMike Smith continue; 36235863739SMike Smith } 36335863739SMike Smith 364cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 365cbfd045bSScott Long aac_add_container(sc, mir, 0); 36636e0bf6eSScott Long i++; 367cbfd045bSScott Long } while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS)); 368cbfd045bSScott Long 369cbfd045bSScott Long aac_release_sync_fib(sc); 37035863739SMike Smith 37135863739SMike Smith /* poke the bus to actually attach the child devices */ 37235863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 37335863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 37435863739SMike Smith 37535863739SMike Smith /* mark the controller up */ 37635863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 37735863739SMike Smith 37835863739SMike Smith /* enable interrupts now */ 37935863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 38035863739SMike Smith } 38135863739SMike Smith 382914da7d0SScott Long /* 383914da7d0SScott Long * Create a device to respresent a new container 384914da7d0SScott Long */ 385914da7d0SScott Long static void 386cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 387914da7d0SScott Long { 388914da7d0SScott Long struct aac_container *co; 389914da7d0SScott Long device_t child; 390914da7d0SScott Long 391914da7d0SScott Long /* 392914da7d0SScott Long * Check container volume type for validity. Note that many of 393914da7d0SScott Long * the possible types may never show up. 394914da7d0SScott Long */ 395914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 396a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 397a761a1caSScott Long M_NOWAIT | M_ZERO); 398914da7d0SScott Long if (co == NULL) 399914da7d0SScott Long panic("Out of memory?!\n"); 400914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 401914da7d0SScott Long mir->MntTable[0].ObjectId, 402914da7d0SScott Long mir->MntTable[0].FileSystemName, 403914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 404914da7d0SScott Long 405fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 406914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 407914da7d0SScott Long else 408914da7d0SScott Long device_set_ivars(child, co); 409914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 410914da7d0SScott Long mir->MntTable[0].VolType)); 411914da7d0SScott Long co->co_disk = child; 412914da7d0SScott Long co->co_found = f; 413914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 414914da7d0SScott Long sizeof(struct aac_mntobj)); 415c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 416914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 417914da7d0SScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 418914da7d0SScott Long } 419914da7d0SScott Long } 420914da7d0SScott Long 421914da7d0SScott Long /* 42235863739SMike Smith * Free all of the resources associated with (sc) 42335863739SMike Smith * 42435863739SMike Smith * Should not be called if the controller is active. 42535863739SMike Smith */ 42635863739SMike Smith void 42735863739SMike Smith aac_free(struct aac_softc *sc) 42835863739SMike Smith { 429ffb37f33SScott Long 43035863739SMike Smith debug_called(1); 43135863739SMike Smith 43235863739SMike Smith /* remove the control device */ 43335863739SMike Smith if (sc->aac_dev_t != NULL) 43435863739SMike Smith destroy_dev(sc->aac_dev_t); 43535863739SMike Smith 4360b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 4378480cc63SScott Long aac_free_commands(sc); 4380b94a66eSMike Smith if (sc->aac_fib_dmat) 4390b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 44035863739SMike Smith 441ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 442ffb37f33SScott Long 44335863739SMike Smith /* destroy the common area */ 44435863739SMike Smith if (sc->aac_common) { 44535863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 446c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 447c6eafcf2SScott Long sc->aac_common_dmamap); 44835863739SMike Smith } 4490b94a66eSMike Smith if (sc->aac_common_dmat) 4500b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 45135863739SMike Smith 45235863739SMike Smith /* disconnect the interrupt handler */ 45335863739SMike Smith if (sc->aac_intr) 45435863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 45535863739SMike Smith if (sc->aac_irq != NULL) 456c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 457c6eafcf2SScott Long sc->aac_irq); 45835863739SMike Smith 45935863739SMike Smith /* destroy data-transfer DMA tag */ 46035863739SMike Smith if (sc->aac_buffer_dmat) 46135863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 46235863739SMike Smith 46335863739SMike Smith /* destroy the parent DMA tag */ 46435863739SMike Smith if (sc->aac_parent_dmat) 46535863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 46635863739SMike Smith 46735863739SMike Smith /* release the register window mapping */ 46835863739SMike Smith if (sc->aac_regs_resource != NULL) 469914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 470914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 47135863739SMike Smith } 47235863739SMike Smith 473914da7d0SScott Long /* 47435863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 47535863739SMike Smith */ 47635863739SMike Smith int 47735863739SMike Smith aac_detach(device_t dev) 47835863739SMike Smith { 479914da7d0SScott Long struct aac_softc *sc; 48070545d1aSScott Long struct aac_container *co; 48170545d1aSScott Long struct aac_sim *sim; 48235863739SMike Smith int error; 48335863739SMike Smith 48435863739SMike Smith debug_called(1); 48535863739SMike Smith 486914da7d0SScott Long sc = device_get_softc(dev); 487914da7d0SScott Long 48835863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 48935863739SMike Smith return(EBUSY); 49035863739SMike Smith 49170545d1aSScott Long /* Remove the child containers */ 492a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 493a761a1caSScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 49470545d1aSScott Long error = device_delete_child(dev, co->co_disk); 49570545d1aSScott Long if (error) 49670545d1aSScott Long return (error); 497a761a1caSScott Long free(co, M_AACBUF); 49870545d1aSScott Long } 49970545d1aSScott Long 50070545d1aSScott Long /* Remove the CAM SIMs */ 501a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 502a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 50370545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 50470545d1aSScott Long if (error) 50570545d1aSScott Long return (error); 506a761a1caSScott Long free(sim, M_AACBUF); 50770545d1aSScott Long } 50870545d1aSScott Long 50936e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 51036e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 51136e0bf6eSScott Long wakeup(sc->aifthread); 51236e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 51336e0bf6eSScott Long } 51436e0bf6eSScott Long 51536e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 51636e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 51736e0bf6eSScott Long 51835863739SMike Smith if ((error = aac_shutdown(dev))) 51935863739SMike Smith return(error); 52035863739SMike Smith 5215f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 5225f54d522SScott Long 52335863739SMike Smith aac_free(sc); 52435863739SMike Smith 52535863739SMike Smith return(0); 52635863739SMike Smith } 52735863739SMike Smith 528914da7d0SScott Long /* 52935863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 53035863739SMike Smith * 53135863739SMike Smith * This function is called before detach or system shutdown. 53235863739SMike Smith * 5330b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 53435863739SMike Smith * allow shutdown if any device is open. 53535863739SMike Smith */ 53635863739SMike Smith int 53735863739SMike Smith aac_shutdown(device_t dev) 53835863739SMike Smith { 539914da7d0SScott Long struct aac_softc *sc; 540cbfd045bSScott Long struct aac_fib *fib; 541cbfd045bSScott Long struct aac_close_command *cc; 542cbfd045bSScott Long int s; 54335863739SMike Smith 54435863739SMike Smith debug_called(1); 54535863739SMike Smith 546914da7d0SScott Long sc = device_get_softc(dev); 547914da7d0SScott Long 54835863739SMike Smith s = splbio(); 54935863739SMike Smith 55035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 55135863739SMike Smith 55235863739SMike Smith /* 55335863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 55435863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 55535863739SMike Smith * We've been closed and all I/O completed already 55635863739SMike Smith */ 55735863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 55835863739SMike Smith 559fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 560cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 561cbfd045bSScott Long 56239ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 563cbfd045bSScott Long cc->Command = VM_CloseAll; 564cbfd045bSScott Long cc->ContainerId = 0xffffffff; 565cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 566cbfd045bSScott Long sizeof(struct aac_close_command))) 56735863739SMike Smith printf("FAILED.\n"); 56870545d1aSScott Long else 56970545d1aSScott Long printf("done\n"); 57070545d1aSScott Long #if 0 571914da7d0SScott Long else { 572cbfd045bSScott Long fib->data[0] = 0; 57336e0bf6eSScott Long /* 574914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 57536e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 57636e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 57736e0bf6eSScott Long * driver module with the intent to reload it later. 57836e0bf6eSScott Long */ 579cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 580cbfd045bSScott Long fib, 1)) { 58135863739SMike Smith printf("FAILED.\n"); 58235863739SMike Smith } else { 58335863739SMike Smith printf("done.\n"); 58435863739SMike Smith } 58535863739SMike Smith } 58670545d1aSScott Long #endif 58735863739SMike Smith 58835863739SMike Smith AAC_MASK_INTERRUPTS(sc); 58935863739SMike Smith 59035863739SMike Smith splx(s); 59135863739SMike Smith return(0); 59235863739SMike Smith } 59335863739SMike Smith 594914da7d0SScott Long /* 59535863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 59635863739SMike Smith */ 59735863739SMike Smith int 59835863739SMike Smith aac_suspend(device_t dev) 59935863739SMike Smith { 600914da7d0SScott Long struct aac_softc *sc; 60135863739SMike Smith int s; 60235863739SMike Smith 60335863739SMike Smith debug_called(1); 604914da7d0SScott Long 605914da7d0SScott Long sc = device_get_softc(dev); 606914da7d0SScott Long 60735863739SMike Smith s = splbio(); 60835863739SMike Smith 60935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 61035863739SMike Smith 61135863739SMike Smith AAC_MASK_INTERRUPTS(sc); 61235863739SMike Smith splx(s); 61335863739SMike Smith return(0); 61435863739SMike Smith } 61535863739SMike Smith 616914da7d0SScott Long /* 61735863739SMike Smith * Bring the controller back to a state ready for operation. 61835863739SMike Smith */ 61935863739SMike Smith int 62035863739SMike Smith aac_resume(device_t dev) 62135863739SMike Smith { 622914da7d0SScott Long struct aac_softc *sc; 62335863739SMike Smith 62435863739SMike Smith debug_called(1); 625914da7d0SScott Long 626914da7d0SScott Long sc = device_get_softc(dev); 627914da7d0SScott Long 62835863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 62935863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 63035863739SMike Smith return(0); 63135863739SMike Smith } 63235863739SMike Smith 633914da7d0SScott Long /* 63435863739SMike Smith * Take an interrupt. 63535863739SMike Smith */ 63635863739SMike Smith void 63735863739SMike Smith aac_intr(void *arg) 63835863739SMike Smith { 639914da7d0SScott Long struct aac_softc *sc; 640f30ac74cSScott Long u_int32_t *resp_queue; 64170545d1aSScott Long u_int16_t reason; 64235863739SMike Smith 64335863739SMike Smith debug_called(2); 64435863739SMike Smith 645914da7d0SScott Long sc = (struct aac_softc *)arg; 646914da7d0SScott Long 647f30ac74cSScott Long /* 648f30ac74cSScott Long * Optimize the common case of adapter response interrupts. 649f30ac74cSScott Long * We must read from the card prior to processing the responses 650f30ac74cSScott Long * to ensure the clear is flushed prior to accessing the queues. 651f30ac74cSScott Long * Reading the queues from local memory might save us a PCI read. 652f30ac74cSScott Long */ 653f30ac74cSScott Long resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; 654f30ac74cSScott Long if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) 655f30ac74cSScott Long reason = AAC_DB_RESPONSE_READY; 656f30ac74cSScott Long else 65735863739SMike Smith reason = AAC_GET_ISTATUS(sc); 658f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 659f30ac74cSScott Long (void)AAC_GET_ISTATUS(sc); 660f30ac74cSScott Long 661f30ac74cSScott Long /* It's not ok to return here because of races with the previous step */ 662f30ac74cSScott Long if (reason & AAC_DB_RESPONSE_READY) 6639c3a7fceSScott Long /* handle completion processing */ 6649c3a7fceSScott Long taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 66535863739SMike Smith 666b3457b51SScott Long /* controller wants to talk to the log */ 66770545d1aSScott Long if (reason & AAC_DB_PRINTF) { 66870545d1aSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 66970545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_PRINTF; 67070545d1aSScott Long } else 67136e0bf6eSScott Long aac_print_printf(sc); 67270545d1aSScott Long } 67335863739SMike Smith 67435863739SMike Smith /* controller has a message for us? */ 67535863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 67636e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 67770545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_AIF; 67870545d1aSScott Long } else { 67970545d1aSScott Long /* 68070545d1aSScott Long * XXX If the kthread is dead and we're at this point, 68170545d1aSScott Long * there are bigger problems than just figuring out 68270545d1aSScott Long * what to do with an AIF. 68370545d1aSScott Long */ 68470545d1aSScott Long } 68570545d1aSScott Long 68670545d1aSScott Long } 68770545d1aSScott Long 68870545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) != 0) 68970545d1aSScott Long /* XXX Should this be done with cv_signal? */ 69036e0bf6eSScott Long wakeup(sc->aifthread); 69136e0bf6eSScott Long } 69235863739SMike Smith 693c6eafcf2SScott Long /* 694914da7d0SScott Long * Command Processing 695914da7d0SScott Long */ 69635863739SMike Smith 697914da7d0SScott Long /* 69835863739SMike Smith * Start as much queued I/O as possible on the controller 69935863739SMike Smith */ 700fe3cb0e1SScott Long void 70135863739SMike Smith aac_startio(struct aac_softc *sc) 70235863739SMike Smith { 70335863739SMike Smith struct aac_command *cm; 70435863739SMike Smith 70535863739SMike Smith debug_called(2); 70635863739SMike Smith 70735863739SMike Smith for (;;) { 708914da7d0SScott Long /* 709914da7d0SScott Long * Try to get a command that's been put off for lack of 710914da7d0SScott Long * resources 711914da7d0SScott Long */ 71235863739SMike Smith cm = aac_dequeue_ready(sc); 71335863739SMike Smith 714914da7d0SScott Long /* 715914da7d0SScott Long * Try to build a command off the bio queue (ignore error 716914da7d0SScott Long * return) 717914da7d0SScott Long */ 7180b94a66eSMike Smith if (cm == NULL) 71935863739SMike Smith aac_bio_command(sc, &cm); 72035863739SMike Smith 72135863739SMike Smith /* nothing to do? */ 72235863739SMike Smith if (cm == NULL) 72335863739SMike Smith break; 72435863739SMike Smith 72535863739SMike Smith /* try to give the command to the controller */ 72635863739SMike Smith if (aac_start(cm) == EBUSY) { 72735863739SMike Smith /* put it on the ready queue for later */ 72835863739SMike Smith aac_requeue_ready(cm); 72935863739SMike Smith break; 73035863739SMike Smith } 73135863739SMike Smith } 73235863739SMike Smith } 73335863739SMike Smith 734914da7d0SScott Long /* 73535863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 73635863739SMike Smith * last moment when possible. 73735863739SMike Smith */ 73835863739SMike Smith static int 73935863739SMike Smith aac_start(struct aac_command *cm) 74035863739SMike Smith { 741914da7d0SScott Long struct aac_softc *sc; 742ed5c5fb4SMike Smith int error; 74335863739SMike Smith 74435863739SMike Smith debug_called(2); 74535863739SMike Smith 746914da7d0SScott Long sc = cm->cm_sc; 747914da7d0SScott Long 74835863739SMike Smith /* get the command mapped */ 74935863739SMike Smith aac_map_command(cm); 75035863739SMike Smith 7510b94a66eSMike Smith /* fix up the address values in the FIB */ 75235863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 75335863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 75435863739SMike Smith 75535863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 756c6eafcf2SScott Long cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical 757c6eafcf2SScott Long * address issue */ 75835863739SMike Smith /* put the FIB on the outbound queue */ 75936e0bf6eSScott Long error = aac_enqueue_fib(sc, cm->cm_queue, cm); 7600b94a66eSMike Smith return(error); 76135863739SMike Smith } 76235863739SMike Smith 763914da7d0SScott Long /* 76435863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 76535863739SMike Smith */ 76635863739SMike Smith static void 76770545d1aSScott Long aac_command_thread(struct aac_softc *sc) 76835863739SMike Smith { 76935863739SMike Smith struct aac_fib *fib; 77035863739SMike Smith u_int32_t fib_size; 77136e0bf6eSScott Long int size; 77235863739SMike Smith 77336e0bf6eSScott Long debug_called(2); 77435863739SMike Smith 77536e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_RUNNING; 77636e0bf6eSScott Long 77736e0bf6eSScott Long while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 77870545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 77970545d1aSScott Long tsleep(sc->aifthread, PRIBIO, "aifthd", 78070545d1aSScott Long AAC_PERIODIC_INTERVAL * hz); 78136e0bf6eSScott Long 78270545d1aSScott Long /* While we're here, check to see if any commands are stuck */ 78370545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 78470545d1aSScott Long aac_timeout(sc); 78570545d1aSScott Long 78670545d1aSScott Long /* Check the hardware printf message buffer */ 78770545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) { 78870545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_PRINTF; 78970545d1aSScott Long aac_print_printf(sc); 79070545d1aSScott Long } 79170545d1aSScott Long 79270545d1aSScott Long while (sc->aifflags & AAC_AIFFLAGS_AIF) { 79370545d1aSScott Long 794914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 79570545d1aSScott Long &fib_size, &fib)) { 79670545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_AIF; 79735863739SMike Smith break; /* nothing to do */ 79870545d1aSScott Long } 79935863739SMike Smith 80036e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 80136e0bf6eSScott Long 80235863739SMike Smith switch (fib->Header.Command) { 80335863739SMike Smith case AifRequest: 80436e0bf6eSScott Long aac_handle_aif(sc, fib); 80535863739SMike Smith break; 80635863739SMike Smith default: 807914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 808914da7d0SScott Long "from controller\n"); 80935863739SMike Smith break; 81035863739SMike Smith } 81135863739SMike Smith 81236e0bf6eSScott Long if ((fib->Header.XferState == 0) || 81336e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 81436e0bf6eSScott Long break; 81536e0bf6eSScott Long 81670545d1aSScott Long /* Return the AIF to the controller. */ 81736e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 81836e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 81936e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 82036e0bf6eSScott Long 82136e0bf6eSScott Long /* XXX Compute the Size field? */ 82236e0bf6eSScott Long size = fib->Header.Size; 82336e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 82436e0bf6eSScott Long size = sizeof(struct aac_fib); 82536e0bf6eSScott Long fib->Header.Size = size; 82636e0bf6eSScott Long } 82736e0bf6eSScott Long /* 828914da7d0SScott Long * Since we did not generate this command, it 829914da7d0SScott Long * cannot go through the normal 830914da7d0SScott Long * enqueue->startio chain. 83136e0bf6eSScott Long */ 832914da7d0SScott Long aac_enqueue_response(sc, 833914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 834914da7d0SScott Long fib); 83536e0bf6eSScott Long } 83636e0bf6eSScott Long } 83736e0bf6eSScott Long } 83836e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 83936e0bf6eSScott Long wakeup(sc->aac_dev); 84036e0bf6eSScott Long 84136e0bf6eSScott Long #if __FreeBSD_version > 500005 84236e0bf6eSScott Long mtx_lock(&Giant); 84336e0bf6eSScott Long #endif 84436e0bf6eSScott Long kthread_exit(0); 84535863739SMike Smith } 84635863739SMike Smith 847914da7d0SScott Long /* 8489c3a7fceSScott Long * Process completed commands. 84935863739SMike Smith */ 85035863739SMike Smith static void 8519c3a7fceSScott Long aac_complete(void *context, int pending) 85235863739SMike Smith { 8539c3a7fceSScott Long struct aac_softc *sc; 85435863739SMike Smith struct aac_command *cm; 85535863739SMike Smith struct aac_fib *fib; 85635863739SMike Smith u_int32_t fib_size; 85735863739SMike Smith 85835863739SMike Smith debug_called(2); 85935863739SMike Smith 8609c3a7fceSScott Long sc = (struct aac_softc *)context; 8619c3a7fceSScott Long 8629c3a7fceSScott Long /* pull completed commands off the queue */ 86335863739SMike Smith for (;;) { 86435863739SMike Smith /* look for completed FIBs on our queue */ 865914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 866914da7d0SScott Long &fib)) 86735863739SMike Smith break; /* nothing to do */ 86835863739SMike Smith 86935863739SMike Smith /* get the command, unmap and queue for later processing */ 87035863739SMike Smith cm = (struct aac_command *)fib->Header.SenderData; 87135863739SMike Smith if (cm == NULL) { 87235863739SMike Smith AAC_PRINT_FIB(sc, fib); 8739c3a7fceSScott Long break; 8749c3a7fceSScott Long } 8759c3a7fceSScott Long 8760b94a66eSMike Smith aac_remove_busy(cm); 87735863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 87835863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 87935863739SMike Smith 88035863739SMike Smith /* is there a completion handler? */ 88135863739SMike Smith if (cm->cm_complete != NULL) { 88235863739SMike Smith cm->cm_complete(cm); 88335863739SMike Smith } else { 88435863739SMike Smith /* assume that someone is sleeping on this command */ 88535863739SMike Smith wakeup(cm); 88635863739SMike Smith } 88735863739SMike Smith } 8880b94a66eSMike Smith 8890b94a66eSMike Smith /* see if we can start some more I/O */ 8900b94a66eSMike Smith aac_startio(sc); 89135863739SMike Smith } 89235863739SMike Smith 893914da7d0SScott Long /* 89435863739SMike Smith * Handle a bio submitted from a disk device. 89535863739SMike Smith */ 89635863739SMike Smith void 89735863739SMike Smith aac_submit_bio(struct bio *bp) 89835863739SMike Smith { 899914da7d0SScott Long struct aac_disk *ad; 900914da7d0SScott Long struct aac_softc *sc; 90135863739SMike Smith 90235863739SMike Smith debug_called(2); 90335863739SMike Smith 904914da7d0SScott Long ad = (struct aac_disk *)bp->bio_dev->si_drv1; 905914da7d0SScott Long sc = ad->ad_controller; 906914da7d0SScott Long 90735863739SMike Smith /* queue the BIO and try to get some work done */ 9080b94a66eSMike Smith aac_enqueue_bio(sc, bp); 90935863739SMike Smith aac_startio(sc); 91035863739SMike Smith } 91135863739SMike Smith 912914da7d0SScott Long /* 91335863739SMike Smith * Get a bio and build a command to go with it. 91435863739SMike Smith */ 91535863739SMike Smith static int 91635863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 91735863739SMike Smith { 91835863739SMike Smith struct aac_command *cm; 91935863739SMike Smith struct aac_fib *fib; 92035863739SMike Smith struct aac_blockread *br; 92135863739SMike Smith struct aac_blockwrite *bw; 92235863739SMike Smith struct aac_disk *ad; 92335863739SMike Smith struct bio *bp; 92435863739SMike Smith 92535863739SMike Smith debug_called(2); 92635863739SMike Smith 92735863739SMike Smith /* get the resources we will need */ 92835863739SMike Smith cm = NULL; 9290b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 93035863739SMike Smith goto fail; 93135863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 93235863739SMike Smith goto fail; 93335863739SMike Smith 93435863739SMike Smith /* fill out the command */ 9350b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9360b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9370b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 93835863739SMike Smith cm->cm_private = bp; 9390b94a66eSMike Smith cm->cm_timestamp = time_second; 94036e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 94135863739SMike Smith 94235863739SMike Smith /* build the FIB */ 94335863739SMike Smith fib = cm->cm_fib; 94435863739SMike Smith fib->Header.XferState = 94535863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 94635863739SMike Smith AAC_FIBSTATE_INITIALISED | 947f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 94835863739SMike Smith AAC_FIBSTATE_FROMHOST | 94935863739SMike Smith AAC_FIBSTATE_REXPECTED | 950f30ac74cSScott Long AAC_FIBSTATE_NORM | 951f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 952f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 95335863739SMike Smith fib->Header.Command = ContainerCommand; 95435863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 95535863739SMike Smith 95635863739SMike Smith /* build the read/write request */ 95735863739SMike Smith ad = (struct aac_disk *)bp->bio_dev->si_drv1; 95835863739SMike Smith if (BIO_IS_READ(bp)) { 95935863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 96035863739SMike Smith br->Command = VM_CtBlockRead; 96135863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 96235863739SMike Smith br->BlockNumber = bp->bio_pblkno; 96335863739SMike Smith br->ByteCount = bp->bio_bcount; 96435863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 96535863739SMike Smith cm->cm_sgtable = &br->SgMap; 96635863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 96735863739SMike Smith } else { 96835863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 96935863739SMike Smith bw->Command = VM_CtBlockWrite; 97035863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 97135863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 97235863739SMike Smith bw->ByteCount = bp->bio_bcount; 97335863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 97435863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 97535863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 97635863739SMike Smith cm->cm_sgtable = &bw->SgMap; 97735863739SMike Smith } 97835863739SMike Smith 97935863739SMike Smith *cmp = cm; 98035863739SMike Smith return(0); 98135863739SMike Smith 98235863739SMike Smith fail: 98335863739SMike Smith if (bp != NULL) 9840b94a66eSMike Smith aac_enqueue_bio(sc, bp); 98535863739SMike Smith if (cm != NULL) 98635863739SMike Smith aac_release_command(cm); 98735863739SMike Smith return(ENOMEM); 98835863739SMike Smith } 98935863739SMike Smith 990914da7d0SScott Long /* 99135863739SMike Smith * Handle a bio-instigated command that has been completed. 99235863739SMike Smith */ 99335863739SMike Smith static void 99435863739SMike Smith aac_bio_complete(struct aac_command *cm) 99535863739SMike Smith { 99635863739SMike Smith struct aac_blockread_response *brr; 99735863739SMike Smith struct aac_blockwrite_response *bwr; 99835863739SMike Smith struct bio *bp; 99935863739SMike Smith AAC_FSAStatus status; 100035863739SMike Smith 100135863739SMike Smith /* fetch relevant status and then release the command */ 100235863739SMike Smith bp = (struct bio *)cm->cm_private; 100335863739SMike Smith if (BIO_IS_READ(bp)) { 100435863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 100535863739SMike Smith status = brr->Status; 100635863739SMike Smith } else { 100735863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 100835863739SMike Smith status = bwr->Status; 100935863739SMike Smith } 101035863739SMike Smith aac_release_command(cm); 101135863739SMike Smith 101235863739SMike Smith /* fix up the bio based on status */ 101335863739SMike Smith if (status == ST_OK) { 101435863739SMike Smith bp->bio_resid = 0; 101535863739SMike Smith } else { 101635863739SMike Smith bp->bio_error = EIO; 101735863739SMike Smith bp->bio_flags |= BIO_ERROR; 10180b94a66eSMike Smith /* pass an error string out to the disk layer */ 1019914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1020914da7d0SScott Long status); 102135863739SMike Smith } 10220b94a66eSMike Smith aac_biodone(bp); 102335863739SMike Smith } 102435863739SMike Smith 1025914da7d0SScott Long /* 102635863739SMike Smith * Submit a command to the controller, return when it completes. 1027b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1028b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1029b3457b51SScott Long * because there is a risk that a signal could wakeup the tsleep before 1030b3457b51SScott Long * the card has a chance to complete the command. The passed in timeout 1031b3457b51SScott Long * is ignored for the same reason. Since there is no way to cancel a 1032b3457b51SScott Long * command in progress, we should probably create a 'dead' queue where 1033b3457b51SScott Long * commands go that have been interrupted/timed-out/etc, that keeps them 1034b3457b51SScott Long * out of the free pool. That way, if the card is just slow, it won't 1035b3457b51SScott Long * spam the memory of a command that has been recycled. 103635863739SMike Smith */ 103735863739SMike Smith static int 103835863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 103935863739SMike Smith { 104035863739SMike Smith int s, error = 0; 104135863739SMike Smith 104235863739SMike Smith debug_called(2); 104335863739SMike Smith 104435863739SMike Smith /* Put the command on the ready queue and get things going */ 104536e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 104635863739SMike Smith aac_enqueue_ready(cm); 104735863739SMike Smith aac_startio(cm->cm_sc); 104835863739SMike Smith s = splbio(); 104935863739SMike Smith while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1050b3457b51SScott Long error = tsleep(cm, PRIBIO, "aacwait", 0); 105135863739SMike Smith } 105235863739SMike Smith splx(s); 105335863739SMike Smith return(error); 105435863739SMike Smith } 105535863739SMike Smith 1056914da7d0SScott Long /* 1057914da7d0SScott Long *Command Buffer Management 1058914da7d0SScott Long */ 105935863739SMike Smith 1060914da7d0SScott Long /* 106135863739SMike Smith * Allocate a command. 106235863739SMike Smith */ 1063fe3cb0e1SScott Long int 106435863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 106535863739SMike Smith { 106635863739SMike Smith struct aac_command *cm; 106735863739SMike Smith 106835863739SMike Smith debug_called(3); 106935863739SMike Smith 1070ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 10718480cc63SScott Long if ((aac_alloc_commands(sc) != 0) || 10728480cc63SScott Long (cm = aac_dequeue_free(sc)) == NULL) 107335863739SMike Smith return (ENOMEM); 1074ffb37f33SScott Long } 107535863739SMike Smith 10760b94a66eSMike Smith *cmp = cm; 10770b94a66eSMike Smith return(0); 10780b94a66eSMike Smith } 10790b94a66eSMike Smith 1080914da7d0SScott Long /* 10810b94a66eSMike Smith * Release a command back to the freelist. 10820b94a66eSMike Smith */ 1083fe3cb0e1SScott Long void 10840b94a66eSMike Smith aac_release_command(struct aac_command *cm) 10850b94a66eSMike Smith { 10860b94a66eSMike Smith debug_called(3); 10870b94a66eSMike Smith 10880b94a66eSMike Smith /* (re)initialise the command/FIB */ 108935863739SMike Smith cm->cm_sgtable = NULL; 109035863739SMike Smith cm->cm_flags = 0; 109135863739SMike Smith cm->cm_complete = NULL; 109235863739SMike Smith cm->cm_private = NULL; 109335863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 109435863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 109535863739SMike Smith cm->cm_fib->Header.Flags = 0; 109635863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 109735863739SMike Smith 109835863739SMike Smith /* 109935863739SMike Smith * These are duplicated in aac_start to cover the case where an 110035863739SMike Smith * intermediate stage may have destroyed them. They're left 110135863739SMike Smith * initialised here for debugging purposes only. 110235863739SMike Smith */ 110335863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1104f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1105f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 110635863739SMike Smith 110735863739SMike Smith aac_enqueue_free(cm); 110835863739SMike Smith } 110935863739SMike Smith 1110914da7d0SScott Long /* 11110b94a66eSMike Smith * Map helper for command/FIB allocation. 111235863739SMike Smith */ 111335863739SMike Smith static void 11140b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 111535863739SMike Smith { 11168480cc63SScott Long uint32_t *fibphys; 1117914da7d0SScott Long 11188480cc63SScott Long fibphys = (uint32_t *)arg; 111935863739SMike Smith 112035863739SMike Smith debug_called(3); 112135863739SMike Smith 1122ffb37f33SScott Long *fibphys = segs[0].ds_addr; 112335863739SMike Smith } 112435863739SMike Smith 1125914da7d0SScott Long /* 11260b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 112735863739SMike Smith */ 11280b94a66eSMike Smith static int 11290b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 113035863739SMike Smith { 113135863739SMike Smith struct aac_command *cm; 1132ffb37f33SScott Long struct aac_fibmap *fm; 11338480cc63SScott Long uint32_t fibphys; 1134ffb37f33SScott Long int i, error; 113535863739SMike Smith 113635863739SMike Smith debug_called(1); 113735863739SMike Smith 1138ffb37f33SScott Long if (sc->total_fibs + AAC_FIB_COUNT > AAC_MAX_FIBS) 1139ffb37f33SScott Long return (ENOMEM); 1140ffb37f33SScott Long 11418480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1142ffb37f33SScott Long 11430b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1144ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1145ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 114670545d1aSScott Long device_printf(sc->aac_dev, 114770545d1aSScott Long "Not enough contiguous memory available.\n"); 11488480cc63SScott Long free(fm, M_AACBUF); 11490b94a66eSMike Smith return (ENOMEM); 115035863739SMike Smith } 1151128aa5a0SScott Long 1152ffb37f33SScott Long bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1153ffb37f33SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1154ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1155128aa5a0SScott Long 11560b94a66eSMike Smith /* initialise constant fields in the command structure */ 1157ffb37f33SScott Long bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11580b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11598480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1160ffb37f33SScott Long fm->aac_commands = cm; 116135863739SMike Smith cm->cm_sc = sc; 1162ffb37f33SScott Long cm->cm_fib = fm->aac_fibs + i; 11638480cc63SScott Long cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 116435863739SMike Smith 1165ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1166ffb37f33SScott Long &cm->cm_datamap)) == 0) 116735863739SMike Smith aac_release_command(cm); 1168ffb37f33SScott Long else 11698480cc63SScott Long break; 11708480cc63SScott Long sc->total_fibs++; 117135863739SMike Smith } 1172ffb37f33SScott Long 11738480cc63SScott Long if (i > 0) { 1174ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 11750b94a66eSMike Smith return (0); 117635863739SMike Smith } 117735863739SMike Smith 11788480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 11798480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 11808480cc63SScott Long free(fm, M_AACBUF); 11818480cc63SScott Long return (ENOMEM); 11828480cc63SScott Long } 11838480cc63SScott Long 1184914da7d0SScott Long /* 11850b94a66eSMike Smith * Free FIBs owned by this adapter. 118635863739SMike Smith */ 118735863739SMike Smith static void 11888480cc63SScott Long aac_free_commands(struct aac_softc *sc) 118935863739SMike Smith { 11908480cc63SScott Long struct aac_fibmap *fm; 1191ffb37f33SScott Long struct aac_command *cm; 119235863739SMike Smith int i; 119335863739SMike Smith 119435863739SMike Smith debug_called(1); 119535863739SMike Smith 11968480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 11978480cc63SScott Long 11988480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 11998480cc63SScott Long /* 12008480cc63SScott Long * We check against total_fibs to handle partially 12018480cc63SScott Long * allocated blocks. 12028480cc63SScott Long */ 12038480cc63SScott Long for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1204ffb37f33SScott Long cm = fm->aac_commands + i; 1205ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1206ffb37f33SScott Long } 1207ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1208ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12098480cc63SScott Long free(fm, M_AACBUF); 12108480cc63SScott Long } 121135863739SMike Smith } 121235863739SMike Smith 1213914da7d0SScott Long /* 121435863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 121535863739SMike Smith */ 121635863739SMike Smith static void 121735863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 121835863739SMike Smith { 1219914da7d0SScott Long struct aac_command *cm; 1220914da7d0SScott Long struct aac_fib *fib; 122135863739SMike Smith struct aac_sg_table *sg; 122235863739SMike Smith int i; 122335863739SMike Smith 122435863739SMike Smith debug_called(3); 122535863739SMike Smith 1226914da7d0SScott Long cm = (struct aac_command *)arg; 1227914da7d0SScott Long fib = cm->cm_fib; 1228914da7d0SScott Long 122935863739SMike Smith /* find the s/g table */ 123035863739SMike Smith sg = cm->cm_sgtable; 123135863739SMike Smith 123235863739SMike Smith /* copy into the FIB */ 123335863739SMike Smith if (sg != NULL) { 123435863739SMike Smith sg->SgCount = nseg; 123535863739SMike Smith for (i = 0; i < nseg; i++) { 123635863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 123735863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 123835863739SMike Smith } 123935863739SMike Smith /* update the FIB size for the s/g count */ 124035863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 124135863739SMike Smith } 124235863739SMike Smith 124335863739SMike Smith } 124435863739SMike Smith 1245914da7d0SScott Long /* 124635863739SMike Smith * Map a command into controller-visible space. 124735863739SMike Smith */ 124835863739SMike Smith static void 124935863739SMike Smith aac_map_command(struct aac_command *cm) 125035863739SMike Smith { 1251914da7d0SScott Long struct aac_softc *sc; 125235863739SMike Smith 125335863739SMike Smith debug_called(2); 125435863739SMike Smith 1255914da7d0SScott Long sc = cm->cm_sc; 1256914da7d0SScott Long 125735863739SMike Smith /* don't map more than once */ 125835863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 125935863739SMike Smith return; 126035863739SMike Smith 126135863739SMike Smith if (cm->cm_datalen != 0) { 1262914da7d0SScott Long bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 1263914da7d0SScott Long cm->cm_data, cm->cm_datalen, 1264914da7d0SScott Long aac_map_command_sg, cm, 0); 126535863739SMike Smith 126635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1267c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1268c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 126935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1270c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1271c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 127235863739SMike Smith } 127335863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 127435863739SMike Smith } 127535863739SMike Smith 1276914da7d0SScott Long /* 127735863739SMike Smith * Unmap a command from controller-visible space. 127835863739SMike Smith */ 127935863739SMike Smith static void 128035863739SMike Smith aac_unmap_command(struct aac_command *cm) 128135863739SMike Smith { 1282914da7d0SScott Long struct aac_softc *sc; 128335863739SMike Smith 128435863739SMike Smith debug_called(2); 128535863739SMike Smith 1286914da7d0SScott Long sc = cm->cm_sc; 1287914da7d0SScott Long 128835863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 128935863739SMike Smith return; 129035863739SMike Smith 129135863739SMike Smith if (cm->cm_datalen != 0) { 129235863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1293c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1294c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 129535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1296c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1297c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 129835863739SMike Smith 129935863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 130035863739SMike Smith } 130135863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 130235863739SMike Smith } 130335863739SMike Smith 1304914da7d0SScott Long /* 1305914da7d0SScott Long * Hardware Interface 1306914da7d0SScott Long */ 130735863739SMike Smith 1308914da7d0SScott Long /* 130935863739SMike Smith * Initialise the adapter. 131035863739SMike Smith */ 131135863739SMike Smith static void 131235863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 131335863739SMike Smith { 1314914da7d0SScott Long struct aac_softc *sc; 131535863739SMike Smith 131635863739SMike Smith debug_called(1); 131735863739SMike Smith 1318914da7d0SScott Long sc = (struct aac_softc *)arg; 1319914da7d0SScott Long 132035863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 132135863739SMike Smith } 132235863739SMike Smith 1323fe94b852SScott Long /* 1324fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1325fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1326fe94b852SScott Long */ 1327fe94b852SScott Long static int 1328fe94b852SScott Long aac_check_firmware(struct aac_softc *sc) 1329fe94b852SScott Long { 1330fe94b852SScott Long u_int32_t major, minor; 1331fe94b852SScott Long 1332fe94b852SScott Long debug_called(1); 1333fe94b852SScott Long 1334fe94b852SScott Long if (sc->quirks & AAC_QUIRK_PERC2QC) { 1335fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1336fe94b852SScott Long NULL)) { 1337fe94b852SScott Long device_printf(sc->aac_dev, 1338fe94b852SScott Long "Error reading firmware version\n"); 1339fe94b852SScott Long return (EIO); 1340fe94b852SScott Long } 1341fe94b852SScott Long 1342fe94b852SScott Long /* These numbers are stored as ASCII! */ 1343fe94b852SScott Long major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30; 1344fe94b852SScott Long minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30; 1345fe94b852SScott Long if (major == 1) { 1346fe94b852SScott Long device_printf(sc->aac_dev, 1347fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1348fe94b852SScott Long major, minor); 1349fe94b852SScott Long return (EINVAL); 1350fe94b852SScott Long } 1351fe94b852SScott Long } 1352fe94b852SScott Long 1353fe94b852SScott Long return (0); 1354fe94b852SScott Long } 1355fe94b852SScott Long 135635863739SMike Smith static int 135735863739SMike Smith aac_init(struct aac_softc *sc) 135835863739SMike Smith { 135935863739SMike Smith struct aac_adapter_init *ip; 136035863739SMike Smith time_t then; 136135863739SMike Smith u_int32_t code; 136235863739SMike Smith u_int8_t *qaddr; 136335863739SMike Smith 136435863739SMike Smith debug_called(1); 136535863739SMike Smith 136635863739SMike Smith /* 136735863739SMike Smith * First wait for the adapter to come ready. 136835863739SMike Smith */ 136935863739SMike Smith then = time_second; 137035863739SMike Smith do { 137135863739SMike Smith code = AAC_GET_FWSTATUS(sc); 137235863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 137335863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 137435863739SMike Smith return(ENXIO); 137535863739SMike Smith } 137635863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1377914da7d0SScott Long device_printf(sc->aac_dev, 1378914da7d0SScott Long "FATAL: controller kernel panic\n"); 137935863739SMike Smith return(ENXIO); 138035863739SMike Smith } 138135863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1382914da7d0SScott Long device_printf(sc->aac_dev, 1383914da7d0SScott Long "FATAL: controller not coming ready, " 1384c6eafcf2SScott Long "status %x\n", code); 138535863739SMike Smith return(ENXIO); 138635863739SMike Smith } 138735863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 138835863739SMike Smith 138935863739SMike Smith /* 139035863739SMike Smith * Create DMA tag for the common structure and allocate it. 139135863739SMike Smith */ 139235863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1393c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1394fe3cb0e1SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 139535863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 139635863739SMike Smith NULL, NULL, /* filter, filterarg */ 1397ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1398914da7d0SScott Long 1, /* nsegments */ 139935863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 140035863739SMike Smith 0, /* flags */ 140135863739SMike Smith &sc->aac_common_dmat)) { 1402914da7d0SScott Long device_printf(sc->aac_dev, 1403914da7d0SScott Long "can't allocate common structure DMA tag\n"); 140435863739SMike Smith return(ENOMEM); 140535863739SMike Smith } 1406c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1407c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 140835863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 140935863739SMike Smith return(ENOMEM); 141035863739SMike Smith } 1411ffb37f33SScott Long 1412ffb37f33SScott Long /* 1413ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1414ffb37f33SScott Long * below address 8192 in physical memory. 1415ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1416ffb37f33SScott Long * of ignored? 1417ffb37f33SScott Long */ 1418914da7d0SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1419ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1420ffb37f33SScott Long aac_common_map, sc, 0); 1421ffb37f33SScott Long 1422ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1423ffb37f33SScott Long (uint8_t *)sc->aac_common += 8192; 1424ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1425ffb37f33SScott Long } 142635863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 142735863739SMike Smith 1428ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1429ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 1430ffb37f33SScott Long sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 14318480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 14328480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1433ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1434ffb37f33SScott Long break; 1435ffb37f33SScott Long } 1436ffb37f33SScott Long if (sc->total_fibs == 0) 1437ffb37f33SScott Long return (ENOMEM); 1438ffb37f33SScott Long 143935863739SMike Smith /* 1440914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1441914da7d0SScott Long * physical location of various important shared data structures. 144235863739SMike Smith */ 144335863739SMike Smith ip = &sc->aac_common->ac_init; 144435863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1445f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 144635863739SMike Smith 1447c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1448c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1449f30ac74cSScott Long ip->AdapterFibsVirtualAddress = (u_int32_t)&sc->aac_common->ac_fibs[0]; 145035863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 145135863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 145235863739SMike Smith 1453c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1454c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 145535863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 145635863739SMike Smith 1457f30ac74cSScott Long /* The adapter assumes that pages are 4K in size */ 1458f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 145935863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 146035863739SMike Smith 146135863739SMike Smith /* 1462c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1463c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1464c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 146535863739SMike Smith * 146635863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1467914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1468914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1469914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1470914da7d0SScott Long * does. 147135863739SMike Smith * 1472914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1473914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1474914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1475914da7d0SScott Long * virtue of a table. 147635863739SMike Smith */ 147735863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 147835863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 147935863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1480914da7d0SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + 1481914da7d0SScott Long ((u_int32_t)sc->aac_queues - 1482914da7d0SScott Long (u_int32_t)sc->aac_common); 148335863739SMike Smith 1484c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1485c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1486c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1487c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1488c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1489c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1490c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1491c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1492c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1493c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1494c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1495c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1496c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1497c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1498c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1499c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1500c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1501c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1502c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1503c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1504c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1505c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1506c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1507c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1508c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1509c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1510c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1511c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1512c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1513c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1514c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1515c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1516c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1517c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1518c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1519c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1520c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1521c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1522c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1523c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1524c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1525c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1526c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1527c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1528c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1529c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1530c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1531c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 153235863739SMike Smith 153335863739SMike Smith /* 153435863739SMike Smith * Do controller-type-specific initialisation 153535863739SMike Smith */ 153635863739SMike Smith switch (sc->aac_hwif) { 153735863739SMike Smith case AAC_HWIF_I960RX: 153835863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 153935863739SMike Smith break; 154035863739SMike Smith } 154135863739SMike Smith 154235863739SMike Smith /* 154335863739SMike Smith * Give the init structure to the controller. 154435863739SMike Smith */ 154535863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1546914da7d0SScott Long sc->aac_common_busaddr + 1547914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1548914da7d0SScott Long NULL)) { 1549914da7d0SScott Long device_printf(sc->aac_dev, 1550914da7d0SScott Long "error establishing init structure\n"); 155135863739SMike Smith return(EIO); 155235863739SMike Smith } 155335863739SMike Smith 155435863739SMike Smith return(0); 155535863739SMike Smith } 155635863739SMike Smith 1557914da7d0SScott Long /* 155835863739SMike Smith * Send a synchronous command to the controller and wait for a result. 155935863739SMike Smith */ 156035863739SMike Smith static int 156135863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 156235863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 156335863739SMike Smith u_int32_t *sp) 156435863739SMike Smith { 156535863739SMike Smith time_t then; 156635863739SMike Smith u_int32_t status; 156735863739SMike Smith 156835863739SMike Smith debug_called(3); 156935863739SMike Smith 157035863739SMike Smith /* populate the mailbox */ 157135863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 157235863739SMike Smith 157335863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 157435863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 157535863739SMike Smith 157635863739SMike Smith /* then set it to signal the adapter */ 157735863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 157835863739SMike Smith 157935863739SMike Smith /* spin waiting for the command to complete */ 158035863739SMike Smith then = time_second; 158135863739SMike Smith do { 158235863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 158335863739SMike Smith debug(2, "timed out"); 158435863739SMike Smith return(EIO); 158535863739SMike Smith } 158635863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 158735863739SMike Smith 158835863739SMike Smith /* clear the completion flag */ 158935863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 159035863739SMike Smith 159135863739SMike Smith /* get the command status */ 159235863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 159335863739SMike Smith if (sp != NULL) 159435863739SMike Smith *sp = status; 15950b94a66eSMike Smith return(0); 159635863739SMike Smith } 159735863739SMike Smith 1598914da7d0SScott Long /* 1599cbfd045bSScott Long * Grab the sync fib area. 1600cbfd045bSScott Long */ 1601cbfd045bSScott Long int 1602fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1603cbfd045bSScott Long { 1604cbfd045bSScott Long 1605cbfd045bSScott Long /* 1606cbfd045bSScott Long * If the force flag is set, the system is shutting down, or in 1607cbfd045bSScott Long * trouble. Ignore the mutex. 1608cbfd045bSScott Long */ 1609cbfd045bSScott Long if (!(flags & AAC_SYNC_LOCK_FORCE)) 1610cbfd045bSScott Long AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1611cbfd045bSScott Long 1612cbfd045bSScott Long *fib = &sc->aac_common->ac_sync_fib; 1613cbfd045bSScott Long 1614cbfd045bSScott Long return (1); 1615cbfd045bSScott Long } 1616cbfd045bSScott Long 1617cbfd045bSScott Long /* 1618cbfd045bSScott Long * Release the sync fib area. 1619cbfd045bSScott Long */ 1620cbfd045bSScott Long void 1621cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc) 1622cbfd045bSScott Long { 1623cbfd045bSScott Long 1624cbfd045bSScott Long AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1625cbfd045bSScott Long } 1626cbfd045bSScott Long 1627cbfd045bSScott Long /* 162835863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 162935863739SMike Smith */ 1630cbfd045bSScott Long int 163135863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1632cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 163335863739SMike Smith { 163435863739SMike Smith debug_called(3); 163535863739SMike Smith 163635863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 163735863739SMike Smith return(EINVAL); 163835863739SMike Smith 163935863739SMike Smith /* 164035863739SMike Smith * Set up the sync FIB 164135863739SMike Smith */ 1642914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1643914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1644c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 164535863739SMike Smith fib->Header.XferState |= xferstate; 164635863739SMike Smith fib->Header.Command = command; 164735863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 164835863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 164935863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 165035863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1651c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1652914da7d0SScott Long offsetof(struct aac_common, 1653914da7d0SScott Long ac_sync_fib); 165435863739SMike Smith 165535863739SMike Smith /* 165635863739SMike Smith * Give the FIB to the controller, wait for a response. 165735863739SMike Smith */ 1658914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1659914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 166035863739SMike Smith debug(2, "IO error"); 166135863739SMike Smith return(EIO); 166235863739SMike Smith } 166335863739SMike Smith 166435863739SMike Smith return (0); 166535863739SMike Smith } 166635863739SMike Smith 1667914da7d0SScott Long /* 166835863739SMike Smith * Adapter-space FIB queue manipulation 166935863739SMike Smith * 167035863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 167135863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 167235863739SMike Smith */ 167335863739SMike Smith static struct { 167435863739SMike Smith int size; 167535863739SMike Smith int notify; 167635863739SMike Smith } aac_qinfo[] = { 167735863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 167835863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 167935863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 168035863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 168135863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 168235863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 168335863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 168435863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 168535863739SMike Smith }; 168635863739SMike Smith 168735863739SMike Smith /* 1688c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1689c6eafcf2SScott Long * EBUSY if the queue is full. 169035863739SMike Smith * 16910b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1692914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1693914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1694c6eafcf2SScott Long * separate queue/notify interface). 169535863739SMike Smith */ 169635863739SMike Smith static int 1697f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 169835863739SMike Smith { 169935863739SMike Smith u_int32_t pi, ci; 170035863739SMike Smith int s, error; 1701f6c4dd3fSScott Long u_int32_t fib_size; 1702f6c4dd3fSScott Long u_int32_t fib_addr; 1703f6c4dd3fSScott Long 170436e0bf6eSScott Long debug_called(3); 170536e0bf6eSScott Long 1706f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1707f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 170835863739SMike Smith 170935863739SMike Smith s = splbio(); 171035863739SMike Smith 171135863739SMike Smith /* get the producer/consumer indices */ 171235863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 171335863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 171435863739SMike Smith 171535863739SMike Smith /* wrap the queue? */ 171635863739SMike Smith if (pi >= aac_qinfo[queue].size) 171735863739SMike Smith pi = 0; 171835863739SMike Smith 171935863739SMike Smith /* check for queue full */ 172035863739SMike Smith if ((pi + 1) == ci) { 172135863739SMike Smith error = EBUSY; 172235863739SMike Smith goto out; 172335863739SMike Smith } 172435863739SMike Smith 172535863739SMike Smith /* populate queue entry */ 172635863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 172735863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 172835863739SMike Smith 172935863739SMike Smith /* update producer index */ 173035863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 173135863739SMike Smith 1732f6c4dd3fSScott Long /* 1733914da7d0SScott Long * To avoid a race with its completion interrupt, place this command on 1734914da7d0SScott Long * the busy queue prior to advertising it to the controller. 1735f6c4dd3fSScott Long */ 1736f6c4dd3fSScott Long aac_enqueue_busy(cm); 1737f6c4dd3fSScott Long 173835863739SMike Smith /* notify the adapter if we know how */ 173935863739SMike Smith if (aac_qinfo[queue].notify != 0) 174035863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 174135863739SMike Smith 174235863739SMike Smith error = 0; 174335863739SMike Smith 174435863739SMike Smith out: 174535863739SMike Smith splx(s); 174635863739SMike Smith return(error); 174735863739SMike Smith } 174835863739SMike Smith 174935863739SMike Smith /* 175036e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 175136e0bf6eSScott Long * success or ENOENT if the queue is empty. 175235863739SMike Smith */ 175335863739SMike Smith static int 1754c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1755c6eafcf2SScott Long struct aac_fib **fib_addr) 175635863739SMike Smith { 175735863739SMike Smith u_int32_t pi, ci; 175835863739SMike Smith int s, error; 1759f6c4dd3fSScott Long int notify; 176035863739SMike Smith 176135863739SMike Smith debug_called(3); 176235863739SMike Smith 176335863739SMike Smith s = splbio(); 176435863739SMike Smith 176535863739SMike Smith /* get the producer/consumer indices */ 176635863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 176735863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 176835863739SMike Smith 176935863739SMike Smith /* check for queue empty */ 177035863739SMike Smith if (ci == pi) { 177135863739SMike Smith error = ENOENT; 177235863739SMike Smith goto out; 177335863739SMike Smith } 177435863739SMike Smith 1775f6c4dd3fSScott Long notify = 0; 1776f6c4dd3fSScott Long if (ci == pi + 1) 1777f6c4dd3fSScott Long notify++; 1778f6c4dd3fSScott Long 177935863739SMike Smith /* wrap the queue? */ 178035863739SMike Smith if (ci >= aac_qinfo[queue].size) 178135863739SMike Smith ci = 0; 178235863739SMike Smith 178335863739SMike Smith /* fetch the entry */ 178435863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1785914da7d0SScott Long *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + 1786914da7d0SScott Long ci)->aq_fib_addr; 178735863739SMike Smith 1788f30ac74cSScott Long /* 1789f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1790f30ac74cSScott Long * local memory so the whole fib doesn't have to be DMA'd back up. 1791f30ac74cSScott Long */ 1792f30ac74cSScott Long if (*(uintptr_t *)fib_addr & 0x01) { 1793f30ac74cSScott Long *(uintptr_t *)fib_addr &= ~0x01; 1794f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1795f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1796f30ac74cSScott Long } 179735863739SMike Smith /* update consumer index */ 179835863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 179935863739SMike Smith 180035863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1801f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 180235863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 180335863739SMike Smith error = 0; 180435863739SMike Smith 180535863739SMike Smith out: 180635863739SMike Smith splx(s); 180735863739SMike Smith return(error); 180835863739SMike Smith } 180935863739SMike Smith 1810914da7d0SScott Long /* 181136e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 181236e0bf6eSScott Long */ 181336e0bf6eSScott Long static int 181436e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 181536e0bf6eSScott Long { 181636e0bf6eSScott Long u_int32_t pi, ci; 181736e0bf6eSScott Long int s, error; 181836e0bf6eSScott Long u_int32_t fib_size; 181936e0bf6eSScott Long u_int32_t fib_addr; 182036e0bf6eSScott Long 182136e0bf6eSScott Long debug_called(1); 182236e0bf6eSScott Long 182336e0bf6eSScott Long /* Tell the adapter where the FIB is */ 182436e0bf6eSScott Long fib_size = fib->Header.Size; 182536e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 182636e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 182736e0bf6eSScott Long 182836e0bf6eSScott Long s = splbio(); 182936e0bf6eSScott Long 183036e0bf6eSScott Long /* get the producer/consumer indices */ 183136e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 183236e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 183336e0bf6eSScott Long 183436e0bf6eSScott Long /* wrap the queue? */ 183536e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 183636e0bf6eSScott Long pi = 0; 183736e0bf6eSScott Long 183836e0bf6eSScott Long /* check for queue full */ 183936e0bf6eSScott Long if ((pi + 1) == ci) { 184036e0bf6eSScott Long error = EBUSY; 184136e0bf6eSScott Long goto out; 184236e0bf6eSScott Long } 184336e0bf6eSScott Long 184436e0bf6eSScott Long /* populate queue entry */ 184536e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 184636e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 184736e0bf6eSScott Long 184836e0bf6eSScott Long /* update producer index */ 184936e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 185036e0bf6eSScott Long 185136e0bf6eSScott Long /* notify the adapter if we know how */ 185236e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 185336e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 185436e0bf6eSScott Long 185536e0bf6eSScott Long error = 0; 185636e0bf6eSScott Long 185736e0bf6eSScott Long out: 185836e0bf6eSScott Long splx(s); 185936e0bf6eSScott Long return(error); 186036e0bf6eSScott Long } 186136e0bf6eSScott Long 1862914da7d0SScott Long /* 18630b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 18640b94a66eSMike Smith * and complain about them. 18650b94a66eSMike Smith */ 18660b94a66eSMike Smith static void 18670b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 18680b94a66eSMike Smith { 18690b94a66eSMike Smith int s; 18700b94a66eSMike Smith struct aac_command *cm; 18710b94a66eSMike Smith time_t deadline; 18720b94a66eSMike Smith 1873f6c4dd3fSScott Long /* 187470545d1aSScott Long * Traverse the busy command list, bitch about late commands once 1875914da7d0SScott Long * only. 1876914da7d0SScott Long */ 18770b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 18780b94a66eSMike Smith s = splbio(); 18790b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1880f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1881f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 18820b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1883914da7d0SScott Long device_printf(sc->aac_dev, 1884914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1885f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 18860b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 18870b94a66eSMike Smith } 18880b94a66eSMike Smith } 18890b94a66eSMike Smith splx(s); 18900b94a66eSMike Smith 18910b94a66eSMike Smith return; 18920b94a66eSMike Smith } 18930b94a66eSMike Smith 1894914da7d0SScott Long /* 1895914da7d0SScott Long * Interface Function Vectors 1896914da7d0SScott Long */ 189735863739SMike Smith 1898914da7d0SScott Long /* 189935863739SMike Smith * Read the current firmware status word. 190035863739SMike Smith */ 190135863739SMike Smith static int 190235863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 190335863739SMike Smith { 190435863739SMike Smith debug_called(3); 190535863739SMike Smith 190635863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 190735863739SMike Smith } 190835863739SMike Smith 190935863739SMike Smith static int 191035863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 191135863739SMike Smith { 191235863739SMike Smith debug_called(3); 191335863739SMike Smith 191435863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 191535863739SMike Smith } 191635863739SMike Smith 1917b3457b51SScott Long static int 1918b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 1919b3457b51SScott Long { 1920b3457b51SScott Long int val; 1921b3457b51SScott Long 1922b3457b51SScott Long debug_called(3); 1923b3457b51SScott Long 1924b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 1925b3457b51SScott Long return (val); 1926b3457b51SScott Long } 1927b3457b51SScott Long 1928914da7d0SScott Long /* 192935863739SMike Smith * Notify the controller of a change in a given queue 193035863739SMike Smith */ 193135863739SMike Smith 193235863739SMike Smith static void 193335863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 193435863739SMike Smith { 193535863739SMike Smith debug_called(3); 193635863739SMike Smith 193735863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 193835863739SMike Smith } 193935863739SMike Smith 194035863739SMike Smith static void 194135863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 194235863739SMike Smith { 194335863739SMike Smith debug_called(3); 194435863739SMike Smith 194535863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 194635863739SMike Smith } 194735863739SMike Smith 1948b3457b51SScott Long static void 1949b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 1950b3457b51SScott Long { 1951b3457b51SScott Long debug_called(3); 1952b3457b51SScott Long 1953b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 1954b3457b51SScott Long AAC_FA_HACK(sc); 1955b3457b51SScott Long } 1956b3457b51SScott Long 1957914da7d0SScott Long /* 195835863739SMike Smith * Get the interrupt reason bits 195935863739SMike Smith */ 196035863739SMike Smith static int 196135863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 196235863739SMike Smith { 196335863739SMike Smith debug_called(3); 196435863739SMike Smith 196535863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 196635863739SMike Smith } 196735863739SMike Smith 196835863739SMike Smith static int 196935863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 197035863739SMike Smith { 197135863739SMike Smith debug_called(3); 197235863739SMike Smith 197335863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 197435863739SMike Smith } 197535863739SMike Smith 1976b3457b51SScott Long static int 1977b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 1978b3457b51SScott Long { 1979b3457b51SScott Long int val; 1980b3457b51SScott Long 1981b3457b51SScott Long debug_called(3); 1982b3457b51SScott Long 1983b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 1984b3457b51SScott Long return (val); 1985b3457b51SScott Long } 1986b3457b51SScott Long 1987914da7d0SScott Long /* 198835863739SMike Smith * Clear some interrupt reason bits 198935863739SMike Smith */ 199035863739SMike Smith static void 199135863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 199235863739SMike Smith { 199335863739SMike Smith debug_called(3); 199435863739SMike Smith 199535863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 199635863739SMike Smith } 199735863739SMike Smith 199835863739SMike Smith static void 199935863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 200035863739SMike Smith { 200135863739SMike Smith debug_called(3); 200235863739SMike Smith 200335863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 200435863739SMike Smith } 200535863739SMike Smith 2006b3457b51SScott Long static void 2007b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2008b3457b51SScott Long { 2009b3457b51SScott Long debug_called(3); 2010b3457b51SScott Long 2011b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2012b3457b51SScott Long AAC_FA_HACK(sc); 2013b3457b51SScott Long } 2014b3457b51SScott Long 2015914da7d0SScott Long /* 201635863739SMike Smith * Populate the mailbox and set the command word 201735863739SMike Smith */ 201835863739SMike Smith static void 201935863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 202035863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 202135863739SMike Smith { 202235863739SMike Smith debug_called(4); 202335863739SMike Smith 202435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 202535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 202635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 202735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 202835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 202935863739SMike Smith } 203035863739SMike Smith 203135863739SMike Smith static void 203235863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 203335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 203435863739SMike Smith { 203535863739SMike Smith debug_called(4); 203635863739SMike Smith 203735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 203835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 203935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 204035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 204135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 204235863739SMike Smith } 204335863739SMike Smith 2044b3457b51SScott Long static void 2045b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2046b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2047b3457b51SScott Long { 2048b3457b51SScott Long debug_called(4); 2049b3457b51SScott Long 2050b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2051b3457b51SScott Long AAC_FA_HACK(sc); 2052b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2053b3457b51SScott Long AAC_FA_HACK(sc); 2054b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2055b3457b51SScott Long AAC_FA_HACK(sc); 2056b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2057b3457b51SScott Long AAC_FA_HACK(sc); 2058b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2059b3457b51SScott Long AAC_FA_HACK(sc); 2060b3457b51SScott Long } 2061b3457b51SScott Long 2062914da7d0SScott Long /* 206335863739SMike Smith * Fetch the immediate command status word 206435863739SMike Smith */ 206535863739SMike Smith static int 206635863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 206735863739SMike Smith { 206835863739SMike Smith debug_called(4); 206935863739SMike Smith 207035863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 207135863739SMike Smith } 207235863739SMike Smith 207335863739SMike Smith static int 207435863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 207535863739SMike Smith { 207635863739SMike Smith debug_called(4); 207735863739SMike Smith 207835863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 207935863739SMike Smith } 208035863739SMike Smith 2081b3457b51SScott Long static int 2082b3457b51SScott Long aac_fa_get_mailboxstatus(struct aac_softc *sc) 2083b3457b51SScott Long { 2084b3457b51SScott Long int val; 2085b3457b51SScott Long 2086b3457b51SScott Long debug_called(4); 2087b3457b51SScott Long 2088b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX); 2089b3457b51SScott Long return (val); 2090b3457b51SScott Long } 2091b3457b51SScott Long 2092914da7d0SScott Long /* 209335863739SMike Smith * Set/clear interrupt masks 209435863739SMike Smith */ 209535863739SMike Smith static void 209635863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 209735863739SMike Smith { 209835863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 209935863739SMike Smith 210035863739SMike Smith if (enable) { 210135863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 210235863739SMike Smith } else { 210335863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 210435863739SMike Smith } 210535863739SMike Smith } 210635863739SMike Smith 210735863739SMike Smith static void 210835863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 210935863739SMike Smith { 211035863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 211135863739SMike Smith 211235863739SMike Smith if (enable) { 211335863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 211435863739SMike Smith } else { 211535863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 211635863739SMike Smith } 211735863739SMike Smith } 211835863739SMike Smith 2119b3457b51SScott Long static void 2120b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2121b3457b51SScott Long { 2122b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2123b3457b51SScott Long 2124b3457b51SScott Long if (enable) { 2125b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2126b3457b51SScott Long AAC_FA_HACK(sc); 2127b3457b51SScott Long } else { 2128b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2129b3457b51SScott Long AAC_FA_HACK(sc); 2130b3457b51SScott Long } 2131b3457b51SScott Long } 2132b3457b51SScott Long 2133914da7d0SScott Long /* 2134914da7d0SScott Long * Debugging and Diagnostics 2135914da7d0SScott Long */ 213635863739SMike Smith 2137914da7d0SScott Long /* 213835863739SMike Smith * Print some information about the controller. 213935863739SMike Smith */ 214035863739SMike Smith static void 214135863739SMike Smith aac_describe_controller(struct aac_softc *sc) 214235863739SMike Smith { 2143cbfd045bSScott Long struct aac_fib *fib; 214435863739SMike Smith struct aac_adapter_info *info; 214535863739SMike Smith 214635863739SMike Smith debug_called(2); 214735863739SMike Smith 2148fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2149cbfd045bSScott Long 2150cbfd045bSScott Long fib->data[0] = 0; 2151cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 215235863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2153fe3cb0e1SScott Long aac_release_sync_fib(sc); 215435863739SMike Smith return; 215535863739SMike Smith } 2156cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 215735863739SMike Smith 215836e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2159c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 216036e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2161914da7d0SScott Long aac_describe_code(aac_battery_platform, 2162914da7d0SScott Long info->batteryPlatform)); 216335863739SMike Smith 216435863739SMike Smith /* save the kernel revision structure for later use */ 216535863739SMike Smith sc->aac_revision = info->KernelRevision; 216636e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 216735863739SMike Smith info->KernelRevision.external.comp.major, 216835863739SMike Smith info->KernelRevision.external.comp.minor, 216935863739SMike Smith info->KernelRevision.external.comp.dash, 217036e0bf6eSScott Long info->KernelRevision.buildNumber, 217136e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2172fe3cb0e1SScott Long 2173fe3cb0e1SScott Long aac_release_sync_fib(sc); 217435863739SMike Smith } 217535863739SMike Smith 2176914da7d0SScott Long /* 217735863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 217835863739SMike Smith * same. 217935863739SMike Smith */ 218035863739SMike Smith static char * 218135863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 218235863739SMike Smith { 218335863739SMike Smith int i; 218435863739SMike Smith 218535863739SMike Smith for (i = 0; table[i].string != NULL; i++) 218635863739SMike Smith if (table[i].code == code) 218735863739SMike Smith return(table[i].string); 218835863739SMike Smith return(table[i + 1].string); 218935863739SMike Smith } 219035863739SMike Smith 2191914da7d0SScott Long /* 2192914da7d0SScott Long * Management Interface 2193914da7d0SScott Long */ 219435863739SMike Smith 219535863739SMike Smith static int 2196c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 219735863739SMike Smith { 2198914da7d0SScott Long struct aac_softc *sc; 219935863739SMike Smith 220035863739SMike Smith debug_called(2); 220135863739SMike Smith 2202914da7d0SScott Long sc = dev->si_drv1; 2203914da7d0SScott Long 220435863739SMike Smith /* Check to make sure the device isn't already open */ 220535863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 220635863739SMike Smith return EBUSY; 220735863739SMike Smith } 220835863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 220935863739SMike Smith 221035863739SMike Smith return 0; 221135863739SMike Smith } 221235863739SMike Smith 221335863739SMike Smith static int 2214c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 221535863739SMike Smith { 2216914da7d0SScott Long struct aac_softc *sc; 221735863739SMike Smith 221835863739SMike Smith debug_called(2); 221935863739SMike Smith 2220914da7d0SScott Long sc = dev->si_drv1; 2221914da7d0SScott Long 222235863739SMike Smith /* Mark this unit as no longer open */ 222335863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 222435863739SMike Smith 222535863739SMike Smith return 0; 222635863739SMike Smith } 222735863739SMike Smith 222835863739SMike Smith static int 2229c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 223035863739SMike Smith { 2231914da7d0SScott Long union aac_statrequest *as; 2232914da7d0SScott Long struct aac_softc *sc; 22330b94a66eSMike Smith int error = 0; 22340b94a66eSMike Smith int i; 223535863739SMike Smith 223635863739SMike Smith debug_called(2); 223735863739SMike Smith 2238914da7d0SScott Long as = (union aac_statrequest *)arg; 2239914da7d0SScott Long sc = dev->si_drv1; 2240914da7d0SScott Long 224135863739SMike Smith switch (cmd) { 22420b94a66eSMike Smith case AACIO_STATS: 22430b94a66eSMike Smith switch (as->as_item) { 22440b94a66eSMike Smith case AACQ_FREE: 22450b94a66eSMike Smith case AACQ_BIO: 22460b94a66eSMike Smith case AACQ_READY: 22470b94a66eSMike Smith case AACQ_BUSY: 22480b94a66eSMike Smith case AACQ_COMPLETE: 2249c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2250c6eafcf2SScott Long sizeof(struct aac_qstat)); 22510b94a66eSMike Smith break; 22520b94a66eSMike Smith default: 22530b94a66eSMike Smith error = ENOENT; 22540b94a66eSMike Smith break; 22550b94a66eSMike Smith } 22560b94a66eSMike Smith break; 22570b94a66eSMike Smith 225835863739SMike Smith case FSACTL_SENDFIB: 2259fb0c27d7SScott Long arg = *(caddr_t*)arg; 2260fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 22610b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 226235863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 226335863739SMike Smith break; 226435863739SMike Smith case FSACTL_AIF_THREAD: 2265fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 22660b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 226735863739SMike Smith error = EINVAL; 226835863739SMike Smith break; 226935863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2270fb0c27d7SScott Long arg = *(caddr_t*)arg; 2271fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 22720b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 227335863739SMike Smith /* 227435863739SMike Smith * Pass the caller out an AdapterFibContext. 227535863739SMike Smith * 227635863739SMike Smith * Note that because we only support one opener, we 227735863739SMike Smith * basically ignore this. Set the caller's context to a magic 227835863739SMike Smith * number just in case. 22790b94a66eSMike Smith * 22800b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 22810b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2282914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2283914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 228435863739SMike Smith */ 228536e0bf6eSScott Long i = (int)sc->aifthread; 228635863739SMike Smith error = copyout(&i, arg, sizeof(i)); 228735863739SMike Smith break; 228835863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2289fb0c27d7SScott Long arg = *(caddr_t*)arg; 2290fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 22910b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2292fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 229335863739SMike Smith break; 229435863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2295fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 22960b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 229735863739SMike Smith /* don't do anything here */ 229835863739SMike Smith break; 229935863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2300fb0c27d7SScott Long arg = *(caddr_t*)arg; 2301fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 23020b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2303fb0c27d7SScott Long error = aac_rev_check(sc, arg); 230435863739SMike Smith break; 230536e0bf6eSScott Long case FSACTL_QUERY_DISK: 230636e0bf6eSScott Long arg = *(caddr_t*)arg; 230736e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 230836e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 230936e0bf6eSScott Long error = aac_query_disk(sc, arg); 231036e0bf6eSScott Long break; 231136e0bf6eSScott Long case FSACTL_DELETE_DISK: 231236e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2313914da7d0SScott Long /* 2314914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2315914da7d0SScott Long * container, rather we rely on an AIF coming from the 2316914da7d0SScott Long * controller 2317914da7d0SScott Long */ 231836e0bf6eSScott Long error = 0; 231936e0bf6eSScott Long break; 232035863739SMike Smith default: 2321b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 232235863739SMike Smith error = EINVAL; 232335863739SMike Smith break; 232435863739SMike Smith } 232535863739SMike Smith return(error); 232635863739SMike Smith } 232735863739SMike Smith 2328b3457b51SScott Long static int 2329c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td) 2330b3457b51SScott Long { 2331b3457b51SScott Long struct aac_softc *sc; 2332b3457b51SScott Long int revents; 2333b3457b51SScott Long 2334b3457b51SScott Long sc = dev->si_drv1; 2335b3457b51SScott Long revents = 0; 2336b3457b51SScott Long 2337c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2338b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2339b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2340b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2341b3457b51SScott Long } 2342b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2343b3457b51SScott Long 2344b3457b51SScott Long if (revents == 0) { 2345b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2346b3457b51SScott Long selrecord(td, &sc->rcv_select); 2347b3457b51SScott Long } 2348b3457b51SScott Long 2349b3457b51SScott Long return (revents); 2350b3457b51SScott Long } 2351b3457b51SScott Long 2352914da7d0SScott Long /* 235335863739SMike Smith * Send a FIB supplied from userspace 235435863739SMike Smith */ 235535863739SMike Smith static int 235635863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 235735863739SMike Smith { 235835863739SMike Smith struct aac_command *cm; 235935863739SMike Smith int size, error; 236035863739SMike Smith 236135863739SMike Smith debug_called(2); 236235863739SMike Smith 236335863739SMike Smith cm = NULL; 236435863739SMike Smith 236535863739SMike Smith /* 236635863739SMike Smith * Get a command 236735863739SMike Smith */ 236835863739SMike Smith if (aac_alloc_command(sc, &cm)) { 236935863739SMike Smith error = EBUSY; 237035863739SMike Smith goto out; 237135863739SMike Smith } 237235863739SMike Smith 237335863739SMike Smith /* 237435863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 237535863739SMike Smith */ 2376914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2377914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 237835863739SMike Smith goto out; 237935863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 238035863739SMike Smith if (size > sizeof(struct aac_fib)) { 2381914da7d0SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2382914da7d0SScott Long size, sizeof(struct aac_fib)); 238335863739SMike Smith size = sizeof(struct aac_fib); 238435863739SMike Smith } 238535863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 238635863739SMike Smith goto out; 238735863739SMike Smith cm->cm_fib->Header.Size = size; 2388f6c4dd3fSScott Long cm->cm_timestamp = time_second; 238935863739SMike Smith 239035863739SMike Smith /* 239135863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 239235863739SMike Smith */ 2393b3457b51SScott Long if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 239470545d1aSScott Long device_printf(sc->aac_dev, 239570545d1aSScott Long "aac_wait_command return %d\n", error); 239635863739SMike Smith goto out; 2397b3457b51SScott Long } 239835863739SMike Smith 239935863739SMike Smith /* 240035863739SMike Smith * Copy the FIB and data back out to the caller. 240135863739SMike Smith */ 240235863739SMike Smith size = cm->cm_fib->Header.Size; 240335863739SMike Smith if (size > sizeof(struct aac_fib)) { 2404914da7d0SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2405914da7d0SScott Long size, sizeof(struct aac_fib)); 240635863739SMike Smith size = sizeof(struct aac_fib); 240735863739SMike Smith } 240835863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 240935863739SMike Smith 241035863739SMike Smith out: 2411f6c4dd3fSScott Long if (cm != NULL) { 241235863739SMike Smith aac_release_command(cm); 2413f6c4dd3fSScott Long } 241435863739SMike Smith return(error); 241535863739SMike Smith } 241635863739SMike Smith 2417914da7d0SScott Long /* 241835863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 241936e0bf6eSScott Long * If the queue fills up, then drop the older entries. 242035863739SMike Smith */ 242135863739SMike Smith static void 242236e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 242335863739SMike Smith { 242436e0bf6eSScott Long struct aac_aif_command *aif; 242536e0bf6eSScott Long struct aac_container *co, *co_next; 2426cbfd045bSScott Long struct aac_mntinfo *mi; 2427cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 242836e0bf6eSScott Long u_int16_t rsize; 2429b3457b51SScott Long int next, found; 243036e0bf6eSScott Long int added = 0, i = 0; 243135863739SMike Smith 243235863739SMike Smith debug_called(2); 243335863739SMike Smith 243436e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 243536e0bf6eSScott Long aac_print_aif(sc, aif); 243636e0bf6eSScott Long 243736e0bf6eSScott Long /* Is it an event that we should care about? */ 243836e0bf6eSScott Long switch (aif->command) { 243936e0bf6eSScott Long case AifCmdEventNotify: 244036e0bf6eSScott Long switch (aif->data.EN.type) { 244136e0bf6eSScott Long case AifEnAddContainer: 244236e0bf6eSScott Long case AifEnDeleteContainer: 244336e0bf6eSScott Long /* 2444914da7d0SScott Long * A container was added or deleted, but the message 2445914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2446914da7d0SScott Long * containers and sort things out. 244736e0bf6eSScott Long */ 2448fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2449cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 245036e0bf6eSScott Long do { 245136e0bf6eSScott Long /* 2452914da7d0SScott Long * Ask the controller for its containers one at 2453914da7d0SScott Long * a time. 2454914da7d0SScott Long * XXX What if the controller's list changes 2455914da7d0SScott Long * midway through this enumaration? 245636e0bf6eSScott Long * XXX This should be done async. 245736e0bf6eSScott Long */ 245839ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 245939ee03c3SScott Long mi->Command = VM_NameServe; 246039ee03c3SScott Long mi->MntType = FT_FILESYS; 2461cbfd045bSScott Long mi->MntCount = i; 246236e0bf6eSScott Long rsize = sizeof(mir); 2463cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2464cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2465914da7d0SScott Long debug(2, "Error probing container %d\n", 2466914da7d0SScott Long i); 246736e0bf6eSScott Long continue; 246836e0bf6eSScott Long } 2469cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 247036e0bf6eSScott Long /* 2471914da7d0SScott Long * Check the container against our list. 2472914da7d0SScott Long * co->co_found was already set to 0 in a 2473914da7d0SScott Long * previous run. 247436e0bf6eSScott Long */ 2475cbfd045bSScott Long if ((mir->Status == ST_OK) && 2476cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 247736e0bf6eSScott Long found = 0; 2478914da7d0SScott Long TAILQ_FOREACH(co, 2479914da7d0SScott Long &sc->aac_container_tqh, 2480914da7d0SScott Long co_link) { 248136e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2482cbfd045bSScott Long mir->MntTable[0].ObjectId) { 248336e0bf6eSScott Long co->co_found = 1; 248436e0bf6eSScott Long found = 1; 248536e0bf6eSScott Long break; 248636e0bf6eSScott Long } 248736e0bf6eSScott Long } 2488914da7d0SScott Long /* 2489914da7d0SScott Long * If the container matched, continue 2490914da7d0SScott Long * in the list. 2491914da7d0SScott Long */ 249236e0bf6eSScott Long if (found) { 249336e0bf6eSScott Long i++; 249436e0bf6eSScott Long continue; 249536e0bf6eSScott Long } 249636e0bf6eSScott Long 249736e0bf6eSScott Long /* 2498914da7d0SScott Long * This is a new container. Do all the 249970545d1aSScott Long * appropriate things to set it up. 250070545d1aSScott Long */ 2501cbfd045bSScott Long aac_add_container(sc, mir, 1); 250236e0bf6eSScott Long added = 1; 250336e0bf6eSScott Long } 250436e0bf6eSScott Long i++; 2505cbfd045bSScott Long } while ((i < mir->MntRespCount) && 2506914da7d0SScott Long (i < AAC_MAX_CONTAINERS)); 2507cbfd045bSScott Long aac_release_sync_fib(sc); 250836e0bf6eSScott Long 250936e0bf6eSScott Long /* 2510914da7d0SScott Long * Go through our list of containers and see which ones 2511914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2512914da7d0SScott Long * list them they must have been deleted. Do the 2513914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2514914da7d0SScott Long * the co->co_found field. 251536e0bf6eSScott Long */ 251636e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 251736e0bf6eSScott Long while (co != NULL) { 251836e0bf6eSScott Long if (co->co_found == 0) { 2519914da7d0SScott Long device_delete_child(sc->aac_dev, 2520914da7d0SScott Long co->co_disk); 252136e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2522c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc-> 2523914da7d0SScott Long aac_container_lock); 2524914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2525914da7d0SScott Long co_link); 2526914da7d0SScott Long AAC_LOCK_RELEASE(&sc-> 2527914da7d0SScott Long aac_container_lock); 252836e0bf6eSScott Long FREE(co, M_AACBUF); 252936e0bf6eSScott Long co = co_next; 253036e0bf6eSScott Long } else { 253136e0bf6eSScott Long co->co_found = 0; 253236e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 253336e0bf6eSScott Long } 253436e0bf6eSScott Long } 253536e0bf6eSScott Long 253636e0bf6eSScott Long /* Attach the newly created containers */ 253736e0bf6eSScott Long if (added) 253836e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 253936e0bf6eSScott Long 254036e0bf6eSScott Long break; 254136e0bf6eSScott Long 254236e0bf6eSScott Long default: 254336e0bf6eSScott Long break; 254436e0bf6eSScott Long } 254536e0bf6eSScott Long 254636e0bf6eSScott Long default: 254736e0bf6eSScott Long break; 254836e0bf6eSScott Long } 254936e0bf6eSScott Long 255036e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2551c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 255235863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 255335863739SMike Smith if (next != sc->aac_aifq_tail) { 255435863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 255535863739SMike Smith sc->aac_aifq_head = next; 2556b3457b51SScott Long 2557b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 255835863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 255935863739SMike Smith wakeup(sc->aac_aifq); 2560b3457b51SScott Long /* Wakeup any poll()ers */ 2561b3457b51SScott Long selwakeup(&sc->rcv_select); 256235863739SMike Smith } 2563b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 256436e0bf6eSScott Long 256536e0bf6eSScott Long return; 256635863739SMike Smith } 256735863739SMike Smith 2568914da7d0SScott Long /* 25690b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 257036e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 257136e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 257236e0bf6eSScott Long * returning what the card reported. 257335863739SMike Smith */ 257435863739SMike Smith static int 2575fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 257635863739SMike Smith { 257735863739SMike Smith struct aac_rev_check rev_check; 257835863739SMike Smith struct aac_rev_check_resp rev_check_resp; 257935863739SMike Smith int error = 0; 258035863739SMike Smith 258135863739SMike Smith debug_called(2); 258235863739SMike Smith 258335863739SMike Smith /* 258435863739SMike Smith * Copyin the revision struct from userspace 258535863739SMike Smith */ 2586c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2587c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 258835863739SMike Smith return error; 258935863739SMike Smith } 259035863739SMike Smith 2591914da7d0SScott Long debug(2, "Userland revision= %d\n", 2592914da7d0SScott Long rev_check.callingRevision.buildNumber); 259335863739SMike Smith 259435863739SMike Smith /* 259535863739SMike Smith * Doctor up the response struct. 259635863739SMike Smith */ 259735863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2598914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2599914da7d0SScott Long sc->aac_revision.external.ul; 2600914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2601914da7d0SScott Long sc->aac_revision.buildNumber; 260235863739SMike Smith 2603c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2604c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 260535863739SMike Smith } 260635863739SMike Smith 2607914da7d0SScott Long /* 260835863739SMike Smith * Pass the caller the next AIF in their queue 260935863739SMike Smith */ 261035863739SMike Smith static int 2611fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 261235863739SMike Smith { 261335863739SMike Smith struct get_adapter_fib_ioctl agf; 261435863739SMike Smith int error, s; 261535863739SMike Smith 261635863739SMike Smith debug_called(2); 261735863739SMike Smith 261835863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 261935863739SMike Smith 262035863739SMike Smith /* 262135863739SMike Smith * Check the magic number that we gave the caller. 262235863739SMike Smith */ 262336e0bf6eSScott Long if (agf.AdapterFibContext != (int)sc->aifthread) { 262435863739SMike Smith error = EFAULT; 262535863739SMike Smith } else { 262635863739SMike Smith 262735863739SMike Smith s = splbio(); 2628fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 262935863739SMike Smith 263035863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 263135863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 263235863739SMike Smith while (error == EAGAIN) { 2633914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2634914da7d0SScott Long PCATCH, "aacaif", 0); 263535863739SMike Smith if (error == 0) 2636914da7d0SScott Long error = aac_return_aif(sc, 2637914da7d0SScott Long agf.AifFib); 263835863739SMike Smith } 263935863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 264035863739SMike Smith } 264135863739SMike Smith splx(s); 264235863739SMike Smith } 264335863739SMike Smith } 264435863739SMike Smith return(error); 264535863739SMike Smith } 264635863739SMike Smith 2647914da7d0SScott Long /* 26480b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 26490b94a66eSMike Smith */ 26500b94a66eSMike Smith static int 2651fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 26520b94a66eSMike Smith { 2653b3457b51SScott Long int error; 26540b94a66eSMike Smith 26550b94a66eSMike Smith debug_called(2); 26560b94a66eSMike Smith 2657c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 26580b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 26590b94a66eSMike Smith error = EAGAIN; 26600b94a66eSMike Smith } else { 2661c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2662c6eafcf2SScott Long sizeof(struct aac_aif_command)); 266336e0bf6eSScott Long if (error) 266470545d1aSScott Long device_printf(sc->aac_dev, 266570545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 26660b94a66eSMike Smith if (!error) 2667914da7d0SScott Long sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 2668914da7d0SScott Long AAC_AIFQ_LENGTH; 26690b94a66eSMike Smith } 2670b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 26710b94a66eSMike Smith return(error); 26720b94a66eSMike Smith } 267336e0bf6eSScott Long 2674914da7d0SScott Long /* 267536e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 267636e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 267736e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 267836e0bf6eSScott Long */ 267936e0bf6eSScott Long static int 268036e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 268136e0bf6eSScott Long { 268236e0bf6eSScott Long struct aac_query_disk query_disk; 268336e0bf6eSScott Long struct aac_container *co; 2684914da7d0SScott Long struct aac_disk *disk; 268536e0bf6eSScott Long int error, id; 268636e0bf6eSScott Long 268736e0bf6eSScott Long debug_called(2); 268836e0bf6eSScott Long 2689914da7d0SScott Long disk = NULL; 2690914da7d0SScott Long 2691914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2692914da7d0SScott Long sizeof(struct aac_query_disk)); 269336e0bf6eSScott Long if (error) 269436e0bf6eSScott Long return (error); 269536e0bf6eSScott Long 269636e0bf6eSScott Long id = query_disk.ContainerNumber; 269736e0bf6eSScott Long if (id == -1) 269836e0bf6eSScott Long return (EINVAL); 269936e0bf6eSScott Long 2700c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 270136e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 270236e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 270336e0bf6eSScott Long break; 270436e0bf6eSScott Long } 270536e0bf6eSScott Long 270636e0bf6eSScott Long if (co == NULL) { 270736e0bf6eSScott Long query_disk.Valid = 0; 270836e0bf6eSScott Long query_disk.Locked = 0; 270936e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 271036e0bf6eSScott Long } else { 271136e0bf6eSScott Long disk = device_get_softc(co->co_disk); 271236e0bf6eSScott Long query_disk.Valid = 1; 2713914da7d0SScott Long query_disk.Locked = 2714914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 271536e0bf6eSScott Long query_disk.Deleted = 0; 2716b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 271736e0bf6eSScott Long query_disk.Target = disk->unit; 271836e0bf6eSScott Long query_disk.Lun = 0; 271936e0bf6eSScott Long query_disk.UnMapped = 0; 2720914da7d0SScott Long bcopy(disk->ad_dev_t->si_name, 2721914da7d0SScott Long &query_disk.diskDeviceName[0], 10); 272236e0bf6eSScott Long } 272336e0bf6eSScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 272436e0bf6eSScott Long 2725914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2726914da7d0SScott Long sizeof(struct aac_query_disk)); 272736e0bf6eSScott Long 272836e0bf6eSScott Long return (error); 272936e0bf6eSScott Long } 273036e0bf6eSScott Long 2731fe3cb0e1SScott Long static void 2732fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2733fe3cb0e1SScott Long { 2734fe3cb0e1SScott Long struct aac_fib *fib; 2735fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2736fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2737fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2738fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2739fe3cb0e1SScott Long struct aac_getbusinf businfo; 274070545d1aSScott Long struct aac_sim *caminf; 2741fe3cb0e1SScott Long device_t child; 2742fe3cb0e1SScott Long int i, found, error; 2743fe3cb0e1SScott Long 2744fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2745fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 274639ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2747fe3cb0e1SScott Long 2748fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2749fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2750fe3cb0e1SScott Long c_cmd->param = 0; 2751fe3cb0e1SScott Long 2752fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2753fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2754fe3cb0e1SScott Long if (error) { 2755fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2756fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2757fe3cb0e1SScott Long aac_release_sync_fib(sc); 2758fe3cb0e1SScott Long return; 2759fe3cb0e1SScott Long } 2760fe3cb0e1SScott Long 2761fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2762fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2763fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2764fe3cb0e1SScott Long c_resp->Status); 2765fe3cb0e1SScott Long aac_release_sync_fib(sc); 2766fe3cb0e1SScott Long return; 2767fe3cb0e1SScott Long } 2768fe3cb0e1SScott Long 2769fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2770fe3cb0e1SScott Long 2771fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 277239ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 277339ee03c3SScott Long 2774fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2775fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2776fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2777fe3cb0e1SScott Long vmi->ObjId = 0; 2778fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2779fe3cb0e1SScott Long 2780fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2781fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2782fe3cb0e1SScott Long if (error) { 2783fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2784fe3cb0e1SScott Long error); 2785fe3cb0e1SScott Long aac_release_sync_fib(sc); 2786fe3cb0e1SScott Long return; 2787fe3cb0e1SScott Long } 2788fe3cb0e1SScott Long 2789fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2790fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2791fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2792fe3cb0e1SScott Long vmi_resp->Status); 2793fe3cb0e1SScott Long aac_release_sync_fib(sc); 2794fe3cb0e1SScott Long return; 2795fe3cb0e1SScott Long } 2796fe3cb0e1SScott Long 2797fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2798fe3cb0e1SScott Long aac_release_sync_fib(sc); 2799fe3cb0e1SScott Long 2800fe3cb0e1SScott Long found = 0; 2801fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2802fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2803fe3cb0e1SScott Long continue; 2804fe3cb0e1SScott Long 2805a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2806a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 2807fe3cb0e1SScott Long if (caminf == NULL) 2808fe3cb0e1SScott Long continue; 2809fe3cb0e1SScott Long 2810fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2811fe3cb0e1SScott Long if (child == NULL) { 2812fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2813fe3cb0e1SScott Long continue; 2814fe3cb0e1SScott Long } 2815fe3cb0e1SScott Long 2816fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2817fe3cb0e1SScott Long caminf->BusNumber = i; 2818fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2819fe3cb0e1SScott Long caminf->aac_sc = sc; 2820ddb8683eSScott Long caminf->sim_dev = child; 2821fe3cb0e1SScott Long 2822fe3cb0e1SScott Long device_set_ivars(child, caminf); 2823fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 282470545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2825fe3cb0e1SScott Long 2826fe3cb0e1SScott Long found = 1; 2827fe3cb0e1SScott Long } 2828fe3cb0e1SScott Long 2829fe3cb0e1SScott Long if (found) 2830fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2831fe3cb0e1SScott Long 2832fe3cb0e1SScott Long return; 2833fe3cb0e1SScott Long } 2834