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_bio(sc); 23835863739SMike Smith 23935863739SMike Smith #if __FreeBSD_version >= 500005 24035863739SMike Smith /* 24135863739SMike Smith * Initialise command-completion task. 24235863739SMike Smith */ 24335863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 24435863739SMike Smith #endif 24535863739SMike Smith 24635863739SMike Smith /* disable interrupts before we enable anything */ 24735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 24835863739SMike Smith 24935863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25135863739SMike Smith 25235863739SMike Smith /* 253fe94b852SScott Long * Check that the firmware on the card is supported. 254fe94b852SScott Long */ 255fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 256fe94b852SScott Long return(error); 257fe94b852SScott Long 258cbfd045bSScott Long /* Init the sync fib lock */ 259cbfd045bSScott Long AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 260cbfd045bSScott Long 2610b94a66eSMike Smith /* 26235863739SMike Smith * Initialise the adapter. 26335863739SMike Smith */ 2640b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 26535863739SMike Smith return(error); 26635863739SMike Smith 26735863739SMike Smith /* 26835863739SMike Smith * Print a little information about the controller. 26935863739SMike Smith */ 27035863739SMike Smith aac_describe_controller(sc); 27135863739SMike Smith 27235863739SMike Smith /* 27335863739SMike Smith * Register to probe our containers later. 27435863739SMike Smith */ 27536e0bf6eSScott Long TAILQ_INIT(&sc->aac_container_tqh); 276b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 277b3457b51SScott Long 278b3457b51SScott Long /* 279b3457b51SScott Long * Lock for the AIF queue 280b3457b51SScott Long */ 281b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 28236e0bf6eSScott Long 28335863739SMike Smith sc->aac_ich.ich_func = aac_startup; 28435863739SMike Smith sc->aac_ich.ich_arg = sc; 28535863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 286914da7d0SScott Long device_printf(sc->aac_dev, 287914da7d0SScott Long "can't establish configuration hook\n"); 28835863739SMike Smith return(ENXIO); 28935863739SMike Smith } 29035863739SMike Smith 29135863739SMike Smith /* 29235863739SMike Smith * Make the control device. 29335863739SMike Smith */ 29435863739SMike Smith unit = device_get_unit(sc->aac_dev); 2959e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 2969e9466baSRobert Watson 0640, "aac%d", unit); 29736e0bf6eSScott Long #if __FreeBSD_version > 500005 298157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 2994aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 30036e0bf6eSScott Long #endif 30135863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 30235863739SMike Smith 30336e0bf6eSScott Long /* Create the AIF thread */ 30436e0bf6eSScott Long #if __FreeBSD_version > 500005 30570545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 306316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 30736e0bf6eSScott Long #else 30870545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 309914da7d0SScott Long &sc->aifthread, "aac%daif", unit)) 31036e0bf6eSScott Long #endif 31136e0bf6eSScott Long panic("Could not create AIF thread\n"); 31236e0bf6eSScott Long 31336e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3145f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3155f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3165f54d522SScott Long device_printf(sc->aac_dev, 3175f54d522SScott Long "shutdown event registration failed\n"); 31836e0bf6eSScott Long 319fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 32070545d1aSScott Long if (!(sc->quirks & AAC_QUIRK_NOCAM)) { 32170545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 322fe3cb0e1SScott Long aac_get_bus_info(sc); 32370545d1aSScott Long } 324fe3cb0e1SScott Long 32535863739SMike Smith return(0); 32635863739SMike Smith } 32735863739SMike Smith 328914da7d0SScott Long /* 32935863739SMike Smith * Probe for containers, create disks. 33035863739SMike Smith */ 33135863739SMike Smith static void 33235863739SMike Smith aac_startup(void *arg) 33335863739SMike Smith { 334914da7d0SScott Long struct aac_softc *sc; 335cbfd045bSScott Long struct aac_fib *fib; 336cbfd045bSScott Long struct aac_mntinfo *mi; 337cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 33836e0bf6eSScott Long int i = 0; 33935863739SMike Smith 34035863739SMike Smith debug_called(1); 34135863739SMike Smith 342914da7d0SScott Long sc = (struct aac_softc *)arg; 343914da7d0SScott Long 34435863739SMike Smith /* disconnect ourselves from the intrhook chain */ 34535863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 34635863739SMike Smith 347fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 348cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 349cbfd045bSScott Long 35035863739SMike Smith /* loop over possible containers */ 35136e0bf6eSScott Long do { 35235863739SMike Smith /* request information on this container */ 35339ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 35439ee03c3SScott Long mi->Command = VM_NameServe; 35539ee03c3SScott Long mi->MntType = FT_FILESYS; 356cbfd045bSScott Long mi->MntCount = i; 357cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 358cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 35935863739SMike Smith debug(2, "error probing container %d", i); 36035863739SMike Smith continue; 36135863739SMike Smith } 36235863739SMike Smith 363cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 364cbfd045bSScott Long aac_add_container(sc, mir, 0); 36536e0bf6eSScott Long i++; 366cbfd045bSScott Long } while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS)); 367cbfd045bSScott Long 368cbfd045bSScott Long aac_release_sync_fib(sc); 36935863739SMike Smith 37035863739SMike Smith /* poke the bus to actually attach the child devices */ 37135863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 37235863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 37335863739SMike Smith 37435863739SMike Smith /* mark the controller up */ 37535863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 37635863739SMike Smith 37735863739SMike Smith /* enable interrupts now */ 37835863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 37935863739SMike Smith } 38035863739SMike Smith 381914da7d0SScott Long /* 382914da7d0SScott Long * Create a device to respresent a new container 383914da7d0SScott Long */ 384914da7d0SScott Long static void 385cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 386914da7d0SScott Long { 387914da7d0SScott Long struct aac_container *co; 388914da7d0SScott Long device_t child; 389914da7d0SScott Long 390914da7d0SScott Long /* 391914da7d0SScott Long * Check container volume type for validity. Note that many of 392914da7d0SScott Long * the possible types may never show up. 393914da7d0SScott Long */ 394914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 395a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 396a761a1caSScott Long M_NOWAIT | M_ZERO); 397914da7d0SScott Long if (co == NULL) 398914da7d0SScott Long panic("Out of memory?!\n"); 399914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 400914da7d0SScott Long mir->MntTable[0].ObjectId, 401914da7d0SScott Long mir->MntTable[0].FileSystemName, 402914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 403914da7d0SScott Long 404fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 405914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 406914da7d0SScott Long else 407914da7d0SScott Long device_set_ivars(child, co); 408914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 409914da7d0SScott Long mir->MntTable[0].VolType)); 410914da7d0SScott Long co->co_disk = child; 411914da7d0SScott Long co->co_found = f; 412914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 413914da7d0SScott Long sizeof(struct aac_mntobj)); 414c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 415914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 416914da7d0SScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 417914da7d0SScott Long } 418914da7d0SScott Long } 419914da7d0SScott Long 420914da7d0SScott Long /* 42135863739SMike Smith * Free all of the resources associated with (sc) 42235863739SMike Smith * 42335863739SMike Smith * Should not be called if the controller is active. 42435863739SMike Smith */ 42535863739SMike Smith void 42635863739SMike Smith aac_free(struct aac_softc *sc) 42735863739SMike Smith { 428ffb37f33SScott Long 42935863739SMike Smith debug_called(1); 43035863739SMike Smith 43135863739SMike Smith /* remove the control device */ 43235863739SMike Smith if (sc->aac_dev_t != NULL) 43335863739SMike Smith destroy_dev(sc->aac_dev_t); 43435863739SMike Smith 4350b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 4368480cc63SScott Long aac_free_commands(sc); 4370b94a66eSMike Smith if (sc->aac_fib_dmat) 4380b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 43935863739SMike Smith 440ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 441ffb37f33SScott Long 44235863739SMike Smith /* destroy the common area */ 44335863739SMike Smith if (sc->aac_common) { 44435863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 445c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 446c6eafcf2SScott Long sc->aac_common_dmamap); 44735863739SMike Smith } 4480b94a66eSMike Smith if (sc->aac_common_dmat) 4490b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 45035863739SMike Smith 45135863739SMike Smith /* disconnect the interrupt handler */ 45235863739SMike Smith if (sc->aac_intr) 45335863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 45435863739SMike Smith if (sc->aac_irq != NULL) 455c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 456c6eafcf2SScott Long sc->aac_irq); 45735863739SMike Smith 45835863739SMike Smith /* destroy data-transfer DMA tag */ 45935863739SMike Smith if (sc->aac_buffer_dmat) 46035863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 46135863739SMike Smith 46235863739SMike Smith /* destroy the parent DMA tag */ 46335863739SMike Smith if (sc->aac_parent_dmat) 46435863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 46535863739SMike Smith 46635863739SMike Smith /* release the register window mapping */ 46735863739SMike Smith if (sc->aac_regs_resource != NULL) 468914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 469914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 47035863739SMike Smith } 47135863739SMike Smith 472914da7d0SScott Long /* 47335863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 47435863739SMike Smith */ 47535863739SMike Smith int 47635863739SMike Smith aac_detach(device_t dev) 47735863739SMike Smith { 478914da7d0SScott Long struct aac_softc *sc; 47970545d1aSScott Long struct aac_container *co; 48070545d1aSScott Long struct aac_sim *sim; 48135863739SMike Smith int error; 48235863739SMike Smith 48335863739SMike Smith debug_called(1); 48435863739SMike Smith 485914da7d0SScott Long sc = device_get_softc(dev); 486914da7d0SScott Long 48735863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 48835863739SMike Smith return(EBUSY); 48935863739SMike Smith 49070545d1aSScott Long /* Remove the child containers */ 491a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 49270545d1aSScott Long error = device_delete_child(dev, co->co_disk); 49370545d1aSScott Long if (error) 49470545d1aSScott Long return (error); 49565ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 496a761a1caSScott Long free(co, M_AACBUF); 49770545d1aSScott Long } 49870545d1aSScott Long 49970545d1aSScott Long /* Remove the CAM SIMs */ 500a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 501a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 50270545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 50370545d1aSScott Long if (error) 50470545d1aSScott Long return (error); 505a761a1caSScott Long free(sim, M_AACBUF); 50670545d1aSScott Long } 50770545d1aSScott Long 50836e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 50936e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 51036e0bf6eSScott Long wakeup(sc->aifthread); 51136e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 51236e0bf6eSScott Long } 51336e0bf6eSScott Long 51436e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 51536e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 51636e0bf6eSScott Long 51735863739SMike Smith if ((error = aac_shutdown(dev))) 51835863739SMike Smith return(error); 51935863739SMike Smith 5205f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 5215f54d522SScott Long 52235863739SMike Smith aac_free(sc); 52335863739SMike Smith 52435863739SMike Smith return(0); 52535863739SMike Smith } 52635863739SMike Smith 527914da7d0SScott Long /* 52835863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 52935863739SMike Smith * 53035863739SMike Smith * This function is called before detach or system shutdown. 53135863739SMike Smith * 5320b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 53335863739SMike Smith * allow shutdown if any device is open. 53435863739SMike Smith */ 53535863739SMike Smith int 53635863739SMike Smith aac_shutdown(device_t dev) 53735863739SMike Smith { 538914da7d0SScott Long struct aac_softc *sc; 539cbfd045bSScott Long struct aac_fib *fib; 540cbfd045bSScott Long struct aac_close_command *cc; 541cbfd045bSScott Long int s; 54235863739SMike Smith 54335863739SMike Smith debug_called(1); 54435863739SMike Smith 545914da7d0SScott Long sc = device_get_softc(dev); 546914da7d0SScott Long 54735863739SMike Smith s = splbio(); 54835863739SMike Smith 54935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 55035863739SMike Smith 55135863739SMike Smith /* 55235863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 55335863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 55435863739SMike Smith * We've been closed and all I/O completed already 55535863739SMike Smith */ 55635863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 55735863739SMike Smith 558fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 559cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 560cbfd045bSScott Long 56139ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 562cbfd045bSScott Long cc->Command = VM_CloseAll; 563cbfd045bSScott Long cc->ContainerId = 0xffffffff; 564cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 565cbfd045bSScott Long sizeof(struct aac_close_command))) 56635863739SMike Smith printf("FAILED.\n"); 56770545d1aSScott Long else 56870545d1aSScott Long printf("done\n"); 56970545d1aSScott Long #if 0 570914da7d0SScott Long else { 571cbfd045bSScott Long fib->data[0] = 0; 57236e0bf6eSScott Long /* 573914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 57436e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 57536e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 57636e0bf6eSScott Long * driver module with the intent to reload it later. 57736e0bf6eSScott Long */ 578cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 579cbfd045bSScott Long fib, 1)) { 58035863739SMike Smith printf("FAILED.\n"); 58135863739SMike Smith } else { 58235863739SMike Smith printf("done.\n"); 58335863739SMike Smith } 58435863739SMike Smith } 58570545d1aSScott Long #endif 58635863739SMike Smith 58735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 58835863739SMike Smith 58935863739SMike Smith splx(s); 59035863739SMike Smith return(0); 59135863739SMike Smith } 59235863739SMike Smith 593914da7d0SScott Long /* 59435863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 59535863739SMike Smith */ 59635863739SMike Smith int 59735863739SMike Smith aac_suspend(device_t dev) 59835863739SMike Smith { 599914da7d0SScott Long struct aac_softc *sc; 60035863739SMike Smith int s; 60135863739SMike Smith 60235863739SMike Smith debug_called(1); 603914da7d0SScott Long 604914da7d0SScott Long sc = device_get_softc(dev); 605914da7d0SScott Long 60635863739SMike Smith s = splbio(); 60735863739SMike Smith 60835863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 60935863739SMike Smith 61035863739SMike Smith AAC_MASK_INTERRUPTS(sc); 61135863739SMike Smith splx(s); 61235863739SMike Smith return(0); 61335863739SMike Smith } 61435863739SMike Smith 615914da7d0SScott Long /* 61635863739SMike Smith * Bring the controller back to a state ready for operation. 61735863739SMike Smith */ 61835863739SMike Smith int 61935863739SMike Smith aac_resume(device_t dev) 62035863739SMike Smith { 621914da7d0SScott Long struct aac_softc *sc; 62235863739SMike Smith 62335863739SMike Smith debug_called(1); 624914da7d0SScott Long 625914da7d0SScott Long sc = device_get_softc(dev); 626914da7d0SScott Long 62735863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 62835863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 62935863739SMike Smith return(0); 63035863739SMike Smith } 63135863739SMike Smith 632914da7d0SScott Long /* 63335863739SMike Smith * Take an interrupt. 63435863739SMike Smith */ 63535863739SMike Smith void 63635863739SMike Smith aac_intr(void *arg) 63735863739SMike Smith { 638914da7d0SScott Long struct aac_softc *sc; 639f30ac74cSScott Long u_int32_t *resp_queue; 64070545d1aSScott Long u_int16_t reason; 64135863739SMike Smith 64235863739SMike Smith debug_called(2); 64335863739SMike Smith 644914da7d0SScott Long sc = (struct aac_softc *)arg; 645914da7d0SScott Long 646f30ac74cSScott Long /* 647f30ac74cSScott Long * Optimize the common case of adapter response interrupts. 648f30ac74cSScott Long * We must read from the card prior to processing the responses 649f30ac74cSScott Long * to ensure the clear is flushed prior to accessing the queues. 650f30ac74cSScott Long * Reading the queues from local memory might save us a PCI read. 651f30ac74cSScott Long */ 652f30ac74cSScott Long resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; 653f30ac74cSScott Long if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) 654f30ac74cSScott Long reason = AAC_DB_RESPONSE_READY; 655f30ac74cSScott Long else 65635863739SMike Smith reason = AAC_GET_ISTATUS(sc); 657f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 658f30ac74cSScott Long (void)AAC_GET_ISTATUS(sc); 659f30ac74cSScott Long 660f30ac74cSScott Long /* It's not ok to return here because of races with the previous step */ 661f30ac74cSScott Long if (reason & AAC_DB_RESPONSE_READY) 6629c3a7fceSScott Long /* handle completion processing */ 6639c3a7fceSScott Long taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 66435863739SMike Smith 665b3457b51SScott Long /* controller wants to talk to the log */ 66670545d1aSScott Long if (reason & AAC_DB_PRINTF) { 66770545d1aSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 66870545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_PRINTF; 66970545d1aSScott Long } else 67036e0bf6eSScott Long aac_print_printf(sc); 67170545d1aSScott Long } 67235863739SMike Smith 67335863739SMike Smith /* controller has a message for us? */ 67435863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 67536e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 67670545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_AIF; 67770545d1aSScott Long } else { 67870545d1aSScott Long /* 67970545d1aSScott Long * XXX If the kthread is dead and we're at this point, 68070545d1aSScott Long * there are bigger problems than just figuring out 68170545d1aSScott Long * what to do with an AIF. 68270545d1aSScott Long */ 68370545d1aSScott Long } 68470545d1aSScott Long 68570545d1aSScott Long } 68670545d1aSScott Long 68770545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) != 0) 68870545d1aSScott Long /* XXX Should this be done with cv_signal? */ 68936e0bf6eSScott Long wakeup(sc->aifthread); 69036e0bf6eSScott Long } 69135863739SMike Smith 692c6eafcf2SScott Long /* 693914da7d0SScott Long * Command Processing 694914da7d0SScott Long */ 69535863739SMike Smith 696914da7d0SScott Long /* 69735863739SMike Smith * Start as much queued I/O as possible on the controller 69835863739SMike Smith */ 699fe3cb0e1SScott Long void 70035863739SMike Smith aac_startio(struct aac_softc *sc) 70135863739SMike Smith { 70235863739SMike Smith struct aac_command *cm; 70335863739SMike Smith 70435863739SMike Smith debug_called(2); 70535863739SMike Smith 70635863739SMike Smith for (;;) { 707914da7d0SScott Long /* 708914da7d0SScott Long * Try to get a command that's been put off for lack of 709914da7d0SScott Long * resources 710914da7d0SScott Long */ 71135863739SMike Smith cm = aac_dequeue_ready(sc); 71235863739SMike Smith 713914da7d0SScott Long /* 714914da7d0SScott Long * Try to build a command off the bio queue (ignore error 715914da7d0SScott Long * return) 716914da7d0SScott Long */ 7170b94a66eSMike Smith if (cm == NULL) 71835863739SMike Smith aac_bio_command(sc, &cm); 71935863739SMike Smith 72035863739SMike Smith /* nothing to do? */ 72135863739SMike Smith if (cm == NULL) 72235863739SMike Smith break; 72335863739SMike Smith 72435863739SMike Smith /* try to give the command to the controller */ 72535863739SMike Smith if (aac_start(cm) == EBUSY) { 72635863739SMike Smith /* put it on the ready queue for later */ 72735863739SMike Smith aac_requeue_ready(cm); 72835863739SMike Smith break; 72935863739SMike Smith } 73035863739SMike Smith } 73135863739SMike Smith } 73235863739SMike Smith 733914da7d0SScott Long /* 73435863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 73535863739SMike Smith * last moment when possible. 73635863739SMike Smith */ 73735863739SMike Smith static int 73835863739SMike Smith aac_start(struct aac_command *cm) 73935863739SMike Smith { 740914da7d0SScott Long struct aac_softc *sc; 741ed5c5fb4SMike Smith int error; 74235863739SMike Smith 74335863739SMike Smith debug_called(2); 74435863739SMike Smith 745914da7d0SScott Long sc = cm->cm_sc; 746914da7d0SScott Long 74735863739SMike Smith /* get the command mapped */ 74835863739SMike Smith aac_map_command(cm); 74935863739SMike Smith 7500b94a66eSMike Smith /* fix up the address values in the FIB */ 75135863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 75235863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 75335863739SMike Smith 75435863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 755cb0d64b9SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 75635863739SMike Smith /* put the FIB on the outbound queue */ 75736e0bf6eSScott Long error = aac_enqueue_fib(sc, cm->cm_queue, cm); 7580b94a66eSMike Smith return(error); 75935863739SMike Smith } 76035863739SMike Smith 761914da7d0SScott Long /* 76235863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 76335863739SMike Smith */ 76435863739SMike Smith static void 76570545d1aSScott Long aac_command_thread(struct aac_softc *sc) 76635863739SMike Smith { 76735863739SMike Smith struct aac_fib *fib; 76835863739SMike Smith u_int32_t fib_size; 76936e0bf6eSScott Long int size; 77035863739SMike Smith 77136e0bf6eSScott Long debug_called(2); 77235863739SMike Smith 77336e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_RUNNING; 77436e0bf6eSScott Long 77536e0bf6eSScott Long while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 77670545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 77770545d1aSScott Long tsleep(sc->aifthread, PRIBIO, "aifthd", 77870545d1aSScott Long AAC_PERIODIC_INTERVAL * hz); 77936e0bf6eSScott Long 78070545d1aSScott Long /* While we're here, check to see if any commands are stuck */ 78170545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 78270545d1aSScott Long aac_timeout(sc); 78370545d1aSScott Long 78470545d1aSScott Long /* Check the hardware printf message buffer */ 78570545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) { 78670545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_PRINTF; 78770545d1aSScott Long aac_print_printf(sc); 78870545d1aSScott Long } 78970545d1aSScott Long 79070545d1aSScott Long while (sc->aifflags & AAC_AIFFLAGS_AIF) { 79170545d1aSScott Long 792914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 79370545d1aSScott Long &fib_size, &fib)) { 79470545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_AIF; 79535863739SMike Smith break; /* nothing to do */ 79670545d1aSScott Long } 79735863739SMike Smith 79836e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 79936e0bf6eSScott Long 80035863739SMike Smith switch (fib->Header.Command) { 80135863739SMike Smith case AifRequest: 80236e0bf6eSScott Long aac_handle_aif(sc, fib); 80335863739SMike Smith break; 80435863739SMike Smith default: 805914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 806914da7d0SScott Long "from controller\n"); 80735863739SMike Smith break; 80835863739SMike Smith } 80935863739SMike Smith 81036e0bf6eSScott Long if ((fib->Header.XferState == 0) || 81136e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 81236e0bf6eSScott Long break; 81336e0bf6eSScott Long 81470545d1aSScott Long /* Return the AIF to the controller. */ 81536e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 81636e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 81736e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 81836e0bf6eSScott Long 81936e0bf6eSScott Long /* XXX Compute the Size field? */ 82036e0bf6eSScott Long size = fib->Header.Size; 82136e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 82236e0bf6eSScott Long size = sizeof(struct aac_fib); 82336e0bf6eSScott Long fib->Header.Size = size; 82436e0bf6eSScott Long } 82536e0bf6eSScott Long /* 826914da7d0SScott Long * Since we did not generate this command, it 827914da7d0SScott Long * cannot go through the normal 828914da7d0SScott Long * enqueue->startio chain. 82936e0bf6eSScott Long */ 830914da7d0SScott Long aac_enqueue_response(sc, 831914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 832914da7d0SScott Long fib); 83336e0bf6eSScott Long } 83436e0bf6eSScott Long } 83536e0bf6eSScott Long } 83636e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 83736e0bf6eSScott Long wakeup(sc->aac_dev); 83836e0bf6eSScott Long 83936e0bf6eSScott Long #if __FreeBSD_version > 500005 84036e0bf6eSScott Long mtx_lock(&Giant); 84136e0bf6eSScott Long #endif 84236e0bf6eSScott Long kthread_exit(0); 84335863739SMike Smith } 84435863739SMike Smith 845914da7d0SScott Long /* 8469c3a7fceSScott Long * Process completed commands. 84735863739SMike Smith */ 84835863739SMike Smith static void 8499c3a7fceSScott Long aac_complete(void *context, int pending) 85035863739SMike Smith { 8519c3a7fceSScott Long struct aac_softc *sc; 85235863739SMike Smith struct aac_command *cm; 85335863739SMike Smith struct aac_fib *fib; 85435863739SMike Smith u_int32_t fib_size; 85535863739SMike Smith 85635863739SMike Smith debug_called(2); 85735863739SMike Smith 8589c3a7fceSScott Long sc = (struct aac_softc *)context; 8599c3a7fceSScott Long 8609c3a7fceSScott Long /* pull completed commands off the queue */ 86135863739SMike Smith for (;;) { 86235863739SMike Smith /* look for completed FIBs on our queue */ 863914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 864914da7d0SScott Long &fib)) 86535863739SMike Smith break; /* nothing to do */ 86635863739SMike Smith 86735863739SMike Smith /* get the command, unmap and queue for later processing */ 868cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 86935863739SMike Smith if (cm == NULL) { 87035863739SMike Smith AAC_PRINT_FIB(sc, fib); 8719c3a7fceSScott Long break; 8729c3a7fceSScott Long } 8739c3a7fceSScott Long 8740b94a66eSMike Smith aac_remove_busy(cm); 87535863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 87635863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 87735863739SMike Smith 87835863739SMike Smith /* is there a completion handler? */ 87935863739SMike Smith if (cm->cm_complete != NULL) { 88035863739SMike Smith cm->cm_complete(cm); 88135863739SMike Smith } else { 88235863739SMike Smith /* assume that someone is sleeping on this command */ 88335863739SMike Smith wakeup(cm); 88435863739SMike Smith } 88535863739SMike Smith } 8860b94a66eSMike Smith 8870b94a66eSMike Smith /* see if we can start some more I/O */ 8880b94a66eSMike Smith aac_startio(sc); 88935863739SMike Smith } 89035863739SMike Smith 891914da7d0SScott Long /* 89235863739SMike Smith * Handle a bio submitted from a disk device. 89335863739SMike Smith */ 89435863739SMike Smith void 89535863739SMike Smith aac_submit_bio(struct bio *bp) 89635863739SMike Smith { 897914da7d0SScott Long struct aac_disk *ad; 898914da7d0SScott Long struct aac_softc *sc; 89935863739SMike Smith 90035863739SMike Smith debug_called(2); 90135863739SMike Smith 9027540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 903914da7d0SScott Long sc = ad->ad_controller; 904914da7d0SScott Long 90535863739SMike Smith /* queue the BIO and try to get some work done */ 9060b94a66eSMike Smith aac_enqueue_bio(sc, bp); 90735863739SMike Smith aac_startio(sc); 90835863739SMike Smith } 90935863739SMike Smith 910914da7d0SScott Long /* 91135863739SMike Smith * Get a bio and build a command to go with it. 91235863739SMike Smith */ 91335863739SMike Smith static int 91435863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 91535863739SMike Smith { 91635863739SMike Smith struct aac_command *cm; 91735863739SMike Smith struct aac_fib *fib; 91835863739SMike Smith struct aac_blockread *br; 91935863739SMike Smith struct aac_blockwrite *bw; 92035863739SMike Smith struct aac_disk *ad; 92135863739SMike Smith struct bio *bp; 92235863739SMike Smith 92335863739SMike Smith debug_called(2); 92435863739SMike Smith 92535863739SMike Smith /* get the resources we will need */ 92635863739SMike Smith cm = NULL; 9270b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 92835863739SMike Smith goto fail; 92935863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 93035863739SMike Smith goto fail; 93135863739SMike Smith 93235863739SMike Smith /* fill out the command */ 9330b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9340b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9350b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 93635863739SMike Smith cm->cm_private = bp; 9370b94a66eSMike Smith cm->cm_timestamp = time_second; 93836e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 93935863739SMike Smith 94035863739SMike Smith /* build the FIB */ 94135863739SMike Smith fib = cm->cm_fib; 94235863739SMike Smith fib->Header.XferState = 94335863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 94435863739SMike Smith AAC_FIBSTATE_INITIALISED | 945f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 94635863739SMike Smith AAC_FIBSTATE_FROMHOST | 94735863739SMike Smith AAC_FIBSTATE_REXPECTED | 948f30ac74cSScott Long AAC_FIBSTATE_NORM | 949f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 950f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 95135863739SMike Smith fib->Header.Command = ContainerCommand; 95235863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 95335863739SMike Smith 95435863739SMike Smith /* build the read/write request */ 9557540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 95635863739SMike Smith if (BIO_IS_READ(bp)) { 95735863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 95835863739SMike Smith br->Command = VM_CtBlockRead; 95935863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 96035863739SMike Smith br->BlockNumber = bp->bio_pblkno; 96135863739SMike Smith br->ByteCount = bp->bio_bcount; 96235863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 96335863739SMike Smith cm->cm_sgtable = &br->SgMap; 96435863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 96535863739SMike Smith } else { 96635863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 96735863739SMike Smith bw->Command = VM_CtBlockWrite; 96835863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 96935863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 97035863739SMike Smith bw->ByteCount = bp->bio_bcount; 97135863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 97235863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 97335863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 97435863739SMike Smith cm->cm_sgtable = &bw->SgMap; 97535863739SMike Smith } 97635863739SMike Smith 97735863739SMike Smith *cmp = cm; 97835863739SMike Smith return(0); 97935863739SMike Smith 98035863739SMike Smith fail: 98135863739SMike Smith if (bp != NULL) 9820b94a66eSMike Smith aac_enqueue_bio(sc, bp); 98335863739SMike Smith if (cm != NULL) 98435863739SMike Smith aac_release_command(cm); 98535863739SMike Smith return(ENOMEM); 98635863739SMike Smith } 98735863739SMike Smith 988914da7d0SScott Long /* 98935863739SMike Smith * Handle a bio-instigated command that has been completed. 99035863739SMike Smith */ 99135863739SMike Smith static void 99235863739SMike Smith aac_bio_complete(struct aac_command *cm) 99335863739SMike Smith { 99435863739SMike Smith struct aac_blockread_response *brr; 99535863739SMike Smith struct aac_blockwrite_response *bwr; 99635863739SMike Smith struct bio *bp; 99735863739SMike Smith AAC_FSAStatus status; 99835863739SMike Smith 99935863739SMike Smith /* fetch relevant status and then release the command */ 100035863739SMike Smith bp = (struct bio *)cm->cm_private; 100135863739SMike Smith if (BIO_IS_READ(bp)) { 100235863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 100335863739SMike Smith status = brr->Status; 100435863739SMike Smith } else { 100535863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 100635863739SMike Smith status = bwr->Status; 100735863739SMike Smith } 100835863739SMike Smith aac_release_command(cm); 100935863739SMike Smith 101035863739SMike Smith /* fix up the bio based on status */ 101135863739SMike Smith if (status == ST_OK) { 101235863739SMike Smith bp->bio_resid = 0; 101335863739SMike Smith } else { 101435863739SMike Smith bp->bio_error = EIO; 101535863739SMike Smith bp->bio_flags |= BIO_ERROR; 10160b94a66eSMike Smith /* pass an error string out to the disk layer */ 1017914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1018914da7d0SScott Long status); 101935863739SMike Smith } 10200b94a66eSMike Smith aac_biodone(bp); 102135863739SMike Smith } 102235863739SMike Smith 1023914da7d0SScott Long /* 102435863739SMike Smith * Submit a command to the controller, return when it completes. 1025b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1026b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1027b3457b51SScott Long * because there is a risk that a signal could wakeup the tsleep before 1028b3457b51SScott Long * the card has a chance to complete the command. The passed in timeout 1029b3457b51SScott Long * is ignored for the same reason. Since there is no way to cancel a 1030b3457b51SScott Long * command in progress, we should probably create a 'dead' queue where 1031b3457b51SScott Long * commands go that have been interrupted/timed-out/etc, that keeps them 1032b3457b51SScott Long * out of the free pool. That way, if the card is just slow, it won't 1033b3457b51SScott Long * spam the memory of a command that has been recycled. 103435863739SMike Smith */ 103535863739SMike Smith static int 103635863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 103735863739SMike Smith { 103835863739SMike Smith int s, error = 0; 103935863739SMike Smith 104035863739SMike Smith debug_called(2); 104135863739SMike Smith 104235863739SMike Smith /* Put the command on the ready queue and get things going */ 104336e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 104435863739SMike Smith aac_enqueue_ready(cm); 104535863739SMike Smith aac_startio(cm->cm_sc); 104635863739SMike Smith s = splbio(); 104735863739SMike Smith while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1048b3457b51SScott Long error = tsleep(cm, PRIBIO, "aacwait", 0); 104935863739SMike Smith } 105035863739SMike Smith splx(s); 105135863739SMike Smith return(error); 105235863739SMike Smith } 105335863739SMike Smith 1054914da7d0SScott Long /* 1055914da7d0SScott Long *Command Buffer Management 1056914da7d0SScott Long */ 105735863739SMike Smith 1058914da7d0SScott Long /* 105935863739SMike Smith * Allocate a command. 106035863739SMike Smith */ 1061fe3cb0e1SScott Long int 106235863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 106335863739SMike Smith { 106435863739SMike Smith struct aac_command *cm; 106535863739SMike Smith 106635863739SMike Smith debug_called(3); 106735863739SMike Smith 1068ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 10698480cc63SScott Long if ((aac_alloc_commands(sc) != 0) || 10708480cc63SScott Long (cm = aac_dequeue_free(sc)) == NULL) 107135863739SMike Smith return (ENOMEM); 1072ffb37f33SScott Long } 107335863739SMike Smith 10740b94a66eSMike Smith *cmp = cm; 10750b94a66eSMike Smith return(0); 10760b94a66eSMike Smith } 10770b94a66eSMike Smith 1078914da7d0SScott Long /* 10790b94a66eSMike Smith * Release a command back to the freelist. 10800b94a66eSMike Smith */ 1081fe3cb0e1SScott Long void 10820b94a66eSMike Smith aac_release_command(struct aac_command *cm) 10830b94a66eSMike Smith { 10840b94a66eSMike Smith debug_called(3); 10850b94a66eSMike Smith 10860b94a66eSMike Smith /* (re)initialise the command/FIB */ 108735863739SMike Smith cm->cm_sgtable = NULL; 108835863739SMike Smith cm->cm_flags = 0; 108935863739SMike Smith cm->cm_complete = NULL; 109035863739SMike Smith cm->cm_private = NULL; 109135863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 109235863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 109335863739SMike Smith cm->cm_fib->Header.Flags = 0; 109435863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 109535863739SMike Smith 109635863739SMike Smith /* 109735863739SMike Smith * These are duplicated in aac_start to cover the case where an 109835863739SMike Smith * intermediate stage may have destroyed them. They're left 109935863739SMike Smith * initialised here for debugging purposes only. 110035863739SMike Smith */ 110135863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1102f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1103f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 110435863739SMike Smith 110535863739SMike Smith aac_enqueue_free(cm); 110635863739SMike Smith } 110735863739SMike Smith 1108914da7d0SScott Long /* 11090b94a66eSMike Smith * Map helper for command/FIB allocation. 111035863739SMike Smith */ 111135863739SMike Smith static void 11120b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 111335863739SMike Smith { 11148480cc63SScott Long uint32_t *fibphys; 1115914da7d0SScott Long 11168480cc63SScott Long fibphys = (uint32_t *)arg; 111735863739SMike Smith 111835863739SMike Smith debug_called(3); 111935863739SMike Smith 1120ffb37f33SScott Long *fibphys = segs[0].ds_addr; 112135863739SMike Smith } 112235863739SMike Smith 1123914da7d0SScott Long /* 11240b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 112535863739SMike Smith */ 11260b94a66eSMike Smith static int 11270b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 112835863739SMike Smith { 112935863739SMike Smith struct aac_command *cm; 1130ffb37f33SScott Long struct aac_fibmap *fm; 11318480cc63SScott Long uint32_t fibphys; 1132ffb37f33SScott Long int i, error; 113335863739SMike Smith 113435863739SMike Smith debug_called(1); 113535863739SMike Smith 1136ffb37f33SScott Long if (sc->total_fibs + AAC_FIB_COUNT > AAC_MAX_FIBS) 1137ffb37f33SScott Long return (ENOMEM); 1138ffb37f33SScott Long 11398480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1140ffb37f33SScott Long 11410b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1142ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1143ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 114470545d1aSScott Long device_printf(sc->aac_dev, 114570545d1aSScott Long "Not enough contiguous memory available.\n"); 11468480cc63SScott Long free(fm, M_AACBUF); 11470b94a66eSMike Smith return (ENOMEM); 114835863739SMike Smith } 1149128aa5a0SScott Long 1150ffb37f33SScott Long bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1151ffb37f33SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1152ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1153128aa5a0SScott Long 11540b94a66eSMike Smith /* initialise constant fields in the command structure */ 1155ffb37f33SScott Long bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11560b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11578480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1158ffb37f33SScott Long fm->aac_commands = cm; 115935863739SMike Smith cm->cm_sc = sc; 1160ffb37f33SScott Long cm->cm_fib = fm->aac_fibs + i; 11618480cc63SScott Long cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1162cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 116335863739SMike Smith 1164ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1165ffb37f33SScott Long &cm->cm_datamap)) == 0) 116635863739SMike Smith aac_release_command(cm); 1167ffb37f33SScott Long else 11688480cc63SScott Long break; 11698480cc63SScott Long sc->total_fibs++; 117035863739SMike Smith } 1171ffb37f33SScott Long 11728480cc63SScott Long if (i > 0) { 1173ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 11740b94a66eSMike Smith return (0); 117535863739SMike Smith } 117635863739SMike Smith 11778480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 11788480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 11798480cc63SScott Long free(fm, M_AACBUF); 11808480cc63SScott Long return (ENOMEM); 11818480cc63SScott Long } 11828480cc63SScott Long 1183914da7d0SScott Long /* 11840b94a66eSMike Smith * Free FIBs owned by this adapter. 118535863739SMike Smith */ 118635863739SMike Smith static void 11878480cc63SScott Long aac_free_commands(struct aac_softc *sc) 118835863739SMike Smith { 11898480cc63SScott Long struct aac_fibmap *fm; 1190ffb37f33SScott Long struct aac_command *cm; 119135863739SMike Smith int i; 119235863739SMike Smith 119335863739SMike Smith debug_called(1); 119435863739SMike Smith 11958480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 11968480cc63SScott Long 11978480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 11988480cc63SScott Long /* 11998480cc63SScott Long * We check against total_fibs to handle partially 12008480cc63SScott Long * allocated blocks. 12018480cc63SScott Long */ 12028480cc63SScott Long for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1203ffb37f33SScott Long cm = fm->aac_commands + i; 1204ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1205ffb37f33SScott Long } 1206ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1207ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12088480cc63SScott Long free(fm, M_AACBUF); 12098480cc63SScott Long } 121035863739SMike Smith } 121135863739SMike Smith 1212914da7d0SScott Long /* 121335863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 121435863739SMike Smith */ 121535863739SMike Smith static void 121635863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 121735863739SMike Smith { 1218914da7d0SScott Long struct aac_command *cm; 1219914da7d0SScott Long struct aac_fib *fib; 122035863739SMike Smith struct aac_sg_table *sg; 122135863739SMike Smith int i; 122235863739SMike Smith 122335863739SMike Smith debug_called(3); 122435863739SMike Smith 1225914da7d0SScott Long cm = (struct aac_command *)arg; 1226914da7d0SScott Long fib = cm->cm_fib; 1227914da7d0SScott Long 122835863739SMike Smith /* find the s/g table */ 122935863739SMike Smith sg = cm->cm_sgtable; 123035863739SMike Smith 123135863739SMike Smith /* copy into the FIB */ 123235863739SMike Smith if (sg != NULL) { 123335863739SMike Smith sg->SgCount = nseg; 123435863739SMike Smith for (i = 0; i < nseg; i++) { 123535863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 123635863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 123735863739SMike Smith } 123835863739SMike Smith /* update the FIB size for the s/g count */ 123935863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 124035863739SMike Smith } 124135863739SMike Smith 124235863739SMike Smith } 124335863739SMike Smith 1244914da7d0SScott Long /* 124535863739SMike Smith * Map a command into controller-visible space. 124635863739SMike Smith */ 124735863739SMike Smith static void 124835863739SMike Smith aac_map_command(struct aac_command *cm) 124935863739SMike Smith { 1250914da7d0SScott Long struct aac_softc *sc; 125135863739SMike Smith 125235863739SMike Smith debug_called(2); 125335863739SMike Smith 1254914da7d0SScott Long sc = cm->cm_sc; 1255914da7d0SScott Long 125635863739SMike Smith /* don't map more than once */ 125735863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 125835863739SMike Smith return; 125935863739SMike Smith 126035863739SMike Smith if (cm->cm_datalen != 0) { 1261914da7d0SScott Long bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 1262914da7d0SScott Long cm->cm_data, cm->cm_datalen, 1263914da7d0SScott Long aac_map_command_sg, cm, 0); 126435863739SMike Smith 126535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1266c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1267c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 126835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1269c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1270c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 127135863739SMike Smith } 127235863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 127335863739SMike Smith } 127435863739SMike Smith 1275914da7d0SScott Long /* 127635863739SMike Smith * Unmap a command from controller-visible space. 127735863739SMike Smith */ 127835863739SMike Smith static void 127935863739SMike Smith aac_unmap_command(struct aac_command *cm) 128035863739SMike Smith { 1281914da7d0SScott Long struct aac_softc *sc; 128235863739SMike Smith 128335863739SMike Smith debug_called(2); 128435863739SMike Smith 1285914da7d0SScott Long sc = cm->cm_sc; 1286914da7d0SScott Long 128735863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 128835863739SMike Smith return; 128935863739SMike Smith 129035863739SMike Smith if (cm->cm_datalen != 0) { 129135863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1292c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1293c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 129435863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1295c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1296c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 129735863739SMike Smith 129835863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 129935863739SMike Smith } 130035863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 130135863739SMike Smith } 130235863739SMike Smith 1303914da7d0SScott Long /* 1304914da7d0SScott Long * Hardware Interface 1305914da7d0SScott Long */ 130635863739SMike Smith 1307914da7d0SScott Long /* 130835863739SMike Smith * Initialise the adapter. 130935863739SMike Smith */ 131035863739SMike Smith static void 131135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 131235863739SMike Smith { 1313914da7d0SScott Long struct aac_softc *sc; 131435863739SMike Smith 131535863739SMike Smith debug_called(1); 131635863739SMike Smith 1317914da7d0SScott Long sc = (struct aac_softc *)arg; 1318914da7d0SScott Long 131935863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 132035863739SMike Smith } 132135863739SMike Smith 1322fe94b852SScott Long /* 1323fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1324fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1325fe94b852SScott Long */ 1326fe94b852SScott Long static int 1327fe94b852SScott Long aac_check_firmware(struct aac_softc *sc) 1328fe94b852SScott Long { 1329fe94b852SScott Long u_int32_t major, minor; 1330fe94b852SScott Long 1331fe94b852SScott Long debug_called(1); 1332fe94b852SScott Long 1333fe94b852SScott Long if (sc->quirks & AAC_QUIRK_PERC2QC) { 1334fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1335fe94b852SScott Long NULL)) { 1336fe94b852SScott Long device_printf(sc->aac_dev, 1337fe94b852SScott Long "Error reading firmware version\n"); 1338fe94b852SScott Long return (EIO); 1339fe94b852SScott Long } 1340fe94b852SScott Long 1341fe94b852SScott Long /* These numbers are stored as ASCII! */ 1342fe94b852SScott Long major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30; 1343fe94b852SScott Long minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30; 1344fe94b852SScott Long if (major == 1) { 1345fe94b852SScott Long device_printf(sc->aac_dev, 1346fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1347fe94b852SScott Long major, minor); 1348fe94b852SScott Long return (EINVAL); 1349fe94b852SScott Long } 1350fe94b852SScott Long } 1351fe94b852SScott Long 1352fe94b852SScott Long return (0); 1353fe94b852SScott Long } 1354fe94b852SScott Long 135535863739SMike Smith static int 135635863739SMike Smith aac_init(struct aac_softc *sc) 135735863739SMike Smith { 135835863739SMike Smith struct aac_adapter_init *ip; 135935863739SMike Smith time_t then; 136035863739SMike Smith u_int32_t code; 136135863739SMike Smith u_int8_t *qaddr; 136235863739SMike Smith 136335863739SMike Smith debug_called(1); 136435863739SMike Smith 136535863739SMike Smith /* 136635863739SMike Smith * First wait for the adapter to come ready. 136735863739SMike Smith */ 136835863739SMike Smith then = time_second; 136935863739SMike Smith do { 137035863739SMike Smith code = AAC_GET_FWSTATUS(sc); 137135863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 137235863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 137335863739SMike Smith return(ENXIO); 137435863739SMike Smith } 137535863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1376914da7d0SScott Long device_printf(sc->aac_dev, 1377914da7d0SScott Long "FATAL: controller kernel panic\n"); 137835863739SMike Smith return(ENXIO); 137935863739SMike Smith } 138035863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1381914da7d0SScott Long device_printf(sc->aac_dev, 1382914da7d0SScott Long "FATAL: controller not coming ready, " 1383c6eafcf2SScott Long "status %x\n", code); 138435863739SMike Smith return(ENXIO); 138535863739SMike Smith } 138635863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 138735863739SMike Smith 138835863739SMike Smith /* 138935863739SMike Smith * Create DMA tag for the common structure and allocate it. 139035863739SMike Smith */ 139135863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1392c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1393fe3cb0e1SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 139435863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 139535863739SMike Smith NULL, NULL, /* filter, filterarg */ 1396ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1397914da7d0SScott Long 1, /* nsegments */ 139835863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 139935863739SMike Smith 0, /* flags */ 140035863739SMike Smith &sc->aac_common_dmat)) { 1401914da7d0SScott Long device_printf(sc->aac_dev, 1402914da7d0SScott Long "can't allocate common structure DMA tag\n"); 140335863739SMike Smith return(ENOMEM); 140435863739SMike Smith } 1405c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1406c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 140735863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 140835863739SMike Smith return(ENOMEM); 140935863739SMike Smith } 1410ffb37f33SScott Long 1411ffb37f33SScott Long /* 1412ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1413ffb37f33SScott Long * below address 8192 in physical memory. 1414ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1415ffb37f33SScott Long * of ignored? 1416ffb37f33SScott Long */ 1417914da7d0SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1418ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1419ffb37f33SScott Long aac_common_map, sc, 0); 1420ffb37f33SScott Long 1421ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1422ffb37f33SScott Long (uint8_t *)sc->aac_common += 8192; 1423ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1424ffb37f33SScott Long } 142535863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 142635863739SMike Smith 1427ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1428ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 1429ffb37f33SScott Long sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 14308480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 14318480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1432ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1433ffb37f33SScott Long break; 1434ffb37f33SScott Long } 1435ffb37f33SScott Long if (sc->total_fibs == 0) 1436ffb37f33SScott Long return (ENOMEM); 1437ffb37f33SScott Long 143835863739SMike Smith /* 1439914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1440914da7d0SScott Long * physical location of various important shared data structures. 144135863739SMike Smith */ 144235863739SMike Smith ip = &sc->aac_common->ac_init; 144335863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1444f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 144535863739SMike Smith 1446c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1447c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1448f30ac74cSScott Long ip->AdapterFibsVirtualAddress = (u_int32_t)&sc->aac_common->ac_fibs[0]; 144935863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 145035863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 145135863739SMike Smith 1452c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1453c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 145435863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 145535863739SMike Smith 1456f30ac74cSScott Long /* The adapter assumes that pages are 4K in size */ 1457f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 145835863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 145935863739SMike Smith 146035863739SMike Smith /* 1461c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1462c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1463c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 146435863739SMike Smith * 146535863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1466914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1467914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1468914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1469914da7d0SScott Long * does. 147035863739SMike Smith * 1471914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1472914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1473914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1474914da7d0SScott Long * virtue of a table. 147535863739SMike Smith */ 147635863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 147735863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 147835863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1479914da7d0SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + 1480914da7d0SScott Long ((u_int32_t)sc->aac_queues - 1481914da7d0SScott Long (u_int32_t)sc->aac_common); 148235863739SMike Smith 1483c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1484c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1485c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1486c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1487c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1488c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1489c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1490c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1491c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1492c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1493c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1494c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1495c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1496c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1497c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1498c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1499c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1500c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1501c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1502c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1503c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1504c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1505c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1506c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1507c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1508c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1509c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1510c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1511c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1512c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1513c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1514c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1515c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1516c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1517c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1518c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1519c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1520c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1521c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1522c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1523c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1524c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1525c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1526c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1527c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1528c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1529c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1530c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 153135863739SMike Smith 153235863739SMike Smith /* 153335863739SMike Smith * Do controller-type-specific initialisation 153435863739SMike Smith */ 153535863739SMike Smith switch (sc->aac_hwif) { 153635863739SMike Smith case AAC_HWIF_I960RX: 153735863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 153835863739SMike Smith break; 153935863739SMike Smith } 154035863739SMike Smith 154135863739SMike Smith /* 154235863739SMike Smith * Give the init structure to the controller. 154335863739SMike Smith */ 154435863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1545914da7d0SScott Long sc->aac_common_busaddr + 1546914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1547914da7d0SScott Long NULL)) { 1548914da7d0SScott Long device_printf(sc->aac_dev, 1549914da7d0SScott Long "error establishing init structure\n"); 155035863739SMike Smith return(EIO); 155135863739SMike Smith } 155235863739SMike Smith 155335863739SMike Smith return(0); 155435863739SMike Smith } 155535863739SMike Smith 1556914da7d0SScott Long /* 155735863739SMike Smith * Send a synchronous command to the controller and wait for a result. 155835863739SMike Smith */ 155935863739SMike Smith static int 156035863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 156135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 156235863739SMike Smith u_int32_t *sp) 156335863739SMike Smith { 156435863739SMike Smith time_t then; 156535863739SMike Smith u_int32_t status; 156635863739SMike Smith 156735863739SMike Smith debug_called(3); 156835863739SMike Smith 156935863739SMike Smith /* populate the mailbox */ 157035863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 157135863739SMike Smith 157235863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 157335863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 157435863739SMike Smith 157535863739SMike Smith /* then set it to signal the adapter */ 157635863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 157735863739SMike Smith 157835863739SMike Smith /* spin waiting for the command to complete */ 157935863739SMike Smith then = time_second; 158035863739SMike Smith do { 158135863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 158235863739SMike Smith debug(2, "timed out"); 158335863739SMike Smith return(EIO); 158435863739SMike Smith } 158535863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 158635863739SMike Smith 158735863739SMike Smith /* clear the completion flag */ 158835863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 158935863739SMike Smith 159035863739SMike Smith /* get the command status */ 159135863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 159235863739SMike Smith if (sp != NULL) 159335863739SMike Smith *sp = status; 15940b94a66eSMike Smith return(0); 159535863739SMike Smith } 159635863739SMike Smith 1597914da7d0SScott Long /* 1598cbfd045bSScott Long * Grab the sync fib area. 1599cbfd045bSScott Long */ 1600cbfd045bSScott Long int 1601fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1602cbfd045bSScott Long { 1603cbfd045bSScott Long 1604cbfd045bSScott Long /* 1605cbfd045bSScott Long * If the force flag is set, the system is shutting down, or in 1606cbfd045bSScott Long * trouble. Ignore the mutex. 1607cbfd045bSScott Long */ 1608cbfd045bSScott Long if (!(flags & AAC_SYNC_LOCK_FORCE)) 1609cbfd045bSScott Long AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1610cbfd045bSScott Long 1611cbfd045bSScott Long *fib = &sc->aac_common->ac_sync_fib; 1612cbfd045bSScott Long 1613cbfd045bSScott Long return (1); 1614cbfd045bSScott Long } 1615cbfd045bSScott Long 1616cbfd045bSScott Long /* 1617cbfd045bSScott Long * Release the sync fib area. 1618cbfd045bSScott Long */ 1619cbfd045bSScott Long void 1620cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc) 1621cbfd045bSScott Long { 1622cbfd045bSScott Long 1623cbfd045bSScott Long AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1624cbfd045bSScott Long } 1625cbfd045bSScott Long 1626cbfd045bSScott Long /* 162735863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 162835863739SMike Smith */ 1629cbfd045bSScott Long int 163035863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1631cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 163235863739SMike Smith { 163335863739SMike Smith debug_called(3); 163435863739SMike Smith 163535863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 163635863739SMike Smith return(EINVAL); 163735863739SMike Smith 163835863739SMike Smith /* 163935863739SMike Smith * Set up the sync FIB 164035863739SMike Smith */ 1641914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1642914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1643c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 164435863739SMike Smith fib->Header.XferState |= xferstate; 164535863739SMike Smith fib->Header.Command = command; 164635863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 164735863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 164835863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 164935863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1650c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1651914da7d0SScott Long offsetof(struct aac_common, 1652914da7d0SScott Long ac_sync_fib); 165335863739SMike Smith 165435863739SMike Smith /* 165535863739SMike Smith * Give the FIB to the controller, wait for a response. 165635863739SMike Smith */ 1657914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1658914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 165935863739SMike Smith debug(2, "IO error"); 166035863739SMike Smith return(EIO); 166135863739SMike Smith } 166235863739SMike Smith 166335863739SMike Smith return (0); 166435863739SMike Smith } 166535863739SMike Smith 1666914da7d0SScott Long /* 166735863739SMike Smith * Adapter-space FIB queue manipulation 166835863739SMike Smith * 166935863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 167035863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 167135863739SMike Smith */ 167235863739SMike Smith static struct { 167335863739SMike Smith int size; 167435863739SMike Smith int notify; 167535863739SMike Smith } aac_qinfo[] = { 167635863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 167735863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 167835863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 167935863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 168035863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 168135863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 168235863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 168335863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 168435863739SMike Smith }; 168535863739SMike Smith 168635863739SMike Smith /* 1687c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1688c6eafcf2SScott Long * EBUSY if the queue is full. 168935863739SMike Smith * 16900b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1691914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1692914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1693c6eafcf2SScott Long * separate queue/notify interface). 169435863739SMike Smith */ 169535863739SMike Smith static int 1696f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 169735863739SMike Smith { 169835863739SMike Smith u_int32_t pi, ci; 169935863739SMike Smith int s, error; 1700f6c4dd3fSScott Long u_int32_t fib_size; 1701f6c4dd3fSScott Long u_int32_t fib_addr; 1702f6c4dd3fSScott Long 170336e0bf6eSScott Long debug_called(3); 170436e0bf6eSScott Long 1705f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1706f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 170735863739SMike Smith 170835863739SMike Smith s = splbio(); 170935863739SMike Smith 171035863739SMike Smith /* get the producer/consumer indices */ 171135863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 171235863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 171335863739SMike Smith 171435863739SMike Smith /* wrap the queue? */ 171535863739SMike Smith if (pi >= aac_qinfo[queue].size) 171635863739SMike Smith pi = 0; 171735863739SMike Smith 171835863739SMike Smith /* check for queue full */ 171935863739SMike Smith if ((pi + 1) == ci) { 172035863739SMike Smith error = EBUSY; 172135863739SMike Smith goto out; 172235863739SMike Smith } 172335863739SMike Smith 172435863739SMike Smith /* populate queue entry */ 172535863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 172635863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 172735863739SMike Smith 172835863739SMike Smith /* update producer index */ 172935863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 173035863739SMike Smith 1731f6c4dd3fSScott Long /* 1732914da7d0SScott Long * To avoid a race with its completion interrupt, place this command on 1733914da7d0SScott Long * the busy queue prior to advertising it to the controller. 1734f6c4dd3fSScott Long */ 1735f6c4dd3fSScott Long aac_enqueue_busy(cm); 1736f6c4dd3fSScott Long 173735863739SMike Smith /* notify the adapter if we know how */ 173835863739SMike Smith if (aac_qinfo[queue].notify != 0) 173935863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 174035863739SMike Smith 174135863739SMike Smith error = 0; 174235863739SMike Smith 174335863739SMike Smith out: 174435863739SMike Smith splx(s); 174535863739SMike Smith return(error); 174635863739SMike Smith } 174735863739SMike Smith 174835863739SMike Smith /* 174936e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 175036e0bf6eSScott Long * success or ENOENT if the queue is empty. 175135863739SMike Smith */ 175235863739SMike Smith static int 1753c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1754c6eafcf2SScott Long struct aac_fib **fib_addr) 175535863739SMike Smith { 175635863739SMike Smith u_int32_t pi, ci; 175735863739SMike Smith int s, error; 1758f6c4dd3fSScott Long int notify; 175935863739SMike Smith 176035863739SMike Smith debug_called(3); 176135863739SMike Smith 176235863739SMike Smith s = splbio(); 176335863739SMike Smith 176435863739SMike Smith /* get the producer/consumer indices */ 176535863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 176635863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 176735863739SMike Smith 176835863739SMike Smith /* check for queue empty */ 176935863739SMike Smith if (ci == pi) { 177035863739SMike Smith error = ENOENT; 177135863739SMike Smith goto out; 177235863739SMike Smith } 177335863739SMike Smith 1774f6c4dd3fSScott Long notify = 0; 1775f6c4dd3fSScott Long if (ci == pi + 1) 1776f6c4dd3fSScott Long notify++; 1777f6c4dd3fSScott Long 177835863739SMike Smith /* wrap the queue? */ 177935863739SMike Smith if (ci >= aac_qinfo[queue].size) 178035863739SMike Smith ci = 0; 178135863739SMike Smith 178235863739SMike Smith /* fetch the entry */ 178335863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1784914da7d0SScott Long *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + 1785914da7d0SScott Long ci)->aq_fib_addr; 178635863739SMike Smith 1787f30ac74cSScott Long /* 1788f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1789f30ac74cSScott Long * local memory so the whole fib doesn't have to be DMA'd back up. 1790f30ac74cSScott Long */ 1791f30ac74cSScott Long if (*(uintptr_t *)fib_addr & 0x01) { 1792f30ac74cSScott Long *(uintptr_t *)fib_addr &= ~0x01; 1793f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1794f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1795f30ac74cSScott Long } 179635863739SMike Smith /* update consumer index */ 179735863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 179835863739SMike Smith 179935863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1800f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 180135863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 180235863739SMike Smith error = 0; 180335863739SMike Smith 180435863739SMike Smith out: 180535863739SMike Smith splx(s); 180635863739SMike Smith return(error); 180735863739SMike Smith } 180835863739SMike Smith 1809914da7d0SScott Long /* 181036e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 181136e0bf6eSScott Long */ 181236e0bf6eSScott Long static int 181336e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 181436e0bf6eSScott Long { 181536e0bf6eSScott Long u_int32_t pi, ci; 181636e0bf6eSScott Long int s, error; 181736e0bf6eSScott Long u_int32_t fib_size; 181836e0bf6eSScott Long u_int32_t fib_addr; 181936e0bf6eSScott Long 182036e0bf6eSScott Long debug_called(1); 182136e0bf6eSScott Long 182236e0bf6eSScott Long /* Tell the adapter where the FIB is */ 182336e0bf6eSScott Long fib_size = fib->Header.Size; 182436e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 182536e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 182636e0bf6eSScott Long 182736e0bf6eSScott Long s = splbio(); 182836e0bf6eSScott Long 182936e0bf6eSScott Long /* get the producer/consumer indices */ 183036e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 183136e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 183236e0bf6eSScott Long 183336e0bf6eSScott Long /* wrap the queue? */ 183436e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 183536e0bf6eSScott Long pi = 0; 183636e0bf6eSScott Long 183736e0bf6eSScott Long /* check for queue full */ 183836e0bf6eSScott Long if ((pi + 1) == ci) { 183936e0bf6eSScott Long error = EBUSY; 184036e0bf6eSScott Long goto out; 184136e0bf6eSScott Long } 184236e0bf6eSScott Long 184336e0bf6eSScott Long /* populate queue entry */ 184436e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 184536e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 184636e0bf6eSScott Long 184736e0bf6eSScott Long /* update producer index */ 184836e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 184936e0bf6eSScott Long 185036e0bf6eSScott Long /* notify the adapter if we know how */ 185136e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 185236e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 185336e0bf6eSScott Long 185436e0bf6eSScott Long error = 0; 185536e0bf6eSScott Long 185636e0bf6eSScott Long out: 185736e0bf6eSScott Long splx(s); 185836e0bf6eSScott Long return(error); 185936e0bf6eSScott Long } 186036e0bf6eSScott Long 1861914da7d0SScott Long /* 18620b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 18630b94a66eSMike Smith * and complain about them. 18640b94a66eSMike Smith */ 18650b94a66eSMike Smith static void 18660b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 18670b94a66eSMike Smith { 18680b94a66eSMike Smith int s; 18690b94a66eSMike Smith struct aac_command *cm; 18700b94a66eSMike Smith time_t deadline; 18710b94a66eSMike Smith 1872f6c4dd3fSScott Long /* 187370545d1aSScott Long * Traverse the busy command list, bitch about late commands once 1874914da7d0SScott Long * only. 1875914da7d0SScott Long */ 18760b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 18770b94a66eSMike Smith s = splbio(); 18780b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1879f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1880f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 18810b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1882914da7d0SScott Long device_printf(sc->aac_dev, 1883914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1884f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 18850b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 18860b94a66eSMike Smith } 18870b94a66eSMike Smith } 18880b94a66eSMike Smith splx(s); 18890b94a66eSMike Smith 18900b94a66eSMike Smith return; 18910b94a66eSMike Smith } 18920b94a66eSMike Smith 1893914da7d0SScott Long /* 1894914da7d0SScott Long * Interface Function Vectors 1895914da7d0SScott Long */ 189635863739SMike Smith 1897914da7d0SScott Long /* 189835863739SMike Smith * Read the current firmware status word. 189935863739SMike Smith */ 190035863739SMike Smith static int 190135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 190235863739SMike Smith { 190335863739SMike Smith debug_called(3); 190435863739SMike Smith 190535863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 190635863739SMike Smith } 190735863739SMike Smith 190835863739SMike Smith static int 190935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 191035863739SMike Smith { 191135863739SMike Smith debug_called(3); 191235863739SMike Smith 191335863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 191435863739SMike Smith } 191535863739SMike Smith 1916b3457b51SScott Long static int 1917b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 1918b3457b51SScott Long { 1919b3457b51SScott Long int val; 1920b3457b51SScott Long 1921b3457b51SScott Long debug_called(3); 1922b3457b51SScott Long 1923b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 1924b3457b51SScott Long return (val); 1925b3457b51SScott Long } 1926b3457b51SScott Long 1927914da7d0SScott Long /* 192835863739SMike Smith * Notify the controller of a change in a given queue 192935863739SMike Smith */ 193035863739SMike Smith 193135863739SMike Smith static void 193235863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 193335863739SMike Smith { 193435863739SMike Smith debug_called(3); 193535863739SMike Smith 193635863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 193735863739SMike Smith } 193835863739SMike Smith 193935863739SMike Smith static void 194035863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 194135863739SMike Smith { 194235863739SMike Smith debug_called(3); 194335863739SMike Smith 194435863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 194535863739SMike Smith } 194635863739SMike Smith 1947b3457b51SScott Long static void 1948b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 1949b3457b51SScott Long { 1950b3457b51SScott Long debug_called(3); 1951b3457b51SScott Long 1952b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 1953b3457b51SScott Long AAC_FA_HACK(sc); 1954b3457b51SScott Long } 1955b3457b51SScott Long 1956914da7d0SScott Long /* 195735863739SMike Smith * Get the interrupt reason bits 195835863739SMike Smith */ 195935863739SMike Smith static int 196035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 196135863739SMike Smith { 196235863739SMike Smith debug_called(3); 196335863739SMike Smith 196435863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 196535863739SMike Smith } 196635863739SMike Smith 196735863739SMike Smith static int 196835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 196935863739SMike Smith { 197035863739SMike Smith debug_called(3); 197135863739SMike Smith 197235863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 197335863739SMike Smith } 197435863739SMike Smith 1975b3457b51SScott Long static int 1976b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 1977b3457b51SScott Long { 1978b3457b51SScott Long int val; 1979b3457b51SScott Long 1980b3457b51SScott Long debug_called(3); 1981b3457b51SScott Long 1982b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 1983b3457b51SScott Long return (val); 1984b3457b51SScott Long } 1985b3457b51SScott Long 1986914da7d0SScott Long /* 198735863739SMike Smith * Clear some interrupt reason bits 198835863739SMike Smith */ 198935863739SMike Smith static void 199035863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 199135863739SMike Smith { 199235863739SMike Smith debug_called(3); 199335863739SMike Smith 199435863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 199535863739SMike Smith } 199635863739SMike Smith 199735863739SMike Smith static void 199835863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 199935863739SMike Smith { 200035863739SMike Smith debug_called(3); 200135863739SMike Smith 200235863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 200335863739SMike Smith } 200435863739SMike Smith 2005b3457b51SScott Long static void 2006b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2007b3457b51SScott Long { 2008b3457b51SScott Long debug_called(3); 2009b3457b51SScott Long 2010b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2011b3457b51SScott Long AAC_FA_HACK(sc); 2012b3457b51SScott Long } 2013b3457b51SScott Long 2014914da7d0SScott Long /* 201535863739SMike Smith * Populate the mailbox and set the command word 201635863739SMike Smith */ 201735863739SMike Smith static void 201835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 201935863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 202035863739SMike Smith { 202135863739SMike Smith debug_called(4); 202235863739SMike Smith 202335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 202435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 202535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 202635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 202735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 202835863739SMike Smith } 202935863739SMike Smith 203035863739SMike Smith static void 203135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 203235863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 203335863739SMike Smith { 203435863739SMike Smith debug_called(4); 203535863739SMike Smith 203635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 203735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 203835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 203935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 204035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 204135863739SMike Smith } 204235863739SMike Smith 2043b3457b51SScott Long static void 2044b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2045b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2046b3457b51SScott Long { 2047b3457b51SScott Long debug_called(4); 2048b3457b51SScott Long 2049b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2050b3457b51SScott Long AAC_FA_HACK(sc); 2051b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2052b3457b51SScott Long AAC_FA_HACK(sc); 2053b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2054b3457b51SScott Long AAC_FA_HACK(sc); 2055b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2056b3457b51SScott Long AAC_FA_HACK(sc); 2057b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2058b3457b51SScott Long AAC_FA_HACK(sc); 2059b3457b51SScott Long } 2060b3457b51SScott Long 2061914da7d0SScott Long /* 206235863739SMike Smith * Fetch the immediate command status word 206335863739SMike Smith */ 206435863739SMike Smith static int 206535863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 206635863739SMike Smith { 206735863739SMike Smith debug_called(4); 206835863739SMike Smith 206935863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 207035863739SMike Smith } 207135863739SMike Smith 207235863739SMike Smith static int 207335863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 207435863739SMike Smith { 207535863739SMike Smith debug_called(4); 207635863739SMike Smith 207735863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 207835863739SMike Smith } 207935863739SMike Smith 2080b3457b51SScott Long static int 2081b3457b51SScott Long aac_fa_get_mailboxstatus(struct aac_softc *sc) 2082b3457b51SScott Long { 2083b3457b51SScott Long int val; 2084b3457b51SScott Long 2085b3457b51SScott Long debug_called(4); 2086b3457b51SScott Long 2087b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX); 2088b3457b51SScott Long return (val); 2089b3457b51SScott Long } 2090b3457b51SScott Long 2091914da7d0SScott Long /* 209235863739SMike Smith * Set/clear interrupt masks 209335863739SMike Smith */ 209435863739SMike Smith static void 209535863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 209635863739SMike Smith { 209735863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 209835863739SMike Smith 209935863739SMike Smith if (enable) { 210035863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 210135863739SMike Smith } else { 210235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 210335863739SMike Smith } 210435863739SMike Smith } 210535863739SMike Smith 210635863739SMike Smith static void 210735863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 210835863739SMike Smith { 210935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 211035863739SMike Smith 211135863739SMike Smith if (enable) { 211235863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 211335863739SMike Smith } else { 211435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 211535863739SMike Smith } 211635863739SMike Smith } 211735863739SMike Smith 2118b3457b51SScott Long static void 2119b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2120b3457b51SScott Long { 2121b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2122b3457b51SScott Long 2123b3457b51SScott Long if (enable) { 2124b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2125b3457b51SScott Long AAC_FA_HACK(sc); 2126b3457b51SScott Long } else { 2127b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2128b3457b51SScott Long AAC_FA_HACK(sc); 2129b3457b51SScott Long } 2130b3457b51SScott Long } 2131b3457b51SScott Long 2132914da7d0SScott Long /* 2133914da7d0SScott Long * Debugging and Diagnostics 2134914da7d0SScott Long */ 213535863739SMike Smith 2136914da7d0SScott Long /* 213735863739SMike Smith * Print some information about the controller. 213835863739SMike Smith */ 213935863739SMike Smith static void 214035863739SMike Smith aac_describe_controller(struct aac_softc *sc) 214135863739SMike Smith { 2142cbfd045bSScott Long struct aac_fib *fib; 214335863739SMike Smith struct aac_adapter_info *info; 214435863739SMike Smith 214535863739SMike Smith debug_called(2); 214635863739SMike Smith 2147fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2148cbfd045bSScott Long 2149cbfd045bSScott Long fib->data[0] = 0; 2150cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 215135863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2152fe3cb0e1SScott Long aac_release_sync_fib(sc); 215335863739SMike Smith return; 215435863739SMike Smith } 2155cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 215635863739SMike Smith 215736e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2158c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 215936e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2160914da7d0SScott Long aac_describe_code(aac_battery_platform, 2161914da7d0SScott Long info->batteryPlatform)); 216235863739SMike Smith 216335863739SMike Smith /* save the kernel revision structure for later use */ 216435863739SMike Smith sc->aac_revision = info->KernelRevision; 216536e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 216635863739SMike Smith info->KernelRevision.external.comp.major, 216735863739SMike Smith info->KernelRevision.external.comp.minor, 216835863739SMike Smith info->KernelRevision.external.comp.dash, 216936e0bf6eSScott Long info->KernelRevision.buildNumber, 217036e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2171fe3cb0e1SScott Long 2172fe3cb0e1SScott Long aac_release_sync_fib(sc); 217335863739SMike Smith } 217435863739SMike Smith 2175914da7d0SScott Long /* 217635863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 217735863739SMike Smith * same. 217835863739SMike Smith */ 217935863739SMike Smith static char * 218035863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 218135863739SMike Smith { 218235863739SMike Smith int i; 218335863739SMike Smith 218435863739SMike Smith for (i = 0; table[i].string != NULL; i++) 218535863739SMike Smith if (table[i].code == code) 218635863739SMike Smith return(table[i].string); 218735863739SMike Smith return(table[i + 1].string); 218835863739SMike Smith } 218935863739SMike Smith 2190914da7d0SScott Long /* 2191914da7d0SScott Long * Management Interface 2192914da7d0SScott Long */ 219335863739SMike Smith 219435863739SMike Smith static int 2195c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 219635863739SMike Smith { 2197914da7d0SScott Long struct aac_softc *sc; 219835863739SMike Smith 219935863739SMike Smith debug_called(2); 220035863739SMike Smith 2201914da7d0SScott Long sc = dev->si_drv1; 2202914da7d0SScott Long 220335863739SMike Smith /* Check to make sure the device isn't already open */ 220435863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 220535863739SMike Smith return EBUSY; 220635863739SMike Smith } 220735863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 220835863739SMike Smith 220935863739SMike Smith return 0; 221035863739SMike Smith } 221135863739SMike Smith 221235863739SMike Smith static int 2213c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 221435863739SMike Smith { 2215914da7d0SScott Long struct aac_softc *sc; 221635863739SMike Smith 221735863739SMike Smith debug_called(2); 221835863739SMike Smith 2219914da7d0SScott Long sc = dev->si_drv1; 2220914da7d0SScott Long 222135863739SMike Smith /* Mark this unit as no longer open */ 222235863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 222335863739SMike Smith 222435863739SMike Smith return 0; 222535863739SMike Smith } 222635863739SMike Smith 222735863739SMike Smith static int 2228c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 222935863739SMike Smith { 2230914da7d0SScott Long union aac_statrequest *as; 2231914da7d0SScott Long struct aac_softc *sc; 22320b94a66eSMike Smith int error = 0; 22330b94a66eSMike Smith int i; 223435863739SMike Smith 223535863739SMike Smith debug_called(2); 223635863739SMike Smith 2237914da7d0SScott Long as = (union aac_statrequest *)arg; 2238914da7d0SScott Long sc = dev->si_drv1; 2239914da7d0SScott Long 224035863739SMike Smith switch (cmd) { 22410b94a66eSMike Smith case AACIO_STATS: 22420b94a66eSMike Smith switch (as->as_item) { 22430b94a66eSMike Smith case AACQ_FREE: 22440b94a66eSMike Smith case AACQ_BIO: 22450b94a66eSMike Smith case AACQ_READY: 22460b94a66eSMike Smith case AACQ_BUSY: 22470b94a66eSMike Smith case AACQ_COMPLETE: 2248c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2249c6eafcf2SScott Long sizeof(struct aac_qstat)); 22500b94a66eSMike Smith break; 22510b94a66eSMike Smith default: 22520b94a66eSMike Smith error = ENOENT; 22530b94a66eSMike Smith break; 22540b94a66eSMike Smith } 22550b94a66eSMike Smith break; 22560b94a66eSMike Smith 225735863739SMike Smith case FSACTL_SENDFIB: 2258fb0c27d7SScott Long arg = *(caddr_t*)arg; 2259fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 22600b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 226135863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 226235863739SMike Smith break; 226335863739SMike Smith case FSACTL_AIF_THREAD: 2264fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 22650b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 226635863739SMike Smith error = EINVAL; 226735863739SMike Smith break; 226835863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2269fb0c27d7SScott Long arg = *(caddr_t*)arg; 2270fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 22710b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 227235863739SMike Smith /* 227335863739SMike Smith * Pass the caller out an AdapterFibContext. 227435863739SMike Smith * 227535863739SMike Smith * Note that because we only support one opener, we 227635863739SMike Smith * basically ignore this. Set the caller's context to a magic 227735863739SMike Smith * number just in case. 22780b94a66eSMike Smith * 22790b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 22800b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2281914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2282914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 228335863739SMike Smith */ 228436e0bf6eSScott Long i = (int)sc->aifthread; 228535863739SMike Smith error = copyout(&i, arg, sizeof(i)); 228635863739SMike Smith break; 228735863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2288fb0c27d7SScott Long arg = *(caddr_t*)arg; 2289fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 22900b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2291fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 229235863739SMike Smith break; 229335863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2294fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 22950b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 229635863739SMike Smith /* don't do anything here */ 229735863739SMike Smith break; 229835863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2299fb0c27d7SScott Long arg = *(caddr_t*)arg; 2300fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 23010b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2302fb0c27d7SScott Long error = aac_rev_check(sc, arg); 230335863739SMike Smith break; 230436e0bf6eSScott Long case FSACTL_QUERY_DISK: 230536e0bf6eSScott Long arg = *(caddr_t*)arg; 230636e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 230736e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 230836e0bf6eSScott Long error = aac_query_disk(sc, arg); 230936e0bf6eSScott Long break; 231036e0bf6eSScott Long case FSACTL_DELETE_DISK: 231136e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2312914da7d0SScott Long /* 2313914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2314914da7d0SScott Long * container, rather we rely on an AIF coming from the 2315914da7d0SScott Long * controller 2316914da7d0SScott Long */ 231736e0bf6eSScott Long error = 0; 231836e0bf6eSScott Long break; 231935863739SMike Smith default: 2320b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 232135863739SMike Smith error = EINVAL; 232235863739SMike Smith break; 232335863739SMike Smith } 232435863739SMike Smith return(error); 232535863739SMike Smith } 232635863739SMike Smith 2327b3457b51SScott Long static int 2328c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td) 2329b3457b51SScott Long { 2330b3457b51SScott Long struct aac_softc *sc; 2331b3457b51SScott Long int revents; 2332b3457b51SScott Long 2333b3457b51SScott Long sc = dev->si_drv1; 2334b3457b51SScott Long revents = 0; 2335b3457b51SScott Long 2336c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2337b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2338b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2339b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2340b3457b51SScott Long } 2341b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2342b3457b51SScott Long 2343b3457b51SScott Long if (revents == 0) { 2344b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2345b3457b51SScott Long selrecord(td, &sc->rcv_select); 2346b3457b51SScott Long } 2347b3457b51SScott Long 2348b3457b51SScott Long return (revents); 2349b3457b51SScott Long } 2350b3457b51SScott Long 2351914da7d0SScott Long /* 235235863739SMike Smith * Send a FIB supplied from userspace 235335863739SMike Smith */ 235435863739SMike Smith static int 235535863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 235635863739SMike Smith { 235735863739SMike Smith struct aac_command *cm; 235835863739SMike Smith int size, error; 235935863739SMike Smith 236035863739SMike Smith debug_called(2); 236135863739SMike Smith 236235863739SMike Smith cm = NULL; 236335863739SMike Smith 236435863739SMike Smith /* 236535863739SMike Smith * Get a command 236635863739SMike Smith */ 236735863739SMike Smith if (aac_alloc_command(sc, &cm)) { 236835863739SMike Smith error = EBUSY; 236935863739SMike Smith goto out; 237035863739SMike Smith } 237135863739SMike Smith 237235863739SMike Smith /* 237335863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 237435863739SMike Smith */ 2375914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2376914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 237735863739SMike Smith goto out; 237835863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 237935863739SMike Smith if (size > sizeof(struct aac_fib)) { 2380914da7d0SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2381914da7d0SScott Long size, sizeof(struct aac_fib)); 238235863739SMike Smith size = sizeof(struct aac_fib); 238335863739SMike Smith } 238435863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 238535863739SMike Smith goto out; 238635863739SMike Smith cm->cm_fib->Header.Size = size; 2387f6c4dd3fSScott Long cm->cm_timestamp = time_second; 238835863739SMike Smith 238935863739SMike Smith /* 239035863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 239135863739SMike Smith */ 2392b3457b51SScott Long if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 239370545d1aSScott Long device_printf(sc->aac_dev, 239470545d1aSScott Long "aac_wait_command return %d\n", error); 239535863739SMike Smith goto out; 2396b3457b51SScott Long } 239735863739SMike Smith 239835863739SMike Smith /* 239935863739SMike Smith * Copy the FIB and data back out to the caller. 240035863739SMike Smith */ 240135863739SMike Smith size = cm->cm_fib->Header.Size; 240235863739SMike Smith if (size > sizeof(struct aac_fib)) { 2403914da7d0SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2404914da7d0SScott Long size, sizeof(struct aac_fib)); 240535863739SMike Smith size = sizeof(struct aac_fib); 240635863739SMike Smith } 240735863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 240835863739SMike Smith 240935863739SMike Smith out: 2410f6c4dd3fSScott Long if (cm != NULL) { 241135863739SMike Smith aac_release_command(cm); 2412f6c4dd3fSScott Long } 241335863739SMike Smith return(error); 241435863739SMike Smith } 241535863739SMike Smith 2416914da7d0SScott Long /* 241735863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 241836e0bf6eSScott Long * If the queue fills up, then drop the older entries. 241935863739SMike Smith */ 242035863739SMike Smith static void 242136e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 242235863739SMike Smith { 242336e0bf6eSScott Long struct aac_aif_command *aif; 242436e0bf6eSScott Long struct aac_container *co, *co_next; 2425cbfd045bSScott Long struct aac_mntinfo *mi; 2426cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 242736e0bf6eSScott Long u_int16_t rsize; 2428b3457b51SScott Long int next, found; 242936e0bf6eSScott Long int added = 0, i = 0; 243035863739SMike Smith 243135863739SMike Smith debug_called(2); 243235863739SMike Smith 243336e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 243436e0bf6eSScott Long aac_print_aif(sc, aif); 243536e0bf6eSScott Long 243636e0bf6eSScott Long /* Is it an event that we should care about? */ 243736e0bf6eSScott Long switch (aif->command) { 243836e0bf6eSScott Long case AifCmdEventNotify: 243936e0bf6eSScott Long switch (aif->data.EN.type) { 244036e0bf6eSScott Long case AifEnAddContainer: 244136e0bf6eSScott Long case AifEnDeleteContainer: 244236e0bf6eSScott Long /* 2443914da7d0SScott Long * A container was added or deleted, but the message 2444914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2445914da7d0SScott Long * containers and sort things out. 244636e0bf6eSScott Long */ 2447fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2448cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 244936e0bf6eSScott Long do { 245036e0bf6eSScott Long /* 2451914da7d0SScott Long * Ask the controller for its containers one at 2452914da7d0SScott Long * a time. 2453914da7d0SScott Long * XXX What if the controller's list changes 2454914da7d0SScott Long * midway through this enumaration? 245536e0bf6eSScott Long * XXX This should be done async. 245636e0bf6eSScott Long */ 245739ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 245839ee03c3SScott Long mi->Command = VM_NameServe; 245939ee03c3SScott Long mi->MntType = FT_FILESYS; 2460cbfd045bSScott Long mi->MntCount = i; 246136e0bf6eSScott Long rsize = sizeof(mir); 2462cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2463cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2464914da7d0SScott Long debug(2, "Error probing container %d\n", 2465914da7d0SScott Long i); 246636e0bf6eSScott Long continue; 246736e0bf6eSScott Long } 2468cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 246936e0bf6eSScott Long /* 2470914da7d0SScott Long * Check the container against our list. 2471914da7d0SScott Long * co->co_found was already set to 0 in a 2472914da7d0SScott Long * previous run. 247336e0bf6eSScott Long */ 2474cbfd045bSScott Long if ((mir->Status == ST_OK) && 2475cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 247636e0bf6eSScott Long found = 0; 2477914da7d0SScott Long TAILQ_FOREACH(co, 2478914da7d0SScott Long &sc->aac_container_tqh, 2479914da7d0SScott Long co_link) { 248036e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2481cbfd045bSScott Long mir->MntTable[0].ObjectId) { 248236e0bf6eSScott Long co->co_found = 1; 248336e0bf6eSScott Long found = 1; 248436e0bf6eSScott Long break; 248536e0bf6eSScott Long } 248636e0bf6eSScott Long } 2487914da7d0SScott Long /* 2488914da7d0SScott Long * If the container matched, continue 2489914da7d0SScott Long * in the list. 2490914da7d0SScott Long */ 249136e0bf6eSScott Long if (found) { 249236e0bf6eSScott Long i++; 249336e0bf6eSScott Long continue; 249436e0bf6eSScott Long } 249536e0bf6eSScott Long 249636e0bf6eSScott Long /* 2497914da7d0SScott Long * This is a new container. Do all the 249870545d1aSScott Long * appropriate things to set it up. 249970545d1aSScott Long */ 2500cbfd045bSScott Long aac_add_container(sc, mir, 1); 250136e0bf6eSScott Long added = 1; 250236e0bf6eSScott Long } 250336e0bf6eSScott Long i++; 2504cbfd045bSScott Long } while ((i < mir->MntRespCount) && 2505914da7d0SScott Long (i < AAC_MAX_CONTAINERS)); 2506cbfd045bSScott Long aac_release_sync_fib(sc); 250736e0bf6eSScott Long 250836e0bf6eSScott Long /* 2509914da7d0SScott Long * Go through our list of containers and see which ones 2510914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2511914da7d0SScott Long * list them they must have been deleted. Do the 2512914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2513914da7d0SScott Long * the co->co_found field. 251436e0bf6eSScott Long */ 251536e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 251636e0bf6eSScott Long while (co != NULL) { 251736e0bf6eSScott Long if (co->co_found == 0) { 2518914da7d0SScott Long device_delete_child(sc->aac_dev, 2519914da7d0SScott Long co->co_disk); 252036e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2521c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc-> 2522914da7d0SScott Long aac_container_lock); 2523914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2524914da7d0SScott Long co_link); 2525914da7d0SScott Long AAC_LOCK_RELEASE(&sc-> 2526914da7d0SScott Long aac_container_lock); 252736e0bf6eSScott Long FREE(co, M_AACBUF); 252836e0bf6eSScott Long co = co_next; 252936e0bf6eSScott Long } else { 253036e0bf6eSScott Long co->co_found = 0; 253136e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 253236e0bf6eSScott Long } 253336e0bf6eSScott Long } 253436e0bf6eSScott Long 253536e0bf6eSScott Long /* Attach the newly created containers */ 253636e0bf6eSScott Long if (added) 253736e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 253836e0bf6eSScott Long 253936e0bf6eSScott Long break; 254036e0bf6eSScott Long 254136e0bf6eSScott Long default: 254236e0bf6eSScott Long break; 254336e0bf6eSScott Long } 254436e0bf6eSScott Long 254536e0bf6eSScott Long default: 254636e0bf6eSScott Long break; 254736e0bf6eSScott Long } 254836e0bf6eSScott Long 254936e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2550c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 255135863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 255235863739SMike Smith if (next != sc->aac_aifq_tail) { 255335863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 255435863739SMike Smith sc->aac_aifq_head = next; 2555b3457b51SScott Long 2556b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 255735863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 255835863739SMike Smith wakeup(sc->aac_aifq); 2559b3457b51SScott Long /* Wakeup any poll()ers */ 2560b3457b51SScott Long selwakeup(&sc->rcv_select); 256135863739SMike Smith } 2562b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 256336e0bf6eSScott Long 256436e0bf6eSScott Long return; 256535863739SMike Smith } 256635863739SMike Smith 2567914da7d0SScott Long /* 25680b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 256936e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 257036e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 257136e0bf6eSScott Long * returning what the card reported. 257235863739SMike Smith */ 257335863739SMike Smith static int 2574fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 257535863739SMike Smith { 257635863739SMike Smith struct aac_rev_check rev_check; 257735863739SMike Smith struct aac_rev_check_resp rev_check_resp; 257835863739SMike Smith int error = 0; 257935863739SMike Smith 258035863739SMike Smith debug_called(2); 258135863739SMike Smith 258235863739SMike Smith /* 258335863739SMike Smith * Copyin the revision struct from userspace 258435863739SMike Smith */ 2585c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2586c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 258735863739SMike Smith return error; 258835863739SMike Smith } 258935863739SMike Smith 2590914da7d0SScott Long debug(2, "Userland revision= %d\n", 2591914da7d0SScott Long rev_check.callingRevision.buildNumber); 259235863739SMike Smith 259335863739SMike Smith /* 259435863739SMike Smith * Doctor up the response struct. 259535863739SMike Smith */ 259635863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2597914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2598914da7d0SScott Long sc->aac_revision.external.ul; 2599914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2600914da7d0SScott Long sc->aac_revision.buildNumber; 260135863739SMike Smith 2602c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2603c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 260435863739SMike Smith } 260535863739SMike Smith 2606914da7d0SScott Long /* 260735863739SMike Smith * Pass the caller the next AIF in their queue 260835863739SMike Smith */ 260935863739SMike Smith static int 2610fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 261135863739SMike Smith { 261235863739SMike Smith struct get_adapter_fib_ioctl agf; 261335863739SMike Smith int error, s; 261435863739SMike Smith 261535863739SMike Smith debug_called(2); 261635863739SMike Smith 261735863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 261835863739SMike Smith 261935863739SMike Smith /* 262035863739SMike Smith * Check the magic number that we gave the caller. 262135863739SMike Smith */ 262236e0bf6eSScott Long if (agf.AdapterFibContext != (int)sc->aifthread) { 262335863739SMike Smith error = EFAULT; 262435863739SMike Smith } else { 262535863739SMike Smith 262635863739SMike Smith s = splbio(); 2627fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 262835863739SMike Smith 262935863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 263035863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 263135863739SMike Smith while (error == EAGAIN) { 2632914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2633914da7d0SScott Long PCATCH, "aacaif", 0); 263435863739SMike Smith if (error == 0) 2635914da7d0SScott Long error = aac_return_aif(sc, 2636914da7d0SScott Long agf.AifFib); 263735863739SMike Smith } 263835863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 263935863739SMike Smith } 264035863739SMike Smith splx(s); 264135863739SMike Smith } 264235863739SMike Smith } 264335863739SMike Smith return(error); 264435863739SMike Smith } 264535863739SMike Smith 2646914da7d0SScott Long /* 26470b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 26480b94a66eSMike Smith */ 26490b94a66eSMike Smith static int 2650fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 26510b94a66eSMike Smith { 2652b3457b51SScott Long int error; 26530b94a66eSMike Smith 26540b94a66eSMike Smith debug_called(2); 26550b94a66eSMike Smith 2656c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 26570b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 26580b94a66eSMike Smith error = EAGAIN; 26590b94a66eSMike Smith } else { 2660c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2661c6eafcf2SScott Long sizeof(struct aac_aif_command)); 266236e0bf6eSScott Long if (error) 266370545d1aSScott Long device_printf(sc->aac_dev, 266470545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 26650b94a66eSMike Smith if (!error) 2666914da7d0SScott Long sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 2667914da7d0SScott Long AAC_AIFQ_LENGTH; 26680b94a66eSMike Smith } 2669b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 26700b94a66eSMike Smith return(error); 26710b94a66eSMike Smith } 267236e0bf6eSScott Long 2673914da7d0SScott Long /* 267436e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 267536e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 267636e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 267736e0bf6eSScott Long */ 267836e0bf6eSScott Long static int 267936e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 268036e0bf6eSScott Long { 268136e0bf6eSScott Long struct aac_query_disk query_disk; 268236e0bf6eSScott Long struct aac_container *co; 2683914da7d0SScott Long struct aac_disk *disk; 268436e0bf6eSScott Long int error, id; 268536e0bf6eSScott Long 268636e0bf6eSScott Long debug_called(2); 268736e0bf6eSScott Long 2688914da7d0SScott Long disk = NULL; 2689914da7d0SScott Long 2690914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2691914da7d0SScott Long sizeof(struct aac_query_disk)); 269236e0bf6eSScott Long if (error) 269336e0bf6eSScott Long return (error); 269436e0bf6eSScott Long 269536e0bf6eSScott Long id = query_disk.ContainerNumber; 269636e0bf6eSScott Long if (id == -1) 269736e0bf6eSScott Long return (EINVAL); 269836e0bf6eSScott Long 2699c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 270036e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 270136e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 270236e0bf6eSScott Long break; 270336e0bf6eSScott Long } 270436e0bf6eSScott Long 270536e0bf6eSScott Long if (co == NULL) { 270636e0bf6eSScott Long query_disk.Valid = 0; 270736e0bf6eSScott Long query_disk.Locked = 0; 270836e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 270936e0bf6eSScott Long } else { 271036e0bf6eSScott Long disk = device_get_softc(co->co_disk); 271136e0bf6eSScott Long query_disk.Valid = 1; 2712914da7d0SScott Long query_disk.Locked = 2713914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 271436e0bf6eSScott Long query_disk.Deleted = 0; 2715b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 271636e0bf6eSScott Long query_disk.Target = disk->unit; 271736e0bf6eSScott Long query_disk.Lun = 0; 271836e0bf6eSScott Long query_disk.UnMapped = 0; 27197540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 27207540e65eSScott Long disk->ad_disk.d_name, disk->ad_disk.d_unit); 272136e0bf6eSScott Long } 272236e0bf6eSScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 272336e0bf6eSScott Long 2724914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2725914da7d0SScott Long sizeof(struct aac_query_disk)); 272636e0bf6eSScott Long 272736e0bf6eSScott Long return (error); 272836e0bf6eSScott Long } 272936e0bf6eSScott Long 2730fe3cb0e1SScott Long static void 2731fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2732fe3cb0e1SScott Long { 2733fe3cb0e1SScott Long struct aac_fib *fib; 2734fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2735fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2736fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2737fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2738fe3cb0e1SScott Long struct aac_getbusinf businfo; 273970545d1aSScott Long struct aac_sim *caminf; 2740fe3cb0e1SScott Long device_t child; 2741fe3cb0e1SScott Long int i, found, error; 2742fe3cb0e1SScott Long 2743fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2744fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 274539ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2746fe3cb0e1SScott Long 2747fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2748fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2749fe3cb0e1SScott Long c_cmd->param = 0; 2750fe3cb0e1SScott Long 2751fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2752fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2753fe3cb0e1SScott Long if (error) { 2754fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2755fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2756fe3cb0e1SScott Long aac_release_sync_fib(sc); 2757fe3cb0e1SScott Long return; 2758fe3cb0e1SScott Long } 2759fe3cb0e1SScott Long 2760fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2761fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2762fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2763fe3cb0e1SScott Long c_resp->Status); 2764fe3cb0e1SScott Long aac_release_sync_fib(sc); 2765fe3cb0e1SScott Long return; 2766fe3cb0e1SScott Long } 2767fe3cb0e1SScott Long 2768fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2769fe3cb0e1SScott Long 2770fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 277139ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 277239ee03c3SScott Long 2773fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2774fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2775fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2776fe3cb0e1SScott Long vmi->ObjId = 0; 2777fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2778fe3cb0e1SScott Long 2779fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2780fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2781fe3cb0e1SScott Long if (error) { 2782fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2783fe3cb0e1SScott Long error); 2784fe3cb0e1SScott Long aac_release_sync_fib(sc); 2785fe3cb0e1SScott Long return; 2786fe3cb0e1SScott Long } 2787fe3cb0e1SScott Long 2788fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2789fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2790fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2791fe3cb0e1SScott Long vmi_resp->Status); 2792fe3cb0e1SScott Long aac_release_sync_fib(sc); 2793fe3cb0e1SScott Long return; 2794fe3cb0e1SScott Long } 2795fe3cb0e1SScott Long 2796fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2797fe3cb0e1SScott Long aac_release_sync_fib(sc); 2798fe3cb0e1SScott Long 2799fe3cb0e1SScott Long found = 0; 2800fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2801fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2802fe3cb0e1SScott Long continue; 2803fe3cb0e1SScott Long 2804a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2805a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 2806fe3cb0e1SScott Long if (caminf == NULL) 2807fe3cb0e1SScott Long continue; 2808fe3cb0e1SScott Long 2809fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2810fe3cb0e1SScott Long if (child == NULL) { 2811fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2812fe3cb0e1SScott Long continue; 2813fe3cb0e1SScott Long } 2814fe3cb0e1SScott Long 2815fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2816fe3cb0e1SScott Long caminf->BusNumber = i; 2817fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2818fe3cb0e1SScott Long caminf->aac_sc = sc; 2819ddb8683eSScott Long caminf->sim_dev = child; 2820fe3cb0e1SScott Long 2821fe3cb0e1SScott Long device_set_ivars(child, caminf); 2822fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 282370545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2824fe3cb0e1SScott Long 2825fe3cb0e1SScott Long found = 1; 2826fe3cb0e1SScott Long } 2827fe3cb0e1SScott Long 2828fe3cb0e1SScott Long if (found) 2829fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2830fe3cb0e1SScott Long 2831fe3cb0e1SScott Long return; 2832fe3cb0e1SScott Long } 2833