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 30aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 32aad970f1SDavid E. O'Brien 3335863739SMike Smith /* 3435863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3535863739SMike Smith */ 3635863739SMike Smith 37f6c4dd3fSScott Long #include "opt_aac.h" 38f6c4dd3fSScott Long 3936e0bf6eSScott Long /* #include <stddef.h> */ 4035863739SMike Smith #include <sys/param.h> 4135863739SMike Smith #include <sys/systm.h> 4235863739SMike Smith #include <sys/malloc.h> 4335863739SMike Smith #include <sys/kernel.h> 4436e0bf6eSScott Long #include <sys/kthread.h> 453d04a9d7SScott Long #include <sys/sysctl.h> 46b3457b51SScott Long #include <sys/poll.h> 47891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 4835863739SMike Smith 4935863739SMike Smith #include <sys/bus.h> 5035863739SMike Smith #include <sys/conf.h> 5135863739SMike Smith #include <sys/signalvar.h> 520b94a66eSMike Smith #include <sys/time.h> 5336e0bf6eSScott Long #include <sys/eventhandler.h> 5435863739SMike Smith 5535863739SMike Smith #include <machine/bus_memio.h> 5635863739SMike Smith #include <machine/bus.h> 5735863739SMike Smith #include <machine/resource.h> 5835863739SMike Smith 5935863739SMike Smith #include <dev/aac/aacreg.h> 600b94a66eSMike Smith #include <dev/aac/aac_ioctl.h> 6135863739SMike Smith #include <dev/aac/aacvar.h> 6235863739SMike Smith #include <dev/aac/aac_tables.h> 6335863739SMike Smith 6435863739SMike Smith static void aac_startup(void *arg); 65914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 66cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 67fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 6835863739SMike Smith 6935863739SMike Smith /* Command Processing */ 700b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7135863739SMike Smith static void aac_complete(void *context, int pending); 7235863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7335863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 74d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 7570545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 7635863739SMike Smith 7735863739SMike Smith /* Command Buffer Management */ 78cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 79cd481291SScott Long int nseg, int error); 80c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 81c6eafcf2SScott Long int nseg, int error); 820b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 838480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 8435863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 8535863739SMike Smith 8635863739SMike Smith /* Hardware Interface */ 87c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 88c6eafcf2SScott Long int error); 89fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9035863739SMike Smith static int aac_init(struct aac_softc *sc); 9135863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 92c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 93c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 94c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 95f6c4dd3fSScott Long struct aac_command *cm); 96c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 97914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 9836e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 9936e0bf6eSScott Long struct aac_fib *fib); 10035863739SMike Smith 101b3457b51SScott Long /* Falcon/PPC interface */ 102b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 103b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 104b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 105b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 106b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 107b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 108b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 109a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 110b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 111b3457b51SScott Long 112b3457b51SScott Long struct aac_interface aac_fa_interface = { 113b3457b51SScott Long aac_fa_get_fwstatus, 114b3457b51SScott Long aac_fa_qnotify, 115b3457b51SScott Long aac_fa_get_istatus, 116b3457b51SScott Long aac_fa_clear_istatus, 117b3457b51SScott Long aac_fa_set_mailbox, 118a6d35632SScott Long aac_fa_get_mailbox, 119b3457b51SScott Long aac_fa_set_interrupts 120b3457b51SScott Long }; 121b3457b51SScott Long 12235863739SMike Smith /* StrongARM interface */ 12335863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 12435863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 12535863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 12635863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 12735863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 128c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 129c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 130a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13135863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 13235863739SMike Smith 13335863739SMike Smith struct aac_interface aac_sa_interface = { 13435863739SMike Smith aac_sa_get_fwstatus, 13535863739SMike Smith aac_sa_qnotify, 13635863739SMike Smith aac_sa_get_istatus, 13735863739SMike Smith aac_sa_clear_istatus, 13835863739SMike Smith aac_sa_set_mailbox, 139a6d35632SScott Long aac_sa_get_mailbox, 14035863739SMike Smith aac_sa_set_interrupts 14135863739SMike Smith }; 14235863739SMike Smith 14335863739SMike Smith /* i960Rx interface */ 14435863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 14535863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 14635863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 14735863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 14835863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 149c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 150c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 151a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 15235863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 15335863739SMike Smith 15435863739SMike Smith struct aac_interface aac_rx_interface = { 15535863739SMike Smith aac_rx_get_fwstatus, 15635863739SMike Smith aac_rx_qnotify, 15735863739SMike Smith aac_rx_get_istatus, 15835863739SMike Smith aac_rx_clear_istatus, 15935863739SMike Smith aac_rx_set_mailbox, 160a6d35632SScott Long aac_rx_get_mailbox, 16135863739SMike Smith aac_rx_set_interrupts 16235863739SMike Smith }; 16335863739SMike Smith 16435863739SMike Smith /* Debugging and Diagnostics */ 16535863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1666965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 167c6eafcf2SScott Long u_int32_t code); 16835863739SMike Smith 16935863739SMike Smith /* Management Interface */ 17035863739SMike Smith static d_open_t aac_open; 17135863739SMike Smith static d_close_t aac_close; 17235863739SMike Smith static d_ioctl_t aac_ioctl; 173b3457b51SScott Long static d_poll_t aac_poll; 174c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 175c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 17636e0bf6eSScott Long struct aac_fib *fib); 177fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 178fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 179fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 18036e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 18135863739SMike Smith 18235863739SMike Smith static struct cdevsw aac_cdevsw = { 183dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 184dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1857ac40f5fSPoul-Henning Kamp .d_open = aac_open, 1867ac40f5fSPoul-Henning Kamp .d_close = aac_close, 1877ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 1887ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 1897ac40f5fSPoul-Henning Kamp .d_name = "aac", 19035863739SMike Smith }; 19135863739SMike Smith 19236e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 19336e0bf6eSScott Long 1943d04a9d7SScott Long /* sysctl node */ 1953d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 1963d04a9d7SScott Long 197914da7d0SScott Long /* 198914da7d0SScott Long * Device Interface 199914da7d0SScott Long */ 20035863739SMike Smith 201914da7d0SScott Long /* 20235863739SMike Smith * Initialise the controller and softc 20335863739SMike Smith */ 20435863739SMike Smith int 20535863739SMike Smith aac_attach(struct aac_softc *sc) 20635863739SMike Smith { 20735863739SMike Smith int error, unit; 20835863739SMike Smith 20935863739SMike Smith debug_called(1); 21035863739SMike Smith 21135863739SMike Smith /* 21235863739SMike Smith * Initialise per-controller queues. 21335863739SMike Smith */ 2140b94a66eSMike Smith aac_initq_free(sc); 2150b94a66eSMike Smith aac_initq_ready(sc); 2160b94a66eSMike Smith aac_initq_busy(sc); 2170b94a66eSMike Smith aac_initq_bio(sc); 21835863739SMike Smith 21935863739SMike Smith /* 22035863739SMike Smith * Initialise command-completion task. 22135863739SMike Smith */ 22235863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 22335863739SMike Smith 22435863739SMike Smith /* disable interrupts before we enable anything */ 22535863739SMike Smith AAC_MASK_INTERRUPTS(sc); 22635863739SMike Smith 22735863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 22835863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 22935863739SMike Smith 23035863739SMike Smith /* 231fe94b852SScott Long * Check that the firmware on the card is supported. 232fe94b852SScott Long */ 233fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 234fe94b852SScott Long return(error); 235fe94b852SScott Long 236f6b1c44dSScott Long /* 237f6b1c44dSScott Long * Initialize locks 238f6b1c44dSScott Long */ 239bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 240bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 241bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 242f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 243f6b1c44dSScott Long 2443df780cfSScott Long /* Initialize the local AIF queue pointers */ 2453df780cfSScott Long sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; 246cbfd045bSScott Long 2470b94a66eSMike Smith /* 24835863739SMike Smith * Initialise the adapter. 24935863739SMike Smith */ 2500b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 25135863739SMike Smith return(error); 25235863739SMike Smith 25335863739SMike Smith /* 25435863739SMike Smith * Print a little information about the controller. 25535863739SMike Smith */ 25635863739SMike Smith aac_describe_controller(sc); 25735863739SMike Smith 25835863739SMike Smith /* 259ae543596SScott Long * Register to probe our containers later. 260ae543596SScott Long */ 26135863739SMike Smith sc->aac_ich.ich_func = aac_startup; 26235863739SMike Smith sc->aac_ich.ich_arg = sc; 26335863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 264914da7d0SScott Long device_printf(sc->aac_dev, 265914da7d0SScott Long "can't establish configuration hook\n"); 26635863739SMike Smith return(ENXIO); 26735863739SMike Smith } 26835863739SMike Smith 26935863739SMike Smith /* 27035863739SMike Smith * Make the control device. 27135863739SMike Smith */ 27235863739SMike Smith unit = device_get_unit(sc->aac_dev); 2739e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 2749e9466baSRobert Watson 0640, "aac%d", unit); 275157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 2764aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 27735863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 27835863739SMike Smith 27936e0bf6eSScott Long /* Create the AIF thread */ 28070545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 281316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 28236e0bf6eSScott Long panic("Could not create AIF thread\n"); 28336e0bf6eSScott Long 28436e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 2855f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 2865f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 2875f54d522SScott Long device_printf(sc->aac_dev, 2885f54d522SScott Long "shutdown event registration failed\n"); 28936e0bf6eSScott Long 290fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 291a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 29270545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 293fe3cb0e1SScott Long aac_get_bus_info(sc); 29470545d1aSScott Long } 295fe3cb0e1SScott Long 29635863739SMike Smith return(0); 29735863739SMike Smith } 29835863739SMike Smith 299914da7d0SScott Long /* 30035863739SMike Smith * Probe for containers, create disks. 30135863739SMike Smith */ 30235863739SMike Smith static void 30335863739SMike Smith aac_startup(void *arg) 30435863739SMike Smith { 305914da7d0SScott Long struct aac_softc *sc; 306cbfd045bSScott Long struct aac_fib *fib; 307cbfd045bSScott Long struct aac_mntinfo *mi; 308cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 309795d7dc0SScott Long int count = 0, i = 0; 31035863739SMike Smith 31135863739SMike Smith debug_called(1); 31235863739SMike Smith 313914da7d0SScott Long sc = (struct aac_softc *)arg; 314914da7d0SScott Long 31535863739SMike Smith /* disconnect ourselves from the intrhook chain */ 31635863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 31735863739SMike Smith 31803b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 319cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 320cbfd045bSScott Long 32135863739SMike Smith /* loop over possible containers */ 32236e0bf6eSScott Long do { 32335863739SMike Smith /* request information on this container */ 32439ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 32539ee03c3SScott Long mi->Command = VM_NameServe; 32639ee03c3SScott Long mi->MntType = FT_FILESYS; 327cbfd045bSScott Long mi->MntCount = i; 328cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 329cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 330795d7dc0SScott Long printf("error probing container %d", i); 33135863739SMike Smith continue; 33235863739SMike Smith } 33335863739SMike Smith 334cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 335795d7dc0SScott Long /* XXX Need to check if count changed */ 336795d7dc0SScott Long count = mir->MntRespCount; 337cbfd045bSScott Long aac_add_container(sc, mir, 0); 33836e0bf6eSScott Long i++; 339795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 340cbfd045bSScott Long 341cbfd045bSScott Long aac_release_sync_fib(sc); 34235863739SMike Smith 34335863739SMike Smith /* poke the bus to actually attach the child devices */ 34435863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 34535863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 34635863739SMike Smith 34735863739SMike Smith /* mark the controller up */ 34835863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 34935863739SMike Smith 35035863739SMike Smith /* enable interrupts now */ 35135863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 35235863739SMike Smith } 35335863739SMike Smith 354914da7d0SScott Long /* 355914da7d0SScott Long * Create a device to respresent a new container 356914da7d0SScott Long */ 357914da7d0SScott Long static void 358cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 359914da7d0SScott Long { 360914da7d0SScott Long struct aac_container *co; 361914da7d0SScott Long device_t child; 362914da7d0SScott Long 363914da7d0SScott Long /* 364914da7d0SScott Long * Check container volume type for validity. Note that many of 365914da7d0SScott Long * the possible types may never show up. 366914da7d0SScott Long */ 367914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 368a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 369a761a1caSScott Long M_NOWAIT | M_ZERO); 370914da7d0SScott Long if (co == NULL) 371914da7d0SScott Long panic("Out of memory?!\n"); 372914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 373914da7d0SScott Long mir->MntTable[0].ObjectId, 374914da7d0SScott Long mir->MntTable[0].FileSystemName, 375914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 376914da7d0SScott Long 377fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 378914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 379914da7d0SScott Long else 380914da7d0SScott Long device_set_ivars(child, co); 381914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 382914da7d0SScott Long mir->MntTable[0].VolType)); 383914da7d0SScott Long co->co_disk = child; 384914da7d0SScott Long co->co_found = f; 385914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 386914da7d0SScott Long sizeof(struct aac_mntobj)); 387bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 388914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 389bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 390914da7d0SScott Long } 391914da7d0SScott Long } 392914da7d0SScott Long 393914da7d0SScott Long /* 39435863739SMike Smith * Free all of the resources associated with (sc) 39535863739SMike Smith * 39635863739SMike Smith * Should not be called if the controller is active. 39735863739SMike Smith */ 39835863739SMike Smith void 39935863739SMike Smith aac_free(struct aac_softc *sc) 40035863739SMike Smith { 401ffb37f33SScott Long 40235863739SMike Smith debug_called(1); 40335863739SMike Smith 40435863739SMike Smith /* remove the control device */ 40535863739SMike Smith if (sc->aac_dev_t != NULL) 40635863739SMike Smith destroy_dev(sc->aac_dev_t); 40735863739SMike Smith 4080b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 4098480cc63SScott Long aac_free_commands(sc); 4100b94a66eSMike Smith if (sc->aac_fib_dmat) 4110b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 41235863739SMike Smith 413ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 414ffb37f33SScott Long 41535863739SMike Smith /* destroy the common area */ 41635863739SMike Smith if (sc->aac_common) { 41735863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 418c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 419c6eafcf2SScott Long sc->aac_common_dmamap); 42035863739SMike Smith } 4210b94a66eSMike Smith if (sc->aac_common_dmat) 4220b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 42335863739SMike Smith 42435863739SMike Smith /* disconnect the interrupt handler */ 42535863739SMike Smith if (sc->aac_intr) 42635863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 42735863739SMike Smith if (sc->aac_irq != NULL) 428c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 429c6eafcf2SScott Long sc->aac_irq); 43035863739SMike Smith 43135863739SMike Smith /* destroy data-transfer DMA tag */ 43235863739SMike Smith if (sc->aac_buffer_dmat) 43335863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 43435863739SMike Smith 43535863739SMike Smith /* destroy the parent DMA tag */ 43635863739SMike Smith if (sc->aac_parent_dmat) 43735863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 43835863739SMike Smith 43935863739SMike Smith /* release the register window mapping */ 44035863739SMike Smith if (sc->aac_regs_resource != NULL) 441914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 442914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 44335863739SMike Smith } 44435863739SMike Smith 445914da7d0SScott Long /* 44635863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 44735863739SMike Smith */ 44835863739SMike Smith int 44935863739SMike Smith aac_detach(device_t dev) 45035863739SMike Smith { 451914da7d0SScott Long struct aac_softc *sc; 45270545d1aSScott Long struct aac_container *co; 45370545d1aSScott Long struct aac_sim *sim; 45435863739SMike Smith int error; 45535863739SMike Smith 45635863739SMike Smith debug_called(1); 45735863739SMike Smith 458914da7d0SScott Long sc = device_get_softc(dev); 459914da7d0SScott Long 46035863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 46135863739SMike Smith return(EBUSY); 46235863739SMike Smith 46370545d1aSScott Long /* Remove the child containers */ 464a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 46570545d1aSScott Long error = device_delete_child(dev, co->co_disk); 46670545d1aSScott Long if (error) 46770545d1aSScott Long return (error); 46865ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 469a761a1caSScott Long free(co, M_AACBUF); 47070545d1aSScott Long } 47170545d1aSScott Long 47270545d1aSScott Long /* Remove the CAM SIMs */ 473a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 474a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 47570545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 47670545d1aSScott Long if (error) 47770545d1aSScott Long return (error); 478a761a1caSScott Long free(sim, M_AACBUF); 47970545d1aSScott Long } 48070545d1aSScott Long 48136e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 48236e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 48336e0bf6eSScott Long wakeup(sc->aifthread); 48436e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 48536e0bf6eSScott Long } 48636e0bf6eSScott Long 48736e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 48836e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 48936e0bf6eSScott Long 49035863739SMike Smith if ((error = aac_shutdown(dev))) 49135863739SMike Smith return(error); 49235863739SMike Smith 4935f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 4945f54d522SScott Long 49535863739SMike Smith aac_free(sc); 49635863739SMike Smith 49735863739SMike Smith return(0); 49835863739SMike Smith } 49935863739SMike Smith 500914da7d0SScott Long /* 50135863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 50235863739SMike Smith * 50335863739SMike Smith * This function is called before detach or system shutdown. 50435863739SMike Smith * 5050b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 50635863739SMike Smith * allow shutdown if any device is open. 50735863739SMike Smith */ 50835863739SMike Smith int 50935863739SMike Smith aac_shutdown(device_t dev) 51035863739SMike Smith { 511914da7d0SScott Long struct aac_softc *sc; 512cbfd045bSScott Long struct aac_fib *fib; 513cbfd045bSScott Long struct aac_close_command *cc; 51435863739SMike Smith 51535863739SMike Smith debug_called(1); 51635863739SMike Smith 517914da7d0SScott Long sc = device_get_softc(dev); 518914da7d0SScott Long 51935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 52035863739SMike Smith 52135863739SMike Smith /* 52235863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 52335863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 52435863739SMike Smith * We've been closed and all I/O completed already 52535863739SMike Smith */ 52635863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 52735863739SMike Smith 52803b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 529cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 530cbfd045bSScott Long 53139ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 532cbfd045bSScott Long cc->Command = VM_CloseAll; 533cbfd045bSScott Long cc->ContainerId = 0xffffffff; 534cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 535cbfd045bSScott Long sizeof(struct aac_close_command))) 53635863739SMike Smith printf("FAILED.\n"); 53770545d1aSScott Long else 53870545d1aSScott Long printf("done\n"); 53970545d1aSScott Long #if 0 540914da7d0SScott Long else { 541cbfd045bSScott Long fib->data[0] = 0; 54236e0bf6eSScott Long /* 543914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 54436e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 54536e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 54636e0bf6eSScott Long * driver module with the intent to reload it later. 54736e0bf6eSScott Long */ 548cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 549cbfd045bSScott Long fib, 1)) { 55035863739SMike Smith printf("FAILED.\n"); 55135863739SMike Smith } else { 55235863739SMike Smith printf("done.\n"); 55335863739SMike Smith } 55435863739SMike Smith } 55570545d1aSScott Long #endif 55635863739SMike Smith 55735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 5583576af8fSScott Long aac_release_sync_fib(sc); 55935863739SMike Smith 56035863739SMike Smith return(0); 56135863739SMike Smith } 56235863739SMike Smith 563914da7d0SScott Long /* 56435863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 56535863739SMike Smith */ 56635863739SMike Smith int 56735863739SMike Smith aac_suspend(device_t dev) 56835863739SMike Smith { 569914da7d0SScott Long struct aac_softc *sc; 57035863739SMike Smith 57135863739SMike Smith debug_called(1); 572914da7d0SScott Long 573914da7d0SScott Long sc = device_get_softc(dev); 574914da7d0SScott Long 57535863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 57635863739SMike Smith 57735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 57835863739SMike Smith return(0); 57935863739SMike Smith } 58035863739SMike Smith 581914da7d0SScott Long /* 58235863739SMike Smith * Bring the controller back to a state ready for operation. 58335863739SMike Smith */ 58435863739SMike Smith int 58535863739SMike Smith aac_resume(device_t dev) 58635863739SMike Smith { 587914da7d0SScott Long struct aac_softc *sc; 58835863739SMike Smith 58935863739SMike Smith debug_called(1); 590914da7d0SScott Long 591914da7d0SScott Long sc = device_get_softc(dev); 592914da7d0SScott Long 59335863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 59435863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 59535863739SMike Smith return(0); 59635863739SMike Smith } 59735863739SMike Smith 598914da7d0SScott Long /* 59935863739SMike Smith * Take an interrupt. 60035863739SMike Smith */ 60135863739SMike Smith void 60235863739SMike Smith aac_intr(void *arg) 60335863739SMike Smith { 604914da7d0SScott Long struct aac_softc *sc; 60570545d1aSScott Long u_int16_t reason; 60635863739SMike Smith 60735863739SMike Smith debug_called(2); 60835863739SMike Smith 609914da7d0SScott Long sc = (struct aac_softc *)arg; 610914da7d0SScott Long 611f30ac74cSScott Long /* 6129148fa21SScott Long * Read the status register directly. This is faster than taking the 6139148fa21SScott Long * driver lock and reading the queues directly. It also saves having 6149148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 6159148fa21SScott Long * ugly. 616f30ac74cSScott Long */ 61735863739SMike Smith reason = AAC_GET_ISTATUS(sc); 618f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 619f30ac74cSScott Long 6209c3a7fceSScott Long /* handle completion processing */ 6219148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 6229148fa21SScott Long taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 62335863739SMike Smith 6249148fa21SScott Long /* controller wants to talk to us */ 6259148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 62670545d1aSScott Long /* 6279148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 6289148fa21SScott Long * that start with a NULL. 62970545d1aSScott Long */ 6309148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 6319148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 6329148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 63370545d1aSScott Long 6349148fa21SScott Long /* 6359148fa21SScott Long * This might miss doing the actual wakeup. However, the 636a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 6379148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 6389148fa21SScott Long * priority that they can handle hanging out for a few seconds 6399148fa21SScott Long * if needed. 6409148fa21SScott Long */ 64136e0bf6eSScott Long wakeup(sc->aifthread); 64236e0bf6eSScott Long } 6439148fa21SScott Long } 64435863739SMike Smith 645c6eafcf2SScott Long /* 646914da7d0SScott Long * Command Processing 647914da7d0SScott Long */ 64835863739SMike Smith 649914da7d0SScott Long /* 65035863739SMike Smith * Start as much queued I/O as possible on the controller 65135863739SMike Smith */ 652fe3cb0e1SScott Long void 65335863739SMike Smith aac_startio(struct aac_softc *sc) 65435863739SMike Smith { 65535863739SMike Smith struct aac_command *cm; 656397fa34fSScott Long int error; 65735863739SMike Smith 65835863739SMike Smith debug_called(2); 65935863739SMike Smith 66035863739SMike Smith for (;;) { 661914da7d0SScott Long /* 662397fa34fSScott Long * This flag might be set if the card is out of resources. 663397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 664397fa34fSScott Long */ 665397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 666397fa34fSScott Long break; 667397fa34fSScott Long 668397fa34fSScott Long /* 669914da7d0SScott Long * Try to get a command that's been put off for lack of 670914da7d0SScott Long * resources 671914da7d0SScott Long */ 67235863739SMike Smith cm = aac_dequeue_ready(sc); 67335863739SMike Smith 674914da7d0SScott Long /* 675914da7d0SScott Long * Try to build a command off the bio queue (ignore error 676914da7d0SScott Long * return) 677914da7d0SScott Long */ 6780b94a66eSMike Smith if (cm == NULL) 67935863739SMike Smith aac_bio_command(sc, &cm); 68035863739SMike Smith 68135863739SMike Smith /* nothing to do? */ 68235863739SMike Smith if (cm == NULL) 68335863739SMike Smith break; 68435863739SMike Smith 685cd481291SScott Long /* don't map more than once */ 686cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 6874102d44bSScott Long panic("aac: command %p already mapped", cm); 68835863739SMike Smith 689397fa34fSScott Long /* 690397fa34fSScott Long * Set up the command to go to the controller. If there are no 691397fa34fSScott Long * data buffers associated with the command then it can bypass 692397fa34fSScott Long * busdma. 693397fa34fSScott Long */ 694cd481291SScott Long if (cm->cm_datalen != 0) { 695397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 696397fa34fSScott Long cm->cm_datamap, cm->cm_data, 697397fa34fSScott Long cm->cm_datalen, 698cd481291SScott Long aac_map_command_sg, cm, 0); 699cd481291SScott Long if (error == EINPROGRESS) { 700cd481291SScott Long debug(1, "freezing queue\n"); 701cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 702cd481291SScott Long error = 0; 703614c22b2SScott Long } else if (error != 0) 704397fa34fSScott Long panic("aac_startio: unexpected error %d from " 705397fa34fSScott Long "busdma\n", error); 706397fa34fSScott Long } else 7078778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 708cd481291SScott Long } 70935863739SMike Smith } 71035863739SMike Smith 711914da7d0SScott Long /* 71235863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 71335863739SMike Smith */ 71435863739SMike Smith static void 71570545d1aSScott Long aac_command_thread(struct aac_softc *sc) 71635863739SMike Smith { 71735863739SMike Smith struct aac_fib *fib; 71835863739SMike Smith u_int32_t fib_size; 7199148fa21SScott Long int size, retval; 72035863739SMike Smith 72136e0bf6eSScott Long debug_called(2); 72235863739SMike Smith 723bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 724a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 72536e0bf6eSScott Long 726a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 727a32a982dSScott Long 728a32a982dSScott Long retval = 0; 729a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 730a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 731a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 73236e0bf6eSScott Long 7339148fa21SScott Long /* 7349148fa21SScott Long * First see if any FIBs need to be allocated. This needs 7359148fa21SScott Long * to be called without the driver lock because contigmalloc 7369148fa21SScott Long * will grab Giant, and would result in an LOR. 7379148fa21SScott Long */ 7389148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 739bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 740a32a982dSScott Long aac_alloc_commands(sc); 741bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 7424102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 743a32a982dSScott Long aac_startio(sc); 744a32a982dSScott Long } 7459148fa21SScott Long 7469148fa21SScott Long /* 7479148fa21SScott Long * While we're here, check to see if any commands are stuck. 7489148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 7499148fa21SScott Long * always fire. 7509148fa21SScott Long */ 7519148fa21SScott Long if (retval == EWOULDBLOCK) 75270545d1aSScott Long aac_timeout(sc); 75370545d1aSScott Long 75470545d1aSScott Long /* Check the hardware printf message buffer */ 7559148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 75670545d1aSScott Long aac_print_printf(sc); 75770545d1aSScott Long 7589148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 7599148fa21SScott Long while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 7609148fa21SScott Long &fib_size, &fib) == 0) { 76135863739SMike Smith 76236e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 76336e0bf6eSScott Long 76435863739SMike Smith switch (fib->Header.Command) { 76535863739SMike Smith case AifRequest: 76636e0bf6eSScott Long aac_handle_aif(sc, fib); 76735863739SMike Smith break; 76835863739SMike Smith default: 769914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 770914da7d0SScott Long "from controller\n"); 77135863739SMike Smith break; 77235863739SMike Smith } 77335863739SMike Smith 77436e0bf6eSScott Long if ((fib->Header.XferState == 0) || 77536e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 77636e0bf6eSScott Long break; 77736e0bf6eSScott Long 77870545d1aSScott Long /* Return the AIF to the controller. */ 77936e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 78036e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 78136e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 78236e0bf6eSScott Long 78336e0bf6eSScott Long /* XXX Compute the Size field? */ 78436e0bf6eSScott Long size = fib->Header.Size; 78536e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 78636e0bf6eSScott Long size = sizeof(struct aac_fib); 78736e0bf6eSScott Long fib->Header.Size = size; 78836e0bf6eSScott Long } 78936e0bf6eSScott Long /* 790914da7d0SScott Long * Since we did not generate this command, it 791914da7d0SScott Long * cannot go through the normal 792914da7d0SScott Long * enqueue->startio chain. 79336e0bf6eSScott Long */ 794914da7d0SScott Long aac_enqueue_response(sc, 795914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 796914da7d0SScott Long fib); 79736e0bf6eSScott Long } 79836e0bf6eSScott Long } 79936e0bf6eSScott Long } 80036e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 801bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 80236e0bf6eSScott Long wakeup(sc->aac_dev); 80336e0bf6eSScott Long 80436e0bf6eSScott Long kthread_exit(0); 80535863739SMike Smith } 80635863739SMike Smith 807914da7d0SScott Long /* 8089c3a7fceSScott Long * Process completed commands. 80935863739SMike Smith */ 81035863739SMike Smith static void 8119c3a7fceSScott Long aac_complete(void *context, int pending) 81235863739SMike Smith { 8139c3a7fceSScott Long struct aac_softc *sc; 81435863739SMike Smith struct aac_command *cm; 81535863739SMike Smith struct aac_fib *fib; 81635863739SMike Smith u_int32_t fib_size; 81735863739SMike Smith 81835863739SMike Smith debug_called(2); 81935863739SMike Smith 8209c3a7fceSScott Long sc = (struct aac_softc *)context; 8219c3a7fceSScott Long 822bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 823ae543596SScott Long 8249c3a7fceSScott Long /* pull completed commands off the queue */ 82535863739SMike Smith for (;;) { 82635863739SMike Smith /* look for completed FIBs on our queue */ 827914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 828914da7d0SScott Long &fib)) 82935863739SMike Smith break; /* nothing to do */ 83035863739SMike Smith 831ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 832cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 83335863739SMike Smith if (cm == NULL) { 83435863739SMike Smith AAC_PRINT_FIB(sc, fib); 8359c3a7fceSScott Long break; 8369c3a7fceSScott Long } 8379c3a7fceSScott Long 8380b94a66eSMike Smith aac_remove_busy(cm); 839ecd1c51fSScott Long aac_unmap_command(cm); 84035863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 84135863739SMike Smith 84235863739SMike Smith /* is there a completion handler? */ 84335863739SMike Smith if (cm->cm_complete != NULL) { 84435863739SMike Smith cm->cm_complete(cm); 84535863739SMike Smith } else { 84635863739SMike Smith /* assume that someone is sleeping on this command */ 84735863739SMike Smith wakeup(cm); 84835863739SMike Smith } 84935863739SMike Smith } 8500b94a66eSMike Smith 8510b94a66eSMike Smith /* see if we can start some more I/O */ 852cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 8530b94a66eSMike Smith aac_startio(sc); 854ae543596SScott Long 855bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 85635863739SMike Smith } 85735863739SMike Smith 858914da7d0SScott Long /* 85935863739SMike Smith * Handle a bio submitted from a disk device. 86035863739SMike Smith */ 86135863739SMike Smith void 86235863739SMike Smith aac_submit_bio(struct bio *bp) 86335863739SMike Smith { 864914da7d0SScott Long struct aac_disk *ad; 865914da7d0SScott Long struct aac_softc *sc; 86635863739SMike Smith 86735863739SMike Smith debug_called(2); 86835863739SMike Smith 8697540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 870914da7d0SScott Long sc = ad->ad_controller; 871914da7d0SScott Long 87235863739SMike Smith /* queue the BIO and try to get some work done */ 8730b94a66eSMike Smith aac_enqueue_bio(sc, bp); 87435863739SMike Smith aac_startio(sc); 87535863739SMike Smith } 87635863739SMike Smith 877914da7d0SScott Long /* 87835863739SMike Smith * Get a bio and build a command to go with it. 87935863739SMike Smith */ 88035863739SMike Smith static int 88135863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 88235863739SMike Smith { 88335863739SMike Smith struct aac_command *cm; 88435863739SMike Smith struct aac_fib *fib; 88535863739SMike Smith struct aac_disk *ad; 88635863739SMike Smith struct bio *bp; 88735863739SMike Smith 88835863739SMike Smith debug_called(2); 88935863739SMike Smith 89035863739SMike Smith /* get the resources we will need */ 89135863739SMike Smith cm = NULL; 892a32a982dSScott Long bp = NULL; 89335863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 89435863739SMike Smith goto fail; 895a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 896a32a982dSScott Long goto fail; 89735863739SMike Smith 89835863739SMike Smith /* fill out the command */ 8990b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9000b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9010b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 90235863739SMike Smith cm->cm_private = bp; 9030b94a66eSMike Smith cm->cm_timestamp = time_second; 90436e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 90535863739SMike Smith 90635863739SMike Smith /* build the FIB */ 90735863739SMike Smith fib = cm->cm_fib; 908b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 90935863739SMike Smith fib->Header.XferState = 91035863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 91135863739SMike Smith AAC_FIBSTATE_INITIALISED | 912f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 91335863739SMike Smith AAC_FIBSTATE_FROMHOST | 91435863739SMike Smith AAC_FIBSTATE_REXPECTED | 915f30ac74cSScott Long AAC_FIBSTATE_NORM | 916f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 917f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 91835863739SMike Smith 91935863739SMike Smith /* build the read/write request */ 9207540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 921b85f5808SScott Long 922b85f5808SScott Long if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 923b85f5808SScott Long fib->Header.Command = ContainerCommand; 9249e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 925b85f5808SScott Long struct aac_blockread *br; 92635863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 92735863739SMike Smith br->Command = VM_CtBlockRead; 92835863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 92935863739SMike Smith br->BlockNumber = bp->bio_pblkno; 93035863739SMike Smith br->ByteCount = bp->bio_bcount; 93135863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 93235863739SMike Smith cm->cm_sgtable = &br->SgMap; 93335863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 93435863739SMike Smith } else { 935b85f5808SScott Long struct aac_blockwrite *bw; 93635863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 93735863739SMike Smith bw->Command = VM_CtBlockWrite; 93835863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 93935863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 94035863739SMike Smith bw->ByteCount = bp->bio_bcount; 941b85f5808SScott Long bw->Stable = CUNSTABLE; 94235863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 94335863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 94435863739SMike Smith cm->cm_sgtable = &bw->SgMap; 94535863739SMike Smith } 946b85f5808SScott Long } else { 947b85f5808SScott Long fib->Header.Command = ContainerCommand64; 948b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 949b85f5808SScott Long struct aac_blockread64 *br; 950b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 951b85f5808SScott Long br->Command = VM_CtHostRead64; 952b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 953b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 954b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 955b85f5808SScott Long br->Pad = 0; 956b85f5808SScott Long br->Flags = 0; 957b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 958b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 959eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 960b85f5808SScott Long } else { 961b85f5808SScott Long struct aac_blockwrite64 *bw; 962b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 963b85f5808SScott Long bw->Command = VM_CtHostWrite64; 964b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 965b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 966b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 967b85f5808SScott Long bw->Pad = 0; 968b85f5808SScott Long bw->Flags = 0; 969b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 970b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 971eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 972b85f5808SScott Long } 973b85f5808SScott Long } 97435863739SMike Smith 97535863739SMike Smith *cmp = cm; 97635863739SMike Smith return(0); 97735863739SMike Smith 97835863739SMike Smith fail: 97935863739SMike Smith if (bp != NULL) 9800b94a66eSMike Smith aac_enqueue_bio(sc, bp); 98135863739SMike Smith if (cm != NULL) 98235863739SMike Smith aac_release_command(cm); 98335863739SMike Smith return(ENOMEM); 98435863739SMike Smith } 98535863739SMike Smith 986914da7d0SScott Long /* 98735863739SMike Smith * Handle a bio-instigated command that has been completed. 98835863739SMike Smith */ 98935863739SMike Smith static void 99035863739SMike Smith aac_bio_complete(struct aac_command *cm) 99135863739SMike Smith { 99235863739SMike Smith struct aac_blockread_response *brr; 99335863739SMike Smith struct aac_blockwrite_response *bwr; 99435863739SMike Smith struct bio *bp; 99535863739SMike Smith AAC_FSAStatus status; 99635863739SMike Smith 99735863739SMike Smith /* fetch relevant status and then release the command */ 99835863739SMike Smith bp = (struct bio *)cm->cm_private; 9999e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 100035863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 100135863739SMike Smith status = brr->Status; 100235863739SMike Smith } else { 100335863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 100435863739SMike Smith status = bwr->Status; 100535863739SMike Smith } 100635863739SMike Smith aac_release_command(cm); 100735863739SMike Smith 100835863739SMike Smith /* fix up the bio based on status */ 100935863739SMike Smith if (status == ST_OK) { 101035863739SMike Smith bp->bio_resid = 0; 101135863739SMike Smith } else { 101235863739SMike Smith bp->bio_error = EIO; 101335863739SMike Smith bp->bio_flags |= BIO_ERROR; 10140b94a66eSMike Smith /* pass an error string out to the disk layer */ 1015914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1016914da7d0SScott Long status); 101735863739SMike Smith } 10180b94a66eSMike Smith aac_biodone(bp); 101935863739SMike Smith } 102035863739SMike Smith 1021914da7d0SScott Long /* 102235863739SMike Smith * Submit a command to the controller, return when it completes. 1023b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1024b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1025d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1026d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1027d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1028d8a0a473SScott Long * card completing a command late and spamming the command and data 1029d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 103035863739SMike Smith */ 103135863739SMike Smith static int 1032d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 103335863739SMike Smith { 1034ae543596SScott Long struct aac_softc *sc; 1035d8a0a473SScott Long int error; 103635863739SMike Smith 103735863739SMike Smith debug_called(2); 103835863739SMike Smith 1039ae543596SScott Long sc = cm->cm_sc; 1040ae543596SScott Long 104135863739SMike Smith /* Put the command on the ready queue and get things going */ 104236e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 104335863739SMike Smith aac_enqueue_ready(cm); 1044ae543596SScott Long aac_startio(sc); 1045ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 104635863739SMike Smith return(error); 104735863739SMike Smith } 104835863739SMike Smith 1049914da7d0SScott Long /* 1050914da7d0SScott Long *Command Buffer Management 1051914da7d0SScott Long */ 105235863739SMike Smith 1053914da7d0SScott Long /* 105435863739SMike Smith * Allocate a command. 105535863739SMike Smith */ 1056fe3cb0e1SScott Long int 105735863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 105835863739SMike Smith { 105935863739SMike Smith struct aac_command *cm; 106035863739SMike Smith 106135863739SMike Smith debug_called(3); 106235863739SMike Smith 1063ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1064b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1065ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1066ae543596SScott Long wakeup(sc->aifthread); 1067b85f5808SScott Long } 1068ae543596SScott Long return (EBUSY); 1069ffb37f33SScott Long } 107035863739SMike Smith 10710b94a66eSMike Smith *cmp = cm; 10720b94a66eSMike Smith return(0); 10730b94a66eSMike Smith } 10740b94a66eSMike Smith 1075914da7d0SScott Long /* 10760b94a66eSMike Smith * Release a command back to the freelist. 10770b94a66eSMike Smith */ 1078fe3cb0e1SScott Long void 10790b94a66eSMike Smith aac_release_command(struct aac_command *cm) 10800b94a66eSMike Smith { 10810b94a66eSMike Smith debug_called(3); 10820b94a66eSMike Smith 10830b94a66eSMike Smith /* (re)initialise the command/FIB */ 108435863739SMike Smith cm->cm_sgtable = NULL; 108535863739SMike Smith cm->cm_flags = 0; 108635863739SMike Smith cm->cm_complete = NULL; 108735863739SMike Smith cm->cm_private = NULL; 108835863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 108935863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 109035863739SMike Smith cm->cm_fib->Header.Flags = 0; 109135863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 109235863739SMike Smith 109335863739SMike Smith /* 109435863739SMike Smith * These are duplicated in aac_start to cover the case where an 109535863739SMike Smith * intermediate stage may have destroyed them. They're left 109635863739SMike Smith * initialised here for debugging purposes only. 109735863739SMike Smith */ 1098f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1099f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 110035863739SMike Smith 110135863739SMike Smith aac_enqueue_free(cm); 110235863739SMike Smith } 110335863739SMike Smith 1104914da7d0SScott Long /* 11050b94a66eSMike Smith * Map helper for command/FIB allocation. 110635863739SMike Smith */ 110735863739SMike Smith static void 11080b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 110935863739SMike Smith { 11108480cc63SScott Long uint32_t *fibphys; 1111914da7d0SScott Long 11128480cc63SScott Long fibphys = (uint32_t *)arg; 111335863739SMike Smith 111435863739SMike Smith debug_called(3); 111535863739SMike Smith 1116ffb37f33SScott Long *fibphys = segs[0].ds_addr; 111735863739SMike Smith } 111835863739SMike Smith 1119914da7d0SScott Long /* 11200b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 112135863739SMike Smith */ 11220b94a66eSMike Smith static int 11230b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 112435863739SMike Smith { 112535863739SMike Smith struct aac_command *cm; 1126ffb37f33SScott Long struct aac_fibmap *fm; 11278480cc63SScott Long uint32_t fibphys; 1128ffb37f33SScott Long int i, error; 112935863739SMike Smith 1130a6d35632SScott Long debug_called(2); 113135863739SMike Smith 1132a6d35632SScott Long if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs) 1133ffb37f33SScott Long return (ENOMEM); 1134ffb37f33SScott Long 11358480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1136a6d35632SScott Long if (fm == NULL) 1137a6d35632SScott Long return (ENOMEM); 1138ffb37f33SScott Long 11390b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1140ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1141ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 114270545d1aSScott Long device_printf(sc->aac_dev, 114370545d1aSScott Long "Not enough contiguous memory available.\n"); 11448480cc63SScott Long free(fm, M_AACBUF); 11450b94a66eSMike Smith return (ENOMEM); 114635863739SMike Smith } 1147128aa5a0SScott Long 1148cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1149cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1150ffb37f33SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1151ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1152128aa5a0SScott Long 11530b94a66eSMike Smith /* initialise constant fields in the command structure */ 1154bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1155ffb37f33SScott Long bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11560b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11578480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1158ffb37f33SScott Long fm->aac_commands = cm; 115935863739SMike Smith cm->cm_sc = sc; 1160ffb37f33SScott Long cm->cm_fib = fm->aac_fibs + i; 11618480cc63SScott Long cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1162cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 116335863739SMike Smith 1164ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1165ffb37f33SScott Long &cm->cm_datamap)) == 0) 116635863739SMike Smith aac_release_command(cm); 1167ffb37f33SScott Long else 11688480cc63SScott Long break; 11698480cc63SScott Long sc->total_fibs++; 117035863739SMike Smith } 1171ffb37f33SScott Long 11728480cc63SScott Long if (i > 0) { 1173ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1174a6d35632SScott Long debug(1, "total_fibs= %d\n", sc->total_fibs); 1175bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 11760b94a66eSMike Smith return (0); 117735863739SMike Smith } 117835863739SMike Smith 1179bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 11808480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 11818480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 11828480cc63SScott Long free(fm, M_AACBUF); 11838480cc63SScott Long return (ENOMEM); 11848480cc63SScott Long } 11858480cc63SScott Long 1186914da7d0SScott Long /* 11870b94a66eSMike Smith * Free FIBs owned by this adapter. 118835863739SMike Smith */ 118935863739SMike Smith static void 11908480cc63SScott Long aac_free_commands(struct aac_softc *sc) 119135863739SMike Smith { 11928480cc63SScott Long struct aac_fibmap *fm; 1193ffb37f33SScott Long struct aac_command *cm; 119435863739SMike Smith int i; 119535863739SMike Smith 119635863739SMike Smith debug_called(1); 119735863739SMike Smith 11988480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 11998480cc63SScott Long 12008480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 12018480cc63SScott Long /* 12028480cc63SScott Long * We check against total_fibs to handle partially 12038480cc63SScott Long * allocated blocks. 12048480cc63SScott Long */ 12058480cc63SScott Long for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1206ffb37f33SScott Long cm = fm->aac_commands + i; 1207ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1208ffb37f33SScott Long } 1209ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1210ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12118480cc63SScott Long free(fm, M_AACBUF); 12128480cc63SScott Long } 121335863739SMike Smith } 121435863739SMike Smith 1215914da7d0SScott Long /* 121635863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 121735863739SMike Smith */ 121835863739SMike Smith static void 121935863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 122035863739SMike Smith { 1221cd481291SScott Long struct aac_softc *sc; 1222914da7d0SScott Long struct aac_command *cm; 1223914da7d0SScott Long struct aac_fib *fib; 122435863739SMike Smith int i; 122535863739SMike Smith 122635863739SMike Smith debug_called(3); 122735863739SMike Smith 1228914da7d0SScott Long cm = (struct aac_command *)arg; 1229cd481291SScott Long sc = cm->cm_sc; 1230914da7d0SScott Long fib = cm->cm_fib; 1231914da7d0SScott Long 123235863739SMike Smith /* copy into the FIB */ 1233b85f5808SScott Long if (cm->cm_sgtable != NULL) { 1234b85f5808SScott Long if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1235b85f5808SScott Long struct aac_sg_table *sg; 1236b85f5808SScott Long sg = cm->cm_sgtable; 123735863739SMike Smith sg->SgCount = nseg; 123835863739SMike Smith for (i = 0; i < nseg; i++) { 123935863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 124035863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 124135863739SMike Smith } 124235863739SMike Smith /* update the FIB size for the s/g count */ 124335863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 1244b85f5808SScott Long } else { 1245b85f5808SScott Long struct aac_sg_table64 *sg; 1246b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1247b85f5808SScott Long sg->SgCount = nseg; 1248b85f5808SScott Long for (i = 0; i < nseg; i++) { 1249b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1250b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 125135863739SMike Smith } 1252b85f5808SScott Long /* update the FIB size for the s/g count */ 1253b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1254b85f5808SScott Long } 1255b85f5808SScott Long } 125635863739SMike Smith 1257cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1258cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 1259cd481291SScott Long * the SenderFibAddress over to make room for the fast response bit. 126035863739SMike Smith */ 1261cd481291SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1); 1262cd481291SScott Long cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 126335863739SMike Smith 1264cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1265cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 126635863739SMike Smith 126735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1268c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1269c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 127035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1271c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1272c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 127335863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1274cd481291SScott Long 1275397fa34fSScott Long /* Put the FIB on the outbound queue */ 12764102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 12774102d44bSScott Long aac_unmap_command(cm); 1278397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1279cd481291SScott Long aac_requeue_ready(cm); 12804102d44bSScott Long } 1281cd481291SScott Long 1282cd481291SScott Long return; 128335863739SMike Smith } 128435863739SMike Smith 1285914da7d0SScott Long /* 128635863739SMike Smith * Unmap a command from controller-visible space. 128735863739SMike Smith */ 128835863739SMike Smith static void 128935863739SMike Smith aac_unmap_command(struct aac_command *cm) 129035863739SMike Smith { 1291914da7d0SScott Long struct aac_softc *sc; 129235863739SMike Smith 129335863739SMike Smith debug_called(2); 129435863739SMike Smith 1295914da7d0SScott Long sc = cm->cm_sc; 1296914da7d0SScott Long 129735863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 129835863739SMike Smith return; 129935863739SMike Smith 130035863739SMike Smith if (cm->cm_datalen != 0) { 130135863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1302c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1303c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 130435863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1305c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1306c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 130735863739SMike Smith 130835863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 130935863739SMike Smith } 131035863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 131135863739SMike Smith } 131235863739SMike Smith 1313914da7d0SScott Long /* 1314914da7d0SScott Long * Hardware Interface 1315914da7d0SScott Long */ 131635863739SMike Smith 1317914da7d0SScott Long /* 131835863739SMike Smith * Initialise the adapter. 131935863739SMike Smith */ 132035863739SMike Smith static void 132135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 132235863739SMike Smith { 1323914da7d0SScott Long struct aac_softc *sc; 132435863739SMike Smith 132535863739SMike Smith debug_called(1); 132635863739SMike Smith 1327914da7d0SScott Long sc = (struct aac_softc *)arg; 1328914da7d0SScott Long 132935863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 133035863739SMike Smith } 133135863739SMike Smith 1332a6d35632SScott Long static int 1333a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1334a6d35632SScott Long { 1335a6d35632SScott Long u_int32_t major, minor, options; 1336a6d35632SScott Long 1337a6d35632SScott Long debug_called(1); 1338a6d35632SScott Long 1339fe94b852SScott Long /* 1340fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1341fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1342fe94b852SScott Long */ 1343a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1344fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1345fe94b852SScott Long NULL)) { 1346fe94b852SScott Long device_printf(sc->aac_dev, 1347fe94b852SScott Long "Error reading firmware version\n"); 1348fe94b852SScott Long return (EIO); 1349fe94b852SScott Long } 1350fe94b852SScott Long 1351fe94b852SScott Long /* These numbers are stored as ASCII! */ 1352a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1353a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1354fe94b852SScott Long if (major == 1) { 1355fe94b852SScott Long device_printf(sc->aac_dev, 1356fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1357fe94b852SScott Long major, minor); 1358fe94b852SScott Long return (EINVAL); 1359fe94b852SScott Long } 1360fe94b852SScott Long } 1361fe94b852SScott Long 1362a6d35632SScott Long /* 1363a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1364a6d35632SScott Long * work-arounds to enable. 1365a6d35632SScott Long */ 1366a6d35632SScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1367a6d35632SScott Long device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1368a6d35632SScott Long return (EIO); 1369a6d35632SScott Long } 1370a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 1371a6d35632SScott Long sc->supported_options = options; 1372a6d35632SScott Long 1373a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1374a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1375a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1376a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1377a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1378cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1379cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1380a6d35632SScott Long device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1381a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1382a6d35632SScott Long } 1383a6d35632SScott Long 1384a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 1385a6d35632SScott Long if ((sc->flags & AAC_FLAGS_256FIBS) == 0) 1386a6d35632SScott Long sc->aac_max_fibs = AAC_MAX_FIBS; 1387a6d35632SScott Long else 1388a6d35632SScott Long sc->aac_max_fibs = 256; 1389a6d35632SScott Long 1390fe94b852SScott Long return (0); 1391fe94b852SScott Long } 1392fe94b852SScott Long 139335863739SMike Smith static int 139435863739SMike Smith aac_init(struct aac_softc *sc) 139535863739SMike Smith { 139635863739SMike Smith struct aac_adapter_init *ip; 139735863739SMike Smith time_t then; 1398b88ffdc8SScott Long u_int32_t code, qoffset; 1399a6d35632SScott Long int error; 140035863739SMike Smith 140135863739SMike Smith debug_called(1); 140235863739SMike Smith 140335863739SMike Smith /* 140435863739SMike Smith * First wait for the adapter to come ready. 140535863739SMike Smith */ 140635863739SMike Smith then = time_second; 140735863739SMike Smith do { 140835863739SMike Smith code = AAC_GET_FWSTATUS(sc); 140935863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 141035863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 141135863739SMike Smith return(ENXIO); 141235863739SMike Smith } 141335863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1414914da7d0SScott Long device_printf(sc->aac_dev, 1415914da7d0SScott Long "FATAL: controller kernel panic\n"); 141635863739SMike Smith return(ENXIO); 141735863739SMike Smith } 141835863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1419914da7d0SScott Long device_printf(sc->aac_dev, 1420914da7d0SScott Long "FATAL: controller not coming ready, " 1421c6eafcf2SScott Long "status %x\n", code); 142235863739SMike Smith return(ENXIO); 142335863739SMike Smith } 142435863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 142535863739SMike Smith 1426a6d35632SScott Long error = ENOMEM; 1427a6d35632SScott Long /* 1428a6d35632SScott Long * Create DMA tag for mapping buffers into controller-addressable space. 1429a6d35632SScott Long */ 1430a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1431a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1432a6d35632SScott Long (sc->flags & AAC_FLAGS_SG_64BIT) ? 1433a6d35632SScott Long BUS_SPACE_MAXADDR : 1434a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1435a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1436a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1437a6d35632SScott Long MAXBSIZE, /* maxsize */ 1438a6d35632SScott Long AAC_MAXSGENTRIES, /* nsegments */ 1439a6d35632SScott Long MAXBSIZE, /* maxsegsize */ 1440a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1441f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 1442f6b1c44dSScott Long &sc->aac_io_lock, /* lockfuncarg */ 1443a6d35632SScott Long &sc->aac_buffer_dmat)) { 1444a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1445a6d35632SScott Long goto out; 1446a6d35632SScott Long } 1447a6d35632SScott Long 1448a6d35632SScott Long /* 1449a6d35632SScott Long * Create DMA tag for mapping FIBs into controller-addressable space.. 1450a6d35632SScott Long */ 1451a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1452a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1453a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1454a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1455a6d35632SScott Long 0x7fffffff, /* lowaddr */ 1456a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1457a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1458a6d35632SScott Long AAC_FIB_COUNT * 1459a6d35632SScott Long sizeof(struct aac_fib), /* maxsize */ 1460a6d35632SScott Long 1, /* nsegments */ 1461a6d35632SScott Long AAC_FIB_COUNT * 1462a6d35632SScott Long sizeof(struct aac_fib), /* maxsegsize */ 1463a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1464f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 1465a6d35632SScott Long &sc->aac_fib_dmat)) { 1466a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1467a6d35632SScott Long goto out; 1468a6d35632SScott Long } 1469a6d35632SScott Long 147035863739SMike Smith /* 147135863739SMike Smith * Create DMA tag for the common structure and allocate it. 147235863739SMike Smith */ 147335863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1474c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1475a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1476a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1477a6d35632SScott Long 0x7fffffff, /* lowaddr */ 147835863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 147935863739SMike Smith NULL, NULL, /* filter, filterarg */ 1480ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1481914da7d0SScott Long 1, /* nsegments */ 148235863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1483a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1484f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 148535863739SMike Smith &sc->aac_common_dmat)) { 1486914da7d0SScott Long device_printf(sc->aac_dev, 1487914da7d0SScott Long "can't allocate common structure DMA tag\n"); 1488a6d35632SScott Long goto out; 148935863739SMike Smith } 1490c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1491c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 149235863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 1493a6d35632SScott Long goto out; 149435863739SMike Smith } 1495ffb37f33SScott Long 1496ffb37f33SScott Long /* 1497ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1498ffb37f33SScott Long * below address 8192 in physical memory. 1499ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1500ffb37f33SScott Long * of ignored? 1501ffb37f33SScott Long */ 1502cd481291SScott Long (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1503ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1504ffb37f33SScott Long aac_common_map, sc, 0); 1505ffb37f33SScott Long 1506ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1507eec256deSAlexander Kabaev sc->aac_common = (struct aac_common *) 1508eec256deSAlexander Kabaev ((uint8_t *)sc->aac_common + 8192); 1509ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1510ffb37f33SScott Long } 151135863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 151235863739SMike Smith 1513ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1514ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 1515ffb37f33SScott Long sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 15168480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 15178480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1518ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1519ffb37f33SScott Long break; 1520ffb37f33SScott Long } 1521ffb37f33SScott Long if (sc->total_fibs == 0) 1522a6d35632SScott Long goto out; 1523ffb37f33SScott Long 152435863739SMike Smith /* 1525914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1526914da7d0SScott Long * physical location of various important shared data structures. 152735863739SMike Smith */ 152835863739SMike Smith ip = &sc->aac_common->ac_init; 152935863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1530f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 153135863739SMike Smith 1532c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1533c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1534149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 153535863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 153635863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 153735863739SMike Smith 1538c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1539c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 154035863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 154135863739SMike Smith 15424b00f859SScott Long /* 15434b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 15444b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 15454b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 15464b00f859SScott Long * Round up since the granularity is so high. 15474b00f859SScott Long */ 1548f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 15494b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 15504b00f859SScott Long ip->HostPhysMemPages = 15514b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1552204c0befSScott Long } 155335863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 155435863739SMike Smith 155535863739SMike Smith /* 1556c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1557c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1558c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 155935863739SMike Smith * 156035863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1561914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1562914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1563914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1564914da7d0SScott Long * does. 156535863739SMike Smith * 1566914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1567914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1568914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1569914da7d0SScott Long * virtue of a table. 157035863739SMike Smith */ 1571b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 15720bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 15730bcbebd6SScott Long sc->aac_queues = 15740bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1575b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 157635863739SMike Smith 1577c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1578c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1579c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1580c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1581c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1582c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1583c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1584c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1585c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1586c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1587c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1588c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1589c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1590c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1591c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1592c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1593c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1594c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1595c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1596c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1597c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1598c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1599c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1600c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1601c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1602c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1603c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1604c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1605c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1606c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1607c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1608c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1609c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1610c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1611c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1612c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1613c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1614c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1615c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1616c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1617c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1618c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1619c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1620c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1621c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1622c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1623c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1624c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 162535863739SMike Smith 162635863739SMike Smith /* 162735863739SMike Smith * Do controller-type-specific initialisation 162835863739SMike Smith */ 162935863739SMike Smith switch (sc->aac_hwif) { 163035863739SMike Smith case AAC_HWIF_I960RX: 163135863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 163235863739SMike Smith break; 163335863739SMike Smith } 163435863739SMike Smith 163535863739SMike Smith /* 163635863739SMike Smith * Give the init structure to the controller. 163735863739SMike Smith */ 163835863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1639914da7d0SScott Long sc->aac_common_busaddr + 1640914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1641914da7d0SScott Long NULL)) { 1642914da7d0SScott Long device_printf(sc->aac_dev, 1643914da7d0SScott Long "error establishing init structure\n"); 1644a6d35632SScott Long error = EIO; 1645a6d35632SScott Long goto out; 164635863739SMike Smith } 164735863739SMike Smith 1648a6d35632SScott Long error = 0; 1649a6d35632SScott Long out: 1650a6d35632SScott Long return(error); 165135863739SMike Smith } 165235863739SMike Smith 1653914da7d0SScott Long /* 165435863739SMike Smith * Send a synchronous command to the controller and wait for a result. 165535863739SMike Smith */ 165635863739SMike Smith static int 165735863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 165835863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 165935863739SMike Smith u_int32_t *sp) 166035863739SMike Smith { 166135863739SMike Smith time_t then; 166235863739SMike Smith u_int32_t status; 166335863739SMike Smith 166435863739SMike Smith debug_called(3); 166535863739SMike Smith 166635863739SMike Smith /* populate the mailbox */ 166735863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 166835863739SMike Smith 166935863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 167035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 167135863739SMike Smith 167235863739SMike Smith /* then set it to signal the adapter */ 167335863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 167435863739SMike Smith 167535863739SMike Smith /* spin waiting for the command to complete */ 167635863739SMike Smith then = time_second; 167735863739SMike Smith do { 167835863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 1679a6d35632SScott Long debug(1, "timed out"); 168035863739SMike Smith return(EIO); 168135863739SMike Smith } 168235863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 168335863739SMike Smith 168435863739SMike Smith /* clear the completion flag */ 168535863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 168635863739SMike Smith 168735863739SMike Smith /* get the command status */ 1688a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 168935863739SMike Smith if (sp != NULL) 169035863739SMike Smith *sp = status; 16910b94a66eSMike Smith return(0); 169235863739SMike Smith } 169335863739SMike Smith 1694cbfd045bSScott Long int 169535863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1696cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 169735863739SMike Smith { 169835863739SMike Smith debug_called(3); 169935863739SMike Smith 170035863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 170135863739SMike Smith return(EINVAL); 170235863739SMike Smith 170335863739SMike Smith /* 170435863739SMike Smith * Set up the sync FIB 170535863739SMike Smith */ 1706914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1707914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1708c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 170935863739SMike Smith fib->Header.XferState |= xferstate; 171035863739SMike Smith fib->Header.Command = command; 171135863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 171235863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 171335863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 1714b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 1715c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1716914da7d0SScott Long offsetof(struct aac_common, 1717914da7d0SScott Long ac_sync_fib); 171835863739SMike Smith 171935863739SMike Smith /* 172035863739SMike Smith * Give the FIB to the controller, wait for a response. 172135863739SMike Smith */ 1722914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1723914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 172435863739SMike Smith debug(2, "IO error"); 172535863739SMike Smith return(EIO); 172635863739SMike Smith } 172735863739SMike Smith 172835863739SMike Smith return (0); 172935863739SMike Smith } 173035863739SMike Smith 1731914da7d0SScott Long /* 173235863739SMike Smith * Adapter-space FIB queue manipulation 173335863739SMike Smith * 173435863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 173535863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 173635863739SMike Smith */ 173735863739SMike Smith static struct { 173835863739SMike Smith int size; 173935863739SMike Smith int notify; 174035863739SMike Smith } aac_qinfo[] = { 174135863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 174235863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 174335863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 174435863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 174535863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 174635863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 174735863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 174835863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 174935863739SMike Smith }; 175035863739SMike Smith 175135863739SMike Smith /* 1752c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1753c6eafcf2SScott Long * EBUSY if the queue is full. 175435863739SMike Smith * 17550b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1756914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1757914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1758c6eafcf2SScott Long * separate queue/notify interface). 175935863739SMike Smith */ 176035863739SMike Smith static int 1761f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 176235863739SMike Smith { 176335863739SMike Smith u_int32_t pi, ci; 17649e2e96d8SScott Long int error; 1765f6c4dd3fSScott Long u_int32_t fib_size; 1766f6c4dd3fSScott Long u_int32_t fib_addr; 1767f6c4dd3fSScott Long 176836e0bf6eSScott Long debug_called(3); 176936e0bf6eSScott Long 1770f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1771f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 177235863739SMike Smith 177335863739SMike Smith /* get the producer/consumer indices */ 177435863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 177535863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 177635863739SMike Smith 177735863739SMike Smith /* wrap the queue? */ 177835863739SMike Smith if (pi >= aac_qinfo[queue].size) 177935863739SMike Smith pi = 0; 178035863739SMike Smith 178135863739SMike Smith /* check for queue full */ 178235863739SMike Smith if ((pi + 1) == ci) { 178335863739SMike Smith error = EBUSY; 178435863739SMike Smith goto out; 178535863739SMike Smith } 178635863739SMike Smith 1787614c22b2SScott Long /* 1788614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 1789614c22b2SScott Long * the busy queue prior to advertising it to the controller. 1790614c22b2SScott Long */ 1791614c22b2SScott Long aac_enqueue_busy(cm); 1792614c22b2SScott Long 179335863739SMike Smith /* populate queue entry */ 179435863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 179535863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 179635863739SMike Smith 179735863739SMike Smith /* update producer index */ 179835863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 179935863739SMike Smith 180035863739SMike Smith /* notify the adapter if we know how */ 180135863739SMike Smith if (aac_qinfo[queue].notify != 0) 180235863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 180335863739SMike Smith 180435863739SMike Smith error = 0; 180535863739SMike Smith 180635863739SMike Smith out: 180735863739SMike Smith return(error); 180835863739SMike Smith } 180935863739SMike Smith 181035863739SMike Smith /* 181136e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 181236e0bf6eSScott Long * success or ENOENT if the queue is empty. 181335863739SMike Smith */ 181435863739SMike Smith static int 1815c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1816c6eafcf2SScott Long struct aac_fib **fib_addr) 181735863739SMike Smith { 181835863739SMike Smith u_int32_t pi, ci; 1819149af931SScott Long u_int32_t fib_index; 18209e2e96d8SScott Long int error; 1821f6c4dd3fSScott Long int notify; 182235863739SMike Smith 182335863739SMike Smith debug_called(3); 182435863739SMike Smith 182535863739SMike Smith /* get the producer/consumer indices */ 182635863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 182735863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 182835863739SMike Smith 182935863739SMike Smith /* check for queue empty */ 183035863739SMike Smith if (ci == pi) { 183135863739SMike Smith error = ENOENT; 183235863739SMike Smith goto out; 183335863739SMike Smith } 183435863739SMike Smith 18357753acd2SScott Long /* wrap the pi so the following test works */ 18367753acd2SScott Long if (pi >= aac_qinfo[queue].size) 18377753acd2SScott Long pi = 0; 18387753acd2SScott Long 1839f6c4dd3fSScott Long notify = 0; 1840f6c4dd3fSScott Long if (ci == pi + 1) 1841f6c4dd3fSScott Long notify++; 1842f6c4dd3fSScott Long 184335863739SMike Smith /* wrap the queue? */ 184435863739SMike Smith if (ci >= aac_qinfo[queue].size) 184535863739SMike Smith ci = 0; 184635863739SMike Smith 184735863739SMike Smith /* fetch the entry */ 184835863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1849149af931SScott Long 1850149af931SScott Long switch (queue) { 1851149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 1852149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 1853149af931SScott Long /* 1854149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 1855149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 1856149af931SScott Long * that it's giving us an address into the array of AIF fibs. 1857149af931SScott Long * Therefore, we have to convert it to an index. 1858149af931SScott Long */ 1859149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 1860149af931SScott Long sizeof(struct aac_fib); 1861149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 1862149af931SScott Long break; 1863149af931SScott Long 1864149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 1865149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 1866149af931SScott Long { 1867149af931SScott Long struct aac_command *cm; 1868149af931SScott Long 1869149af931SScott Long /* 1870149af931SScott Long * As above, an index is used instead of an actual address. 1871149af931SScott Long * Gotta shift the index to account for the fast response 1872149af931SScott Long * bit. No other correction is needed since this value was 1873149af931SScott Long * originally provided by the driver via the SenderFibAddress 1874149af931SScott Long * field. 1875149af931SScott Long */ 1876149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 1877149af931SScott Long cm = sc->aac_commands + (fib_index >> 1); 1878149af931SScott Long *fib_addr = cm->cm_fib; 187935863739SMike Smith 1880f30ac74cSScott Long /* 1881f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1882149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 1883f30ac74cSScott Long */ 1884149af931SScott Long if (fib_index & 0x01) { 1885f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1886f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1887f30ac74cSScott Long } 1888149af931SScott Long break; 1889149af931SScott Long } 1890149af931SScott Long default: 1891149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 1892149af931SScott Long break; 1893149af931SScott Long } 1894149af931SScott Long 189535863739SMike Smith /* update consumer index */ 189635863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 189735863739SMike Smith 189835863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1899f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 190035863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 190135863739SMike Smith error = 0; 190235863739SMike Smith 190335863739SMike Smith out: 190435863739SMike Smith return(error); 190535863739SMike Smith } 190635863739SMike Smith 1907914da7d0SScott Long /* 190836e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 190936e0bf6eSScott Long */ 191036e0bf6eSScott Long static int 191136e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 191236e0bf6eSScott Long { 191336e0bf6eSScott Long u_int32_t pi, ci; 19149e2e96d8SScott Long int error; 191536e0bf6eSScott Long u_int32_t fib_size; 191636e0bf6eSScott Long u_int32_t fib_addr; 191736e0bf6eSScott Long 191836e0bf6eSScott Long debug_called(1); 191936e0bf6eSScott Long 192036e0bf6eSScott Long /* Tell the adapter where the FIB is */ 192136e0bf6eSScott Long fib_size = fib->Header.Size; 192236e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 192336e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 192436e0bf6eSScott Long 192536e0bf6eSScott Long /* get the producer/consumer indices */ 192636e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 192736e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 192836e0bf6eSScott Long 192936e0bf6eSScott Long /* wrap the queue? */ 193036e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 193136e0bf6eSScott Long pi = 0; 193236e0bf6eSScott Long 193336e0bf6eSScott Long /* check for queue full */ 193436e0bf6eSScott Long if ((pi + 1) == ci) { 193536e0bf6eSScott Long error = EBUSY; 193636e0bf6eSScott Long goto out; 193736e0bf6eSScott Long } 193836e0bf6eSScott Long 193936e0bf6eSScott Long /* populate queue entry */ 194036e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 194136e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 194236e0bf6eSScott Long 194336e0bf6eSScott Long /* update producer index */ 194436e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 194536e0bf6eSScott Long 194636e0bf6eSScott Long /* notify the adapter if we know how */ 194736e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 194836e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 194936e0bf6eSScott Long 195036e0bf6eSScott Long error = 0; 195136e0bf6eSScott Long 195236e0bf6eSScott Long out: 195336e0bf6eSScott Long return(error); 195436e0bf6eSScott Long } 195536e0bf6eSScott Long 1956914da7d0SScott Long /* 19570b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 19580b94a66eSMike Smith * and complain about them. 19590b94a66eSMike Smith */ 19600b94a66eSMike Smith static void 19610b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 19620b94a66eSMike Smith { 19630b94a66eSMike Smith struct aac_command *cm; 19640b94a66eSMike Smith time_t deadline; 19650b94a66eSMike Smith 1966f6c4dd3fSScott Long /* 196770545d1aSScott Long * Traverse the busy command list, bitch about late commands once 1968914da7d0SScott Long * only. 1969914da7d0SScott Long */ 19700b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 19710b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1972f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 1973f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 19740b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 1975914da7d0SScott Long device_printf(sc->aac_dev, 1976914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1977f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 19780b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 19790b94a66eSMike Smith } 19800b94a66eSMike Smith } 19810b94a66eSMike Smith 19820b94a66eSMike Smith return; 19830b94a66eSMike Smith } 19840b94a66eSMike Smith 1985914da7d0SScott Long /* 1986914da7d0SScott Long * Interface Function Vectors 1987914da7d0SScott Long */ 198835863739SMike Smith 1989914da7d0SScott Long /* 199035863739SMike Smith * Read the current firmware status word. 199135863739SMike Smith */ 199235863739SMike Smith static int 199335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 199435863739SMike Smith { 199535863739SMike Smith debug_called(3); 199635863739SMike Smith 199735863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 199835863739SMike Smith } 199935863739SMike Smith 200035863739SMike Smith static int 200135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 200235863739SMike Smith { 200335863739SMike Smith debug_called(3); 200435863739SMike Smith 200535863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 200635863739SMike Smith } 200735863739SMike Smith 2008b3457b51SScott Long static int 2009b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2010b3457b51SScott Long { 2011b3457b51SScott Long int val; 2012b3457b51SScott Long 2013b3457b51SScott Long debug_called(3); 2014b3457b51SScott Long 2015b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2016b3457b51SScott Long return (val); 2017b3457b51SScott Long } 2018b3457b51SScott Long 2019914da7d0SScott Long /* 202035863739SMike Smith * Notify the controller of a change in a given queue 202135863739SMike Smith */ 202235863739SMike Smith 202335863739SMike Smith static void 202435863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 202535863739SMike Smith { 202635863739SMike Smith debug_called(3); 202735863739SMike Smith 202835863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 202935863739SMike Smith } 203035863739SMike Smith 203135863739SMike Smith static void 203235863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 203335863739SMike Smith { 203435863739SMike Smith debug_called(3); 203535863739SMike Smith 203635863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 203735863739SMike Smith } 203835863739SMike Smith 2039b3457b51SScott Long static void 2040b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2041b3457b51SScott Long { 2042b3457b51SScott Long debug_called(3); 2043b3457b51SScott Long 2044b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2045b3457b51SScott Long AAC_FA_HACK(sc); 2046b3457b51SScott Long } 2047b3457b51SScott Long 2048914da7d0SScott Long /* 204935863739SMike Smith * Get the interrupt reason bits 205035863739SMike Smith */ 205135863739SMike Smith static int 205235863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 205335863739SMike Smith { 205435863739SMike Smith debug_called(3); 205535863739SMike Smith 205635863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 205735863739SMike Smith } 205835863739SMike Smith 205935863739SMike Smith static int 206035863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 206135863739SMike Smith { 206235863739SMike Smith debug_called(3); 206335863739SMike Smith 206435863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 206535863739SMike Smith } 206635863739SMike Smith 2067b3457b51SScott Long static int 2068b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2069b3457b51SScott Long { 2070b3457b51SScott Long int val; 2071b3457b51SScott Long 2072b3457b51SScott Long debug_called(3); 2073b3457b51SScott Long 2074b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2075b3457b51SScott Long return (val); 2076b3457b51SScott Long } 2077b3457b51SScott Long 2078914da7d0SScott Long /* 207935863739SMike Smith * Clear some interrupt reason bits 208035863739SMike Smith */ 208135863739SMike Smith static void 208235863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 208335863739SMike Smith { 208435863739SMike Smith debug_called(3); 208535863739SMike Smith 208635863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 208735863739SMike Smith } 208835863739SMike Smith 208935863739SMike Smith static void 209035863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 209135863739SMike Smith { 209235863739SMike Smith debug_called(3); 209335863739SMike Smith 209435863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 209535863739SMike Smith } 209635863739SMike Smith 2097b3457b51SScott Long static void 2098b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2099b3457b51SScott Long { 2100b3457b51SScott Long debug_called(3); 2101b3457b51SScott Long 2102b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2103b3457b51SScott Long AAC_FA_HACK(sc); 2104b3457b51SScott Long } 2105b3457b51SScott Long 2106914da7d0SScott Long /* 210735863739SMike Smith * Populate the mailbox and set the command word 210835863739SMike Smith */ 210935863739SMike Smith static void 211035863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 211135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 211235863739SMike Smith { 211335863739SMike Smith debug_called(4); 211435863739SMike Smith 211535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 211635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 211735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 211835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 211935863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 212035863739SMike Smith } 212135863739SMike Smith 212235863739SMike Smith static void 212335863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 212435863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 212535863739SMike Smith { 212635863739SMike Smith debug_called(4); 212735863739SMike Smith 212835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 212935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 213035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 213135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 213235863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 213335863739SMike Smith } 213435863739SMike Smith 2135b3457b51SScott Long static void 2136b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2137b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2138b3457b51SScott Long { 2139b3457b51SScott Long debug_called(4); 2140b3457b51SScott Long 2141b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2142b3457b51SScott Long AAC_FA_HACK(sc); 2143b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2144b3457b51SScott Long AAC_FA_HACK(sc); 2145b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2146b3457b51SScott Long AAC_FA_HACK(sc); 2147b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2148b3457b51SScott Long AAC_FA_HACK(sc); 2149b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2150b3457b51SScott Long AAC_FA_HACK(sc); 2151b3457b51SScott Long } 2152b3457b51SScott Long 2153914da7d0SScott Long /* 215435863739SMike Smith * Fetch the immediate command status word 215535863739SMike Smith */ 215635863739SMike Smith static int 2157a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 215835863739SMike Smith { 215935863739SMike Smith debug_called(4); 216035863739SMike Smith 2161a6d35632SScott Long return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 216235863739SMike Smith } 216335863739SMike Smith 216435863739SMike Smith static int 2165a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 216635863739SMike Smith { 216735863739SMike Smith debug_called(4); 216835863739SMike Smith 2169a6d35632SScott Long return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 217035863739SMike Smith } 217135863739SMike Smith 2172b3457b51SScott Long static int 2173a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2174b3457b51SScott Long { 2175b3457b51SScott Long int val; 2176b3457b51SScott Long 2177b3457b51SScott Long debug_called(4); 2178b3457b51SScott Long 2179a6d35632SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2180b3457b51SScott Long return (val); 2181b3457b51SScott Long } 2182b3457b51SScott Long 2183914da7d0SScott Long /* 218435863739SMike Smith * Set/clear interrupt masks 218535863739SMike Smith */ 218635863739SMike Smith static void 218735863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 218835863739SMike Smith { 218935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 219035863739SMike Smith 219135863739SMike Smith if (enable) { 219235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 219335863739SMike Smith } else { 219435863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 219535863739SMike Smith } 219635863739SMike Smith } 219735863739SMike Smith 219835863739SMike Smith static void 219935863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 220035863739SMike Smith { 220135863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 220235863739SMike Smith 220335863739SMike Smith if (enable) { 220435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 220535863739SMike Smith } else { 220635863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 220735863739SMike Smith } 220835863739SMike Smith } 220935863739SMike Smith 2210b3457b51SScott Long static void 2211b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2212b3457b51SScott Long { 2213b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2214b3457b51SScott Long 2215b3457b51SScott Long if (enable) { 2216b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2217b3457b51SScott Long AAC_FA_HACK(sc); 2218b3457b51SScott Long } else { 2219b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2220b3457b51SScott Long AAC_FA_HACK(sc); 2221b3457b51SScott Long } 2222b3457b51SScott Long } 2223b3457b51SScott Long 2224914da7d0SScott Long /* 2225914da7d0SScott Long * Debugging and Diagnostics 2226914da7d0SScott Long */ 222735863739SMike Smith 2228914da7d0SScott Long /* 222935863739SMike Smith * Print some information about the controller. 223035863739SMike Smith */ 223135863739SMike Smith static void 223235863739SMike Smith aac_describe_controller(struct aac_softc *sc) 223335863739SMike Smith { 2234cbfd045bSScott Long struct aac_fib *fib; 223535863739SMike Smith struct aac_adapter_info *info; 223635863739SMike Smith 223735863739SMike Smith debug_called(2); 223835863739SMike Smith 223903b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2240cbfd045bSScott Long 2241cbfd045bSScott Long fib->data[0] = 0; 2242cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 224335863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2244fe3cb0e1SScott Long aac_release_sync_fib(sc); 224535863739SMike Smith return; 224635863739SMike Smith } 2247cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 224835863739SMike Smith 224936e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2250c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 225136e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2252914da7d0SScott Long aac_describe_code(aac_battery_platform, 2253914da7d0SScott Long info->batteryPlatform)); 225435863739SMike Smith 225535863739SMike Smith /* save the kernel revision structure for later use */ 225635863739SMike Smith sc->aac_revision = info->KernelRevision; 225736e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 225835863739SMike Smith info->KernelRevision.external.comp.major, 225935863739SMike Smith info->KernelRevision.external.comp.minor, 226035863739SMike Smith info->KernelRevision.external.comp.dash, 226136e0bf6eSScott Long info->KernelRevision.buildNumber, 226236e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2263fe3cb0e1SScott Long 2264fe3cb0e1SScott Long aac_release_sync_fib(sc); 2265a6d35632SScott Long 2266a6d35632SScott Long if (1 || bootverbose) { 2267a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2268a6d35632SScott Long sc->supported_options, 2269a6d35632SScott Long "\20" 2270a6d35632SScott Long "\1SNAPSHOT" 2271a6d35632SScott Long "\2CLUSTERS" 2272a6d35632SScott Long "\3WCACHE" 2273a6d35632SScott Long "\4DATA64" 2274a6d35632SScott Long "\5HOSTTIME" 2275a6d35632SScott Long "\6RAID50" 2276a6d35632SScott Long "\7WINDOW4GB" 2277a6d35632SScott Long "\10SCSIUPGD" 2278a6d35632SScott Long "\11SOFTERR" 2279a6d35632SScott Long "\12NORECOND" 2280a6d35632SScott Long "\13SGMAP64" 2281a6d35632SScott Long "\14ALARM" 2282a6d35632SScott Long "\15NONDASD"); 2283a6d35632SScott Long } 228435863739SMike Smith } 228535863739SMike Smith 2286914da7d0SScott Long /* 228735863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 228835863739SMike Smith * same. 228935863739SMike Smith */ 229035863739SMike Smith static char * 229135863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 229235863739SMike Smith { 229335863739SMike Smith int i; 229435863739SMike Smith 229535863739SMike Smith for (i = 0; table[i].string != NULL; i++) 229635863739SMike Smith if (table[i].code == code) 229735863739SMike Smith return(table[i].string); 229835863739SMike Smith return(table[i + 1].string); 229935863739SMike Smith } 230035863739SMike Smith 2301914da7d0SScott Long /* 2302914da7d0SScott Long * Management Interface 2303914da7d0SScott Long */ 230435863739SMike Smith 230535863739SMike Smith static int 230689c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 230735863739SMike Smith { 2308914da7d0SScott Long struct aac_softc *sc; 230935863739SMike Smith 231035863739SMike Smith debug_called(2); 231135863739SMike Smith 2312914da7d0SScott Long sc = dev->si_drv1; 2313914da7d0SScott Long 231435863739SMike Smith /* Check to make sure the device isn't already open */ 231535863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 231635863739SMike Smith return EBUSY; 231735863739SMike Smith } 231835863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 231935863739SMike Smith 232035863739SMike Smith return 0; 232135863739SMike Smith } 232235863739SMike Smith 232335863739SMike Smith static int 232489c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 232535863739SMike Smith { 2326914da7d0SScott Long struct aac_softc *sc; 232735863739SMike Smith 232835863739SMike Smith debug_called(2); 232935863739SMike Smith 2330914da7d0SScott Long sc = dev->si_drv1; 2331914da7d0SScott Long 233235863739SMike Smith /* Mark this unit as no longer open */ 233335863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 233435863739SMike Smith 233535863739SMike Smith return 0; 233635863739SMike Smith } 233735863739SMike Smith 233835863739SMike Smith static int 233989c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 234035863739SMike Smith { 2341914da7d0SScott Long union aac_statrequest *as; 2342914da7d0SScott Long struct aac_softc *sc; 23430b94a66eSMike Smith int error = 0; 2344b88ffdc8SScott Long uint32_t cookie; 234535863739SMike Smith 234635863739SMike Smith debug_called(2); 234735863739SMike Smith 2348914da7d0SScott Long as = (union aac_statrequest *)arg; 2349914da7d0SScott Long sc = dev->si_drv1; 2350914da7d0SScott Long 235135863739SMike Smith switch (cmd) { 23520b94a66eSMike Smith case AACIO_STATS: 23530b94a66eSMike Smith switch (as->as_item) { 23540b94a66eSMike Smith case AACQ_FREE: 23550b94a66eSMike Smith case AACQ_BIO: 23560b94a66eSMike Smith case AACQ_READY: 23570b94a66eSMike Smith case AACQ_BUSY: 2358c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2359c6eafcf2SScott Long sizeof(struct aac_qstat)); 23600b94a66eSMike Smith break; 23610b94a66eSMike Smith default: 23620b94a66eSMike Smith error = ENOENT; 23630b94a66eSMike Smith break; 23640b94a66eSMike Smith } 23650b94a66eSMike Smith break; 23660b94a66eSMike Smith 236735863739SMike Smith case FSACTL_SENDFIB: 2368fb0c27d7SScott Long arg = *(caddr_t*)arg; 2369fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 23700b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 237135863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 237235863739SMike Smith break; 237335863739SMike Smith case FSACTL_AIF_THREAD: 2374fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 23750b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 237635863739SMike Smith error = EINVAL; 237735863739SMike Smith break; 237835863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2379fb0c27d7SScott Long arg = *(caddr_t*)arg; 2380fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 23810b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 238235863739SMike Smith /* 238335863739SMike Smith * Pass the caller out an AdapterFibContext. 238435863739SMike Smith * 238535863739SMike Smith * Note that because we only support one opener, we 238635863739SMike Smith * basically ignore this. Set the caller's context to a magic 238735863739SMike Smith * number just in case. 23880b94a66eSMike Smith * 23890b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 23900b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2391914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2392914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 239335863739SMike Smith */ 2394b88ffdc8SScott Long cookie = (uint32_t)(uintptr_t)sc->aifthread; 2395b88ffdc8SScott Long error = copyout(&cookie, arg, sizeof(cookie)); 239635863739SMike Smith break; 239735863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2398fb0c27d7SScott Long arg = *(caddr_t*)arg; 2399fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 24000b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2401fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 240235863739SMike Smith break; 240335863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2404fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 24050b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 240635863739SMike Smith /* don't do anything here */ 240735863739SMike Smith break; 240835863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2409fb0c27d7SScott Long arg = *(caddr_t*)arg; 2410fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 24110b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2412fb0c27d7SScott Long error = aac_rev_check(sc, arg); 241335863739SMike Smith break; 241436e0bf6eSScott Long case FSACTL_QUERY_DISK: 241536e0bf6eSScott Long arg = *(caddr_t*)arg; 241636e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 241736e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 241836e0bf6eSScott Long error = aac_query_disk(sc, arg); 241936e0bf6eSScott Long break; 242036e0bf6eSScott Long case FSACTL_DELETE_DISK: 242136e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2422914da7d0SScott Long /* 2423914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2424914da7d0SScott Long * container, rather we rely on an AIF coming from the 2425914da7d0SScott Long * controller 2426914da7d0SScott Long */ 242736e0bf6eSScott Long error = 0; 242836e0bf6eSScott Long break; 242935863739SMike Smith default: 2430b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 243135863739SMike Smith error = EINVAL; 243235863739SMike Smith break; 243335863739SMike Smith } 243435863739SMike Smith return(error); 243535863739SMike Smith } 243635863739SMike Smith 2437b3457b51SScott Long static int 243889c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 2439b3457b51SScott Long { 2440b3457b51SScott Long struct aac_softc *sc; 2441b3457b51SScott Long int revents; 2442b3457b51SScott Long 2443b3457b51SScott Long sc = dev->si_drv1; 2444b3457b51SScott Long revents = 0; 2445b3457b51SScott Long 2446bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2447b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2448b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2449b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2450b3457b51SScott Long } 2451bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2452b3457b51SScott Long 2453b3457b51SScott Long if (revents == 0) { 2454b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2455b3457b51SScott Long selrecord(td, &sc->rcv_select); 2456b3457b51SScott Long } 2457b3457b51SScott Long 2458b3457b51SScott Long return (revents); 2459b3457b51SScott Long } 2460b3457b51SScott Long 2461914da7d0SScott Long /* 246235863739SMike Smith * Send a FIB supplied from userspace 246335863739SMike Smith */ 246435863739SMike Smith static int 246535863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 246635863739SMike Smith { 246735863739SMike Smith struct aac_command *cm; 246835863739SMike Smith int size, error; 246935863739SMike Smith 247035863739SMike Smith debug_called(2); 247135863739SMike Smith 247235863739SMike Smith cm = NULL; 247335863739SMike Smith 247435863739SMike Smith /* 247535863739SMike Smith * Get a command 247635863739SMike Smith */ 2477bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 247835863739SMike Smith if (aac_alloc_command(sc, &cm)) { 247935863739SMike Smith error = EBUSY; 248035863739SMike Smith goto out; 248135863739SMike Smith } 248235863739SMike Smith 248335863739SMike Smith /* 248435863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 248535863739SMike Smith */ 2486914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2487914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 248835863739SMike Smith goto out; 248935863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 249035863739SMike Smith if (size > sizeof(struct aac_fib)) { 2491b88ffdc8SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 2492914da7d0SScott Long size, sizeof(struct aac_fib)); 249335863739SMike Smith size = sizeof(struct aac_fib); 249435863739SMike Smith } 249535863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 249635863739SMike Smith goto out; 249735863739SMike Smith cm->cm_fib->Header.Size = size; 2498f6c4dd3fSScott Long cm->cm_timestamp = time_second; 249935863739SMike Smith 250035863739SMike Smith /* 250135863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 250235863739SMike Smith */ 2503d8a0a473SScott Long if ((error = aac_wait_command(cm)) != 0) { 250470545d1aSScott Long device_printf(sc->aac_dev, 250570545d1aSScott Long "aac_wait_command return %d\n", error); 250635863739SMike Smith goto out; 2507b3457b51SScott Long } 250835863739SMike Smith 250935863739SMike Smith /* 251035863739SMike Smith * Copy the FIB and data back out to the caller. 251135863739SMike Smith */ 251235863739SMike Smith size = cm->cm_fib->Header.Size; 251335863739SMike Smith if (size > sizeof(struct aac_fib)) { 2514b88ffdc8SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 2515914da7d0SScott Long size, sizeof(struct aac_fib)); 251635863739SMike Smith size = sizeof(struct aac_fib); 251735863739SMike Smith } 251835863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 251935863739SMike Smith 252035863739SMike Smith out: 2521f6c4dd3fSScott Long if (cm != NULL) { 252235863739SMike Smith aac_release_command(cm); 2523f6c4dd3fSScott Long } 2524ae543596SScott Long 2525bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 252635863739SMike Smith return(error); 252735863739SMike Smith } 252835863739SMike Smith 2529914da7d0SScott Long /* 253035863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 253136e0bf6eSScott Long * If the queue fills up, then drop the older entries. 253235863739SMike Smith */ 253335863739SMike Smith static void 253436e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 253535863739SMike Smith { 253636e0bf6eSScott Long struct aac_aif_command *aif; 253736e0bf6eSScott Long struct aac_container *co, *co_next; 2538cbfd045bSScott Long struct aac_mntinfo *mi; 2539cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 254036e0bf6eSScott Long u_int16_t rsize; 2541b3457b51SScott Long int next, found; 2542795d7dc0SScott Long int count = 0, added = 0, i = 0; 254335863739SMike Smith 254435863739SMike Smith debug_called(2); 254535863739SMike Smith 254636e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 254736e0bf6eSScott Long aac_print_aif(sc, aif); 254836e0bf6eSScott Long 254936e0bf6eSScott Long /* Is it an event that we should care about? */ 255036e0bf6eSScott Long switch (aif->command) { 255136e0bf6eSScott Long case AifCmdEventNotify: 255236e0bf6eSScott Long switch (aif->data.EN.type) { 255336e0bf6eSScott Long case AifEnAddContainer: 255436e0bf6eSScott Long case AifEnDeleteContainer: 255536e0bf6eSScott Long /* 2556914da7d0SScott Long * A container was added or deleted, but the message 2557914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2558914da7d0SScott Long * containers and sort things out. 255936e0bf6eSScott Long */ 256003b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2561cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 256236e0bf6eSScott Long do { 256336e0bf6eSScott Long /* 2564914da7d0SScott Long * Ask the controller for its containers one at 2565914da7d0SScott Long * a time. 2566914da7d0SScott Long * XXX What if the controller's list changes 2567914da7d0SScott Long * midway through this enumaration? 256836e0bf6eSScott Long * XXX This should be done async. 256936e0bf6eSScott Long */ 257039ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 257139ee03c3SScott Long mi->Command = VM_NameServe; 257239ee03c3SScott Long mi->MntType = FT_FILESYS; 2573cbfd045bSScott Long mi->MntCount = i; 257436e0bf6eSScott Long rsize = sizeof(mir); 2575cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2576cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2577795d7dc0SScott Long printf("Error probing container %d\n", 2578914da7d0SScott Long i); 257936e0bf6eSScott Long continue; 258036e0bf6eSScott Long } 2581cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 2582795d7dc0SScott Long /* XXX Need to check if count changed */ 2583795d7dc0SScott Long count = mir->MntRespCount; 258436e0bf6eSScott Long /* 2585914da7d0SScott Long * Check the container against our list. 2586914da7d0SScott Long * co->co_found was already set to 0 in a 2587914da7d0SScott Long * previous run. 258836e0bf6eSScott Long */ 2589cbfd045bSScott Long if ((mir->Status == ST_OK) && 2590cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 259136e0bf6eSScott Long found = 0; 2592914da7d0SScott Long TAILQ_FOREACH(co, 2593914da7d0SScott Long &sc->aac_container_tqh, 2594914da7d0SScott Long co_link) { 259536e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2596cbfd045bSScott Long mir->MntTable[0].ObjectId) { 259736e0bf6eSScott Long co->co_found = 1; 259836e0bf6eSScott Long found = 1; 259936e0bf6eSScott Long break; 260036e0bf6eSScott Long } 260136e0bf6eSScott Long } 2602914da7d0SScott Long /* 2603914da7d0SScott Long * If the container matched, continue 2604914da7d0SScott Long * in the list. 2605914da7d0SScott Long */ 260636e0bf6eSScott Long if (found) { 260736e0bf6eSScott Long i++; 260836e0bf6eSScott Long continue; 260936e0bf6eSScott Long } 261036e0bf6eSScott Long 261136e0bf6eSScott Long /* 2612914da7d0SScott Long * This is a new container. Do all the 261370545d1aSScott Long * appropriate things to set it up. 261470545d1aSScott Long */ 2615cbfd045bSScott Long aac_add_container(sc, mir, 1); 261636e0bf6eSScott Long added = 1; 261736e0bf6eSScott Long } 261836e0bf6eSScott Long i++; 2619795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 2620cbfd045bSScott Long aac_release_sync_fib(sc); 262136e0bf6eSScott Long 262236e0bf6eSScott Long /* 2623914da7d0SScott Long * Go through our list of containers and see which ones 2624914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2625914da7d0SScott Long * list them they must have been deleted. Do the 2626914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2627914da7d0SScott Long * the co->co_found field. 262836e0bf6eSScott Long */ 262936e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 263036e0bf6eSScott Long while (co != NULL) { 263136e0bf6eSScott Long if (co->co_found == 0) { 2632914da7d0SScott Long device_delete_child(sc->aac_dev, 2633914da7d0SScott Long co->co_disk); 263436e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2635bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 2636914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2637914da7d0SScott Long co_link); 2638bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 263936e0bf6eSScott Long FREE(co, M_AACBUF); 264036e0bf6eSScott Long co = co_next; 264136e0bf6eSScott Long } else { 264236e0bf6eSScott Long co->co_found = 0; 264336e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 264436e0bf6eSScott Long } 264536e0bf6eSScott Long } 264636e0bf6eSScott Long 264736e0bf6eSScott Long /* Attach the newly created containers */ 264836e0bf6eSScott Long if (added) 264936e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 265036e0bf6eSScott Long 265136e0bf6eSScott Long break; 265236e0bf6eSScott Long 265336e0bf6eSScott Long default: 265436e0bf6eSScott Long break; 265536e0bf6eSScott Long } 265636e0bf6eSScott Long 265736e0bf6eSScott Long default: 265836e0bf6eSScott Long break; 265936e0bf6eSScott Long } 266036e0bf6eSScott Long 266136e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2662bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 266335863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 266435863739SMike Smith if (next != sc->aac_aifq_tail) { 266535863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 266635863739SMike Smith sc->aac_aifq_head = next; 2667b3457b51SScott Long 2668b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 266935863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 267035863739SMike Smith wakeup(sc->aac_aifq); 2671b3457b51SScott Long /* Wakeup any poll()ers */ 2672512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 267335863739SMike Smith } 2674bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 267536e0bf6eSScott Long 267636e0bf6eSScott Long return; 267735863739SMike Smith } 267835863739SMike Smith 2679914da7d0SScott Long /* 26800b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 268136e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 268236e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 268336e0bf6eSScott Long * returning what the card reported. 268435863739SMike Smith */ 268535863739SMike Smith static int 2686fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 268735863739SMike Smith { 268835863739SMike Smith struct aac_rev_check rev_check; 268935863739SMike Smith struct aac_rev_check_resp rev_check_resp; 269035863739SMike Smith int error = 0; 269135863739SMike Smith 269235863739SMike Smith debug_called(2); 269335863739SMike Smith 269435863739SMike Smith /* 269535863739SMike Smith * Copyin the revision struct from userspace 269635863739SMike Smith */ 2697c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2698c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 269935863739SMike Smith return error; 270035863739SMike Smith } 270135863739SMike Smith 2702914da7d0SScott Long debug(2, "Userland revision= %d\n", 2703914da7d0SScott Long rev_check.callingRevision.buildNumber); 270435863739SMike Smith 270535863739SMike Smith /* 270635863739SMike Smith * Doctor up the response struct. 270735863739SMike Smith */ 270835863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2709914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2710914da7d0SScott Long sc->aac_revision.external.ul; 2711914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2712914da7d0SScott Long sc->aac_revision.buildNumber; 271335863739SMike Smith 2714c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2715c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 271635863739SMike Smith } 271735863739SMike Smith 2718914da7d0SScott Long /* 271935863739SMike Smith * Pass the caller the next AIF in their queue 272035863739SMike Smith */ 272135863739SMike Smith static int 2722fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 272335863739SMike Smith { 272435863739SMike Smith struct get_adapter_fib_ioctl agf; 27259e2e96d8SScott Long int error; 272635863739SMike Smith 272735863739SMike Smith debug_called(2); 272835863739SMike Smith 272935863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 273035863739SMike Smith 273135863739SMike Smith /* 273235863739SMike Smith * Check the magic number that we gave the caller. 273335863739SMike Smith */ 2734b88ffdc8SScott Long if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 273535863739SMike Smith error = EFAULT; 273635863739SMike Smith } else { 2737fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 273835863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 273935863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 274035863739SMike Smith while (error == EAGAIN) { 2741914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2742914da7d0SScott Long PCATCH, "aacaif", 0); 274335863739SMike Smith if (error == 0) 2744914da7d0SScott Long error = aac_return_aif(sc, 2745914da7d0SScott Long agf.AifFib); 274635863739SMike Smith } 274735863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 274835863739SMike Smith } 274935863739SMike Smith } 275035863739SMike Smith } 275135863739SMike Smith return(error); 275235863739SMike Smith } 275335863739SMike Smith 2754914da7d0SScott Long /* 27550b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 27560b94a66eSMike Smith */ 27570b94a66eSMike Smith static int 2758fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 27590b94a66eSMike Smith { 27603df780cfSScott Long int next, error; 27610b94a66eSMike Smith 27620b94a66eSMike Smith debug_called(2); 27630b94a66eSMike Smith 2764bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 27650b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 2766bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 27673df780cfSScott Long return (EAGAIN); 27683df780cfSScott Long } 27693df780cfSScott Long 27703df780cfSScott Long next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 27713df780cfSScott Long error = copyout(&sc->aac_aifq[next], uptr, 2772c6eafcf2SScott Long sizeof(struct aac_aif_command)); 277336e0bf6eSScott Long if (error) 277470545d1aSScott Long device_printf(sc->aac_dev, 277570545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 27763df780cfSScott Long else 27773df780cfSScott Long sc->aac_aifq_tail = next; 27783df780cfSScott Long 2779bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 27800b94a66eSMike Smith return(error); 27810b94a66eSMike Smith } 278236e0bf6eSScott Long 2783914da7d0SScott Long /* 278436e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 278536e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 278636e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 278736e0bf6eSScott Long */ 278836e0bf6eSScott Long static int 278936e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 279036e0bf6eSScott Long { 279136e0bf6eSScott Long struct aac_query_disk query_disk; 279236e0bf6eSScott Long struct aac_container *co; 2793914da7d0SScott Long struct aac_disk *disk; 279436e0bf6eSScott Long int error, id; 279536e0bf6eSScott Long 279636e0bf6eSScott Long debug_called(2); 279736e0bf6eSScott Long 2798914da7d0SScott Long disk = NULL; 2799914da7d0SScott Long 2800914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2801914da7d0SScott Long sizeof(struct aac_query_disk)); 280236e0bf6eSScott Long if (error) 280336e0bf6eSScott Long return (error); 280436e0bf6eSScott Long 280536e0bf6eSScott Long id = query_disk.ContainerNumber; 280636e0bf6eSScott Long if (id == -1) 280736e0bf6eSScott Long return (EINVAL); 280836e0bf6eSScott Long 2809bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 281036e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 281136e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 281236e0bf6eSScott Long break; 281336e0bf6eSScott Long } 281436e0bf6eSScott Long 281536e0bf6eSScott Long if (co == NULL) { 281636e0bf6eSScott Long query_disk.Valid = 0; 281736e0bf6eSScott Long query_disk.Locked = 0; 281836e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 281936e0bf6eSScott Long } else { 282036e0bf6eSScott Long disk = device_get_softc(co->co_disk); 282136e0bf6eSScott Long query_disk.Valid = 1; 2822914da7d0SScott Long query_disk.Locked = 2823914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 282436e0bf6eSScott Long query_disk.Deleted = 0; 2825b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 282636e0bf6eSScott Long query_disk.Target = disk->unit; 282736e0bf6eSScott Long query_disk.Lun = 0; 282836e0bf6eSScott Long query_disk.UnMapped = 0; 28297540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 28300b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 283136e0bf6eSScott Long } 2832bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 283336e0bf6eSScott Long 2834914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2835914da7d0SScott Long sizeof(struct aac_query_disk)); 283636e0bf6eSScott Long 283736e0bf6eSScott Long return (error); 283836e0bf6eSScott Long } 283936e0bf6eSScott Long 2840fe3cb0e1SScott Long static void 2841fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2842fe3cb0e1SScott Long { 2843fe3cb0e1SScott Long struct aac_fib *fib; 2844fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2845fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2846fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2847fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2848fe3cb0e1SScott Long struct aac_getbusinf businfo; 284970545d1aSScott Long struct aac_sim *caminf; 2850fe3cb0e1SScott Long device_t child; 2851fe3cb0e1SScott Long int i, found, error; 2852fe3cb0e1SScott Long 285303b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2854fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 285539ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2856fe3cb0e1SScott Long 2857fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2858fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2859fe3cb0e1SScott Long c_cmd->param = 0; 2860fe3cb0e1SScott Long 2861fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2862fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2863fe3cb0e1SScott Long if (error) { 2864fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2865fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2866fe3cb0e1SScott Long aac_release_sync_fib(sc); 2867fe3cb0e1SScott Long return; 2868fe3cb0e1SScott Long } 2869fe3cb0e1SScott Long 2870fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2871fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2872fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2873fe3cb0e1SScott Long c_resp->Status); 2874fe3cb0e1SScott Long aac_release_sync_fib(sc); 2875fe3cb0e1SScott Long return; 2876fe3cb0e1SScott Long } 2877fe3cb0e1SScott Long 2878fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2879fe3cb0e1SScott Long 2880fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 288139ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 288239ee03c3SScott Long 2883fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2884fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2885fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2886fe3cb0e1SScott Long vmi->ObjId = 0; 2887fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2888fe3cb0e1SScott Long 2889fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2890fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2891fe3cb0e1SScott Long if (error) { 2892fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2893fe3cb0e1SScott Long error); 2894fe3cb0e1SScott Long aac_release_sync_fib(sc); 2895fe3cb0e1SScott Long return; 2896fe3cb0e1SScott Long } 2897fe3cb0e1SScott Long 2898fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2899fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2900fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2901fe3cb0e1SScott Long vmi_resp->Status); 2902fe3cb0e1SScott Long aac_release_sync_fib(sc); 2903fe3cb0e1SScott Long return; 2904fe3cb0e1SScott Long } 2905fe3cb0e1SScott Long 2906fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2907fe3cb0e1SScott Long aac_release_sync_fib(sc); 2908fe3cb0e1SScott Long 2909fe3cb0e1SScott Long found = 0; 2910fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2911fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2912fe3cb0e1SScott Long continue; 2913fe3cb0e1SScott Long 2914a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2915a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 2916fe3cb0e1SScott Long if (caminf == NULL) 2917fe3cb0e1SScott Long continue; 2918fe3cb0e1SScott Long 2919fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2920fe3cb0e1SScott Long if (child == NULL) { 2921fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2922fe3cb0e1SScott Long continue; 2923fe3cb0e1SScott Long } 2924fe3cb0e1SScott Long 2925fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2926fe3cb0e1SScott Long caminf->BusNumber = i; 2927fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2928fe3cb0e1SScott Long caminf->aac_sc = sc; 2929ddb8683eSScott Long caminf->sim_dev = child; 2930fe3cb0e1SScott Long 2931fe3cb0e1SScott Long device_set_ivars(child, caminf); 2932fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 293370545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2934fe3cb0e1SScott Long 2935fe3cb0e1SScott Long found = 1; 2936fe3cb0e1SScott Long } 2937fe3cb0e1SScott Long 2938fe3cb0e1SScott Long if (found) 2939fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2940fe3cb0e1SScott Long 2941fe3cb0e1SScott Long return; 2942fe3cb0e1SScott Long } 2943