aac.c revision 114151
165793Smsmith/*- 265793Smsmith * Copyright (c) 2000 Michael Smith 381082Sscottl * Copyright (c) 2001 Scott Long 465793Smsmith * Copyright (c) 2000 BSDi 581082Sscottl * Copyright (c) 2001 Adaptec, Inc. 665793Smsmith * All rights reserved. 765793Smsmith * 865793Smsmith * Redistribution and use in source and binary forms, with or without 965793Smsmith * modification, are permitted provided that the following conditions 1065793Smsmith * are met: 1165793Smsmith * 1. Redistributions of source code must retain the above copyright 1265793Smsmith * notice, this list of conditions and the following disclaimer. 1365793Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1465793Smsmith * notice, this list of conditions and the following disclaimer in the 1565793Smsmith * documentation and/or other materials provided with the distribution. 1665793Smsmith * 1765793Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1865793Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965793Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065793Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2165793Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265793Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365793Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465793Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565793Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665793Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765793Smsmith * SUCH DAMAGE. 2865793Smsmith * 2965793Smsmith * $FreeBSD: head/sys/dev/aac/aac.c 114151 2003-04-28 06:16:20Z scottl $ 3065793Smsmith */ 3165793Smsmith 3265793Smsmith/* 3365793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3465793Smsmith */ 3565793Smsmith 3681151Sscottl#include "opt_aac.h" 3781151Sscottl 3882527Sscottl/* #include <stddef.h> */ 3965793Smsmith#include <sys/param.h> 4065793Smsmith#include <sys/systm.h> 4165793Smsmith#include <sys/malloc.h> 4265793Smsmith#include <sys/kernel.h> 4382527Sscottl#include <sys/kthread.h> 4481154Sscottl#include <sys/sysctl.h> 4587183Sscottl#include <sys/poll.h> 46112946Sphk#include <sys/ioccom.h> 4765793Smsmith 4865793Smsmith#include <sys/bus.h> 4965793Smsmith#include <sys/conf.h> 5065793Smsmith#include <sys/signalvar.h> 5170393Smsmith#include <sys/time.h> 5282527Sscottl#include <sys/eventhandler.h> 5365793Smsmith 5465793Smsmith#include <machine/bus_memio.h> 5565793Smsmith#include <machine/bus.h> 5665793Smsmith#include <machine/resource.h> 5765793Smsmith 5865793Smsmith#include <dev/aac/aacreg.h> 5970393Smsmith#include <dev/aac/aac_ioctl.h> 6065793Smsmith#include <dev/aac/aacvar.h> 6165793Smsmith#include <dev/aac/aac_tables.h> 6265793Smsmith 6365793Smsmithstatic void aac_startup(void *arg); 6483114Sscottlstatic void aac_add_container(struct aac_softc *sc, 6595350Sscottl struct aac_mntinforesp *mir, int f); 6695536Sscottlstatic void aac_get_bus_info(struct aac_softc *sc); 6765793Smsmith 6865793Smsmith/* Command Processing */ 6970393Smsmithstatic void aac_timeout(struct aac_softc *sc); 7065793Smsmithstatic int aac_start(struct aac_command *cm); 7165793Smsmithstatic void aac_complete(void *context, int pending); 7265793Smsmithstatic int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7365793Smsmithstatic void aac_bio_complete(struct aac_command *cm); 7465793Smsmithstatic int aac_wait_command(struct aac_command *cm, int timeout); 75110426Sscottlstatic void aac_command_thread(struct aac_softc *sc); 7665793Smsmith 7765793Smsmith/* Command Buffer Management */ 7881082Sscottlstatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 7981082Sscottl int nseg, int error); 8070393Smsmithstatic int aac_alloc_commands(struct aac_softc *sc); 81111141Sscottlstatic void aac_free_commands(struct aac_softc *sc); 8265793Smsmithstatic void aac_map_command(struct aac_command *cm); 8365793Smsmithstatic void aac_unmap_command(struct aac_command *cm); 8465793Smsmith 8565793Smsmith/* Hardware Interface */ 8681082Sscottlstatic void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 8781082Sscottl int error); 8890275Sscottlstatic int aac_check_firmware(struct aac_softc *sc); 8965793Smsmithstatic int aac_init(struct aac_softc *sc); 9065793Smsmithstatic int aac_sync_command(struct aac_softc *sc, u_int32_t command, 9181082Sscottl u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 9281082Sscottl u_int32_t arg3, u_int32_t *sp); 9381082Sscottlstatic int aac_enqueue_fib(struct aac_softc *sc, int queue, 9481151Sscottl struct aac_command *cm); 9581082Sscottlstatic int aac_dequeue_fib(struct aac_softc *sc, int queue, 9683114Sscottl u_int32_t *fib_size, struct aac_fib **fib_addr); 9782527Sscottlstatic int aac_enqueue_response(struct aac_softc *sc, int queue, 9882527Sscottl struct aac_fib *fib); 9965793Smsmith 10087183Sscottl/* Falcon/PPC interface */ 10187183Sscottlstatic int aac_fa_get_fwstatus(struct aac_softc *sc); 10287183Sscottlstatic void aac_fa_qnotify(struct aac_softc *sc, int qbit); 10387183Sscottlstatic int aac_fa_get_istatus(struct aac_softc *sc); 10487183Sscottlstatic void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 10587183Sscottlstatic void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 10687183Sscottl u_int32_t arg0, u_int32_t arg1, 10787183Sscottl u_int32_t arg2, u_int32_t arg3); 108112679Sscottlstatic int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 10987183Sscottlstatic void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 11087183Sscottl 11187183Sscottlstruct aac_interface aac_fa_interface = { 11287183Sscottl aac_fa_get_fwstatus, 11387183Sscottl aac_fa_qnotify, 11487183Sscottl aac_fa_get_istatus, 11587183Sscottl aac_fa_clear_istatus, 11687183Sscottl aac_fa_set_mailbox, 117112679Sscottl aac_fa_get_mailbox, 11887183Sscottl aac_fa_set_interrupts 11987183Sscottl}; 12087183Sscottl 12165793Smsmith/* StrongARM interface */ 12265793Smsmithstatic int aac_sa_get_fwstatus(struct aac_softc *sc); 12365793Smsmithstatic void aac_sa_qnotify(struct aac_softc *sc, int qbit); 12465793Smsmithstatic int aac_sa_get_istatus(struct aac_softc *sc); 12565793Smsmithstatic void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 12665793Smsmithstatic void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 12781082Sscottl u_int32_t arg0, u_int32_t arg1, 12881082Sscottl u_int32_t arg2, u_int32_t arg3); 129112679Sscottlstatic int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13065793Smsmithstatic void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 13165793Smsmith 13265793Smsmithstruct aac_interface aac_sa_interface = { 13383114Sscottl aac_sa_get_fwstatus, 13483114Sscottl aac_sa_qnotify, 13583114Sscottl aac_sa_get_istatus, 13683114Sscottl aac_sa_clear_istatus, 13783114Sscottl aac_sa_set_mailbox, 138112679Sscottl aac_sa_get_mailbox, 13983114Sscottl aac_sa_set_interrupts 14065793Smsmith}; 14165793Smsmith 14283114Sscottl/* i960Rx interface */ 14365793Smsmithstatic int aac_rx_get_fwstatus(struct aac_softc *sc); 14465793Smsmithstatic void aac_rx_qnotify(struct aac_softc *sc, int qbit); 14565793Smsmithstatic int aac_rx_get_istatus(struct aac_softc *sc); 14665793Smsmithstatic void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 14765793Smsmithstatic void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 14881082Sscottl u_int32_t arg0, u_int32_t arg1, 14981082Sscottl u_int32_t arg2, u_int32_t arg3); 150112679Sscottlstatic int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 15165793Smsmithstatic void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 15265793Smsmith 15365793Smsmithstruct aac_interface aac_rx_interface = { 15483114Sscottl aac_rx_get_fwstatus, 15583114Sscottl aac_rx_qnotify, 15683114Sscottl aac_rx_get_istatus, 15783114Sscottl aac_rx_clear_istatus, 15883114Sscottl aac_rx_set_mailbox, 159112679Sscottl aac_rx_get_mailbox, 16083114Sscottl aac_rx_set_interrupts 16165793Smsmith}; 16265793Smsmith 16365793Smsmith/* Debugging and Diagnostics */ 16465793Smsmithstatic void aac_describe_controller(struct aac_softc *sc); 16582567Sscottlstatic char *aac_describe_code(struct aac_code_lookup *table, 16681082Sscottl u_int32_t code); 16765793Smsmith 16865793Smsmith/* Management Interface */ 16965793Smsmithstatic d_open_t aac_open; 17065793Smsmithstatic d_close_t aac_close; 17165793Smsmithstatic d_ioctl_t aac_ioctl; 17287183Sscottlstatic d_poll_t aac_poll; 17381082Sscottlstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 17481082Sscottlstatic void aac_handle_aif(struct aac_softc *sc, 17583114Sscottl struct aac_fib *fib); 17681189Sscottlstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 17781189Sscottlstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 17881189Sscottlstatic int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 17982527Sscottlstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 18065793Smsmith 18165793Smsmith#define AAC_CDEV_MAJOR 150 18265793Smsmith 18365793Smsmithstatic struct cdevsw aac_cdevsw = { 184111815Sphk .d_open = aac_open, 185111815Sphk .d_close = aac_close, 186111815Sphk .d_ioctl = aac_ioctl, 187111815Sphk .d_poll = aac_poll, 188111815Sphk .d_name = "aac", 189111815Sphk .d_maj = AAC_CDEV_MAJOR, 19065793Smsmith}; 19165793Smsmith 19282527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 19382527Sscottl 19481154Sscottl/* sysctl node */ 19581154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 19681154Sscottl 19783114Sscottl/* 19883114Sscottl * Device Interface 19983114Sscottl */ 20065793Smsmith 20183114Sscottl/* 20265793Smsmith * Initialise the controller and softc 20365793Smsmith */ 20465793Smsmithint 20565793Smsmithaac_attach(struct aac_softc *sc) 20665793Smsmith{ 20783114Sscottl int error, unit; 20865793Smsmith 20983114Sscottl debug_called(1); 21065793Smsmith 21183114Sscottl /* 21283114Sscottl * Initialise per-controller queues. 21383114Sscottl */ 21483114Sscottl aac_initq_free(sc); 21583114Sscottl aac_initq_ready(sc); 21683114Sscottl aac_initq_busy(sc); 21783114Sscottl aac_initq_bio(sc); 21865793Smsmith 21983114Sscottl /* 22083114Sscottl * Initialise command-completion task. 22183114Sscottl */ 22283114Sscottl TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 22365793Smsmith 22483114Sscottl /* disable interrupts before we enable anything */ 22583114Sscottl AAC_MASK_INTERRUPTS(sc); 22665793Smsmith 22783114Sscottl /* mark controller as suspended until we get ourselves organised */ 22883114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 22965793Smsmith 23083114Sscottl /* 23190275Sscottl * Check that the firmware on the card is supported. 23290275Sscottl */ 23390275Sscottl if ((error = aac_check_firmware(sc)) != 0) 23490275Sscottl return(error); 23590275Sscottl 23695350Sscottl /* Init the sync fib lock */ 23795350Sscottl AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 23895350Sscottl 23983114Sscottl /* 24083114Sscottl * Initialise the adapter. 24183114Sscottl */ 24283114Sscottl if ((error = aac_init(sc)) != 0) 24383114Sscottl return(error); 24465793Smsmith 24583114Sscottl /* 24683114Sscottl * Print a little information about the controller. 24783114Sscottl */ 24883114Sscottl aac_describe_controller(sc); 24965793Smsmith 25083114Sscottl /* 251111532Sscottl * Initialize locks 25283114Sscottl */ 253111532Sscottl AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 25483114Sscottl TAILQ_INIT(&sc->aac_container_tqh); 25587183Sscottl AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 256111532Sscottl AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock"); 25782527Sscottl 25887183Sscottl /* 259111532Sscottl * Register to probe our containers later. 26087183Sscottl */ 26183114Sscottl sc->aac_ich.ich_func = aac_startup; 26283114Sscottl sc->aac_ich.ich_arg = sc; 26383114Sscottl if (config_intrhook_establish(&sc->aac_ich) != 0) { 26483114Sscottl device_printf(sc->aac_dev, 26583114Sscottl "can't establish configuration hook\n"); 26683114Sscottl return(ENXIO); 26783114Sscottl } 26865793Smsmith 26983114Sscottl /* 27083114Sscottl * Make the control device. 27183114Sscottl */ 27283114Sscottl unit = device_get_unit(sc->aac_dev); 273108329Srwatson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 274108329Srwatson 0640, "aac%d", unit); 27583114Sscottl (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 27683114Sscottl (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 27783114Sscottl sc->aac_dev_t->si_drv1 = sc; 27865793Smsmith 27983114Sscottl /* Create the AIF thread */ 280110426Sscottl if (kthread_create((void(*)(void *))aac_command_thread, sc, 281104354Sscottl &sc->aifthread, 0, 0, "aac%daif", unit)) 28283114Sscottl panic("Could not create AIF thread\n"); 28382527Sscottl 28483114Sscottl /* Register the shutdown method to only be called post-dump */ 285110427Sscottl if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 286110427Sscottl sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 287110427Sscottl device_printf(sc->aac_dev, 288110427Sscottl "shutdown event registration failed\n"); 28982527Sscottl 29095536Sscottl /* Register with CAM for the non-DASD devices */ 291112679Sscottl if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 292110426Sscottl TAILQ_INIT(&sc->aac_sim_tqh); 29395536Sscottl aac_get_bus_info(sc); 294110426Sscottl } 29595536Sscottl 29683114Sscottl return(0); 29765793Smsmith} 29865793Smsmith 29983114Sscottl/* 30065793Smsmith * Probe for containers, create disks. 30165793Smsmith */ 30265793Smsmithstatic void 30365793Smsmithaac_startup(void *arg) 30465793Smsmith{ 30583114Sscottl struct aac_softc *sc; 30695350Sscottl struct aac_fib *fib; 30795350Sscottl struct aac_mntinfo *mi; 30895350Sscottl struct aac_mntinforesp *mir = NULL; 30983114Sscottl int i = 0; 31065793Smsmith 31183114Sscottl debug_called(1); 31265793Smsmith 31383114Sscottl sc = (struct aac_softc *)arg; 31465793Smsmith 31583114Sscottl /* disconnect ourselves from the intrhook chain */ 31683114Sscottl config_intrhook_disestablish(&sc->aac_ich); 31765793Smsmith 31895536Sscottl aac_alloc_sync_fib(sc, &fib, 0); 31995350Sscottl mi = (struct aac_mntinfo *)&fib->data[0]; 32095350Sscottl 32183114Sscottl /* loop over possible containers */ 32283114Sscottl do { 32383114Sscottl /* request information on this container */ 32495966Sscottl bzero(mi, sizeof(struct aac_mntinfo)); 32595966Sscottl mi->Command = VM_NameServe; 32695966Sscottl mi->MntType = FT_FILESYS; 32795350Sscottl mi->MntCount = i; 32895350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 32995350Sscottl sizeof(struct aac_mntinfo))) { 33083114Sscottl debug(2, "error probing container %d", i); 33183114Sscottl continue; 33283114Sscottl } 33365793Smsmith 33495350Sscottl mir = (struct aac_mntinforesp *)&fib->data[0]; 33595350Sscottl aac_add_container(sc, mir, 0); 33683114Sscottl i++; 33795350Sscottl } while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS)); 33865793Smsmith 33995350Sscottl aac_release_sync_fib(sc); 34095350Sscottl 34183114Sscottl /* poke the bus to actually attach the child devices */ 34283114Sscottl if (bus_generic_attach(sc->aac_dev)) 34383114Sscottl device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 34465793Smsmith 34583114Sscottl /* mark the controller up */ 34683114Sscottl sc->aac_state &= ~AAC_STATE_SUSPEND; 34770393Smsmith 34883114Sscottl /* enable interrupts now */ 34983114Sscottl AAC_UNMASK_INTERRUPTS(sc); 35065793Smsmith} 35165793Smsmith 35283114Sscottl/* 35383114Sscottl * Create a device to respresent a new container 35483114Sscottl */ 35583114Sscottlstatic void 35695350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 35783114Sscottl{ 35883114Sscottl struct aac_container *co; 35983114Sscottl device_t child; 36083114Sscottl 36183114Sscottl /* 36283114Sscottl * Check container volume type for validity. Note that many of 36383114Sscottl * the possible types may never show up. 36483114Sscottl */ 36583114Sscottl if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 366110428Sscottl co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 367110428Sscottl M_NOWAIT | M_ZERO); 36883114Sscottl if (co == NULL) 36983114Sscottl panic("Out of memory?!\n"); 37083114Sscottl debug(1, "id %x name '%.16s' size %u type %d", 37183114Sscottl mir->MntTable[0].ObjectId, 37283114Sscottl mir->MntTable[0].FileSystemName, 37383114Sscottl mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 37483114Sscottl 37595536Sscottl if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 37683114Sscottl device_printf(sc->aac_dev, "device_add_child failed\n"); 37783114Sscottl else 37883114Sscottl device_set_ivars(child, co); 37983114Sscottl device_set_desc(child, aac_describe_code(aac_container_types, 38083114Sscottl mir->MntTable[0].VolType)); 38183114Sscottl co->co_disk = child; 38283114Sscottl co->co_found = f; 38383114Sscottl bcopy(&mir->MntTable[0], &co->co_mntobj, 38483114Sscottl sizeof(struct aac_mntobj)); 38587310Sscottl AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 38683114Sscottl TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 38783114Sscottl AAC_LOCK_RELEASE(&sc->aac_container_lock); 38883114Sscottl } 38983114Sscottl} 39083114Sscottl 39183114Sscottl/* 39265793Smsmith * Free all of the resources associated with (sc) 39365793Smsmith * 39465793Smsmith * Should not be called if the controller is active. 39565793Smsmith */ 39665793Smsmithvoid 39765793Smsmithaac_free(struct aac_softc *sc) 39865793Smsmith{ 399110604Sscottl 40083114Sscottl debug_called(1); 40165793Smsmith 40283114Sscottl /* remove the control device */ 40383114Sscottl if (sc->aac_dev_t != NULL) 40483114Sscottl destroy_dev(sc->aac_dev_t); 40565793Smsmith 40683114Sscottl /* throw away any FIB buffers, discard the FIB DMA tag */ 407111141Sscottl aac_free_commands(sc); 40883114Sscottl if (sc->aac_fib_dmat) 40983114Sscottl bus_dma_tag_destroy(sc->aac_fib_dmat); 41065793Smsmith 411110604Sscottl free(sc->aac_commands, M_AACBUF); 412110604Sscottl 41383114Sscottl /* destroy the common area */ 41483114Sscottl if (sc->aac_common) { 41583114Sscottl bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 41683114Sscottl bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 41783114Sscottl sc->aac_common_dmamap); 41883114Sscottl } 41983114Sscottl if (sc->aac_common_dmat) 42083114Sscottl bus_dma_tag_destroy(sc->aac_common_dmat); 42165793Smsmith 42283114Sscottl /* disconnect the interrupt handler */ 42383114Sscottl if (sc->aac_intr) 42483114Sscottl bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 42583114Sscottl if (sc->aac_irq != NULL) 42683114Sscottl bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 42783114Sscottl sc->aac_irq); 42865793Smsmith 42983114Sscottl /* destroy data-transfer DMA tag */ 43083114Sscottl if (sc->aac_buffer_dmat) 43183114Sscottl bus_dma_tag_destroy(sc->aac_buffer_dmat); 43265793Smsmith 43383114Sscottl /* destroy the parent DMA tag */ 43483114Sscottl if (sc->aac_parent_dmat) 43583114Sscottl bus_dma_tag_destroy(sc->aac_parent_dmat); 43665793Smsmith 43783114Sscottl /* release the register window mapping */ 43883114Sscottl if (sc->aac_regs_resource != NULL) 43983114Sscottl bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 44083114Sscottl sc->aac_regs_rid, sc->aac_regs_resource); 44165793Smsmith} 44265793Smsmith 44383114Sscottl/* 44465793Smsmith * Disconnect from the controller completely, in preparation for unload. 44565793Smsmith */ 44665793Smsmithint 44765793Smsmithaac_detach(device_t dev) 44865793Smsmith{ 44983114Sscottl struct aac_softc *sc; 450110426Sscottl struct aac_container *co; 451110426Sscottl struct aac_sim *sim; 45283114Sscottl int error; 45365793Smsmith 45483114Sscottl debug_called(1); 45565793Smsmith 45683114Sscottl sc = device_get_softc(dev); 45783114Sscottl 45883114Sscottl if (sc->aac_state & AAC_STATE_OPEN) 459110426Sscottl return(EBUSY); 46065793Smsmith 461110426Sscottl /* Remove the child containers */ 462110428Sscottl while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 463110426Sscottl error = device_delete_child(dev, co->co_disk); 464110426Sscottl if (error) 465110426Sscottl return (error); 466111196Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 467110428Sscottl free(co, M_AACBUF); 468110426Sscottl } 469110426Sscottl 470110426Sscottl /* Remove the CAM SIMs */ 471110428Sscottl while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 472110428Sscottl TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 473110426Sscottl error = device_delete_child(dev, sim->sim_dev); 474110426Sscottl if (error) 475110426Sscottl return (error); 476110428Sscottl free(sim, M_AACBUF); 477110426Sscottl } 478110426Sscottl 47983114Sscottl if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 48083114Sscottl sc->aifflags |= AAC_AIFFLAGS_EXIT; 48183114Sscottl wakeup(sc->aifthread); 48283114Sscottl tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 48383114Sscottl } 48482527Sscottl 48583114Sscottl if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 48683114Sscottl panic("Cannot shutdown AIF thread\n"); 48782527Sscottl 48883114Sscottl if ((error = aac_shutdown(dev))) 48983114Sscottl return(error); 49065793Smsmith 491110427Sscottl EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 492110427Sscottl 49383114Sscottl aac_free(sc); 49465793Smsmith 49583114Sscottl return(0); 49665793Smsmith} 49765793Smsmith 49883114Sscottl/* 49965793Smsmith * Bring the controller down to a dormant state and detach all child devices. 50065793Smsmith * 50165793Smsmith * This function is called before detach or system shutdown. 50265793Smsmith * 50370393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't 50465793Smsmith * allow shutdown if any device is open. 50565793Smsmith */ 50665793Smsmithint 50765793Smsmithaac_shutdown(device_t dev) 50865793Smsmith{ 50983114Sscottl struct aac_softc *sc; 51095350Sscottl struct aac_fib *fib; 51195350Sscottl struct aac_close_command *cc; 51265793Smsmith 51383114Sscottl debug_called(1); 51465793Smsmith 51583114Sscottl sc = device_get_softc(dev); 51665793Smsmith 51783114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 51865793Smsmith 51983114Sscottl /* 52083114Sscottl * Send a Container shutdown followed by a HostShutdown FIB to the 52183114Sscottl * controller to convince it that we don't want to talk to it anymore. 52283114Sscottl * We've been closed and all I/O completed already 52382527Sscottl */ 52483114Sscottl device_printf(sc->aac_dev, "shutting down controller..."); 52583114Sscottl 52695536Sscottl aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 52795350Sscottl cc = (struct aac_close_command *)&fib->data[0]; 52895350Sscottl 52995966Sscottl bzero(cc, sizeof(struct aac_close_command)); 53095350Sscottl cc->Command = VM_CloseAll; 53195350Sscottl cc->ContainerId = 0xffffffff; 53295350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 53395350Sscottl sizeof(struct aac_close_command))) 53483114Sscottl printf("FAILED.\n"); 535110426Sscottl else 536110426Sscottl printf("done\n"); 537110426Sscottl#if 0 53883114Sscottl else { 53995350Sscottl fib->data[0] = 0; 54083114Sscottl /* 54183114Sscottl * XXX Issuing this command to the controller makes it shut down 54283114Sscottl * but also keeps it from coming back up without a reset of the 54383114Sscottl * PCI bus. This is not desirable if you are just unloading the 54483114Sscottl * driver module with the intent to reload it later. 54583114Sscottl */ 54695350Sscottl if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 54795350Sscottl fib, 1)) { 54883114Sscottl printf("FAILED.\n"); 54983114Sscottl } else { 55083114Sscottl printf("done.\n"); 55183114Sscottl } 55265793Smsmith } 553110426Sscottl#endif 55465793Smsmith 55583114Sscottl AAC_MASK_INTERRUPTS(sc); 55665793Smsmith 55783114Sscottl return(0); 55865793Smsmith} 55965793Smsmith 56083114Sscottl/* 56165793Smsmith * Bring the controller to a quiescent state, ready for system suspend. 56265793Smsmith */ 56365793Smsmithint 56465793Smsmithaac_suspend(device_t dev) 56565793Smsmith{ 56683114Sscottl struct aac_softc *sc; 56765793Smsmith 56883114Sscottl debug_called(1); 56965793Smsmith 57083114Sscottl sc = device_get_softc(dev); 57183114Sscottl 57283114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 57383114Sscottl 57483114Sscottl AAC_MASK_INTERRUPTS(sc); 57583114Sscottl return(0); 57665793Smsmith} 57765793Smsmith 57883114Sscottl/* 57965793Smsmith * Bring the controller back to a state ready for operation. 58065793Smsmith */ 58165793Smsmithint 58265793Smsmithaac_resume(device_t dev) 58365793Smsmith{ 58483114Sscottl struct aac_softc *sc; 58565793Smsmith 58683114Sscottl debug_called(1); 58783114Sscottl 58883114Sscottl sc = device_get_softc(dev); 58983114Sscottl 59083114Sscottl sc->aac_state &= ~AAC_STATE_SUSPEND; 59183114Sscottl AAC_UNMASK_INTERRUPTS(sc); 59283114Sscottl return(0); 59365793Smsmith} 59465793Smsmith 59583114Sscottl/* 59665793Smsmith * Take an interrupt. 59765793Smsmith */ 59865793Smsmithvoid 59965793Smsmithaac_intr(void *arg) 60065793Smsmith{ 60183114Sscottl struct aac_softc *sc; 602110426Sscottl u_int32_t *resp_queue; 60383114Sscottl u_int16_t reason; 60465793Smsmith 60583114Sscottl debug_called(2); 60665793Smsmith 60783114Sscottl sc = (struct aac_softc *)arg; 60865793Smsmith 609109088Sscottl /* 610109088Sscottl * Optimize the common case of adapter response interrupts. 611109088Sscottl * We must read from the card prior to processing the responses 612109088Sscottl * to ensure the clear is flushed prior to accessing the queues. 613109088Sscottl * Reading the queues from local memory might save us a PCI read. 614109088Sscottl */ 615109088Sscottl resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE]; 616109088Sscottl if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX]) 617109088Sscottl reason = AAC_DB_RESPONSE_READY; 618109088Sscottl else 619109088Sscottl reason = AAC_GET_ISTATUS(sc); 620109088Sscottl AAC_CLEAR_ISTATUS(sc, reason); 621109088Sscottl (void)AAC_GET_ISTATUS(sc); 62265793Smsmith 623109088Sscottl /* It's not ok to return here because of races with the previous step */ 624109088Sscottl if (reason & AAC_DB_RESPONSE_READY) 625111143Sscottl /* handle completion processing */ 626111532Sscottl taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); 627109088Sscottl 62887183Sscottl /* controller wants to talk to the log */ 629110426Sscottl if (reason & AAC_DB_PRINTF) { 630110426Sscottl if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 631110426Sscottl sc->aifflags |= AAC_AIFFLAGS_PRINTF; 632110426Sscottl } else 633110426Sscottl aac_print_printf(sc); 634110426Sscottl } 63565793Smsmith 63683114Sscottl /* controller has a message for us? */ 63783114Sscottl if (reason & AAC_DB_COMMAND_READY) { 63883114Sscottl if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 639110426Sscottl sc->aifflags |= AAC_AIFFLAGS_AIF; 640110426Sscottl } else { 641110426Sscottl /* 642110426Sscottl * XXX If the kthread is dead and we're at this point, 643110426Sscottl * there are bigger problems than just figuring out 644110426Sscottl * what to do with an AIF. 645110426Sscottl */ 64683114Sscottl } 647110426Sscottl 64883114Sscottl } 649110426Sscottl 650110426Sscottl if ((sc->aifflags & AAC_AIFFLAGS_PENDING) != 0) 651110426Sscottl /* XXX Should this be done with cv_signal? */ 652110426Sscottl wakeup(sc->aifthread); 653109088Sscottl} 65483114Sscottl 65583114Sscottl/* 65683114Sscottl * Command Processing 65783114Sscottl */ 65865793Smsmith 65983114Sscottl/* 66065793Smsmith * Start as much queued I/O as possible on the controller 66165793Smsmith */ 66295536Sscottlvoid 66365793Smsmithaac_startio(struct aac_softc *sc) 66465793Smsmith{ 66583114Sscottl struct aac_command *cm; 66665793Smsmith 66783114Sscottl debug_called(2); 66865793Smsmith 66983114Sscottl for (;;) { 67083114Sscottl /* 67183114Sscottl * Try to get a command that's been put off for lack of 67283114Sscottl * resources 67383114Sscottl */ 67483114Sscottl cm = aac_dequeue_ready(sc); 67565793Smsmith 67683114Sscottl /* 67783114Sscottl * Try to build a command off the bio queue (ignore error 67883114Sscottl * return) 67983114Sscottl */ 68083114Sscottl if (cm == NULL) 68183114Sscottl aac_bio_command(sc, &cm); 68265793Smsmith 68383114Sscottl /* nothing to do? */ 68483114Sscottl if (cm == NULL) 68583114Sscottl break; 68665793Smsmith 68783114Sscottl /* try to give the command to the controller */ 68883114Sscottl if (aac_start(cm) == EBUSY) { 68983114Sscottl /* put it on the ready queue for later */ 69083114Sscottl aac_requeue_ready(cm); 69183114Sscottl break; 69283114Sscottl } 69365793Smsmith } 69465793Smsmith} 69565793Smsmith 69683114Sscottl/* 69765793Smsmith * Deliver a command to the controller; allocate controller resources at the 69865793Smsmith * last moment when possible. 69965793Smsmith */ 70065793Smsmithstatic int 70165793Smsmithaac_start(struct aac_command *cm) 70265793Smsmith{ 70383114Sscottl struct aac_softc *sc; 70483114Sscottl int error; 70565793Smsmith 70683114Sscottl debug_called(2); 70765793Smsmith 70883114Sscottl sc = cm->cm_sc; 70965793Smsmith 71083114Sscottl /* get the command mapped */ 71183114Sscottl aac_map_command(cm); 71265793Smsmith 713114151Sscottl /* Fix up the address values in the FIB. Use the command array index 714114151Sscottl * instead of a pointer since these fields are only 32 bits. Shift 715114151Sscottl * the SenderFibAddress over to make room for the fast response bit. 716114151Sscottl */ 717114151Sscottl cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1); 71883114Sscottl cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 71983114Sscottl 72083114Sscottl /* save a pointer to the command for speedy reverse-lookup */ 721111152Sscottl cm->cm_fib->Header.SenderData = cm->cm_index; 72283114Sscottl /* put the FIB on the outbound queue */ 72383114Sscottl error = aac_enqueue_fib(sc, cm->cm_queue, cm); 72483114Sscottl return(error); 72565793Smsmith} 72665793Smsmith 72783114Sscottl/* 72865793Smsmith * Handle notification of one or more FIBs coming from the controller. 72965793Smsmith */ 73065793Smsmithstatic void 731110426Sscottlaac_command_thread(struct aac_softc *sc) 73265793Smsmith{ 73383114Sscottl struct aac_fib *fib; 73483114Sscottl u_int32_t fib_size; 73583114Sscottl int size; 73665793Smsmith 73783114Sscottl debug_called(2); 73865793Smsmith 73983114Sscottl sc->aifflags |= AAC_AIFFLAGS_RUNNING; 74065793Smsmith 74183114Sscottl while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) { 742110426Sscottl if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 743110426Sscottl tsleep(sc->aifthread, PRIBIO, "aifthd", 744110426Sscottl AAC_PERIODIC_INTERVAL * hz); 74582527Sscottl 746110426Sscottl if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 747110426Sscottl aac_timeout(sc); 748110426Sscottl 749110426Sscottl /* Check the hardware printf message buffer */ 750110426Sscottl if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) { 751110426Sscottl sc->aifflags &= ~AAC_AIFFLAGS_PRINTF; 752110426Sscottl aac_print_printf(sc); 753110426Sscottl } 754110426Sscottl 755111532Sscottl /* See if any FIBs need to be allocated */ 756111532Sscottl if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 757111532Sscottl AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 758111532Sscottl aac_alloc_commands(sc); 759111532Sscottl sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 760111532Sscottl AAC_LOCK_RELEASE(&sc->aac_io_lock); 761111532Sscottl } 762111532Sscottl 763111532Sscottl /* While we're here, check to see if any commands are stuck */ 764110426Sscottl while (sc->aifflags & AAC_AIFFLAGS_AIF) { 76583114Sscottl if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 766110426Sscottl &fib_size, &fib)) { 767110426Sscottl sc->aifflags &= ~AAC_AIFFLAGS_AIF; 76883114Sscottl break; /* nothing to do */ 769110426Sscottl } 77083114Sscottl 77183114Sscottl AAC_PRINT_FIB(sc, fib); 77283114Sscottl 77383114Sscottl switch (fib->Header.Command) { 77483114Sscottl case AifRequest: 77583114Sscottl aac_handle_aif(sc, fib); 77683114Sscottl break; 77783114Sscottl default: 77883114Sscottl device_printf(sc->aac_dev, "unknown command " 77983114Sscottl "from controller\n"); 78083114Sscottl break; 78183114Sscottl } 78282527Sscottl 78383114Sscottl if ((fib->Header.XferState == 0) || 78483114Sscottl (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 78583114Sscottl break; 78682527Sscottl 787110426Sscottl /* Return the AIF to the controller. */ 78883114Sscottl if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 78983114Sscottl fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 79083114Sscottl *(AAC_FSAStatus*)fib->data = ST_OK; 79182527Sscottl 79283114Sscottl /* XXX Compute the Size field? */ 79383114Sscottl size = fib->Header.Size; 79483114Sscottl if (size > sizeof(struct aac_fib)) { 79595536Sscottl size = sizeof(struct aac_fib); 79683114Sscottl fib->Header.Size = size; 79783114Sscottl } 79883114Sscottl /* 79983114Sscottl * Since we did not generate this command, it 80083114Sscottl * cannot go through the normal 80183114Sscottl * enqueue->startio chain. 80283114Sscottl */ 80383114Sscottl aac_enqueue_response(sc, 80483114Sscottl AAC_ADAP_NORM_RESP_QUEUE, 80583114Sscottl fib); 80683114Sscottl } 80782527Sscottl } 80865793Smsmith } 80983114Sscottl sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 81083114Sscottl wakeup(sc->aac_dev); 81165793Smsmith 81283114Sscottl mtx_lock(&Giant); 81383114Sscottl kthread_exit(0); 81465793Smsmith} 81565793Smsmith 81683114Sscottl/* 817111143Sscottl * Process completed commands. 81865793Smsmith */ 81965793Smsmithstatic void 820111143Sscottlaac_complete(void *context, int pending) 82165793Smsmith{ 822111143Sscottl struct aac_softc *sc; 82383114Sscottl struct aac_command *cm; 82483114Sscottl struct aac_fib *fib; 82583114Sscottl u_int32_t fib_size; 82665793Smsmith 82783114Sscottl debug_called(2); 82865793Smsmith 829111143Sscottl sc = (struct aac_softc *)context; 830111143Sscottl 831111532Sscottl AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 832111532Sscottl 833111143Sscottl /* pull completed commands off the queue */ 83483114Sscottl for (;;) { 83583114Sscottl /* look for completed FIBs on our queue */ 83683114Sscottl if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 83783114Sscottl &fib)) 83883114Sscottl break; /* nothing to do */ 839111143Sscottl 84083114Sscottl /* get the command, unmap and queue for later processing */ 841111152Sscottl cm = sc->aac_commands + fib->Header.SenderData; 84283114Sscottl if (cm == NULL) { 84383114Sscottl AAC_PRINT_FIB(sc, fib); 844111143Sscottl break; 84583114Sscottl } 84665793Smsmith 847111143Sscottl aac_remove_busy(cm); 848111143Sscottl aac_unmap_command(cm); /* XXX defer? */ 84983114Sscottl cm->cm_flags |= AAC_CMD_COMPLETED; 85083114Sscottl 85183114Sscottl /* is there a completion handler? */ 85283114Sscottl if (cm->cm_complete != NULL) { 85383114Sscottl cm->cm_complete(cm); 85483114Sscottl } else { 85583114Sscottl /* assume that someone is sleeping on this command */ 85683114Sscottl wakeup(cm); 85783114Sscottl } 85865793Smsmith } 85970393Smsmith 86083114Sscottl /* see if we can start some more I/O */ 86183114Sscottl aac_startio(sc); 862111532Sscottl 863111532Sscottl AAC_LOCK_RELEASE(&sc->aac_io_lock); 86465793Smsmith} 86565793Smsmith 86683114Sscottl/* 86765793Smsmith * Handle a bio submitted from a disk device. 86865793Smsmith */ 86965793Smsmithvoid 87065793Smsmithaac_submit_bio(struct bio *bp) 87165793Smsmith{ 87283114Sscottl struct aac_disk *ad; 87383114Sscottl struct aac_softc *sc; 87465793Smsmith 87583114Sscottl debug_called(2); 87665793Smsmith 877111525Sscottl ad = (struct aac_disk *)bp->bio_disk->d_drv1; 87883114Sscottl sc = ad->ad_controller; 87983114Sscottl 88083114Sscottl /* queue the BIO and try to get some work done */ 88183114Sscottl aac_enqueue_bio(sc, bp); 88283114Sscottl aac_startio(sc); 88365793Smsmith} 88465793Smsmith 88583114Sscottl/* 88665793Smsmith * Get a bio and build a command to go with it. 88765793Smsmith */ 88865793Smsmithstatic int 88965793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 89065793Smsmith{ 89183114Sscottl struct aac_command *cm; 89283114Sscottl struct aac_fib *fib; 89383114Sscottl struct aac_disk *ad; 89483114Sscottl struct bio *bp; 89565793Smsmith 89683114Sscottl debug_called(2); 89765793Smsmith 89883114Sscottl /* get the resources we will need */ 89983114Sscottl cm = NULL; 90083114Sscottl if ((bp = aac_dequeue_bio(sc)) == NULL) 90183114Sscottl goto fail; 90283114Sscottl if (aac_alloc_command(sc, &cm)) /* get a command */ 90383114Sscottl goto fail; 90465793Smsmith 90583114Sscottl /* fill out the command */ 90683114Sscottl cm->cm_data = (void *)bp->bio_data; 90783114Sscottl cm->cm_datalen = bp->bio_bcount; 90883114Sscottl cm->cm_complete = aac_bio_complete; 90983114Sscottl cm->cm_private = bp; 91083114Sscottl cm->cm_timestamp = time_second; 91183114Sscottl cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 91265793Smsmith 91383114Sscottl /* build the FIB */ 91483114Sscottl fib = cm->cm_fib; 915112856Sscottl fib->Header.Size = sizeof(struct aac_fib_header); 91683114Sscottl fib->Header.XferState = 917109088Sscottl AAC_FIBSTATE_HOSTOWNED | 918109088Sscottl AAC_FIBSTATE_INITIALISED | 919109088Sscottl AAC_FIBSTATE_EMPTY | 920109088Sscottl AAC_FIBSTATE_FROMHOST | 921109088Sscottl AAC_FIBSTATE_REXPECTED | 922109088Sscottl AAC_FIBSTATE_NORM | 923109088Sscottl AAC_FIBSTATE_ASYNC | 924109088Sscottl AAC_FIBSTATE_FAST_RESPONSE; 92565793Smsmith 92683114Sscottl /* build the read/write request */ 927111525Sscottl ad = (struct aac_disk *)bp->bio_disk->d_drv1; 928112856Sscottl 929112856Sscottl if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 930112856Sscottl fib->Header.Command = ContainerCommand; 931112856Sscottl if (bp->bio_cmd == BIO_READ) { 932112856Sscottl struct aac_blockread *br; 933112856Sscottl br = (struct aac_blockread *)&fib->data[0]; 934112856Sscottl br->Command = VM_CtBlockRead; 935112856Sscottl br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 936112856Sscottl br->BlockNumber = bp->bio_pblkno; 937112856Sscottl br->ByteCount = bp->bio_bcount; 938112856Sscottl fib->Header.Size += sizeof(struct aac_blockread); 939112856Sscottl cm->cm_sgtable = &br->SgMap; 940112856Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 941112856Sscottl } else { 942112856Sscottl struct aac_blockwrite *bw; 943112856Sscottl bw = (struct aac_blockwrite *)&fib->data[0]; 944112856Sscottl bw->Command = VM_CtBlockWrite; 945112856Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 946112856Sscottl bw->BlockNumber = bp->bio_pblkno; 947112856Sscottl bw->ByteCount = bp->bio_bcount; 948112856Sscottl bw->Stable = CUNSTABLE; 949112856Sscottl fib->Header.Size += sizeof(struct aac_blockwrite); 950112856Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 951112856Sscottl cm->cm_sgtable = &bw->SgMap; 952112856Sscottl } 95383114Sscottl } else { 954112856Sscottl fib->Header.Command = ContainerCommand64; 955112856Sscottl if (bp->bio_cmd == BIO_READ) { 956112856Sscottl struct aac_blockread64 *br; 957112856Sscottl br = (struct aac_blockread64 *)&fib->data[0]; 958112856Sscottl br->Command = VM_CtHostRead64; 959112856Sscottl br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 960112856Sscottl br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 961112856Sscottl br->BlockNumber = bp->bio_pblkno; 962112856Sscottl br->Pad = 0; 963112856Sscottl br->Flags = 0; 964112856Sscottl fib->Header.Size += sizeof(struct aac_blockread64); 965112856Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 966112856Sscottl (struct aac_sg_table64 *)cm->cm_sgtable = &br->SgMap64; 967112856Sscottl } else { 968112856Sscottl struct aac_blockwrite64 *bw; 969112856Sscottl bw = (struct aac_blockwrite64 *)&fib->data[0]; 970112856Sscottl bw->Command = VM_CtHostWrite64; 971112856Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 972112856Sscottl bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 973112856Sscottl bw->BlockNumber = bp->bio_pblkno; 974112856Sscottl bw->Pad = 0; 975112856Sscottl bw->Flags = 0; 976112856Sscottl fib->Header.Size += sizeof(struct aac_blockwrite64); 977112856Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 978112856Sscottl (struct aac_sg_table64 *)cm->cm_sgtable = &bw->SgMap64; 979112856Sscottl } 98083114Sscottl } 98165793Smsmith 98283114Sscottl *cmp = cm; 98383114Sscottl return(0); 98465793Smsmith 98565793Smsmithfail: 98683114Sscottl if (bp != NULL) 98783114Sscottl aac_enqueue_bio(sc, bp); 98883114Sscottl if (cm != NULL) 98983114Sscottl aac_release_command(cm); 99083114Sscottl return(ENOMEM); 99165793Smsmith} 99265793Smsmith 99383114Sscottl/* 99465793Smsmith * Handle a bio-instigated command that has been completed. 99565793Smsmith */ 99665793Smsmithstatic void 99765793Smsmithaac_bio_complete(struct aac_command *cm) 99865793Smsmith{ 99983114Sscottl struct aac_blockread_response *brr; 100083114Sscottl struct aac_blockwrite_response *bwr; 100183114Sscottl struct bio *bp; 100283114Sscottl AAC_FSAStatus status; 100365793Smsmith 100483114Sscottl /* fetch relevant status and then release the command */ 100583114Sscottl bp = (struct bio *)cm->cm_private; 1006111691Sscottl if (bp->bio_cmd == BIO_READ) { 100783114Sscottl brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 100883114Sscottl status = brr->Status; 100983114Sscottl } else { 101083114Sscottl bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 101183114Sscottl status = bwr->Status; 101283114Sscottl } 101383114Sscottl aac_release_command(cm); 101465793Smsmith 101583114Sscottl /* fix up the bio based on status */ 101683114Sscottl if (status == ST_OK) { 101783114Sscottl bp->bio_resid = 0; 101883114Sscottl } else { 101983114Sscottl bp->bio_error = EIO; 102083114Sscottl bp->bio_flags |= BIO_ERROR; 102183114Sscottl /* pass an error string out to the disk layer */ 102283114Sscottl bp->bio_driver1 = aac_describe_code(aac_command_status_table, 102383114Sscottl status); 102483114Sscottl } 102583114Sscottl aac_biodone(bp); 102665793Smsmith} 102765793Smsmith 102883114Sscottl/* 102965793Smsmith * Submit a command to the controller, return when it completes. 103087183Sscottl * XXX This is very dangerous! If the card has gone out to lunch, we could 103187183Sscottl * be stuck here forever. At the same time, signals are not caught 103287183Sscottl * because there is a risk that a signal could wakeup the tsleep before 103387183Sscottl * the card has a chance to complete the command. The passed in timeout 103487183Sscottl * is ignored for the same reason. Since there is no way to cancel a 103587183Sscottl * command in progress, we should probably create a 'dead' queue where 103687183Sscottl * commands go that have been interrupted/timed-out/etc, that keeps them 103787183Sscottl * out of the free pool. That way, if the card is just slow, it won't 103887183Sscottl * spam the memory of a command that has been recycled. 103965793Smsmith */ 104065793Smsmithstatic int 104165793Smsmithaac_wait_command(struct aac_command *cm, int timeout) 104265793Smsmith{ 1043111532Sscottl struct aac_softc *sc; 1044111532Sscottl int error = 0; 104565793Smsmith 104683114Sscottl debug_called(2); 104765793Smsmith 1048111532Sscottl sc = cm->cm_sc; 1049111532Sscottl 105083114Sscottl /* Put the command on the ready queue and get things going */ 105183114Sscottl cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 105283114Sscottl aac_enqueue_ready(cm); 1053111532Sscottl aac_startio(sc); 105483114Sscottl while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1055111532Sscottl error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 105683114Sscottl } 105783114Sscottl return(error); 105865793Smsmith} 105965793Smsmith 106083114Sscottl/* 106183114Sscottl *Command Buffer Management 106283114Sscottl */ 106365793Smsmith 106483114Sscottl/* 106565793Smsmith * Allocate a command. 106665793Smsmith */ 106795536Sscottlint 106865793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 106965793Smsmith{ 107083114Sscottl struct aac_command *cm; 107165793Smsmith 107283114Sscottl debug_called(3); 107365793Smsmith 1074110604Sscottl if ((cm = aac_dequeue_free(sc)) == NULL) { 1075112856Sscottl if (sc->total_fibs < sc->aac_max_fibs) { 1076112856Sscottl sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1077112856Sscottl wakeup(sc->aifthread); 1078112856Sscottl } 1079111532Sscottl return (EBUSY); 1080110604Sscottl } 108165793Smsmith 108283114Sscottl *cmp = cm; 108383114Sscottl return(0); 108470393Smsmith} 108570393Smsmith 108683114Sscottl/* 108770393Smsmith * Release a command back to the freelist. 108870393Smsmith */ 108995536Sscottlvoid 109070393Smsmithaac_release_command(struct aac_command *cm) 109170393Smsmith{ 109283114Sscottl debug_called(3); 109370393Smsmith 109483114Sscottl /* (re)initialise the command/FIB */ 109583114Sscottl cm->cm_sgtable = NULL; 109683114Sscottl cm->cm_flags = 0; 109783114Sscottl cm->cm_complete = NULL; 109883114Sscottl cm->cm_private = NULL; 109983114Sscottl cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 110083114Sscottl cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 110183114Sscottl cm->cm_fib->Header.Flags = 0; 110283114Sscottl cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 110365793Smsmith 110483114Sscottl /* 110583114Sscottl * These are duplicated in aac_start to cover the case where an 110683114Sscottl * intermediate stage may have destroyed them. They're left 110783114Sscottl * initialised here for debugging purposes only. 110883114Sscottl */ 110983114Sscottl cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib; 1110109088Sscottl cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1111109088Sscottl cm->cm_fib->Header.SenderData = 0; 111265793Smsmith 111383114Sscottl aac_enqueue_free(cm); 111465793Smsmith} 111565793Smsmith 111683114Sscottl/* 111770393Smsmith * Map helper for command/FIB allocation. 111865793Smsmith */ 111965793Smsmithstatic void 112070393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 112165793Smsmith{ 1122111141Sscottl uint32_t *fibphys; 112365793Smsmith 1124111141Sscottl fibphys = (uint32_t *)arg; 112565793Smsmith 112683114Sscottl debug_called(3); 112783114Sscottl 1128110604Sscottl *fibphys = segs[0].ds_addr; 112965793Smsmith} 113065793Smsmith 113183114Sscottl/* 113270393Smsmith * Allocate and initialise commands/FIBs for this adapter. 113365793Smsmith */ 113470393Smsmithstatic int 113570393Smsmithaac_alloc_commands(struct aac_softc *sc) 113665793Smsmith{ 113783114Sscottl struct aac_command *cm; 1138110604Sscottl struct aac_fibmap *fm; 1139111141Sscottl uint32_t fibphys; 1140110604Sscottl int i, error; 114165793Smsmith 1142112679Sscottl debug_called(2); 114365793Smsmith 1144112679Sscottl if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs) 1145110604Sscottl return (ENOMEM); 1146110604Sscottl 1147111141Sscottl fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1148112679Sscottl if (fm == NULL) 1149112679Sscottl return (ENOMEM); 1150110604Sscottl 115183114Sscottl /* allocate the FIBs in DMAable memory and load them */ 1152110604Sscottl if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1153110604Sscottl BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1154110426Sscottl device_printf(sc->aac_dev, 1155110426Sscottl "Not enough contiguous memory available.\n"); 1156111141Sscottl free(fm, M_AACBUF); 1157102602Sscottl return (ENOMEM); 115883114Sscottl } 1159109716Sscottl 1160110604Sscottl bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1161110604Sscottl AAC_FIB_COUNT * sizeof(struct aac_fib), 1162110604Sscottl aac_map_command_helper, &fibphys, 0); 1163109716Sscottl 1164109716Sscottl /* initialise constant fields in the command structure */ 1165110604Sscottl bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 116683114Sscottl for (i = 0; i < AAC_FIB_COUNT; i++) { 1167111141Sscottl cm = sc->aac_commands + sc->total_fibs; 1168110604Sscottl fm->aac_commands = cm; 116983114Sscottl cm->cm_sc = sc; 1170110604Sscottl cm->cm_fib = fm->aac_fibs + i; 1171111141Sscottl cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1172111152Sscottl cm->cm_index = sc->total_fibs; 117365793Smsmith 1174110604Sscottl if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1175110604Sscottl &cm->cm_datamap)) == 0) 117683114Sscottl aac_release_command(cm); 1177111141Sscottl else 1178111141Sscottl break; 1179111141Sscottl sc->total_fibs++; 118083114Sscottl } 1181110604Sscottl 1182111141Sscottl if (i > 0) { 1183111141Sscottl TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1184112679Sscottl debug(1, "total_fibs= %d\n", sc->total_fibs); 1185111141Sscottl return (0); 1186111141Sscottl } 1187110604Sscottl 1188111141Sscottl bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1189111141Sscottl bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1190111141Sscottl free(fm, M_AACBUF); 1191111141Sscottl return (ENOMEM); 119265793Smsmith} 119365793Smsmith 119483114Sscottl/* 119570393Smsmith * Free FIBs owned by this adapter. 119665793Smsmith */ 119765793Smsmithstatic void 1198111141Sscottlaac_free_commands(struct aac_softc *sc) 119965793Smsmith{ 1200111141Sscottl struct aac_fibmap *fm; 1201110604Sscottl struct aac_command *cm; 120283114Sscottl int i; 120365793Smsmith 120483114Sscottl debug_called(1); 120565793Smsmith 1206111141Sscottl while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1207111141Sscottl 1208111141Sscottl TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1209111141Sscottl /* 1210111141Sscottl * We check against total_fibs to handle partially 1211111141Sscottl * allocated blocks. 1212111141Sscottl */ 1213111141Sscottl for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1214111141Sscottl cm = fm->aac_commands + i; 1215111141Sscottl bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1216111141Sscottl } 1217111141Sscottl bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1218111141Sscottl bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1219111141Sscottl free(fm, M_AACBUF); 1220110604Sscottl } 122165793Smsmith} 122265793Smsmith 122383114Sscottl/* 122465793Smsmith * Command-mapping helper function - populate this command's s/g table. 122565793Smsmith */ 122665793Smsmithstatic void 122765793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 122865793Smsmith{ 122983114Sscottl struct aac_command *cm; 123083114Sscottl struct aac_fib *fib; 123183114Sscottl int i; 123265793Smsmith 123383114Sscottl debug_called(3); 123465793Smsmith 123583114Sscottl cm = (struct aac_command *)arg; 123683114Sscottl fib = cm->cm_fib; 123765793Smsmith 123883114Sscottl /* copy into the FIB */ 1239112856Sscottl if (cm->cm_sgtable != NULL) { 1240112856Sscottl if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1241112856Sscottl struct aac_sg_table *sg; 1242112856Sscottl sg = cm->cm_sgtable; 1243112856Sscottl sg->SgCount = nseg; 1244112856Sscottl for (i = 0; i < nseg; i++) { 1245112856Sscottl sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1246112856Sscottl sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1247112856Sscottl } 1248112856Sscottl /* update the FIB size for the s/g count */ 1249112856Sscottl fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 1250112856Sscottl } else { 1251112856Sscottl struct aac_sg_table64 *sg; 1252112856Sscottl sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1253112856Sscottl sg->SgCount = nseg; 1254112856Sscottl for (i = 0; i < nseg; i++) { 1255112856Sscottl sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1256112856Sscottl sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1257112856Sscottl } 1258112856Sscottl /* update the FIB size for the s/g count */ 1259112856Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 126083114Sscottl } 126165793Smsmith } 126265793Smsmith} 126365793Smsmith 126483114Sscottl/* 126565793Smsmith * Map a command into controller-visible space. 126665793Smsmith */ 126765793Smsmithstatic void 126865793Smsmithaac_map_command(struct aac_command *cm) 126965793Smsmith{ 127083114Sscottl struct aac_softc *sc; 127165793Smsmith 127283114Sscottl debug_called(2); 127365793Smsmith 127483114Sscottl sc = cm->cm_sc; 127565793Smsmith 127683114Sscottl /* don't map more than once */ 127783114Sscottl if (cm->cm_flags & AAC_CMD_MAPPED) 127883114Sscottl return; 127965793Smsmith 128083114Sscottl if (cm->cm_datalen != 0) { 128183114Sscottl bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 128283114Sscottl cm->cm_data, cm->cm_datalen, 128383114Sscottl aac_map_command_sg, cm, 0); 128483114Sscottl 1285109088Sscottl if (cm->cm_flags & AAC_CMD_DATAIN) 1286109088Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1287109088Sscottl BUS_DMASYNC_PREREAD); 1288109088Sscottl if (cm->cm_flags & AAC_CMD_DATAOUT) 1289109088Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1290109088Sscottl BUS_DMASYNC_PREWRITE); 129183114Sscottl } 129283114Sscottl cm->cm_flags |= AAC_CMD_MAPPED; 129365793Smsmith} 129465793Smsmith 129583114Sscottl/* 129665793Smsmith * Unmap a command from controller-visible space. 129765793Smsmith */ 129865793Smsmithstatic void 129965793Smsmithaac_unmap_command(struct aac_command *cm) 130065793Smsmith{ 130183114Sscottl struct aac_softc *sc; 130265793Smsmith 130383114Sscottl debug_called(2); 130465793Smsmith 130583114Sscottl sc = cm->cm_sc; 130665793Smsmith 130783114Sscottl if (!(cm->cm_flags & AAC_CMD_MAPPED)) 130883114Sscottl return; 130965793Smsmith 131083114Sscottl if (cm->cm_datalen != 0) { 131183114Sscottl if (cm->cm_flags & AAC_CMD_DATAIN) 131283114Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 131383114Sscottl BUS_DMASYNC_POSTREAD); 131483114Sscottl if (cm->cm_flags & AAC_CMD_DATAOUT) 131583114Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 131683114Sscottl BUS_DMASYNC_POSTWRITE); 131783114Sscottl 131883114Sscottl bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 131983114Sscottl } 132083114Sscottl cm->cm_flags &= ~AAC_CMD_MAPPED; 132165793Smsmith} 132265793Smsmith 132383114Sscottl/* 132483114Sscottl * Hardware Interface 132583114Sscottl */ 132665793Smsmith 132783114Sscottl/* 132865793Smsmith * Initialise the adapter. 132965793Smsmith */ 133065793Smsmithstatic void 133165793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 133265793Smsmith{ 133383114Sscottl struct aac_softc *sc; 133465793Smsmith 133583114Sscottl debug_called(1); 133665793Smsmith 133783114Sscottl sc = (struct aac_softc *)arg; 133883114Sscottl 133983114Sscottl sc->aac_common_busaddr = segs[0].ds_addr; 134065793Smsmith} 134165793Smsmith 134265793Smsmithstatic int 134390275Sscottlaac_check_firmware(struct aac_softc *sc) 134490275Sscottl{ 1345112679Sscottl u_int32_t major, minor, options; 134690275Sscottl 134790275Sscottl debug_called(1); 134890275Sscottl 1349112679Sscottl /* 1350112679Sscottl * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1351112679Sscottl * firmware version 1.x are not compatible with this driver. 1352112679Sscottl */ 1353112679Sscottl if (sc->flags & AAC_FLAGS_PERC2QC) { 135490275Sscottl if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 135590275Sscottl NULL)) { 135690275Sscottl device_printf(sc->aac_dev, 135790275Sscottl "Error reading firmware version\n"); 135890275Sscottl return (EIO); 135990275Sscottl } 136090275Sscottl 136190275Sscottl /* These numbers are stored as ASCII! */ 1362112679Sscottl major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1363112679Sscottl minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 136490275Sscottl if (major == 1) { 136590275Sscottl device_printf(sc->aac_dev, 136690275Sscottl "Firmware version %d.%d is not supported.\n", 136790275Sscottl major, minor); 136890275Sscottl return (EINVAL); 136990275Sscottl } 137090275Sscottl } 137190275Sscottl 1372112679Sscottl /* 1373112679Sscottl * Retrieve the capabilities/supported options word so we know what 1374112679Sscottl * work-arounds to enable. 1375112679Sscottl */ 1376112679Sscottl if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1377112679Sscottl device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1378112679Sscottl return (EIO); 1379112679Sscottl } 1380112679Sscottl options = AAC_GET_MAILBOX(sc, 1); 1381112679Sscottl sc->supported_options = options; 1382112679Sscottl 1383112679Sscottl if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1384112679Sscottl (sc->flags & AAC_FLAGS_NO4GB) == 0) 1385112679Sscottl sc->flags |= AAC_FLAGS_4GB_WINDOW; 1386112679Sscottl if (options & AAC_SUPPORTED_NONDASD) 1387112679Sscottl sc->flags |= AAC_FLAGS_ENABLE_CAM; 1388112856Sscottl if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 && (sizeof(bus_addr_t) > 4)) { 1389112679Sscottl device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1390112679Sscottl sc->flags |= AAC_FLAGS_SG_64BIT; 1391112679Sscottl } 1392112679Sscottl 1393112679Sscottl /* Check for broken hardware that does a lower number of commands */ 1394112679Sscottl if ((sc->flags & AAC_FLAGS_256FIBS) == 0) 1395112679Sscottl sc->aac_max_fibs = AAC_MAX_FIBS; 1396112679Sscottl else 1397112679Sscottl sc->aac_max_fibs = 256; 1398112679Sscottl 139990275Sscottl return (0); 140090275Sscottl} 140190275Sscottl 140290275Sscottlstatic int 140365793Smsmithaac_init(struct aac_softc *sc) 140465793Smsmith{ 140583114Sscottl struct aac_adapter_init *ip; 140683114Sscottl time_t then; 140783114Sscottl u_int32_t code; 140883114Sscottl u_int8_t *qaddr; 1409112679Sscottl int error; 141065793Smsmith 141183114Sscottl debug_called(1); 141265793Smsmith 141383114Sscottl /* 141483114Sscottl * First wait for the adapter to come ready. 141583114Sscottl */ 141683114Sscottl then = time_second; 141783114Sscottl do { 141883114Sscottl code = AAC_GET_FWSTATUS(sc); 141983114Sscottl if (code & AAC_SELF_TEST_FAILED) { 142083114Sscottl device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 142183114Sscottl return(ENXIO); 142283114Sscottl } 142383114Sscottl if (code & AAC_KERNEL_PANIC) { 142483114Sscottl device_printf(sc->aac_dev, 142583114Sscottl "FATAL: controller kernel panic\n"); 142683114Sscottl return(ENXIO); 142783114Sscottl } 142883114Sscottl if (time_second > (then + AAC_BOOT_TIMEOUT)) { 142983114Sscottl device_printf(sc->aac_dev, 143083114Sscottl "FATAL: controller not coming ready, " 143183114Sscottl "status %x\n", code); 143283114Sscottl return(ENXIO); 143383114Sscottl } 143483114Sscottl } while (!(code & AAC_UP_AND_RUNNING)); 143583114Sscottl 1436112679Sscottl error = ENOMEM; 143783114Sscottl /* 1438112679Sscottl * Create DMA tag for mapping buffers into controller-addressable space. 1439112679Sscottl */ 1440112679Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1441112679Sscottl 1, 0, /* algnmnt, boundary */ 1442112679Sscottl (sc->flags & AAC_FLAGS_SG_64BIT) ? 1443112679Sscottl BUS_SPACE_MAXADDR : 1444112679Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1445112679Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 1446112679Sscottl NULL, NULL, /* filter, filterarg */ 1447112679Sscottl MAXBSIZE, /* maxsize */ 1448112679Sscottl AAC_MAXSGENTRIES, /* nsegments */ 1449112679Sscottl MAXBSIZE, /* maxsegsize */ 1450112679Sscottl BUS_DMA_ALLOCNOW, /* flags */ 1451112679Sscottl &sc->aac_buffer_dmat)) { 1452112679Sscottl device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1453112679Sscottl goto out; 1454112679Sscottl } 1455112679Sscottl 1456112679Sscottl /* 1457112679Sscottl * Create DMA tag for mapping FIBs into controller-addressable space.. 1458112679Sscottl */ 1459112679Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1460112679Sscottl 1, 0, /* algnmnt, boundary */ 1461112679Sscottl (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1462112679Sscottl BUS_SPACE_MAXADDR_32BIT : 1463112679Sscottl 0x7fffffff, /* lowaddr */ 1464112679Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 1465112679Sscottl NULL, NULL, /* filter, filterarg */ 1466112679Sscottl AAC_FIB_COUNT * 1467112679Sscottl sizeof(struct aac_fib), /* maxsize */ 1468112679Sscottl 1, /* nsegments */ 1469112679Sscottl AAC_FIB_COUNT * 1470112679Sscottl sizeof(struct aac_fib), /* maxsegsize */ 1471112679Sscottl BUS_DMA_ALLOCNOW, /* flags */ 1472112679Sscottl &sc->aac_fib_dmat)) { 1473112679Sscottl device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1474112679Sscottl goto out; 1475112679Sscottl } 1476112679Sscottl 1477112679Sscottl /* 147883114Sscottl * Create DMA tag for the common structure and allocate it. 147983114Sscottl */ 148083114Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 148195536Sscottl 1, 0, /* algnmnt, boundary */ 1482112679Sscottl (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1483112679Sscottl BUS_SPACE_MAXADDR_32BIT : 1484112679Sscottl 0x7fffffff, /* lowaddr */ 148583114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 148683114Sscottl NULL, NULL, /* filter, filterarg */ 1487110604Sscottl 8192 + sizeof(struct aac_common), /* maxsize */ 148883114Sscottl 1, /* nsegments */ 148983114Sscottl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1490112679Sscottl BUS_DMA_ALLOCNOW, /* flags */ 149183114Sscottl &sc->aac_common_dmat)) { 149283114Sscottl device_printf(sc->aac_dev, 149383114Sscottl "can't allocate common structure DMA tag\n"); 1494112679Sscottl goto out; 149565793Smsmith } 149683114Sscottl if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 149783114Sscottl BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 149883114Sscottl device_printf(sc->aac_dev, "can't allocate common structure\n"); 1499112679Sscottl goto out; 150065793Smsmith } 1501110604Sscottl 1502110604Sscottl /* 1503110604Sscottl * Work around a bug in the 2120 and 2200 that cannot DMA commands 1504110604Sscottl * below address 8192 in physical memory. 1505110604Sscottl * XXX If the padding is not needed, can it be put to use instead 1506110604Sscottl * of ignored? 1507110604Sscottl */ 150883114Sscottl bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1509110604Sscottl sc->aac_common, 8192 + sizeof(*sc->aac_common), 1510110604Sscottl aac_common_map, sc, 0); 1511110604Sscottl 1512110604Sscottl if (sc->aac_common_busaddr < 8192) { 1513110604Sscottl (uint8_t *)sc->aac_common += 8192; 1514110604Sscottl sc->aac_common_busaddr += 8192; 1515110604Sscottl } 151683114Sscottl bzero(sc->aac_common, sizeof(*sc->aac_common)); 1517110604Sscottl 1518110604Sscottl /* Allocate some FIBs and associated command structs */ 1519110604Sscottl TAILQ_INIT(&sc->aac_fibmap_tqh); 1520110604Sscottl sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 1521111141Sscottl M_AACBUF, M_WAITOK|M_ZERO); 1522111141Sscottl while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1523110604Sscottl if (aac_alloc_commands(sc) != 0) 1524110604Sscottl break; 1525110604Sscottl } 1526110604Sscottl if (sc->total_fibs == 0) 1527112679Sscottl goto out; 152883114Sscottl 152983114Sscottl /* 153083114Sscottl * Fill in the init structure. This tells the adapter about the 153183114Sscottl * physical location of various important shared data structures. 153283114Sscottl */ 153383114Sscottl ip = &sc->aac_common->ac_init; 153483114Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1535109088Sscottl ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 153665793Smsmith 153783114Sscottl ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 153883114Sscottl offsetof(struct aac_common, ac_fibs); 1539114151Sscottl ip->AdapterFibsVirtualAddress = 0; 154083114Sscottl ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 154183114Sscottl ip->AdapterFibAlign = sizeof(struct aac_fib); 154265793Smsmith 154383114Sscottl ip->PrintfBufferAddress = sc->aac_common_busaddr + 154483114Sscottl offsetof(struct aac_common, ac_printf); 154583114Sscottl ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 154665793Smsmith 1547109088Sscottl /* The adapter assumes that pages are 4K in size */ 1548109088Sscottl ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 154983114Sscottl ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 155065793Smsmith 155183114Sscottl /* 155283114Sscottl * Initialise FIB queues. Note that it appears that the layout of the 155383114Sscottl * indexes and the segmentation of the entries may be mandated by the 155483114Sscottl * adapter, which is only told about the base of the queue index fields. 155583114Sscottl * 155683114Sscottl * The initial values of the indices are assumed to inform the adapter 155783114Sscottl * of the sizes of the respective queues, and theoretically it could 155883114Sscottl * work out the entire layout of the queue structures from this. We 155983114Sscottl * take the easy route and just lay this area out like everyone else 156083114Sscottl * does. 156183114Sscottl * 156283114Sscottl * The Linux driver uses a much more complex scheme whereby several 156383114Sscottl * header records are kept for each queue. We use a couple of generic 156483114Sscottl * list manipulation functions which 'know' the size of each list by 156583114Sscottl * virtue of a table. 156683114Sscottl */ 156783114Sscottl qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN; 156883114Sscottl qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; 156983114Sscottl sc->aac_queues = (struct aac_queue_table *)qaddr; 157083114Sscottl ip->CommHeaderAddress = sc->aac_common_busaddr + 157183114Sscottl ((u_int32_t)sc->aac_queues - 157283114Sscottl (u_int32_t)sc->aac_common); 157365793Smsmith 157483114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 157581082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 157683114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 157781082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 157883114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 157981082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 158083114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 158181082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 158283114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 158381082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 158483114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 158581082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 158683114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 158781082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 158883114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 158981082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 159083114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 159181082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 159283114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 159381082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 159483114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 159581082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 159683114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 159781082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 159883114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 159981082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 160083114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 160181082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 160283114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 160381082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 160483114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 160581082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 160683114Sscottl sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 160781082Sscottl &sc->aac_queues->qt_HostNormCmdQueue[0]; 160883114Sscottl sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 160981082Sscottl &sc->aac_queues->qt_HostHighCmdQueue[0]; 161083114Sscottl sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 161181082Sscottl &sc->aac_queues->qt_AdapNormCmdQueue[0]; 161283114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 161381082Sscottl &sc->aac_queues->qt_AdapHighCmdQueue[0]; 161483114Sscottl sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 161581082Sscottl &sc->aac_queues->qt_HostNormRespQueue[0]; 161683114Sscottl sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 161781082Sscottl &sc->aac_queues->qt_HostHighRespQueue[0]; 161883114Sscottl sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 161981082Sscottl &sc->aac_queues->qt_AdapNormRespQueue[0]; 162083114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 162181082Sscottl &sc->aac_queues->qt_AdapHighRespQueue[0]; 162265793Smsmith 162383114Sscottl /* 162483114Sscottl * Do controller-type-specific initialisation 162583114Sscottl */ 162683114Sscottl switch (sc->aac_hwif) { 162783114Sscottl case AAC_HWIF_I960RX: 162883114Sscottl AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 162983114Sscottl break; 163083114Sscottl } 163165793Smsmith 163283114Sscottl /* 163383114Sscottl * Give the init structure to the controller. 163483114Sscottl */ 163583114Sscottl if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 163683114Sscottl sc->aac_common_busaddr + 163783114Sscottl offsetof(struct aac_common, ac_init), 0, 0, 0, 163883114Sscottl NULL)) { 163983114Sscottl device_printf(sc->aac_dev, 164083114Sscottl "error establishing init structure\n"); 1641112679Sscottl error = EIO; 1642112679Sscottl goto out; 164383114Sscottl } 164465793Smsmith 1645112679Sscottl error = 0; 1646112679Sscottlout: 1647112679Sscottl return(error); 164865793Smsmith} 164965793Smsmith 165083114Sscottl/* 165165793Smsmith * Send a synchronous command to the controller and wait for a result. 165265793Smsmith */ 165365793Smsmithstatic int 165465793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command, 165570393Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 165670393Smsmith u_int32_t *sp) 165765793Smsmith{ 165883114Sscottl time_t then; 165983114Sscottl u_int32_t status; 166065793Smsmith 166183114Sscottl debug_called(3); 166265793Smsmith 166383114Sscottl /* populate the mailbox */ 166483114Sscottl AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 166565793Smsmith 166683114Sscottl /* ensure the sync command doorbell flag is cleared */ 166783114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 166865793Smsmith 166983114Sscottl /* then set it to signal the adapter */ 167083114Sscottl AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 167165793Smsmith 167283114Sscottl /* spin waiting for the command to complete */ 167383114Sscottl then = time_second; 167483114Sscottl do { 167583114Sscottl if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 1676112679Sscottl debug(1, "timed out"); 167783114Sscottl return(EIO); 167883114Sscottl } 167983114Sscottl } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 168065793Smsmith 168183114Sscottl /* clear the completion flag */ 168283114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 168365793Smsmith 168483114Sscottl /* get the command status */ 1685112679Sscottl status = AAC_GET_MAILBOX(sc, 0); 168683114Sscottl if (sp != NULL) 168783114Sscottl *sp = status; 168883114Sscottl return(0); 168965793Smsmith} 169065793Smsmith 169183114Sscottl/* 169295350Sscottl * Grab the sync fib area. 169395350Sscottl */ 169495350Sscottlint 169595536Sscottlaac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 169695350Sscottl{ 169795350Sscottl 169895350Sscottl /* 169995350Sscottl * If the force flag is set, the system is shutting down, or in 170095350Sscottl * trouble. Ignore the mutex. 170195350Sscottl */ 170295350Sscottl if (!(flags & AAC_SYNC_LOCK_FORCE)) 170395350Sscottl AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 170495350Sscottl 170595350Sscottl *fib = &sc->aac_common->ac_sync_fib; 170695350Sscottl 170795350Sscottl return (1); 170895350Sscottl} 170995350Sscottl 171095350Sscottl/* 171195350Sscottl * Release the sync fib area. 171295350Sscottl */ 171395350Sscottlvoid 171495350Sscottlaac_release_sync_fib(struct aac_softc *sc) 171595350Sscottl{ 171695350Sscottl 171795350Sscottl AAC_LOCK_RELEASE(&sc->aac_sync_lock); 171895350Sscottl} 171995350Sscottl 172095350Sscottl/* 172165793Smsmith * Send a synchronous FIB to the controller and wait for a result. 172265793Smsmith */ 172395350Sscottlint 172465793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 172595350Sscottl struct aac_fib *fib, u_int16_t datasize) 172665793Smsmith{ 172783114Sscottl debug_called(3); 172865793Smsmith 172983114Sscottl if (datasize > AAC_FIB_DATASIZE) 173083114Sscottl return(EINVAL); 173165793Smsmith 173283114Sscottl /* 173383114Sscottl * Set up the sync FIB 173483114Sscottl */ 173583114Sscottl fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 173683114Sscottl AAC_FIBSTATE_INITIALISED | 173783114Sscottl AAC_FIBSTATE_EMPTY; 173883114Sscottl fib->Header.XferState |= xferstate; 173983114Sscottl fib->Header.Command = command; 174083114Sscottl fib->Header.StructType = AAC_FIBTYPE_TFIB; 174183114Sscottl fib->Header.Size = sizeof(struct aac_fib) + datasize; 174283114Sscottl fib->Header.SenderSize = sizeof(struct aac_fib); 174383114Sscottl fib->Header.SenderFibAddress = (u_int32_t)fib; 174483114Sscottl fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 174583114Sscottl offsetof(struct aac_common, 174683114Sscottl ac_sync_fib); 174765793Smsmith 174883114Sscottl /* 174983114Sscottl * Give the FIB to the controller, wait for a response. 175083114Sscottl */ 175183114Sscottl if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 175283114Sscottl fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 175383114Sscottl debug(2, "IO error"); 175483114Sscottl return(EIO); 175583114Sscottl } 175681151Sscottl 175795350Sscottl return (0); 175865793Smsmith} 175965793Smsmith 176083114Sscottl/* 176165793Smsmith * Adapter-space FIB queue manipulation 176265793Smsmith * 176365793Smsmith * Note that the queue implementation here is a little funky; neither the PI or 176465793Smsmith * CI will ever be zero. This behaviour is a controller feature. 176565793Smsmith */ 176665793Smsmithstatic struct { 176783114Sscottl int size; 176883114Sscottl int notify; 176965793Smsmith} aac_qinfo[] = { 177083114Sscottl {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 177183114Sscottl {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 177283114Sscottl {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 177383114Sscottl {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 177483114Sscottl {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 177583114Sscottl {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 177683114Sscottl {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 177783114Sscottl {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 177865793Smsmith}; 177965793Smsmith 178065793Smsmith/* 178181082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or 178281082Sscottl * EBUSY if the queue is full. 178365793Smsmith * 178470393Smsmith * Note: it would be more efficient to defer notifying the controller in 178583114Sscottl * the case where we may be inserting several entries in rapid succession, 178683114Sscottl * but implementing this usefully may be difficult (it would involve a 178783114Sscottl * separate queue/notify interface). 178865793Smsmith */ 178965793Smsmithstatic int 179081151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 179165793Smsmith{ 179283114Sscottl u_int32_t pi, ci; 1793111691Sscottl int error; 179483114Sscottl u_int32_t fib_size; 179583114Sscottl u_int32_t fib_addr; 179665793Smsmith 179783114Sscottl debug_called(3); 179882527Sscottl 179983114Sscottl fib_size = cm->cm_fib->Header.Size; 180083114Sscottl fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 180181151Sscottl 180283114Sscottl /* get the producer/consumer indices */ 180383114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 180483114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 180565793Smsmith 180683114Sscottl /* wrap the queue? */ 180783114Sscottl if (pi >= aac_qinfo[queue].size) 180883114Sscottl pi = 0; 180965793Smsmith 181083114Sscottl /* check for queue full */ 181183114Sscottl if ((pi + 1) == ci) { 181283114Sscottl error = EBUSY; 181383114Sscottl goto out; 181483114Sscottl } 181565793Smsmith 181683114Sscottl /* populate queue entry */ 181783114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 181883114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 181965793Smsmith 182083114Sscottl /* update producer index */ 182183114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 182265793Smsmith 182383114Sscottl /* 182483114Sscottl * To avoid a race with its completion interrupt, place this command on 182583114Sscottl * the busy queue prior to advertising it to the controller. 182683114Sscottl */ 182783114Sscottl aac_enqueue_busy(cm); 182881151Sscottl 182983114Sscottl /* notify the adapter if we know how */ 183083114Sscottl if (aac_qinfo[queue].notify != 0) 183183114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 183265793Smsmith 183383114Sscottl error = 0; 183465793Smsmith 183565793Smsmithout: 183683114Sscottl return(error); 183765793Smsmith} 183865793Smsmith 183965793Smsmith/* 184082527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on 184182527Sscottl * success or ENOENT if the queue is empty. 184265793Smsmith */ 184365793Smsmithstatic int 184481082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 184581082Sscottl struct aac_fib **fib_addr) 184665793Smsmith{ 184783114Sscottl u_int32_t pi, ci; 1848114151Sscottl u_int32_t fib_index; 1849111691Sscottl int error; 185083114Sscottl int notify; 185165793Smsmith 185283114Sscottl debug_called(3); 185365793Smsmith 185483114Sscottl /* get the producer/consumer indices */ 185583114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 185683114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 185765793Smsmith 185883114Sscottl /* check for queue empty */ 185983114Sscottl if (ci == pi) { 186083114Sscottl error = ENOENT; 186183114Sscottl goto out; 186283114Sscottl } 186383114Sscottl 186483114Sscottl notify = 0; 186583114Sscottl if (ci == pi + 1) 186683114Sscottl notify++; 186781151Sscottl 186883114Sscottl /* wrap the queue? */ 186983114Sscottl if (ci >= aac_qinfo[queue].size) 187083114Sscottl ci = 0; 187165793Smsmith 187283114Sscottl /* fetch the entry */ 187383114Sscottl *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 187465793Smsmith 1875114151Sscottl switch (queue) { 1876114151Sscottl case AAC_HOST_NORM_CMD_QUEUE: 1877114151Sscottl case AAC_HOST_HIGH_CMD_QUEUE: 1878114151Sscottl /* 1879114151Sscottl * The aq_fib_addr is only 32 bits wide so it can't be counted 1880114151Sscottl * on to hold an address. For AIF's, the adapter assumes 1881114151Sscottl * that it's giving us an address into the array of AIF fibs. 1882114151Sscottl * Therefore, we have to convert it to an index. 1883114151Sscottl */ 1884114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 1885114151Sscottl sizeof(struct aac_fib); 1886114151Sscottl *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 1887114151Sscottl break; 1888114151Sscottl 1889114151Sscottl case AAC_HOST_NORM_RESP_QUEUE: 1890114151Sscottl case AAC_HOST_HIGH_RESP_QUEUE: 1891114151Sscottl { 1892114151Sscottl struct aac_command *cm; 1893114151Sscottl 1894114151Sscottl /* 1895114151Sscottl * As above, an index is used instead of an actual address. 1896114151Sscottl * Gotta shift the index to account for the fast response 1897114151Sscottl * bit. No other correction is needed since this value was 1898114151Sscottl * originally provided by the driver via the SenderFibAddress 1899114151Sscottl * field. 1900114151Sscottl */ 1901114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 1902114151Sscottl cm = sc->aac_commands + (fib_index >> 1); 1903114151Sscottl *fib_addr = cm->cm_fib; 1904114151Sscottl 1905114151Sscottl /* 1906114151Sscottl * Is this a fast response? If it is, update the fib fields in 1907114151Sscottl * local memory since the whole fib isn't DMA'd back up. 1908114151Sscottl */ 1909114151Sscottl if (fib_index & 0x01) { 1910114151Sscottl (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1911114151Sscottl *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1912114151Sscottl } 1913114151Sscottl break; 1914109088Sscottl } 1915114151Sscottl default: 1916114151Sscottl panic("Invalid queue in aac_dequeue_fib()"); 1917114151Sscottl break; 1918114151Sscottl } 1919114151Sscottl 192083114Sscottl /* update consumer index */ 192183114Sscottl sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 192265793Smsmith 192383114Sscottl /* if we have made the queue un-full, notify the adapter */ 192483114Sscottl if (notify && (aac_qinfo[queue].notify != 0)) 192583114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 192683114Sscottl error = 0; 192765793Smsmith 192865793Smsmithout: 192983114Sscottl return(error); 193065793Smsmith} 193165793Smsmith 193283114Sscottl/* 193382527Sscottl * Put our response to an Adapter Initialed Fib on the response queue 193482527Sscottl */ 193582527Sscottlstatic int 193682527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 193782527Sscottl{ 193883114Sscottl u_int32_t pi, ci; 1939111691Sscottl int error; 194083114Sscottl u_int32_t fib_size; 194183114Sscottl u_int32_t fib_addr; 194282527Sscottl 194383114Sscottl debug_called(1); 194482527Sscottl 194583114Sscottl /* Tell the adapter where the FIB is */ 194683114Sscottl fib_size = fib->Header.Size; 194783114Sscottl fib_addr = fib->Header.SenderFibAddress; 194883114Sscottl fib->Header.ReceiverFibAddress = fib_addr; 194982527Sscottl 195083114Sscottl /* get the producer/consumer indices */ 195183114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 195283114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 195382527Sscottl 195483114Sscottl /* wrap the queue? */ 195583114Sscottl if (pi >= aac_qinfo[queue].size) 195683114Sscottl pi = 0; 195782527Sscottl 195883114Sscottl /* check for queue full */ 195983114Sscottl if ((pi + 1) == ci) { 196083114Sscottl error = EBUSY; 196183114Sscottl goto out; 196283114Sscottl } 196382527Sscottl 196483114Sscottl /* populate queue entry */ 196583114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 196683114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 196782527Sscottl 196883114Sscottl /* update producer index */ 196983114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 197082527Sscottl 197183114Sscottl /* notify the adapter if we know how */ 197283114Sscottl if (aac_qinfo[queue].notify != 0) 197383114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 197482527Sscottl 197583114Sscottl error = 0; 197682527Sscottl 197782527Sscottlout: 197883114Sscottl return(error); 197982527Sscottl} 198082527Sscottl 198183114Sscottl/* 198270393Smsmith * Check for commands that have been outstanding for a suspiciously long time, 198370393Smsmith * and complain about them. 198470393Smsmith */ 198570393Smsmithstatic void 198670393Smsmithaac_timeout(struct aac_softc *sc) 198770393Smsmith{ 198883114Sscottl struct aac_command *cm; 198983114Sscottl time_t deadline; 199070393Smsmith 199183114Sscottl /* 1992110426Sscottl * Traverse the busy command list, bitch about late commands once 199383114Sscottl * only. 199483114Sscottl */ 199583114Sscottl deadline = time_second - AAC_CMD_TIMEOUT; 199683114Sscottl TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 199783114Sscottl if ((cm->cm_timestamp < deadline) 199883114Sscottl /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 199983114Sscottl cm->cm_flags |= AAC_CMD_TIMEDOUT; 200083114Sscottl device_printf(sc->aac_dev, 200183114Sscottl "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 200283114Sscottl cm, (int)(time_second-cm->cm_timestamp)); 200383114Sscottl AAC_PRINT_FIB(sc, cm->cm_fib); 200483114Sscottl } 200570393Smsmith } 200670393Smsmith 200783114Sscottl return; 200870393Smsmith} 200970393Smsmith 201083114Sscottl/* 201183114Sscottl * Interface Function Vectors 201283114Sscottl */ 201365793Smsmith 201483114Sscottl/* 201565793Smsmith * Read the current firmware status word. 201665793Smsmith */ 201765793Smsmithstatic int 201865793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc) 201965793Smsmith{ 202083114Sscottl debug_called(3); 202165793Smsmith 202283114Sscottl return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 202365793Smsmith} 202465793Smsmith 202565793Smsmithstatic int 202665793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc) 202765793Smsmith{ 202883114Sscottl debug_called(3); 202965793Smsmith 203083114Sscottl return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 203165793Smsmith} 203265793Smsmith 203387183Sscottlstatic int 203487183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc) 203587183Sscottl{ 203687183Sscottl int val; 203787183Sscottl 203887183Sscottl debug_called(3); 203987183Sscottl 204087183Sscottl val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 204187183Sscottl return (val); 204287183Sscottl} 204387183Sscottl 204483114Sscottl/* 204565793Smsmith * Notify the controller of a change in a given queue 204665793Smsmith */ 204765793Smsmith 204865793Smsmithstatic void 204965793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit) 205065793Smsmith{ 205183114Sscottl debug_called(3); 205265793Smsmith 205383114Sscottl AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 205465793Smsmith} 205565793Smsmith 205665793Smsmithstatic void 205765793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit) 205865793Smsmith{ 205983114Sscottl debug_called(3); 206065793Smsmith 206183114Sscottl AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 206265793Smsmith} 206365793Smsmith 206487183Sscottlstatic void 206587183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit) 206687183Sscottl{ 206787183Sscottl debug_called(3); 206887183Sscottl 206987183Sscottl AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 207087183Sscottl AAC_FA_HACK(sc); 207187183Sscottl} 207287183Sscottl 207383114Sscottl/* 207465793Smsmith * Get the interrupt reason bits 207565793Smsmith */ 207665793Smsmithstatic int 207765793Smsmithaac_sa_get_istatus(struct aac_softc *sc) 207865793Smsmith{ 207983114Sscottl debug_called(3); 208065793Smsmith 208183114Sscottl return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 208265793Smsmith} 208365793Smsmith 208465793Smsmithstatic int 208565793Smsmithaac_rx_get_istatus(struct aac_softc *sc) 208665793Smsmith{ 208783114Sscottl debug_called(3); 208865793Smsmith 208983114Sscottl return(AAC_GETREG4(sc, AAC_RX_ODBR)); 209065793Smsmith} 209165793Smsmith 209287183Sscottlstatic int 209387183Sscottlaac_fa_get_istatus(struct aac_softc *sc) 209487183Sscottl{ 209587183Sscottl int val; 209687183Sscottl 209787183Sscottl debug_called(3); 209887183Sscottl 209987183Sscottl val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 210087183Sscottl return (val); 210187183Sscottl} 210287183Sscottl 210383114Sscottl/* 210465793Smsmith * Clear some interrupt reason bits 210565793Smsmith */ 210665793Smsmithstatic void 210765793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask) 210865793Smsmith{ 210983114Sscottl debug_called(3); 211065793Smsmith 211183114Sscottl AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 211265793Smsmith} 211365793Smsmith 211465793Smsmithstatic void 211565793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask) 211665793Smsmith{ 211783114Sscottl debug_called(3); 211865793Smsmith 211983114Sscottl AAC_SETREG4(sc, AAC_RX_ODBR, mask); 212065793Smsmith} 212165793Smsmith 212287183Sscottlstatic void 212387183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask) 212487183Sscottl{ 212587183Sscottl debug_called(3); 212687183Sscottl 212787183Sscottl AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 212887183Sscottl AAC_FA_HACK(sc); 212987183Sscottl} 213087183Sscottl 213183114Sscottl/* 213265793Smsmith * Populate the mailbox and set the command word 213365793Smsmith */ 213465793Smsmithstatic void 213565793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 213665793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 213765793Smsmith{ 213883114Sscottl debug_called(4); 213965793Smsmith 214083114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 214183114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 214283114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 214383114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 214483114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 214565793Smsmith} 214665793Smsmith 214765793Smsmithstatic void 214865793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 214965793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 215065793Smsmith{ 215183114Sscottl debug_called(4); 215265793Smsmith 215383114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 215483114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 215583114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 215683114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 215783114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 215865793Smsmith} 215965793Smsmith 216087183Sscottlstatic void 216187183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 216287183Sscottl u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 216387183Sscottl{ 216487183Sscottl debug_called(4); 216587183Sscottl 216687183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 216787183Sscottl AAC_FA_HACK(sc); 216887183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 216987183Sscottl AAC_FA_HACK(sc); 217087183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 217187183Sscottl AAC_FA_HACK(sc); 217287183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 217387183Sscottl AAC_FA_HACK(sc); 217487183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 217587183Sscottl AAC_FA_HACK(sc); 217687183Sscottl} 217787183Sscottl 217883114Sscottl/* 217965793Smsmith * Fetch the immediate command status word 218065793Smsmith */ 218165793Smsmithstatic int 2182112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb) 218365793Smsmith{ 218483114Sscottl debug_called(4); 218565793Smsmith 2186112679Sscottl return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 218765793Smsmith} 218865793Smsmith 218965793Smsmithstatic int 2190112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb) 219165793Smsmith{ 219283114Sscottl debug_called(4); 219365793Smsmith 2194112679Sscottl return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 219565793Smsmith} 219665793Smsmith 219787183Sscottlstatic int 2198112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb) 219987183Sscottl{ 220087183Sscottl int val; 220187183Sscottl 220287183Sscottl debug_called(4); 220387183Sscottl 2204112679Sscottl val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 220587183Sscottl return (val); 220687183Sscottl} 220787183Sscottl 220883114Sscottl/* 220965793Smsmith * Set/clear interrupt masks 221065793Smsmith */ 221165793Smsmithstatic void 221265793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable) 221365793Smsmith{ 221483114Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 221565793Smsmith 221683114Sscottl if (enable) { 221783114Sscottl AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 221883114Sscottl } else { 221983114Sscottl AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 222083114Sscottl } 222165793Smsmith} 222265793Smsmith 222365793Smsmithstatic void 222465793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable) 222565793Smsmith{ 222683114Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 222765793Smsmith 222883114Sscottl if (enable) { 222983114Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 223083114Sscottl } else { 223183114Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 223283114Sscottl } 223365793Smsmith} 223465793Smsmith 223587183Sscottlstatic void 223687183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable) 223787183Sscottl{ 223887183Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 223987183Sscottl 224087183Sscottl if (enable) { 224187183Sscottl AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 224287183Sscottl AAC_FA_HACK(sc); 224387183Sscottl } else { 224487183Sscottl AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 224587183Sscottl AAC_FA_HACK(sc); 224687183Sscottl } 224787183Sscottl} 224887183Sscottl 224983114Sscottl/* 225083114Sscottl * Debugging and Diagnostics 225183114Sscottl */ 225265793Smsmith 225383114Sscottl/* 225465793Smsmith * Print some information about the controller. 225565793Smsmith */ 225665793Smsmithstatic void 225765793Smsmithaac_describe_controller(struct aac_softc *sc) 225865793Smsmith{ 225995350Sscottl struct aac_fib *fib; 226083114Sscottl struct aac_adapter_info *info; 226165793Smsmith 226283114Sscottl debug_called(2); 226365793Smsmith 226495536Sscottl aac_alloc_sync_fib(sc, &fib, 0); 226595350Sscottl 226695350Sscottl fib->data[0] = 0; 226795350Sscottl if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 226883114Sscottl device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 226995536Sscottl aac_release_sync_fib(sc); 227083114Sscottl return; 227183114Sscottl } 2272112679Sscottl info = (struct aac_adapter_info *)&fib->data[0]; 227365793Smsmith 227483114Sscottl device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 227583114Sscottl aac_describe_code(aac_cpu_variant, info->CpuVariant), 227683114Sscottl info->ClockSpeed, info->BufferMem / (1024 * 1024), 227783114Sscottl aac_describe_code(aac_battery_platform, 227883114Sscottl info->batteryPlatform)); 227965793Smsmith 228083114Sscottl /* save the kernel revision structure for later use */ 228183114Sscottl sc->aac_revision = info->KernelRevision; 228283114Sscottl device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 228383114Sscottl info->KernelRevision.external.comp.major, 228483114Sscottl info->KernelRevision.external.comp.minor, 228583114Sscottl info->KernelRevision.external.comp.dash, 228683114Sscottl info->KernelRevision.buildNumber, 228783114Sscottl (u_int32_t)(info->SerialNumber & 0xffffff)); 228895536Sscottl 228995536Sscottl aac_release_sync_fib(sc); 2290112679Sscottl 2291112679Sscottl if (1 || bootverbose) { 2292112679Sscottl device_printf(sc->aac_dev, "Supported Options=%b\n", 2293112679Sscottl sc->supported_options, 2294112679Sscottl "\20" 2295112679Sscottl "\1SNAPSHOT" 2296112679Sscottl "\2CLUSTERS" 2297112679Sscottl "\3WCACHE" 2298112679Sscottl "\4DATA64" 2299112679Sscottl "\5HOSTTIME" 2300112679Sscottl "\6RAID50" 2301112679Sscottl "\7WINDOW4GB" 2302112679Sscottl "\10SCSIUPGD" 2303112679Sscottl "\11SOFTERR" 2304112679Sscottl "\12NORECOND" 2305112679Sscottl "\13SGMAP64" 2306112679Sscottl "\14ALARM" 2307112679Sscottl "\15NONDASD"); 2308112679Sscottl } 230965793Smsmith} 231065793Smsmith 231183114Sscottl/* 231265793Smsmith * Look up a text description of a numeric error code and return a pointer to 231365793Smsmith * same. 231465793Smsmith */ 231565793Smsmithstatic char * 231665793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code) 231765793Smsmith{ 231883114Sscottl int i; 231965793Smsmith 232083114Sscottl for (i = 0; table[i].string != NULL; i++) 232183114Sscottl if (table[i].code == code) 232283114Sscottl return(table[i].string); 232383114Sscottl return(table[i + 1].string); 232465793Smsmith} 232565793Smsmith 232683114Sscottl/* 232783114Sscottl * Management Interface 232883114Sscottl */ 232965793Smsmith 233065793Smsmithstatic int 233187310Sscottlaac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 233265793Smsmith{ 233383114Sscottl struct aac_softc *sc; 233465793Smsmith 233583114Sscottl debug_called(2); 233665793Smsmith 233783114Sscottl sc = dev->si_drv1; 233865793Smsmith 233983114Sscottl /* Check to make sure the device isn't already open */ 234083114Sscottl if (sc->aac_state & AAC_STATE_OPEN) { 234183114Sscottl return EBUSY; 234283114Sscottl } 234383114Sscottl sc->aac_state |= AAC_STATE_OPEN; 234483114Sscottl 234583114Sscottl return 0; 234665793Smsmith} 234765793Smsmith 234865793Smsmithstatic int 234987310Sscottlaac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 235065793Smsmith{ 235183114Sscottl struct aac_softc *sc; 235265793Smsmith 235383114Sscottl debug_called(2); 235465793Smsmith 235583114Sscottl sc = dev->si_drv1; 235665793Smsmith 235783114Sscottl /* Mark this unit as no longer open */ 235883114Sscottl sc->aac_state &= ~AAC_STATE_OPEN; 235983114Sscottl 236083114Sscottl return 0; 236165793Smsmith} 236265793Smsmith 236365793Smsmithstatic int 236487310Sscottlaac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 236565793Smsmith{ 236683114Sscottl union aac_statrequest *as; 236783114Sscottl struct aac_softc *sc; 236883114Sscottl int error = 0; 236983114Sscottl int i; 237065793Smsmith 237183114Sscottl debug_called(2); 237265793Smsmith 237383114Sscottl as = (union aac_statrequest *)arg; 237483114Sscottl sc = dev->si_drv1; 237583114Sscottl 237683114Sscottl switch (cmd) { 237783114Sscottl case AACIO_STATS: 237883114Sscottl switch (as->as_item) { 237983114Sscottl case AACQ_FREE: 238083114Sscottl case AACQ_BIO: 238183114Sscottl case AACQ_READY: 238283114Sscottl case AACQ_BUSY: 238383114Sscottl case AACQ_COMPLETE: 238483114Sscottl bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 238583114Sscottl sizeof(struct aac_qstat)); 238683114Sscottl break; 238783114Sscottl default: 238883114Sscottl error = ENOENT; 238983114Sscottl break; 239083114Sscottl } 239183114Sscottl break; 239283114Sscottl 239383114Sscottl case FSACTL_SENDFIB: 239483114Sscottl arg = *(caddr_t*)arg; 239583114Sscottl case FSACTL_LNX_SENDFIB: 239683114Sscottl debug(1, "FSACTL_SENDFIB"); 239783114Sscottl error = aac_ioctl_sendfib(sc, arg); 239883114Sscottl break; 239983114Sscottl case FSACTL_AIF_THREAD: 240083114Sscottl case FSACTL_LNX_AIF_THREAD: 240183114Sscottl debug(1, "FSACTL_AIF_THREAD"); 240283114Sscottl error = EINVAL; 240383114Sscottl break; 240483114Sscottl case FSACTL_OPEN_GET_ADAPTER_FIB: 240583114Sscottl arg = *(caddr_t*)arg; 240687183Sscottl case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 240783114Sscottl debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 240883114Sscottl /* 240983114Sscottl * Pass the caller out an AdapterFibContext. 241083114Sscottl * 241183114Sscottl * Note that because we only support one opener, we 241283114Sscottl * basically ignore this. Set the caller's context to a magic 241383114Sscottl * number just in case. 241483114Sscottl * 241583114Sscottl * The Linux code hands the driver a pointer into kernel space, 241683114Sscottl * and then trusts it when the caller hands it back. Aiee! 241783114Sscottl * Here, we give it the proc pointer of the per-adapter aif 241883114Sscottl * thread. It's only used as a sanity check in other calls. 241983114Sscottl */ 242083114Sscottl i = (int)sc->aifthread; 242183114Sscottl error = copyout(&i, arg, sizeof(i)); 242283114Sscottl break; 242383114Sscottl case FSACTL_GET_NEXT_ADAPTER_FIB: 242483114Sscottl arg = *(caddr_t*)arg; 242583114Sscottl case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 242683114Sscottl debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 242783114Sscottl error = aac_getnext_aif(sc, arg); 242883114Sscottl break; 242983114Sscottl case FSACTL_CLOSE_GET_ADAPTER_FIB: 243083114Sscottl case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 243183114Sscottl debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 243283114Sscottl /* don't do anything here */ 243383114Sscottl break; 243483114Sscottl case FSACTL_MINIPORT_REV_CHECK: 243583114Sscottl arg = *(caddr_t*)arg; 243683114Sscottl case FSACTL_LNX_MINIPORT_REV_CHECK: 243783114Sscottl debug(1, "FSACTL_MINIPORT_REV_CHECK"); 243883114Sscottl error = aac_rev_check(sc, arg); 243983114Sscottl break; 244083114Sscottl case FSACTL_QUERY_DISK: 244183114Sscottl arg = *(caddr_t*)arg; 244283114Sscottl case FSACTL_LNX_QUERY_DISK: 244383114Sscottl debug(1, "FSACTL_QUERY_DISK"); 244483114Sscottl error = aac_query_disk(sc, arg); 244583114Sscottl break; 244683114Sscottl case FSACTL_DELETE_DISK: 244783114Sscottl case FSACTL_LNX_DELETE_DISK: 244883114Sscottl /* 244983114Sscottl * We don't trust the underland to tell us when to delete a 245083114Sscottl * container, rather we rely on an AIF coming from the 245183114Sscottl * controller 245283114Sscottl */ 245383114Sscottl error = 0; 245483114Sscottl break; 245570393Smsmith default: 245687183Sscottl debug(1, "unsupported cmd 0x%lx\n", cmd); 245783114Sscottl error = EINVAL; 245883114Sscottl break; 245970393Smsmith } 246083114Sscottl return(error); 246165793Smsmith} 246265793Smsmith 246387183Sscottlstatic int 246487310Sscottlaac_poll(dev_t dev, int poll_events, d_thread_t *td) 246587183Sscottl{ 246687183Sscottl struct aac_softc *sc; 246787183Sscottl int revents; 246887183Sscottl 246987183Sscottl sc = dev->si_drv1; 247087183Sscottl revents = 0; 247187183Sscottl 247287310Sscottl AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 247387183Sscottl if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 247487183Sscottl if (sc->aac_aifq_tail != sc->aac_aifq_head) 247587183Sscottl revents |= poll_events & (POLLIN | POLLRDNORM); 247687183Sscottl } 247787183Sscottl AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 247887183Sscottl 247987183Sscottl if (revents == 0) { 248087183Sscottl if (poll_events & (POLLIN | POLLRDNORM)) 248187183Sscottl selrecord(td, &sc->rcv_select); 248287183Sscottl } 248387183Sscottl 248487183Sscottl return (revents); 248587183Sscottl} 248687183Sscottl 248783114Sscottl/* 248865793Smsmith * Send a FIB supplied from userspace 248965793Smsmith */ 249065793Smsmithstatic int 249165793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 249265793Smsmith{ 249383114Sscottl struct aac_command *cm; 249483114Sscottl int size, error; 249565793Smsmith 249683114Sscottl debug_called(2); 249765793Smsmith 249883114Sscottl cm = NULL; 249965793Smsmith 250083114Sscottl /* 250183114Sscottl * Get a command 250283114Sscottl */ 2503111532Sscottl AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 250483114Sscottl if (aac_alloc_command(sc, &cm)) { 250583114Sscottl error = EBUSY; 250683114Sscottl goto out; 250783114Sscottl } 250865793Smsmith 250983114Sscottl /* 251083114Sscottl * Fetch the FIB header, then re-copy to get data as well. 251183114Sscottl */ 251283114Sscottl if ((error = copyin(ufib, cm->cm_fib, 251383114Sscottl sizeof(struct aac_fib_header))) != 0) 251483114Sscottl goto out; 251583114Sscottl size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 251683114Sscottl if (size > sizeof(struct aac_fib)) { 251783114Sscottl device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 251883114Sscottl size, sizeof(struct aac_fib)); 251983114Sscottl size = sizeof(struct aac_fib); 252083114Sscottl } 252183114Sscottl if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 252283114Sscottl goto out; 252383114Sscottl cm->cm_fib->Header.Size = size; 252483114Sscottl cm->cm_timestamp = time_second; 252565793Smsmith 252683114Sscottl /* 252783114Sscottl * Pass the FIB to the controller, wait for it to complete. 252883114Sscottl */ 252987183Sscottl if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 2530110426Sscottl device_printf(sc->aac_dev, 2531110426Sscottl "aac_wait_command return %d\n", error); 253283114Sscottl goto out; 253387183Sscottl } 253465793Smsmith 253583114Sscottl /* 253683114Sscottl * Copy the FIB and data back out to the caller. 253783114Sscottl */ 253883114Sscottl size = cm->cm_fib->Header.Size; 253983114Sscottl if (size > sizeof(struct aac_fib)) { 254083114Sscottl device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 254183114Sscottl size, sizeof(struct aac_fib)); 254283114Sscottl size = sizeof(struct aac_fib); 254383114Sscottl } 254483114Sscottl error = copyout(cm->cm_fib, ufib, size); 254565793Smsmith 254665793Smsmithout: 254783114Sscottl if (cm != NULL) { 254883114Sscottl aac_release_command(cm); 254983114Sscottl } 2550111532Sscottl 2551111532Sscottl AAC_LOCK_RELEASE(&sc->aac_io_lock); 255283114Sscottl return(error); 255365793Smsmith} 255465793Smsmith 255583114Sscottl/* 255665793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference. 255782527Sscottl * If the queue fills up, then drop the older entries. 255865793Smsmith */ 255965793Smsmithstatic void 256082527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 256165793Smsmith{ 256283114Sscottl struct aac_aif_command *aif; 256383114Sscottl struct aac_container *co, *co_next; 256495350Sscottl struct aac_mntinfo *mi; 256595350Sscottl struct aac_mntinforesp *mir = NULL; 256683114Sscottl u_int16_t rsize; 256787183Sscottl int next, found; 256883114Sscottl int added = 0, i = 0; 256965793Smsmith 257083114Sscottl debug_called(2); 257165793Smsmith 257283114Sscottl aif = (struct aac_aif_command*)&fib->data[0]; 257383114Sscottl aac_print_aif(sc, aif); 257482527Sscottl 257583114Sscottl /* Is it an event that we should care about? */ 257683114Sscottl switch (aif->command) { 257783114Sscottl case AifCmdEventNotify: 257883114Sscottl switch (aif->data.EN.type) { 257983114Sscottl case AifEnAddContainer: 258083114Sscottl case AifEnDeleteContainer: 258183114Sscottl /* 258283114Sscottl * A container was added or deleted, but the message 258383114Sscottl * doesn't tell us anything else! Re-enumerate the 258483114Sscottl * containers and sort things out. 258583114Sscottl */ 258695536Sscottl aac_alloc_sync_fib(sc, &fib, 0); 258795350Sscottl mi = (struct aac_mntinfo *)&fib->data[0]; 258883114Sscottl do { 258983114Sscottl /* 259083114Sscottl * Ask the controller for its containers one at 259183114Sscottl * a time. 259283114Sscottl * XXX What if the controller's list changes 259383114Sscottl * midway through this enumaration? 259483114Sscottl * XXX This should be done async. 259583114Sscottl */ 259695966Sscottl bzero(mi, sizeof(struct aac_mntinfo)); 259795966Sscottl mi->Command = VM_NameServe; 259895966Sscottl mi->MntType = FT_FILESYS; 259995350Sscottl mi->MntCount = i; 260083114Sscottl rsize = sizeof(mir); 260195350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 260295350Sscottl sizeof(struct aac_mntinfo))) { 260383114Sscottl debug(2, "Error probing container %d\n", 260483114Sscottl i); 260583114Sscottl continue; 260683114Sscottl } 260795350Sscottl mir = (struct aac_mntinforesp *)&fib->data[0]; 260883114Sscottl /* 260983114Sscottl * Check the container against our list. 261083114Sscottl * co->co_found was already set to 0 in a 261183114Sscottl * previous run. 261283114Sscottl */ 261395350Sscottl if ((mir->Status == ST_OK) && 261495350Sscottl (mir->MntTable[0].VolType != CT_NONE)) { 261583114Sscottl found = 0; 261683114Sscottl TAILQ_FOREACH(co, 261783114Sscottl &sc->aac_container_tqh, 261883114Sscottl co_link) { 261983114Sscottl if (co->co_mntobj.ObjectId == 262095350Sscottl mir->MntTable[0].ObjectId) { 262183114Sscottl co->co_found = 1; 262283114Sscottl found = 1; 262383114Sscottl break; 262483114Sscottl } 262583114Sscottl } 262683114Sscottl /* 262783114Sscottl * If the container matched, continue 262883114Sscottl * in the list. 262983114Sscottl */ 263083114Sscottl if (found) { 263183114Sscottl i++; 263283114Sscottl continue; 263383114Sscottl } 263483114Sscottl 263583114Sscottl /* 263683114Sscottl * This is a new container. Do all the 2637110426Sscottl * appropriate things to set it up. 2638110426Sscottl */ 263995350Sscottl aac_add_container(sc, mir, 1); 264083114Sscottl added = 1; 264183114Sscottl } 264283114Sscottl i++; 264395350Sscottl } while ((i < mir->MntRespCount) && 264483114Sscottl (i < AAC_MAX_CONTAINERS)); 264595350Sscottl aac_release_sync_fib(sc); 264683114Sscottl 264783114Sscottl /* 264883114Sscottl * Go through our list of containers and see which ones 264983114Sscottl * were not marked 'found'. Since the controller didn't 265083114Sscottl * list them they must have been deleted. Do the 265183114Sscottl * appropriate steps to destroy the device. Also reset 265283114Sscottl * the co->co_found field. 265383114Sscottl */ 265483114Sscottl co = TAILQ_FIRST(&sc->aac_container_tqh); 265583114Sscottl while (co != NULL) { 265683114Sscottl if (co->co_found == 0) { 265783114Sscottl device_delete_child(sc->aac_dev, 265883114Sscottl co->co_disk); 265983114Sscottl co_next = TAILQ_NEXT(co, co_link); 266087310Sscottl AAC_LOCK_ACQUIRE(&sc-> 266183114Sscottl aac_container_lock); 266283114Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, 266383114Sscottl co_link); 266483114Sscottl AAC_LOCK_RELEASE(&sc-> 266583114Sscottl aac_container_lock); 266683114Sscottl FREE(co, M_AACBUF); 266783114Sscottl co = co_next; 266883114Sscottl } else { 266983114Sscottl co->co_found = 0; 267083114Sscottl co = TAILQ_NEXT(co, co_link); 267183114Sscottl } 267282527Sscottl } 267382527Sscottl 267483114Sscottl /* Attach the newly created containers */ 267583114Sscottl if (added) 267683114Sscottl bus_generic_attach(sc->aac_dev); 267783114Sscottl 2678105528Sphk break; 267982527Sscottl 268083114Sscottl default: 268183114Sscottl break; 268282527Sscottl } 268382527Sscottl 268482527Sscottl default: 268583114Sscottl break; 268682527Sscottl } 268782527Sscottl 268883114Sscottl /* Copy the AIF data to the AIF queue for ioctl retrieval */ 268987310Sscottl AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 269083114Sscottl next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 269183114Sscottl if (next != sc->aac_aifq_tail) { 269283114Sscottl bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 269387183Sscottl sc->aac_aifq_head = next; 269487183Sscottl 269587183Sscottl /* On the off chance that someone is sleeping for an aif... */ 269687183Sscottl if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 269787183Sscottl wakeup(sc->aac_aifq); 269887183Sscottl /* Wakeup any poll()ers */ 269987183Sscottl selwakeup(&sc->rcv_select); 270083114Sscottl } 270187183Sscottl AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 270282527Sscottl 270383114Sscottl return; 270465793Smsmith} 270565793Smsmith 270683114Sscottl/* 270770393Smsmith * Return the Revision of the driver to userspace and check to see if the 270882527Sscottl * userspace app is possibly compatible. This is extremely bogus since 270982527Sscottl * our driver doesn't follow Adaptec's versioning system. Cheat by just 271082527Sscottl * returning what the card reported. 271165793Smsmith */ 271265793Smsmithstatic int 271381189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata) 271465793Smsmith{ 271583114Sscottl struct aac_rev_check rev_check; 271683114Sscottl struct aac_rev_check_resp rev_check_resp; 271783114Sscottl int error = 0; 271865793Smsmith 271983114Sscottl debug_called(2); 272065793Smsmith 272183114Sscottl /* 272283114Sscottl * Copyin the revision struct from userspace 272383114Sscottl */ 272483114Sscottl if ((error = copyin(udata, (caddr_t)&rev_check, 272581082Sscottl sizeof(struct aac_rev_check))) != 0) { 272683114Sscottl return error; 272783114Sscottl } 272865793Smsmith 272983114Sscottl debug(2, "Userland revision= %d\n", 273083114Sscottl rev_check.callingRevision.buildNumber); 273165793Smsmith 273283114Sscottl /* 273383114Sscottl * Doctor up the response struct. 273483114Sscottl */ 273583114Sscottl rev_check_resp.possiblyCompatible = 1; 273683114Sscottl rev_check_resp.adapterSWRevision.external.ul = 273783114Sscottl sc->aac_revision.external.ul; 273883114Sscottl rev_check_resp.adapterSWRevision.buildNumber = 273983114Sscottl sc->aac_revision.buildNumber; 274065793Smsmith 274183114Sscottl return(copyout((caddr_t)&rev_check_resp, udata, 274283114Sscottl sizeof(struct aac_rev_check_resp))); 274365793Smsmith} 274465793Smsmith 274583114Sscottl/* 274665793Smsmith * Pass the caller the next AIF in their queue 274765793Smsmith */ 274865793Smsmithstatic int 274981189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 275065793Smsmith{ 275183114Sscottl struct get_adapter_fib_ioctl agf; 2752111691Sscottl int error; 275365793Smsmith 275483114Sscottl debug_called(2); 275565793Smsmith 275683114Sscottl if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 275765793Smsmith 275883114Sscottl /* 275983114Sscottl * Check the magic number that we gave the caller. 276083114Sscottl */ 276183114Sscottl if (agf.AdapterFibContext != (int)sc->aifthread) { 276283114Sscottl error = EFAULT; 276383114Sscottl } else { 276481189Sscottl error = aac_return_aif(sc, agf.AifFib); 276583114Sscottl if ((error == EAGAIN) && (agf.Wait)) { 276683114Sscottl sc->aac_state |= AAC_STATE_AIF_SLEEPER; 276783114Sscottl while (error == EAGAIN) { 276883114Sscottl error = tsleep(sc->aac_aifq, PRIBIO | 276983114Sscottl PCATCH, "aacaif", 0); 277083114Sscottl if (error == 0) 277183114Sscottl error = aac_return_aif(sc, 277283114Sscottl agf.AifFib); 277383114Sscottl } 277483114Sscottl sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 277583114Sscottl } 277665793Smsmith } 277765793Smsmith } 277883114Sscottl return(error); 277965793Smsmith} 278065793Smsmith 278183114Sscottl/* 278270393Smsmith * Hand the next AIF off the top of the queue out to userspace. 278370393Smsmith */ 278470393Smsmithstatic int 278581189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr) 278670393Smsmith{ 278787183Sscottl int error; 278870393Smsmith 278983114Sscottl debug_called(2); 279070393Smsmith 279187310Sscottl AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 279283114Sscottl if (sc->aac_aifq_tail == sc->aac_aifq_head) { 279383114Sscottl error = EAGAIN; 279483114Sscottl } else { 279583114Sscottl error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, 279683114Sscottl sizeof(struct aac_aif_command)); 279783114Sscottl if (error) 2798110426Sscottl device_printf(sc->aac_dev, 2799110426Sscottl "aac_return_aif: copyout returned %d\n", error); 280083114Sscottl if (!error) 280183114Sscottl sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % 280283114Sscottl AAC_AIFQ_LENGTH; 280383114Sscottl } 280487183Sscottl AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 280583114Sscottl return(error); 280670393Smsmith} 280782527Sscottl 280883114Sscottl/* 280982527Sscottl * Give the userland some information about the container. The AAC arch 281082527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects 281182527Sscottl * the containers to have b:t:l numbers. Fake it. 281282527Sscottl */ 281382527Sscottlstatic int 281482527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr) 281582527Sscottl{ 281683114Sscottl struct aac_query_disk query_disk; 281783114Sscottl struct aac_container *co; 281883114Sscottl struct aac_disk *disk; 281983114Sscottl int error, id; 282082527Sscottl 282183114Sscottl debug_called(2); 282282527Sscottl 282383114Sscottl disk = NULL; 282482527Sscottl 282583114Sscottl error = copyin(uptr, (caddr_t)&query_disk, 282683114Sscottl sizeof(struct aac_query_disk)); 282783114Sscottl if (error) 282883114Sscottl return (error); 282982527Sscottl 283083114Sscottl id = query_disk.ContainerNumber; 283183114Sscottl if (id == -1) 283283114Sscottl return (EINVAL); 283382527Sscottl 283487310Sscottl AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 283583114Sscottl TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 283683114Sscottl if (co->co_mntobj.ObjectId == id) 283783114Sscottl break; 283883114Sscottl } 283982527Sscottl 2840105528Sphk if (co == NULL) { 284183114Sscottl query_disk.Valid = 0; 284283114Sscottl query_disk.Locked = 0; 284383114Sscottl query_disk.Deleted = 1; /* XXX is this right? */ 2844105528Sphk } else { 2845105528Sphk disk = device_get_softc(co->co_disk); 2846105528Sphk query_disk.Valid = 1; 2847105528Sphk query_disk.Locked = 2848105528Sphk (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 2849105528Sphk query_disk.Deleted = 0; 2850105528Sphk query_disk.Bus = device_get_unit(sc->aac_dev); 2851105528Sphk query_disk.Target = disk->unit; 2852105528Sphk query_disk.Lun = 0; 2853105528Sphk query_disk.UnMapped = 0; 2854111525Sscottl sprintf(&query_disk.diskDeviceName[0], "%s%d", 2855111525Sscottl disk->ad_disk.d_name, disk->ad_disk.d_unit); 2856105528Sphk } 285783114Sscottl AAC_LOCK_RELEASE(&sc->aac_container_lock); 285882527Sscottl 285983114Sscottl error = copyout((caddr_t)&query_disk, uptr, 286083114Sscottl sizeof(struct aac_query_disk)); 286183114Sscottl 286283114Sscottl return (error); 286382527Sscottl} 286482527Sscottl 286595536Sscottlstatic void 286695536Sscottlaac_get_bus_info(struct aac_softc *sc) 286795536Sscottl{ 286895536Sscottl struct aac_fib *fib; 286995536Sscottl struct aac_ctcfg *c_cmd; 287095536Sscottl struct aac_ctcfg_resp *c_resp; 287195536Sscottl struct aac_vmioctl *vmi; 287295536Sscottl struct aac_vmi_businf_resp *vmi_resp; 287395536Sscottl struct aac_getbusinf businfo; 2874110426Sscottl struct aac_sim *caminf; 287595536Sscottl device_t child; 287695536Sscottl int i, found, error; 287795536Sscottl 287895536Sscottl aac_alloc_sync_fib(sc, &fib, 0); 287995536Sscottl c_cmd = (struct aac_ctcfg *)&fib->data[0]; 288095966Sscottl bzero(c_cmd, sizeof(struct aac_ctcfg)); 288195536Sscottl 288295536Sscottl c_cmd->Command = VM_ContainerConfig; 288395536Sscottl c_cmd->cmd = CT_GET_SCSI_METHOD; 288495536Sscottl c_cmd->param = 0; 288595536Sscottl 288695536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 288795536Sscottl sizeof(struct aac_ctcfg)); 288895536Sscottl if (error) { 288995536Sscottl device_printf(sc->aac_dev, "Error %d sending " 289095536Sscottl "VM_ContainerConfig command\n", error); 289195536Sscottl aac_release_sync_fib(sc); 289295536Sscottl return; 289395536Sscottl } 289495536Sscottl 289595536Sscottl c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 289695536Sscottl if (c_resp->Status != ST_OK) { 289795536Sscottl device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 289895536Sscottl c_resp->Status); 289995536Sscottl aac_release_sync_fib(sc); 290095536Sscottl return; 290195536Sscottl } 290295536Sscottl 290395536Sscottl sc->scsi_method_id = c_resp->param; 290495536Sscottl 290595536Sscottl vmi = (struct aac_vmioctl *)&fib->data[0]; 290695966Sscottl bzero(vmi, sizeof(struct aac_vmioctl)); 290795966Sscottl 290895536Sscottl vmi->Command = VM_Ioctl; 290995536Sscottl vmi->ObjType = FT_DRIVE; 291095536Sscottl vmi->MethId = sc->scsi_method_id; 291195536Sscottl vmi->ObjId = 0; 291295536Sscottl vmi->IoctlCmd = GetBusInfo; 291395536Sscottl 291495536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 291595536Sscottl sizeof(struct aac_vmioctl)); 291695536Sscottl if (error) { 291795536Sscottl device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 291895536Sscottl error); 291995536Sscottl aac_release_sync_fib(sc); 292095536Sscottl return; 292195536Sscottl } 292295536Sscottl 292395536Sscottl vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 292495536Sscottl if (vmi_resp->Status != ST_OK) { 292595536Sscottl device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 292695536Sscottl vmi_resp->Status); 292795536Sscottl aac_release_sync_fib(sc); 292895536Sscottl return; 292995536Sscottl } 293095536Sscottl 293195536Sscottl bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 293295536Sscottl aac_release_sync_fib(sc); 293395536Sscottl 293495536Sscottl found = 0; 293595536Sscottl for (i = 0; i < businfo.BusCount; i++) { 293695536Sscottl if (businfo.BusValid[i] != AAC_BUS_VALID) 293795536Sscottl continue; 293895536Sscottl 2939110428Sscottl caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2940110428Sscottl M_AACBUF, M_NOWAIT | M_ZERO); 294195536Sscottl if (caminf == NULL) 294295536Sscottl continue; 294395536Sscottl 294495536Sscottl child = device_add_child(sc->aac_dev, "aacp", -1); 294595536Sscottl if (child == NULL) { 294695536Sscottl device_printf(sc->aac_dev, "device_add_child failed\n"); 294795536Sscottl continue; 294895536Sscottl } 294995536Sscottl 295095536Sscottl caminf->TargetsPerBus = businfo.TargetsPerBus; 295195536Sscottl caminf->BusNumber = i; 295295536Sscottl caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 295395536Sscottl caminf->aac_sc = sc; 2954110432Sscottl caminf->sim_dev = child; 295595536Sscottl 295695536Sscottl device_set_ivars(child, caminf); 295795536Sscottl device_set_desc(child, "SCSI Passthrough Bus"); 2958110426Sscottl TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 295995536Sscottl 296095536Sscottl found = 1; 296195536Sscottl } 296295536Sscottl 296395536Sscottl if (found) 296495536Sscottl bus_generic_attach(sc->aac_dev); 296595536Sscottl 296695536Sscottl return; 296795536Sscottl} 2968