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> 72fe3cb0e1SScott Long #include <dev/aac/aac_cam.h> 7335863739SMike Smith 7435863739SMike Smith static void aac_startup(void *arg); 75914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 76cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 77fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 7835863739SMike Smith 7935863739SMike Smith /* Command Processing */ 800b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 8135863739SMike Smith static int aac_start(struct aac_command *cm); 8235863739SMike Smith static void aac_complete(void *context, int pending); 8335863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8435863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 8535863739SMike Smith static int aac_wait_command(struct aac_command *cm, int timeout); 8635863739SMike Smith static void aac_host_command(struct aac_softc *sc); 8735863739SMike Smith static void aac_host_response(struct aac_softc *sc); 8835863739SMike Smith 8935863739SMike Smith /* Command Buffer Management */ 90c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 91c6eafcf2SScott Long int nseg, int error); 920b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 930b94a66eSMike Smith static void aac_free_commands(struct aac_softc *sc); 9435863739SMike Smith static void aac_map_command(struct aac_command *cm); 9535863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9635863739SMike Smith 9735863739SMike Smith /* Hardware Interface */ 98c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 99c6eafcf2SScott Long int error); 100fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 10135863739SMike Smith static int aac_init(struct aac_softc *sc); 10235863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 103c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 104c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 105c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 106f6c4dd3fSScott Long struct aac_command *cm); 107c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 108914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10936e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 11036e0bf6eSScott Long struct aac_fib *fib); 11135863739SMike Smith 112b3457b51SScott Long /* Falcon/PPC interface */ 113b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 114b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 115b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 116b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 117b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 118b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 119b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 120b3457b51SScott Long static int aac_fa_get_mailboxstatus(struct aac_softc *sc); 121b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 122b3457b51SScott Long 123b3457b51SScott Long struct aac_interface aac_fa_interface = { 124b3457b51SScott Long aac_fa_get_fwstatus, 125b3457b51SScott Long aac_fa_qnotify, 126b3457b51SScott Long aac_fa_get_istatus, 127b3457b51SScott Long aac_fa_clear_istatus, 128b3457b51SScott Long aac_fa_set_mailbox, 129b3457b51SScott Long aac_fa_get_mailboxstatus, 130b3457b51SScott Long aac_fa_set_interrupts 131b3457b51SScott Long }; 132b3457b51SScott Long 13335863739SMike Smith /* StrongARM interface */ 13435863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13535863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13635863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13735863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13835863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 139c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 140c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 14135863739SMike Smith static int aac_sa_get_mailboxstatus(struct aac_softc *sc); 14235863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 14335863739SMike Smith 14435863739SMike Smith struct aac_interface aac_sa_interface = { 14535863739SMike Smith aac_sa_get_fwstatus, 14635863739SMike Smith aac_sa_qnotify, 14735863739SMike Smith aac_sa_get_istatus, 14835863739SMike Smith aac_sa_clear_istatus, 14935863739SMike Smith aac_sa_set_mailbox, 15035863739SMike Smith aac_sa_get_mailboxstatus, 15135863739SMike Smith aac_sa_set_interrupts 15235863739SMike Smith }; 15335863739SMike Smith 15435863739SMike Smith /* i960Rx interface */ 15535863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15635863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15735863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15835863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15935863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 160c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 161c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 16235863739SMike Smith static int aac_rx_get_mailboxstatus(struct aac_softc *sc); 16335863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 16435863739SMike Smith 16535863739SMike Smith struct aac_interface aac_rx_interface = { 16635863739SMike Smith aac_rx_get_fwstatus, 16735863739SMike Smith aac_rx_qnotify, 16835863739SMike Smith aac_rx_get_istatus, 16935863739SMike Smith aac_rx_clear_istatus, 17035863739SMike Smith aac_rx_set_mailbox, 17135863739SMike Smith aac_rx_get_mailboxstatus, 17235863739SMike Smith aac_rx_set_interrupts 17335863739SMike Smith }; 17435863739SMike Smith 17535863739SMike Smith /* Debugging and Diagnostics */ 17635863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1776965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 178c6eafcf2SScott Long u_int32_t code); 17935863739SMike Smith 18035863739SMike Smith /* Management Interface */ 18135863739SMike Smith static d_open_t aac_open; 18235863739SMike Smith static d_close_t aac_close; 18335863739SMike Smith static d_ioctl_t aac_ioctl; 184b3457b51SScott Long static d_poll_t aac_poll; 185c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 186c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 18736e0bf6eSScott Long struct aac_fib *fib); 188fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 189fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 190fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 19136e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 19235863739SMike Smith 19335863739SMike Smith #define AAC_CDEV_MAJOR 150 19435863739SMike Smith 19535863739SMike Smith static struct cdevsw aac_cdevsw = { 19635863739SMike Smith aac_open, /* open */ 19735863739SMike Smith aac_close, /* close */ 19835863739SMike Smith noread, /* read */ 19935863739SMike Smith nowrite, /* write */ 20035863739SMike Smith aac_ioctl, /* ioctl */ 201b3457b51SScott Long aac_poll, /* poll */ 20235863739SMike Smith nommap, /* mmap */ 20335863739SMike Smith nostrategy, /* strategy */ 20435863739SMike Smith "aac", /* name */ 20535863739SMike Smith AAC_CDEV_MAJOR, /* major */ 20635863739SMike Smith nodump, /* dump */ 20735863739SMike Smith nopsize, /* psize */ 20835863739SMike Smith 0, /* flags */ 20936e0bf6eSScott Long #if __FreeBSD_version < 500005 21036e0bf6eSScott Long -1, /* bmaj */ 21136e0bf6eSScott Long #endif 21235863739SMike Smith }; 21335863739SMike Smith 21436e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 21536e0bf6eSScott Long 2163d04a9d7SScott Long /* sysctl node */ 2173d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2183d04a9d7SScott Long 219914da7d0SScott Long /* 220914da7d0SScott Long * Device Interface 221914da7d0SScott Long */ 22235863739SMike Smith 223914da7d0SScott Long /* 22435863739SMike Smith * Initialise the controller and softc 22535863739SMike Smith */ 22635863739SMike Smith int 22735863739SMike Smith aac_attach(struct aac_softc *sc) 22835863739SMike Smith { 22935863739SMike Smith int error, unit; 23035863739SMike Smith 23135863739SMike Smith debug_called(1); 23235863739SMike Smith 23335863739SMike Smith /* 23435863739SMike Smith * Initialise per-controller queues. 23535863739SMike Smith */ 2360b94a66eSMike Smith aac_initq_free(sc); 2370b94a66eSMike Smith aac_initq_ready(sc); 2380b94a66eSMike Smith aac_initq_busy(sc); 2390b94a66eSMike Smith aac_initq_complete(sc); 2400b94a66eSMike Smith aac_initq_bio(sc); 24135863739SMike Smith 24235863739SMike Smith #if __FreeBSD_version >= 500005 24335863739SMike Smith /* 24435863739SMike Smith * Initialise command-completion task. 24535863739SMike Smith */ 24635863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 24735863739SMike Smith #endif 24835863739SMike Smith 24935863739SMike Smith /* disable interrupts before we enable anything */ 25035863739SMike Smith AAC_MASK_INTERRUPTS(sc); 25135863739SMike Smith 25235863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25335863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25435863739SMike Smith 25535863739SMike Smith /* 256fe94b852SScott Long * Check that the firmware on the card is supported. 257fe94b852SScott Long */ 258fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 259fe94b852SScott Long return(error); 260fe94b852SScott Long 261fe94b852SScott Long /* 2620b94a66eSMike Smith * Allocate command structures. 2630b94a66eSMike Smith */ 2640b94a66eSMike Smith if ((error = aac_alloc_commands(sc)) != 0) 2650b94a66eSMike Smith return(error); 2660b94a66eSMike Smith 267cbfd045bSScott Long /* Init the sync fib lock */ 268cbfd045bSScott Long AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 269cbfd045bSScott Long 2700b94a66eSMike Smith /* 27135863739SMike Smith * Initialise the adapter. 27235863739SMike Smith */ 2730b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 27435863739SMike Smith return(error); 27535863739SMike Smith 27635863739SMike Smith /* 27735863739SMike Smith * Print a little information about the controller. 27835863739SMike Smith */ 27935863739SMike Smith aac_describe_controller(sc); 28035863739SMike Smith 28135863739SMike Smith /* 28235863739SMike Smith * Register to probe our containers later. 28335863739SMike Smith */ 28436e0bf6eSScott Long TAILQ_INIT(&sc->aac_container_tqh); 285b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 286b3457b51SScott Long 287b3457b51SScott Long /* 288b3457b51SScott Long * Lock for the AIF queue 289b3457b51SScott Long */ 290b3457b51SScott Long AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 29136e0bf6eSScott Long 29235863739SMike Smith sc->aac_ich.ich_func = aac_startup; 29335863739SMike Smith sc->aac_ich.ich_arg = sc; 29435863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 295914da7d0SScott Long device_printf(sc->aac_dev, 296914da7d0SScott Long "can't establish configuration hook\n"); 29735863739SMike Smith return(ENXIO); 29835863739SMike Smith } 29935863739SMike Smith 30035863739SMike Smith /* 30135863739SMike Smith * Make the control device. 30235863739SMike Smith */ 30335863739SMike Smith unit = device_get_unit(sc->aac_dev); 3049e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3059e9466baSRobert Watson 0640, "aac%d", unit); 30636e0bf6eSScott Long #if __FreeBSD_version > 500005 307157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3084aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 30936e0bf6eSScott Long #endif 31035863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 31135863739SMike Smith 31236e0bf6eSScott Long /* Create the AIF thread */ 31336e0bf6eSScott Long #if __FreeBSD_version > 500005 314914da7d0SScott Long if (kthread_create((void(*)(void *))aac_host_command, sc, 315316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 31636e0bf6eSScott Long #else 317914da7d0SScott Long if (kthread_create((void(*)(void *))aac_host_command, sc, 318914da7d0SScott Long &sc->aifthread, "aac%daif", unit)) 31936e0bf6eSScott Long #endif 32036e0bf6eSScott Long panic("Could not create AIF thread\n"); 32136e0bf6eSScott Long 32236e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 32336e0bf6eSScott Long if ((EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, sc->aac_dev, 32436e0bf6eSScott Long SHUTDOWN_PRI_DEFAULT)) == NULL) 32536e0bf6eSScott Long device_printf(sc->aac_dev, "shutdown event registration failed\n"); 32636e0bf6eSScott Long 327fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 328fe3cb0e1SScott Long if (!(sc->quirks & AAC_QUIRK_NOCAM)) 329fe3cb0e1SScott Long aac_get_bus_info(sc); 330fe3cb0e1SScott Long 33135863739SMike Smith return(0); 33235863739SMike Smith } 33335863739SMike Smith 334914da7d0SScott Long /* 33535863739SMike Smith * Probe for containers, create disks. 33635863739SMike Smith */ 33735863739SMike Smith static void 33835863739SMike Smith aac_startup(void *arg) 33935863739SMike Smith { 340914da7d0SScott Long struct aac_softc *sc; 341cbfd045bSScott Long struct aac_fib *fib; 342cbfd045bSScott Long struct aac_mntinfo *mi; 343cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 34436e0bf6eSScott Long int i = 0; 34535863739SMike Smith 34635863739SMike Smith debug_called(1); 34735863739SMike Smith 348914da7d0SScott Long sc = (struct aac_softc *)arg; 349914da7d0SScott Long 35035863739SMike Smith /* disconnect ourselves from the intrhook chain */ 35135863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 35235863739SMike Smith 353fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 354cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 355cbfd045bSScott Long 35635863739SMike Smith /* loop over possible containers */ 35736e0bf6eSScott Long do { 35835863739SMike Smith /* request information on this container */ 35939ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 36039ee03c3SScott Long mi->Command = VM_NameServe; 36139ee03c3SScott Long mi->MntType = FT_FILESYS; 362cbfd045bSScott Long mi->MntCount = i; 363cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 364cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 36535863739SMike Smith debug(2, "error probing container %d", i); 36635863739SMike Smith continue; 36735863739SMike Smith } 36835863739SMike Smith 369cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 370cbfd045bSScott Long aac_add_container(sc, mir, 0); 37136e0bf6eSScott Long i++; 372cbfd045bSScott Long } while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS)); 373cbfd045bSScott Long 374cbfd045bSScott Long aac_release_sync_fib(sc); 37535863739SMike Smith 37635863739SMike Smith /* poke the bus to actually attach the child devices */ 37735863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 37835863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 37935863739SMike Smith 38035863739SMike Smith /* mark the controller up */ 38135863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 38235863739SMike Smith 38335863739SMike Smith /* enable interrupts now */ 38435863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 3850b94a66eSMike Smith 3860b94a66eSMike Smith /* enable the timeout watchdog */ 3870b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 38835863739SMike Smith } 38935863739SMike Smith 390914da7d0SScott Long /* 391914da7d0SScott Long * Create a device to respresent a new container 392914da7d0SScott Long */ 393914da7d0SScott Long static void 394cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 395914da7d0SScott Long { 396914da7d0SScott Long struct aac_container *co; 397914da7d0SScott Long device_t child; 398914da7d0SScott Long 399914da7d0SScott Long /* 400914da7d0SScott Long * Check container volume type for validity. Note that many of 401914da7d0SScott Long * the possible types may never show up. 402914da7d0SScott Long */ 403914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 404914da7d0SScott Long MALLOC(co, struct aac_container *, sizeof *co, M_AACBUF, 405914da7d0SScott Long M_NOWAIT); 406914da7d0SScott Long if (co == NULL) 407914da7d0SScott Long panic("Out of memory?!\n"); 408914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 409914da7d0SScott Long mir->MntTable[0].ObjectId, 410914da7d0SScott Long mir->MntTable[0].FileSystemName, 411914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 412914da7d0SScott Long 413fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 414914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 415914da7d0SScott Long else 416914da7d0SScott Long device_set_ivars(child, co); 417914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 418914da7d0SScott Long mir->MntTable[0].VolType)); 419914da7d0SScott Long co->co_disk = child; 420914da7d0SScott Long co->co_found = f; 421914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 422914da7d0SScott Long sizeof(struct aac_mntobj)); 423c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 424914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 425914da7d0SScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 426914da7d0SScott Long } 427914da7d0SScott Long } 428914da7d0SScott Long 429914da7d0SScott Long /* 43035863739SMike Smith * Free all of the resources associated with (sc) 43135863739SMike Smith * 43235863739SMike Smith * Should not be called if the controller is active. 43335863739SMike Smith */ 43435863739SMike Smith void 43535863739SMike Smith aac_free(struct aac_softc *sc) 43635863739SMike Smith { 43735863739SMike Smith debug_called(1); 43835863739SMike Smith 43935863739SMike Smith /* remove the control device */ 44035863739SMike Smith if (sc->aac_dev_t != NULL) 44135863739SMike Smith destroy_dev(sc->aac_dev_t); 44235863739SMike Smith 4430b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 4440b94a66eSMike Smith if (sc->aac_fibs != NULL) 4450b94a66eSMike Smith aac_free_commands(sc); 4460b94a66eSMike Smith if (sc->aac_fib_dmat) 4470b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 44835863739SMike Smith 44935863739SMike Smith /* destroy the common area */ 45035863739SMike Smith if (sc->aac_common) { 45135863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 452c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 453c6eafcf2SScott Long sc->aac_common_dmamap); 45435863739SMike Smith } 4550b94a66eSMike Smith if (sc->aac_common_dmat) 4560b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 45735863739SMike Smith 45835863739SMike Smith /* disconnect the interrupt handler */ 45935863739SMike Smith if (sc->aac_intr) 46035863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 46135863739SMike Smith if (sc->aac_irq != NULL) 462c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 463c6eafcf2SScott Long sc->aac_irq); 46435863739SMike Smith 46535863739SMike Smith /* destroy data-transfer DMA tag */ 46635863739SMike Smith if (sc->aac_buffer_dmat) 46735863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 46835863739SMike Smith 46935863739SMike Smith /* destroy the parent DMA tag */ 47035863739SMike Smith if (sc->aac_parent_dmat) 47135863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 47235863739SMike Smith 47335863739SMike Smith /* release the register window mapping */ 47435863739SMike Smith if (sc->aac_regs_resource != NULL) 475914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 476914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 47735863739SMike Smith } 47835863739SMike Smith 479914da7d0SScott Long /* 48035863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 48135863739SMike Smith */ 48235863739SMike Smith int 48335863739SMike Smith aac_detach(device_t dev) 48435863739SMike Smith { 485914da7d0SScott Long struct aac_softc *sc; 48636e0bf6eSScott Long #if AAC_BROKEN 48735863739SMike Smith int error; 48836e0bf6eSScott Long #endif 48935863739SMike Smith 49035863739SMike Smith debug_called(1); 49135863739SMike Smith 492914da7d0SScott Long sc = device_get_softc(dev); 493914da7d0SScott Long 49435863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 49535863739SMike Smith return(EBUSY); 49635863739SMike Smith 49736e0bf6eSScott Long #if AAC_BROKEN 49836e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 49936e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 50036e0bf6eSScott Long wakeup(sc->aifthread); 50136e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 50236e0bf6eSScott Long } 50336e0bf6eSScott Long 50436e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 50536e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 50636e0bf6eSScott Long 50735863739SMike Smith if ((error = aac_shutdown(dev))) 50835863739SMike Smith return(error); 50935863739SMike Smith 51035863739SMike Smith aac_free(sc); 51135863739SMike Smith 51235863739SMike Smith return(0); 51336e0bf6eSScott Long #else 51436e0bf6eSScott Long return (EBUSY); 51536e0bf6eSScott Long #endif 51635863739SMike Smith } 51735863739SMike Smith 518914da7d0SScott Long /* 51935863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 52035863739SMike Smith * 52135863739SMike Smith * This function is called before detach or system shutdown. 52235863739SMike Smith * 5230b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 52435863739SMike Smith * allow shutdown if any device is open. 52535863739SMike Smith */ 52635863739SMike Smith int 52735863739SMike Smith aac_shutdown(device_t dev) 52835863739SMike Smith { 529914da7d0SScott Long struct aac_softc *sc; 530cbfd045bSScott Long struct aac_fib *fib; 531cbfd045bSScott Long struct aac_close_command *cc; 532cbfd045bSScott Long int s; 53335863739SMike Smith 53435863739SMike Smith debug_called(1); 53535863739SMike Smith 536914da7d0SScott Long sc = device_get_softc(dev); 537914da7d0SScott Long 53835863739SMike Smith s = splbio(); 53935863739SMike Smith 54035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 54135863739SMike Smith 54235863739SMike Smith /* 54335863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 54435863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 54535863739SMike Smith * We've been closed and all I/O completed already 54635863739SMike Smith */ 54735863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 54835863739SMike Smith 549fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 550cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 551cbfd045bSScott Long 55239ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 553cbfd045bSScott Long cc->Command = VM_CloseAll; 554cbfd045bSScott Long cc->ContainerId = 0xffffffff; 555cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 556cbfd045bSScott Long sizeof(struct aac_close_command))) 55735863739SMike Smith printf("FAILED.\n"); 558914da7d0SScott Long else { 559cbfd045bSScott Long fib->data[0] = 0; 56036e0bf6eSScott Long /* 561914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 56236e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 56336e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 56436e0bf6eSScott Long * driver module with the intent to reload it later. 56536e0bf6eSScott Long */ 566cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 567cbfd045bSScott Long fib, 1)) { 56835863739SMike Smith printf("FAILED.\n"); 56935863739SMike Smith } else { 57035863739SMike Smith printf("done.\n"); 57135863739SMike Smith } 57235863739SMike Smith } 57335863739SMike Smith 57435863739SMike Smith AAC_MASK_INTERRUPTS(sc); 57535863739SMike Smith 57635863739SMike Smith splx(s); 57735863739SMike Smith return(0); 57835863739SMike Smith } 57935863739SMike Smith 580914da7d0SScott Long /* 58135863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 58235863739SMike Smith */ 58335863739SMike Smith int 58435863739SMike Smith aac_suspend(device_t dev) 58535863739SMike Smith { 586914da7d0SScott Long struct aac_softc *sc; 58735863739SMike Smith int s; 58835863739SMike Smith 58935863739SMike Smith debug_called(1); 590914da7d0SScott Long 591914da7d0SScott Long sc = device_get_softc(dev); 592914da7d0SScott Long 59335863739SMike Smith s = splbio(); 59435863739SMike Smith 59535863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 59635863739SMike Smith 59735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 59835863739SMike Smith splx(s); 59935863739SMike Smith return(0); 60035863739SMike Smith } 60135863739SMike Smith 602914da7d0SScott Long /* 60335863739SMike Smith * Bring the controller back to a state ready for operation. 60435863739SMike Smith */ 60535863739SMike Smith int 60635863739SMike Smith aac_resume(device_t dev) 60735863739SMike Smith { 608914da7d0SScott Long struct aac_softc *sc; 60935863739SMike Smith 61035863739SMike Smith debug_called(1); 611914da7d0SScott Long 612914da7d0SScott Long sc = device_get_softc(dev); 613914da7d0SScott Long 61435863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 61535863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 61635863739SMike Smith return(0); 61735863739SMike Smith } 61835863739SMike Smith 619914da7d0SScott Long /* 62035863739SMike Smith * Take an interrupt. 62135863739SMike Smith */ 62235863739SMike Smith void 62335863739SMike Smith aac_intr(void *arg) 62435863739SMike Smith { 625914da7d0SScott Long struct aac_softc *sc; 62635863739SMike Smith u_int16_t reason; 627f30ac74cSScott Long u_int32_t *resp_queue; 62835863739SMike Smith 62935863739SMike Smith debug_called(2); 63035863739SMike Smith 631914da7d0SScott Long sc = (struct aac_softc *)arg; 632914da7d0SScott Long 633f30ac74cSScott Long /* 634f30ac74cSScott Long * Optimize the common case of adapter response interrupts. 635f30ac74cSScott Long * We must read from the card prior to processing the responses 636f30ac74cSScott Long * to ensure the clear is flushed prior to accessing the queues. 637f30ac74cSScott Long * Reading the queues from local memory might save us a PCI read. 638f30ac74cSScott Long */ 639f30ac74cSScott Long resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; 640f30ac74cSScott Long if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) 641f30ac74cSScott Long reason = AAC_DB_RESPONSE_READY; 642f30ac74cSScott Long else 64335863739SMike Smith reason = AAC_GET_ISTATUS(sc); 644f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 645f30ac74cSScott Long (void)AAC_GET_ISTATUS(sc); 646f30ac74cSScott Long 647f30ac74cSScott Long /* It's not ok to return here because of races with the previous step */ 648f30ac74cSScott Long if (reason & AAC_DB_RESPONSE_READY) 649f30ac74cSScott Long aac_host_response(sc); 65035863739SMike Smith 651b3457b51SScott Long /* controller wants to talk to the log */ 652f30ac74cSScott Long if (reason & AAC_DB_PRINTF) 65336e0bf6eSScott Long aac_print_printf(sc); 65435863739SMike Smith 65535863739SMike Smith /* controller has a message for us? */ 65635863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 65736e0bf6eSScott Long /* XXX What happens if the thread is already awake? */ 65836e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 65936e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_PENDING; 66036e0bf6eSScott Long wakeup(sc->aifthread); 66136e0bf6eSScott Long } 66235863739SMike Smith } 66335863739SMike Smith } 66435863739SMike Smith 665c6eafcf2SScott Long /* 666914da7d0SScott Long * Command Processing 667914da7d0SScott Long */ 66835863739SMike Smith 669914da7d0SScott Long /* 67035863739SMike Smith * Start as much queued I/O as possible on the controller 67135863739SMike Smith */ 672fe3cb0e1SScott Long void 67335863739SMike Smith aac_startio(struct aac_softc *sc) 67435863739SMike Smith { 67535863739SMike Smith struct aac_command *cm; 67635863739SMike Smith 67735863739SMike Smith debug_called(2); 67835863739SMike Smith 67935863739SMike Smith for (;;) { 680914da7d0SScott Long /* 681914da7d0SScott Long * Try to get a command that's been put off for lack of 682914da7d0SScott Long * resources 683914da7d0SScott Long */ 68435863739SMike Smith cm = aac_dequeue_ready(sc); 68535863739SMike Smith 686914da7d0SScott Long /* 687914da7d0SScott Long * Try to build a command off the bio queue (ignore error 688914da7d0SScott Long * return) 689914da7d0SScott Long */ 6900b94a66eSMike Smith if (cm == NULL) 69135863739SMike Smith aac_bio_command(sc, &cm); 69235863739SMike Smith 69335863739SMike Smith /* nothing to do? */ 69435863739SMike Smith if (cm == NULL) 69535863739SMike Smith break; 69635863739SMike Smith 69735863739SMike Smith /* try to give the command to the controller */ 69835863739SMike Smith if (aac_start(cm) == EBUSY) { 69935863739SMike Smith /* put it on the ready queue for later */ 70035863739SMike Smith aac_requeue_ready(cm); 70135863739SMike Smith break; 70235863739SMike Smith } 70335863739SMike Smith } 70435863739SMike Smith } 70535863739SMike Smith 706914da7d0SScott Long /* 70735863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 70835863739SMike Smith * last moment when possible. 70935863739SMike Smith */ 71035863739SMike Smith static int 71135863739SMike Smith aac_start(struct aac_command *cm) 71235863739SMike Smith { 713914da7d0SScott Long struct aac_softc *sc; 714ed5c5fb4SMike Smith int error; 71535863739SMike Smith 71635863739SMike Smith debug_called(2); 71735863739SMike Smith 718914da7d0SScott Long sc = cm->cm_sc; 719914da7d0SScott Long 72035863739SMike Smith /* get the command mapped */ 72135863739SMike Smith aac_map_command(cm); 72235863739SMike Smith 7230b94a66eSMike Smith /* fix up the address values in the FIB */ 72435863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 72535863739SMike Smith cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 72635863739SMike Smith 72735863739SMike Smith /* save a pointer to the command for speedy reverse-lookup */ 728c6eafcf2SScott Long cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical 729c6eafcf2SScott Long * address issue */ 73035863739SMike Smith /* put the FIB on the outbound queue */ 73136e0bf6eSScott Long error = aac_enqueue_fib(sc, cm->cm_queue, cm); 7320b94a66eSMike Smith return(error); 73335863739SMike Smith } 73435863739SMike Smith 735914da7d0SScott Long /* 73635863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 73735863739SMike Smith */ 73835863739SMike Smith static void 73935863739SMike Smith aac_host_command(struct aac_softc *sc) 74035863739SMike Smith { 74135863739SMike Smith struct aac_fib *fib; 74235863739SMike Smith u_int32_t fib_size; 74336e0bf6eSScott Long int size; 74435863739SMike Smith 74536e0bf6eSScott Long debug_called(2); 74635863739SMike Smith 74736e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_RUNNING; 74836e0bf6eSScott Long 74936e0bf6eSScott Long while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 75036e0bf6eSScott Long if (!(sc->aifflags & AAC_AIFFLAGS_PENDING)) 75136e0bf6eSScott Long tsleep(sc->aifthread, PRIBIO, "aifthd", 15 * hz); 75236e0bf6eSScott Long 75336e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_PENDING; 75435863739SMike Smith for (;;) { 755914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 756914da7d0SScott Long &fib_size, &fib)) 75735863739SMike Smith break; /* nothing to do */ 75835863739SMike Smith 75936e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 76036e0bf6eSScott Long 76135863739SMike Smith switch (fib->Header.Command) { 76235863739SMike Smith case AifRequest: 76336e0bf6eSScott Long aac_handle_aif(sc, fib); 76435863739SMike Smith break; 76535863739SMike Smith default: 766914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 767914da7d0SScott Long "from controller\n"); 76835863739SMike Smith break; 76935863739SMike Smith } 77035863739SMike Smith 77136e0bf6eSScott Long /* Return the AIF to the controller. */ 77236e0bf6eSScott Long if ((fib->Header.XferState == 0) || 77336e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 77436e0bf6eSScott Long break; 77536e0bf6eSScott Long 77636e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 77736e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 77836e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 77936e0bf6eSScott Long 78036e0bf6eSScott Long /* XXX Compute the Size field? */ 78136e0bf6eSScott Long size = fib->Header.Size; 78236e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 78336e0bf6eSScott Long size = sizeof(struct aac_fib); 78436e0bf6eSScott Long fib->Header.Size = size; 78536e0bf6eSScott Long } 78636e0bf6eSScott Long /* 787914da7d0SScott Long * Since we did not generate this command, it 788914da7d0SScott Long * cannot go through the normal 789914da7d0SScott Long * enqueue->startio chain. 79036e0bf6eSScott Long */ 791914da7d0SScott Long aac_enqueue_response(sc, 792914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 793914da7d0SScott Long fib); 79436e0bf6eSScott Long } 79536e0bf6eSScott Long } 79636e0bf6eSScott Long } 79736e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 79836e0bf6eSScott Long wakeup(sc->aac_dev); 79936e0bf6eSScott Long 80036e0bf6eSScott Long #if __FreeBSD_version > 500005 80136e0bf6eSScott Long mtx_lock(&Giant); 80236e0bf6eSScott Long #endif 80336e0bf6eSScott Long kthread_exit(0); 80435863739SMike Smith } 80535863739SMike Smith 806914da7d0SScott Long /* 80735863739SMike Smith * Handle notification of one or more FIBs completed by the controller 80835863739SMike Smith */ 80935863739SMike Smith static void 81035863739SMike Smith aac_host_response(struct aac_softc *sc) 81135863739SMike Smith { 81235863739SMike Smith struct aac_command *cm; 81335863739SMike Smith struct aac_fib *fib; 81435863739SMike Smith u_int32_t fib_size; 81535863739SMike Smith 81635863739SMike Smith debug_called(2); 81735863739SMike Smith 81835863739SMike Smith for (;;) { 81935863739SMike Smith /* look for completed FIBs on our queue */ 820914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 821914da7d0SScott Long &fib)) 82235863739SMike Smith break; /* nothing to do */ 82335863739SMike Smith 82435863739SMike Smith /* get the command, unmap and queue for later processing */ 82535863739SMike Smith cm = (struct aac_command *)fib->Header.SenderData; 82635863739SMike Smith if (cm == NULL) { 82735863739SMike Smith AAC_PRINT_FIB(sc, fib); 82835863739SMike Smith } else { 8290b94a66eSMike Smith aac_remove_busy(cm); 83035863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 8310b94a66eSMike Smith aac_enqueue_complete(cm); 83235863739SMike Smith } 83335863739SMike Smith } 83435863739SMike Smith 83535863739SMike Smith /* handle completion processing */ 83635863739SMike Smith #if __FreeBSD_version >= 500005 83735863739SMike Smith taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 83835863739SMike Smith #else 83935863739SMike Smith aac_complete(sc, 0); 84035863739SMike Smith #endif 84135863739SMike Smith } 84235863739SMike Smith 843914da7d0SScott Long /* 84435863739SMike Smith * Process completed commands. 84535863739SMike Smith */ 84635863739SMike Smith static void 84735863739SMike Smith aac_complete(void *context, int pending) 84835863739SMike Smith { 849914da7d0SScott Long struct aac_softc *sc; 85035863739SMike Smith struct aac_command *cm; 85135863739SMike Smith 85235863739SMike Smith debug_called(2); 85335863739SMike Smith 854914da7d0SScott Long sc = (struct aac_softc *)context; 855914da7d0SScott Long 85635863739SMike Smith /* pull completed commands off the queue */ 85735863739SMike Smith for (;;) { 8580b94a66eSMike Smith cm = aac_dequeue_complete(sc); 85935863739SMike Smith if (cm == NULL) 8600b94a66eSMike Smith break; 86135863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 86235863739SMike Smith 86335863739SMike Smith /* is there a completion handler? */ 86435863739SMike Smith if (cm->cm_complete != NULL) { 86535863739SMike Smith cm->cm_complete(cm); 86635863739SMike Smith } else { 86735863739SMike Smith /* assume that someone is sleeping on this command */ 86835863739SMike Smith wakeup(cm); 86935863739SMike Smith } 87035863739SMike Smith } 8710b94a66eSMike Smith 8720b94a66eSMike Smith /* see if we can start some more I/O */ 8730b94a66eSMike Smith aac_startio(sc); 87435863739SMike Smith } 87535863739SMike Smith 876914da7d0SScott Long /* 87735863739SMike Smith * Handle a bio submitted from a disk device. 87835863739SMike Smith */ 87935863739SMike Smith void 88035863739SMike Smith aac_submit_bio(struct bio *bp) 88135863739SMike Smith { 882914da7d0SScott Long struct aac_disk *ad; 883914da7d0SScott Long struct aac_softc *sc; 88435863739SMike Smith 88535863739SMike Smith debug_called(2); 88635863739SMike Smith 887914da7d0SScott Long ad = (struct aac_disk *)bp->bio_dev->si_drv1; 888914da7d0SScott Long sc = ad->ad_controller; 889914da7d0SScott Long 89035863739SMike Smith /* queue the BIO and try to get some work done */ 8910b94a66eSMike Smith aac_enqueue_bio(sc, bp); 89235863739SMike Smith aac_startio(sc); 89335863739SMike Smith } 89435863739SMike Smith 895914da7d0SScott Long /* 89635863739SMike Smith * Get a bio and build a command to go with it. 89735863739SMike Smith */ 89835863739SMike Smith static int 89935863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 90035863739SMike Smith { 90135863739SMike Smith struct aac_command *cm; 90235863739SMike Smith struct aac_fib *fib; 90335863739SMike Smith struct aac_blockread *br; 90435863739SMike Smith struct aac_blockwrite *bw; 90535863739SMike Smith struct aac_disk *ad; 90635863739SMike Smith struct bio *bp; 90735863739SMike Smith 90835863739SMike Smith debug_called(2); 90935863739SMike Smith 91035863739SMike Smith /* get the resources we will need */ 91135863739SMike Smith cm = NULL; 9120b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 91335863739SMike Smith goto fail; 91435863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 91535863739SMike Smith goto fail; 91635863739SMike Smith 91735863739SMike Smith /* fill out the command */ 9180b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9190b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9200b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 92135863739SMike Smith cm->cm_private = bp; 9220b94a66eSMike Smith cm->cm_timestamp = time_second; 92336e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 92435863739SMike Smith 92535863739SMike Smith /* build the FIB */ 92635863739SMike Smith fib = cm->cm_fib; 92735863739SMike Smith fib->Header.XferState = 92835863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 92935863739SMike Smith AAC_FIBSTATE_INITIALISED | 930f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 93135863739SMike Smith AAC_FIBSTATE_FROMHOST | 93235863739SMike Smith AAC_FIBSTATE_REXPECTED | 933f30ac74cSScott Long AAC_FIBSTATE_NORM | 934f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 935f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 93635863739SMike Smith fib->Header.Command = ContainerCommand; 93735863739SMike Smith fib->Header.Size = sizeof(struct aac_fib_header); 93835863739SMike Smith 93935863739SMike Smith /* build the read/write request */ 94035863739SMike Smith ad = (struct aac_disk *)bp->bio_dev->si_drv1; 94135863739SMike Smith if (BIO_IS_READ(bp)) { 94235863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 94335863739SMike Smith br->Command = VM_CtBlockRead; 94435863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 94535863739SMike Smith br->BlockNumber = bp->bio_pblkno; 94635863739SMike Smith br->ByteCount = bp->bio_bcount; 94735863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 94835863739SMike Smith cm->cm_sgtable = &br->SgMap; 94935863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 95035863739SMike Smith } else { 95135863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 95235863739SMike Smith bw->Command = VM_CtBlockWrite; 95335863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 95435863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 95535863739SMike Smith bw->ByteCount = bp->bio_bcount; 95635863739SMike Smith bw->Stable = CUNSTABLE; /* XXX what's appropriate here? */ 95735863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 95835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 95935863739SMike Smith cm->cm_sgtable = &bw->SgMap; 96035863739SMike Smith } 96135863739SMike Smith 96235863739SMike Smith *cmp = cm; 96335863739SMike Smith return(0); 96435863739SMike Smith 96535863739SMike Smith fail: 96635863739SMike Smith if (bp != NULL) 9670b94a66eSMike Smith aac_enqueue_bio(sc, bp); 96835863739SMike Smith if (cm != NULL) 96935863739SMike Smith aac_release_command(cm); 97035863739SMike Smith return(ENOMEM); 97135863739SMike Smith } 97235863739SMike Smith 973914da7d0SScott Long /* 97435863739SMike Smith * Handle a bio-instigated command that has been completed. 97535863739SMike Smith */ 97635863739SMike Smith static void 97735863739SMike Smith aac_bio_complete(struct aac_command *cm) 97835863739SMike Smith { 97935863739SMike Smith struct aac_blockread_response *brr; 98035863739SMike Smith struct aac_blockwrite_response *bwr; 98135863739SMike Smith struct bio *bp; 98235863739SMike Smith AAC_FSAStatus status; 98335863739SMike Smith 98435863739SMike Smith /* fetch relevant status and then release the command */ 98535863739SMike Smith bp = (struct bio *)cm->cm_private; 98635863739SMike Smith if (BIO_IS_READ(bp)) { 98735863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 98835863739SMike Smith status = brr->Status; 98935863739SMike Smith } else { 99035863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 99135863739SMike Smith status = bwr->Status; 99235863739SMike Smith } 99335863739SMike Smith aac_release_command(cm); 99435863739SMike Smith 99535863739SMike Smith /* fix up the bio based on status */ 99635863739SMike Smith if (status == ST_OK) { 99735863739SMike Smith bp->bio_resid = 0; 99835863739SMike Smith } else { 99935863739SMike Smith bp->bio_error = EIO; 100035863739SMike Smith bp->bio_flags |= BIO_ERROR; 10010b94a66eSMike Smith /* pass an error string out to the disk layer */ 1002914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1003914da7d0SScott Long status); 100435863739SMike Smith } 10050b94a66eSMike Smith aac_biodone(bp); 100635863739SMike Smith } 100735863739SMike Smith 1008914da7d0SScott Long /* 100935863739SMike Smith * Submit a command to the controller, return when it completes. 1010b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1011b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1012b3457b51SScott Long * because there is a risk that a signal could wakeup the tsleep before 1013b3457b51SScott Long * the card has a chance to complete the command. The passed in timeout 1014b3457b51SScott Long * is ignored for the same reason. Since there is no way to cancel a 1015b3457b51SScott Long * command in progress, we should probably create a 'dead' queue where 1016b3457b51SScott Long * commands go that have been interrupted/timed-out/etc, that keeps them 1017b3457b51SScott Long * out of the free pool. That way, if the card is just slow, it won't 1018b3457b51SScott Long * spam the memory of a command that has been recycled. 101935863739SMike Smith */ 102035863739SMike Smith static int 102135863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 102235863739SMike Smith { 102335863739SMike Smith int s, error = 0; 102435863739SMike Smith 102535863739SMike Smith debug_called(2); 102635863739SMike Smith 102735863739SMike Smith /* Put the command on the ready queue and get things going */ 102836e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 102935863739SMike Smith aac_enqueue_ready(cm); 103035863739SMike Smith aac_startio(cm->cm_sc); 103135863739SMike Smith s = splbio(); 103235863739SMike Smith while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1033b3457b51SScott Long error = tsleep(cm, PRIBIO, "aacwait", 0); 103435863739SMike Smith } 103535863739SMike Smith splx(s); 103635863739SMike Smith return(error); 103735863739SMike Smith } 103835863739SMike Smith 1039914da7d0SScott Long /* 1040914da7d0SScott Long *Command Buffer Management 1041914da7d0SScott Long */ 104235863739SMike Smith 1043914da7d0SScott Long /* 104435863739SMike Smith * Allocate a command. 104535863739SMike Smith */ 1046fe3cb0e1SScott Long int 104735863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 104835863739SMike Smith { 104935863739SMike Smith struct aac_command *cm; 105035863739SMike Smith 105135863739SMike Smith debug_called(3); 105235863739SMike Smith 10530b94a66eSMike Smith if ((cm = aac_dequeue_free(sc)) == NULL) 105435863739SMike Smith return(ENOMEM); 105535863739SMike Smith 10560b94a66eSMike Smith *cmp = cm; 10570b94a66eSMike Smith return(0); 10580b94a66eSMike Smith } 10590b94a66eSMike Smith 1060914da7d0SScott Long /* 10610b94a66eSMike Smith * Release a command back to the freelist. 10620b94a66eSMike Smith */ 1063fe3cb0e1SScott Long void 10640b94a66eSMike Smith aac_release_command(struct aac_command *cm) 10650b94a66eSMike Smith { 10660b94a66eSMike Smith debug_called(3); 10670b94a66eSMike Smith 10680b94a66eSMike Smith /* (re)initialise the command/FIB */ 106935863739SMike Smith cm->cm_sgtable = NULL; 107035863739SMike Smith cm->cm_flags = 0; 107135863739SMike Smith cm->cm_complete = NULL; 107235863739SMike Smith cm->cm_private = NULL; 107335863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 107435863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 107535863739SMike Smith cm->cm_fib->Header.Flags = 0; 107635863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 107735863739SMike Smith 107835863739SMike Smith /* 107935863739SMike Smith * These are duplicated in aac_start to cover the case where an 108035863739SMike Smith * intermediate stage may have destroyed them. They're left 108135863739SMike Smith * initialised here for debugging purposes only. 108235863739SMike Smith */ 108335863739SMike Smith cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1084f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1085f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 108635863739SMike Smith 108735863739SMike Smith aac_enqueue_free(cm); 108835863739SMike Smith } 108935863739SMike Smith 1090914da7d0SScott Long /* 10910b94a66eSMike Smith * Map helper for command/FIB allocation. 109235863739SMike Smith */ 109335863739SMike Smith static void 10940b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 109535863739SMike Smith { 1096914da7d0SScott Long struct aac_softc *sc; 1097914da7d0SScott Long 1098914da7d0SScott Long sc = (struct aac_softc *)arg; 109935863739SMike Smith 110035863739SMike Smith debug_called(3); 110135863739SMike Smith 11020b94a66eSMike Smith sc->aac_fibphys = segs[0].ds_addr; 110335863739SMike Smith } 110435863739SMike Smith 1105914da7d0SScott Long /* 11060b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 110735863739SMike Smith */ 11080b94a66eSMike Smith static int 11090b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 111035863739SMike Smith { 111135863739SMike Smith struct aac_command *cm; 111235863739SMike Smith int i; 111335863739SMike Smith 111435863739SMike Smith debug_called(1); 111535863739SMike Smith 11160b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1117c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, 1118c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_fibmap)) { 1119eb3025b3SScott Long printf("Not enough contiguous memory available.\n"); 11200b94a66eSMike Smith return (ENOMEM); 112135863739SMike Smith } 11220b94a66eSMike Smith bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs, 1123c6eafcf2SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1124c6eafcf2SScott Long aac_map_command_helper, sc, 0); 1125f30ac74cSScott Long bzero(sc->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11260b94a66eSMike Smith /* initialise constant fields in the command structure */ 11270b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11280b94a66eSMike Smith cm = &sc->aac_command[i]; 112935863739SMike Smith cm->cm_sc = sc; 11300b94a66eSMike Smith cm->cm_fib = sc->aac_fibs + i; 11310b94a66eSMike Smith cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib)); 113235863739SMike Smith 113335863739SMike Smith if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap)) 113435863739SMike Smith aac_release_command(cm); 113535863739SMike Smith } 11360b94a66eSMike Smith return (0); 113735863739SMike Smith } 113835863739SMike Smith 1139914da7d0SScott Long /* 11400b94a66eSMike Smith * Free FIBs owned by this adapter. 114135863739SMike Smith */ 114235863739SMike Smith static void 11430b94a66eSMike Smith aac_free_commands(struct aac_softc *sc) 114435863739SMike Smith { 114535863739SMike Smith int i; 114635863739SMike Smith 114735863739SMike Smith debug_called(1); 114835863739SMike Smith 11490b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) 1150914da7d0SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, 1151914da7d0SScott Long sc->aac_command[i].cm_datamap); 1152914da7d0SScott Long 11530b94a66eSMike Smith bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap); 11540b94a66eSMike Smith bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap); 115535863739SMike Smith } 115635863739SMike Smith 1157914da7d0SScott Long /* 115835863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 115935863739SMike Smith */ 116035863739SMike Smith static void 116135863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 116235863739SMike Smith { 1163914da7d0SScott Long struct aac_command *cm; 1164914da7d0SScott Long struct aac_fib *fib; 116535863739SMike Smith struct aac_sg_table *sg; 116635863739SMike Smith int i; 116735863739SMike Smith 116835863739SMike Smith debug_called(3); 116935863739SMike Smith 1170914da7d0SScott Long cm = (struct aac_command *)arg; 1171914da7d0SScott Long fib = cm->cm_fib; 1172914da7d0SScott Long 117335863739SMike Smith /* find the s/g table */ 117435863739SMike Smith sg = cm->cm_sgtable; 117535863739SMike Smith 117635863739SMike Smith /* copy into the FIB */ 117735863739SMike Smith if (sg != NULL) { 117835863739SMike Smith sg->SgCount = nseg; 117935863739SMike Smith for (i = 0; i < nseg; i++) { 118035863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 118135863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 118235863739SMike Smith } 118335863739SMike Smith /* update the FIB size for the s/g count */ 118435863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 118535863739SMike Smith } 118635863739SMike Smith 118735863739SMike Smith } 118835863739SMike Smith 1189914da7d0SScott Long /* 119035863739SMike Smith * Map a command into controller-visible space. 119135863739SMike Smith */ 119235863739SMike Smith static void 119335863739SMike Smith aac_map_command(struct aac_command *cm) 119435863739SMike Smith { 1195914da7d0SScott Long struct aac_softc *sc; 119635863739SMike Smith 119735863739SMike Smith debug_called(2); 119835863739SMike Smith 1199914da7d0SScott Long sc = cm->cm_sc; 1200914da7d0SScott Long 120135863739SMike Smith /* don't map more than once */ 120235863739SMike Smith if (cm->cm_flags & AAC_CMD_MAPPED) 120335863739SMike Smith return; 120435863739SMike Smith 120535863739SMike Smith if (cm->cm_datalen != 0) { 1206914da7d0SScott Long bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 1207914da7d0SScott Long cm->cm_data, cm->cm_datalen, 1208914da7d0SScott Long aac_map_command_sg, cm, 0); 120935863739SMike Smith 121035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1211c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1212c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 121335863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1214c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1215c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 121635863739SMike Smith } 121735863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 121835863739SMike Smith } 121935863739SMike Smith 1220914da7d0SScott Long /* 122135863739SMike Smith * Unmap a command from controller-visible space. 122235863739SMike Smith */ 122335863739SMike Smith static void 122435863739SMike Smith aac_unmap_command(struct aac_command *cm) 122535863739SMike Smith { 1226914da7d0SScott Long struct aac_softc *sc; 122735863739SMike Smith 122835863739SMike Smith debug_called(2); 122935863739SMike Smith 1230914da7d0SScott Long sc = cm->cm_sc; 1231914da7d0SScott Long 123235863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 123335863739SMike Smith return; 123435863739SMike Smith 123535863739SMike Smith if (cm->cm_datalen != 0) { 123635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1237c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1238c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 123935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1240c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1241c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 124235863739SMike Smith 124335863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 124435863739SMike Smith } 124535863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 124635863739SMike Smith } 124735863739SMike Smith 1248914da7d0SScott Long /* 1249914da7d0SScott Long * Hardware Interface 1250914da7d0SScott Long */ 125135863739SMike Smith 1252914da7d0SScott Long /* 125335863739SMike Smith * Initialise the adapter. 125435863739SMike Smith */ 125535863739SMike Smith static void 125635863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 125735863739SMike Smith { 1258914da7d0SScott Long struct aac_softc *sc; 125935863739SMike Smith 126035863739SMike Smith debug_called(1); 126135863739SMike Smith 1262914da7d0SScott Long sc = (struct aac_softc *)arg; 1263914da7d0SScott Long 126435863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 126535863739SMike Smith } 126635863739SMike Smith 1267fe94b852SScott Long /* 1268fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1269fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1270fe94b852SScott Long */ 1271fe94b852SScott Long static int 1272fe94b852SScott Long aac_check_firmware(struct aac_softc *sc) 1273fe94b852SScott Long { 1274fe94b852SScott Long u_int32_t major, minor; 1275fe94b852SScott Long 1276fe94b852SScott Long debug_called(1); 1277fe94b852SScott Long 1278fe94b852SScott Long if (sc->quirks & AAC_QUIRK_PERC2QC) { 1279fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1280fe94b852SScott Long NULL)) { 1281fe94b852SScott Long device_printf(sc->aac_dev, 1282fe94b852SScott Long "Error reading firmware version\n"); 1283fe94b852SScott Long return (EIO); 1284fe94b852SScott Long } 1285fe94b852SScott Long 1286fe94b852SScott Long /* These numbers are stored as ASCII! */ 1287fe94b852SScott Long major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30; 1288fe94b852SScott Long minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30; 1289fe94b852SScott Long if (major == 1) { 1290fe94b852SScott Long device_printf(sc->aac_dev, 1291fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1292fe94b852SScott Long major, minor); 1293fe94b852SScott Long return (EINVAL); 1294fe94b852SScott Long } 1295fe94b852SScott Long } 1296fe94b852SScott Long 1297fe94b852SScott Long return (0); 1298fe94b852SScott Long } 1299fe94b852SScott Long 130035863739SMike Smith static int 130135863739SMike Smith aac_init(struct aac_softc *sc) 130235863739SMike Smith { 130335863739SMike Smith struct aac_adapter_init *ip; 130435863739SMike Smith time_t then; 130535863739SMike Smith u_int32_t code; 130635863739SMike Smith u_int8_t *qaddr; 130735863739SMike Smith 130835863739SMike Smith debug_called(1); 130935863739SMike Smith 131035863739SMike Smith /* 131135863739SMike Smith * First wait for the adapter to come ready. 131235863739SMike Smith */ 131335863739SMike Smith then = time_second; 131435863739SMike Smith do { 131535863739SMike Smith code = AAC_GET_FWSTATUS(sc); 131635863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 131735863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 131835863739SMike Smith return(ENXIO); 131935863739SMike Smith } 132035863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1321914da7d0SScott Long device_printf(sc->aac_dev, 1322914da7d0SScott Long "FATAL: controller kernel panic\n"); 132335863739SMike Smith return(ENXIO); 132435863739SMike Smith } 132535863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1326914da7d0SScott Long device_printf(sc->aac_dev, 1327914da7d0SScott Long "FATAL: controller not coming ready, " 1328c6eafcf2SScott Long "status %x\n", code); 132935863739SMike Smith return(ENXIO); 133035863739SMike Smith } 133135863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 133235863739SMike Smith 133335863739SMike Smith /* 133435863739SMike Smith * Create DMA tag for the common structure and allocate it. 133535863739SMike Smith */ 133635863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1337c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1338fe3cb0e1SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 133935863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 134035863739SMike Smith NULL, NULL, /* filter, filterarg */ 1341914da7d0SScott Long sizeof(struct aac_common), /* maxsize */ 1342914da7d0SScott Long 1, /* nsegments */ 134335863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 134435863739SMike Smith 0, /* flags */ 134535863739SMike Smith &sc->aac_common_dmat)) { 1346914da7d0SScott Long device_printf(sc->aac_dev, 1347914da7d0SScott Long "can't allocate common structure DMA tag\n"); 134835863739SMike Smith return(ENOMEM); 134935863739SMike Smith } 1350c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1351c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 135235863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 135335863739SMike Smith return(ENOMEM); 135435863739SMike Smith } 1355914da7d0SScott Long bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1356914da7d0SScott Long sc->aac_common, sizeof(*sc->aac_common), aac_common_map, 1357914da7d0SScott Long sc, 0); 135835863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 135935863739SMike Smith 136035863739SMike Smith /* 1361914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1362914da7d0SScott Long * physical location of various important shared data structures. 136335863739SMike Smith */ 136435863739SMike Smith ip = &sc->aac_common->ac_init; 136535863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1366f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 136735863739SMike Smith 1368c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1369c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1370f30ac74cSScott Long ip->AdapterFibsVirtualAddress = (u_int32_t)&sc->aac_common->ac_fibs[0]; 137135863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 137235863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 137335863739SMike Smith 1374c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1375c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 137635863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 137735863739SMike Smith 1378f30ac74cSScott Long /* The adapter assumes that pages are 4K in size */ 1379f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 138035863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 138135863739SMike Smith 138235863739SMike Smith /* 1383c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1384c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1385c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 138635863739SMike Smith * 138735863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1388914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1389914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1390914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1391914da7d0SScott Long * does. 139235863739SMike Smith * 1393914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1394914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1395914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1396914da7d0SScott Long * virtue of a table. 139735863739SMike Smith */ 139835863739SMike Smith qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 139935863739SMike Smith qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 140035863739SMike Smith sc->aac_queues = (struct aac_queue_table *)qaddr; 1401914da7d0SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + 1402914da7d0SScott Long ((u_int32_t)sc->aac_queues - 1403914da7d0SScott Long (u_int32_t)sc->aac_common); 140435863739SMike Smith 1405c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1406c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1407c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1408c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1409c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1410c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1411c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1412c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1413c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1414c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1415c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1416c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1417c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1418c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1419c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1420c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1421c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1422c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1423c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1424c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1425c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1426c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1427c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1428c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1429c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1430c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1431c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1432c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1433c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1434c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1435c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1436c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1437c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1438c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1439c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1440c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1441c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1442c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1443c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1444c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1445c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1446c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1447c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1448c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1449c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1450c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1451c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1452c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 145335863739SMike Smith 145435863739SMike Smith /* 145535863739SMike Smith * Do controller-type-specific initialisation 145635863739SMike Smith */ 145735863739SMike Smith switch (sc->aac_hwif) { 145835863739SMike Smith case AAC_HWIF_I960RX: 145935863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 146035863739SMike Smith break; 146135863739SMike Smith } 146235863739SMike Smith 146335863739SMike Smith /* 146435863739SMike Smith * Give the init structure to the controller. 146535863739SMike Smith */ 146635863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1467914da7d0SScott Long sc->aac_common_busaddr + 1468914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1469914da7d0SScott Long NULL)) { 1470914da7d0SScott Long device_printf(sc->aac_dev, 1471914da7d0SScott Long "error establishing init structure\n"); 147235863739SMike Smith return(EIO); 147335863739SMike Smith } 147435863739SMike Smith 147535863739SMike Smith return(0); 147635863739SMike Smith } 147735863739SMike Smith 1478914da7d0SScott Long /* 147935863739SMike Smith * Send a synchronous command to the controller and wait for a result. 148035863739SMike Smith */ 148135863739SMike Smith static int 148235863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 148335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 148435863739SMike Smith u_int32_t *sp) 148535863739SMike Smith { 148635863739SMike Smith time_t then; 148735863739SMike Smith u_int32_t status; 148835863739SMike Smith 148935863739SMike Smith debug_called(3); 149035863739SMike Smith 149135863739SMike Smith /* populate the mailbox */ 149235863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 149335863739SMike Smith 149435863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 149535863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 149635863739SMike Smith 149735863739SMike Smith /* then set it to signal the adapter */ 149835863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 149935863739SMike Smith 150035863739SMike Smith /* spin waiting for the command to complete */ 150135863739SMike Smith then = time_second; 150235863739SMike Smith do { 150335863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 150435863739SMike Smith debug(2, "timed out"); 150535863739SMike Smith return(EIO); 150635863739SMike Smith } 150735863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 150835863739SMike Smith 150935863739SMike Smith /* clear the completion flag */ 151035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 151135863739SMike Smith 151235863739SMike Smith /* get the command status */ 151335863739SMike Smith status = AAC_GET_MAILBOXSTATUS(sc); 151435863739SMike Smith if (sp != NULL) 151535863739SMike Smith *sp = status; 15160b94a66eSMike Smith return(0); 151735863739SMike Smith } 151835863739SMike Smith 1519914da7d0SScott Long /* 1520cbfd045bSScott Long * Grab the sync fib area. 1521cbfd045bSScott Long */ 1522cbfd045bSScott Long int 1523fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1524cbfd045bSScott Long { 1525cbfd045bSScott Long 1526cbfd045bSScott Long /* 1527cbfd045bSScott Long * If the force flag is set, the system is shutting down, or in 1528cbfd045bSScott Long * trouble. Ignore the mutex. 1529cbfd045bSScott Long */ 1530cbfd045bSScott Long if (!(flags & AAC_SYNC_LOCK_FORCE)) 1531cbfd045bSScott Long AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1532cbfd045bSScott Long 1533cbfd045bSScott Long *fib = &sc->aac_common->ac_sync_fib; 1534cbfd045bSScott Long 1535cbfd045bSScott Long return (1); 1536cbfd045bSScott Long } 1537cbfd045bSScott Long 1538cbfd045bSScott Long /* 1539cbfd045bSScott Long * Release the sync fib area. 1540cbfd045bSScott Long */ 1541cbfd045bSScott Long void 1542cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc) 1543cbfd045bSScott Long { 1544cbfd045bSScott Long 1545cbfd045bSScott Long AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1546cbfd045bSScott Long } 1547cbfd045bSScott Long 1548cbfd045bSScott Long /* 154935863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 155035863739SMike Smith */ 1551cbfd045bSScott Long int 155235863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1553cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 155435863739SMike Smith { 155535863739SMike Smith debug_called(3); 155635863739SMike Smith 155735863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 155835863739SMike Smith return(EINVAL); 155935863739SMike Smith 156035863739SMike Smith /* 156135863739SMike Smith * Set up the sync FIB 156235863739SMike Smith */ 1563914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1564914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1565c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 156635863739SMike Smith fib->Header.XferState |= xferstate; 156735863739SMike Smith fib->Header.Command = command; 156835863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 156935863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 157035863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 157135863739SMike Smith fib->Header.SenderFibAddress = (u_int32_t)fib; 1572c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1573914da7d0SScott Long offsetof(struct aac_common, 1574914da7d0SScott Long ac_sync_fib); 157535863739SMike Smith 157635863739SMike Smith /* 157735863739SMike Smith * Give the FIB to the controller, wait for a response. 157835863739SMike Smith */ 1579914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1580914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 158135863739SMike Smith debug(2, "IO error"); 158235863739SMike Smith return(EIO); 158335863739SMike Smith } 158435863739SMike Smith 158535863739SMike Smith return (0); 158635863739SMike Smith } 158735863739SMike Smith 1588914da7d0SScott Long /* 158935863739SMike Smith * Adapter-space FIB queue manipulation 159035863739SMike Smith * 159135863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 159235863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 159335863739SMike Smith */ 159435863739SMike Smith static struct { 159535863739SMike Smith int size; 159635863739SMike Smith int notify; 159735863739SMike Smith } aac_qinfo[] = { 159835863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 159935863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 160035863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 160135863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 160235863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 160335863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 160435863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 160535863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 160635863739SMike Smith }; 160735863739SMike Smith 160835863739SMike Smith /* 1609c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1610c6eafcf2SScott Long * EBUSY if the queue is full. 161135863739SMike Smith * 16120b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1613914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1614914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1615c6eafcf2SScott Long * separate queue/notify interface). 161635863739SMike Smith */ 161735863739SMike Smith static int 1618f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 161935863739SMike Smith { 162035863739SMike Smith u_int32_t pi, ci; 162135863739SMike Smith int s, error; 1622f6c4dd3fSScott Long u_int32_t fib_size; 1623f6c4dd3fSScott Long u_int32_t fib_addr; 1624f6c4dd3fSScott Long 162536e0bf6eSScott Long debug_called(3); 162636e0bf6eSScott Long 1627f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1628f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 162935863739SMike Smith 163035863739SMike Smith s = splbio(); 163135863739SMike Smith 163235863739SMike Smith /* get the producer/consumer indices */ 163335863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 163435863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 163535863739SMike Smith 163635863739SMike Smith /* wrap the queue? */ 163735863739SMike Smith if (pi >= aac_qinfo[queue].size) 163835863739SMike Smith pi = 0; 163935863739SMike Smith 164035863739SMike Smith /* check for queue full */ 164135863739SMike Smith if ((pi + 1) == ci) { 164235863739SMike Smith error = EBUSY; 164335863739SMike Smith goto out; 164435863739SMike Smith } 164535863739SMike Smith 164635863739SMike Smith /* populate queue entry */ 164735863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 164835863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 164935863739SMike Smith 165035863739SMike Smith /* update producer index */ 165135863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 165235863739SMike Smith 1653f6c4dd3fSScott Long /* 1654914da7d0SScott Long * To avoid a race with its completion interrupt, place this command on 1655914da7d0SScott Long * the busy queue prior to advertising it to the controller. 1656f6c4dd3fSScott Long */ 1657f6c4dd3fSScott Long aac_enqueue_busy(cm); 1658f6c4dd3fSScott Long 165935863739SMike Smith /* notify the adapter if we know how */ 166035863739SMike Smith if (aac_qinfo[queue].notify != 0) 166135863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 166235863739SMike Smith 166335863739SMike Smith error = 0; 166435863739SMike Smith 166535863739SMike Smith out: 166635863739SMike Smith splx(s); 166735863739SMike Smith return(error); 166835863739SMike Smith } 166935863739SMike Smith 167035863739SMike Smith /* 167136e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 167236e0bf6eSScott Long * success or ENOENT if the queue is empty. 167335863739SMike Smith */ 167435863739SMike Smith static int 1675c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1676c6eafcf2SScott Long struct aac_fib **fib_addr) 167735863739SMike Smith { 167835863739SMike Smith u_int32_t pi, ci; 167935863739SMike Smith int s, error; 1680f6c4dd3fSScott Long int notify; 168135863739SMike Smith 168235863739SMike Smith debug_called(3); 168335863739SMike Smith 168435863739SMike Smith s = splbio(); 168535863739SMike Smith 168635863739SMike Smith /* get the producer/consumer indices */ 168735863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 168835863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 168935863739SMike Smith 169035863739SMike Smith /* check for queue empty */ 169135863739SMike Smith if (ci == pi) { 169235863739SMike Smith error = ENOENT; 169335863739SMike Smith goto out; 169435863739SMike Smith } 169535863739SMike Smith 1696f6c4dd3fSScott Long notify = 0; 1697f6c4dd3fSScott Long if (ci == pi + 1) 1698f6c4dd3fSScott Long notify++; 1699f6c4dd3fSScott Long 170035863739SMike Smith /* wrap the queue? */ 170135863739SMike Smith if (ci >= aac_qinfo[queue].size) 170235863739SMike Smith ci = 0; 170335863739SMike Smith 170435863739SMike Smith /* fetch the entry */ 170535863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1706914da7d0SScott Long *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + 1707914da7d0SScott Long ci)->aq_fib_addr; 170835863739SMike Smith 1709f30ac74cSScott Long /* 1710f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1711f30ac74cSScott Long * local memory so the whole fib doesn't have to be DMA'd back up. 1712f30ac74cSScott Long */ 1713f30ac74cSScott Long if (*(uintptr_t *)fib_addr & 0x01) { 1714f30ac74cSScott Long *(uintptr_t *)fib_addr &= ~0x01; 1715f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1716f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1717f30ac74cSScott Long } 171835863739SMike Smith /* update consumer index */ 171935863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 172035863739SMike Smith 172135863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1722f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 172335863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 172435863739SMike Smith error = 0; 172535863739SMike Smith 172635863739SMike Smith out: 172735863739SMike Smith splx(s); 172835863739SMike Smith return(error); 172935863739SMike Smith } 173035863739SMike Smith 1731914da7d0SScott Long /* 173236e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 173336e0bf6eSScott Long */ 173436e0bf6eSScott Long static int 173536e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 173636e0bf6eSScott Long { 173736e0bf6eSScott Long u_int32_t pi, ci; 173836e0bf6eSScott Long int s, error; 173936e0bf6eSScott Long u_int32_t fib_size; 174036e0bf6eSScott Long u_int32_t fib_addr; 174136e0bf6eSScott Long 174236e0bf6eSScott Long debug_called(1); 174336e0bf6eSScott Long 174436e0bf6eSScott Long /* Tell the adapter where the FIB is */ 174536e0bf6eSScott Long fib_size = fib->Header.Size; 174636e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 174736e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 174836e0bf6eSScott Long 174936e0bf6eSScott Long s = splbio(); 175036e0bf6eSScott Long 175136e0bf6eSScott Long /* get the producer/consumer indices */ 175236e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 175336e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 175436e0bf6eSScott Long 175536e0bf6eSScott Long /* wrap the queue? */ 175636e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 175736e0bf6eSScott Long pi = 0; 175836e0bf6eSScott Long 175936e0bf6eSScott Long /* check for queue full */ 176036e0bf6eSScott Long if ((pi + 1) == ci) { 176136e0bf6eSScott Long error = EBUSY; 176236e0bf6eSScott Long goto out; 176336e0bf6eSScott Long } 176436e0bf6eSScott Long 176536e0bf6eSScott Long /* populate queue entry */ 176636e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 176736e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 176836e0bf6eSScott Long 176936e0bf6eSScott Long /* update producer index */ 177036e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 177136e0bf6eSScott Long 177236e0bf6eSScott Long /* notify the adapter if we know how */ 177336e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 177436e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 177536e0bf6eSScott Long 177636e0bf6eSScott Long error = 0; 177736e0bf6eSScott Long 177836e0bf6eSScott Long out: 177936e0bf6eSScott Long splx(s); 178036e0bf6eSScott Long return(error); 178136e0bf6eSScott Long } 178236e0bf6eSScott Long 1783914da7d0SScott Long /* 17840b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 17850b94a66eSMike Smith * and complain about them. 17860b94a66eSMike Smith */ 17870b94a66eSMike Smith static void 17880b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 17890b94a66eSMike Smith { 17900b94a66eSMike Smith int s; 17910b94a66eSMike Smith struct aac_command *cm; 17920b94a66eSMike Smith time_t deadline; 17930b94a66eSMike Smith 1794f6c4dd3fSScott Long #if 0 17950b94a66eSMike Smith /* simulate an interrupt to handle possibly-missed interrupts */ 1796f6c4dd3fSScott Long /* 1797f6c4dd3fSScott Long * XXX This was done to work around another bug which has since been 1798f6c4dd3fSScott Long * fixed. It is dangerous anyways because you don't want multiple 1799f6c4dd3fSScott Long * threads in the interrupt handler at the same time! If calling 1800f6c4dd3fSScott Long * is deamed neccesary in the future, proper mutexes must be used. 1801f6c4dd3fSScott Long */ 1802f6c4dd3fSScott Long s = splbio(); 18030b94a66eSMike Smith aac_intr(sc); 1804f6c4dd3fSScott Long splx(s); 18050b94a66eSMike Smith 18060b94a66eSMike Smith /* kick the I/O queue to restart it in the case of deadlock */ 18070b94a66eSMike Smith aac_startio(sc); 180836e0bf6eSScott Long #endif 18090b94a66eSMike Smith 1810914da7d0SScott Long /* 1811914da7d0SScott Long * traverse the busy command list, bitch about late commands once 1812914da7d0SScott Long * only. 1813914da7d0SScott Long */ 18140b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 18150b94a66eSMike Smith s = splbio(); 18160b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1817f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1818f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 18190b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1820914da7d0SScott Long device_printf(sc->aac_dev, 1821914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1822f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 18230b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 18240b94a66eSMike Smith } 18250b94a66eSMike Smith } 18260b94a66eSMike Smith splx(s); 18270b94a66eSMike Smith 18280b94a66eSMike Smith /* reset the timer for next time */ 18290b94a66eSMike Smith timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz); 18300b94a66eSMike Smith return; 18310b94a66eSMike Smith } 18320b94a66eSMike Smith 1833914da7d0SScott Long /* 1834914da7d0SScott Long * Interface Function Vectors 1835914da7d0SScott Long */ 183635863739SMike Smith 1837914da7d0SScott Long /* 183835863739SMike Smith * Read the current firmware status word. 183935863739SMike Smith */ 184035863739SMike Smith static int 184135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 184235863739SMike Smith { 184335863739SMike Smith debug_called(3); 184435863739SMike Smith 184535863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 184635863739SMike Smith } 184735863739SMike Smith 184835863739SMike Smith static int 184935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 185035863739SMike Smith { 185135863739SMike Smith debug_called(3); 185235863739SMike Smith 185335863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 185435863739SMike Smith } 185535863739SMike Smith 1856b3457b51SScott Long static int 1857b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 1858b3457b51SScott Long { 1859b3457b51SScott Long int val; 1860b3457b51SScott Long 1861b3457b51SScott Long debug_called(3); 1862b3457b51SScott Long 1863b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 1864b3457b51SScott Long return (val); 1865b3457b51SScott Long } 1866b3457b51SScott Long 1867914da7d0SScott Long /* 186835863739SMike Smith * Notify the controller of a change in a given queue 186935863739SMike Smith */ 187035863739SMike Smith 187135863739SMike Smith static void 187235863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 187335863739SMike Smith { 187435863739SMike Smith debug_called(3); 187535863739SMike Smith 187635863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 187735863739SMike Smith } 187835863739SMike Smith 187935863739SMike Smith static void 188035863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 188135863739SMike Smith { 188235863739SMike Smith debug_called(3); 188335863739SMike Smith 188435863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 188535863739SMike Smith } 188635863739SMike Smith 1887b3457b51SScott Long static void 1888b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 1889b3457b51SScott Long { 1890b3457b51SScott Long debug_called(3); 1891b3457b51SScott Long 1892b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 1893b3457b51SScott Long AAC_FA_HACK(sc); 1894b3457b51SScott Long } 1895b3457b51SScott Long 1896914da7d0SScott Long /* 189735863739SMike Smith * Get the interrupt reason bits 189835863739SMike Smith */ 189935863739SMike Smith static int 190035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 190135863739SMike Smith { 190235863739SMike Smith debug_called(3); 190335863739SMike Smith 190435863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 190535863739SMike Smith } 190635863739SMike Smith 190735863739SMike Smith static int 190835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 190935863739SMike Smith { 191035863739SMike Smith debug_called(3); 191135863739SMike Smith 191235863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 191335863739SMike Smith } 191435863739SMike Smith 1915b3457b51SScott Long static int 1916b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 1917b3457b51SScott Long { 1918b3457b51SScott Long int val; 1919b3457b51SScott Long 1920b3457b51SScott Long debug_called(3); 1921b3457b51SScott Long 1922b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 1923b3457b51SScott Long return (val); 1924b3457b51SScott Long } 1925b3457b51SScott Long 1926914da7d0SScott Long /* 192735863739SMike Smith * Clear some interrupt reason bits 192835863739SMike Smith */ 192935863739SMike Smith static void 193035863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 193135863739SMike Smith { 193235863739SMike Smith debug_called(3); 193335863739SMike Smith 193435863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 193535863739SMike Smith } 193635863739SMike Smith 193735863739SMike Smith static void 193835863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 193935863739SMike Smith { 194035863739SMike Smith debug_called(3); 194135863739SMike Smith 194235863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 194335863739SMike Smith } 194435863739SMike Smith 1945b3457b51SScott Long static void 1946b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 1947b3457b51SScott Long { 1948b3457b51SScott Long debug_called(3); 1949b3457b51SScott Long 1950b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 1951b3457b51SScott Long AAC_FA_HACK(sc); 1952b3457b51SScott Long } 1953b3457b51SScott Long 1954914da7d0SScott Long /* 195535863739SMike Smith * Populate the mailbox and set the command word 195635863739SMike Smith */ 195735863739SMike Smith static void 195835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 195935863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 196035863739SMike Smith { 196135863739SMike Smith debug_called(4); 196235863739SMike Smith 196335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 196435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 196535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 196635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 196735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 196835863739SMike Smith } 196935863739SMike Smith 197035863739SMike Smith static void 197135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 197235863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 197335863739SMike Smith { 197435863739SMike Smith debug_called(4); 197535863739SMike Smith 197635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 197735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 197835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 197935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 198035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 198135863739SMike Smith } 198235863739SMike Smith 1983b3457b51SScott Long static void 1984b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 1985b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1986b3457b51SScott Long { 1987b3457b51SScott Long debug_called(4); 1988b3457b51SScott Long 1989b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 1990b3457b51SScott Long AAC_FA_HACK(sc); 1991b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 1992b3457b51SScott Long AAC_FA_HACK(sc); 1993b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 1994b3457b51SScott Long AAC_FA_HACK(sc); 1995b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 1996b3457b51SScott Long AAC_FA_HACK(sc); 1997b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 1998b3457b51SScott Long AAC_FA_HACK(sc); 1999b3457b51SScott Long } 2000b3457b51SScott Long 2001914da7d0SScott Long /* 200235863739SMike Smith * Fetch the immediate command status word 200335863739SMike Smith */ 200435863739SMike Smith static int 200535863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc) 200635863739SMike Smith { 200735863739SMike Smith debug_called(4); 200835863739SMike Smith 200935863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_MAILBOX)); 201035863739SMike Smith } 201135863739SMike Smith 201235863739SMike Smith static int 201335863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc) 201435863739SMike Smith { 201535863739SMike Smith debug_called(4); 201635863739SMike Smith 201735863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_MAILBOX)); 201835863739SMike Smith } 201935863739SMike Smith 2020b3457b51SScott Long static int 2021b3457b51SScott Long aac_fa_get_mailboxstatus(struct aac_softc *sc) 2022b3457b51SScott Long { 2023b3457b51SScott Long int val; 2024b3457b51SScott Long 2025b3457b51SScott Long debug_called(4); 2026b3457b51SScott Long 2027b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX); 2028b3457b51SScott Long return (val); 2029b3457b51SScott Long } 2030b3457b51SScott Long 2031914da7d0SScott Long /* 203235863739SMike Smith * Set/clear interrupt masks 203335863739SMike Smith */ 203435863739SMike Smith static void 203535863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 203635863739SMike Smith { 203735863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 203835863739SMike Smith 203935863739SMike Smith if (enable) { 204035863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 204135863739SMike Smith } else { 204235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 204335863739SMike Smith } 204435863739SMike Smith } 204535863739SMike Smith 204635863739SMike Smith static void 204735863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 204835863739SMike Smith { 204935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 205035863739SMike Smith 205135863739SMike Smith if (enable) { 205235863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 205335863739SMike Smith } else { 205435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 205535863739SMike Smith } 205635863739SMike Smith } 205735863739SMike Smith 2058b3457b51SScott Long static void 2059b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2060b3457b51SScott Long { 2061b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2062b3457b51SScott Long 2063b3457b51SScott Long if (enable) { 2064b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2065b3457b51SScott Long AAC_FA_HACK(sc); 2066b3457b51SScott Long } else { 2067b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2068b3457b51SScott Long AAC_FA_HACK(sc); 2069b3457b51SScott Long } 2070b3457b51SScott Long } 2071b3457b51SScott Long 2072914da7d0SScott Long /* 2073914da7d0SScott Long * Debugging and Diagnostics 2074914da7d0SScott Long */ 207535863739SMike Smith 2076914da7d0SScott Long /* 207735863739SMike Smith * Print some information about the controller. 207835863739SMike Smith */ 207935863739SMike Smith static void 208035863739SMike Smith aac_describe_controller(struct aac_softc *sc) 208135863739SMike Smith { 2082cbfd045bSScott Long struct aac_fib *fib; 208335863739SMike Smith struct aac_adapter_info *info; 208435863739SMike Smith 208535863739SMike Smith debug_called(2); 208635863739SMike Smith 2087fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2088cbfd045bSScott Long 2089cbfd045bSScott Long fib->data[0] = 0; 2090cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 209135863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2092fe3cb0e1SScott Long aac_release_sync_fib(sc); 209335863739SMike Smith return; 209435863739SMike Smith } 2095cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 209635863739SMike Smith 209736e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2098c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 209936e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2100914da7d0SScott Long aac_describe_code(aac_battery_platform, 2101914da7d0SScott Long info->batteryPlatform)); 210235863739SMike Smith 210335863739SMike Smith /* save the kernel revision structure for later use */ 210435863739SMike Smith sc->aac_revision = info->KernelRevision; 210536e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 210635863739SMike Smith info->KernelRevision.external.comp.major, 210735863739SMike Smith info->KernelRevision.external.comp.minor, 210835863739SMike Smith info->KernelRevision.external.comp.dash, 210936e0bf6eSScott Long info->KernelRevision.buildNumber, 211036e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2111fe3cb0e1SScott Long 2112fe3cb0e1SScott Long aac_release_sync_fib(sc); 211335863739SMike Smith } 211435863739SMike Smith 2115914da7d0SScott Long /* 211635863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 211735863739SMike Smith * same. 211835863739SMike Smith */ 211935863739SMike Smith static char * 212035863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 212135863739SMike Smith { 212235863739SMike Smith int i; 212335863739SMike Smith 212435863739SMike Smith for (i = 0; table[i].string != NULL; i++) 212535863739SMike Smith if (table[i].code == code) 212635863739SMike Smith return(table[i].string); 212735863739SMike Smith return(table[i + 1].string); 212835863739SMike Smith } 212935863739SMike Smith 2130914da7d0SScott Long /* 2131914da7d0SScott Long * Management Interface 2132914da7d0SScott Long */ 213335863739SMike Smith 213435863739SMike Smith static int 2135c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 213635863739SMike Smith { 2137914da7d0SScott Long struct aac_softc *sc; 213835863739SMike Smith 213935863739SMike Smith debug_called(2); 214035863739SMike Smith 2141914da7d0SScott Long sc = dev->si_drv1; 2142914da7d0SScott Long 214335863739SMike Smith /* Check to make sure the device isn't already open */ 214435863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 214535863739SMike Smith return EBUSY; 214635863739SMike Smith } 214735863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 214835863739SMike Smith 214935863739SMike Smith return 0; 215035863739SMike Smith } 215135863739SMike Smith 215235863739SMike Smith static int 2153c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 215435863739SMike Smith { 2155914da7d0SScott Long struct aac_softc *sc; 215635863739SMike Smith 215735863739SMike Smith debug_called(2); 215835863739SMike Smith 2159914da7d0SScott Long sc = dev->si_drv1; 2160914da7d0SScott Long 216135863739SMike Smith /* Mark this unit as no longer open */ 216235863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 216335863739SMike Smith 216435863739SMike Smith return 0; 216535863739SMike Smith } 216635863739SMike Smith 216735863739SMike Smith static int 2168c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 216935863739SMike Smith { 2170914da7d0SScott Long union aac_statrequest *as; 2171914da7d0SScott Long struct aac_softc *sc; 21720b94a66eSMike Smith int error = 0; 21730b94a66eSMike Smith int i; 217435863739SMike Smith 217535863739SMike Smith debug_called(2); 217635863739SMike Smith 2177914da7d0SScott Long as = (union aac_statrequest *)arg; 2178914da7d0SScott Long sc = dev->si_drv1; 2179914da7d0SScott Long 218035863739SMike Smith switch (cmd) { 21810b94a66eSMike Smith case AACIO_STATS: 21820b94a66eSMike Smith switch (as->as_item) { 21830b94a66eSMike Smith case AACQ_FREE: 21840b94a66eSMike Smith case AACQ_BIO: 21850b94a66eSMike Smith case AACQ_READY: 21860b94a66eSMike Smith case AACQ_BUSY: 21870b94a66eSMike Smith case AACQ_COMPLETE: 2188c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2189c6eafcf2SScott Long sizeof(struct aac_qstat)); 21900b94a66eSMike Smith break; 21910b94a66eSMike Smith default: 21920b94a66eSMike Smith error = ENOENT; 21930b94a66eSMike Smith break; 21940b94a66eSMike Smith } 21950b94a66eSMike Smith break; 21960b94a66eSMike Smith 219735863739SMike Smith case FSACTL_SENDFIB: 2198fb0c27d7SScott Long arg = *(caddr_t*)arg; 2199fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 22000b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 220135863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 220235863739SMike Smith break; 220335863739SMike Smith case FSACTL_AIF_THREAD: 2204fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 22050b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 220635863739SMike Smith error = EINVAL; 220735863739SMike Smith break; 220835863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2209fb0c27d7SScott Long arg = *(caddr_t*)arg; 2210fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 22110b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 221235863739SMike Smith /* 221335863739SMike Smith * Pass the caller out an AdapterFibContext. 221435863739SMike Smith * 221535863739SMike Smith * Note that because we only support one opener, we 221635863739SMike Smith * basically ignore this. Set the caller's context to a magic 221735863739SMike Smith * number just in case. 22180b94a66eSMike Smith * 22190b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 22200b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2221914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2222914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 222335863739SMike Smith */ 222436e0bf6eSScott Long i = (int)sc->aifthread; 222535863739SMike Smith error = copyout(&i, arg, sizeof(i)); 222635863739SMike Smith break; 222735863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2228fb0c27d7SScott Long arg = *(caddr_t*)arg; 2229fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 22300b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2231fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 223235863739SMike Smith break; 223335863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2234fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 22350b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 223635863739SMike Smith /* don't do anything here */ 223735863739SMike Smith break; 223835863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2239fb0c27d7SScott Long arg = *(caddr_t*)arg; 2240fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 22410b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2242fb0c27d7SScott Long error = aac_rev_check(sc, arg); 224335863739SMike Smith break; 224436e0bf6eSScott Long case FSACTL_QUERY_DISK: 224536e0bf6eSScott Long arg = *(caddr_t*)arg; 224636e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 224736e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 224836e0bf6eSScott Long error = aac_query_disk(sc, arg); 224936e0bf6eSScott Long break; 225036e0bf6eSScott Long case FSACTL_DELETE_DISK: 225136e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2252914da7d0SScott Long /* 2253914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2254914da7d0SScott Long * container, rather we rely on an AIF coming from the 2255914da7d0SScott Long * controller 2256914da7d0SScott Long */ 225736e0bf6eSScott Long error = 0; 225836e0bf6eSScott Long break; 225935863739SMike Smith default: 2260b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 226135863739SMike Smith error = EINVAL; 226235863739SMike Smith break; 226335863739SMike Smith } 226435863739SMike Smith return(error); 226535863739SMike Smith } 226635863739SMike Smith 2267b3457b51SScott Long static int 2268c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td) 2269b3457b51SScott Long { 2270b3457b51SScott Long struct aac_softc *sc; 2271b3457b51SScott Long int revents; 2272b3457b51SScott Long 2273b3457b51SScott Long sc = dev->si_drv1; 2274b3457b51SScott Long revents = 0; 2275b3457b51SScott Long 2276c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2277b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2278b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2279b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2280b3457b51SScott Long } 2281b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2282b3457b51SScott Long 2283b3457b51SScott Long if (revents == 0) { 2284b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2285b3457b51SScott Long selrecord(td, &sc->rcv_select); 2286b3457b51SScott Long } 2287b3457b51SScott Long 2288b3457b51SScott Long return (revents); 2289b3457b51SScott Long } 2290b3457b51SScott Long 2291914da7d0SScott Long /* 229235863739SMike Smith * Send a FIB supplied from userspace 229335863739SMike Smith */ 229435863739SMike Smith static int 229535863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 229635863739SMike Smith { 229735863739SMike Smith struct aac_command *cm; 229835863739SMike Smith int size, error; 229935863739SMike Smith 230035863739SMike Smith debug_called(2); 230135863739SMike Smith 230235863739SMike Smith cm = NULL; 230335863739SMike Smith 230435863739SMike Smith /* 230535863739SMike Smith * Get a command 230635863739SMike Smith */ 230735863739SMike Smith if (aac_alloc_command(sc, &cm)) { 230835863739SMike Smith error = EBUSY; 230935863739SMike Smith goto out; 231035863739SMike Smith } 231135863739SMike Smith 231235863739SMike Smith /* 231335863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 231435863739SMike Smith */ 2315914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2316914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 231735863739SMike Smith goto out; 231835863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 231935863739SMike Smith if (size > sizeof(struct aac_fib)) { 2320914da7d0SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2321914da7d0SScott Long size, sizeof(struct aac_fib)); 232235863739SMike Smith size = sizeof(struct aac_fib); 232335863739SMike Smith } 232435863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 232535863739SMike Smith goto out; 232635863739SMike Smith cm->cm_fib->Header.Size = size; 2327f6c4dd3fSScott Long cm->cm_timestamp = time_second; 232835863739SMike Smith 232935863739SMike Smith /* 233035863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 233135863739SMike Smith */ 2332b3457b51SScott Long if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 2333b3457b51SScott Long printf("aac_wait_command return %d\n", error); 233435863739SMike Smith goto out; 2335b3457b51SScott Long } 233635863739SMike Smith 233735863739SMike Smith /* 233835863739SMike Smith * Copy the FIB and data back out to the caller. 233935863739SMike Smith */ 234035863739SMike Smith size = cm->cm_fib->Header.Size; 234135863739SMike Smith if (size > sizeof(struct aac_fib)) { 2342914da7d0SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2343914da7d0SScott Long size, sizeof(struct aac_fib)); 234435863739SMike Smith size = sizeof(struct aac_fib); 234535863739SMike Smith } 234635863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 234735863739SMike Smith 234835863739SMike Smith out: 2349f6c4dd3fSScott Long if (cm != NULL) { 235035863739SMike Smith aac_release_command(cm); 2351f6c4dd3fSScott Long } 235235863739SMike Smith return(error); 235335863739SMike Smith } 235435863739SMike Smith 2355914da7d0SScott Long /* 235635863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 235736e0bf6eSScott Long * If the queue fills up, then drop the older entries. 235835863739SMike Smith */ 235935863739SMike Smith static void 236036e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 236135863739SMike Smith { 236236e0bf6eSScott Long struct aac_aif_command *aif; 236336e0bf6eSScott Long struct aac_container *co, *co_next; 2364cbfd045bSScott Long struct aac_mntinfo *mi; 2365cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 236636e0bf6eSScott Long u_int16_t rsize; 2367b3457b51SScott Long int next, found; 236836e0bf6eSScott Long int added = 0, i = 0; 236935863739SMike Smith 237035863739SMike Smith debug_called(2); 237135863739SMike Smith 237236e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 237336e0bf6eSScott Long aac_print_aif(sc, aif); 237436e0bf6eSScott Long 237536e0bf6eSScott Long /* Is it an event that we should care about? */ 237636e0bf6eSScott Long switch (aif->command) { 237736e0bf6eSScott Long case AifCmdEventNotify: 237836e0bf6eSScott Long switch (aif->data.EN.type) { 237936e0bf6eSScott Long case AifEnAddContainer: 238036e0bf6eSScott Long case AifEnDeleteContainer: 238136e0bf6eSScott Long /* 2382914da7d0SScott Long * A container was added or deleted, but the message 2383914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2384914da7d0SScott Long * containers and sort things out. 238536e0bf6eSScott Long */ 2386fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2387cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 238836e0bf6eSScott Long do { 238936e0bf6eSScott Long /* 2390914da7d0SScott Long * Ask the controller for its containers one at 2391914da7d0SScott Long * a time. 2392914da7d0SScott Long * XXX What if the controller's list changes 2393914da7d0SScott Long * midway through this enumaration? 239436e0bf6eSScott Long * XXX This should be done async. 239536e0bf6eSScott Long */ 239639ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 239739ee03c3SScott Long mi->Command = VM_NameServe; 239839ee03c3SScott Long mi->MntType = FT_FILESYS; 2399cbfd045bSScott Long mi->MntCount = i; 240036e0bf6eSScott Long rsize = sizeof(mir); 2401cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2402cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2403914da7d0SScott Long debug(2, "Error probing container %d\n", 2404914da7d0SScott Long i); 240536e0bf6eSScott Long continue; 240636e0bf6eSScott Long } 2407cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 240836e0bf6eSScott Long /* 2409914da7d0SScott Long * Check the container against our list. 2410914da7d0SScott Long * co->co_found was already set to 0 in a 2411914da7d0SScott Long * previous run. 241236e0bf6eSScott Long */ 2413cbfd045bSScott Long if ((mir->Status == ST_OK) && 2414cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 241536e0bf6eSScott Long found = 0; 2416914da7d0SScott Long TAILQ_FOREACH(co, 2417914da7d0SScott Long &sc->aac_container_tqh, 2418914da7d0SScott Long co_link) { 241936e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2420cbfd045bSScott Long mir->MntTable[0].ObjectId) { 242136e0bf6eSScott Long co->co_found = 1; 242236e0bf6eSScott Long found = 1; 242336e0bf6eSScott Long break; 242436e0bf6eSScott Long } 242536e0bf6eSScott Long } 2426914da7d0SScott Long /* 2427914da7d0SScott Long * If the container matched, continue 2428914da7d0SScott Long * in the list. 2429914da7d0SScott Long */ 243036e0bf6eSScott Long if (found) { 243136e0bf6eSScott Long i++; 243236e0bf6eSScott Long continue; 243336e0bf6eSScott Long } 243436e0bf6eSScott Long 243536e0bf6eSScott Long /* 2436914da7d0SScott Long * This is a new container. Do all the 2437914da7d0SScott Long * appropriate things to set it up. */ 2438cbfd045bSScott Long aac_add_container(sc, mir, 1); 243936e0bf6eSScott Long added = 1; 244036e0bf6eSScott Long } 244136e0bf6eSScott Long i++; 2442cbfd045bSScott Long } while ((i < mir->MntRespCount) && 2443914da7d0SScott Long (i < AAC_MAX_CONTAINERS)); 2444cbfd045bSScott Long aac_release_sync_fib(sc); 244536e0bf6eSScott Long 244636e0bf6eSScott Long /* 2447914da7d0SScott Long * Go through our list of containers and see which ones 2448914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2449914da7d0SScott Long * list them they must have been deleted. Do the 2450914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2451914da7d0SScott Long * the co->co_found field. 245236e0bf6eSScott Long */ 245336e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 245436e0bf6eSScott Long while (co != NULL) { 245536e0bf6eSScott Long if (co->co_found == 0) { 2456914da7d0SScott Long device_delete_child(sc->aac_dev, 2457914da7d0SScott Long co->co_disk); 245836e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2459c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc-> 2460914da7d0SScott Long aac_container_lock); 2461914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2462914da7d0SScott Long co_link); 2463914da7d0SScott Long AAC_LOCK_RELEASE(&sc-> 2464914da7d0SScott Long aac_container_lock); 246536e0bf6eSScott Long FREE(co, M_AACBUF); 246636e0bf6eSScott Long co = co_next; 246736e0bf6eSScott Long } else { 246836e0bf6eSScott Long co->co_found = 0; 246936e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 247036e0bf6eSScott Long } 247136e0bf6eSScott Long } 247236e0bf6eSScott Long 247336e0bf6eSScott Long /* Attach the newly created containers */ 247436e0bf6eSScott Long if (added) 247536e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 247636e0bf6eSScott Long 247736e0bf6eSScott Long break; 247836e0bf6eSScott Long 247936e0bf6eSScott Long default: 248036e0bf6eSScott Long break; 248136e0bf6eSScott Long } 248236e0bf6eSScott Long 248336e0bf6eSScott Long default: 248436e0bf6eSScott Long break; 248536e0bf6eSScott Long } 248636e0bf6eSScott Long 248736e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2488c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 248935863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 249035863739SMike Smith if (next != sc->aac_aifq_tail) { 249135863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 249235863739SMike Smith sc->aac_aifq_head = next; 2493b3457b51SScott Long 2494b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 249535863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 249635863739SMike Smith wakeup(sc->aac_aifq); 2497b3457b51SScott Long /* Wakeup any poll()ers */ 2498b3457b51SScott Long selwakeup(&sc->rcv_select); 249935863739SMike Smith } 2500b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 250136e0bf6eSScott Long 250236e0bf6eSScott Long return; 250335863739SMike Smith } 250435863739SMike Smith 2505914da7d0SScott Long /* 25060b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 250736e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 250836e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 250936e0bf6eSScott Long * returning what the card reported. 251035863739SMike Smith */ 251135863739SMike Smith static int 2512fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 251335863739SMike Smith { 251435863739SMike Smith struct aac_rev_check rev_check; 251535863739SMike Smith struct aac_rev_check_resp rev_check_resp; 251635863739SMike Smith int error = 0; 251735863739SMike Smith 251835863739SMike Smith debug_called(2); 251935863739SMike Smith 252035863739SMike Smith /* 252135863739SMike Smith * Copyin the revision struct from userspace 252235863739SMike Smith */ 2523c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2524c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 252535863739SMike Smith return error; 252635863739SMike Smith } 252735863739SMike Smith 2528914da7d0SScott Long debug(2, "Userland revision= %d\n", 2529914da7d0SScott Long rev_check.callingRevision.buildNumber); 253035863739SMike Smith 253135863739SMike Smith /* 253235863739SMike Smith * Doctor up the response struct. 253335863739SMike Smith */ 253435863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2535914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2536914da7d0SScott Long sc->aac_revision.external.ul; 2537914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2538914da7d0SScott Long sc->aac_revision.buildNumber; 253935863739SMike Smith 2540c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2541c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 254235863739SMike Smith } 254335863739SMike Smith 2544914da7d0SScott Long /* 254535863739SMike Smith * Pass the caller the next AIF in their queue 254635863739SMike Smith */ 254735863739SMike Smith static int 2548fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 254935863739SMike Smith { 255035863739SMike Smith struct get_adapter_fib_ioctl agf; 255135863739SMike Smith int error, s; 255235863739SMike Smith 255335863739SMike Smith debug_called(2); 255435863739SMike Smith 255535863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 255635863739SMike Smith 255735863739SMike Smith /* 255835863739SMike Smith * Check the magic number that we gave the caller. 255935863739SMike Smith */ 256036e0bf6eSScott Long if (agf.AdapterFibContext != (int)sc->aifthread) { 256135863739SMike Smith error = EFAULT; 256235863739SMike Smith } else { 256335863739SMike Smith 256435863739SMike Smith s = splbio(); 2565fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 256635863739SMike Smith 256735863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 256835863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 256935863739SMike Smith while (error == EAGAIN) { 2570914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2571914da7d0SScott Long PCATCH, "aacaif", 0); 257235863739SMike Smith if (error == 0) 2573914da7d0SScott Long error = aac_return_aif(sc, 2574914da7d0SScott Long agf.AifFib); 257535863739SMike Smith } 257635863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 257735863739SMike Smith } 257835863739SMike Smith splx(s); 257935863739SMike Smith } 258035863739SMike Smith } 258135863739SMike Smith return(error); 258235863739SMike Smith } 258335863739SMike Smith 2584914da7d0SScott Long /* 25850b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 25860b94a66eSMike Smith */ 25870b94a66eSMike Smith static int 2588fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 25890b94a66eSMike Smith { 2590b3457b51SScott Long int error; 25910b94a66eSMike Smith 25920b94a66eSMike Smith debug_called(2); 25930b94a66eSMike Smith 2594c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 25950b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 25960b94a66eSMike Smith error = EAGAIN; 25970b94a66eSMike Smith } else { 2598c6eafcf2SScott Long error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 2599c6eafcf2SScott Long sizeof(struct aac_aif_command)); 260036e0bf6eSScott Long if (error) 260136e0bf6eSScott Long printf("aac_return_aif: copyout returned %d\n", error); 26020b94a66eSMike Smith if (!error) 2603914da7d0SScott Long sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 2604914da7d0SScott Long AAC_AIFQ_LENGTH; 26050b94a66eSMike Smith } 2606b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 26070b94a66eSMike Smith return(error); 26080b94a66eSMike Smith } 260936e0bf6eSScott Long 2610914da7d0SScott Long /* 261136e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 261236e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 261336e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 261436e0bf6eSScott Long */ 261536e0bf6eSScott Long static int 261636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 261736e0bf6eSScott Long { 261836e0bf6eSScott Long struct aac_query_disk query_disk; 261936e0bf6eSScott Long struct aac_container *co; 2620914da7d0SScott Long struct aac_disk *disk; 262136e0bf6eSScott Long int error, id; 262236e0bf6eSScott Long 262336e0bf6eSScott Long debug_called(2); 262436e0bf6eSScott Long 2625914da7d0SScott Long disk = NULL; 2626914da7d0SScott Long 2627914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2628914da7d0SScott Long sizeof(struct aac_query_disk)); 262936e0bf6eSScott Long if (error) 263036e0bf6eSScott Long return (error); 263136e0bf6eSScott Long 263236e0bf6eSScott Long id = query_disk.ContainerNumber; 263336e0bf6eSScott Long if (id == -1) 263436e0bf6eSScott Long return (EINVAL); 263536e0bf6eSScott Long 2636c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 263736e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 263836e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 263936e0bf6eSScott Long break; 264036e0bf6eSScott Long } 264136e0bf6eSScott Long 264236e0bf6eSScott Long if (co == NULL) { 264336e0bf6eSScott Long query_disk.Valid = 0; 264436e0bf6eSScott Long query_disk.Locked = 0; 264536e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 264636e0bf6eSScott Long } else { 264736e0bf6eSScott Long disk = device_get_softc(co->co_disk); 264836e0bf6eSScott Long query_disk.Valid = 1; 2649914da7d0SScott Long query_disk.Locked = 2650914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 265136e0bf6eSScott Long query_disk.Deleted = 0; 2652b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 265336e0bf6eSScott Long query_disk.Target = disk->unit; 265436e0bf6eSScott Long query_disk.Lun = 0; 265536e0bf6eSScott Long query_disk.UnMapped = 0; 2656914da7d0SScott Long bcopy(disk->ad_dev_t->si_name, 2657914da7d0SScott Long &query_disk.diskDeviceName[0], 10); 265836e0bf6eSScott Long } 265936e0bf6eSScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 266036e0bf6eSScott Long 2661914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2662914da7d0SScott Long sizeof(struct aac_query_disk)); 266336e0bf6eSScott Long 266436e0bf6eSScott Long return (error); 266536e0bf6eSScott Long } 266636e0bf6eSScott Long 2667fe3cb0e1SScott Long static void 2668fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2669fe3cb0e1SScott Long { 2670fe3cb0e1SScott Long struct aac_fib *fib; 2671fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2672fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2673fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2674fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2675fe3cb0e1SScott Long struct aac_getbusinf businfo; 2676fe3cb0e1SScott Long struct aac_cam_inf *caminf; 2677fe3cb0e1SScott Long device_t child; 2678fe3cb0e1SScott Long int i, found, error; 2679fe3cb0e1SScott Long 2680fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2681fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 268239ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2683fe3cb0e1SScott Long 2684fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2685fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2686fe3cb0e1SScott Long c_cmd->param = 0; 2687fe3cb0e1SScott Long 2688fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2689fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2690fe3cb0e1SScott Long if (error) { 2691fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2692fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2693fe3cb0e1SScott Long aac_release_sync_fib(sc); 2694fe3cb0e1SScott Long return; 2695fe3cb0e1SScott Long } 2696fe3cb0e1SScott Long 2697fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2698fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2699fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2700fe3cb0e1SScott Long c_resp->Status); 2701fe3cb0e1SScott Long aac_release_sync_fib(sc); 2702fe3cb0e1SScott Long return; 2703fe3cb0e1SScott Long } 2704fe3cb0e1SScott Long 2705fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2706fe3cb0e1SScott Long 2707fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 270839ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 270939ee03c3SScott Long 2710fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2711fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2712fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2713fe3cb0e1SScott Long vmi->ObjId = 0; 2714fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2715fe3cb0e1SScott Long 2716fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2717fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2718fe3cb0e1SScott Long if (error) { 2719fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2720fe3cb0e1SScott Long error); 2721fe3cb0e1SScott Long aac_release_sync_fib(sc); 2722fe3cb0e1SScott Long return; 2723fe3cb0e1SScott Long } 2724fe3cb0e1SScott Long 2725fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2726fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2727fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2728fe3cb0e1SScott Long vmi_resp->Status); 2729fe3cb0e1SScott Long aac_release_sync_fib(sc); 2730fe3cb0e1SScott Long return; 2731fe3cb0e1SScott Long } 2732fe3cb0e1SScott Long 2733fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2734fe3cb0e1SScott Long aac_release_sync_fib(sc); 2735fe3cb0e1SScott Long 2736fe3cb0e1SScott Long found = 0; 2737fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2738fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2739fe3cb0e1SScott Long continue; 2740fe3cb0e1SScott Long 2741fe3cb0e1SScott Long MALLOC(caminf, struct aac_cam_inf *, 2742fe3cb0e1SScott Long sizeof(struct aac_cam_inf), M_AACBUF, M_NOWAIT | M_ZERO); 2743fe3cb0e1SScott Long if (caminf == NULL) 2744fe3cb0e1SScott Long continue; 2745fe3cb0e1SScott Long 2746fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2747fe3cb0e1SScott Long if (child == NULL) { 2748fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2749fe3cb0e1SScott Long continue; 2750fe3cb0e1SScott Long } 2751fe3cb0e1SScott Long 2752fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2753fe3cb0e1SScott Long caminf->BusNumber = i; 2754fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2755fe3cb0e1SScott Long caminf->aac_sc = sc; 2756fe3cb0e1SScott Long 2757fe3cb0e1SScott Long device_set_ivars(child, caminf); 2758fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 2759fe3cb0e1SScott Long 2760fe3cb0e1SScott Long found = 1; 2761fe3cb0e1SScott Long } 2762fe3cb0e1SScott Long 2763fe3cb0e1SScott Long if (found) 2764fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2765fe3cb0e1SScott Long 2766fe3cb0e1SScott Long return; 2767fe3cb0e1SScott Long } 2768