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 /* 273ae543596SScott Long * Initialize locks 274b3457b51SScott Long */ 275b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 276ae543596SScott Long TAILQ_INIT(&sc->aac_container_tqh); 277ae543596SScott Long AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 278ae543596SScott Long AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock"); 27936e0bf6eSScott Long 280ae543596SScott Long /* 281ae543596SScott Long * Register to probe our containers later. 282ae543596SScott 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 */ 663ae543596SScott 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 if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 78170545d1aSScott Long aac_timeout(sc); 78270545d1aSScott Long 78370545d1aSScott Long /* Check the hardware printf message buffer */ 78470545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) { 78570545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_PRINTF; 78670545d1aSScott Long aac_print_printf(sc); 78770545d1aSScott Long } 78870545d1aSScott Long 789ae543596SScott Long /* See if any FIBs need to be allocated */ 790ae543596SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 791ae543596SScott Long mtx_lock(&Giant); 792ae543596SScott Long AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 793ae543596SScott Long aac_alloc_commands(sc); 794ae543596SScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 795ae543596SScott Long AAC_LOCK_RELEASE(&sc->aac_io_lock); 796ae543596SScott Long mtx_unlock(&Giant); 797ae543596SScott Long } 79870545d1aSScott Long 799ae543596SScott Long /* While we're here, check to see if any commands are stuck */ 800ae543596SScott Long while (sc->aifflags & AAC_AIFFLAGS_AIF) { 801914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 80270545d1aSScott Long &fib_size, &fib)) { 80370545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_AIF; 80435863739SMike Smith break; /* nothing to do */ 80570545d1aSScott Long } 80635863739SMike Smith 80736e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 80836e0bf6eSScott Long 80935863739SMike Smith switch (fib->Header.Command) { 81035863739SMike Smith case AifRequest: 81136e0bf6eSScott Long aac_handle_aif(sc, fib); 81235863739SMike Smith break; 81335863739SMike Smith default: 814914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 815914da7d0SScott Long "from controller\n"); 81635863739SMike Smith break; 81735863739SMike Smith } 81835863739SMike Smith 81936e0bf6eSScott Long if ((fib->Header.XferState == 0) || 82036e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 82136e0bf6eSScott Long break; 82236e0bf6eSScott Long 82370545d1aSScott Long /* Return the AIF to the controller. */ 82436e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 82536e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 82636e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 82736e0bf6eSScott Long 82836e0bf6eSScott Long /* XXX Compute the Size field? */ 82936e0bf6eSScott Long size = fib->Header.Size; 83036e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 83136e0bf6eSScott Long size = sizeof(struct aac_fib); 83236e0bf6eSScott Long fib->Header.Size = size; 83336e0bf6eSScott Long } 83436e0bf6eSScott Long /* 835914da7d0SScott Long * Since we did not generate this command, it 836914da7d0SScott Long * cannot go through the normal 837914da7d0SScott Long * enqueue->startio chain. 83836e0bf6eSScott Long */ 839914da7d0SScott Long aac_enqueue_response(sc, 840914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 841914da7d0SScott Long fib); 84236e0bf6eSScott Long } 84336e0bf6eSScott Long } 84436e0bf6eSScott Long } 84536e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 84636e0bf6eSScott Long wakeup(sc->aac_dev); 84736e0bf6eSScott Long 84836e0bf6eSScott Long #if __FreeBSD_version > 500005 84936e0bf6eSScott Long mtx_lock(&Giant); 85036e0bf6eSScott Long #endif 85136e0bf6eSScott Long kthread_exit(0); 85235863739SMike Smith } 85335863739SMike Smith 854914da7d0SScott Long /* 8559c3a7fceSScott Long * Process completed commands. 85635863739SMike Smith */ 85735863739SMike Smith static void 8589c3a7fceSScott Long aac_complete(void *context, int pending) 85935863739SMike Smith { 8609c3a7fceSScott Long struct aac_softc *sc; 86135863739SMike Smith struct aac_command *cm; 86235863739SMike Smith struct aac_fib *fib; 86335863739SMike Smith u_int32_t fib_size; 86435863739SMike Smith 86535863739SMike Smith debug_called(2); 86635863739SMike Smith 8679c3a7fceSScott Long sc = (struct aac_softc *)context; 8689c3a7fceSScott Long 869ae543596SScott Long AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 870ae543596SScott Long 8719c3a7fceSScott Long /* pull completed commands off the queue */ 87235863739SMike Smith for (;;) { 87335863739SMike Smith /* look for completed FIBs on our queue */ 874914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 875914da7d0SScott Long &fib)) 87635863739SMike Smith break; /* nothing to do */ 87735863739SMike Smith 87835863739SMike Smith /* get the command, unmap and queue for later processing */ 879cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 88035863739SMike Smith if (cm == NULL) { 88135863739SMike Smith AAC_PRINT_FIB(sc, fib); 8829c3a7fceSScott Long break; 8839c3a7fceSScott Long } 8849c3a7fceSScott Long 8850b94a66eSMike Smith aac_remove_busy(cm); 88635863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 88735863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 88835863739SMike Smith 88935863739SMike Smith /* is there a completion handler? */ 89035863739SMike Smith if (cm->cm_complete != NULL) { 89135863739SMike Smith cm->cm_complete(cm); 89235863739SMike Smith } else { 89335863739SMike Smith /* assume that someone is sleeping on this command */ 89435863739SMike Smith wakeup(cm); 89535863739SMike Smith } 89635863739SMike Smith } 8970b94a66eSMike Smith 8980b94a66eSMike Smith /* see if we can start some more I/O */ 8990b94a66eSMike Smith aac_startio(sc); 900ae543596SScott Long 901ae543596SScott Long AAC_LOCK_RELEASE(&sc->aac_io_lock); 90235863739SMike Smith } 90335863739SMike Smith 904914da7d0SScott Long /* 90535863739SMike Smith * Handle a bio submitted from a disk device. 90635863739SMike Smith */ 90735863739SMike Smith void 90835863739SMike Smith aac_submit_bio(struct bio *bp) 90935863739SMike Smith { 910914da7d0SScott Long struct aac_disk *ad; 911914da7d0SScott Long struct aac_softc *sc; 91235863739SMike Smith 91335863739SMike Smith debug_called(2); 91435863739SMike Smith 9157540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 916914da7d0SScott Long sc = ad->ad_controller; 917914da7d0SScott Long 91835863739SMike Smith /* queue the BIO and try to get some work done */ 9190b94a66eSMike Smith aac_enqueue_bio(sc, bp); 92035863739SMike Smith aac_startio(sc); 92135863739SMike Smith } 92235863739SMike Smith 923914da7d0SScott Long /* 92435863739SMike Smith * Get a bio and build a command to go with it. 92535863739SMike Smith */ 92635863739SMike Smith static int 92735863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 92835863739SMike Smith { 92935863739SMike Smith struct aac_command *cm; 93035863739SMike Smith struct aac_fib *fib; 93135863739SMike Smith struct aac_blockread *br; 93235863739SMike Smith struct aac_blockwrite *bw; 93335863739SMike Smith struct aac_disk *ad; 93435863739SMike Smith struct bio *bp; 93535863739SMike Smith 93635863739SMike Smith debug_called(2); 93735863739SMike Smith 93835863739SMike Smith /* get the resources we will need */ 93935863739SMike Smith cm = NULL; 9400b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 94135863739SMike Smith goto fail; 94235863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 94335863739SMike Smith goto fail; 94435863739SMike Smith 94535863739SMike Smith /* fill out the command */ 9460b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9470b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9480b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 94935863739SMike Smith cm->cm_private = bp; 9500b94a66eSMike Smith cm->cm_timestamp = time_second; 95136e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 95235863739SMike Smith 95335863739SMike Smith /* build the FIB */ 95435863739SMike Smith fib = cm->cm_fib; 95535863739SMike Smith fib->Header.XferState = 95635863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 95735863739SMike Smith AAC_FIBSTATE_INITIALISED | 958f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 95935863739SMike Smith AAC_FIBSTATE_FROMHOST | 96035863739SMike Smith AAC_FIBSTATE_REXPECTED | 961f30ac74cSScott Long AAC_FIBSTATE_NORM | 962f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 963f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 96435863739SMike Smith fib->Header.Command = ContainerCommand; 96535863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 96635863739SMike Smith 96735863739SMike Smith /* build the read/write request */ 9687540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 96935863739SMike Smith if (BIO_IS_READ(bp)) { 97035863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 97135863739SMike Smith br->Command = VM_CtBlockRead; 97235863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 97335863739SMike Smith br->BlockNumber = bp->bio_pblkno; 97435863739SMike Smith br->ByteCount = bp->bio_bcount; 97535863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 97635863739SMike Smith cm->cm_sgtable = &br->SgMap; 97735863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 97835863739SMike Smith } else { 97935863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 98035863739SMike Smith bw->Command = VM_CtBlockWrite; 98135863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 98235863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 98335863739SMike Smith bw->ByteCount = bp->bio_bcount; 98435863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 98535863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 98635863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 98735863739SMike Smith cm->cm_sgtable = &bw->SgMap; 98835863739SMike Smith } 98935863739SMike Smith 99035863739SMike Smith *cmp = cm; 99135863739SMike Smith return(0); 99235863739SMike Smith 99335863739SMike Smith fail: 99435863739SMike Smith if (bp != NULL) 9950b94a66eSMike Smith aac_enqueue_bio(sc, bp); 99635863739SMike Smith if (cm != NULL) 99735863739SMike Smith aac_release_command(cm); 99835863739SMike Smith return(ENOMEM); 99935863739SMike Smith } 100035863739SMike Smith 1001914da7d0SScott Long /* 100235863739SMike Smith * Handle a bio-instigated command that has been completed. 100335863739SMike Smith */ 100435863739SMike Smith static void 100535863739SMike Smith aac_bio_complete(struct aac_command *cm) 100635863739SMike Smith { 100735863739SMike Smith struct aac_blockread_response *brr; 100835863739SMike Smith struct aac_blockwrite_response *bwr; 100935863739SMike Smith struct bio *bp; 101035863739SMike Smith AAC_FSAStatus status; 101135863739SMike Smith 101235863739SMike Smith /* fetch relevant status and then release the command */ 101335863739SMike Smith bp = (struct bio *)cm->cm_private; 101435863739SMike Smith if (BIO_IS_READ(bp)) { 101535863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 101635863739SMike Smith status = brr->Status; 101735863739SMike Smith } else { 101835863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 101935863739SMike Smith status = bwr->Status; 102035863739SMike Smith } 102135863739SMike Smith aac_release_command(cm); 102235863739SMike Smith 102335863739SMike Smith /* fix up the bio based on status */ 102435863739SMike Smith if (status == ST_OK) { 102535863739SMike Smith bp->bio_resid = 0; 102635863739SMike Smith } else { 102735863739SMike Smith bp->bio_error = EIO; 102835863739SMike Smith bp->bio_flags |= BIO_ERROR; 10290b94a66eSMike Smith /* pass an error string out to the disk layer */ 1030914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1031914da7d0SScott Long status); 103235863739SMike Smith } 10330b94a66eSMike Smith aac_biodone(bp); 103435863739SMike Smith } 103535863739SMike Smith 1036914da7d0SScott Long /* 103735863739SMike Smith * Submit a command to the controller, return when it completes. 1038b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1039b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1040b3457b51SScott Long * because there is a risk that a signal could wakeup the tsleep before 1041b3457b51SScott Long * the card has a chance to complete the command. The passed in timeout 1042b3457b51SScott Long * is ignored for the same reason. Since there is no way to cancel a 1043b3457b51SScott Long * command in progress, we should probably create a 'dead' queue where 1044b3457b51SScott Long * commands go that have been interrupted/timed-out/etc, that keeps them 1045b3457b51SScott Long * out of the free pool. That way, if the card is just slow, it won't 1046b3457b51SScott Long * spam the memory of a command that has been recycled. 104735863739SMike Smith */ 104835863739SMike Smith static int 104935863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 105035863739SMike Smith { 1051ae543596SScott Long struct aac_softc *sc; 1052ae543596SScott Long int error = 0; 105335863739SMike Smith 105435863739SMike Smith debug_called(2); 105535863739SMike Smith 1056ae543596SScott Long sc = cm->cm_sc; 1057ae543596SScott Long 105835863739SMike Smith /* Put the command on the ready queue and get things going */ 105936e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 106035863739SMike Smith aac_enqueue_ready(cm); 1061ae543596SScott Long aac_startio(sc); 106235863739SMike Smith while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1063ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 106435863739SMike Smith } 106535863739SMike Smith return(error); 106635863739SMike Smith } 106735863739SMike Smith 1068914da7d0SScott Long /* 1069914da7d0SScott Long *Command Buffer Management 1070914da7d0SScott Long */ 107135863739SMike Smith 1072914da7d0SScott Long /* 107335863739SMike Smith * Allocate a command. 107435863739SMike Smith */ 1075fe3cb0e1SScott Long int 107635863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 107735863739SMike Smith { 107835863739SMike Smith struct aac_command *cm; 107935863739SMike Smith 108035863739SMike Smith debug_called(3); 108135863739SMike Smith 1082ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1083ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1084ae543596SScott Long wakeup(sc->aifthread); 1085ae543596SScott Long return (EBUSY); 1086ffb37f33SScott Long } 108735863739SMike Smith 10880b94a66eSMike Smith *cmp = cm; 10890b94a66eSMike Smith return(0); 10900b94a66eSMike Smith } 10910b94a66eSMike Smith 1092914da7d0SScott Long /* 10930b94a66eSMike Smith * Release a command back to the freelist. 10940b94a66eSMike Smith */ 1095fe3cb0e1SScott Long void 10960b94a66eSMike Smith aac_release_command(struct aac_command *cm) 10970b94a66eSMike Smith { 10980b94a66eSMike Smith debug_called(3); 10990b94a66eSMike Smith 11000b94a66eSMike Smith /* (re)initialise the command/FIB */ 110135863739SMike Smith cm->cm_sgtable = NULL; 110235863739SMike Smith cm->cm_flags = 0; 110335863739SMike Smith cm->cm_complete = NULL; 110435863739SMike Smith cm->cm_private = NULL; 110535863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 110635863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 110735863739SMike Smith cm->cm_fib->Header.Flags = 0; 110835863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 110935863739SMike Smith 111035863739SMike Smith /* 111135863739SMike Smith * These are duplicated in aac_start to cover the case where an 111235863739SMike Smith * intermediate stage may have destroyed them. They're left 111335863739SMike Smith * initialised here for debugging purposes only. 111435863739SMike Smith */ 111535863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1116f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1117f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 111835863739SMike Smith 111935863739SMike Smith aac_enqueue_free(cm); 112035863739SMike Smith } 112135863739SMike Smith 1122914da7d0SScott Long /* 11230b94a66eSMike Smith * Map helper for command/FIB allocation. 112435863739SMike Smith */ 112535863739SMike Smith static void 11260b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 112735863739SMike Smith { 11288480cc63SScott Long uint32_t *fibphys; 1129914da7d0SScott Long 11308480cc63SScott Long fibphys = (uint32_t *)arg; 113135863739SMike Smith 113235863739SMike Smith debug_called(3); 113335863739SMike Smith 1134ffb37f33SScott Long *fibphys = segs[0].ds_addr; 113535863739SMike Smith } 113635863739SMike Smith 1137914da7d0SScott Long /* 11380b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 113935863739SMike Smith */ 11400b94a66eSMike Smith static int 11410b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 114235863739SMike Smith { 114335863739SMike Smith struct aac_command *cm; 1144ffb37f33SScott Long struct aac_fibmap *fm; 11458480cc63SScott Long uint32_t fibphys; 1146ffb37f33SScott Long int i, error; 114735863739SMike Smith 114835863739SMike Smith debug_called(1); 114935863739SMike Smith 1150ffb37f33SScott Long if (sc->total_fibs + AAC_FIB_COUNT > AAC_MAX_FIBS) 1151ffb37f33SScott Long return (ENOMEM); 1152ffb37f33SScott Long 11538480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1154ffb37f33SScott Long 11550b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1156ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1157ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 115870545d1aSScott Long device_printf(sc->aac_dev, 115970545d1aSScott Long "Not enough contiguous memory available.\n"); 11608480cc63SScott Long free(fm, M_AACBUF); 11610b94a66eSMike Smith return (ENOMEM); 116235863739SMike Smith } 1163128aa5a0SScott Long 1164ffb37f33SScott Long bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1165ffb37f33SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1166ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1167128aa5a0SScott Long 11680b94a66eSMike Smith /* initialise constant fields in the command structure */ 1169ffb37f33SScott Long bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11700b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11718480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1172ffb37f33SScott Long fm->aac_commands = cm; 117335863739SMike Smith cm->cm_sc = sc; 1174ffb37f33SScott Long cm->cm_fib = fm->aac_fibs + i; 11758480cc63SScott Long cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1176cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 117735863739SMike Smith 1178ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1179ffb37f33SScott Long &cm->cm_datamap)) == 0) 118035863739SMike Smith aac_release_command(cm); 1181ffb37f33SScott Long else 11828480cc63SScott Long break; 11838480cc63SScott Long sc->total_fibs++; 118435863739SMike Smith } 1185ffb37f33SScott Long 11868480cc63SScott Long if (i > 0) { 1187ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 11880b94a66eSMike Smith return (0); 118935863739SMike Smith } 119035863739SMike Smith 11918480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 11928480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 11938480cc63SScott Long free(fm, M_AACBUF); 11948480cc63SScott Long return (ENOMEM); 11958480cc63SScott Long } 11968480cc63SScott Long 1197914da7d0SScott Long /* 11980b94a66eSMike Smith * Free FIBs owned by this adapter. 119935863739SMike Smith */ 120035863739SMike Smith static void 12018480cc63SScott Long aac_free_commands(struct aac_softc *sc) 120235863739SMike Smith { 12038480cc63SScott Long struct aac_fibmap *fm; 1204ffb37f33SScott Long struct aac_command *cm; 120535863739SMike Smith int i; 120635863739SMike Smith 120735863739SMike Smith debug_called(1); 120835863739SMike Smith 12098480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 12108480cc63SScott Long 12118480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 12128480cc63SScott Long /* 12138480cc63SScott Long * We check against total_fibs to handle partially 12148480cc63SScott Long * allocated blocks. 12158480cc63SScott Long */ 12168480cc63SScott Long for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1217ffb37f33SScott Long cm = fm->aac_commands + i; 1218ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1219ffb37f33SScott Long } 1220ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1221ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12228480cc63SScott Long free(fm, M_AACBUF); 12238480cc63SScott Long } 122435863739SMike Smith } 122535863739SMike Smith 1226914da7d0SScott Long /* 122735863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 122835863739SMike Smith */ 122935863739SMike Smith static void 123035863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 123135863739SMike Smith { 1232914da7d0SScott Long struct aac_command *cm; 1233914da7d0SScott Long struct aac_fib *fib; 123435863739SMike Smith struct aac_sg_table *sg; 123535863739SMike Smith int i; 123635863739SMike Smith 123735863739SMike Smith debug_called(3); 123835863739SMike Smith 1239914da7d0SScott Long cm = (struct aac_command *)arg; 1240914da7d0SScott Long fib = cm->cm_fib; 1241914da7d0SScott Long 124235863739SMike Smith /* find the s/g table */ 124335863739SMike Smith sg = cm->cm_sgtable; 124435863739SMike Smith 124535863739SMike Smith /* copy into the FIB */ 124635863739SMike Smith if (sg != NULL) { 124735863739SMike Smith sg->SgCount = nseg; 124835863739SMike Smith for (i = 0; i < nseg; i++) { 124935863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 125035863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 125135863739SMike Smith } 125235863739SMike Smith /* update the FIB size for the s/g count */ 125335863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 125435863739SMike Smith } 125535863739SMike Smith 125635863739SMike Smith } 125735863739SMike Smith 1258914da7d0SScott Long /* 125935863739SMike Smith * Map a command into controller-visible space. 126035863739SMike Smith */ 126135863739SMike Smith static void 126235863739SMike Smith aac_map_command(struct aac_command *cm) 126335863739SMike Smith { 1264914da7d0SScott Long struct aac_softc *sc; 126535863739SMike Smith 126635863739SMike Smith debug_called(2); 126735863739SMike Smith 1268914da7d0SScott Long sc = cm->cm_sc; 1269914da7d0SScott Long 127035863739SMike Smith /* don't map more than once */ 127135863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 127235863739SMike Smith return; 127335863739SMike Smith 127435863739SMike Smith if (cm->cm_datalen != 0) { 1275914da7d0SScott Long bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 1276914da7d0SScott Long cm->cm_data, cm->cm_datalen, 1277914da7d0SScott Long aac_map_command_sg, cm, 0); 127835863739SMike Smith 127935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1280c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1281c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 128235863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1283c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1284c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 128535863739SMike Smith } 128635863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 128735863739SMike Smith } 128835863739SMike Smith 1289914da7d0SScott Long /* 129035863739SMike Smith * Unmap a command from controller-visible space. 129135863739SMike Smith */ 129235863739SMike Smith static void 129335863739SMike Smith aac_unmap_command(struct aac_command *cm) 129435863739SMike Smith { 1295914da7d0SScott Long struct aac_softc *sc; 129635863739SMike Smith 129735863739SMike Smith debug_called(2); 129835863739SMike Smith 1299914da7d0SScott Long sc = cm->cm_sc; 1300914da7d0SScott Long 130135863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 130235863739SMike Smith return; 130335863739SMike Smith 130435863739SMike Smith if (cm->cm_datalen != 0) { 130535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1306c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1307c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 130835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1309c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1310c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 131135863739SMike Smith 131235863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 131335863739SMike Smith } 131435863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 131535863739SMike Smith } 131635863739SMike Smith 1317914da7d0SScott Long /* 1318914da7d0SScott Long * Hardware Interface 1319914da7d0SScott Long */ 132035863739SMike Smith 1321914da7d0SScott Long /* 132235863739SMike Smith * Initialise the adapter. 132335863739SMike Smith */ 132435863739SMike Smith static void 132535863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 132635863739SMike Smith { 1327914da7d0SScott Long struct aac_softc *sc; 132835863739SMike Smith 132935863739SMike Smith debug_called(1); 133035863739SMike Smith 1331914da7d0SScott Long sc = (struct aac_softc *)arg; 1332914da7d0SScott Long 133335863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 133435863739SMike Smith } 133535863739SMike Smith 1336fe94b852SScott Long /* 1337fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1338fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1339fe94b852SScott Long */ 1340fe94b852SScott Long static int 1341fe94b852SScott Long aac_check_firmware(struct aac_softc *sc) 1342fe94b852SScott Long { 1343fe94b852SScott Long u_int32_t major, minor; 1344fe94b852SScott Long 1345fe94b852SScott Long debug_called(1); 1346fe94b852SScott Long 1347fe94b852SScott Long if (sc->quirks & AAC_QUIRK_PERC2QC) { 1348fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1349fe94b852SScott Long NULL)) { 1350fe94b852SScott Long device_printf(sc->aac_dev, 1351fe94b852SScott Long "Error reading firmware version\n"); 1352fe94b852SScott Long return (EIO); 1353fe94b852SScott Long } 1354fe94b852SScott Long 1355fe94b852SScott Long /* These numbers are stored as ASCII! */ 1356fe94b852SScott Long major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30; 1357fe94b852SScott Long minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30; 1358fe94b852SScott Long if (major == 1) { 1359fe94b852SScott Long device_printf(sc->aac_dev, 1360fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1361fe94b852SScott Long major, minor); 1362fe94b852SScott Long return (EINVAL); 1363fe94b852SScott Long } 1364fe94b852SScott Long } 1365fe94b852SScott Long 1366fe94b852SScott Long return (0); 1367fe94b852SScott Long } 1368fe94b852SScott Long 136935863739SMike Smith static int 137035863739SMike Smith aac_init(struct aac_softc *sc) 137135863739SMike Smith { 137235863739SMike Smith struct aac_adapter_init *ip; 137335863739SMike Smith time_t then; 137435863739SMike Smith u_int32_t code; 137535863739SMike Smith u_int8_t *qaddr; 137635863739SMike Smith 137735863739SMike Smith debug_called(1); 137835863739SMike Smith 137935863739SMike Smith /* 138035863739SMike Smith * First wait for the adapter to come ready. 138135863739SMike Smith */ 138235863739SMike Smith then = time_second; 138335863739SMike Smith do { 138435863739SMike Smith code = AAC_GET_FWSTATUS(sc); 138535863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 138635863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 138735863739SMike Smith return(ENXIO); 138835863739SMike Smith } 138935863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1390914da7d0SScott Long device_printf(sc->aac_dev, 1391914da7d0SScott Long "FATAL: controller kernel panic\n"); 139235863739SMike Smith return(ENXIO); 139335863739SMike Smith } 139435863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1395914da7d0SScott Long device_printf(sc->aac_dev, 1396914da7d0SScott Long "FATAL: controller not coming ready, " 1397c6eafcf2SScott Long "status %x\n", code); 139835863739SMike Smith return(ENXIO); 139935863739SMike Smith } 140035863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 140135863739SMike Smith 140235863739SMike Smith /* 140335863739SMike Smith * Create DMA tag for the common structure and allocate it. 140435863739SMike Smith */ 140535863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1406c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1407fe3cb0e1SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 140835863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 140935863739SMike Smith NULL, NULL, /* filter, filterarg */ 1410ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1411914da7d0SScott Long 1, /* nsegments */ 141235863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 141335863739SMike Smith 0, /* flags */ 141435863739SMike Smith &sc->aac_common_dmat)) { 1415914da7d0SScott Long device_printf(sc->aac_dev, 1416914da7d0SScott Long "can't allocate common structure DMA tag\n"); 141735863739SMike Smith return(ENOMEM); 141835863739SMike Smith } 1419c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1420c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 142135863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 142235863739SMike Smith return(ENOMEM); 142335863739SMike Smith } 1424ffb37f33SScott Long 1425ffb37f33SScott Long /* 1426ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1427ffb37f33SScott Long * below address 8192 in physical memory. 1428ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1429ffb37f33SScott Long * of ignored? 1430ffb37f33SScott Long */ 1431914da7d0SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1432ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1433ffb37f33SScott Long aac_common_map, sc, 0); 1434ffb37f33SScott Long 1435ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1436ffb37f33SScott Long (uint8_t *)sc->aac_common += 8192; 1437ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1438ffb37f33SScott Long } 143935863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 144035863739SMike Smith 1441ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1442ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 1443ffb37f33SScott Long sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 14448480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 14458480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1446ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1447ffb37f33SScott Long break; 1448ffb37f33SScott Long } 1449ffb37f33SScott Long if (sc->total_fibs == 0) 1450ffb37f33SScott Long return (ENOMEM); 1451ffb37f33SScott Long 145235863739SMike Smith /* 1453914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1454914da7d0SScott Long * physical location of various important shared data structures. 145535863739SMike Smith */ 145635863739SMike Smith ip = &sc->aac_common->ac_init; 145735863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1458f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 145935863739SMike Smith 1460c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1461c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1462f30ac74cSScott Long ip->AdapterFibsVirtualAddress = (u_int32_t)&sc->aac_common->ac_fibs[0]; 146335863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 146435863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 146535863739SMike Smith 1466c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1467c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 146835863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 146935863739SMike Smith 1470f30ac74cSScott Long /* The adapter assumes that pages are 4K in size */ 1471f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 147235863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 147335863739SMike Smith 147435863739SMike Smith /* 1475c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1476c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1477c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 147835863739SMike Smith * 147935863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1480914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1481914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1482914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1483914da7d0SScott Long * does. 148435863739SMike Smith * 1485914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1486914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1487914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1488914da7d0SScott Long * virtue of a table. 148935863739SMike Smith */ 149035863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 149135863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 149235863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1493914da7d0SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + 1494914da7d0SScott Long ((u_int32_t)sc->aac_queues - 1495914da7d0SScott Long (u_int32_t)sc->aac_common); 149635863739SMike Smith 1497c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1498c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1499c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1500c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1501c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1502c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1503c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1504c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1505c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1506c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1507c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1508c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1509c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1510c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1511c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1512c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1513c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1514c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1515c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1516c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1517c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1518c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1519c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1520c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1521c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1522c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1523c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1524c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1525c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1526c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1527c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1528c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1529c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1530c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1531c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1532c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1533c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1534c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1535c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1536c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1537c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1538c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1539c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1540c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1541c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1542c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1543c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1544c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 154535863739SMike Smith 154635863739SMike Smith /* 154735863739SMike Smith * Do controller-type-specific initialisation 154835863739SMike Smith */ 154935863739SMike Smith switch (sc->aac_hwif) { 155035863739SMike Smith case AAC_HWIF_I960RX: 155135863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 155235863739SMike Smith break; 155335863739SMike Smith } 155435863739SMike Smith 155535863739SMike Smith /* 155635863739SMike Smith * Give the init structure to the controller. 155735863739SMike Smith */ 155835863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1559914da7d0SScott Long sc->aac_common_busaddr + 1560914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1561914da7d0SScott Long NULL)) { 1562914da7d0SScott Long device_printf(sc->aac_dev, 1563914da7d0SScott Long "error establishing init structure\n"); 156435863739SMike Smith return(EIO); 156535863739SMike Smith } 156635863739SMike Smith 156735863739SMike Smith return(0); 156835863739SMike Smith } 156935863739SMike Smith 1570914da7d0SScott Long /* 157135863739SMike Smith * Send a synchronous command to the controller and wait for a result. 157235863739SMike Smith */ 157335863739SMike Smith static int 157435863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 157535863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 157635863739SMike Smith u_int32_t *sp) 157735863739SMike Smith { 157835863739SMike Smith time_t then; 157935863739SMike Smith u_int32_t status; 158035863739SMike Smith 158135863739SMike Smith debug_called(3); 158235863739SMike Smith 158335863739SMike Smith /* populate the mailbox */ 158435863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 158535863739SMike Smith 158635863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 158735863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 158835863739SMike Smith 158935863739SMike Smith /* then set it to signal the adapter */ 159035863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 159135863739SMike Smith 159235863739SMike Smith /* spin waiting for the command to complete */ 159335863739SMike Smith then = time_second; 159435863739SMike Smith do { 159535863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 159635863739SMike Smith debug(2, "timed out"); 159735863739SMike Smith return(EIO); 159835863739SMike Smith } 159935863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 160035863739SMike Smith 160135863739SMike Smith /* clear the completion flag */ 160235863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 160335863739SMike Smith 160435863739SMike Smith /* get the command status */ 160535863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 160635863739SMike Smith if (sp != NULL) 160735863739SMike Smith *sp = status; 16080b94a66eSMike Smith return(0); 160935863739SMike Smith } 161035863739SMike Smith 1611914da7d0SScott Long /* 1612cbfd045bSScott Long * Grab the sync fib area. 1613cbfd045bSScott Long */ 1614cbfd045bSScott Long int 1615fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1616cbfd045bSScott Long { 1617cbfd045bSScott Long 1618cbfd045bSScott Long /* 1619cbfd045bSScott Long * If the force flag is set, the system is shutting down, or in 1620cbfd045bSScott Long * trouble. Ignore the mutex. 1621cbfd045bSScott Long */ 1622cbfd045bSScott Long if (!(flags & AAC_SYNC_LOCK_FORCE)) 1623cbfd045bSScott Long AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1624cbfd045bSScott Long 1625cbfd045bSScott Long *fib = &sc->aac_common->ac_sync_fib; 1626cbfd045bSScott Long 1627cbfd045bSScott Long return (1); 1628cbfd045bSScott Long } 1629cbfd045bSScott Long 1630cbfd045bSScott Long /* 1631cbfd045bSScott Long * Release the sync fib area. 1632cbfd045bSScott Long */ 1633cbfd045bSScott Long void 1634cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc) 1635cbfd045bSScott Long { 1636cbfd045bSScott Long 1637cbfd045bSScott Long AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1638cbfd045bSScott Long } 1639cbfd045bSScott Long 1640cbfd045bSScott Long /* 164135863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 164235863739SMike Smith */ 1643cbfd045bSScott Long int 164435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1645cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 164635863739SMike Smith { 164735863739SMike Smith debug_called(3); 164835863739SMike Smith 164935863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 165035863739SMike Smith return(EINVAL); 165135863739SMike Smith 165235863739SMike Smith /* 165335863739SMike Smith * Set up the sync FIB 165435863739SMike Smith */ 1655914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1656914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1657c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 165835863739SMike Smith fib->Header.XferState |= xferstate; 165935863739SMike Smith fib->Header.Command = command; 166035863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 166135863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 166235863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 166335863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1664c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1665914da7d0SScott Long offsetof(struct aac_common, 1666914da7d0SScott Long ac_sync_fib); 166735863739SMike Smith 166835863739SMike Smith /* 166935863739SMike Smith * Give the FIB to the controller, wait for a response. 167035863739SMike Smith */ 1671914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1672914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 167335863739SMike Smith debug(2, "IO error"); 167435863739SMike Smith return(EIO); 167535863739SMike Smith } 167635863739SMike Smith 167735863739SMike Smith return (0); 167835863739SMike Smith } 167935863739SMike Smith 1680914da7d0SScott Long /* 168135863739SMike Smith * Adapter-space FIB queue manipulation 168235863739SMike Smith * 168335863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 168435863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 168535863739SMike Smith */ 168635863739SMike Smith static struct { 168735863739SMike Smith int size; 168835863739SMike Smith int notify; 168935863739SMike Smith } aac_qinfo[] = { 169035863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 169135863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 169235863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 169335863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 169435863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 169535863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 169635863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 169735863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 169835863739SMike Smith }; 169935863739SMike Smith 170035863739SMike Smith /* 1701c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1702c6eafcf2SScott Long * EBUSY if the queue is full. 170335863739SMike Smith * 17040b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1705914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1706914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1707c6eafcf2SScott Long * separate queue/notify interface). 170835863739SMike Smith */ 170935863739SMike Smith static int 1710f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 171135863739SMike Smith { 171235863739SMike Smith u_int32_t pi, ci; 171335863739SMike Smith int s, error; 1714f6c4dd3fSScott Long u_int32_t fib_size; 1715f6c4dd3fSScott Long u_int32_t fib_addr; 1716f6c4dd3fSScott Long 171736e0bf6eSScott Long debug_called(3); 171836e0bf6eSScott Long 1719f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1720f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 172135863739SMike Smith 172235863739SMike Smith s = splbio(); 172335863739SMike Smith 172435863739SMike Smith /* get the producer/consumer indices */ 172535863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 172635863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 172735863739SMike Smith 172835863739SMike Smith /* wrap the queue? */ 172935863739SMike Smith if (pi >= aac_qinfo[queue].size) 173035863739SMike Smith pi = 0; 173135863739SMike Smith 173235863739SMike Smith /* check for queue full */ 173335863739SMike Smith if ((pi + 1) == ci) { 173435863739SMike Smith error = EBUSY; 173535863739SMike Smith goto out; 173635863739SMike Smith } 173735863739SMike Smith 173835863739SMike Smith /* populate queue entry */ 173935863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 174035863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 174135863739SMike Smith 174235863739SMike Smith /* update producer index */ 174335863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 174435863739SMike Smith 1745f6c4dd3fSScott Long /* 1746914da7d0SScott Long * To avoid a race with its completion interrupt, place this command on 1747914da7d0SScott Long * the busy queue prior to advertising it to the controller. 1748f6c4dd3fSScott Long */ 1749f6c4dd3fSScott Long aac_enqueue_busy(cm); 1750f6c4dd3fSScott Long 175135863739SMike Smith /* notify the adapter if we know how */ 175235863739SMike Smith if (aac_qinfo[queue].notify != 0) 175335863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 175435863739SMike Smith 175535863739SMike Smith error = 0; 175635863739SMike Smith 175735863739SMike Smith out: 175835863739SMike Smith splx(s); 175935863739SMike Smith return(error); 176035863739SMike Smith } 176135863739SMike Smith 176235863739SMike Smith /* 176336e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 176436e0bf6eSScott Long * success or ENOENT if the queue is empty. 176535863739SMike Smith */ 176635863739SMike Smith static int 1767c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1768c6eafcf2SScott Long struct aac_fib **fib_addr) 176935863739SMike Smith { 177035863739SMike Smith u_int32_t pi, ci; 177135863739SMike Smith int s, error; 1772f6c4dd3fSScott Long int notify; 177335863739SMike Smith 177435863739SMike Smith debug_called(3); 177535863739SMike Smith 177635863739SMike Smith s = splbio(); 177735863739SMike Smith 177835863739SMike Smith /* get the producer/consumer indices */ 177935863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 178035863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 178135863739SMike Smith 178235863739SMike Smith /* check for queue empty */ 178335863739SMike Smith if (ci == pi) { 178435863739SMike Smith error = ENOENT; 178535863739SMike Smith goto out; 178635863739SMike Smith } 178735863739SMike Smith 1788f6c4dd3fSScott Long notify = 0; 1789f6c4dd3fSScott Long if (ci == pi + 1) 1790f6c4dd3fSScott Long notify++; 1791f6c4dd3fSScott Long 179235863739SMike Smith /* wrap the queue? */ 179335863739SMike Smith if (ci >= aac_qinfo[queue].size) 179435863739SMike Smith ci = 0; 179535863739SMike Smith 179635863739SMike Smith /* fetch the entry */ 179735863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1798914da7d0SScott Long *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + 1799914da7d0SScott Long ci)->aq_fib_addr; 180035863739SMike Smith 1801f30ac74cSScott Long /* 1802f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1803f30ac74cSScott Long * local memory so the whole fib doesn't have to be DMA'd back up. 1804f30ac74cSScott Long */ 1805f30ac74cSScott Long if (*(uintptr_t *)fib_addr & 0x01) { 1806f30ac74cSScott Long *(uintptr_t *)fib_addr &= ~0x01; 1807f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1808f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1809f30ac74cSScott Long } 181035863739SMike Smith /* update consumer index */ 181135863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 181235863739SMike Smith 181335863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1814f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 181535863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 181635863739SMike Smith error = 0; 181735863739SMike Smith 181835863739SMike Smith out: 181935863739SMike Smith splx(s); 182035863739SMike Smith return(error); 182135863739SMike Smith } 182235863739SMike Smith 1823914da7d0SScott Long /* 182436e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 182536e0bf6eSScott Long */ 182636e0bf6eSScott Long static int 182736e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 182836e0bf6eSScott Long { 182936e0bf6eSScott Long u_int32_t pi, ci; 183036e0bf6eSScott Long int s, error; 183136e0bf6eSScott Long u_int32_t fib_size; 183236e0bf6eSScott Long u_int32_t fib_addr; 183336e0bf6eSScott Long 183436e0bf6eSScott Long debug_called(1); 183536e0bf6eSScott Long 183636e0bf6eSScott Long /* Tell the adapter where the FIB is */ 183736e0bf6eSScott Long fib_size = fib->Header.Size; 183836e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 183936e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 184036e0bf6eSScott Long 184136e0bf6eSScott Long s = splbio(); 184236e0bf6eSScott Long 184336e0bf6eSScott Long /* get the producer/consumer indices */ 184436e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 184536e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 184636e0bf6eSScott Long 184736e0bf6eSScott Long /* wrap the queue? */ 184836e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 184936e0bf6eSScott Long pi = 0; 185036e0bf6eSScott Long 185136e0bf6eSScott Long /* check for queue full */ 185236e0bf6eSScott Long if ((pi + 1) == ci) { 185336e0bf6eSScott Long error = EBUSY; 185436e0bf6eSScott Long goto out; 185536e0bf6eSScott Long } 185636e0bf6eSScott Long 185736e0bf6eSScott Long /* populate queue entry */ 185836e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 185936e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 186036e0bf6eSScott Long 186136e0bf6eSScott Long /* update producer index */ 186236e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 186336e0bf6eSScott Long 186436e0bf6eSScott Long /* notify the adapter if we know how */ 186536e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 186636e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 186736e0bf6eSScott Long 186836e0bf6eSScott Long error = 0; 186936e0bf6eSScott Long 187036e0bf6eSScott Long out: 187136e0bf6eSScott Long splx(s); 187236e0bf6eSScott Long return(error); 187336e0bf6eSScott Long } 187436e0bf6eSScott Long 1875914da7d0SScott Long /* 18760b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 18770b94a66eSMike Smith * and complain about them. 18780b94a66eSMike Smith */ 18790b94a66eSMike Smith static void 18800b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 18810b94a66eSMike Smith { 18820b94a66eSMike Smith int s; 18830b94a66eSMike Smith struct aac_command *cm; 18840b94a66eSMike Smith time_t deadline; 18850b94a66eSMike Smith 1886f6c4dd3fSScott Long /* 188770545d1aSScott Long * Traverse the busy command list, bitch about late commands once 1888914da7d0SScott Long * only. 1889914da7d0SScott Long */ 18900b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 18910b94a66eSMike Smith s = splbio(); 18920b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1893f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1894f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 18950b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1896914da7d0SScott Long device_printf(sc->aac_dev, 1897914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1898f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 18990b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 19000b94a66eSMike Smith } 19010b94a66eSMike Smith } 19020b94a66eSMike Smith splx(s); 19030b94a66eSMike Smith 19040b94a66eSMike Smith return; 19050b94a66eSMike Smith } 19060b94a66eSMike Smith 1907914da7d0SScott Long /* 1908914da7d0SScott Long * Interface Function Vectors 1909914da7d0SScott Long */ 191035863739SMike Smith 1911914da7d0SScott Long /* 191235863739SMike Smith * Read the current firmware status word. 191335863739SMike Smith */ 191435863739SMike Smith static int 191535863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 191635863739SMike Smith { 191735863739SMike Smith debug_called(3); 191835863739SMike Smith 191935863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 192035863739SMike Smith } 192135863739SMike Smith 192235863739SMike Smith static int 192335863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 192435863739SMike Smith { 192535863739SMike Smith debug_called(3); 192635863739SMike Smith 192735863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 192835863739SMike Smith } 192935863739SMike Smith 1930b3457b51SScott Long static int 1931b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 1932b3457b51SScott Long { 1933b3457b51SScott Long int val; 1934b3457b51SScott Long 1935b3457b51SScott Long debug_called(3); 1936b3457b51SScott Long 1937b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 1938b3457b51SScott Long return (val); 1939b3457b51SScott Long } 1940b3457b51SScott Long 1941914da7d0SScott Long /* 194235863739SMike Smith * Notify the controller of a change in a given queue 194335863739SMike Smith */ 194435863739SMike Smith 194535863739SMike Smith static void 194635863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 194735863739SMike Smith { 194835863739SMike Smith debug_called(3); 194935863739SMike Smith 195035863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 195135863739SMike Smith } 195235863739SMike Smith 195335863739SMike Smith static void 195435863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 195535863739SMike Smith { 195635863739SMike Smith debug_called(3); 195735863739SMike Smith 195835863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 195935863739SMike Smith } 196035863739SMike Smith 1961b3457b51SScott Long static void 1962b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 1963b3457b51SScott Long { 1964b3457b51SScott Long debug_called(3); 1965b3457b51SScott Long 1966b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 1967b3457b51SScott Long AAC_FA_HACK(sc); 1968b3457b51SScott Long } 1969b3457b51SScott Long 1970914da7d0SScott Long /* 197135863739SMike Smith * Get the interrupt reason bits 197235863739SMike Smith */ 197335863739SMike Smith static int 197435863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 197535863739SMike Smith { 197635863739SMike Smith debug_called(3); 197735863739SMike Smith 197835863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 197935863739SMike Smith } 198035863739SMike Smith 198135863739SMike Smith static int 198235863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 198335863739SMike Smith { 198435863739SMike Smith debug_called(3); 198535863739SMike Smith 198635863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 198735863739SMike Smith } 198835863739SMike Smith 1989b3457b51SScott Long static int 1990b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 1991b3457b51SScott Long { 1992b3457b51SScott Long int val; 1993b3457b51SScott Long 1994b3457b51SScott Long debug_called(3); 1995b3457b51SScott Long 1996b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 1997b3457b51SScott Long return (val); 1998b3457b51SScott Long } 1999b3457b51SScott Long 2000914da7d0SScott Long /* 200135863739SMike Smith * Clear some interrupt reason bits 200235863739SMike Smith */ 200335863739SMike Smith static void 200435863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 200535863739SMike Smith { 200635863739SMike Smith debug_called(3); 200735863739SMike Smith 200835863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 200935863739SMike Smith } 201035863739SMike Smith 201135863739SMike Smith static void 201235863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 201335863739SMike Smith { 201435863739SMike Smith debug_called(3); 201535863739SMike Smith 201635863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 201735863739SMike Smith } 201835863739SMike Smith 2019b3457b51SScott Long static void 2020b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2021b3457b51SScott Long { 2022b3457b51SScott Long debug_called(3); 2023b3457b51SScott Long 2024b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2025b3457b51SScott Long AAC_FA_HACK(sc); 2026b3457b51SScott Long } 2027b3457b51SScott Long 2028914da7d0SScott Long /* 202935863739SMike Smith * Populate the mailbox and set the command word 203035863739SMike Smith */ 203135863739SMike Smith static void 203235863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 203335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 203435863739SMike Smith { 203535863739SMike Smith debug_called(4); 203635863739SMike Smith 203735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 203835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 203935863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 204035863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 204135863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 204235863739SMike Smith } 204335863739SMike Smith 204435863739SMike Smith static void 204535863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 204635863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 204735863739SMike Smith { 204835863739SMike Smith debug_called(4); 204935863739SMike Smith 205035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 205135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 205235863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 205335863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 205435863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 205535863739SMike Smith } 205635863739SMike Smith 2057b3457b51SScott Long static void 2058b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2059b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2060b3457b51SScott Long { 2061b3457b51SScott Long debug_called(4); 2062b3457b51SScott Long 2063b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2064b3457b51SScott Long AAC_FA_HACK(sc); 2065b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2066b3457b51SScott Long AAC_FA_HACK(sc); 2067b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2068b3457b51SScott Long AAC_FA_HACK(sc); 2069b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2070b3457b51SScott Long AAC_FA_HACK(sc); 2071b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2072b3457b51SScott Long AAC_FA_HACK(sc); 2073b3457b51SScott Long } 2074b3457b51SScott Long 2075914da7d0SScott Long /* 207635863739SMike Smith * Fetch the immediate command status word 207735863739SMike Smith */ 207835863739SMike Smith static int 207935863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 208035863739SMike Smith { 208135863739SMike Smith debug_called(4); 208235863739SMike Smith 208335863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 208435863739SMike Smith } 208535863739SMike Smith 208635863739SMike Smith static int 208735863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 208835863739SMike Smith { 208935863739SMike Smith debug_called(4); 209035863739SMike Smith 209135863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 209235863739SMike Smith } 209335863739SMike Smith 2094b3457b51SScott Long static int 2095b3457b51SScott Long aac_fa_get_mailboxstatus(struct aac_softc *sc) 2096b3457b51SScott Long { 2097b3457b51SScott Long int val; 2098b3457b51SScott Long 2099b3457b51SScott Long debug_called(4); 2100b3457b51SScott Long 2101b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX); 2102b3457b51SScott Long return (val); 2103b3457b51SScott Long } 2104b3457b51SScott Long 2105914da7d0SScott Long /* 210635863739SMike Smith * Set/clear interrupt masks 210735863739SMike Smith */ 210835863739SMike Smith static void 210935863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 211035863739SMike Smith { 211135863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 211235863739SMike Smith 211335863739SMike Smith if (enable) { 211435863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 211535863739SMike Smith } else { 211635863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 211735863739SMike Smith } 211835863739SMike Smith } 211935863739SMike Smith 212035863739SMike Smith static void 212135863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 212235863739SMike Smith { 212335863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 212435863739SMike Smith 212535863739SMike Smith if (enable) { 212635863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 212735863739SMike Smith } else { 212835863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 212935863739SMike Smith } 213035863739SMike Smith } 213135863739SMike Smith 2132b3457b51SScott Long static void 2133b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2134b3457b51SScott Long { 2135b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2136b3457b51SScott Long 2137b3457b51SScott Long if (enable) { 2138b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2139b3457b51SScott Long AAC_FA_HACK(sc); 2140b3457b51SScott Long } else { 2141b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2142b3457b51SScott Long AAC_FA_HACK(sc); 2143b3457b51SScott Long } 2144b3457b51SScott Long } 2145b3457b51SScott Long 2146914da7d0SScott Long /* 2147914da7d0SScott Long * Debugging and Diagnostics 2148914da7d0SScott Long */ 214935863739SMike Smith 2150914da7d0SScott Long /* 215135863739SMike Smith * Print some information about the controller. 215235863739SMike Smith */ 215335863739SMike Smith static void 215435863739SMike Smith aac_describe_controller(struct aac_softc *sc) 215535863739SMike Smith { 2156cbfd045bSScott Long struct aac_fib *fib; 215735863739SMike Smith struct aac_adapter_info *info; 215835863739SMike Smith 215935863739SMike Smith debug_called(2); 216035863739SMike Smith 2161fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2162cbfd045bSScott Long 2163cbfd045bSScott Long fib->data[0] = 0; 2164cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 216535863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2166fe3cb0e1SScott Long aac_release_sync_fib(sc); 216735863739SMike Smith return; 216835863739SMike Smith } 2169cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 217035863739SMike Smith 217136e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2172c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 217336e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2174914da7d0SScott Long aac_describe_code(aac_battery_platform, 2175914da7d0SScott Long info->batteryPlatform)); 217635863739SMike Smith 217735863739SMike Smith /* save the kernel revision structure for later use */ 217835863739SMike Smith sc->aac_revision = info->KernelRevision; 217936e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 218035863739SMike Smith info->KernelRevision.external.comp.major, 218135863739SMike Smith info->KernelRevision.external.comp.minor, 218235863739SMike Smith info->KernelRevision.external.comp.dash, 218336e0bf6eSScott Long info->KernelRevision.buildNumber, 218436e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2185fe3cb0e1SScott Long 2186fe3cb0e1SScott Long aac_release_sync_fib(sc); 218735863739SMike Smith } 218835863739SMike Smith 2189914da7d0SScott Long /* 219035863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 219135863739SMike Smith * same. 219235863739SMike Smith */ 219335863739SMike Smith static char * 219435863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 219535863739SMike Smith { 219635863739SMike Smith int i; 219735863739SMike Smith 219835863739SMike Smith for (i = 0; table[i].string != NULL; i++) 219935863739SMike Smith if (table[i].code == code) 220035863739SMike Smith return(table[i].string); 220135863739SMike Smith return(table[i + 1].string); 220235863739SMike Smith } 220335863739SMike Smith 2204914da7d0SScott Long /* 2205914da7d0SScott Long * Management Interface 2206914da7d0SScott Long */ 220735863739SMike Smith 220835863739SMike Smith static int 2209c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 221035863739SMike Smith { 2211914da7d0SScott Long struct aac_softc *sc; 221235863739SMike Smith 221335863739SMike Smith debug_called(2); 221435863739SMike Smith 2215914da7d0SScott Long sc = dev->si_drv1; 2216914da7d0SScott Long 221735863739SMike Smith /* Check to make sure the device isn't already open */ 221835863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 221935863739SMike Smith return EBUSY; 222035863739SMike Smith } 222135863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 222235863739SMike Smith 222335863739SMike Smith return 0; 222435863739SMike Smith } 222535863739SMike Smith 222635863739SMike Smith static int 2227c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 222835863739SMike Smith { 2229914da7d0SScott Long struct aac_softc *sc; 223035863739SMike Smith 223135863739SMike Smith debug_called(2); 223235863739SMike Smith 2233914da7d0SScott Long sc = dev->si_drv1; 2234914da7d0SScott Long 223535863739SMike Smith /* Mark this unit as no longer open */ 223635863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 223735863739SMike Smith 223835863739SMike Smith return 0; 223935863739SMike Smith } 224035863739SMike Smith 224135863739SMike Smith static int 2242c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 224335863739SMike Smith { 2244914da7d0SScott Long union aac_statrequest *as; 2245914da7d0SScott Long struct aac_softc *sc; 22460b94a66eSMike Smith int error = 0; 22470b94a66eSMike Smith int i; 224835863739SMike Smith 224935863739SMike Smith debug_called(2); 225035863739SMike Smith 2251914da7d0SScott Long as = (union aac_statrequest *)arg; 2252914da7d0SScott Long sc = dev->si_drv1; 2253914da7d0SScott Long 225435863739SMike Smith switch (cmd) { 22550b94a66eSMike Smith case AACIO_STATS: 22560b94a66eSMike Smith switch (as->as_item) { 22570b94a66eSMike Smith case AACQ_FREE: 22580b94a66eSMike Smith case AACQ_BIO: 22590b94a66eSMike Smith case AACQ_READY: 22600b94a66eSMike Smith case AACQ_BUSY: 22610b94a66eSMike Smith case AACQ_COMPLETE: 2262c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2263c6eafcf2SScott Long sizeof(struct aac_qstat)); 22640b94a66eSMike Smith break; 22650b94a66eSMike Smith default: 22660b94a66eSMike Smith error = ENOENT; 22670b94a66eSMike Smith break; 22680b94a66eSMike Smith } 22690b94a66eSMike Smith break; 22700b94a66eSMike Smith 227135863739SMike Smith case FSACTL_SENDFIB: 2272fb0c27d7SScott Long arg = *(caddr_t*)arg; 2273fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 22740b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 227535863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 227635863739SMike Smith break; 227735863739SMike Smith case FSACTL_AIF_THREAD: 2278fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 22790b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 228035863739SMike Smith error = EINVAL; 228135863739SMike Smith break; 228235863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2283fb0c27d7SScott Long arg = *(caddr_t*)arg; 2284fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 22850b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 228635863739SMike Smith /* 228735863739SMike Smith * Pass the caller out an AdapterFibContext. 228835863739SMike Smith * 228935863739SMike Smith * Note that because we only support one opener, we 229035863739SMike Smith * basically ignore this. Set the caller's context to a magic 229135863739SMike Smith * number just in case. 22920b94a66eSMike Smith * 22930b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 22940b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2295914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2296914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 229735863739SMike Smith */ 229836e0bf6eSScott Long i = (int)sc->aifthread; 229935863739SMike Smith error = copyout(&i, arg, sizeof(i)); 230035863739SMike Smith break; 230135863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2302fb0c27d7SScott Long arg = *(caddr_t*)arg; 2303fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 23040b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2305fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 230635863739SMike Smith break; 230735863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2308fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 23090b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 231035863739SMike Smith /* don't do anything here */ 231135863739SMike Smith break; 231235863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2313fb0c27d7SScott Long arg = *(caddr_t*)arg; 2314fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 23150b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2316fb0c27d7SScott Long error = aac_rev_check(sc, arg); 231735863739SMike Smith break; 231836e0bf6eSScott Long case FSACTL_QUERY_DISK: 231936e0bf6eSScott Long arg = *(caddr_t*)arg; 232036e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 232136e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 232236e0bf6eSScott Long error = aac_query_disk(sc, arg); 232336e0bf6eSScott Long break; 232436e0bf6eSScott Long case FSACTL_DELETE_DISK: 232536e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2326914da7d0SScott Long /* 2327914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2328914da7d0SScott Long * container, rather we rely on an AIF coming from the 2329914da7d0SScott Long * controller 2330914da7d0SScott Long */ 233136e0bf6eSScott Long error = 0; 233236e0bf6eSScott Long break; 233335863739SMike Smith default: 2334b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 233535863739SMike Smith error = EINVAL; 233635863739SMike Smith break; 233735863739SMike Smith } 233835863739SMike Smith return(error); 233935863739SMike Smith } 234035863739SMike Smith 2341b3457b51SScott Long static int 2342c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td) 2343b3457b51SScott Long { 2344b3457b51SScott Long struct aac_softc *sc; 2345b3457b51SScott Long int revents; 2346b3457b51SScott Long 2347b3457b51SScott Long sc = dev->si_drv1; 2348b3457b51SScott Long revents = 0; 2349b3457b51SScott Long 2350c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2351b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2352b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2353b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2354b3457b51SScott Long } 2355b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2356b3457b51SScott Long 2357b3457b51SScott Long if (revents == 0) { 2358b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2359b3457b51SScott Long selrecord(td, &sc->rcv_select); 2360b3457b51SScott Long } 2361b3457b51SScott Long 2362b3457b51SScott Long return (revents); 2363b3457b51SScott Long } 2364b3457b51SScott Long 2365914da7d0SScott Long /* 236635863739SMike Smith * Send a FIB supplied from userspace 236735863739SMike Smith */ 236835863739SMike Smith static int 236935863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 237035863739SMike Smith { 237135863739SMike Smith struct aac_command *cm; 237235863739SMike Smith int size, error; 237335863739SMike Smith 237435863739SMike Smith debug_called(2); 237535863739SMike Smith 237635863739SMike Smith cm = NULL; 237735863739SMike Smith 237835863739SMike Smith /* 237935863739SMike Smith * Get a command 238035863739SMike Smith */ 2381ae543596SScott Long AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 238235863739SMike Smith if (aac_alloc_command(sc, &cm)) { 238335863739SMike Smith error = EBUSY; 238435863739SMike Smith goto out; 238535863739SMike Smith } 238635863739SMike Smith 238735863739SMike Smith /* 238835863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 238935863739SMike Smith */ 2390914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2391914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 239235863739SMike Smith goto out; 239335863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 239435863739SMike Smith if (size > sizeof(struct aac_fib)) { 2395914da7d0SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2396914da7d0SScott Long size, sizeof(struct aac_fib)); 239735863739SMike Smith size = sizeof(struct aac_fib); 239835863739SMike Smith } 239935863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 240035863739SMike Smith goto out; 240135863739SMike Smith cm->cm_fib->Header.Size = size; 2402f6c4dd3fSScott Long cm->cm_timestamp = time_second; 240335863739SMike Smith 240435863739SMike Smith /* 240535863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 240635863739SMike Smith */ 2407b3457b51SScott Long if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 240870545d1aSScott Long device_printf(sc->aac_dev, 240970545d1aSScott Long "aac_wait_command return %d\n", error); 241035863739SMike Smith goto out; 2411b3457b51SScott Long } 241235863739SMike Smith 241335863739SMike Smith /* 241435863739SMike Smith * Copy the FIB and data back out to the caller. 241535863739SMike Smith */ 241635863739SMike Smith size = cm->cm_fib->Header.Size; 241735863739SMike Smith if (size > sizeof(struct aac_fib)) { 2418914da7d0SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2419914da7d0SScott Long size, sizeof(struct aac_fib)); 242035863739SMike Smith size = sizeof(struct aac_fib); 242135863739SMike Smith } 242235863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 242335863739SMike Smith 242435863739SMike Smith out: 2425f6c4dd3fSScott Long if (cm != NULL) { 242635863739SMike Smith aac_release_command(cm); 2427f6c4dd3fSScott Long } 2428ae543596SScott Long 2429ae543596SScott Long AAC_LOCK_RELEASE(&sc->aac_io_lock); 243035863739SMike Smith return(error); 243135863739SMike Smith } 243235863739SMike Smith 2433914da7d0SScott Long /* 243435863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 243536e0bf6eSScott Long * If the queue fills up, then drop the older entries. 243635863739SMike Smith */ 243735863739SMike Smith static void 243836e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 243935863739SMike Smith { 244036e0bf6eSScott Long struct aac_aif_command *aif; 244136e0bf6eSScott Long struct aac_container *co, *co_next; 2442cbfd045bSScott Long struct aac_mntinfo *mi; 2443cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 244436e0bf6eSScott Long u_int16_t rsize; 2445b3457b51SScott Long int next, found; 244636e0bf6eSScott Long int added = 0, i = 0; 244735863739SMike Smith 244835863739SMike Smith debug_called(2); 244935863739SMike Smith 245036e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 245136e0bf6eSScott Long aac_print_aif(sc, aif); 245236e0bf6eSScott Long 245336e0bf6eSScott Long /* Is it an event that we should care about? */ 245436e0bf6eSScott Long switch (aif->command) { 245536e0bf6eSScott Long case AifCmdEventNotify: 245636e0bf6eSScott Long switch (aif->data.EN.type) { 245736e0bf6eSScott Long case AifEnAddContainer: 245836e0bf6eSScott Long case AifEnDeleteContainer: 245936e0bf6eSScott Long /* 2460914da7d0SScott Long * A container was added or deleted, but the message 2461914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2462914da7d0SScott Long * containers and sort things out. 246336e0bf6eSScott Long */ 2464fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2465cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 246636e0bf6eSScott Long do { 246736e0bf6eSScott Long /* 2468914da7d0SScott Long * Ask the controller for its containers one at 2469914da7d0SScott Long * a time. 2470914da7d0SScott Long * XXX What if the controller's list changes 2471914da7d0SScott Long * midway through this enumaration? 247236e0bf6eSScott Long * XXX This should be done async. 247336e0bf6eSScott Long */ 247439ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 247539ee03c3SScott Long mi->Command = VM_NameServe; 247639ee03c3SScott Long mi->MntType = FT_FILESYS; 2477cbfd045bSScott Long mi->MntCount = i; 247836e0bf6eSScott Long rsize = sizeof(mir); 2479cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2480cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2481914da7d0SScott Long debug(2, "Error probing container %d\n", 2482914da7d0SScott Long i); 248336e0bf6eSScott Long continue; 248436e0bf6eSScott Long } 2485cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 248636e0bf6eSScott Long /* 2487914da7d0SScott Long * Check the container against our list. 2488914da7d0SScott Long * co->co_found was already set to 0 in a 2489914da7d0SScott Long * previous run. 249036e0bf6eSScott Long */ 2491cbfd045bSScott Long if ((mir->Status == ST_OK) && 2492cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 249336e0bf6eSScott Long found = 0; 2494914da7d0SScott Long TAILQ_FOREACH(co, 2495914da7d0SScott Long &sc->aac_container_tqh, 2496914da7d0SScott Long co_link) { 249736e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2498cbfd045bSScott Long mir->MntTable[0].ObjectId) { 249936e0bf6eSScott Long co->co_found = 1; 250036e0bf6eSScott Long found = 1; 250136e0bf6eSScott Long break; 250236e0bf6eSScott Long } 250336e0bf6eSScott Long } 2504914da7d0SScott Long /* 2505914da7d0SScott Long * If the container matched, continue 2506914da7d0SScott Long * in the list. 2507914da7d0SScott Long */ 250836e0bf6eSScott Long if (found) { 250936e0bf6eSScott Long i++; 251036e0bf6eSScott Long continue; 251136e0bf6eSScott Long } 251236e0bf6eSScott Long 251336e0bf6eSScott Long /* 2514914da7d0SScott Long * This is a new container. Do all the 251570545d1aSScott Long * appropriate things to set it up. 251670545d1aSScott Long */ 2517cbfd045bSScott Long aac_add_container(sc, mir, 1); 251836e0bf6eSScott Long added = 1; 251936e0bf6eSScott Long } 252036e0bf6eSScott Long i++; 2521cbfd045bSScott Long } while ((i < mir->MntRespCount) && 2522914da7d0SScott Long (i < AAC_MAX_CONTAINERS)); 2523cbfd045bSScott Long aac_release_sync_fib(sc); 252436e0bf6eSScott Long 252536e0bf6eSScott Long /* 2526914da7d0SScott Long * Go through our list of containers and see which ones 2527914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2528914da7d0SScott Long * list them they must have been deleted. Do the 2529914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2530914da7d0SScott Long * the co->co_found field. 253136e0bf6eSScott Long */ 253236e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 253336e0bf6eSScott Long while (co != NULL) { 253436e0bf6eSScott Long if (co->co_found == 0) { 2535914da7d0SScott Long device_delete_child(sc->aac_dev, 2536914da7d0SScott Long co->co_disk); 253736e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2538c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc-> 2539914da7d0SScott Long aac_container_lock); 2540914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2541914da7d0SScott Long co_link); 2542914da7d0SScott Long AAC_LOCK_RELEASE(&sc-> 2543914da7d0SScott Long aac_container_lock); 254436e0bf6eSScott Long FREE(co, M_AACBUF); 254536e0bf6eSScott Long co = co_next; 254636e0bf6eSScott Long } else { 254736e0bf6eSScott Long co->co_found = 0; 254836e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 254936e0bf6eSScott Long } 255036e0bf6eSScott Long } 255136e0bf6eSScott Long 255236e0bf6eSScott Long /* Attach the newly created containers */ 255336e0bf6eSScott Long if (added) 255436e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 255536e0bf6eSScott Long 255636e0bf6eSScott Long break; 255736e0bf6eSScott Long 255836e0bf6eSScott Long default: 255936e0bf6eSScott Long break; 256036e0bf6eSScott Long } 256136e0bf6eSScott Long 256236e0bf6eSScott Long default: 256336e0bf6eSScott Long break; 256436e0bf6eSScott Long } 256536e0bf6eSScott Long 256636e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2567c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 256835863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 256935863739SMike Smith if (next != sc->aac_aifq_tail) { 257035863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 257135863739SMike Smith sc->aac_aifq_head = next; 2572b3457b51SScott Long 2573b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 257435863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 257535863739SMike Smith wakeup(sc->aac_aifq); 2576b3457b51SScott Long /* Wakeup any poll()ers */ 2577b3457b51SScott Long selwakeup(&sc->rcv_select); 257835863739SMike Smith } 2579b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 258036e0bf6eSScott Long 258136e0bf6eSScott Long return; 258235863739SMike Smith } 258335863739SMike Smith 2584914da7d0SScott Long /* 25850b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 258636e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 258736e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 258836e0bf6eSScott Long * returning what the card reported. 258935863739SMike Smith */ 259035863739SMike Smith static int 2591fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 259235863739SMike Smith { 259335863739SMike Smith struct aac_rev_check rev_check; 259435863739SMike Smith struct aac_rev_check_resp rev_check_resp; 259535863739SMike Smith int error = 0; 259635863739SMike Smith 259735863739SMike Smith debug_called(2); 259835863739SMike Smith 259935863739SMike Smith /* 260035863739SMike Smith * Copyin the revision struct from userspace 260135863739SMike Smith */ 2602c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2603c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 260435863739SMike Smith return error; 260535863739SMike Smith } 260635863739SMike Smith 2607914da7d0SScott Long debug(2, "Userland revision= %d\n", 2608914da7d0SScott Long rev_check.callingRevision.buildNumber); 260935863739SMike Smith 261035863739SMike Smith /* 261135863739SMike Smith * Doctor up the response struct. 261235863739SMike Smith */ 261335863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2614914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2615914da7d0SScott Long sc->aac_revision.external.ul; 2616914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2617914da7d0SScott Long sc->aac_revision.buildNumber; 261835863739SMike Smith 2619c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2620c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 262135863739SMike Smith } 262235863739SMike Smith 2623914da7d0SScott Long /* 262435863739SMike Smith * Pass the caller the next AIF in their queue 262535863739SMike Smith */ 262635863739SMike Smith static int 2627fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 262835863739SMike Smith { 262935863739SMike Smith struct get_adapter_fib_ioctl agf; 263035863739SMike Smith int error, s; 263135863739SMike Smith 263235863739SMike Smith debug_called(2); 263335863739SMike Smith 263435863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 263535863739SMike Smith 263635863739SMike Smith /* 263735863739SMike Smith * Check the magic number that we gave the caller. 263835863739SMike Smith */ 263936e0bf6eSScott Long if (agf.AdapterFibContext != (int)sc->aifthread) { 264035863739SMike Smith error = EFAULT; 264135863739SMike Smith } else { 264235863739SMike Smith 264335863739SMike Smith s = splbio(); 2644fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 264535863739SMike Smith 264635863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 264735863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 264835863739SMike Smith while (error == EAGAIN) { 2649914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2650914da7d0SScott Long PCATCH, "aacaif", 0); 265135863739SMike Smith if (error == 0) 2652914da7d0SScott Long error = aac_return_aif(sc, 2653914da7d0SScott Long agf.AifFib); 265435863739SMike Smith } 265535863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 265635863739SMike Smith } 265735863739SMike Smith splx(s); 265835863739SMike Smith } 265935863739SMike Smith } 266035863739SMike Smith return(error); 266135863739SMike Smith } 266235863739SMike Smith 2663914da7d0SScott Long /* 26640b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 26650b94a66eSMike Smith */ 26660b94a66eSMike Smith static int 2667fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 26680b94a66eSMike Smith { 2669b3457b51SScott Long int error; 26700b94a66eSMike Smith 26710b94a66eSMike Smith debug_called(2); 26720b94a66eSMike Smith 2673c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 26740b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 26750b94a66eSMike Smith error = EAGAIN; 26760b94a66eSMike Smith } else { 2677c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2678c6eafcf2SScott Long sizeof(struct aac_aif_command)); 267936e0bf6eSScott Long if (error) 268070545d1aSScott Long device_printf(sc->aac_dev, 268170545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 26820b94a66eSMike Smith if (!error) 2683914da7d0SScott Long sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 2684914da7d0SScott Long AAC_AIFQ_LENGTH; 26850b94a66eSMike Smith } 2686b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 26870b94a66eSMike Smith return(error); 26880b94a66eSMike Smith } 268936e0bf6eSScott Long 2690914da7d0SScott Long /* 269136e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 269236e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 269336e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 269436e0bf6eSScott Long */ 269536e0bf6eSScott Long static int 269636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 269736e0bf6eSScott Long { 269836e0bf6eSScott Long struct aac_query_disk query_disk; 269936e0bf6eSScott Long struct aac_container *co; 2700914da7d0SScott Long struct aac_disk *disk; 270136e0bf6eSScott Long int error, id; 270236e0bf6eSScott Long 270336e0bf6eSScott Long debug_called(2); 270436e0bf6eSScott Long 2705914da7d0SScott Long disk = NULL; 2706914da7d0SScott Long 2707914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2708914da7d0SScott Long sizeof(struct aac_query_disk)); 270936e0bf6eSScott Long if (error) 271036e0bf6eSScott Long return (error); 271136e0bf6eSScott Long 271236e0bf6eSScott Long id = query_disk.ContainerNumber; 271336e0bf6eSScott Long if (id == -1) 271436e0bf6eSScott Long return (EINVAL); 271536e0bf6eSScott Long 2716c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 271736e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 271836e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 271936e0bf6eSScott Long break; 272036e0bf6eSScott Long } 272136e0bf6eSScott Long 272236e0bf6eSScott Long if (co == NULL) { 272336e0bf6eSScott Long query_disk.Valid = 0; 272436e0bf6eSScott Long query_disk.Locked = 0; 272536e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 272636e0bf6eSScott Long } else { 272736e0bf6eSScott Long disk = device_get_softc(co->co_disk); 272836e0bf6eSScott Long query_disk.Valid = 1; 2729914da7d0SScott Long query_disk.Locked = 2730914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 273136e0bf6eSScott Long query_disk.Deleted = 0; 2732b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 273336e0bf6eSScott Long query_disk.Target = disk->unit; 273436e0bf6eSScott Long query_disk.Lun = 0; 273536e0bf6eSScott Long query_disk.UnMapped = 0; 27367540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 27377540e65eSScott Long disk->ad_disk.d_name, disk->ad_disk.d_unit); 273836e0bf6eSScott Long } 273936e0bf6eSScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 274036e0bf6eSScott Long 2741914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2742914da7d0SScott Long sizeof(struct aac_query_disk)); 274336e0bf6eSScott Long 274436e0bf6eSScott Long return (error); 274536e0bf6eSScott Long } 274636e0bf6eSScott Long 2747fe3cb0e1SScott Long static void 2748fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2749fe3cb0e1SScott Long { 2750fe3cb0e1SScott Long struct aac_fib *fib; 2751fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2752fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2753fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2754fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2755fe3cb0e1SScott Long struct aac_getbusinf businfo; 275670545d1aSScott Long struct aac_sim *caminf; 2757fe3cb0e1SScott Long device_t child; 2758fe3cb0e1SScott Long int i, found, error; 2759fe3cb0e1SScott Long 2760fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2761fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 276239ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2763fe3cb0e1SScott Long 2764fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2765fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2766fe3cb0e1SScott Long c_cmd->param = 0; 2767fe3cb0e1SScott Long 2768fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2769fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2770fe3cb0e1SScott Long if (error) { 2771fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2772fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2773fe3cb0e1SScott Long aac_release_sync_fib(sc); 2774fe3cb0e1SScott Long return; 2775fe3cb0e1SScott Long } 2776fe3cb0e1SScott Long 2777fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2778fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2779fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2780fe3cb0e1SScott Long c_resp->Status); 2781fe3cb0e1SScott Long aac_release_sync_fib(sc); 2782fe3cb0e1SScott Long return; 2783fe3cb0e1SScott Long } 2784fe3cb0e1SScott Long 2785fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2786fe3cb0e1SScott Long 2787fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 278839ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 278939ee03c3SScott Long 2790fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2791fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2792fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2793fe3cb0e1SScott Long vmi->ObjId = 0; 2794fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2795fe3cb0e1SScott Long 2796fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2797fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2798fe3cb0e1SScott Long if (error) { 2799fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2800fe3cb0e1SScott Long error); 2801fe3cb0e1SScott Long aac_release_sync_fib(sc); 2802fe3cb0e1SScott Long return; 2803fe3cb0e1SScott Long } 2804fe3cb0e1SScott Long 2805fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2806fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2807fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2808fe3cb0e1SScott Long vmi_resp->Status); 2809fe3cb0e1SScott Long aac_release_sync_fib(sc); 2810fe3cb0e1SScott Long return; 2811fe3cb0e1SScott Long } 2812fe3cb0e1SScott Long 2813fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2814fe3cb0e1SScott Long aac_release_sync_fib(sc); 2815fe3cb0e1SScott Long 2816fe3cb0e1SScott Long found = 0; 2817fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2818fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2819fe3cb0e1SScott Long continue; 2820fe3cb0e1SScott Long 2821a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2822a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 2823fe3cb0e1SScott Long if (caminf == NULL) 2824fe3cb0e1SScott Long continue; 2825fe3cb0e1SScott Long 2826fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2827fe3cb0e1SScott Long if (child == NULL) { 2828fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2829fe3cb0e1SScott Long continue; 2830fe3cb0e1SScott Long } 2831fe3cb0e1SScott Long 2832fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2833fe3cb0e1SScott Long caminf->BusNumber = i; 2834fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2835fe3cb0e1SScott Long caminf->aac_sc = sc; 2836ddb8683eSScott Long caminf->sim_dev = child; 2837fe3cb0e1SScott Long 2838fe3cb0e1SScott Long device_set_ivars(child, caminf); 2839fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 284070545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2841fe3cb0e1SScott Long 2842fe3cb0e1SScott Long found = 1; 2843fe3cb0e1SScott Long } 2844fe3cb0e1SScott Long 2845fe3cb0e1SScott Long if (found) 2846fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2847fe3cb0e1SScott Long 2848fe3cb0e1SScott Long return; 2849fe3cb0e1SScott Long } 2850