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.h> 56b5f516cdSScott Long #include <sys/bus_dma.h> 5735863739SMike Smith #include <machine/resource.h> 5835863739SMike Smith 5935863739SMike Smith #include <dev/aac/aacreg.h> 600b0594cdSScott Long #include <sys/aac_ioctl.h> 6135863739SMike Smith #include <dev/aac/aacvar.h> 6235863739SMike Smith #include <dev/aac/aac_tables.h> 6335863739SMike Smith 6435863739SMike Smith static void aac_startup(void *arg); 65914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 66cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 67fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 6835863739SMike Smith 6935863739SMike Smith /* Command Processing */ 700b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7135863739SMike Smith static void aac_complete(void *context, int pending); 7235863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7335863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 74d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 7570545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 7635863739SMike Smith 7735863739SMike Smith /* Command Buffer Management */ 78cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 79cd481291SScott Long int nseg, int error); 80c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 81c6eafcf2SScott Long int nseg, int error); 820b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 838480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 8435863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 8535863739SMike Smith 8635863739SMike Smith /* Hardware Interface */ 87c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 88c6eafcf2SScott Long int error); 89fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9035863739SMike Smith static int aac_init(struct aac_softc *sc); 9135863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 92c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 93c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 94c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 95f6c4dd3fSScott Long struct aac_command *cm); 96c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 97914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 9836e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 9936e0bf6eSScott Long struct aac_fib *fib); 10035863739SMike Smith 101b3457b51SScott Long /* Falcon/PPC interface */ 102b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 103b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 104b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 105b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 106b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 107b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 108b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 109a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 110b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 111b3457b51SScott Long 112b3457b51SScott Long struct aac_interface aac_fa_interface = { 113b3457b51SScott Long aac_fa_get_fwstatus, 114b3457b51SScott Long aac_fa_qnotify, 115b3457b51SScott Long aac_fa_get_istatus, 116b3457b51SScott Long aac_fa_clear_istatus, 117b3457b51SScott Long aac_fa_set_mailbox, 118a6d35632SScott Long aac_fa_get_mailbox, 119b3457b51SScott Long aac_fa_set_interrupts 120b3457b51SScott Long }; 121b3457b51SScott Long 12235863739SMike Smith /* StrongARM interface */ 12335863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 12435863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 12535863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 12635863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 12735863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 128c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 129c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 130a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13135863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 13235863739SMike Smith 13335863739SMike Smith struct aac_interface aac_sa_interface = { 13435863739SMike Smith aac_sa_get_fwstatus, 13535863739SMike Smith aac_sa_qnotify, 13635863739SMike Smith aac_sa_get_istatus, 13735863739SMike Smith aac_sa_clear_istatus, 13835863739SMike Smith aac_sa_set_mailbox, 139a6d35632SScott Long aac_sa_get_mailbox, 14035863739SMike Smith aac_sa_set_interrupts 14135863739SMike Smith }; 14235863739SMike Smith 14335863739SMike Smith /* i960Rx interface */ 14435863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 14535863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 14635863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 14735863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 14835863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 149c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 150c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 151a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 15235863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 15335863739SMike Smith 15435863739SMike Smith struct aac_interface aac_rx_interface = { 15535863739SMike Smith aac_rx_get_fwstatus, 15635863739SMike Smith aac_rx_qnotify, 15735863739SMike Smith aac_rx_get_istatus, 15835863739SMike Smith aac_rx_clear_istatus, 15935863739SMike Smith aac_rx_set_mailbox, 160a6d35632SScott Long aac_rx_get_mailbox, 16135863739SMike Smith aac_rx_set_interrupts 16235863739SMike Smith }; 16335863739SMike Smith 1644afedc31SScott Long /* Rocket/MIPS interface */ 1654afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1664afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1674afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1684afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1694afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1704afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1714afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1724afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1734afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1744afedc31SScott Long 1754afedc31SScott Long struct aac_interface aac_rkt_interface = { 1764afedc31SScott Long aac_rkt_get_fwstatus, 1774afedc31SScott Long aac_rkt_qnotify, 1784afedc31SScott Long aac_rkt_get_istatus, 1794afedc31SScott Long aac_rkt_clear_istatus, 1804afedc31SScott Long aac_rkt_set_mailbox, 1814afedc31SScott Long aac_rkt_get_mailbox, 1824afedc31SScott Long aac_rkt_set_interrupts 1834afedc31SScott Long }; 1844afedc31SScott Long 18535863739SMike Smith /* Debugging and Diagnostics */ 18635863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1876965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 188c6eafcf2SScott Long u_int32_t code); 18935863739SMike Smith 19035863739SMike Smith /* Management Interface */ 19135863739SMike Smith static d_open_t aac_open; 19235863739SMike Smith static d_close_t aac_close; 19335863739SMike Smith static d_ioctl_t aac_ioctl; 194b3457b51SScott Long static d_poll_t aac_poll; 195c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 196c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 19736e0bf6eSScott Long struct aac_fib *fib); 198fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 199fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 200fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 20136e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 20235863739SMike Smith 20335863739SMike Smith static struct cdevsw aac_cdevsw = { 204dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 205dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 2067ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2077ac40f5fSPoul-Henning Kamp .d_close = aac_close, 2087ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2097ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2107ac40f5fSPoul-Henning Kamp .d_name = "aac", 21135863739SMike Smith }; 21235863739SMike Smith 21336e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 21436e0bf6eSScott Long 2153d04a9d7SScott Long /* sysctl node */ 2163d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2173d04a9d7SScott Long 218914da7d0SScott Long /* 219914da7d0SScott Long * Device Interface 220914da7d0SScott Long */ 22135863739SMike Smith 222914da7d0SScott Long /* 22335863739SMike Smith * Initialise the controller and softc 22435863739SMike Smith */ 22535863739SMike Smith int 22635863739SMike Smith aac_attach(struct aac_softc *sc) 22735863739SMike Smith { 22835863739SMike Smith int error, unit; 22935863739SMike Smith 23035863739SMike Smith debug_called(1); 23135863739SMike Smith 23235863739SMike Smith /* 23335863739SMike Smith * Initialise per-controller queues. 23435863739SMike Smith */ 2350b94a66eSMike Smith aac_initq_free(sc); 2360b94a66eSMike Smith aac_initq_ready(sc); 2370b94a66eSMike Smith aac_initq_busy(sc); 2380b94a66eSMike Smith aac_initq_bio(sc); 23935863739SMike Smith 24035863739SMike Smith /* 24135863739SMike Smith * Initialise command-completion task. 24235863739SMike Smith */ 24335863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 24435863739SMike Smith 24535863739SMike Smith /* disable interrupts before we enable anything */ 24635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 24735863739SMike Smith 24835863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 24935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25035863739SMike Smith 25135863739SMike Smith /* 252fe94b852SScott Long * Check that the firmware on the card is supported. 253fe94b852SScott Long */ 254fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 255fe94b852SScott Long return(error); 256fe94b852SScott Long 257f6b1c44dSScott Long /* 258f6b1c44dSScott Long * Initialize locks 259f6b1c44dSScott Long */ 260bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 261bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 262bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 263f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 264f6b1c44dSScott Long 2653df780cfSScott Long /* Initialize the local AIF queue pointers */ 2663df780cfSScott Long sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; 267cbfd045bSScott Long 2680b94a66eSMike Smith /* 26935863739SMike Smith * Initialise the adapter. 27035863739SMike Smith */ 2710b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 27235863739SMike Smith return(error); 27335863739SMike Smith 27435863739SMike Smith /* 27535863739SMike Smith * Print a little information about the controller. 27635863739SMike Smith */ 27735863739SMike Smith aac_describe_controller(sc); 27835863739SMike Smith 27935863739SMike Smith /* 280ae543596SScott Long * Register to probe our containers later. 281ae543596SScott Long */ 28235863739SMike Smith sc->aac_ich.ich_func = aac_startup; 28335863739SMike Smith sc->aac_ich.ich_arg = sc; 28435863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 285914da7d0SScott Long device_printf(sc->aac_dev, 286914da7d0SScott Long "can't establish configuration hook\n"); 28735863739SMike Smith return(ENXIO); 28835863739SMike Smith } 28935863739SMike Smith 29035863739SMike Smith /* 29135863739SMike Smith * Make the control device. 29235863739SMike Smith */ 29335863739SMike Smith unit = device_get_unit(sc->aac_dev); 2949e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 2959e9466baSRobert Watson 0640, "aac%d", unit); 296157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 2974aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 29835863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 29935863739SMike Smith 30036e0bf6eSScott Long /* Create the AIF thread */ 30170545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 302316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 30336e0bf6eSScott Long panic("Could not create AIF thread\n"); 30436e0bf6eSScott Long 30536e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3065f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3075f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3085f54d522SScott Long device_printf(sc->aac_dev, 3095f54d522SScott Long "shutdown event registration failed\n"); 31036e0bf6eSScott Long 311fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 312a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 31370545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 314fe3cb0e1SScott Long aac_get_bus_info(sc); 31570545d1aSScott Long } 316fe3cb0e1SScott Long 31735863739SMike Smith return(0); 31835863739SMike Smith } 31935863739SMike Smith 320914da7d0SScott Long /* 32135863739SMike Smith * Probe for containers, create disks. 32235863739SMike Smith */ 32335863739SMike Smith static void 32435863739SMike Smith aac_startup(void *arg) 32535863739SMike Smith { 326914da7d0SScott Long struct aac_softc *sc; 327cbfd045bSScott Long struct aac_fib *fib; 328cbfd045bSScott Long struct aac_mntinfo *mi; 329cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 330795d7dc0SScott Long int count = 0, i = 0; 33135863739SMike Smith 33235863739SMike Smith debug_called(1); 33335863739SMike Smith 334914da7d0SScott Long sc = (struct aac_softc *)arg; 335914da7d0SScott Long 33635863739SMike Smith /* disconnect ourselves from the intrhook chain */ 33735863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 33835863739SMike Smith 33903b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 340cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 341cbfd045bSScott Long 34235863739SMike Smith /* loop over possible containers */ 34336e0bf6eSScott Long do { 34435863739SMike Smith /* request information on this container */ 34539ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 34639ee03c3SScott Long mi->Command = VM_NameServe; 34739ee03c3SScott Long mi->MntType = FT_FILESYS; 348cbfd045bSScott Long mi->MntCount = i; 349cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 350cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 351795d7dc0SScott Long printf("error probing container %d", i); 35235863739SMike Smith continue; 35335863739SMike Smith } 35435863739SMike Smith 355cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 356795d7dc0SScott Long /* XXX Need to check if count changed */ 357795d7dc0SScott Long count = mir->MntRespCount; 358cbfd045bSScott Long aac_add_container(sc, mir, 0); 35936e0bf6eSScott Long i++; 360795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 361cbfd045bSScott Long 362cbfd045bSScott Long aac_release_sync_fib(sc); 36335863739SMike Smith 36435863739SMike Smith /* poke the bus to actually attach the child devices */ 36535863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 36635863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 36735863739SMike Smith 36835863739SMike Smith /* mark the controller up */ 36935863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 37035863739SMike Smith 37135863739SMike Smith /* enable interrupts now */ 37235863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 37335863739SMike Smith } 37435863739SMike Smith 375914da7d0SScott Long /* 376914da7d0SScott Long * Create a device to respresent a new container 377914da7d0SScott Long */ 378914da7d0SScott Long static void 379cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 380914da7d0SScott Long { 381914da7d0SScott Long struct aac_container *co; 382914da7d0SScott Long device_t child; 383914da7d0SScott Long 384914da7d0SScott Long /* 385914da7d0SScott Long * Check container volume type for validity. Note that many of 386914da7d0SScott Long * the possible types may never show up. 387914da7d0SScott Long */ 388914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 389a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 390a761a1caSScott Long M_NOWAIT | M_ZERO); 391914da7d0SScott Long if (co == NULL) 392914da7d0SScott Long panic("Out of memory?!\n"); 393914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 394914da7d0SScott Long mir->MntTable[0].ObjectId, 395914da7d0SScott Long mir->MntTable[0].FileSystemName, 396914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 397914da7d0SScott Long 398fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 399914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 400914da7d0SScott Long else 401914da7d0SScott Long device_set_ivars(child, co); 402914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 403914da7d0SScott Long mir->MntTable[0].VolType)); 404914da7d0SScott Long co->co_disk = child; 405914da7d0SScott Long co->co_found = f; 406914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 407914da7d0SScott Long sizeof(struct aac_mntobj)); 408bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 409914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 410bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 411914da7d0SScott Long } 412914da7d0SScott Long } 413914da7d0SScott Long 414914da7d0SScott Long /* 41535863739SMike Smith * Free all of the resources associated with (sc) 41635863739SMike Smith * 41735863739SMike Smith * Should not be called if the controller is active. 41835863739SMike Smith */ 41935863739SMike Smith void 42035863739SMike Smith aac_free(struct aac_softc *sc) 42135863739SMike Smith { 422ffb37f33SScott Long 42335863739SMike Smith debug_called(1); 42435863739SMike Smith 42535863739SMike Smith /* remove the control device */ 42635863739SMike Smith if (sc->aac_dev_t != NULL) 42735863739SMike Smith destroy_dev(sc->aac_dev_t); 42835863739SMike Smith 4290b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 4308480cc63SScott Long aac_free_commands(sc); 4310b94a66eSMike Smith if (sc->aac_fib_dmat) 4320b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 43335863739SMike Smith 434ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 435ffb37f33SScott Long 43635863739SMike Smith /* destroy the common area */ 43735863739SMike Smith if (sc->aac_common) { 43835863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 439c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 440c6eafcf2SScott Long sc->aac_common_dmamap); 44135863739SMike Smith } 4420b94a66eSMike Smith if (sc->aac_common_dmat) 4430b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 44435863739SMike Smith 44535863739SMike Smith /* disconnect the interrupt handler */ 44635863739SMike Smith if (sc->aac_intr) 44735863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 44835863739SMike Smith if (sc->aac_irq != NULL) 449c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 450c6eafcf2SScott Long sc->aac_irq); 45135863739SMike Smith 45235863739SMike Smith /* destroy data-transfer DMA tag */ 45335863739SMike Smith if (sc->aac_buffer_dmat) 45435863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 45535863739SMike Smith 45635863739SMike Smith /* destroy the parent DMA tag */ 45735863739SMike Smith if (sc->aac_parent_dmat) 45835863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 45935863739SMike Smith 46035863739SMike Smith /* release the register window mapping */ 46135863739SMike Smith if (sc->aac_regs_resource != NULL) 462914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 463914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 46435863739SMike Smith } 46535863739SMike Smith 466914da7d0SScott Long /* 46735863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 46835863739SMike Smith */ 46935863739SMike Smith int 47035863739SMike Smith aac_detach(device_t dev) 47135863739SMike Smith { 472914da7d0SScott Long struct aac_softc *sc; 47370545d1aSScott Long struct aac_container *co; 47470545d1aSScott Long struct aac_sim *sim; 47535863739SMike Smith int error; 47635863739SMike Smith 47735863739SMike Smith debug_called(1); 47835863739SMike Smith 479914da7d0SScott Long sc = device_get_softc(dev); 480914da7d0SScott Long 48135863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 48235863739SMike Smith return(EBUSY); 48335863739SMike Smith 48470545d1aSScott Long /* Remove the child containers */ 485a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 48670545d1aSScott Long error = device_delete_child(dev, co->co_disk); 48770545d1aSScott Long if (error) 48870545d1aSScott Long return (error); 48965ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 490a761a1caSScott Long free(co, M_AACBUF); 49170545d1aSScott Long } 49270545d1aSScott Long 49370545d1aSScott Long /* Remove the CAM SIMs */ 494a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 495a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 49670545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 49770545d1aSScott Long if (error) 49870545d1aSScott Long return (error); 499a761a1caSScott Long free(sim, M_AACBUF); 50070545d1aSScott Long } 50170545d1aSScott Long 50236e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 50336e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 50436e0bf6eSScott Long wakeup(sc->aifthread); 50536e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 50636e0bf6eSScott Long } 50736e0bf6eSScott Long 50836e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 50936e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 51036e0bf6eSScott Long 51135863739SMike Smith if ((error = aac_shutdown(dev))) 51235863739SMike Smith return(error); 51335863739SMike Smith 5145f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 5155f54d522SScott Long 51635863739SMike Smith aac_free(sc); 51735863739SMike Smith 518dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 519dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 520dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 521dc9efde5SScott Long 52235863739SMike Smith return(0); 52335863739SMike Smith } 52435863739SMike Smith 525914da7d0SScott Long /* 52635863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 52735863739SMike Smith * 52835863739SMike Smith * This function is called before detach or system shutdown. 52935863739SMike Smith * 5300b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 53135863739SMike Smith * allow shutdown if any device is open. 53235863739SMike Smith */ 53335863739SMike Smith int 53435863739SMike Smith aac_shutdown(device_t dev) 53535863739SMike Smith { 536914da7d0SScott Long struct aac_softc *sc; 537cbfd045bSScott Long struct aac_fib *fib; 538cbfd045bSScott Long struct aac_close_command *cc; 53935863739SMike Smith 54035863739SMike Smith debug_called(1); 54135863739SMike Smith 542914da7d0SScott Long sc = device_get_softc(dev); 543914da7d0SScott Long 54435863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 54535863739SMike Smith 54635863739SMike Smith /* 54735863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 54835863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 54935863739SMike Smith * We've been closed and all I/O completed already 55035863739SMike Smith */ 55135863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 55235863739SMike Smith 55303b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 554cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 555cbfd045bSScott Long 55639ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 557cbfd045bSScott Long cc->Command = VM_CloseAll; 558cbfd045bSScott Long cc->ContainerId = 0xffffffff; 559cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 560cbfd045bSScott Long sizeof(struct aac_close_command))) 56135863739SMike Smith printf("FAILED.\n"); 56270545d1aSScott Long else 56370545d1aSScott Long printf("done\n"); 56470545d1aSScott Long #if 0 565914da7d0SScott Long else { 566cbfd045bSScott Long fib->data[0] = 0; 56736e0bf6eSScott Long /* 568914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 56936e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 57036e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 57136e0bf6eSScott Long * driver module with the intent to reload it later. 57236e0bf6eSScott Long */ 573cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 574cbfd045bSScott Long fib, 1)) { 57535863739SMike Smith printf("FAILED.\n"); 57635863739SMike Smith } else { 57735863739SMike Smith printf("done.\n"); 57835863739SMike Smith } 57935863739SMike Smith } 58070545d1aSScott Long #endif 58135863739SMike Smith 58235863739SMike Smith AAC_MASK_INTERRUPTS(sc); 5833576af8fSScott Long aac_release_sync_fib(sc); 58435863739SMike Smith 58535863739SMike Smith return(0); 58635863739SMike Smith } 58735863739SMike Smith 588914da7d0SScott Long /* 58935863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 59035863739SMike Smith */ 59135863739SMike Smith int 59235863739SMike Smith aac_suspend(device_t dev) 59335863739SMike Smith { 594914da7d0SScott Long struct aac_softc *sc; 59535863739SMike Smith 59635863739SMike Smith debug_called(1); 597914da7d0SScott Long 598914da7d0SScott Long sc = device_get_softc(dev); 599914da7d0SScott Long 60035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 60135863739SMike Smith 60235863739SMike Smith AAC_MASK_INTERRUPTS(sc); 60335863739SMike Smith return(0); 60435863739SMike Smith } 60535863739SMike Smith 606914da7d0SScott Long /* 60735863739SMike Smith * Bring the controller back to a state ready for operation. 60835863739SMike Smith */ 60935863739SMike Smith int 61035863739SMike Smith aac_resume(device_t dev) 61135863739SMike Smith { 612914da7d0SScott Long struct aac_softc *sc; 61335863739SMike Smith 61435863739SMike Smith debug_called(1); 615914da7d0SScott Long 616914da7d0SScott Long sc = device_get_softc(dev); 617914da7d0SScott Long 61835863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 61935863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 62035863739SMike Smith return(0); 62135863739SMike Smith } 62235863739SMike Smith 623914da7d0SScott Long /* 62435863739SMike Smith * Take an interrupt. 62535863739SMike Smith */ 62635863739SMike Smith void 62735863739SMike Smith aac_intr(void *arg) 62835863739SMike Smith { 629914da7d0SScott Long struct aac_softc *sc; 63070545d1aSScott Long u_int16_t reason; 63135863739SMike Smith 63235863739SMike Smith debug_called(2); 63335863739SMike Smith 634914da7d0SScott Long sc = (struct aac_softc *)arg; 635914da7d0SScott Long 636f30ac74cSScott Long /* 6379148fa21SScott Long * Read the status register directly. This is faster than taking the 6389148fa21SScott Long * driver lock and reading the queues directly. It also saves having 6399148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 6409148fa21SScott Long * ugly. 641f30ac74cSScott Long */ 64235863739SMike Smith reason = AAC_GET_ISTATUS(sc); 643f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 644f30ac74cSScott Long 6459c3a7fceSScott Long /* handle completion processing */ 6469148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 6479148fa21SScott Long taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 64835863739SMike Smith 6499148fa21SScott Long /* controller wants to talk to us */ 6509148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 65170545d1aSScott Long /* 6529148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 6539148fa21SScott Long * that start with a NULL. 65470545d1aSScott Long */ 6559148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 6569148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 6579148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 65870545d1aSScott Long 6599148fa21SScott Long /* 6609148fa21SScott Long * This might miss doing the actual wakeup. However, the 661a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 6629148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 6639148fa21SScott Long * priority that they can handle hanging out for a few seconds 6649148fa21SScott Long * if needed. 6659148fa21SScott Long */ 66636e0bf6eSScott Long wakeup(sc->aifthread); 66736e0bf6eSScott Long } 6689148fa21SScott Long } 66935863739SMike Smith 670c6eafcf2SScott Long /* 671914da7d0SScott Long * Command Processing 672914da7d0SScott Long */ 67335863739SMike Smith 674914da7d0SScott Long /* 67535863739SMike Smith * Start as much queued I/O as possible on the controller 67635863739SMike Smith */ 677fe3cb0e1SScott Long void 67835863739SMike Smith aac_startio(struct aac_softc *sc) 67935863739SMike Smith { 68035863739SMike Smith struct aac_command *cm; 681397fa34fSScott Long int error; 68235863739SMike Smith 68335863739SMike Smith debug_called(2); 68435863739SMike Smith 68535863739SMike Smith for (;;) { 686914da7d0SScott Long /* 687397fa34fSScott Long * This flag might be set if the card is out of resources. 688397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 689397fa34fSScott Long */ 690397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 691397fa34fSScott Long break; 692397fa34fSScott Long 693397fa34fSScott Long /* 694914da7d0SScott Long * Try to get a command that's been put off for lack of 695914da7d0SScott Long * resources 696914da7d0SScott Long */ 69735863739SMike Smith cm = aac_dequeue_ready(sc); 69835863739SMike Smith 699914da7d0SScott Long /* 700914da7d0SScott Long * Try to build a command off the bio queue (ignore error 701914da7d0SScott Long * return) 702914da7d0SScott Long */ 7030b94a66eSMike Smith if (cm == NULL) 70435863739SMike Smith aac_bio_command(sc, &cm); 70535863739SMike Smith 70635863739SMike Smith /* nothing to do? */ 70735863739SMike Smith if (cm == NULL) 70835863739SMike Smith break; 70935863739SMike Smith 710cd481291SScott Long /* don't map more than once */ 711cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 7124102d44bSScott Long panic("aac: command %p already mapped", cm); 71335863739SMike Smith 714397fa34fSScott Long /* 715397fa34fSScott Long * Set up the command to go to the controller. If there are no 716397fa34fSScott Long * data buffers associated with the command then it can bypass 717397fa34fSScott Long * busdma. 718397fa34fSScott Long */ 719cd481291SScott Long if (cm->cm_datalen != 0) { 720397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 721397fa34fSScott Long cm->cm_datamap, cm->cm_data, 722397fa34fSScott Long 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; 728614c22b2SScott Long } else if (error != 0) 729397fa34fSScott Long panic("aac_startio: unexpected error %d from " 730397fa34fSScott Long "busdma\n", error); 731397fa34fSScott Long } else 7328778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 733cd481291SScott Long } 73435863739SMike Smith } 73535863739SMike Smith 736914da7d0SScott Long /* 73735863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 73835863739SMike Smith */ 73935863739SMike Smith static void 74070545d1aSScott Long aac_command_thread(struct aac_softc *sc) 74135863739SMike Smith { 74235863739SMike Smith struct aac_fib *fib; 74335863739SMike Smith u_int32_t fib_size; 7449148fa21SScott Long int size, retval; 74535863739SMike Smith 74636e0bf6eSScott Long debug_called(2); 74735863739SMike Smith 748bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 749a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 75036e0bf6eSScott Long 751a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 752a32a982dSScott Long 753a32a982dSScott Long retval = 0; 754a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 755a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 756a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 75736e0bf6eSScott Long 7589148fa21SScott Long /* 7599148fa21SScott Long * First see if any FIBs need to be allocated. This needs 7609148fa21SScott Long * to be called without the driver lock because contigmalloc 7619148fa21SScott Long * will grab Giant, and would result in an LOR. 7629148fa21SScott Long */ 7639148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 764bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 765a32a982dSScott Long aac_alloc_commands(sc); 766bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 7674102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 768a32a982dSScott Long aac_startio(sc); 769a32a982dSScott Long } 7709148fa21SScott Long 7719148fa21SScott Long /* 7729148fa21SScott Long * While we're here, check to see if any commands are stuck. 7739148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 7749148fa21SScott Long * always fire. 7759148fa21SScott Long */ 7769148fa21SScott Long if (retval == EWOULDBLOCK) 77770545d1aSScott Long aac_timeout(sc); 77870545d1aSScott Long 77970545d1aSScott Long /* Check the hardware printf message buffer */ 7809148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 78170545d1aSScott Long aac_print_printf(sc); 78270545d1aSScott Long 7839148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 7849148fa21SScott Long while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 7859148fa21SScott Long &fib_size, &fib) == 0) { 78635863739SMike Smith 78736e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 78836e0bf6eSScott Long 78935863739SMike Smith switch (fib->Header.Command) { 79035863739SMike Smith case AifRequest: 79136e0bf6eSScott Long aac_handle_aif(sc, fib); 79235863739SMike Smith break; 79335863739SMike Smith default: 794914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 795914da7d0SScott Long "from controller\n"); 79635863739SMike Smith break; 79735863739SMike Smith } 79835863739SMike Smith 79936e0bf6eSScott Long if ((fib->Header.XferState == 0) || 80036e0bf6eSScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 80136e0bf6eSScott Long break; 80236e0bf6eSScott Long 80370545d1aSScott Long /* Return the AIF to the controller. */ 80436e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 80536e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 80636e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 80736e0bf6eSScott Long 80836e0bf6eSScott Long /* XXX Compute the Size field? */ 80936e0bf6eSScott Long size = fib->Header.Size; 81036e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 81136e0bf6eSScott Long size = sizeof(struct aac_fib); 81236e0bf6eSScott Long fib->Header.Size = size; 81336e0bf6eSScott Long } 81436e0bf6eSScott Long /* 815914da7d0SScott Long * Since we did not generate this command, it 816914da7d0SScott Long * cannot go through the normal 817914da7d0SScott Long * enqueue->startio chain. 81836e0bf6eSScott Long */ 819914da7d0SScott Long aac_enqueue_response(sc, 820914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 821914da7d0SScott Long fib); 82236e0bf6eSScott Long } 82336e0bf6eSScott Long } 82436e0bf6eSScott Long } 82536e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 826bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 82736e0bf6eSScott Long wakeup(sc->aac_dev); 82836e0bf6eSScott Long 82936e0bf6eSScott Long kthread_exit(0); 83035863739SMike Smith } 83135863739SMike Smith 832914da7d0SScott Long /* 8339c3a7fceSScott Long * Process completed commands. 83435863739SMike Smith */ 83535863739SMike Smith static void 8369c3a7fceSScott Long aac_complete(void *context, int pending) 83735863739SMike Smith { 8389c3a7fceSScott Long struct aac_softc *sc; 83935863739SMike Smith struct aac_command *cm; 84035863739SMike Smith struct aac_fib *fib; 84135863739SMike Smith u_int32_t fib_size; 84235863739SMike Smith 84335863739SMike Smith debug_called(2); 84435863739SMike Smith 8459c3a7fceSScott Long sc = (struct aac_softc *)context; 8469c3a7fceSScott Long 847bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 848ae543596SScott Long 8499c3a7fceSScott Long /* pull completed commands off the queue */ 85035863739SMike Smith for (;;) { 85135863739SMike Smith /* look for completed FIBs on our queue */ 852914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 853914da7d0SScott Long &fib)) 85435863739SMike Smith break; /* nothing to do */ 85535863739SMike Smith 856ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 857cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 85835863739SMike Smith if (cm == NULL) { 85935863739SMike Smith AAC_PRINT_FIB(sc, fib); 8609c3a7fceSScott Long break; 8619c3a7fceSScott Long } 8629c3a7fceSScott Long 8630b94a66eSMike Smith aac_remove_busy(cm); 864ecd1c51fSScott Long aac_unmap_command(cm); 86535863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 86635863739SMike Smith 86735863739SMike Smith /* is there a completion handler? */ 86835863739SMike Smith if (cm->cm_complete != NULL) { 86935863739SMike Smith cm->cm_complete(cm); 87035863739SMike Smith } else { 87135863739SMike Smith /* assume that someone is sleeping on this command */ 87235863739SMike Smith wakeup(cm); 87335863739SMike Smith } 87435863739SMike Smith } 8750b94a66eSMike Smith 8760b94a66eSMike Smith /* see if we can start some more I/O */ 877cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 8780b94a66eSMike Smith aac_startio(sc); 879ae543596SScott Long 880bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 88135863739SMike Smith } 88235863739SMike Smith 883914da7d0SScott Long /* 88435863739SMike Smith * Handle a bio submitted from a disk device. 88535863739SMike Smith */ 88635863739SMike Smith void 88735863739SMike Smith aac_submit_bio(struct bio *bp) 88835863739SMike Smith { 889914da7d0SScott Long struct aac_disk *ad; 890914da7d0SScott Long struct aac_softc *sc; 89135863739SMike Smith 89235863739SMike Smith debug_called(2); 89335863739SMike Smith 8947540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 895914da7d0SScott Long sc = ad->ad_controller; 896914da7d0SScott Long 89735863739SMike Smith /* queue the BIO and try to get some work done */ 8980b94a66eSMike Smith aac_enqueue_bio(sc, bp); 89935863739SMike Smith aac_startio(sc); 90035863739SMike Smith } 90135863739SMike Smith 902914da7d0SScott Long /* 90335863739SMike Smith * Get a bio and build a command to go with it. 90435863739SMike Smith */ 90535863739SMike Smith static int 90635863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 90735863739SMike Smith { 90835863739SMike Smith struct aac_command *cm; 90935863739SMike Smith struct aac_fib *fib; 91035863739SMike Smith struct aac_disk *ad; 91135863739SMike Smith struct bio *bp; 91235863739SMike Smith 91335863739SMike Smith debug_called(2); 91435863739SMike Smith 91535863739SMike Smith /* get the resources we will need */ 91635863739SMike Smith cm = NULL; 917a32a982dSScott Long bp = NULL; 91835863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 91935863739SMike Smith goto fail; 920a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 921a32a982dSScott Long goto fail; 92235863739SMike Smith 92335863739SMike Smith /* fill out the command */ 9240b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 9250b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 9260b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 92735863739SMike Smith cm->cm_private = bp; 9280b94a66eSMike Smith cm->cm_timestamp = time_second; 92936e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 93035863739SMike Smith 93135863739SMike Smith /* build the FIB */ 93235863739SMike Smith fib = cm->cm_fib; 933b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 93435863739SMike Smith fib->Header.XferState = 93535863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 93635863739SMike Smith AAC_FIBSTATE_INITIALISED | 937f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 93835863739SMike Smith AAC_FIBSTATE_FROMHOST | 93935863739SMike Smith AAC_FIBSTATE_REXPECTED | 940f30ac74cSScott Long AAC_FIBSTATE_NORM | 941f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 942f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 94335863739SMike Smith 94435863739SMike Smith /* build the read/write request */ 9457540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 946b85f5808SScott Long 947b85f5808SScott Long if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 948b85f5808SScott Long fib->Header.Command = ContainerCommand; 9499e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 950b85f5808SScott Long struct aac_blockread *br; 95135863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 95235863739SMike Smith br->Command = VM_CtBlockRead; 95335863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 95435863739SMike Smith br->BlockNumber = bp->bio_pblkno; 95535863739SMike Smith br->ByteCount = bp->bio_bcount; 95635863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 95735863739SMike Smith cm->cm_sgtable = &br->SgMap; 95835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 95935863739SMike Smith } else { 960b85f5808SScott Long struct aac_blockwrite *bw; 96135863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 96235863739SMike Smith bw->Command = VM_CtBlockWrite; 96335863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 96435863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 96535863739SMike Smith bw->ByteCount = bp->bio_bcount; 966b85f5808SScott Long bw->Stable = CUNSTABLE; 96735863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 96835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 96935863739SMike Smith cm->cm_sgtable = &bw->SgMap; 97035863739SMike Smith } 971b85f5808SScott Long } else { 972b85f5808SScott Long fib->Header.Command = ContainerCommand64; 973b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 974b85f5808SScott Long struct aac_blockread64 *br; 975b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 976b85f5808SScott Long br->Command = VM_CtHostRead64; 977b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 978b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 979b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 980b85f5808SScott Long br->Pad = 0; 981b85f5808SScott Long br->Flags = 0; 982b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 983b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 984eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 985b85f5808SScott Long } else { 986b85f5808SScott Long struct aac_blockwrite64 *bw; 987b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 988b85f5808SScott Long bw->Command = VM_CtHostWrite64; 989b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 990b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 991b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 992b85f5808SScott Long bw->Pad = 0; 993b85f5808SScott Long bw->Flags = 0; 994b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 995b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 996eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 997b85f5808SScott Long } 998b85f5808SScott Long } 99935863739SMike Smith 100035863739SMike Smith *cmp = cm; 100135863739SMike Smith return(0); 100235863739SMike Smith 100335863739SMike Smith fail: 100435863739SMike Smith if (cm != NULL) 100535863739SMike Smith aac_release_command(cm); 100635863739SMike Smith return(ENOMEM); 100735863739SMike Smith } 100835863739SMike Smith 1009914da7d0SScott Long /* 101035863739SMike Smith * Handle a bio-instigated command that has been completed. 101135863739SMike Smith */ 101235863739SMike Smith static void 101335863739SMike Smith aac_bio_complete(struct aac_command *cm) 101435863739SMike Smith { 101535863739SMike Smith struct aac_blockread_response *brr; 101635863739SMike Smith struct aac_blockwrite_response *bwr; 101735863739SMike Smith struct bio *bp; 101835863739SMike Smith AAC_FSAStatus status; 101935863739SMike Smith 102035863739SMike Smith /* fetch relevant status and then release the command */ 102135863739SMike Smith bp = (struct bio *)cm->cm_private; 10229e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 102335863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 102435863739SMike Smith status = brr->Status; 102535863739SMike Smith } else { 102635863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 102735863739SMike Smith status = bwr->Status; 102835863739SMike Smith } 102935863739SMike Smith aac_release_command(cm); 103035863739SMike Smith 103135863739SMike Smith /* fix up the bio based on status */ 103235863739SMike Smith if (status == ST_OK) { 103335863739SMike Smith bp->bio_resid = 0; 103435863739SMike Smith } else { 103535863739SMike Smith bp->bio_error = EIO; 103635863739SMike Smith bp->bio_flags |= BIO_ERROR; 10370b94a66eSMike Smith /* pass an error string out to the disk layer */ 1038914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1039914da7d0SScott Long status); 104035863739SMike Smith } 10410b94a66eSMike Smith aac_biodone(bp); 104235863739SMike Smith } 104335863739SMike Smith 1044914da7d0SScott Long /* 104535863739SMike Smith * Submit a command to the controller, return when it completes. 1046b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1047b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1048d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1049d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1050d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1051d8a0a473SScott Long * card completing a command late and spamming the command and data 1052d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 105335863739SMike Smith */ 105435863739SMike Smith static int 1055d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 105635863739SMike Smith { 1057ae543596SScott Long struct aac_softc *sc; 1058d8a0a473SScott Long int error; 105935863739SMike Smith 106035863739SMike Smith debug_called(2); 106135863739SMike Smith 1062ae543596SScott Long sc = cm->cm_sc; 1063ae543596SScott Long 106435863739SMike Smith /* Put the command on the ready queue and get things going */ 106536e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 106635863739SMike Smith aac_enqueue_ready(cm); 1067ae543596SScott Long aac_startio(sc); 1068ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 106935863739SMike Smith return(error); 107035863739SMike Smith } 107135863739SMike Smith 1072914da7d0SScott Long /* 1073914da7d0SScott Long *Command Buffer Management 1074914da7d0SScott Long */ 107535863739SMike Smith 1076914da7d0SScott Long /* 107735863739SMike Smith * Allocate a command. 107835863739SMike Smith */ 1079fe3cb0e1SScott Long int 108035863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 108135863739SMike Smith { 108235863739SMike Smith struct aac_command *cm; 108335863739SMike Smith 108435863739SMike Smith debug_called(3); 108535863739SMike Smith 1086ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1087b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1088ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1089ae543596SScott Long wakeup(sc->aifthread); 1090b85f5808SScott Long } 1091ae543596SScott Long return (EBUSY); 1092ffb37f33SScott Long } 109335863739SMike Smith 10940b94a66eSMike Smith *cmp = cm; 10950b94a66eSMike Smith return(0); 10960b94a66eSMike Smith } 10970b94a66eSMike Smith 1098914da7d0SScott Long /* 10990b94a66eSMike Smith * Release a command back to the freelist. 11000b94a66eSMike Smith */ 1101fe3cb0e1SScott Long void 11020b94a66eSMike Smith aac_release_command(struct aac_command *cm) 11030b94a66eSMike Smith { 11040b94a66eSMike Smith debug_called(3); 11050b94a66eSMike Smith 11060b94a66eSMike Smith /* (re)initialise the command/FIB */ 110735863739SMike Smith cm->cm_sgtable = NULL; 110835863739SMike Smith cm->cm_flags = 0; 110935863739SMike Smith cm->cm_complete = NULL; 111035863739SMike Smith cm->cm_private = NULL; 111135863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 111235863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 111335863739SMike Smith cm->cm_fib->Header.Flags = 0; 111435863739SMike Smith cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 111535863739SMike Smith 111635863739SMike Smith /* 111735863739SMike Smith * These are duplicated in aac_start to cover the case where an 111835863739SMike Smith * intermediate stage may have destroyed them. They're left 111935863739SMike Smith * initialised here for debugging purposes only. 112035863739SMike Smith */ 1121f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1122f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 112335863739SMike Smith 112435863739SMike Smith aac_enqueue_free(cm); 112535863739SMike Smith } 112635863739SMike Smith 1127914da7d0SScott Long /* 11280b94a66eSMike Smith * Map helper for command/FIB allocation. 112935863739SMike Smith */ 113035863739SMike Smith static void 11310b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 113235863739SMike Smith { 11338480cc63SScott Long uint32_t *fibphys; 1134914da7d0SScott Long 11358480cc63SScott Long fibphys = (uint32_t *)arg; 113635863739SMike Smith 113735863739SMike Smith debug_called(3); 113835863739SMike Smith 1139ffb37f33SScott Long *fibphys = segs[0].ds_addr; 114035863739SMike Smith } 114135863739SMike Smith 1142914da7d0SScott Long /* 11430b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 114435863739SMike Smith */ 11450b94a66eSMike Smith static int 11460b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 114735863739SMike Smith { 114835863739SMike Smith struct aac_command *cm; 1149ffb37f33SScott Long struct aac_fibmap *fm; 11508480cc63SScott Long uint32_t fibphys; 1151ffb37f33SScott Long int i, error; 115235863739SMike Smith 1153a6d35632SScott Long debug_called(2); 115435863739SMike Smith 1155a6d35632SScott Long if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs) 1156ffb37f33SScott Long return (ENOMEM); 1157ffb37f33SScott Long 11588480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1159a6d35632SScott Long if (fm == NULL) 1160a6d35632SScott Long return (ENOMEM); 1161ffb37f33SScott Long 11620b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1163ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1164ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 116570545d1aSScott Long device_printf(sc->aac_dev, 116670545d1aSScott Long "Not enough contiguous memory available.\n"); 11678480cc63SScott Long free(fm, M_AACBUF); 11680b94a66eSMike Smith return (ENOMEM); 116935863739SMike Smith } 1170128aa5a0SScott Long 1171cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1172cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1173ffb37f33SScott Long AAC_FIB_COUNT * sizeof(struct aac_fib), 1174ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1175128aa5a0SScott Long 11760b94a66eSMike Smith /* initialise constant fields in the command structure */ 1177bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1178ffb37f33SScott Long bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 11790b94a66eSMike Smith for (i = 0; i < AAC_FIB_COUNT; i++) { 11808480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1181ffb37f33SScott Long fm->aac_commands = cm; 118235863739SMike Smith cm->cm_sc = sc; 1183ffb37f33SScott Long cm->cm_fib = fm->aac_fibs + i; 11848480cc63SScott Long cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1185cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 118635863739SMike Smith 1187ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1188ffb37f33SScott Long &cm->cm_datamap)) == 0) 118935863739SMike Smith aac_release_command(cm); 1190ffb37f33SScott Long else 11918480cc63SScott Long break; 11928480cc63SScott Long sc->total_fibs++; 119335863739SMike Smith } 1194ffb37f33SScott Long 11958480cc63SScott Long if (i > 0) { 1196ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1197a6d35632SScott Long debug(1, "total_fibs= %d\n", sc->total_fibs); 1198bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 11990b94a66eSMike Smith return (0); 120035863739SMike Smith } 120135863739SMike Smith 1202bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 12038480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 12048480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12058480cc63SScott Long free(fm, M_AACBUF); 12068480cc63SScott Long return (ENOMEM); 12078480cc63SScott Long } 12088480cc63SScott Long 1209914da7d0SScott Long /* 12100b94a66eSMike Smith * Free FIBs owned by this adapter. 121135863739SMike Smith */ 121235863739SMike Smith static void 12138480cc63SScott Long aac_free_commands(struct aac_softc *sc) 121435863739SMike Smith { 12158480cc63SScott Long struct aac_fibmap *fm; 1216ffb37f33SScott Long struct aac_command *cm; 121735863739SMike Smith int i; 121835863739SMike Smith 121935863739SMike Smith debug_called(1); 122035863739SMike Smith 12218480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 12228480cc63SScott Long 12238480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 12248480cc63SScott Long /* 12258480cc63SScott Long * We check against total_fibs to handle partially 12268480cc63SScott Long * allocated blocks. 12278480cc63SScott Long */ 12288480cc63SScott Long for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1229ffb37f33SScott Long cm = fm->aac_commands + i; 1230ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1231ffb37f33SScott Long } 1232ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1233ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 12348480cc63SScott Long free(fm, M_AACBUF); 12358480cc63SScott Long } 123635863739SMike Smith } 123735863739SMike Smith 1238914da7d0SScott Long /* 123935863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 124035863739SMike Smith */ 124135863739SMike Smith static void 124235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 124335863739SMike Smith { 1244cd481291SScott Long struct aac_softc *sc; 1245914da7d0SScott Long struct aac_command *cm; 1246914da7d0SScott Long struct aac_fib *fib; 124735863739SMike Smith int i; 124835863739SMike Smith 124935863739SMike Smith debug_called(3); 125035863739SMike Smith 1251914da7d0SScott Long cm = (struct aac_command *)arg; 1252cd481291SScott Long sc = cm->cm_sc; 1253914da7d0SScott Long fib = cm->cm_fib; 1254914da7d0SScott Long 125535863739SMike Smith /* copy into the FIB */ 1256b85f5808SScott Long if (cm->cm_sgtable != NULL) { 1257b85f5808SScott Long if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1258b85f5808SScott Long struct aac_sg_table *sg; 1259b85f5808SScott Long sg = cm->cm_sgtable; 126035863739SMike Smith sg->SgCount = nseg; 126135863739SMike Smith for (i = 0; i < nseg; i++) { 126235863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 126335863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 126435863739SMike Smith } 126535863739SMike Smith /* update the FIB size for the s/g count */ 126635863739SMike Smith fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 1267b85f5808SScott Long } else { 1268b85f5808SScott Long struct aac_sg_table64 *sg; 1269b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1270b85f5808SScott Long sg->SgCount = nseg; 1271b85f5808SScott Long for (i = 0; i < nseg; i++) { 1272b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1273b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 127435863739SMike Smith } 1275b85f5808SScott Long /* update the FIB size for the s/g count */ 1276b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1277b85f5808SScott Long } 1278b85f5808SScott Long } 127935863739SMike Smith 1280cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1281cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 1282cd481291SScott Long * the SenderFibAddress over to make room for the fast response bit. 128335863739SMike Smith */ 1284cd481291SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1); 1285cd481291SScott Long cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 128635863739SMike Smith 1287cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1288cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 128935863739SMike Smith 129035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1291c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1292c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 129335863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1294c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1295c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 129635863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1297cd481291SScott Long 1298397fa34fSScott Long /* Put the FIB on the outbound queue */ 12994102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 13004102d44bSScott Long aac_unmap_command(cm); 1301397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1302cd481291SScott Long aac_requeue_ready(cm); 13034102d44bSScott Long } 1304cd481291SScott Long 1305cd481291SScott Long return; 130635863739SMike Smith } 130735863739SMike Smith 1308914da7d0SScott Long /* 130935863739SMike Smith * Unmap a command from controller-visible space. 131035863739SMike Smith */ 131135863739SMike Smith static void 131235863739SMike Smith aac_unmap_command(struct aac_command *cm) 131335863739SMike Smith { 1314914da7d0SScott Long struct aac_softc *sc; 131535863739SMike Smith 131635863739SMike Smith debug_called(2); 131735863739SMike Smith 1318914da7d0SScott Long sc = cm->cm_sc; 1319914da7d0SScott Long 132035863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 132135863739SMike Smith return; 132235863739SMike Smith 132335863739SMike Smith if (cm->cm_datalen != 0) { 132435863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1325c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1326c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 132735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1328c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1329c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 133035863739SMike Smith 133135863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 133235863739SMike Smith } 133335863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 133435863739SMike Smith } 133535863739SMike Smith 1336914da7d0SScott Long /* 1337914da7d0SScott Long * Hardware Interface 1338914da7d0SScott Long */ 133935863739SMike Smith 1340914da7d0SScott Long /* 134135863739SMike Smith * Initialise the adapter. 134235863739SMike Smith */ 134335863739SMike Smith static void 134435863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 134535863739SMike Smith { 1346914da7d0SScott Long struct aac_softc *sc; 134735863739SMike Smith 134835863739SMike Smith debug_called(1); 134935863739SMike Smith 1350914da7d0SScott Long sc = (struct aac_softc *)arg; 1351914da7d0SScott Long 135235863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 135335863739SMike Smith } 135435863739SMike Smith 1355a6d35632SScott Long static int 1356a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1357a6d35632SScott Long { 1358a6d35632SScott Long u_int32_t major, minor, options; 1359a6d35632SScott Long 1360a6d35632SScott Long debug_called(1); 1361a6d35632SScott Long 1362fe94b852SScott Long /* 1363fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1364fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1365fe94b852SScott Long */ 1366a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1367fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1368fe94b852SScott Long NULL)) { 1369fe94b852SScott Long device_printf(sc->aac_dev, 1370fe94b852SScott Long "Error reading firmware version\n"); 1371fe94b852SScott Long return (EIO); 1372fe94b852SScott Long } 1373fe94b852SScott Long 1374fe94b852SScott Long /* These numbers are stored as ASCII! */ 1375a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1376a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1377fe94b852SScott Long if (major == 1) { 1378fe94b852SScott Long device_printf(sc->aac_dev, 1379fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1380fe94b852SScott Long major, minor); 1381fe94b852SScott Long return (EINVAL); 1382fe94b852SScott Long } 1383fe94b852SScott Long } 1384fe94b852SScott Long 1385a6d35632SScott Long /* 1386a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1387a6d35632SScott Long * work-arounds to enable. 1388a6d35632SScott Long */ 1389a6d35632SScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1390a6d35632SScott Long device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1391a6d35632SScott Long return (EIO); 1392a6d35632SScott Long } 1393a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 1394a6d35632SScott Long sc->supported_options = options; 1395a6d35632SScott Long 1396a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1397a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1398a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1399a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1400a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1401cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1402cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1403a6d35632SScott Long device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1404a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1405a6d35632SScott Long } 1406a6d35632SScott Long 1407a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 1408a6d35632SScott Long if ((sc->flags & AAC_FLAGS_256FIBS) == 0) 1409a6d35632SScott Long sc->aac_max_fibs = AAC_MAX_FIBS; 1410a6d35632SScott Long else 1411a6d35632SScott Long sc->aac_max_fibs = 256; 1412a6d35632SScott Long 1413fe94b852SScott Long return (0); 1414fe94b852SScott Long } 1415fe94b852SScott Long 141635863739SMike Smith static int 141735863739SMike Smith aac_init(struct aac_softc *sc) 141835863739SMike Smith { 141935863739SMike Smith struct aac_adapter_init *ip; 142035863739SMike Smith time_t then; 1421b88ffdc8SScott Long u_int32_t code, qoffset; 1422a6d35632SScott Long int error; 142335863739SMike Smith 142435863739SMike Smith debug_called(1); 142535863739SMike Smith 142635863739SMike Smith /* 142735863739SMike Smith * First wait for the adapter to come ready. 142835863739SMike Smith */ 142935863739SMike Smith then = time_second; 143035863739SMike Smith do { 143135863739SMike Smith code = AAC_GET_FWSTATUS(sc); 143235863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 143335863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 143435863739SMike Smith return(ENXIO); 143535863739SMike Smith } 143635863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1437914da7d0SScott Long device_printf(sc->aac_dev, 1438914da7d0SScott Long "FATAL: controller kernel panic\n"); 143935863739SMike Smith return(ENXIO); 144035863739SMike Smith } 144135863739SMike Smith if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1442914da7d0SScott Long device_printf(sc->aac_dev, 1443914da7d0SScott Long "FATAL: controller not coming ready, " 1444c6eafcf2SScott Long "status %x\n", code); 144535863739SMike Smith return(ENXIO); 144635863739SMike Smith } 144735863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 144835863739SMike Smith 1449a6d35632SScott Long error = ENOMEM; 1450a6d35632SScott Long /* 1451a6d35632SScott Long * Create DMA tag for mapping buffers into controller-addressable space. 1452a6d35632SScott Long */ 1453a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1454a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1455a6d35632SScott Long (sc->flags & AAC_FLAGS_SG_64BIT) ? 1456a6d35632SScott Long BUS_SPACE_MAXADDR : 1457a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1458a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1459a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1460a6d35632SScott Long MAXBSIZE, /* maxsize */ 1461a6d35632SScott Long AAC_MAXSGENTRIES, /* nsegments */ 1462a6d35632SScott Long MAXBSIZE, /* maxsegsize */ 1463a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1464f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 1465f6b1c44dSScott Long &sc->aac_io_lock, /* lockfuncarg */ 1466a6d35632SScott Long &sc->aac_buffer_dmat)) { 1467a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1468a6d35632SScott Long goto out; 1469a6d35632SScott Long } 1470a6d35632SScott Long 1471a6d35632SScott Long /* 1472a6d35632SScott Long * Create DMA tag for mapping FIBs into controller-addressable space.. 1473a6d35632SScott Long */ 1474a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1475a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1476a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1477a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1478a6d35632SScott Long 0x7fffffff, /* lowaddr */ 1479a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1480a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1481a6d35632SScott Long AAC_FIB_COUNT * 1482a6d35632SScott Long sizeof(struct aac_fib), /* maxsize */ 1483a6d35632SScott Long 1, /* nsegments */ 1484a6d35632SScott Long AAC_FIB_COUNT * 1485a6d35632SScott Long sizeof(struct aac_fib), /* maxsegsize */ 14861248408dSScott Long 0, /* flags */ 1487f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 1488a6d35632SScott Long &sc->aac_fib_dmat)) { 1489a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1490a6d35632SScott Long goto out; 1491a6d35632SScott Long } 1492a6d35632SScott Long 149335863739SMike Smith /* 149435863739SMike Smith * Create DMA tag for the common structure and allocate it. 149535863739SMike Smith */ 149635863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1497c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1498a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1499a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1500a6d35632SScott Long 0x7fffffff, /* lowaddr */ 150135863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 150235863739SMike Smith NULL, NULL, /* filter, filterarg */ 1503ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1504914da7d0SScott Long 1, /* nsegments */ 150535863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 15061248408dSScott Long 0, /* flags */ 1507f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 150835863739SMike Smith &sc->aac_common_dmat)) { 1509914da7d0SScott Long device_printf(sc->aac_dev, 1510914da7d0SScott Long "can't allocate common structure DMA tag\n"); 1511a6d35632SScott Long goto out; 151235863739SMike Smith } 1513c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1514c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 151535863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 1516a6d35632SScott Long goto out; 151735863739SMike Smith } 1518ffb37f33SScott Long 1519ffb37f33SScott Long /* 1520ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1521ffb37f33SScott Long * below address 8192 in physical memory. 1522ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1523ffb37f33SScott Long * of ignored? 1524ffb37f33SScott Long */ 1525cd481291SScott Long (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1526ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1527ffb37f33SScott Long aac_common_map, sc, 0); 1528ffb37f33SScott Long 1529ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1530eec256deSAlexander Kabaev sc->aac_common = (struct aac_common *) 1531eec256deSAlexander Kabaev ((uint8_t *)sc->aac_common + 8192); 1532ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1533ffb37f33SScott Long } 153435863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 153535863739SMike Smith 1536ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1537ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 1538ffb37f33SScott Long sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 15398480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 15408480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1541ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1542ffb37f33SScott Long break; 1543ffb37f33SScott Long } 1544ffb37f33SScott Long if (sc->total_fibs == 0) 1545a6d35632SScott Long goto out; 1546ffb37f33SScott Long 154735863739SMike Smith /* 1548914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1549914da7d0SScott Long * physical location of various important shared data structures. 155035863739SMike Smith */ 155135863739SMike Smith ip = &sc->aac_common->ac_init; 155235863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1553f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 155435863739SMike Smith 1555c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1556c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1557149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 155835863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 155935863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 156035863739SMike Smith 1561c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1562c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 156335863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 156435863739SMike Smith 15654b00f859SScott Long /* 15664b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 15674b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 15684b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 15694b00f859SScott Long * Round up since the granularity is so high. 15704b00f859SScott Long */ 1571f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 15724b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 15734b00f859SScott Long ip->HostPhysMemPages = 15744b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1575204c0befSScott Long } 157635863739SMike Smith ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 157735863739SMike Smith 157835863739SMike Smith /* 1579c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1580c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1581c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 158235863739SMike Smith * 158335863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1584914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1585914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1586914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1587914da7d0SScott Long * does. 158835863739SMike Smith * 1589914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1590914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1591914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1592914da7d0SScott Long * virtue of a table. 159335863739SMike Smith */ 1594b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 15950bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 15960bcbebd6SScott Long sc->aac_queues = 15970bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1598b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 159935863739SMike Smith 1600c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1601c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1602c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1603c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1604c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1605c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1606c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1607c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1608c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1609c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1610c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1611c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1612c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1613c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1614c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1615c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1616c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1617c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1618c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1619c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1620c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1621c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1622c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1623c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1624c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1625c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1626c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1627c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1628c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1629c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1630c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1631c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1632c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1633c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1634c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1635c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1636c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1637c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1638c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1639c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1640c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1641c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1642c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1643c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1644c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1645c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1646c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1647c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 164835863739SMike Smith 164935863739SMike Smith /* 165035863739SMike Smith * Do controller-type-specific initialisation 165135863739SMike Smith */ 165235863739SMike Smith switch (sc->aac_hwif) { 165335863739SMike Smith case AAC_HWIF_I960RX: 165435863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 165535863739SMike Smith break; 16564afedc31SScott Long case AAC_HWIF_RKT: 16574afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); 16584afedc31SScott Long break; 16594afedc31SScott Long default: 16604afedc31SScott Long break; 166135863739SMike Smith } 166235863739SMike Smith 166335863739SMike Smith /* 166435863739SMike Smith * Give the init structure to the controller. 166535863739SMike Smith */ 166635863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1667914da7d0SScott Long sc->aac_common_busaddr + 1668914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1669914da7d0SScott Long NULL)) { 1670914da7d0SScott Long device_printf(sc->aac_dev, 1671914da7d0SScott Long "error establishing init structure\n"); 1672a6d35632SScott Long error = EIO; 1673a6d35632SScott Long goto out; 167435863739SMike Smith } 167535863739SMike Smith 1676a6d35632SScott Long error = 0; 1677a6d35632SScott Long out: 1678a6d35632SScott Long return(error); 167935863739SMike Smith } 168035863739SMike Smith 1681914da7d0SScott Long /* 168235863739SMike Smith * Send a synchronous command to the controller and wait for a result. 168335863739SMike Smith */ 168435863739SMike Smith static int 168535863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 168635863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 168735863739SMike Smith u_int32_t *sp) 168835863739SMike Smith { 168935863739SMike Smith time_t then; 169035863739SMike Smith u_int32_t status; 169135863739SMike Smith 169235863739SMike Smith debug_called(3); 169335863739SMike Smith 169435863739SMike Smith /* populate the mailbox */ 169535863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 169635863739SMike Smith 169735863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 169835863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 169935863739SMike Smith 170035863739SMike Smith /* then set it to signal the adapter */ 170135863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 170235863739SMike Smith 170335863739SMike Smith /* spin waiting for the command to complete */ 170435863739SMike Smith then = time_second; 170535863739SMike Smith do { 170635863739SMike Smith if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 1707a6d35632SScott Long debug(1, "timed out"); 170835863739SMike Smith return(EIO); 170935863739SMike Smith } 171035863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 171135863739SMike Smith 171235863739SMike Smith /* clear the completion flag */ 171335863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 171435863739SMike Smith 171535863739SMike Smith /* get the command status */ 1716a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 171735863739SMike Smith if (sp != NULL) 171835863739SMike Smith *sp = status; 17190b94a66eSMike Smith return(0); 172035863739SMike Smith } 172135863739SMike Smith 1722cbfd045bSScott Long int 172335863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1724cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 172535863739SMike Smith { 172635863739SMike Smith debug_called(3); 172735863739SMike Smith 172835863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 172935863739SMike Smith return(EINVAL); 173035863739SMike Smith 173135863739SMike Smith /* 173235863739SMike Smith * Set up the sync FIB 173335863739SMike Smith */ 1734914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1735914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 1736c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 173735863739SMike Smith fib->Header.XferState |= xferstate; 173835863739SMike Smith fib->Header.Command = command; 173935863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 174035863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 174135863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 1742b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 1743c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1744914da7d0SScott Long offsetof(struct aac_common, 1745914da7d0SScott Long ac_sync_fib); 174635863739SMike Smith 174735863739SMike Smith /* 174835863739SMike Smith * Give the FIB to the controller, wait for a response. 174935863739SMike Smith */ 1750914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1751914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 175235863739SMike Smith debug(2, "IO error"); 175335863739SMike Smith return(EIO); 175435863739SMike Smith } 175535863739SMike Smith 175635863739SMike Smith return (0); 175735863739SMike Smith } 175835863739SMike Smith 1759914da7d0SScott Long /* 176035863739SMike Smith * Adapter-space FIB queue manipulation 176135863739SMike Smith * 176235863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 176335863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 176435863739SMike Smith */ 176535863739SMike Smith static struct { 176635863739SMike Smith int size; 176735863739SMike Smith int notify; 176835863739SMike Smith } aac_qinfo[] = { 176935863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 177035863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 177135863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 177235863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 177335863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 177435863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 177535863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 177635863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 177735863739SMike Smith }; 177835863739SMike Smith 177935863739SMike Smith /* 1780c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 1781c6eafcf2SScott Long * EBUSY if the queue is full. 178235863739SMike Smith * 17830b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 1784914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 1785914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 1786c6eafcf2SScott Long * separate queue/notify interface). 178735863739SMike Smith */ 178835863739SMike Smith static int 1789f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 179035863739SMike Smith { 179135863739SMike Smith u_int32_t pi, ci; 17929e2e96d8SScott Long int error; 1793f6c4dd3fSScott Long u_int32_t fib_size; 1794f6c4dd3fSScott Long u_int32_t fib_addr; 1795f6c4dd3fSScott Long 179636e0bf6eSScott Long debug_called(3); 179736e0bf6eSScott Long 1798f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 1799f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 180035863739SMike Smith 180135863739SMike Smith /* get the producer/consumer indices */ 180235863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 180335863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 180435863739SMike Smith 180535863739SMike Smith /* wrap the queue? */ 180635863739SMike Smith if (pi >= aac_qinfo[queue].size) 180735863739SMike Smith pi = 0; 180835863739SMike Smith 180935863739SMike Smith /* check for queue full */ 181035863739SMike Smith if ((pi + 1) == ci) { 181135863739SMike Smith error = EBUSY; 181235863739SMike Smith goto out; 181335863739SMike Smith } 181435863739SMike Smith 1815614c22b2SScott Long /* 1816614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 1817614c22b2SScott Long * the busy queue prior to advertising it to the controller. 1818614c22b2SScott Long */ 1819614c22b2SScott Long aac_enqueue_busy(cm); 1820614c22b2SScott Long 182135863739SMike Smith /* populate queue entry */ 182235863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 182335863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 182435863739SMike Smith 182535863739SMike Smith /* update producer index */ 182635863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 182735863739SMike Smith 182835863739SMike Smith /* notify the adapter if we know how */ 182935863739SMike Smith if (aac_qinfo[queue].notify != 0) 183035863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 183135863739SMike Smith 183235863739SMike Smith error = 0; 183335863739SMike Smith 183435863739SMike Smith out: 183535863739SMike Smith return(error); 183635863739SMike Smith } 183735863739SMike Smith 183835863739SMike Smith /* 183936e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 184036e0bf6eSScott Long * success or ENOENT if the queue is empty. 184135863739SMike Smith */ 184235863739SMike Smith static int 1843c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1844c6eafcf2SScott Long struct aac_fib **fib_addr) 184535863739SMike Smith { 184635863739SMike Smith u_int32_t pi, ci; 1847149af931SScott Long u_int32_t fib_index; 18489e2e96d8SScott Long int error; 1849f6c4dd3fSScott Long int notify; 185035863739SMike Smith 185135863739SMike Smith debug_called(3); 185235863739SMike Smith 185335863739SMike Smith /* get the producer/consumer indices */ 185435863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 185535863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 185635863739SMike Smith 185735863739SMike Smith /* check for queue empty */ 185835863739SMike Smith if (ci == pi) { 185935863739SMike Smith error = ENOENT; 186035863739SMike Smith goto out; 186135863739SMike Smith } 186235863739SMike Smith 18637753acd2SScott Long /* wrap the pi so the following test works */ 18647753acd2SScott Long if (pi >= aac_qinfo[queue].size) 18657753acd2SScott Long pi = 0; 18667753acd2SScott Long 1867f6c4dd3fSScott Long notify = 0; 1868f6c4dd3fSScott Long if (ci == pi + 1) 1869f6c4dd3fSScott Long notify++; 1870f6c4dd3fSScott Long 187135863739SMike Smith /* wrap the queue? */ 187235863739SMike Smith if (ci >= aac_qinfo[queue].size) 187335863739SMike Smith ci = 0; 187435863739SMike Smith 187535863739SMike Smith /* fetch the entry */ 187635863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1877149af931SScott Long 1878149af931SScott Long switch (queue) { 1879149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 1880149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 1881149af931SScott Long /* 1882149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 1883149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 1884149af931SScott Long * that it's giving us an address into the array of AIF fibs. 1885149af931SScott Long * Therefore, we have to convert it to an index. 1886149af931SScott Long */ 1887149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 1888149af931SScott Long sizeof(struct aac_fib); 1889149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 1890149af931SScott Long break; 1891149af931SScott Long 1892149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 1893149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 1894149af931SScott Long { 1895149af931SScott Long struct aac_command *cm; 1896149af931SScott Long 1897149af931SScott Long /* 1898149af931SScott Long * As above, an index is used instead of an actual address. 1899149af931SScott Long * Gotta shift the index to account for the fast response 1900149af931SScott Long * bit. No other correction is needed since this value was 1901149af931SScott Long * originally provided by the driver via the SenderFibAddress 1902149af931SScott Long * field. 1903149af931SScott Long */ 1904149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 1905149af931SScott Long cm = sc->aac_commands + (fib_index >> 1); 1906149af931SScott Long *fib_addr = cm->cm_fib; 190735863739SMike Smith 1908f30ac74cSScott Long /* 1909f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 1910149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 1911f30ac74cSScott Long */ 1912149af931SScott Long if (fib_index & 0x01) { 1913f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1914f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1915f30ac74cSScott Long } 1916149af931SScott Long break; 1917149af931SScott Long } 1918149af931SScott Long default: 1919149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 1920149af931SScott Long break; 1921149af931SScott Long } 1922149af931SScott Long 192335863739SMike Smith /* update consumer index */ 192435863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 192535863739SMike Smith 192635863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 1927f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 192835863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 192935863739SMike Smith error = 0; 193035863739SMike Smith 193135863739SMike Smith out: 193235863739SMike Smith return(error); 193335863739SMike Smith } 193435863739SMike Smith 1935914da7d0SScott Long /* 193636e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 193736e0bf6eSScott Long */ 193836e0bf6eSScott Long static int 193936e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 194036e0bf6eSScott Long { 194136e0bf6eSScott Long u_int32_t pi, ci; 19429e2e96d8SScott Long int error; 194336e0bf6eSScott Long u_int32_t fib_size; 194436e0bf6eSScott Long u_int32_t fib_addr; 194536e0bf6eSScott Long 194636e0bf6eSScott Long debug_called(1); 194736e0bf6eSScott Long 194836e0bf6eSScott Long /* Tell the adapter where the FIB is */ 194936e0bf6eSScott Long fib_size = fib->Header.Size; 195036e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 195136e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 195236e0bf6eSScott Long 195336e0bf6eSScott Long /* get the producer/consumer indices */ 195436e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 195536e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 195636e0bf6eSScott Long 195736e0bf6eSScott Long /* wrap the queue? */ 195836e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 195936e0bf6eSScott Long pi = 0; 196036e0bf6eSScott Long 196136e0bf6eSScott Long /* check for queue full */ 196236e0bf6eSScott Long if ((pi + 1) == ci) { 196336e0bf6eSScott Long error = EBUSY; 196436e0bf6eSScott Long goto out; 196536e0bf6eSScott Long } 196636e0bf6eSScott Long 196736e0bf6eSScott Long /* populate queue entry */ 196836e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 196936e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 197036e0bf6eSScott Long 197136e0bf6eSScott Long /* update producer index */ 197236e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 197336e0bf6eSScott Long 197436e0bf6eSScott Long /* notify the adapter if we know how */ 197536e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 197636e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 197736e0bf6eSScott Long 197836e0bf6eSScott Long error = 0; 197936e0bf6eSScott Long 198036e0bf6eSScott Long out: 198136e0bf6eSScott Long return(error); 198236e0bf6eSScott Long } 198336e0bf6eSScott Long 1984914da7d0SScott Long /* 19850b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 19860b94a66eSMike Smith * and complain about them. 19870b94a66eSMike Smith */ 19880b94a66eSMike Smith static void 19890b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 19900b94a66eSMike Smith { 19910b94a66eSMike Smith struct aac_command *cm; 19920b94a66eSMike Smith time_t deadline; 199315c37be0SScott Long int timedout, code; 19940b94a66eSMike Smith 1995f6c4dd3fSScott Long /* 199670545d1aSScott Long * Traverse the busy command list, bitch about late commands once 1997914da7d0SScott Long * only. 1998914da7d0SScott Long */ 199915c37be0SScott Long timedout = 0; 20000b94a66eSMike Smith deadline = time_second - AAC_CMD_TIMEOUT; 20010b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2002f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2003f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 20040b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2005914da7d0SScott Long device_printf(sc->aac_dev, 2006914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2007f6c4dd3fSScott Long cm, (int)(time_second-cm->cm_timestamp)); 20080b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 200915c37be0SScott Long timedout++; 20100b94a66eSMike Smith } 20110b94a66eSMike Smith } 20120b94a66eSMike Smith 201315c37be0SScott Long if (timedout) { 201415c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 201515c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 201615c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 201715c37be0SScott Long "longer running! code= 0x%x\n", code); 201815c37be0SScott Long } 201915c37be0SScott Long } 20200b94a66eSMike Smith return; 20210b94a66eSMike Smith } 20220b94a66eSMike Smith 2023914da7d0SScott Long /* 2024914da7d0SScott Long * Interface Function Vectors 2025914da7d0SScott Long */ 202635863739SMike Smith 2027914da7d0SScott Long /* 202835863739SMike Smith * Read the current firmware status word. 202935863739SMike Smith */ 203035863739SMike Smith static int 203135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 203235863739SMike Smith { 203335863739SMike Smith debug_called(3); 203435863739SMike Smith 203535863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 203635863739SMike Smith } 203735863739SMike Smith 203835863739SMike Smith static int 203935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 204035863739SMike Smith { 204135863739SMike Smith debug_called(3); 204235863739SMike Smith 204335863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 204435863739SMike Smith } 204535863739SMike Smith 2046b3457b51SScott Long static int 2047b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2048b3457b51SScott Long { 2049b3457b51SScott Long int val; 2050b3457b51SScott Long 2051b3457b51SScott Long debug_called(3); 2052b3457b51SScott Long 2053b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2054b3457b51SScott Long return (val); 2055b3457b51SScott Long } 2056b3457b51SScott Long 20574afedc31SScott Long static int 20584afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 20594afedc31SScott Long { 20604afedc31SScott Long debug_called(3); 20614afedc31SScott Long 20624afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); 20634afedc31SScott Long } 20644afedc31SScott Long 2065914da7d0SScott Long /* 206635863739SMike Smith * Notify the controller of a change in a given queue 206735863739SMike Smith */ 206835863739SMike Smith 206935863739SMike Smith static void 207035863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 207135863739SMike Smith { 207235863739SMike Smith debug_called(3); 207335863739SMike Smith 207435863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 207535863739SMike Smith } 207635863739SMike Smith 207735863739SMike Smith static void 207835863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 207935863739SMike Smith { 208035863739SMike Smith debug_called(3); 208135863739SMike Smith 208235863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 208335863739SMike Smith } 208435863739SMike Smith 2085b3457b51SScott Long static void 2086b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2087b3457b51SScott Long { 2088b3457b51SScott Long debug_called(3); 2089b3457b51SScott Long 2090b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2091b3457b51SScott Long AAC_FA_HACK(sc); 2092b3457b51SScott Long } 2093b3457b51SScott Long 20944afedc31SScott Long static void 20954afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 20964afedc31SScott Long { 20974afedc31SScott Long debug_called(3); 20984afedc31SScott Long 20994afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); 21004afedc31SScott Long } 21014afedc31SScott Long 2102914da7d0SScott Long /* 210335863739SMike Smith * Get the interrupt reason bits 210435863739SMike Smith */ 210535863739SMike Smith static int 210635863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 210735863739SMike Smith { 210835863739SMike Smith debug_called(3); 210935863739SMike Smith 211035863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 211135863739SMike Smith } 211235863739SMike Smith 211335863739SMike Smith static int 211435863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 211535863739SMike Smith { 211635863739SMike Smith debug_called(3); 211735863739SMike Smith 211835863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 211935863739SMike Smith } 212035863739SMike Smith 2121b3457b51SScott Long static int 2122b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2123b3457b51SScott Long { 2124b3457b51SScott Long int val; 2125b3457b51SScott Long 2126b3457b51SScott Long debug_called(3); 2127b3457b51SScott Long 2128b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2129b3457b51SScott Long return (val); 2130b3457b51SScott Long } 2131b3457b51SScott Long 21324afedc31SScott Long static int 21334afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 21344afedc31SScott Long { 21354afedc31SScott Long debug_called(3); 21364afedc31SScott Long 21374afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_ODBR)); 21384afedc31SScott Long } 21394afedc31SScott Long 2140914da7d0SScott Long /* 214135863739SMike Smith * Clear some interrupt reason bits 214235863739SMike Smith */ 214335863739SMike Smith static void 214435863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 214535863739SMike Smith { 214635863739SMike Smith debug_called(3); 214735863739SMike Smith 214835863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 214935863739SMike Smith } 215035863739SMike Smith 215135863739SMike Smith static void 215235863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 215335863739SMike Smith { 215435863739SMike Smith debug_called(3); 215535863739SMike Smith 215635863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 215735863739SMike Smith } 215835863739SMike Smith 2159b3457b51SScott Long static void 2160b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2161b3457b51SScott Long { 2162b3457b51SScott Long debug_called(3); 2163b3457b51SScott Long 2164b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2165b3457b51SScott Long AAC_FA_HACK(sc); 2166b3457b51SScott Long } 2167b3457b51SScott Long 21684afedc31SScott Long static void 21694afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 21704afedc31SScott Long { 21714afedc31SScott Long debug_called(3); 21724afedc31SScott Long 21734afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, mask); 21744afedc31SScott Long } 21754afedc31SScott Long 2176914da7d0SScott Long /* 217735863739SMike Smith * Populate the mailbox and set the command word 217835863739SMike Smith */ 217935863739SMike Smith static void 218035863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 218135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 218235863739SMike Smith { 218335863739SMike Smith debug_called(4); 218435863739SMike Smith 218535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 218635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 218735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 218835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 218935863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 219035863739SMike Smith } 219135863739SMike Smith 219235863739SMike Smith static void 219335863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 219435863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 219535863739SMike Smith { 219635863739SMike Smith debug_called(4); 219735863739SMike Smith 219835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 219935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 220035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 220135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 220235863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 220335863739SMike Smith } 220435863739SMike Smith 2205b3457b51SScott Long static void 2206b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2207b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2208b3457b51SScott Long { 2209b3457b51SScott Long debug_called(4); 2210b3457b51SScott Long 2211b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2212b3457b51SScott Long AAC_FA_HACK(sc); 2213b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2214b3457b51SScott Long AAC_FA_HACK(sc); 2215b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2216b3457b51SScott Long AAC_FA_HACK(sc); 2217b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2218b3457b51SScott Long AAC_FA_HACK(sc); 2219b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2220b3457b51SScott Long AAC_FA_HACK(sc); 2221b3457b51SScott Long } 2222b3457b51SScott Long 22234afedc31SScott Long static void 22244afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 22254afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 22264afedc31SScott Long { 22274afedc31SScott Long debug_called(4); 22284afedc31SScott Long 22294afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); 22304afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 22314afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 22324afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 22334afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 22344afedc31SScott Long } 22354afedc31SScott Long 2236914da7d0SScott Long /* 223735863739SMike Smith * Fetch the immediate command status word 223835863739SMike Smith */ 223935863739SMike Smith static int 2240a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 224135863739SMike Smith { 224235863739SMike Smith debug_called(4); 224335863739SMike Smith 2244a6d35632SScott Long return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 224535863739SMike Smith } 224635863739SMike Smith 224735863739SMike Smith static int 2248a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 224935863739SMike Smith { 225035863739SMike Smith debug_called(4); 225135863739SMike Smith 2252a6d35632SScott Long return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 225335863739SMike Smith } 225435863739SMike Smith 2255b3457b51SScott Long static int 2256a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2257b3457b51SScott Long { 2258b3457b51SScott Long int val; 2259b3457b51SScott Long 2260b3457b51SScott Long debug_called(4); 2261b3457b51SScott Long 2262a6d35632SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2263b3457b51SScott Long return (val); 2264b3457b51SScott Long } 2265b3457b51SScott Long 22664afedc31SScott Long static int 22674afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 22684afedc31SScott Long { 22694afedc31SScott Long debug_called(4); 22704afedc31SScott Long 22714afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 22724afedc31SScott Long } 22734afedc31SScott Long 2274914da7d0SScott Long /* 227535863739SMike Smith * Set/clear interrupt masks 227635863739SMike Smith */ 227735863739SMike Smith static void 227835863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 227935863739SMike Smith { 228035863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 228135863739SMike Smith 228235863739SMike Smith if (enable) { 228335863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 228435863739SMike Smith } else { 228535863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 228635863739SMike Smith } 228735863739SMike Smith } 228835863739SMike Smith 228935863739SMike Smith static void 229035863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 229135863739SMike Smith { 229235863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 229335863739SMike Smith 229435863739SMike Smith if (enable) { 229535863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 229635863739SMike Smith } else { 229735863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 229835863739SMike Smith } 229935863739SMike Smith } 230035863739SMike Smith 2301b3457b51SScott Long static void 2302b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2303b3457b51SScott Long { 2304b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2305b3457b51SScott Long 2306b3457b51SScott Long if (enable) { 2307b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2308b3457b51SScott Long AAC_FA_HACK(sc); 2309b3457b51SScott Long } else { 2310b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2311b3457b51SScott Long AAC_FA_HACK(sc); 2312b3457b51SScott Long } 2313b3457b51SScott Long } 2314b3457b51SScott Long 23154afedc31SScott Long static void 23164afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 23174afedc31SScott Long { 23184afedc31SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 23194afedc31SScott Long 23204afedc31SScott Long if (enable) { 23214afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 23224afedc31SScott Long } else { 23234afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); 23244afedc31SScott Long } 23254afedc31SScott Long } 23264afedc31SScott Long 2327914da7d0SScott Long /* 2328914da7d0SScott Long * Debugging and Diagnostics 2329914da7d0SScott Long */ 233035863739SMike Smith 2331914da7d0SScott Long /* 233235863739SMike Smith * Print some information about the controller. 233335863739SMike Smith */ 233435863739SMike Smith static void 233535863739SMike Smith aac_describe_controller(struct aac_softc *sc) 233635863739SMike Smith { 2337cbfd045bSScott Long struct aac_fib *fib; 233835863739SMike Smith struct aac_adapter_info *info; 233935863739SMike Smith 234035863739SMike Smith debug_called(2); 234135863739SMike Smith 234203b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2343cbfd045bSScott Long 2344cbfd045bSScott Long fib->data[0] = 0; 2345cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 234635863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2347fe3cb0e1SScott Long aac_release_sync_fib(sc); 234835863739SMike Smith return; 234935863739SMike Smith } 235035863739SMike Smith 2351bd971c49SScott Long /* save the kernel revision structure for later use */ 2352bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2353bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2354bd971c49SScott Long 2355bd971c49SScott Long if (bootverbose) { 2356b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2357b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2358c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2359b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2360b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2361b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2362914da7d0SScott Long aac_describe_code(aac_battery_platform, 2363914da7d0SScott Long info->batteryPlatform)); 236435863739SMike Smith 2365bd971c49SScott Long device_printf(sc->aac_dev, 2366bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 236735863739SMike Smith info->KernelRevision.external.comp.major, 236835863739SMike Smith info->KernelRevision.external.comp.minor, 236935863739SMike Smith info->KernelRevision.external.comp.dash, 237036e0bf6eSScott Long info->KernelRevision.buildNumber, 237136e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2372fe3cb0e1SScott Long 2373a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2374a6d35632SScott Long sc->supported_options, 2375a6d35632SScott Long "\20" 2376a6d35632SScott Long "\1SNAPSHOT" 2377a6d35632SScott Long "\2CLUSTERS" 2378a6d35632SScott Long "\3WCACHE" 2379a6d35632SScott Long "\4DATA64" 2380a6d35632SScott Long "\5HOSTTIME" 2381a6d35632SScott Long "\6RAID50" 2382a6d35632SScott Long "\7WINDOW4GB" 2383a6d35632SScott Long "\10SCSIUPGD" 2384a6d35632SScott Long "\11SOFTERR" 2385a6d35632SScott Long "\12NORECOND" 2386a6d35632SScott Long "\13SGMAP64" 2387a6d35632SScott Long "\14ALARM" 2388a6d35632SScott Long "\15NONDASD"); 2389a6d35632SScott Long } 2390bd971c49SScott Long aac_release_sync_fib(sc); 239135863739SMike Smith } 239235863739SMike Smith 2393914da7d0SScott Long /* 239435863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 239535863739SMike Smith * same. 239635863739SMike Smith */ 239735863739SMike Smith static char * 239835863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 239935863739SMike Smith { 240035863739SMike Smith int i; 240135863739SMike Smith 240235863739SMike Smith for (i = 0; table[i].string != NULL; i++) 240335863739SMike Smith if (table[i].code == code) 240435863739SMike Smith return(table[i].string); 240535863739SMike Smith return(table[i + 1].string); 240635863739SMike Smith } 240735863739SMike Smith 2408914da7d0SScott Long /* 2409914da7d0SScott Long * Management Interface 2410914da7d0SScott Long */ 241135863739SMike Smith 241235863739SMike Smith static int 241389c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 241435863739SMike Smith { 2415914da7d0SScott Long struct aac_softc *sc; 241635863739SMike Smith 241735863739SMike Smith debug_called(2); 241835863739SMike Smith 2419914da7d0SScott Long sc = dev->si_drv1; 2420914da7d0SScott Long 242135863739SMike Smith /* Check to make sure the device isn't already open */ 242235863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 242335863739SMike Smith return EBUSY; 242435863739SMike Smith } 242535863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 242635863739SMike Smith 242735863739SMike Smith return 0; 242835863739SMike Smith } 242935863739SMike Smith 243035863739SMike Smith static int 243189c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 243235863739SMike Smith { 2433914da7d0SScott Long struct aac_softc *sc; 243435863739SMike Smith 243535863739SMike Smith debug_called(2); 243635863739SMike Smith 2437914da7d0SScott Long sc = dev->si_drv1; 2438914da7d0SScott Long 243935863739SMike Smith /* Mark this unit as no longer open */ 244035863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 244135863739SMike Smith 244235863739SMike Smith return 0; 244335863739SMike Smith } 244435863739SMike Smith 244535863739SMike Smith static int 244689c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 244735863739SMike Smith { 2448914da7d0SScott Long union aac_statrequest *as; 2449914da7d0SScott Long struct aac_softc *sc; 24500b94a66eSMike Smith int error = 0; 2451b88ffdc8SScott Long uint32_t cookie; 245235863739SMike Smith 245335863739SMike Smith debug_called(2); 245435863739SMike Smith 2455914da7d0SScott Long as = (union aac_statrequest *)arg; 2456914da7d0SScott Long sc = dev->si_drv1; 2457914da7d0SScott Long 245835863739SMike Smith switch (cmd) { 24590b94a66eSMike Smith case AACIO_STATS: 24600b94a66eSMike Smith switch (as->as_item) { 24610b94a66eSMike Smith case AACQ_FREE: 24620b94a66eSMike Smith case AACQ_BIO: 24630b94a66eSMike Smith case AACQ_READY: 24640b94a66eSMike Smith case AACQ_BUSY: 2465c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2466c6eafcf2SScott Long sizeof(struct aac_qstat)); 24670b94a66eSMike Smith break; 24680b94a66eSMike Smith default: 24690b94a66eSMike Smith error = ENOENT; 24700b94a66eSMike Smith break; 24710b94a66eSMike Smith } 24720b94a66eSMike Smith break; 24730b94a66eSMike Smith 247435863739SMike Smith case FSACTL_SENDFIB: 2475fb0c27d7SScott Long arg = *(caddr_t*)arg; 2476fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 24770b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 247835863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 247935863739SMike Smith break; 248035863739SMike Smith case FSACTL_AIF_THREAD: 2481fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 24820b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 248335863739SMike Smith error = EINVAL; 248435863739SMike Smith break; 248535863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2486fb0c27d7SScott Long arg = *(caddr_t*)arg; 2487fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 24880b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 248935863739SMike Smith /* 249035863739SMike Smith * Pass the caller out an AdapterFibContext. 249135863739SMike Smith * 249235863739SMike Smith * Note that because we only support one opener, we 249335863739SMike Smith * basically ignore this. Set the caller's context to a magic 249435863739SMike Smith * number just in case. 24950b94a66eSMike Smith * 24960b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 24970b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2498914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2499914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 250035863739SMike Smith */ 2501b88ffdc8SScott Long cookie = (uint32_t)(uintptr_t)sc->aifthread; 2502b88ffdc8SScott Long error = copyout(&cookie, arg, sizeof(cookie)); 250335863739SMike Smith break; 250435863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2505fb0c27d7SScott Long arg = *(caddr_t*)arg; 2506fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 25070b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2508fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 250935863739SMike Smith break; 251035863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2511fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 25120b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 251335863739SMike Smith /* don't do anything here */ 251435863739SMike Smith break; 251535863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2516fb0c27d7SScott Long arg = *(caddr_t*)arg; 2517fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 25180b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2519fb0c27d7SScott Long error = aac_rev_check(sc, arg); 252035863739SMike Smith break; 252136e0bf6eSScott Long case FSACTL_QUERY_DISK: 252236e0bf6eSScott Long arg = *(caddr_t*)arg; 252336e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 252436e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 252536e0bf6eSScott Long error = aac_query_disk(sc, arg); 252636e0bf6eSScott Long break; 252736e0bf6eSScott Long case FSACTL_DELETE_DISK: 252836e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2529914da7d0SScott Long /* 2530914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2531914da7d0SScott Long * container, rather we rely on an AIF coming from the 2532914da7d0SScott Long * controller 2533914da7d0SScott Long */ 253436e0bf6eSScott Long error = 0; 253536e0bf6eSScott Long break; 253635863739SMike Smith default: 2537b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 253835863739SMike Smith error = EINVAL; 253935863739SMike Smith break; 254035863739SMike Smith } 254135863739SMike Smith return(error); 254235863739SMike Smith } 254335863739SMike Smith 2544b3457b51SScott Long static int 254589c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 2546b3457b51SScott Long { 2547b3457b51SScott Long struct aac_softc *sc; 2548b3457b51SScott Long int revents; 2549b3457b51SScott Long 2550b3457b51SScott Long sc = dev->si_drv1; 2551b3457b51SScott Long revents = 0; 2552b3457b51SScott Long 2553bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2554b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2555b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2556b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2557b3457b51SScott Long } 2558bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2559b3457b51SScott Long 2560b3457b51SScott Long if (revents == 0) { 2561b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2562b3457b51SScott Long selrecord(td, &sc->rcv_select); 2563b3457b51SScott Long } 2564b3457b51SScott Long 2565b3457b51SScott Long return (revents); 2566b3457b51SScott Long } 2567b3457b51SScott Long 2568914da7d0SScott Long /* 256935863739SMike Smith * Send a FIB supplied from userspace 257035863739SMike Smith */ 257135863739SMike Smith static int 257235863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 257335863739SMike Smith { 257435863739SMike Smith struct aac_command *cm; 257535863739SMike Smith int size, error; 257635863739SMike Smith 257735863739SMike Smith debug_called(2); 257835863739SMike Smith 257935863739SMike Smith cm = NULL; 258035863739SMike Smith 258135863739SMike Smith /* 258235863739SMike Smith * Get a command 258335863739SMike Smith */ 2584bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 258535863739SMike Smith if (aac_alloc_command(sc, &cm)) { 258635863739SMike Smith error = EBUSY; 258735863739SMike Smith goto out; 258835863739SMike Smith } 258935863739SMike Smith 259035863739SMike Smith /* 259135863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 259235863739SMike Smith */ 2593914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2594914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 259535863739SMike Smith goto out; 259635863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 259735863739SMike Smith if (size > sizeof(struct aac_fib)) { 2598b88ffdc8SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 2599914da7d0SScott Long size, sizeof(struct aac_fib)); 260035863739SMike Smith size = sizeof(struct aac_fib); 260135863739SMike Smith } 260235863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 260335863739SMike Smith goto out; 260435863739SMike Smith cm->cm_fib->Header.Size = size; 2605f6c4dd3fSScott Long cm->cm_timestamp = time_second; 260635863739SMike Smith 260735863739SMike Smith /* 260835863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 260935863739SMike Smith */ 2610d8a0a473SScott Long if ((error = aac_wait_command(cm)) != 0) { 261170545d1aSScott Long device_printf(sc->aac_dev, 261270545d1aSScott Long "aac_wait_command return %d\n", error); 261335863739SMike Smith goto out; 2614b3457b51SScott Long } 261535863739SMike Smith 261635863739SMike Smith /* 261735863739SMike Smith * Copy the FIB and data back out to the caller. 261835863739SMike Smith */ 261935863739SMike Smith size = cm->cm_fib->Header.Size; 262035863739SMike Smith if (size > sizeof(struct aac_fib)) { 2621b88ffdc8SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 2622914da7d0SScott Long size, sizeof(struct aac_fib)); 262335863739SMike Smith size = sizeof(struct aac_fib); 262435863739SMike Smith } 262535863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 262635863739SMike Smith 262735863739SMike Smith out: 2628f6c4dd3fSScott Long if (cm != NULL) { 262935863739SMike Smith aac_release_command(cm); 2630f6c4dd3fSScott Long } 2631ae543596SScott Long 2632bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 263335863739SMike Smith return(error); 263435863739SMike Smith } 263535863739SMike Smith 2636914da7d0SScott Long /* 263735863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 263836e0bf6eSScott Long * If the queue fills up, then drop the older entries. 263935863739SMike Smith */ 264035863739SMike Smith static void 264136e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 264235863739SMike Smith { 264336e0bf6eSScott Long struct aac_aif_command *aif; 264436e0bf6eSScott Long struct aac_container *co, *co_next; 2645cbfd045bSScott Long struct aac_mntinfo *mi; 2646cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 264736e0bf6eSScott Long u_int16_t rsize; 2648b3457b51SScott Long int next, found; 2649795d7dc0SScott Long int count = 0, added = 0, i = 0; 265035863739SMike Smith 265135863739SMike Smith debug_called(2); 265235863739SMike Smith 265336e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 265436e0bf6eSScott Long aac_print_aif(sc, aif); 265536e0bf6eSScott Long 265636e0bf6eSScott Long /* Is it an event that we should care about? */ 265736e0bf6eSScott Long switch (aif->command) { 265836e0bf6eSScott Long case AifCmdEventNotify: 265936e0bf6eSScott Long switch (aif->data.EN.type) { 266036e0bf6eSScott Long case AifEnAddContainer: 266136e0bf6eSScott Long case AifEnDeleteContainer: 266236e0bf6eSScott Long /* 2663914da7d0SScott Long * A container was added or deleted, but the message 2664914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 2665914da7d0SScott Long * containers and sort things out. 266636e0bf6eSScott Long */ 266703b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2668cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 266936e0bf6eSScott Long do { 267036e0bf6eSScott Long /* 2671914da7d0SScott Long * Ask the controller for its containers one at 2672914da7d0SScott Long * a time. 2673914da7d0SScott Long * XXX What if the controller's list changes 2674914da7d0SScott Long * midway through this enumaration? 267536e0bf6eSScott Long * XXX This should be done async. 267636e0bf6eSScott Long */ 267739ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 267839ee03c3SScott Long mi->Command = VM_NameServe; 267939ee03c3SScott Long mi->MntType = FT_FILESYS; 2680cbfd045bSScott Long mi->MntCount = i; 268136e0bf6eSScott Long rsize = sizeof(mir); 2682cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2683cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 2684795d7dc0SScott Long printf("Error probing container %d\n", 2685914da7d0SScott Long i); 268636e0bf6eSScott Long continue; 268736e0bf6eSScott Long } 2688cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 2689795d7dc0SScott Long /* XXX Need to check if count changed */ 2690795d7dc0SScott Long count = mir->MntRespCount; 269136e0bf6eSScott Long /* 2692914da7d0SScott Long * Check the container against our list. 2693914da7d0SScott Long * co->co_found was already set to 0 in a 2694914da7d0SScott Long * previous run. 269536e0bf6eSScott Long */ 2696cbfd045bSScott Long if ((mir->Status == ST_OK) && 2697cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 269836e0bf6eSScott Long found = 0; 2699914da7d0SScott Long TAILQ_FOREACH(co, 2700914da7d0SScott Long &sc->aac_container_tqh, 2701914da7d0SScott Long co_link) { 270236e0bf6eSScott Long if (co->co_mntobj.ObjectId == 2703cbfd045bSScott Long mir->MntTable[0].ObjectId) { 270436e0bf6eSScott Long co->co_found = 1; 270536e0bf6eSScott Long found = 1; 270636e0bf6eSScott Long break; 270736e0bf6eSScott Long } 270836e0bf6eSScott Long } 2709914da7d0SScott Long /* 2710914da7d0SScott Long * If the container matched, continue 2711914da7d0SScott Long * in the list. 2712914da7d0SScott Long */ 271336e0bf6eSScott Long if (found) { 271436e0bf6eSScott Long i++; 271536e0bf6eSScott Long continue; 271636e0bf6eSScott Long } 271736e0bf6eSScott Long 271836e0bf6eSScott Long /* 2719914da7d0SScott Long * This is a new container. Do all the 272070545d1aSScott Long * appropriate things to set it up. 272170545d1aSScott Long */ 2722cbfd045bSScott Long aac_add_container(sc, mir, 1); 272336e0bf6eSScott Long added = 1; 272436e0bf6eSScott Long } 272536e0bf6eSScott Long i++; 2726795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 2727cbfd045bSScott Long aac_release_sync_fib(sc); 272836e0bf6eSScott Long 272936e0bf6eSScott Long /* 2730914da7d0SScott Long * Go through our list of containers and see which ones 2731914da7d0SScott Long * were not marked 'found'. Since the controller didn't 2732914da7d0SScott Long * list them they must have been deleted. Do the 2733914da7d0SScott Long * appropriate steps to destroy the device. Also reset 2734914da7d0SScott Long * the co->co_found field. 273536e0bf6eSScott Long */ 273636e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 273736e0bf6eSScott Long while (co != NULL) { 273836e0bf6eSScott Long if (co->co_found == 0) { 2739914da7d0SScott Long device_delete_child(sc->aac_dev, 2740914da7d0SScott Long co->co_disk); 274136e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 2742bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 2743914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 2744914da7d0SScott Long co_link); 2745bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 2746ba1d57e7SScott Long free(co, M_AACBUF); 274736e0bf6eSScott Long co = co_next; 274836e0bf6eSScott Long } else { 274936e0bf6eSScott Long co->co_found = 0; 275036e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 275136e0bf6eSScott Long } 275236e0bf6eSScott Long } 275336e0bf6eSScott Long 275436e0bf6eSScott Long /* Attach the newly created containers */ 275536e0bf6eSScott Long if (added) 275636e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 275736e0bf6eSScott Long 275836e0bf6eSScott Long break; 275936e0bf6eSScott Long 276036e0bf6eSScott Long default: 276136e0bf6eSScott Long break; 276236e0bf6eSScott Long } 276336e0bf6eSScott Long 276436e0bf6eSScott Long default: 276536e0bf6eSScott Long break; 276636e0bf6eSScott Long } 276736e0bf6eSScott Long 276836e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2769bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 277035863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 277135863739SMike Smith if (next != sc->aac_aifq_tail) { 277235863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 277335863739SMike Smith sc->aac_aifq_head = next; 2774b3457b51SScott Long 2775b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 277635863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 277735863739SMike Smith wakeup(sc->aac_aifq); 2778b3457b51SScott Long /* Wakeup any poll()ers */ 2779512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 278035863739SMike Smith } 2781bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 278236e0bf6eSScott Long 278336e0bf6eSScott Long return; 278435863739SMike Smith } 278535863739SMike Smith 2786914da7d0SScott Long /* 27870b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 278836e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 278936e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 279036e0bf6eSScott Long * returning what the card reported. 279135863739SMike Smith */ 279235863739SMike Smith static int 2793fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 279435863739SMike Smith { 279535863739SMike Smith struct aac_rev_check rev_check; 279635863739SMike Smith struct aac_rev_check_resp rev_check_resp; 279735863739SMike Smith int error = 0; 279835863739SMike Smith 279935863739SMike Smith debug_called(2); 280035863739SMike Smith 280135863739SMike Smith /* 280235863739SMike Smith * Copyin the revision struct from userspace 280335863739SMike Smith */ 2804c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 2805c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 280635863739SMike Smith return error; 280735863739SMike Smith } 280835863739SMike Smith 2809914da7d0SScott Long debug(2, "Userland revision= %d\n", 2810914da7d0SScott Long rev_check.callingRevision.buildNumber); 281135863739SMike Smith 281235863739SMike Smith /* 281335863739SMike Smith * Doctor up the response struct. 281435863739SMike Smith */ 281535863739SMike Smith rev_check_resp.possiblyCompatible = 1; 2816914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 2817914da7d0SScott Long sc->aac_revision.external.ul; 2818914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 2819914da7d0SScott Long sc->aac_revision.buildNumber; 282035863739SMike Smith 2821c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 2822c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 282335863739SMike Smith } 282435863739SMike Smith 2825914da7d0SScott Long /* 282635863739SMike Smith * Pass the caller the next AIF in their queue 282735863739SMike Smith */ 282835863739SMike Smith static int 2829fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 283035863739SMike Smith { 283135863739SMike Smith struct get_adapter_fib_ioctl agf; 28329e2e96d8SScott Long int error; 283335863739SMike Smith 283435863739SMike Smith debug_called(2); 283535863739SMike Smith 283635863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 283735863739SMike Smith 283835863739SMike Smith /* 283935863739SMike Smith * Check the magic number that we gave the caller. 284035863739SMike Smith */ 2841b88ffdc8SScott Long if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 284235863739SMike Smith error = EFAULT; 284335863739SMike Smith } else { 2844fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 284535863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 284635863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 284735863739SMike Smith while (error == EAGAIN) { 2848914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 2849914da7d0SScott Long PCATCH, "aacaif", 0); 285035863739SMike Smith if (error == 0) 2851914da7d0SScott Long error = aac_return_aif(sc, 2852914da7d0SScott Long agf.AifFib); 285335863739SMike Smith } 285435863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 285535863739SMike Smith } 285635863739SMike Smith } 285735863739SMike Smith } 285835863739SMike Smith return(error); 285935863739SMike Smith } 286035863739SMike Smith 2861914da7d0SScott Long /* 28620b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 28630b94a66eSMike Smith */ 28640b94a66eSMike Smith static int 2865fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 28660b94a66eSMike Smith { 28673df780cfSScott Long int next, error; 28680b94a66eSMike Smith 28690b94a66eSMike Smith debug_called(2); 28700b94a66eSMike Smith 2871bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 28720b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 2873bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 28743df780cfSScott Long return (EAGAIN); 28753df780cfSScott Long } 28763df780cfSScott Long 28773df780cfSScott Long next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 28783df780cfSScott Long error = copyout(&sc->aac_aifq[next], uptr, 2879c6eafcf2SScott Long sizeof(struct aac_aif_command)); 288036e0bf6eSScott Long if (error) 288170545d1aSScott Long device_printf(sc->aac_dev, 288270545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 28833df780cfSScott Long else 28843df780cfSScott Long sc->aac_aifq_tail = next; 28853df780cfSScott Long 2886bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 28870b94a66eSMike Smith return(error); 28880b94a66eSMike Smith } 288936e0bf6eSScott Long 2890914da7d0SScott Long /* 289136e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 289236e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 289336e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 289436e0bf6eSScott Long */ 289536e0bf6eSScott Long static int 289636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 289736e0bf6eSScott Long { 289836e0bf6eSScott Long struct aac_query_disk query_disk; 289936e0bf6eSScott Long struct aac_container *co; 2900914da7d0SScott Long struct aac_disk *disk; 290136e0bf6eSScott Long int error, id; 290236e0bf6eSScott Long 290336e0bf6eSScott Long debug_called(2); 290436e0bf6eSScott Long 2905914da7d0SScott Long disk = NULL; 2906914da7d0SScott Long 2907914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 2908914da7d0SScott Long sizeof(struct aac_query_disk)); 290936e0bf6eSScott Long if (error) 291036e0bf6eSScott Long return (error); 291136e0bf6eSScott Long 291236e0bf6eSScott Long id = query_disk.ContainerNumber; 291336e0bf6eSScott Long if (id == -1) 291436e0bf6eSScott Long return (EINVAL); 291536e0bf6eSScott Long 2916bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 291736e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 291836e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 291936e0bf6eSScott Long break; 292036e0bf6eSScott Long } 292136e0bf6eSScott Long 292236e0bf6eSScott Long if (co == NULL) { 292336e0bf6eSScott Long query_disk.Valid = 0; 292436e0bf6eSScott Long query_disk.Locked = 0; 292536e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 292636e0bf6eSScott Long } else { 292736e0bf6eSScott Long disk = device_get_softc(co->co_disk); 292836e0bf6eSScott Long query_disk.Valid = 1; 2929914da7d0SScott Long query_disk.Locked = 2930914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 293136e0bf6eSScott Long query_disk.Deleted = 0; 2932b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 293336e0bf6eSScott Long query_disk.Target = disk->unit; 293436e0bf6eSScott Long query_disk.Lun = 0; 293536e0bf6eSScott Long query_disk.UnMapped = 0; 29367540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 29370b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 293836e0bf6eSScott Long } 2939bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 294036e0bf6eSScott Long 2941914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 2942914da7d0SScott Long sizeof(struct aac_query_disk)); 294336e0bf6eSScott Long 294436e0bf6eSScott Long return (error); 294536e0bf6eSScott Long } 294636e0bf6eSScott Long 2947fe3cb0e1SScott Long static void 2948fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 2949fe3cb0e1SScott Long { 2950fe3cb0e1SScott Long struct aac_fib *fib; 2951fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 2952fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 2953fe3cb0e1SScott Long struct aac_vmioctl *vmi; 2954fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 2955fe3cb0e1SScott Long struct aac_getbusinf businfo; 295670545d1aSScott Long struct aac_sim *caminf; 2957fe3cb0e1SScott Long device_t child; 2958fe3cb0e1SScott Long int i, found, error; 2959fe3cb0e1SScott Long 296003b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2961fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 296239ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 2963fe3cb0e1SScott Long 2964fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 2965fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 2966fe3cb0e1SScott Long c_cmd->param = 0; 2967fe3cb0e1SScott Long 2968fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2969fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 2970fe3cb0e1SScott Long if (error) { 2971fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 2972fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 2973fe3cb0e1SScott Long aac_release_sync_fib(sc); 2974fe3cb0e1SScott Long return; 2975fe3cb0e1SScott Long } 2976fe3cb0e1SScott Long 2977fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2978fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 2979fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2980fe3cb0e1SScott Long c_resp->Status); 2981fe3cb0e1SScott Long aac_release_sync_fib(sc); 2982fe3cb0e1SScott Long return; 2983fe3cb0e1SScott Long } 2984fe3cb0e1SScott Long 2985fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 2986fe3cb0e1SScott Long 2987fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 298839ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 298939ee03c3SScott Long 2990fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 2991fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 2992fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 2993fe3cb0e1SScott Long vmi->ObjId = 0; 2994fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 2995fe3cb0e1SScott Long 2996fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2997fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 2998fe3cb0e1SScott Long if (error) { 2999fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3000fe3cb0e1SScott Long error); 3001fe3cb0e1SScott Long aac_release_sync_fib(sc); 3002fe3cb0e1SScott Long return; 3003fe3cb0e1SScott Long } 3004fe3cb0e1SScott Long 3005fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3006fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3007fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3008fe3cb0e1SScott Long vmi_resp->Status); 3009fe3cb0e1SScott Long aac_release_sync_fib(sc); 3010fe3cb0e1SScott Long return; 3011fe3cb0e1SScott Long } 3012fe3cb0e1SScott Long 3013fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3014fe3cb0e1SScott Long aac_release_sync_fib(sc); 3015fe3cb0e1SScott Long 3016fe3cb0e1SScott Long found = 0; 3017fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3018fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3019fe3cb0e1SScott Long continue; 3020fe3cb0e1SScott Long 3021a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3022a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3023b5f516cdSScott Long if (caminf == NULL) { 3024b5f516cdSScott Long device_printf(sc->aac_dev, 3025b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3026b5f516cdSScott Long break; 3027b5f516cdSScott Long } 3028fe3cb0e1SScott Long 3029fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3030fe3cb0e1SScott Long if (child == NULL) { 3031b5f516cdSScott Long device_printf(sc->aac_dev, 3032b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3033b5f516cdSScott Long i); 3034b5f516cdSScott Long free(caminf, M_AACBUF); 3035b5f516cdSScott Long break; 3036fe3cb0e1SScott Long } 3037fe3cb0e1SScott Long 3038fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3039fe3cb0e1SScott Long caminf->BusNumber = i; 3040fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3041fe3cb0e1SScott Long caminf->aac_sc = sc; 3042ddb8683eSScott Long caminf->sim_dev = child; 3043fe3cb0e1SScott Long 3044fe3cb0e1SScott Long device_set_ivars(child, caminf); 3045fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 304670545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3047fe3cb0e1SScott Long 3048fe3cb0e1SScott Long found = 1; 3049fe3cb0e1SScott Long } 3050fe3cb0e1SScott Long 3051fe3cb0e1SScott Long if (found) 3052fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3053fe3cb0e1SScott Long 3054fe3cb0e1SScott Long return; 3055fe3cb0e1SScott Long } 3056