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); 71cd481291SScott Long static int aac_map_command(struct aac_command *cm); 7235863739SMike Smith static void aac_complete(void *context, int pending); 7335863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7435863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 7535863739SMike Smith static int aac_wait_command(struct aac_command *cm, int timeout); 7670545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 7735863739SMike Smith 7835863739SMike Smith /* Command Buffer Management */ 79cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 80cd481291SScott Long int nseg, int error); 81c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 82c6eafcf2SScott Long int nseg, int error); 830b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 848480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 8535863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 8635863739SMike Smith 8735863739SMike Smith /* Hardware Interface */ 88c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 89c6eafcf2SScott Long int error); 90fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9135863739SMike Smith static int aac_init(struct aac_softc *sc); 9235863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 93c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 94c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 95c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 96f6c4dd3fSScott Long struct aac_command *cm); 97c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 98914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 9936e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10036e0bf6eSScott Long struct aac_fib *fib); 10135863739SMike Smith 102b3457b51SScott Long /* Falcon/PPC interface */ 103b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 104b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 105b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 106b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 107b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 108b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 109b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 110a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 111b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 112b3457b51SScott Long 113b3457b51SScott Long struct aac_interface aac_fa_interface = { 114b3457b51SScott Long aac_fa_get_fwstatus, 115b3457b51SScott Long aac_fa_qnotify, 116b3457b51SScott Long aac_fa_get_istatus, 117b3457b51SScott Long aac_fa_clear_istatus, 118b3457b51SScott Long aac_fa_set_mailbox, 119a6d35632SScott Long aac_fa_get_mailbox, 120b3457b51SScott Long aac_fa_set_interrupts 121b3457b51SScott Long }; 122b3457b51SScott Long 12335863739SMike Smith /* StrongARM interface */ 12435863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 12535863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 12635863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 12735863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 12835863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 129c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 130c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 131a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13235863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 13335863739SMike Smith 13435863739SMike Smith struct aac_interface aac_sa_interface = { 13535863739SMike Smith aac_sa_get_fwstatus, 13635863739SMike Smith aac_sa_qnotify, 13735863739SMike Smith aac_sa_get_istatus, 13835863739SMike Smith aac_sa_clear_istatus, 13935863739SMike Smith aac_sa_set_mailbox, 140a6d35632SScott Long aac_sa_get_mailbox, 14135863739SMike Smith aac_sa_set_interrupts 14235863739SMike Smith }; 14335863739SMike Smith 14435863739SMike Smith /* i960Rx interface */ 14535863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 14635863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 14735863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 14835863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 14935863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 150c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 151c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 152a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 15335863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 15435863739SMike Smith 15535863739SMike Smith struct aac_interface aac_rx_interface = { 15635863739SMike Smith aac_rx_get_fwstatus, 15735863739SMike Smith aac_rx_qnotify, 15835863739SMike Smith aac_rx_get_istatus, 15935863739SMike Smith aac_rx_clear_istatus, 16035863739SMike Smith aac_rx_set_mailbox, 161a6d35632SScott Long aac_rx_get_mailbox, 16235863739SMike Smith aac_rx_set_interrupts 16335863739SMike Smith }; 16435863739SMike Smith 16535863739SMike Smith /* Debugging and Diagnostics */ 16635863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1676965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 168c6eafcf2SScott Long u_int32_t code); 16935863739SMike Smith 17035863739SMike Smith /* Management Interface */ 17135863739SMike Smith static d_open_t aac_open; 17235863739SMike Smith static d_close_t aac_close; 17335863739SMike Smith static d_ioctl_t aac_ioctl; 174b3457b51SScott Long static d_poll_t aac_poll; 175c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 176c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 17736e0bf6eSScott Long struct aac_fib *fib); 178fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 179fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 180fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 18136e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 18235863739SMike Smith 18335863739SMike Smith static struct cdevsw aac_cdevsw = { 1847ac40f5fSPoul-Henning Kamp .d_open = aac_open, 1857ac40f5fSPoul-Henning Kamp .d_close = aac_close, 1867ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 1877ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 1887ac40f5fSPoul-Henning Kamp .d_name = "aac", 18935863739SMike Smith }; 19035863739SMike Smith 19136e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 19236e0bf6eSScott Long 1933d04a9d7SScott Long /* sysctl node */ 1943d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 1953d04a9d7SScott Long 196914da7d0SScott Long /* 197914da7d0SScott Long * Device Interface 198914da7d0SScott Long */ 19935863739SMike Smith 200914da7d0SScott Long /* 20135863739SMike Smith * Initialise the controller and softc 20235863739SMike Smith */ 20335863739SMike Smith int 20435863739SMike Smith aac_attach(struct aac_softc *sc) 20535863739SMike Smith { 20635863739SMike Smith int error, unit; 20735863739SMike Smith 20835863739SMike Smith debug_called(1); 20935863739SMike Smith 21035863739SMike Smith /* 21135863739SMike Smith * Initialise per-controller queues. 21235863739SMike Smith */ 2130b94a66eSMike Smith aac_initq_free(sc); 2140b94a66eSMike Smith aac_initq_ready(sc); 2150b94a66eSMike Smith aac_initq_busy(sc); 2160b94a66eSMike Smith aac_initq_bio(sc); 21735863739SMike Smith 21835863739SMike Smith /* 21935863739SMike Smith * Initialise command-completion task. 22035863739SMike Smith */ 22135863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 22235863739SMike Smith 22335863739SMike Smith /* disable interrupts before we enable anything */ 22435863739SMike Smith AAC_MASK_INTERRUPTS(sc); 22535863739SMike Smith 22635863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 22735863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 22835863739SMike Smith 22935863739SMike Smith /* 230fe94b852SScott Long * Check that the firmware on the card is supported. 231fe94b852SScott Long */ 232fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 233fe94b852SScott Long return(error); 234fe94b852SScott Long 235f6b1c44dSScott Long /* 236f6b1c44dSScott Long * Initialize locks 237f6b1c44dSScott Long */ 238cbfd045bSScott Long AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 239f6b1c44dSScott Long AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 240f6b1c44dSScott Long AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock"); 241f6b1c44dSScott Long AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 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 318fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 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)); 387c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 388914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 389914da7d0SScott Long AAC_LOCK_RELEASE(&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 528fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 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); 55835863739SMike Smith 55935863739SMike Smith return(0); 56035863739SMike Smith } 56135863739SMike Smith 562914da7d0SScott Long /* 56335863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 56435863739SMike Smith */ 56535863739SMike Smith int 56635863739SMike Smith aac_suspend(device_t dev) 56735863739SMike Smith { 568914da7d0SScott Long struct aac_softc *sc; 56935863739SMike Smith 57035863739SMike Smith debug_called(1); 571914da7d0SScott Long 572914da7d0SScott Long sc = device_get_softc(dev); 573914da7d0SScott Long 57435863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 57535863739SMike Smith 57635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 57735863739SMike Smith return(0); 57835863739SMike Smith } 57935863739SMike Smith 580914da7d0SScott Long /* 58135863739SMike Smith * Bring the controller back to a state ready for operation. 58235863739SMike Smith */ 58335863739SMike Smith int 58435863739SMike Smith aac_resume(device_t dev) 58535863739SMike Smith { 586914da7d0SScott Long struct aac_softc *sc; 58735863739SMike Smith 58835863739SMike Smith debug_called(1); 589914da7d0SScott Long 590914da7d0SScott Long sc = device_get_softc(dev); 591914da7d0SScott Long 59235863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 59335863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 59435863739SMike Smith return(0); 59535863739SMike Smith } 59635863739SMike Smith 597914da7d0SScott Long /* 59835863739SMike Smith * Take an interrupt. 59935863739SMike Smith */ 60035863739SMike Smith void 60135863739SMike Smith aac_intr(void *arg) 60235863739SMike Smith { 603914da7d0SScott Long struct aac_softc *sc; 604f30ac74cSScott Long u_int32_t *resp_queue; 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 /* 612f30ac74cSScott Long * Optimize the common case of adapter response interrupts. 613f30ac74cSScott Long * We must read from the card prior to processing the responses 614f30ac74cSScott Long * to ensure the clear is flushed prior to accessing the queues. 615f30ac74cSScott Long * Reading the queues from local memory might save us a PCI read. 616f30ac74cSScott Long */ 617f30ac74cSScott Long resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; 618f30ac74cSScott Long if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) 619f30ac74cSScott Long reason = AAC_DB_RESPONSE_READY; 620f30ac74cSScott Long else 62135863739SMike Smith reason = AAC_GET_ISTATUS(sc); 622f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 623f30ac74cSScott Long (void)AAC_GET_ISTATUS(sc); 624f30ac74cSScott Long 625f30ac74cSScott Long /* It's not ok to return here because of races with the previous step */ 626f30ac74cSScott Long if (reason & AAC_DB_RESPONSE_READY) 6279c3a7fceSScott Long /* handle completion processing */ 628ae543596SScott Long taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 62935863739SMike Smith 630b3457b51SScott Long /* controller wants to talk to the log */ 63170545d1aSScott Long if (reason & AAC_DB_PRINTF) { 63270545d1aSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 63370545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_PRINTF; 63470545d1aSScott Long } else 63536e0bf6eSScott Long aac_print_printf(sc); 63670545d1aSScott Long } 63735863739SMike Smith 63835863739SMike Smith /* controller has a message for us? */ 63935863739SMike Smith if (reason & AAC_DB_COMMAND_READY) { 64036e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 64170545d1aSScott Long sc->aifflags |= AAC_AIFFLAGS_AIF; 64270545d1aSScott Long } else { 64370545d1aSScott Long /* 64470545d1aSScott Long * XXX If the kthread is dead and we're at this point, 64570545d1aSScott Long * there are bigger problems than just figuring out 64670545d1aSScott Long * what to do with an AIF. 64770545d1aSScott Long */ 64870545d1aSScott Long } 64970545d1aSScott Long 65070545d1aSScott Long } 65170545d1aSScott Long 65270545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) != 0) 65370545d1aSScott Long /* XXX Should this be done with cv_signal? */ 65436e0bf6eSScott Long wakeup(sc->aifthread); 65536e0bf6eSScott Long } 65635863739SMike Smith 657c6eafcf2SScott Long /* 658914da7d0SScott Long * Command Processing 659914da7d0SScott Long */ 66035863739SMike Smith 661914da7d0SScott Long /* 66235863739SMike Smith * Start as much queued I/O as possible on the controller 66335863739SMike Smith */ 664fe3cb0e1SScott Long void 66535863739SMike Smith aac_startio(struct aac_softc *sc) 66635863739SMike Smith { 66735863739SMike Smith struct aac_command *cm; 66835863739SMike Smith 66935863739SMike Smith debug_called(2); 67035863739SMike Smith 671cd481291SScott Long if (sc->flags & AAC_QUEUE_FRZN) 672cd481291SScott Long return; 673cd481291SScott Long 67435863739SMike Smith for (;;) { 675914da7d0SScott Long /* 676914da7d0SScott Long * Try to get a command that's been put off for lack of 677914da7d0SScott Long * resources 678914da7d0SScott Long */ 67935863739SMike Smith cm = aac_dequeue_ready(sc); 68035863739SMike Smith 681914da7d0SScott Long /* 682914da7d0SScott Long * Try to build a command off the bio queue (ignore error 683914da7d0SScott Long * return) 684914da7d0SScott Long */ 6850b94a66eSMike Smith if (cm == NULL) 68635863739SMike Smith aac_bio_command(sc, &cm); 68735863739SMike Smith 68835863739SMike Smith /* nothing to do? */ 68935863739SMike Smith if (cm == NULL) 69035863739SMike Smith break; 69135863739SMike Smith 69235863739SMike Smith /* try to give the command to the controller */ 693cd481291SScott Long if (aac_map_command(cm) == EBUSY) { 69435863739SMike Smith /* put it on the ready queue for later */ 69535863739SMike Smith aac_requeue_ready(cm); 69635863739SMike Smith break; 69735863739SMike Smith } 69835863739SMike Smith } 69935863739SMike Smith } 70035863739SMike Smith 701914da7d0SScott Long /* 70235863739SMike Smith * Deliver a command to the controller; allocate controller resources at the 70335863739SMike Smith * last moment when possible. 70435863739SMike Smith */ 70535863739SMike Smith static int 706cd481291SScott Long aac_map_command(struct aac_command *cm) 70735863739SMike Smith { 708914da7d0SScott Long struct aac_softc *sc; 709ed5c5fb4SMike Smith int error; 71035863739SMike Smith 71135863739SMike Smith debug_called(2); 71235863739SMike Smith 713914da7d0SScott Long sc = cm->cm_sc; 714cd481291SScott Long error = 0; 715914da7d0SScott Long 716cd481291SScott Long /* don't map more than once */ 717cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 718cd481291SScott Long return (0); 71935863739SMike Smith 720cd481291SScott Long if (cm->cm_datalen != 0) { 721cd481291SScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 722cd481291SScott Long cm->cm_data, cm->cm_datalen, 723cd481291SScott Long aac_map_command_sg, cm, 0); 724cd481291SScott Long if (error == EINPROGRESS) { 725cd481291SScott Long debug(1, "freezing queue\n"); 726cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 727cd481291SScott Long error = 0; 728cd481291SScott Long } 7298778f63dSScott Long } else { 7308778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 731cd481291SScott Long } 7320b94a66eSMike Smith return (error); 73335863739SMike Smith } 73435863739SMike Smith 735914da7d0SScott Long /* 73635863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 73735863739SMike Smith */ 73835863739SMike Smith static void 73970545d1aSScott Long aac_command_thread(struct aac_softc *sc) 74035863739SMike Smith { 74135863739SMike Smith struct aac_fib *fib; 74235863739SMike Smith u_int32_t fib_size; 74336e0bf6eSScott Long int size; 74435863739SMike Smith 74536e0bf6eSScott Long debug_called(2); 74635863739SMike Smith 74736e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_RUNNING; 74836e0bf6eSScott Long 74936e0bf6eSScott Long while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 75070545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 75170545d1aSScott Long tsleep(sc->aifthread, PRIBIO, "aifthd", 75270545d1aSScott Long AAC_PERIODIC_INTERVAL * hz); 75336e0bf6eSScott Long 75470545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 75570545d1aSScott Long aac_timeout(sc); 75670545d1aSScott Long 75770545d1aSScott Long /* Check the hardware printf message buffer */ 75870545d1aSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) { 75970545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_PRINTF; 76070545d1aSScott Long aac_print_printf(sc); 76170545d1aSScott Long } 76270545d1aSScott Long 763ae543596SScott Long /* See if any FIBs need to be allocated */ 764ae543596SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 765ae543596SScott Long AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 766ae543596SScott Long aac_alloc_commands(sc); 767ae543596SScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 768ae543596SScott Long AAC_LOCK_RELEASE(&sc->aac_io_lock); 769ae543596SScott Long } 77070545d1aSScott Long 771ae543596SScott Long /* While we're here, check to see if any commands are stuck */ 772ae543596SScott Long while (sc->aifflags & AAC_AIFFLAGS_AIF) { 773914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 77470545d1aSScott Long &fib_size, &fib)) { 77570545d1aSScott Long sc->aifflags &= ~AAC_AIFFLAGS_AIF; 77635863739SMike Smith break; /* nothing to do */ 77770545d1aSScott Long } 77835863739SMike Smith 77936e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 78036e0bf6eSScott Long 78135863739SMike Smith switch (fib->Header.Command) { 78235863739SMike Smith case AifRequest: 78336e0bf6eSScott Long aac_handle_aif(sc, fib); 78435863739SMike Smith break; 78535863739SMike Smith default: 786914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 787914da7d0SScott Long "from controller\n"); 78835863739SMike Smith break; 78935863739SMike Smith } 79035863739SMike Smith 79136e0bf6eSScott Long if ((fib->Header.XferState == 0) || 79236e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 79336e0bf6eSScott Long break; 79436e0bf6eSScott Long 79570545d1aSScott Long /* Return the AIF to the controller. */ 79636e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 79736e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 79836e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 79936e0bf6eSScott Long 80036e0bf6eSScott Long /* XXX Compute the Size field? */ 80136e0bf6eSScott Long size = fib->Header.Size; 80236e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 80336e0bf6eSScott Long size = sizeof(struct aac_fib); 80436e0bf6eSScott Long fib->Header.Size = size; 80536e0bf6eSScott Long } 80636e0bf6eSScott Long /* 807914da7d0SScott Long * Since we did not generate this command, it 808914da7d0SScott Long * cannot go through the normal 809914da7d0SScott Long * enqueue->startio chain. 81036e0bf6eSScott Long */ 811914da7d0SScott Long aac_enqueue_response(sc, 812914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 813914da7d0SScott Long fib); 81436e0bf6eSScott Long } 81536e0bf6eSScott Long } 81636e0bf6eSScott Long } 81736e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 81836e0bf6eSScott Long wakeup(sc->aac_dev); 81936e0bf6eSScott Long 82036e0bf6eSScott Long mtx_lock(&Giant); 82136e0bf6eSScott Long kthread_exit(0); 82235863739SMike Smith } 82335863739SMike Smith 824914da7d0SScott Long /* 8259c3a7fceSScott Long * Process completed commands. 82635863739SMike Smith */ 82735863739SMike Smith static void 8289c3a7fceSScott Long aac_complete(void *context, int pending) 82935863739SMike Smith { 8309c3a7fceSScott Long struct aac_softc *sc; 83135863739SMike Smith struct aac_command *cm; 83235863739SMike Smith struct aac_fib *fib; 83335863739SMike Smith u_int32_t fib_size; 83435863739SMike Smith 83535863739SMike Smith debug_called(2); 83635863739SMike Smith 8379c3a7fceSScott Long sc = (struct aac_softc *)context; 8389c3a7fceSScott Long 839ae543596SScott Long AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 840ae543596SScott Long 8419c3a7fceSScott Long /* pull completed commands off the queue */ 84235863739SMike Smith for (;;) { 84335863739SMike Smith /* look for completed FIBs on our queue */ 844914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 845914da7d0SScott Long &fib)) 84635863739SMike Smith break; /* nothing to do */ 84735863739SMike Smith 84835863739SMike Smith /* get the command, unmap and queue for later processing */ 849cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 85035863739SMike Smith if (cm == NULL) { 85135863739SMike Smith AAC_PRINT_FIB(sc, fib); 8529c3a7fceSScott Long break; 8539c3a7fceSScott Long } 8549c3a7fceSScott Long 8550b94a66eSMike Smith aac_remove_busy(cm); 85635863739SMike Smith aac_unmap_command(cm); /* XXX defer? */ 85735863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 85835863739SMike Smith 85935863739SMike Smith /* is there a completion handler? */ 86035863739SMike Smith if (cm->cm_complete != NULL) { 86135863739SMike Smith cm->cm_complete(cm); 86235863739SMike Smith } else { 86335863739SMike Smith /* assume that someone is sleeping on this command */ 86435863739SMike Smith wakeup(cm); 86535863739SMike Smith } 86635863739SMike Smith } 8670b94a66eSMike Smith 8680b94a66eSMike Smith /* see if we can start some more I/O */ 869cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 8700b94a66eSMike Smith aac_startio(sc); 871ae543596SScott Long 872ae543596SScott Long AAC_LOCK_RELEASE(&sc->aac_io_lock); 87335863739SMike Smith } 87435863739SMike Smith 875914da7d0SScott Long /* 87635863739SMike Smith * Handle a bio submitted from a disk device. 87735863739SMike Smith */ 87835863739SMike Smith void 87935863739SMike Smith aac_submit_bio(struct bio *bp) 88035863739SMike Smith { 881914da7d0SScott Long struct aac_disk *ad; 882914da7d0SScott Long struct aac_softc *sc; 88335863739SMike Smith 88435863739SMike Smith debug_called(2); 88535863739SMike Smith 8867540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 887914da7d0SScott Long sc = ad->ad_controller; 888914da7d0SScott Long 88935863739SMike Smith /* queue the BIO and try to get some work done */ 8900b94a66eSMike Smith aac_enqueue_bio(sc, bp); 89135863739SMike Smith aac_startio(sc); 89235863739SMike Smith } 89335863739SMike Smith 894914da7d0SScott Long /* 89535863739SMike Smith * Get a bio and build a command to go with it. 89635863739SMike Smith */ 89735863739SMike Smith static int 89835863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 89935863739SMike Smith { 90035863739SMike Smith struct aac_command *cm; 90135863739SMike Smith struct aac_fib *fib; 90235863739SMike Smith struct aac_disk *ad; 90335863739SMike Smith struct bio *bp; 90435863739SMike Smith 90535863739SMike Smith debug_called(2); 90635863739SMike Smith 90735863739SMike Smith /* get the resources we will need */ 90835863739SMike Smith cm = NULL; 9090b94a66eSMike Smith if ((bp = aac_dequeue_bio(sc)) == NULL) 91035863739SMike Smith goto fail; 91135863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 91235863739SMike Smith goto fail; 91335863739SMike Smith 91435863739SMike Smith /* fill out the command */ 9150b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9160b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9170b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 91835863739SMike Smith cm->cm_private = bp; 9190b94a66eSMike Smith cm->cm_timestamp = time_second; 92036e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 92135863739SMike Smith 92235863739SMike Smith /* build the FIB */ 92335863739SMike Smith fib = cm->cm_fib; 924b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 92535863739SMike Smith fib->Header.XferState = 92635863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 92735863739SMike Smith AAC_FIBSTATE_INITIALISED | 928f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 92935863739SMike Smith AAC_FIBSTATE_FROMHOST | 93035863739SMike Smith AAC_FIBSTATE_REXPECTED | 931f30ac74cSScott Long AAC_FIBSTATE_NORM | 932f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 933f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 93435863739SMike Smith 93535863739SMike Smith /* build the read/write request */ 9367540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 937b85f5808SScott Long 938b85f5808SScott Long if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 939b85f5808SScott Long fib->Header.Command = ContainerCommand; 9409e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 941b85f5808SScott Long struct aac_blockread *br; 94235863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 94335863739SMike Smith br->Command = VM_CtBlockRead; 94435863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 94535863739SMike Smith br->BlockNumber = bp->bio_pblkno; 94635863739SMike Smith br->ByteCount = bp->bio_bcount; 94735863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 94835863739SMike Smith cm->cm_sgtable = &br->SgMap; 94935863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 95035863739SMike Smith } else { 951b85f5808SScott Long struct aac_blockwrite *bw; 95235863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 95335863739SMike Smith bw->Command = VM_CtBlockWrite; 95435863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 95535863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 95635863739SMike Smith bw->ByteCount = bp->bio_bcount; 957b85f5808SScott Long bw->Stable = CUNSTABLE; 95835863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 95935863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 96035863739SMike Smith cm->cm_sgtable = &bw->SgMap; 96135863739SMike Smith } 962b85f5808SScott Long } else { 963b85f5808SScott Long fib->Header.Command = ContainerCommand64; 964b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 965b85f5808SScott Long struct aac_blockread64 *br; 966b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 967b85f5808SScott Long br->Command = VM_CtHostRead64; 968b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 969b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 970b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 971b85f5808SScott Long br->Pad = 0; 972b85f5808SScott Long br->Flags = 0; 973b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 974b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 975b85f5808SScott Long (struct aac_sg_table64 *)cm->cm_sgtable = &br->SgMap64; 976b85f5808SScott Long } else { 977b85f5808SScott Long struct aac_blockwrite64 *bw; 978b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 979b85f5808SScott Long bw->Command = VM_CtHostWrite64; 980b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 981b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 982b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 983b85f5808SScott Long bw->Pad = 0; 984b85f5808SScott Long bw->Flags = 0; 985b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 986b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 987b85f5808SScott Long (struct aac_sg_table64 *)cm->cm_sgtable = &bw->SgMap64; 988b85f5808SScott Long } 989b85f5808SScott Long } 99035863739SMike Smith 99135863739SMike Smith *cmp = cm; 99235863739SMike Smith return(0); 99335863739SMike Smith 99435863739SMike Smith fail: 99535863739SMike Smith if (bp != NULL) 9960b94a66eSMike Smith aac_enqueue_bio(sc, bp); 99735863739SMike Smith if (cm != NULL) 99835863739SMike Smith aac_release_command(cm); 99935863739SMike Smith return(ENOMEM); 100035863739SMike Smith } 100135863739SMike Smith 1002914da7d0SScott Long /* 100335863739SMike Smith * Handle a bio-instigated command that has been completed. 100435863739SMike Smith */ 100535863739SMike Smith static void 100635863739SMike Smith aac_bio_complete(struct aac_command *cm) 100735863739SMike Smith { 100835863739SMike Smith struct aac_blockread_response *brr; 100935863739SMike Smith struct aac_blockwrite_response *bwr; 101035863739SMike Smith struct bio *bp; 101135863739SMike Smith AAC_FSAStatus status; 101235863739SMike Smith 101335863739SMike Smith /* fetch relevant status and then release the command */ 101435863739SMike Smith bp = (struct bio *)cm->cm_private; 10159e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 101635863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 101735863739SMike Smith status = brr->Status; 101835863739SMike Smith } else { 101935863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 102035863739SMike Smith status = bwr->Status; 102135863739SMike Smith } 102235863739SMike Smith aac_release_command(cm); 102335863739SMike Smith 102435863739SMike Smith /* fix up the bio based on status */ 102535863739SMike Smith if (status == ST_OK) { 102635863739SMike Smith bp->bio_resid = 0; 102735863739SMike Smith } else { 102835863739SMike Smith bp->bio_error = EIO; 102935863739SMike Smith bp->bio_flags |= BIO_ERROR; 10300b94a66eSMike Smith /* pass an error string out to the disk layer */ 1031914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1032914da7d0SScott Long status); 103335863739SMike Smith } 10340b94a66eSMike Smith aac_biodone(bp); 103535863739SMike Smith } 103635863739SMike Smith 1037914da7d0SScott Long /* 103835863739SMike Smith * Submit a command to the controller, return when it completes. 1039b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1040b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1041b3457b51SScott Long * because there is a risk that a signal could wakeup the tsleep before 1042b3457b51SScott Long * the card has a chance to complete the command. The passed in timeout 1043b3457b51SScott Long * is ignored for the same reason. Since there is no way to cancel a 1044b3457b51SScott Long * command in progress, we should probably create a 'dead' queue where 1045b3457b51SScott Long * commands go that have been interrupted/timed-out/etc, that keeps them 1046b3457b51SScott Long * out of the free pool. That way, if the card is just slow, it won't 1047b3457b51SScott Long * spam the memory of a command that has been recycled. 104835863739SMike Smith */ 104935863739SMike Smith static int 105035863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout) 105135863739SMike Smith { 1052ae543596SScott Long struct aac_softc *sc; 1053ae543596SScott Long int error = 0; 105435863739SMike Smith 105535863739SMike Smith debug_called(2); 105635863739SMike Smith 1057ae543596SScott Long sc = cm->cm_sc; 1058ae543596SScott Long 105935863739SMike Smith /* Put the command on the ready queue and get things going */ 106036e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 106135863739SMike Smith aac_enqueue_ready(cm); 1062ae543596SScott Long aac_startio(sc); 106335863739SMike Smith while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1064ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 106535863739SMike Smith } 106635863739SMike Smith return(error); 106735863739SMike Smith } 106835863739SMike Smith 1069914da7d0SScott Long /* 1070914da7d0SScott Long *Command Buffer Management 1071914da7d0SScott Long */ 107235863739SMike Smith 1073914da7d0SScott Long /* 107435863739SMike Smith * Allocate a command. 107535863739SMike Smith */ 1076fe3cb0e1SScott Long int 107735863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 107835863739SMike Smith { 107935863739SMike Smith struct aac_command *cm; 108035863739SMike Smith 108135863739SMike Smith debug_called(3); 108235863739SMike Smith 1083ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1084b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1085ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1086ae543596SScott Long wakeup(sc->aifthread); 1087b85f5808SScott Long } 1088ae543596SScott Long return (EBUSY); 1089ffb37f33SScott Long } 109035863739SMike Smith 10910b94a66eSMike Smith *cmp = cm; 10920b94a66eSMike Smith return(0); 10930b94a66eSMike Smith } 10940b94a66eSMike Smith 1095914da7d0SScott Long /* 10960b94a66eSMike Smith * Release a command back to the freelist. 10970b94a66eSMike Smith */ 1098fe3cb0e1SScott Long void 10990b94a66eSMike Smith aac_release_command(struct aac_command *cm) 11000b94a66eSMike Smith { 11010b94a66eSMike Smith debug_called(3); 11020b94a66eSMike Smith 11030b94a66eSMike Smith /* (re)initialise the command/FIB */ 110435863739SMike Smith cm->cm_sgtable = NULL; 110535863739SMike Smith cm->cm_flags = 0; 110635863739SMike Smith cm->cm_complete = NULL; 110735863739SMike Smith cm->cm_private = NULL; 110835863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 110935863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 111035863739SMike Smith cm->cm_fib->Header.Flags = 0; 111135863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 111235863739SMike Smith 111335863739SMike Smith /* 111435863739SMike Smith * These are duplicated in aac_start to cover the case where an 111535863739SMike Smith * intermediate stage may have destroyed them. They're left 111635863739SMike Smith * initialised here for debugging purposes only. 111735863739SMike Smith */ 1118f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1119f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 112035863739SMike Smith 112135863739SMike Smith aac_enqueue_free(cm); 112235863739SMike Smith } 112335863739SMike Smith 1124914da7d0SScott Long /* 11250b94a66eSMike Smith * Map helper for command/FIB allocation. 112635863739SMike Smith */ 112735863739SMike Smith static void 11280b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 112935863739SMike Smith { 11308480cc63SScott Long uint32_t *fibphys; 1131914da7d0SScott Long 11328480cc63SScott Long fibphys = (uint32_t *)arg; 113335863739SMike Smith 113435863739SMike Smith debug_called(3); 113535863739SMike Smith 1136ffb37f33SScott Long *fibphys = segs[0].ds_addr; 113735863739SMike Smith } 113835863739SMike Smith 1139914da7d0SScott Long /* 11400b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 114135863739SMike Smith */ 11420b94a66eSMike Smith static int 11430b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 114435863739SMike Smith { 114535863739SMike Smith struct aac_command *cm; 1146ffb37f33SScott Long struct aac_fibmap *fm; 11478480cc63SScott Long uint32_t fibphys; 1148ffb37f33SScott Long int i, error; 114935863739SMike Smith 1150a6d35632SScott Long debug_called(2); 115135863739SMike Smith 1152a6d35632SScott Long if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs) 1153ffb37f33SScott Long return (ENOMEM); 1154ffb37f33SScott Long 11558480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1156a6d35632SScott Long if (fm == NULL) 1157a6d35632SScott Long return (ENOMEM); 1158ffb37f33SScott Long 11590b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1160ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1161ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 116270545d1aSScott Long device_printf(sc->aac_dev, 116370545d1aSScott Long "Not enough contiguous memory available.\n"); 11648480cc63SScott Long free(fm, M_AACBUF); 11650b94a66eSMike Smith return (ENOMEM); 116635863739SMike Smith } 1167128aa5a0SScott Long 1168cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1169cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1170ffb37f33SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1171ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1172128aa5a0SScott Long 11730b94a66eSMike Smith /* initialise constant fields in the command structure */ 1174ffb37f33SScott Long bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11750b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11768480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1177ffb37f33SScott Long fm->aac_commands = cm; 117835863739SMike Smith cm->cm_sc = sc; 1179ffb37f33SScott Long cm->cm_fib = fm->aac_fibs + i; 11808480cc63SScott Long cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1181cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 118235863739SMike Smith 1183ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1184ffb37f33SScott Long &cm->cm_datamap)) == 0) 118535863739SMike Smith aac_release_command(cm); 1186ffb37f33SScott Long else 11878480cc63SScott Long break; 11888480cc63SScott Long sc->total_fibs++; 118935863739SMike Smith } 1190ffb37f33SScott Long 11918480cc63SScott Long if (i > 0) { 1192ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1193a6d35632SScott Long debug(1, "total_fibs= %d\n", sc->total_fibs); 11940b94a66eSMike Smith return (0); 119535863739SMike Smith } 119635863739SMike Smith 11978480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 11988480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 11998480cc63SScott Long free(fm, M_AACBUF); 12008480cc63SScott Long return (ENOMEM); 12018480cc63SScott Long } 12028480cc63SScott Long 1203914da7d0SScott Long /* 12040b94a66eSMike Smith * Free FIBs owned by this adapter. 120535863739SMike Smith */ 120635863739SMike Smith static void 12078480cc63SScott Long aac_free_commands(struct aac_softc *sc) 120835863739SMike Smith { 12098480cc63SScott Long struct aac_fibmap *fm; 1210ffb37f33SScott Long struct aac_command *cm; 121135863739SMike Smith int i; 121235863739SMike Smith 121335863739SMike Smith debug_called(1); 121435863739SMike Smith 12158480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 12168480cc63SScott Long 12178480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 12188480cc63SScott Long /* 12198480cc63SScott Long * We check against total_fibs to handle partially 12208480cc63SScott Long * allocated blocks. 12218480cc63SScott Long */ 12228480cc63SScott Long for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1223ffb37f33SScott Long cm = fm->aac_commands + i; 1224ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1225ffb37f33SScott Long } 1226ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1227ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12288480cc63SScott Long free(fm, M_AACBUF); 12298480cc63SScott Long } 123035863739SMike Smith } 123135863739SMike Smith 1232914da7d0SScott Long /* 123335863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 123435863739SMike Smith */ 123535863739SMike Smith static void 123635863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 123735863739SMike Smith { 1238cd481291SScott Long struct aac_softc *sc; 1239914da7d0SScott Long struct aac_command *cm; 1240914da7d0SScott Long struct aac_fib *fib; 124135863739SMike Smith int i; 124235863739SMike Smith 124335863739SMike Smith debug_called(3); 124435863739SMike Smith 1245914da7d0SScott Long cm = (struct aac_command *)arg; 1246cd481291SScott Long sc = cm->cm_sc; 1247914da7d0SScott Long fib = cm->cm_fib; 1248914da7d0SScott Long 124935863739SMike Smith /* copy into the FIB */ 1250b85f5808SScott Long if (cm->cm_sgtable != NULL) { 1251b85f5808SScott Long if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1252b85f5808SScott Long struct aac_sg_table *sg; 1253b85f5808SScott Long sg = cm->cm_sgtable; 125435863739SMike Smith sg->SgCount = nseg; 125535863739SMike Smith for (i = 0; i < nseg; i++) { 125635863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 125735863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 125835863739SMike Smith } 125935863739SMike Smith /* update the FIB size for the s/g count */ 126035863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 1261b85f5808SScott Long } else { 1262b85f5808SScott Long struct aac_sg_table64 *sg; 1263b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1264b85f5808SScott Long sg->SgCount = nseg; 1265b85f5808SScott Long for (i = 0; i < nseg; i++) { 1266b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1267b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 126835863739SMike Smith } 1269b85f5808SScott Long /* update the FIB size for the s/g count */ 1270b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1271b85f5808SScott Long } 1272b85f5808SScott Long } 127335863739SMike Smith 1274cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1275cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 1276cd481291SScott Long * the SenderFibAddress over to make room for the fast response bit. 127735863739SMike Smith */ 1278cd481291SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1); 1279cd481291SScott Long cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 128035863739SMike Smith 1281cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1282cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 128335863739SMike Smith 128435863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1285c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1286c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 128735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1288c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1289c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 129035863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1291cd481291SScott Long 1292cd481291SScott Long /* put the FIB on the outbound queue */ 1293cd481291SScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) 1294cd481291SScott Long aac_requeue_ready(cm); 1295cd481291SScott Long 1296cd481291SScott Long return; 129735863739SMike Smith } 129835863739SMike Smith 1299914da7d0SScott Long /* 130035863739SMike Smith * Unmap a command from controller-visible space. 130135863739SMike Smith */ 130235863739SMike Smith static void 130335863739SMike Smith aac_unmap_command(struct aac_command *cm) 130435863739SMike Smith { 1305914da7d0SScott Long struct aac_softc *sc; 130635863739SMike Smith 130735863739SMike Smith debug_called(2); 130835863739SMike Smith 1309914da7d0SScott Long sc = cm->cm_sc; 1310914da7d0SScott Long 131135863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 131235863739SMike Smith return; 131335863739SMike Smith 131435863739SMike Smith if (cm->cm_datalen != 0) { 131535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1316c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1317c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 131835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1319c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1320c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 132135863739SMike Smith 132235863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 132335863739SMike Smith } 132435863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 132535863739SMike Smith } 132635863739SMike Smith 1327914da7d0SScott Long /* 1328914da7d0SScott Long * Hardware Interface 1329914da7d0SScott Long */ 133035863739SMike Smith 1331914da7d0SScott Long /* 133235863739SMike Smith * Initialise the adapter. 133335863739SMike Smith */ 133435863739SMike Smith static void 133535863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 133635863739SMike Smith { 1337914da7d0SScott Long struct aac_softc *sc; 133835863739SMike Smith 133935863739SMike Smith debug_called(1); 134035863739SMike Smith 1341914da7d0SScott Long sc = (struct aac_softc *)arg; 1342914da7d0SScott Long 134335863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 134435863739SMike Smith } 134535863739SMike Smith 1346a6d35632SScott Long static int 1347a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1348a6d35632SScott Long { 1349a6d35632SScott Long u_int32_t major, minor, options; 1350a6d35632SScott Long 1351a6d35632SScott Long debug_called(1); 1352a6d35632SScott Long 1353fe94b852SScott Long /* 1354fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1355fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1356fe94b852SScott Long */ 1357a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1358fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1359fe94b852SScott Long NULL)) { 1360fe94b852SScott Long device_printf(sc->aac_dev, 1361fe94b852SScott Long "Error reading firmware version\n"); 1362fe94b852SScott Long return (EIO); 1363fe94b852SScott Long } 1364fe94b852SScott Long 1365fe94b852SScott Long /* These numbers are stored as ASCII! */ 1366a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1367a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1368fe94b852SScott Long if (major == 1) { 1369fe94b852SScott Long device_printf(sc->aac_dev, 1370fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1371fe94b852SScott Long major, minor); 1372fe94b852SScott Long return (EINVAL); 1373fe94b852SScott Long } 1374fe94b852SScott Long } 1375fe94b852SScott Long 1376a6d35632SScott Long /* 1377a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1378a6d35632SScott Long * work-arounds to enable. 1379a6d35632SScott Long */ 1380a6d35632SScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1381a6d35632SScott Long device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1382a6d35632SScott Long return (EIO); 1383a6d35632SScott Long } 1384a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 1385a6d35632SScott Long sc->supported_options = options; 1386a6d35632SScott Long 1387a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1388a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1389a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1390a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1391a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1392cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1393cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1394a6d35632SScott Long device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1395a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1396a6d35632SScott Long } 1397a6d35632SScott Long 1398a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 1399a6d35632SScott Long if ((sc->flags & AAC_FLAGS_256FIBS) == 0) 1400a6d35632SScott Long sc->aac_max_fibs = AAC_MAX_FIBS; 1401a6d35632SScott Long else 1402a6d35632SScott Long sc->aac_max_fibs = 256; 1403a6d35632SScott Long 1404fe94b852SScott Long return (0); 1405fe94b852SScott Long } 1406fe94b852SScott Long 140735863739SMike Smith static int 140835863739SMike Smith aac_init(struct aac_softc *sc) 140935863739SMike Smith { 141035863739SMike Smith struct aac_adapter_init *ip; 141135863739SMike Smith time_t then; 1412b88ffdc8SScott Long u_int32_t code, qoffset; 1413a6d35632SScott Long int error; 141435863739SMike Smith 141535863739SMike Smith debug_called(1); 141635863739SMike Smith 141735863739SMike Smith /* 141835863739SMike Smith * First wait for the adapter to come ready. 141935863739SMike Smith */ 142035863739SMike Smith then = time_second; 142135863739SMike Smith do { 142235863739SMike Smith code = AAC_GET_FWSTATUS(sc); 142335863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 142435863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 142535863739SMike Smith return(ENXIO); 142635863739SMike Smith } 142735863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1428914da7d0SScott Long device_printf(sc->aac_dev, 1429914da7d0SScott Long "FATAL: controller kernel panic\n"); 143035863739SMike Smith return(ENXIO); 143135863739SMike Smith } 143235863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1433914da7d0SScott Long device_printf(sc->aac_dev, 1434914da7d0SScott Long "FATAL: controller not coming ready, " 1435c6eafcf2SScott Long "status %x\n", code); 143635863739SMike Smith return(ENXIO); 143735863739SMike Smith } 143835863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 143935863739SMike Smith 1440a6d35632SScott Long error = ENOMEM; 1441a6d35632SScott Long /* 1442a6d35632SScott Long * Create DMA tag for mapping buffers into controller-addressable space. 1443a6d35632SScott Long */ 1444a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1445a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1446a6d35632SScott Long (sc->flags & AAC_FLAGS_SG_64BIT) ? 1447a6d35632SScott Long BUS_SPACE_MAXADDR : 1448a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1449a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1450a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1451a6d35632SScott Long MAXBSIZE, /* maxsize */ 1452a6d35632SScott Long AAC_MAXSGENTRIES, /* nsegments */ 1453a6d35632SScott Long MAXBSIZE, /* maxsegsize */ 1454a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1455f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 1456f6b1c44dSScott Long &sc->aac_io_lock, /* lockfuncarg */ 1457a6d35632SScott Long &sc->aac_buffer_dmat)) { 1458a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1459a6d35632SScott Long goto out; 1460a6d35632SScott Long } 1461a6d35632SScott Long 1462a6d35632SScott Long /* 1463a6d35632SScott Long * Create DMA tag for mapping FIBs into controller-addressable space.. 1464a6d35632SScott Long */ 1465a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1466a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1467a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1468a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1469a6d35632SScott Long 0x7fffffff, /* lowaddr */ 1470a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1471a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1472a6d35632SScott Long AAC_FIB_COUNT * 1473a6d35632SScott Long sizeof(struct aac_fib), /* maxsize */ 1474a6d35632SScott Long 1, /* nsegments */ 1475a6d35632SScott Long AAC_FIB_COUNT * 1476a6d35632SScott Long sizeof(struct aac_fib), /* maxsegsize */ 1477a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1478f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 1479a6d35632SScott Long &sc->aac_fib_dmat)) { 1480a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1481a6d35632SScott Long goto out; 1482a6d35632SScott Long } 1483a6d35632SScott Long 148435863739SMike Smith /* 148535863739SMike Smith * Create DMA tag for the common structure and allocate it. 148635863739SMike Smith */ 148735863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1488c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1489a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1490a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1491a6d35632SScott Long 0x7fffffff, /* lowaddr */ 149235863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 149335863739SMike Smith NULL, NULL, /* filter, filterarg */ 1494ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1495914da7d0SScott Long 1, /* nsegments */ 149635863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1497a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1498f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 149935863739SMike Smith &sc->aac_common_dmat)) { 1500914da7d0SScott Long device_printf(sc->aac_dev, 1501914da7d0SScott Long "can't allocate common structure DMA tag\n"); 1502a6d35632SScott Long goto out; 150335863739SMike Smith } 1504c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1505c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 150635863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 1507a6d35632SScott Long goto out; 150835863739SMike Smith } 1509ffb37f33SScott Long 1510ffb37f33SScott Long /* 1511ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1512ffb37f33SScott Long * below address 8192 in physical memory. 1513ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1514ffb37f33SScott Long * of ignored? 1515ffb37f33SScott Long */ 1516cd481291SScott Long (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1517ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1518ffb37f33SScott Long aac_common_map, sc, 0); 1519ffb37f33SScott Long 1520ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1521ffb37f33SScott Long (uint8_t *)sc->aac_common += 8192; 1522ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1523ffb37f33SScott Long } 152435863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 152535863739SMike Smith 1526ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1527ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 1528ffb37f33SScott Long sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 15298480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 15308480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1531ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1532ffb37f33SScott Long break; 1533ffb37f33SScott Long } 1534ffb37f33SScott Long if (sc->total_fibs == 0) 1535a6d35632SScott Long goto out; 1536ffb37f33SScott Long 153735863739SMike Smith /* 1538914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1539914da7d0SScott Long * physical location of various important shared data structures. 154035863739SMike Smith */ 154135863739SMike Smith ip = &sc->aac_common->ac_init; 154235863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1543f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 154435863739SMike Smith 1545c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1546c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1547149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 154835863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 154935863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 155035863739SMike Smith 1551c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1552c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 155335863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 155435863739SMike Smith 15554b00f859SScott Long /* 15564b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 15574b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 15584b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 15594b00f859SScott Long * Round up since the granularity is so high. 15604b00f859SScott Long */ 1561f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 15624b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 15634b00f859SScott Long ip->HostPhysMemPages = 15644b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1565204c0befSScott Long } 156635863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 156735863739SMike Smith 156835863739SMike Smith /* 1569c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1570c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1571c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 157235863739SMike Smith * 157335863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1574914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1575914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1576914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1577914da7d0SScott Long * does. 157835863739SMike Smith * 1579914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1580914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1581914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1582914da7d0SScott Long * virtue of a table. 158335863739SMike Smith */ 1584b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 15850bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 15860bcbebd6SScott Long sc->aac_queues = 15870bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1588b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 158935863739SMike Smith 1590c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1591c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1592c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1593c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1594c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1595c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1596c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1597c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1598c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1599c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1600c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1601c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1602c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1603c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1604c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1605c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1606c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1607c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1608c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1609c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1610c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1611c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1612c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1613c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1614c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1615c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1616c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1617c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1618c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1619c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1620c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1621c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1622c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1623c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1624c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1625c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1626c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1627c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1628c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1629c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1630c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1631c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1632c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1633c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1634c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1635c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1636c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1637c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 163835863739SMike Smith 163935863739SMike Smith /* 164035863739SMike Smith * Do controller-type-specific initialisation 164135863739SMike Smith */ 164235863739SMike Smith switch (sc->aac_hwif) { 164335863739SMike Smith case AAC_HWIF_I960RX: 164435863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 164535863739SMike Smith break; 164635863739SMike Smith } 164735863739SMike Smith 164835863739SMike Smith /* 164935863739SMike Smith * Give the init structure to the controller. 165035863739SMike Smith */ 165135863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1652914da7d0SScott Long sc->aac_common_busaddr + 1653914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1654914da7d0SScott Long NULL)) { 1655914da7d0SScott Long device_printf(sc->aac_dev, 1656914da7d0SScott Long "error establishing init structure\n"); 1657a6d35632SScott Long error = EIO; 1658a6d35632SScott Long goto out; 165935863739SMike Smith } 166035863739SMike Smith 1661a6d35632SScott Long error = 0; 1662a6d35632SScott Long out: 1663a6d35632SScott Long return(error); 166435863739SMike Smith } 166535863739SMike Smith 1666914da7d0SScott Long /* 166735863739SMike Smith * Send a synchronous command to the controller and wait for a result. 166835863739SMike Smith */ 166935863739SMike Smith static int 167035863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 167135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 167235863739SMike Smith u_int32_t *sp) 167335863739SMike Smith { 167435863739SMike Smith time_t then; 167535863739SMike Smith u_int32_t status; 167635863739SMike Smith 167735863739SMike Smith debug_called(3); 167835863739SMike Smith 167935863739SMike Smith /* populate the mailbox */ 168035863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 168135863739SMike Smith 168235863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 168335863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 168435863739SMike Smith 168535863739SMike Smith /* then set it to signal the adapter */ 168635863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 168735863739SMike Smith 168835863739SMike Smith /* spin waiting for the command to complete */ 168935863739SMike Smith then = time_second; 169035863739SMike Smith do { 169135863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 1692a6d35632SScott Long debug(1, "timed out"); 169335863739SMike Smith return(EIO); 169435863739SMike Smith } 169535863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 169635863739SMike Smith 169735863739SMike Smith /* clear the completion flag */ 169835863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 169935863739SMike Smith 170035863739SMike Smith /* get the command status */ 1701a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 170235863739SMike Smith if (sp != NULL) 170335863739SMike Smith *sp = status; 17040b94a66eSMike Smith return(0); 170535863739SMike Smith } 170635863739SMike Smith 1707914da7d0SScott Long /* 1708cbfd045bSScott Long * Grab the sync fib area. 1709cbfd045bSScott Long */ 1710cbfd045bSScott Long int 1711fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1712cbfd045bSScott Long { 1713cbfd045bSScott Long 1714cbfd045bSScott Long /* 1715cbfd045bSScott Long * If the force flag is set, the system is shutting down, or in 1716cbfd045bSScott Long * trouble. Ignore the mutex. 1717cbfd045bSScott Long */ 1718cbfd045bSScott Long if (!(flags & AAC_SYNC_LOCK_FORCE)) 1719cbfd045bSScott Long AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1720cbfd045bSScott Long 1721cbfd045bSScott Long *fib = &sc->aac_common->ac_sync_fib; 1722cbfd045bSScott Long 1723cbfd045bSScott Long return (1); 1724cbfd045bSScott Long } 1725cbfd045bSScott Long 1726cbfd045bSScott Long /* 1727cbfd045bSScott Long * Release the sync fib area. 1728cbfd045bSScott Long */ 1729cbfd045bSScott Long void 1730cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc) 1731cbfd045bSScott Long { 1732cbfd045bSScott Long 1733cbfd045bSScott Long AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1734cbfd045bSScott Long } 1735cbfd045bSScott Long 1736cbfd045bSScott Long /* 173735863739SMike Smith * Send a synchronous FIB to the controller and wait for a result. 173835863739SMike Smith */ 1739cbfd045bSScott Long int 174035863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1741cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 174235863739SMike Smith { 174335863739SMike Smith debug_called(3); 174435863739SMike Smith 174535863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 174635863739SMike Smith return(EINVAL); 174735863739SMike Smith 174835863739SMike Smith /* 174935863739SMike Smith * Set up the sync FIB 175035863739SMike Smith */ 1751914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1752914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1753c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 175435863739SMike Smith fib->Header.XferState |= xferstate; 175535863739SMike Smith fib->Header.Command = command; 175635863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 175735863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 175835863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 1759b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 1760c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1761914da7d0SScott Long offsetof(struct aac_common, 1762914da7d0SScott Long ac_sync_fib); 176335863739SMike Smith 176435863739SMike Smith /* 176535863739SMike Smith * Give the FIB to the controller, wait for a response. 176635863739SMike Smith */ 1767914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1768914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 176935863739SMike Smith debug(2, "IO error"); 177035863739SMike Smith return(EIO); 177135863739SMike Smith } 177235863739SMike Smith 177335863739SMike Smith return (0); 177435863739SMike Smith } 177535863739SMike Smith 1776914da7d0SScott Long /* 177735863739SMike Smith * Adapter-space FIB queue manipulation 177835863739SMike Smith * 177935863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 178035863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 178135863739SMike Smith */ 178235863739SMike Smith static struct { 178335863739SMike Smith int size; 178435863739SMike Smith int notify; 178535863739SMike Smith } aac_qinfo[] = { 178635863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 178735863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 178835863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 178935863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 179035863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 179135863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 179235863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 179335863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 179435863739SMike Smith }; 179535863739SMike Smith 179635863739SMike Smith /* 1797c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1798c6eafcf2SScott Long * EBUSY if the queue is full. 179935863739SMike Smith * 18000b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1801914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1802914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1803c6eafcf2SScott Long * separate queue/notify interface). 180435863739SMike Smith */ 180535863739SMike Smith static int 1806f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 180735863739SMike Smith { 180835863739SMike Smith u_int32_t pi, ci; 18099e2e96d8SScott Long int error; 1810f6c4dd3fSScott Long u_int32_t fib_size; 1811f6c4dd3fSScott Long u_int32_t fib_addr; 1812f6c4dd3fSScott Long 181336e0bf6eSScott Long debug_called(3); 181436e0bf6eSScott Long 1815f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1816f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 181735863739SMike Smith 181835863739SMike Smith /* get the producer/consumer indices */ 181935863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 182035863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 182135863739SMike Smith 182235863739SMike Smith /* wrap the queue? */ 182335863739SMike Smith if (pi >= aac_qinfo[queue].size) 182435863739SMike Smith pi = 0; 182535863739SMike Smith 182635863739SMike Smith /* check for queue full */ 182735863739SMike Smith if ((pi + 1) == ci) { 182835863739SMike Smith error = EBUSY; 182935863739SMike Smith goto out; 183035863739SMike Smith } 183135863739SMike Smith 183235863739SMike Smith /* populate queue entry */ 183335863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 183435863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 183535863739SMike Smith 183635863739SMike Smith /* update producer index */ 183735863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 183835863739SMike Smith 1839f6c4dd3fSScott Long /* 1840914da7d0SScott Long * To avoid a race with its completion interrupt, place this command on 1841914da7d0SScott Long * the busy queue prior to advertising it to the controller. 1842f6c4dd3fSScott Long */ 1843f6c4dd3fSScott Long aac_enqueue_busy(cm); 1844f6c4dd3fSScott Long 184535863739SMike Smith /* notify the adapter if we know how */ 184635863739SMike Smith if (aac_qinfo[queue].notify != 0) 184735863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 184835863739SMike Smith 184935863739SMike Smith error = 0; 185035863739SMike Smith 185135863739SMike Smith out: 185235863739SMike Smith return(error); 185335863739SMike Smith } 185435863739SMike Smith 185535863739SMike Smith /* 185636e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 185736e0bf6eSScott Long * success or ENOENT if the queue is empty. 185835863739SMike Smith */ 185935863739SMike Smith static int 1860c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1861c6eafcf2SScott Long struct aac_fib **fib_addr) 186235863739SMike Smith { 186335863739SMike Smith u_int32_t pi, ci; 1864149af931SScott Long u_int32_t fib_index; 18659e2e96d8SScott Long int error; 1866f6c4dd3fSScott Long int notify; 186735863739SMike Smith 186835863739SMike Smith debug_called(3); 186935863739SMike Smith 187035863739SMike Smith /* get the producer/consumer indices */ 187135863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 187235863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 187335863739SMike Smith 187435863739SMike Smith /* check for queue empty */ 187535863739SMike Smith if (ci == pi) { 187635863739SMike Smith error = ENOENT; 187735863739SMike Smith goto out; 187835863739SMike Smith } 187935863739SMike Smith 18807753acd2SScott Long /* wrap the pi so the following test works */ 18817753acd2SScott Long if (pi >= aac_qinfo[queue].size) 18827753acd2SScott Long pi = 0; 18837753acd2SScott Long 1884f6c4dd3fSScott Long notify = 0; 1885f6c4dd3fSScott Long if (ci == pi + 1) 1886f6c4dd3fSScott Long notify++; 1887f6c4dd3fSScott Long 188835863739SMike Smith /* wrap the queue? */ 188935863739SMike Smith if (ci >= aac_qinfo[queue].size) 189035863739SMike Smith ci = 0; 189135863739SMike Smith 189235863739SMike Smith /* fetch the entry */ 189335863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1894149af931SScott Long 1895149af931SScott Long switch (queue) { 1896149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 1897149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 1898149af931SScott Long /* 1899149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 1900149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 1901149af931SScott Long * that it's giving us an address into the array of AIF fibs. 1902149af931SScott Long * Therefore, we have to convert it to an index. 1903149af931SScott Long */ 1904149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 1905149af931SScott Long sizeof(struct aac_fib); 1906149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 1907149af931SScott Long break; 1908149af931SScott Long 1909149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 1910149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 1911149af931SScott Long { 1912149af931SScott Long struct aac_command *cm; 1913149af931SScott Long 1914149af931SScott Long /* 1915149af931SScott Long * As above, an index is used instead of an actual address. 1916149af931SScott Long * Gotta shift the index to account for the fast response 1917149af931SScott Long * bit. No other correction is needed since this value was 1918149af931SScott Long * originally provided by the driver via the SenderFibAddress 1919149af931SScott Long * field. 1920149af931SScott Long */ 1921149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 1922149af931SScott Long cm = sc->aac_commands + (fib_index >> 1); 1923149af931SScott Long *fib_addr = cm->cm_fib; 192435863739SMike Smith 1925f30ac74cSScott Long /* 1926f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1927149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 1928f30ac74cSScott Long */ 1929149af931SScott Long if (fib_index & 0x01) { 1930f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1931f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1932f30ac74cSScott Long } 1933149af931SScott Long break; 1934149af931SScott Long } 1935149af931SScott Long default: 1936149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 1937149af931SScott Long break; 1938149af931SScott Long } 1939149af931SScott Long 194035863739SMike Smith /* update consumer index */ 194135863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 194235863739SMike Smith 194335863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1944f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 194535863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 194635863739SMike Smith error = 0; 194735863739SMike Smith 194835863739SMike Smith out: 194935863739SMike Smith return(error); 195035863739SMike Smith } 195135863739SMike Smith 1952914da7d0SScott Long /* 195336e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 195436e0bf6eSScott Long */ 195536e0bf6eSScott Long static int 195636e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 195736e0bf6eSScott Long { 195836e0bf6eSScott Long u_int32_t pi, ci; 19599e2e96d8SScott Long int error; 196036e0bf6eSScott Long u_int32_t fib_size; 196136e0bf6eSScott Long u_int32_t fib_addr; 196236e0bf6eSScott Long 196336e0bf6eSScott Long debug_called(1); 196436e0bf6eSScott Long 196536e0bf6eSScott Long /* Tell the adapter where the FIB is */ 196636e0bf6eSScott Long fib_size = fib->Header.Size; 196736e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 196836e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 196936e0bf6eSScott Long 197036e0bf6eSScott Long /* get the producer/consumer indices */ 197136e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 197236e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 197336e0bf6eSScott Long 197436e0bf6eSScott Long /* wrap the queue? */ 197536e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 197636e0bf6eSScott Long pi = 0; 197736e0bf6eSScott Long 197836e0bf6eSScott Long /* check for queue full */ 197936e0bf6eSScott Long if ((pi + 1) == ci) { 198036e0bf6eSScott Long error = EBUSY; 198136e0bf6eSScott Long goto out; 198236e0bf6eSScott Long } 198336e0bf6eSScott Long 198436e0bf6eSScott Long /* populate queue entry */ 198536e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 198636e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 198736e0bf6eSScott Long 198836e0bf6eSScott Long /* update producer index */ 198936e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 199036e0bf6eSScott Long 199136e0bf6eSScott Long /* notify the adapter if we know how */ 199236e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 199336e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 199436e0bf6eSScott Long 199536e0bf6eSScott Long error = 0; 199636e0bf6eSScott Long 199736e0bf6eSScott Long out: 199836e0bf6eSScott Long return(error); 199936e0bf6eSScott Long } 200036e0bf6eSScott Long 2001914da7d0SScott Long /* 20020b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 20030b94a66eSMike Smith * and complain about them. 20040b94a66eSMike Smith */ 20050b94a66eSMike Smith static void 20060b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 20070b94a66eSMike Smith { 20080b94a66eSMike Smith struct aac_command *cm; 20090b94a66eSMike Smith time_t deadline; 20100b94a66eSMike Smith 2011f6c4dd3fSScott Long /* 201270545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2013914da7d0SScott Long * only. 2014914da7d0SScott Long */ 20150b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 20160b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2017f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2018f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 20190b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2020914da7d0SScott Long device_printf(sc->aac_dev, 2021914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2022f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 20230b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 20240b94a66eSMike Smith } 20250b94a66eSMike Smith } 20260b94a66eSMike Smith 20270b94a66eSMike Smith return; 20280b94a66eSMike Smith } 20290b94a66eSMike Smith 2030914da7d0SScott Long /* 2031914da7d0SScott Long * Interface Function Vectors 2032914da7d0SScott Long */ 203335863739SMike Smith 2034914da7d0SScott Long /* 203535863739SMike Smith * Read the current firmware status word. 203635863739SMike Smith */ 203735863739SMike Smith static int 203835863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 203935863739SMike Smith { 204035863739SMike Smith debug_called(3); 204135863739SMike Smith 204235863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 204335863739SMike Smith } 204435863739SMike Smith 204535863739SMike Smith static int 204635863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 204735863739SMike Smith { 204835863739SMike Smith debug_called(3); 204935863739SMike Smith 205035863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 205135863739SMike Smith } 205235863739SMike Smith 2053b3457b51SScott Long static int 2054b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2055b3457b51SScott Long { 2056b3457b51SScott Long int val; 2057b3457b51SScott Long 2058b3457b51SScott Long debug_called(3); 2059b3457b51SScott Long 2060b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2061b3457b51SScott Long return (val); 2062b3457b51SScott Long } 2063b3457b51SScott Long 2064914da7d0SScott Long /* 206535863739SMike Smith * Notify the controller of a change in a given queue 206635863739SMike Smith */ 206735863739SMike Smith 206835863739SMike Smith static void 206935863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 207035863739SMike Smith { 207135863739SMike Smith debug_called(3); 207235863739SMike Smith 207335863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 207435863739SMike Smith } 207535863739SMike Smith 207635863739SMike Smith static void 207735863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 207835863739SMike Smith { 207935863739SMike Smith debug_called(3); 208035863739SMike Smith 208135863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 208235863739SMike Smith } 208335863739SMike Smith 2084b3457b51SScott Long static void 2085b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2086b3457b51SScott Long { 2087b3457b51SScott Long debug_called(3); 2088b3457b51SScott Long 2089b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2090b3457b51SScott Long AAC_FA_HACK(sc); 2091b3457b51SScott Long } 2092b3457b51SScott Long 2093914da7d0SScott Long /* 209435863739SMike Smith * Get the interrupt reason bits 209535863739SMike Smith */ 209635863739SMike Smith static int 209735863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 209835863739SMike Smith { 209935863739SMike Smith debug_called(3); 210035863739SMike Smith 210135863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 210235863739SMike Smith } 210335863739SMike Smith 210435863739SMike Smith static int 210535863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 210635863739SMike Smith { 210735863739SMike Smith debug_called(3); 210835863739SMike Smith 210935863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 211035863739SMike Smith } 211135863739SMike Smith 2112b3457b51SScott Long static int 2113b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2114b3457b51SScott Long { 2115b3457b51SScott Long int val; 2116b3457b51SScott Long 2117b3457b51SScott Long debug_called(3); 2118b3457b51SScott Long 2119b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2120b3457b51SScott Long return (val); 2121b3457b51SScott Long } 2122b3457b51SScott Long 2123914da7d0SScott Long /* 212435863739SMike Smith * Clear some interrupt reason bits 212535863739SMike Smith */ 212635863739SMike Smith static void 212735863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 212835863739SMike Smith { 212935863739SMike Smith debug_called(3); 213035863739SMike Smith 213135863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 213235863739SMike Smith } 213335863739SMike Smith 213435863739SMike Smith static void 213535863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 213635863739SMike Smith { 213735863739SMike Smith debug_called(3); 213835863739SMike Smith 213935863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 214035863739SMike Smith } 214135863739SMike Smith 2142b3457b51SScott Long static void 2143b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2144b3457b51SScott Long { 2145b3457b51SScott Long debug_called(3); 2146b3457b51SScott Long 2147b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2148b3457b51SScott Long AAC_FA_HACK(sc); 2149b3457b51SScott Long } 2150b3457b51SScott Long 2151914da7d0SScott Long /* 215235863739SMike Smith * Populate the mailbox and set the command word 215335863739SMike Smith */ 215435863739SMike Smith static void 215535863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 215635863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 215735863739SMike Smith { 215835863739SMike Smith debug_called(4); 215935863739SMike Smith 216035863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 216135863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 216235863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 216335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 216435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 216535863739SMike Smith } 216635863739SMike Smith 216735863739SMike Smith static void 216835863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 216935863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 217035863739SMike Smith { 217135863739SMike Smith debug_called(4); 217235863739SMike Smith 217335863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 217435863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 217535863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 217635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 217735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 217835863739SMike Smith } 217935863739SMike Smith 2180b3457b51SScott Long static void 2181b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2182b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2183b3457b51SScott Long { 2184b3457b51SScott Long debug_called(4); 2185b3457b51SScott Long 2186b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2187b3457b51SScott Long AAC_FA_HACK(sc); 2188b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2189b3457b51SScott Long AAC_FA_HACK(sc); 2190b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2191b3457b51SScott Long AAC_FA_HACK(sc); 2192b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2193b3457b51SScott Long AAC_FA_HACK(sc); 2194b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2195b3457b51SScott Long AAC_FA_HACK(sc); 2196b3457b51SScott Long } 2197b3457b51SScott Long 2198914da7d0SScott Long /* 219935863739SMike Smith * Fetch the immediate command status word 220035863739SMike Smith */ 220135863739SMike Smith static int 2202a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 220335863739SMike Smith { 220435863739SMike Smith debug_called(4); 220535863739SMike Smith 2206a6d35632SScott Long return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 220735863739SMike Smith } 220835863739SMike Smith 220935863739SMike Smith static int 2210a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 221135863739SMike Smith { 221235863739SMike Smith debug_called(4); 221335863739SMike Smith 2214a6d35632SScott Long return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 221535863739SMike Smith } 221635863739SMike Smith 2217b3457b51SScott Long static int 2218a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2219b3457b51SScott Long { 2220b3457b51SScott Long int val; 2221b3457b51SScott Long 2222b3457b51SScott Long debug_called(4); 2223b3457b51SScott Long 2224a6d35632SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2225b3457b51SScott Long return (val); 2226b3457b51SScott Long } 2227b3457b51SScott Long 2228914da7d0SScott Long /* 222935863739SMike Smith * Set/clear interrupt masks 223035863739SMike Smith */ 223135863739SMike Smith static void 223235863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 223335863739SMike Smith { 223435863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 223535863739SMike Smith 223635863739SMike Smith if (enable) { 223735863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 223835863739SMike Smith } else { 223935863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 224035863739SMike Smith } 224135863739SMike Smith } 224235863739SMike Smith 224335863739SMike Smith static void 224435863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 224535863739SMike Smith { 224635863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 224735863739SMike Smith 224835863739SMike Smith if (enable) { 224935863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 225035863739SMike Smith } else { 225135863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 225235863739SMike Smith } 225335863739SMike Smith } 225435863739SMike Smith 2255b3457b51SScott Long static void 2256b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2257b3457b51SScott Long { 2258b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2259b3457b51SScott Long 2260b3457b51SScott Long if (enable) { 2261b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2262b3457b51SScott Long AAC_FA_HACK(sc); 2263b3457b51SScott Long } else { 2264b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2265b3457b51SScott Long AAC_FA_HACK(sc); 2266b3457b51SScott Long } 2267b3457b51SScott Long } 2268b3457b51SScott Long 2269914da7d0SScott Long /* 2270914da7d0SScott Long * Debugging and Diagnostics 2271914da7d0SScott Long */ 227235863739SMike Smith 2273914da7d0SScott Long /* 227435863739SMike Smith * Print some information about the controller. 227535863739SMike Smith */ 227635863739SMike Smith static void 227735863739SMike Smith aac_describe_controller(struct aac_softc *sc) 227835863739SMike Smith { 2279cbfd045bSScott Long struct aac_fib *fib; 228035863739SMike Smith struct aac_adapter_info *info; 228135863739SMike Smith 228235863739SMike Smith debug_called(2); 228335863739SMike Smith 2284fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2285cbfd045bSScott Long 2286cbfd045bSScott Long fib->data[0] = 0; 2287cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 228835863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2289fe3cb0e1SScott Long aac_release_sync_fib(sc); 229035863739SMike Smith return; 229135863739SMike Smith } 2292cbfd045bSScott Long info = (struct aac_adapter_info *)&fib->data[0]; 229335863739SMike Smith 229436e0bf6eSScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2295c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 229636e0bf6eSScott Long info->ClockSpeed, info->BufferMem / (1024 * 1024), 2297914da7d0SScott Long aac_describe_code(aac_battery_platform, 2298914da7d0SScott Long info->batteryPlatform)); 229935863739SMike Smith 230035863739SMike Smith /* save the kernel revision structure for later use */ 230135863739SMike Smith sc->aac_revision = info->KernelRevision; 230236e0bf6eSScott Long device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 230335863739SMike Smith info->KernelRevision.external.comp.major, 230435863739SMike Smith info->KernelRevision.external.comp.minor, 230535863739SMike Smith info->KernelRevision.external.comp.dash, 230636e0bf6eSScott Long info->KernelRevision.buildNumber, 230736e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2308fe3cb0e1SScott Long 2309fe3cb0e1SScott Long aac_release_sync_fib(sc); 2310a6d35632SScott Long 2311a6d35632SScott Long if (1 || bootverbose) { 2312a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2313a6d35632SScott Long sc->supported_options, 2314a6d35632SScott Long "\20" 2315a6d35632SScott Long "\1SNAPSHOT" 2316a6d35632SScott Long "\2CLUSTERS" 2317a6d35632SScott Long "\3WCACHE" 2318a6d35632SScott Long "\4DATA64" 2319a6d35632SScott Long "\5HOSTTIME" 2320a6d35632SScott Long "\6RAID50" 2321a6d35632SScott Long "\7WINDOW4GB" 2322a6d35632SScott Long "\10SCSIUPGD" 2323a6d35632SScott Long "\11SOFTERR" 2324a6d35632SScott Long "\12NORECOND" 2325a6d35632SScott Long "\13SGMAP64" 2326a6d35632SScott Long "\14ALARM" 2327a6d35632SScott Long "\15NONDASD"); 2328a6d35632SScott Long } 232935863739SMike Smith } 233035863739SMike Smith 2331914da7d0SScott Long /* 233235863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 233335863739SMike Smith * same. 233435863739SMike Smith */ 233535863739SMike Smith static char * 233635863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 233735863739SMike Smith { 233835863739SMike Smith int i; 233935863739SMike Smith 234035863739SMike Smith for (i = 0; table[i].string != NULL; i++) 234135863739SMike Smith if (table[i].code == code) 234235863739SMike Smith return(table[i].string); 234335863739SMike Smith return(table[i + 1].string); 234435863739SMike Smith } 234535863739SMike Smith 2346914da7d0SScott Long /* 2347914da7d0SScott Long * Management Interface 2348914da7d0SScott Long */ 234935863739SMike Smith 235035863739SMike Smith static int 2351c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 235235863739SMike Smith { 2353914da7d0SScott Long struct aac_softc *sc; 235435863739SMike Smith 235535863739SMike Smith debug_called(2); 235635863739SMike Smith 2357914da7d0SScott Long sc = dev->si_drv1; 2358914da7d0SScott Long 235935863739SMike Smith /* Check to make sure the device isn't already open */ 236035863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 236135863739SMike Smith return EBUSY; 236235863739SMike Smith } 236335863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 236435863739SMike Smith 236535863739SMike Smith return 0; 236635863739SMike Smith } 236735863739SMike Smith 236835863739SMike Smith static int 2369c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 237035863739SMike Smith { 2371914da7d0SScott Long struct aac_softc *sc; 237235863739SMike Smith 237335863739SMike Smith debug_called(2); 237435863739SMike Smith 2375914da7d0SScott Long sc = dev->si_drv1; 2376914da7d0SScott Long 237735863739SMike Smith /* Mark this unit as no longer open */ 237835863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 237935863739SMike Smith 238035863739SMike Smith return 0; 238135863739SMike Smith } 238235863739SMike Smith 238335863739SMike Smith static int 2384c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 238535863739SMike Smith { 2386914da7d0SScott Long union aac_statrequest *as; 2387914da7d0SScott Long struct aac_softc *sc; 23880b94a66eSMike Smith int error = 0; 2389b88ffdc8SScott Long uint32_t cookie; 239035863739SMike Smith 239135863739SMike Smith debug_called(2); 239235863739SMike Smith 2393914da7d0SScott Long as = (union aac_statrequest *)arg; 2394914da7d0SScott Long sc = dev->si_drv1; 2395914da7d0SScott Long 239635863739SMike Smith switch (cmd) { 23970b94a66eSMike Smith case AACIO_STATS: 23980b94a66eSMike Smith switch (as->as_item) { 23990b94a66eSMike Smith case AACQ_FREE: 24000b94a66eSMike Smith case AACQ_BIO: 24010b94a66eSMike Smith case AACQ_READY: 24020b94a66eSMike Smith case AACQ_BUSY: 24030b94a66eSMike Smith case AACQ_COMPLETE: 2404c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2405c6eafcf2SScott Long sizeof(struct aac_qstat)); 24060b94a66eSMike Smith break; 24070b94a66eSMike Smith default: 24080b94a66eSMike Smith error = ENOENT; 24090b94a66eSMike Smith break; 24100b94a66eSMike Smith } 24110b94a66eSMike Smith break; 24120b94a66eSMike Smith 241335863739SMike Smith case FSACTL_SENDFIB: 2414fb0c27d7SScott Long arg = *(caddr_t*)arg; 2415fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 24160b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 241735863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 241835863739SMike Smith break; 241935863739SMike Smith case FSACTL_AIF_THREAD: 2420fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 24210b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 242235863739SMike Smith error = EINVAL; 242335863739SMike Smith break; 242435863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2425fb0c27d7SScott Long arg = *(caddr_t*)arg; 2426fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 24270b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 242835863739SMike Smith /* 242935863739SMike Smith * Pass the caller out an AdapterFibContext. 243035863739SMike Smith * 243135863739SMike Smith * Note that because we only support one opener, we 243235863739SMike Smith * basically ignore this. Set the caller's context to a magic 243335863739SMike Smith * number just in case. 24340b94a66eSMike Smith * 24350b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 24360b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2437914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2438914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 243935863739SMike Smith */ 2440b88ffdc8SScott Long cookie = (uint32_t)(uintptr_t)sc->aifthread; 2441b88ffdc8SScott Long error = copyout(&cookie, arg, sizeof(cookie)); 244235863739SMike Smith break; 244335863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2444fb0c27d7SScott Long arg = *(caddr_t*)arg; 2445fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 24460b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2447fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 244835863739SMike Smith break; 244935863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2450fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 24510b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 245235863739SMike Smith /* don't do anything here */ 245335863739SMike Smith break; 245435863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2455fb0c27d7SScott Long arg = *(caddr_t*)arg; 2456fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 24570b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2458fb0c27d7SScott Long error = aac_rev_check(sc, arg); 245935863739SMike Smith break; 246036e0bf6eSScott Long case FSACTL_QUERY_DISK: 246136e0bf6eSScott Long arg = *(caddr_t*)arg; 246236e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 246336e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 246436e0bf6eSScott Long error = aac_query_disk(sc, arg); 246536e0bf6eSScott Long break; 246636e0bf6eSScott Long case FSACTL_DELETE_DISK: 246736e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2468914da7d0SScott Long /* 2469914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2470914da7d0SScott Long * container, rather we rely on an AIF coming from the 2471914da7d0SScott Long * controller 2472914da7d0SScott Long */ 247336e0bf6eSScott Long error = 0; 247436e0bf6eSScott Long break; 247535863739SMike Smith default: 2476b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 247735863739SMike Smith error = EINVAL; 247835863739SMike Smith break; 247935863739SMike Smith } 248035863739SMike Smith return(error); 248135863739SMike Smith } 248235863739SMike Smith 2483b3457b51SScott Long static int 2484c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td) 2485b3457b51SScott Long { 2486b3457b51SScott Long struct aac_softc *sc; 2487b3457b51SScott Long int revents; 2488b3457b51SScott Long 2489b3457b51SScott Long sc = dev->si_drv1; 2490b3457b51SScott Long revents = 0; 2491b3457b51SScott Long 2492c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2493b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2494b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2495b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2496b3457b51SScott Long } 2497b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2498b3457b51SScott Long 2499b3457b51SScott Long if (revents == 0) { 2500b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2501b3457b51SScott Long selrecord(td, &sc->rcv_select); 2502b3457b51SScott Long } 2503b3457b51SScott Long 2504b3457b51SScott Long return (revents); 2505b3457b51SScott Long } 2506b3457b51SScott Long 2507914da7d0SScott Long /* 250835863739SMike Smith * Send a FIB supplied from userspace 250935863739SMike Smith */ 251035863739SMike Smith static int 251135863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 251235863739SMike Smith { 251335863739SMike Smith struct aac_command *cm; 251435863739SMike Smith int size, error; 251535863739SMike Smith 251635863739SMike Smith debug_called(2); 251735863739SMike Smith 251835863739SMike Smith cm = NULL; 251935863739SMike Smith 252035863739SMike Smith /* 252135863739SMike Smith * Get a command 252235863739SMike Smith */ 2523ae543596SScott Long AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 252435863739SMike Smith if (aac_alloc_command(sc, &cm)) { 252535863739SMike Smith error = EBUSY; 252635863739SMike Smith goto out; 252735863739SMike Smith } 252835863739SMike Smith 252935863739SMike Smith /* 253035863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 253135863739SMike Smith */ 2532914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2533914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 253435863739SMike Smith goto out; 253535863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 253635863739SMike Smith if (size > sizeof(struct aac_fib)) { 2537b88ffdc8SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 2538914da7d0SScott Long size, sizeof(struct aac_fib)); 253935863739SMike Smith size = sizeof(struct aac_fib); 254035863739SMike Smith } 254135863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 254235863739SMike Smith goto out; 254335863739SMike Smith cm->cm_fib->Header.Size = size; 2544f6c4dd3fSScott Long cm->cm_timestamp = time_second; 254535863739SMike Smith 254635863739SMike Smith /* 254735863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 254835863739SMike Smith */ 2549b3457b51SScott Long if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 255070545d1aSScott Long device_printf(sc->aac_dev, 255170545d1aSScott Long "aac_wait_command return %d\n", error); 255235863739SMike Smith goto out; 2553b3457b51SScott Long } 255435863739SMike Smith 255535863739SMike Smith /* 255635863739SMike Smith * Copy the FIB and data back out to the caller. 255735863739SMike Smith */ 255835863739SMike Smith size = cm->cm_fib->Header.Size; 255935863739SMike Smith if (size > sizeof(struct aac_fib)) { 2560b88ffdc8SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 2561914da7d0SScott Long size, sizeof(struct aac_fib)); 256235863739SMike Smith size = sizeof(struct aac_fib); 256335863739SMike Smith } 256435863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 256535863739SMike Smith 256635863739SMike Smith out: 2567f6c4dd3fSScott Long if (cm != NULL) { 256835863739SMike Smith aac_release_command(cm); 2569f6c4dd3fSScott Long } 2570ae543596SScott Long 2571ae543596SScott Long AAC_LOCK_RELEASE(&sc->aac_io_lock); 257235863739SMike Smith return(error); 257335863739SMike Smith } 257435863739SMike Smith 2575914da7d0SScott Long /* 257635863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 257736e0bf6eSScott Long * If the queue fills up, then drop the older entries. 257835863739SMike Smith */ 257935863739SMike Smith static void 258036e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 258135863739SMike Smith { 258236e0bf6eSScott Long struct aac_aif_command *aif; 258336e0bf6eSScott Long struct aac_container *co, *co_next; 2584cbfd045bSScott Long struct aac_mntinfo *mi; 2585cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 258636e0bf6eSScott Long u_int16_t rsize; 2587b3457b51SScott Long int next, found; 2588795d7dc0SScott Long int count = 0, added = 0, i = 0; 258935863739SMike Smith 259035863739SMike Smith debug_called(2); 259135863739SMike Smith 259236e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 259336e0bf6eSScott Long aac_print_aif(sc, aif); 259436e0bf6eSScott Long 259536e0bf6eSScott Long /* Is it an event that we should care about? */ 259636e0bf6eSScott Long switch (aif->command) { 259736e0bf6eSScott Long case AifCmdEventNotify: 259836e0bf6eSScott Long switch (aif->data.EN.type) { 259936e0bf6eSScott Long case AifEnAddContainer: 260036e0bf6eSScott Long case AifEnDeleteContainer: 260136e0bf6eSScott Long /* 2602914da7d0SScott Long * A container was added or deleted, but the message 2603914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2604914da7d0SScott Long * containers and sort things out. 260536e0bf6eSScott Long */ 2606fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2607cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 260836e0bf6eSScott Long do { 260936e0bf6eSScott Long /* 2610914da7d0SScott Long * Ask the controller for its containers one at 2611914da7d0SScott Long * a time. 2612914da7d0SScott Long * XXX What if the controller's list changes 2613914da7d0SScott Long * midway through this enumaration? 261436e0bf6eSScott Long * XXX This should be done async. 261536e0bf6eSScott Long */ 261639ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 261739ee03c3SScott Long mi->Command = VM_NameServe; 261839ee03c3SScott Long mi->MntType = FT_FILESYS; 2619cbfd045bSScott Long mi->MntCount = i; 262036e0bf6eSScott Long rsize = sizeof(mir); 2621cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2622cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2623795d7dc0SScott Long printf("Error probing container %d\n", 2624914da7d0SScott Long i); 262536e0bf6eSScott Long continue; 262636e0bf6eSScott Long } 2627cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 2628795d7dc0SScott Long /* XXX Need to check if count changed */ 2629795d7dc0SScott Long count = mir->MntRespCount; 263036e0bf6eSScott Long /* 2631914da7d0SScott Long * Check the container against our list. 2632914da7d0SScott Long * co->co_found was already set to 0 in a 2633914da7d0SScott Long * previous run. 263436e0bf6eSScott Long */ 2635cbfd045bSScott Long if ((mir->Status == ST_OK) && 2636cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 263736e0bf6eSScott Long found = 0; 2638914da7d0SScott Long TAILQ_FOREACH(co, 2639914da7d0SScott Long &sc->aac_container_tqh, 2640914da7d0SScott Long co_link) { 264136e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2642cbfd045bSScott Long mir->MntTable[0].ObjectId) { 264336e0bf6eSScott Long co->co_found = 1; 264436e0bf6eSScott Long found = 1; 264536e0bf6eSScott Long break; 264636e0bf6eSScott Long } 264736e0bf6eSScott Long } 2648914da7d0SScott Long /* 2649914da7d0SScott Long * If the container matched, continue 2650914da7d0SScott Long * in the list. 2651914da7d0SScott Long */ 265236e0bf6eSScott Long if (found) { 265336e0bf6eSScott Long i++; 265436e0bf6eSScott Long continue; 265536e0bf6eSScott Long } 265636e0bf6eSScott Long 265736e0bf6eSScott Long /* 2658914da7d0SScott Long * This is a new container. Do all the 265970545d1aSScott Long * appropriate things to set it up. 266070545d1aSScott Long */ 2661cbfd045bSScott Long aac_add_container(sc, mir, 1); 266236e0bf6eSScott Long added = 1; 266336e0bf6eSScott Long } 266436e0bf6eSScott Long i++; 2665795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 2666cbfd045bSScott Long aac_release_sync_fib(sc); 266736e0bf6eSScott Long 266836e0bf6eSScott Long /* 2669914da7d0SScott Long * Go through our list of containers and see which ones 2670914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2671914da7d0SScott Long * list them they must have been deleted. Do the 2672914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2673914da7d0SScott Long * the co->co_found field. 267436e0bf6eSScott Long */ 267536e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 267636e0bf6eSScott Long while (co != NULL) { 267736e0bf6eSScott Long if (co->co_found == 0) { 2678914da7d0SScott Long device_delete_child(sc->aac_dev, 2679914da7d0SScott Long co->co_disk); 268036e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2681c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc-> 2682914da7d0SScott Long aac_container_lock); 2683914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2684914da7d0SScott Long co_link); 2685914da7d0SScott Long AAC_LOCK_RELEASE(&sc-> 2686914da7d0SScott Long aac_container_lock); 268736e0bf6eSScott Long FREE(co, M_AACBUF); 268836e0bf6eSScott Long co = co_next; 268936e0bf6eSScott Long } else { 269036e0bf6eSScott Long co->co_found = 0; 269136e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 269236e0bf6eSScott Long } 269336e0bf6eSScott Long } 269436e0bf6eSScott Long 269536e0bf6eSScott Long /* Attach the newly created containers */ 269636e0bf6eSScott Long if (added) 269736e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 269836e0bf6eSScott Long 269936e0bf6eSScott Long break; 270036e0bf6eSScott Long 270136e0bf6eSScott Long default: 270236e0bf6eSScott Long break; 270336e0bf6eSScott Long } 270436e0bf6eSScott Long 270536e0bf6eSScott Long default: 270636e0bf6eSScott Long break; 270736e0bf6eSScott Long } 270836e0bf6eSScott Long 270936e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2710c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 271135863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 271235863739SMike Smith if (next != sc->aac_aifq_tail) { 271335863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 271435863739SMike Smith sc->aac_aifq_head = next; 2715b3457b51SScott Long 2716b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 271735863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 271835863739SMike Smith wakeup(sc->aac_aifq); 2719b3457b51SScott Long /* Wakeup any poll()ers */ 2720b3457b51SScott Long selwakeup(&sc->rcv_select); 272135863739SMike Smith } 2722b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 272336e0bf6eSScott Long 272436e0bf6eSScott Long return; 272535863739SMike Smith } 272635863739SMike Smith 2727914da7d0SScott Long /* 27280b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 272936e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 273036e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 273136e0bf6eSScott Long * returning what the card reported. 273235863739SMike Smith */ 273335863739SMike Smith static int 2734fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 273535863739SMike Smith { 273635863739SMike Smith struct aac_rev_check rev_check; 273735863739SMike Smith struct aac_rev_check_resp rev_check_resp; 273835863739SMike Smith int error = 0; 273935863739SMike Smith 274035863739SMike Smith debug_called(2); 274135863739SMike Smith 274235863739SMike Smith /* 274335863739SMike Smith * Copyin the revision struct from userspace 274435863739SMike Smith */ 2745c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2746c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 274735863739SMike Smith return error; 274835863739SMike Smith } 274935863739SMike Smith 2750914da7d0SScott Long debug(2, "Userland revision= %d\n", 2751914da7d0SScott Long rev_check.callingRevision.buildNumber); 275235863739SMike Smith 275335863739SMike Smith /* 275435863739SMike Smith * Doctor up the response struct. 275535863739SMike Smith */ 275635863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2757914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2758914da7d0SScott Long sc->aac_revision.external.ul; 2759914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2760914da7d0SScott Long sc->aac_revision.buildNumber; 276135863739SMike Smith 2762c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2763c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 276435863739SMike Smith } 276535863739SMike Smith 2766914da7d0SScott Long /* 276735863739SMike Smith * Pass the caller the next AIF in their queue 276835863739SMike Smith */ 276935863739SMike Smith static int 2770fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 277135863739SMike Smith { 277235863739SMike Smith struct get_adapter_fib_ioctl agf; 27739e2e96d8SScott Long int error; 277435863739SMike Smith 277535863739SMike Smith debug_called(2); 277635863739SMike Smith 277735863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 277835863739SMike Smith 277935863739SMike Smith /* 278035863739SMike Smith * Check the magic number that we gave the caller. 278135863739SMike Smith */ 2782b88ffdc8SScott Long if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 278335863739SMike Smith error = EFAULT; 278435863739SMike Smith } else { 2785fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 278635863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 278735863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 278835863739SMike Smith while (error == EAGAIN) { 2789914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2790914da7d0SScott Long PCATCH, "aacaif", 0); 279135863739SMike Smith if (error == 0) 2792914da7d0SScott Long error = aac_return_aif(sc, 2793914da7d0SScott Long agf.AifFib); 279435863739SMike Smith } 279535863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 279635863739SMike Smith } 279735863739SMike Smith } 279835863739SMike Smith } 279935863739SMike Smith return(error); 280035863739SMike Smith } 280135863739SMike Smith 2802914da7d0SScott Long /* 28030b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 28040b94a66eSMike Smith */ 28050b94a66eSMike Smith static int 2806fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 28070b94a66eSMike Smith { 28083df780cfSScott Long int next, error; 28090b94a66eSMike Smith 28100b94a66eSMike Smith debug_called(2); 28110b94a66eSMike Smith 2812c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 28130b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 28143df780cfSScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 28153df780cfSScott Long return (EAGAIN); 28163df780cfSScott Long } 28173df780cfSScott Long 28183df780cfSScott Long next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 28193df780cfSScott Long error = copyout(&sc->aac_aifq[next], uptr, 2820c6eafcf2SScott Long sizeof(struct aac_aif_command)); 282136e0bf6eSScott Long if (error) 282270545d1aSScott Long device_printf(sc->aac_dev, 282370545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 28243df780cfSScott Long else 28253df780cfSScott Long sc->aac_aifq_tail = next; 28263df780cfSScott Long 2827b3457b51SScott Long AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 28280b94a66eSMike Smith return(error); 28290b94a66eSMike Smith } 283036e0bf6eSScott Long 2831914da7d0SScott Long /* 283236e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 283336e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 283436e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 283536e0bf6eSScott Long */ 283636e0bf6eSScott Long static int 283736e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 283836e0bf6eSScott Long { 283936e0bf6eSScott Long struct aac_query_disk query_disk; 284036e0bf6eSScott Long struct aac_container *co; 2841914da7d0SScott Long struct aac_disk *disk; 284236e0bf6eSScott Long int error, id; 284336e0bf6eSScott Long 284436e0bf6eSScott Long debug_called(2); 284536e0bf6eSScott Long 2846914da7d0SScott Long disk = NULL; 2847914da7d0SScott Long 2848914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2849914da7d0SScott Long sizeof(struct aac_query_disk)); 285036e0bf6eSScott Long if (error) 285136e0bf6eSScott Long return (error); 285236e0bf6eSScott Long 285336e0bf6eSScott Long id = query_disk.ContainerNumber; 285436e0bf6eSScott Long if (id == -1) 285536e0bf6eSScott Long return (EINVAL); 285636e0bf6eSScott Long 2857c3d15322SScott Long AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 285836e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 285936e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 286036e0bf6eSScott Long break; 286136e0bf6eSScott Long } 286236e0bf6eSScott Long 286336e0bf6eSScott Long if (co == NULL) { 286436e0bf6eSScott Long query_disk.Valid = 0; 286536e0bf6eSScott Long query_disk.Locked = 0; 286636e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 286736e0bf6eSScott Long } else { 286836e0bf6eSScott Long disk = device_get_softc(co->co_disk); 286936e0bf6eSScott Long query_disk.Valid = 1; 2870914da7d0SScott Long query_disk.Locked = 2871914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 287236e0bf6eSScott Long query_disk.Deleted = 0; 2873b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 287436e0bf6eSScott Long query_disk.Target = disk->unit; 287536e0bf6eSScott Long query_disk.Lun = 0; 287636e0bf6eSScott Long query_disk.UnMapped = 0; 28777540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 28787540e65eSScott Long disk->ad_disk.d_name, disk->ad_disk.d_unit); 287936e0bf6eSScott Long } 288036e0bf6eSScott Long AAC_LOCK_RELEASE(&sc->aac_container_lock); 288136e0bf6eSScott Long 2882914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2883914da7d0SScott Long sizeof(struct aac_query_disk)); 288436e0bf6eSScott Long 288536e0bf6eSScott Long return (error); 288636e0bf6eSScott Long } 288736e0bf6eSScott Long 2888fe3cb0e1SScott Long static void 2889fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2890fe3cb0e1SScott Long { 2891fe3cb0e1SScott Long struct aac_fib *fib; 2892fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2893fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2894fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2895fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2896fe3cb0e1SScott Long struct aac_getbusinf businfo; 289770545d1aSScott Long struct aac_sim *caminf; 2898fe3cb0e1SScott Long device_t child; 2899fe3cb0e1SScott Long int i, found, error; 2900fe3cb0e1SScott Long 2901fe3cb0e1SScott Long aac_alloc_sync_fib(sc, &fib, 0); 2902fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 290339ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2904fe3cb0e1SScott Long 2905fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2906fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2907fe3cb0e1SScott Long c_cmd->param = 0; 2908fe3cb0e1SScott Long 2909fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2910fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2911fe3cb0e1SScott Long if (error) { 2912fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2913fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2914fe3cb0e1SScott Long aac_release_sync_fib(sc); 2915fe3cb0e1SScott Long return; 2916fe3cb0e1SScott Long } 2917fe3cb0e1SScott Long 2918fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2919fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2920fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2921fe3cb0e1SScott Long c_resp->Status); 2922fe3cb0e1SScott Long aac_release_sync_fib(sc); 2923fe3cb0e1SScott Long return; 2924fe3cb0e1SScott Long } 2925fe3cb0e1SScott Long 2926fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2927fe3cb0e1SScott Long 2928fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 292939ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 293039ee03c3SScott Long 2931fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2932fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2933fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2934fe3cb0e1SScott Long vmi->ObjId = 0; 2935fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2936fe3cb0e1SScott Long 2937fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2938fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2939fe3cb0e1SScott Long if (error) { 2940fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2941fe3cb0e1SScott Long error); 2942fe3cb0e1SScott Long aac_release_sync_fib(sc); 2943fe3cb0e1SScott Long return; 2944fe3cb0e1SScott Long } 2945fe3cb0e1SScott Long 2946fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2947fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 2948fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2949fe3cb0e1SScott Long vmi_resp->Status); 2950fe3cb0e1SScott Long aac_release_sync_fib(sc); 2951fe3cb0e1SScott Long return; 2952fe3cb0e1SScott Long } 2953fe3cb0e1SScott Long 2954fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2955fe3cb0e1SScott Long aac_release_sync_fib(sc); 2956fe3cb0e1SScott Long 2957fe3cb0e1SScott Long found = 0; 2958fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 2959fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 2960fe3cb0e1SScott Long continue; 2961fe3cb0e1SScott Long 2962a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2963a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 2964fe3cb0e1SScott Long if (caminf == NULL) 2965fe3cb0e1SScott Long continue; 2966fe3cb0e1SScott Long 2967fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 2968fe3cb0e1SScott Long if (child == NULL) { 2969fe3cb0e1SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 2970fe3cb0e1SScott Long continue; 2971fe3cb0e1SScott Long } 2972fe3cb0e1SScott Long 2973fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 2974fe3cb0e1SScott Long caminf->BusNumber = i; 2975fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2976fe3cb0e1SScott Long caminf->aac_sc = sc; 2977ddb8683eSScott Long caminf->sim_dev = child; 2978fe3cb0e1SScott Long 2979fe3cb0e1SScott Long device_set_ivars(child, caminf); 2980fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 298170545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2982fe3cb0e1SScott Long 2983fe3cb0e1SScott Long found = 1; 2984fe3cb0e1SScott Long } 2985fe3cb0e1SScott Long 2986fe3cb0e1SScott Long if (found) 2987fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 2988fe3cb0e1SScott Long 2989fe3cb0e1SScott Long return; 2990fe3cb0e1SScott Long } 2991