aac.c revision 126080
1135446Strhodes/*- 2234010Sdougb * Copyright (c) 2000 Michael Smith 3135446Strhodes * Copyright (c) 2001 Scott Long 4135446Strhodes * Copyright (c) 2000 BSDi 5174187Sdougb * Copyright (c) 2001 Adaptec, Inc. 6135446Strhodes * All rights reserved. 7135446Strhodes * 8135446Strhodes * Redistribution and use in source and binary forms, with or without 9135446Strhodes * modification, are permitted provided that the following conditions 10135446Strhodes * are met: 11135446Strhodes * 1. Redistributions of source code must retain the above copyright 12135446Strhodes * notice, this list of conditions and the following disclaimer. 13135446Strhodes * 2. Redistributions in binary form must reproduce the above copyright 14135446Strhodes * notice, this list of conditions and the following disclaimer in the 15135446Strhodes * documentation and/or other materials provided with the distribution. 16135446Strhodes * 17135446Strhodes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18234010Sdougb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19135446Strhodes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20170222Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21170222Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22135446Strhodes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23135446Strhodes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24135446Strhodes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25186462Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26224092Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27224092Sdougb * SUCH DAMAGE. 28224092Sdougb */ 29224092Sdougb 30135446Strhodes#include <sys/cdefs.h> 31135446Strhodes__FBSDID("$FreeBSD: head/sys/dev/aac/aac.c 126080 2004-02-21 21:10:55Z phk $"); 32135446Strhodes 33135446Strhodes/* 34135446Strhodes * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 35135446Strhodes */ 36135446Strhodes 37193149Sdougb#include "opt_aac.h" 38135446Strhodes 39135446Strhodes/* #include <stddef.h> */ 40186462Sdougb#include <sys/param.h> 41135446Strhodes#include <sys/systm.h> 42135446Strhodes#include <sys/malloc.h> 43224092Sdougb#include <sys/kernel.h> 44186462Sdougb#include <sys/kthread.h> 45224092Sdougb#include <sys/sysctl.h> 46193149Sdougb#include <sys/poll.h> 47135446Strhodes#include <sys/ioccom.h> 48135446Strhodes 49135446Strhodes#include <sys/bus.h> 50135446Strhodes#include <sys/conf.h> 51135446Strhodes#include <sys/signalvar.h> 52193149Sdougb#include <sys/time.h> 53135446Strhodes#include <sys/eventhandler.h> 54135446Strhodes 55135446Strhodes#include <machine/bus_memio.h> 56135446Strhodes#include <machine/bus.h> 57135446Strhodes#include <machine/resource.h> 58170222Sdougb 59135446Strhodes#include <dev/aac/aacreg.h> 60135446Strhodes#include <dev/aac/aac_ioctl.h> 61135446Strhodes#include <dev/aac/aacvar.h> 62135446Strhodes#include <dev/aac/aac_tables.h> 63170222Sdougb 64224092Sdougbstatic void aac_startup(void *arg); 65135446Strhodesstatic void aac_add_container(struct aac_softc *sc, 66135446Strhodes struct aac_mntinforesp *mir, int f); 67135446Strhodesstatic void aac_get_bus_info(struct aac_softc *sc); 68224092Sdougb 69170222Sdougb/* Command Processing */ 70135446Strhodesstatic void aac_timeout(struct aac_softc *sc); 71135446Strhodesstatic int aac_map_command(struct aac_command *cm); 72135446Strhodesstatic void aac_complete(void *context, int pending); 73135446Strhodesstatic int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 74135446Strhodesstatic void aac_bio_complete(struct aac_command *cm); 75193149Sdougbstatic int aac_wait_command(struct aac_command *cm, int timeout); 76135446Strhodesstatic void aac_command_thread(struct aac_softc *sc); 77135446Strhodes 78135446Strhodes/* Command Buffer Management */ 79135446Strhodesstatic void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 80135446Strhodes int nseg, int error); 81135446Strhodesstatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 82135446Strhodes int nseg, int error); 83135446Strhodesstatic int aac_alloc_commands(struct aac_softc *sc); 84193149Sdougbstatic void aac_free_commands(struct aac_softc *sc); 85135446Strhodesstatic void aac_unmap_command(struct aac_command *cm); 86135446Strhodes 87135446Strhodes/* Hardware Interface */ 88135446Strhodesstatic void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 89135446Strhodes int error); 90135446Strhodesstatic int aac_check_firmware(struct aac_softc *sc); 91135446Strhodesstatic int aac_init(struct aac_softc *sc); 92135446Strhodesstatic int aac_sync_command(struct aac_softc *sc, u_int32_t command, 93135446Strhodes u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 94135446Strhodes u_int32_t arg3, u_int32_t *sp); 95135446Strhodesstatic int aac_enqueue_fib(struct aac_softc *sc, int queue, 96135446Strhodes struct aac_command *cm); 97135446Strhodesstatic int aac_dequeue_fib(struct aac_softc *sc, int queue, 98135446Strhodes u_int32_t *fib_size, struct aac_fib **fib_addr); 99135446Strhodesstatic int aac_enqueue_response(struct aac_softc *sc, int queue, 100135446Strhodes struct aac_fib *fib); 101135446Strhodes 102193149Sdougb/* Falcon/PPC interface */ 103135446Strhodesstatic int aac_fa_get_fwstatus(struct aac_softc *sc); 104135446Strhodesstatic void aac_fa_qnotify(struct aac_softc *sc, int qbit); 105135446Strhodesstatic int aac_fa_get_istatus(struct aac_softc *sc); 106153816Sdougbstatic void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 107153816Sdougbstatic void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 108153816Sdougb u_int32_t arg0, u_int32_t arg1, 109153816Sdougb u_int32_t arg2, u_int32_t arg3); 110135446Strhodesstatic int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 111224092Sdougbstatic void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 112224092Sdougb 113224092Sdougbstruct aac_interface aac_fa_interface = { 114224092Sdougb aac_fa_get_fwstatus, 115170222Sdougb aac_fa_qnotify, 116135446Strhodes aac_fa_get_istatus, 117135446Strhodes aac_fa_clear_istatus, 118135446Strhodes aac_fa_set_mailbox, 119135446Strhodes aac_fa_get_mailbox, 120193149Sdougb aac_fa_set_interrupts 121193149Sdougb}; 122135446Strhodes 123135446Strhodes/* StrongARM interface */ 124135446Strhodesstatic int aac_sa_get_fwstatus(struct aac_softc *sc); 125193149Sdougbstatic void aac_sa_qnotify(struct aac_softc *sc, int qbit); 126135446Strhodesstatic int aac_sa_get_istatus(struct aac_softc *sc); 127135446Strhodesstatic void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 128135446Strhodesstatic void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 129135446Strhodes u_int32_t arg0, u_int32_t arg1, 130135446Strhodes u_int32_t arg2, u_int32_t arg3); 131135446Strhodesstatic int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 132135446Strhodesstatic void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 133135446Strhodes 134135446Strhodesstruct aac_interface aac_sa_interface = { 135135446Strhodes aac_sa_get_fwstatus, 136135446Strhodes aac_sa_qnotify, 137135446Strhodes aac_sa_get_istatus, 138193149Sdougb aac_sa_clear_istatus, 139135446Strhodes aac_sa_set_mailbox, 140135446Strhodes aac_sa_get_mailbox, 141135446Strhodes aac_sa_set_interrupts 142135446Strhodes}; 143135446Strhodes 144135446Strhodes/* i960Rx interface */ 145135446Strhodesstatic int aac_rx_get_fwstatus(struct aac_softc *sc); 146135446Strhodesstatic void aac_rx_qnotify(struct aac_softc *sc, int qbit); 147135446Strhodesstatic int aac_rx_get_istatus(struct aac_softc *sc); 148135446Strhodesstatic void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 149135446Strhodesstatic void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 150135446Strhodes u_int32_t arg0, u_int32_t arg1, 151193149Sdougb u_int32_t arg2, u_int32_t arg3); 152135446Strhodesstatic int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 153135446Strhodesstatic void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 154135446Strhodes 155135446Strhodesstruct aac_interface aac_rx_interface = { 156224092Sdougb aac_rx_get_fwstatus, 157224092Sdougb aac_rx_qnotify, 158224092Sdougb aac_rx_get_istatus, 159224092Sdougb aac_rx_clear_istatus, 160224092Sdougb aac_rx_set_mailbox, 161224092Sdougb aac_rx_get_mailbox, 162224092Sdougb aac_rx_set_interrupts 163224092Sdougb}; 164135446Strhodes 165135446Strhodes/* Debugging and Diagnostics */ 166135446Strhodesstatic void aac_describe_controller(struct aac_softc *sc); 167135446Strhodesstatic char *aac_describe_code(struct aac_code_lookup *table, 168135446Strhodes u_int32_t code); 169135446Strhodes 170135446Strhodes/* Management Interface */ 171224092Sdougbstatic d_open_t aac_open; 172224092Sdougbstatic d_close_t aac_close; 173224092Sdougbstatic d_ioctl_t aac_ioctl; 174224092Sdougbstatic d_poll_t aac_poll; 175224092Sdougbstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 176224092Sdougbstatic void aac_handle_aif(struct aac_softc *sc, 177224092Sdougb struct aac_fib *fib); 178224092Sdougbstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 179135446Strhodesstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 180135446Strhodesstatic int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 181135446Strhodesstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 182135446Strhodes 183135446Strhodesstatic struct cdevsw aac_cdevsw = { 184135446Strhodes .d_version = D_VERSION, 185135446Strhodes .d_flags = D_NEEDGIANT, 186135446Strhodes .d_open = aac_open, 187135446Strhodes .d_close = aac_close, 188135446Strhodes .d_ioctl = aac_ioctl, 189135446Strhodes .d_poll = aac_poll, 190135446Strhodes .d_name = "aac", 191135446Strhodes}; 192135446Strhodes 193135446StrhodesMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 194135446Strhodes 195135446Strhodes/* sysctl node */ 196135446StrhodesSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 197135446Strhodes 198135446Strhodes/* 199135446Strhodes * Device Interface 200135446Strhodes */ 201135446Strhodes 202135446Strhodes/* 203135446Strhodes * Initialise the controller and softc 204135446Strhodes */ 205224092Sdougbint 206224092Sdougbaac_attach(struct aac_softc *sc) 207225361Sdougb{ 208224092Sdougb int error, unit; 209224092Sdougb 210224092Sdougb debug_called(1); 211225361Sdougb 212224092Sdougb /* 213225361Sdougb * Initialise per-controller queues. 214225361Sdougb */ 215225361Sdougb aac_initq_free(sc); 216224092Sdougb aac_initq_ready(sc); 217224092Sdougb aac_initq_busy(sc); 218170222Sdougb aac_initq_bio(sc); 219170222Sdougb 220170222Sdougb /* 221170222Sdougb * Initialise command-completion task. 222170222Sdougb */ 223170222Sdougb TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 224170222Sdougb 225170222Sdougb /* disable interrupts before we enable anything */ 226170222Sdougb AAC_MASK_INTERRUPTS(sc); 227170222Sdougb 228170222Sdougb /* mark controller as suspended until we get ourselves organised */ 229170222Sdougb sc->aac_state |= AAC_STATE_SUSPEND; 230170222Sdougb 231170222Sdougb /* 232170222Sdougb * Check that the firmware on the card is supported. 233170222Sdougb */ 234170222Sdougb if ((error = aac_check_firmware(sc)) != 0) 235170222Sdougb return(error); 236170222Sdougb 237170222Sdougb /* 238170222Sdougb * Initialize locks 239170222Sdougb */ 240170222Sdougb AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock"); 241170222Sdougb AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock"); 242170222Sdougb AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock"); 243170222Sdougb AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock"); 244170222Sdougb TAILQ_INIT(&sc->aac_container_tqh); 245218384Sdougb 246186462Sdougb /* Initialize the local AIF queue pointers */ 247170222Sdougb sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; 248170222Sdougb 249170222Sdougb /* 250218384Sdougb * Initialise the adapter. 251218384Sdougb */ 252170222Sdougb if ((error = aac_init(sc)) != 0) 253170222Sdougb return(error); 254170222Sdougb 255170222Sdougb /* 256170222Sdougb * Print a little information about the controller. 257193149Sdougb */ 258170222Sdougb aac_describe_controller(sc); 259170222Sdougb 260170222Sdougb /* 261170222Sdougb * Register to probe our containers later. 262170222Sdougb */ 263170222Sdougb sc->aac_ich.ich_func = aac_startup; 264218384Sdougb sc->aac_ich.ich_arg = sc; 265218384Sdougb if (config_intrhook_establish(&sc->aac_ich) != 0) { 266218384Sdougb device_printf(sc->aac_dev, 267170222Sdougb "can't establish configuration hook\n"); 268170222Sdougb return(ENXIO); 269170222Sdougb } 270224092Sdougb 271224092Sdougb /* 272135446Strhodes * Make the control device. 273135446Strhodes */ 274135446Strhodes unit = device_get_unit(sc->aac_dev); 275135446Strhodes sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 276135446Strhodes 0640, "aac%d", unit); 277165071Sdougb (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 278170222Sdougb (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 279135446Strhodes sc->aac_dev_t->si_drv1 = sc; 280135446Strhodes 281165071Sdougb /* Create the AIF thread */ 282170222Sdougb if (kthread_create((void(*)(void *))aac_command_thread, sc, 283135446Strhodes &sc->aifthread, 0, 0, "aac%daif", unit)) 284135446Strhodes panic("Could not create AIF thread\n"); 285135446Strhodes 286165071Sdougb /* Register the shutdown method to only be called post-dump */ 287165071Sdougb if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 288135446Strhodes sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 289135446Strhodes device_printf(sc->aac_dev, 290165071Sdougb "shutdown event registration failed\n"); 291165071Sdougb 292135446Strhodes /* Register with CAM for the non-DASD devices */ 293135446Strhodes if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 294165071Sdougb TAILQ_INIT(&sc->aac_sim_tqh); 295165071Sdougb aac_get_bus_info(sc); 296224092Sdougb } 297135446Strhodes 298224092Sdougb return(0); 299224092Sdougb} 300224092Sdougb 301135446Strhodes/* 302135446Strhodes * Probe for containers, create disks. 303135446Strhodes */ 304224092Sdougbstatic void 305225361Sdougbaac_startup(void *arg) 306224092Sdougb{ 307170222Sdougb struct aac_softc *sc; 308193149Sdougb struct aac_fib *fib; 309193149Sdougb struct aac_mntinfo *mi; 310135446Strhodes struct aac_mntinforesp *mir = NULL; 311135446Strhodes int count = 0, i = 0; 312165071Sdougb 313224092Sdougb debug_called(1); 314224092Sdougb 315135446Strhodes sc = (struct aac_softc *)arg; 316135446Strhodes 317165071Sdougb /* disconnect ourselves from the intrhook chain */ 318165071Sdougb config_intrhook_disestablish(&sc->aac_ich); 319135446Strhodes 320135446Strhodes aac_alloc_sync_fib(sc, &fib, 0); 321135446Strhodes mi = (struct aac_mntinfo *)&fib->data[0]; 322135446Strhodes 323135446Strhodes /* loop over possible containers */ 324135446Strhodes do { 325135446Strhodes /* request information on this container */ 326165071Sdougb bzero(mi, sizeof(struct aac_mntinfo)); 327135446Strhodes mi->Command = VM_NameServe; 328135446Strhodes mi->MntType = FT_FILESYS; 329135446Strhodes mi->MntCount = i; 330135446Strhodes if (aac_sync_fib(sc, ContainerCommand, 0, fib, 331135446Strhodes sizeof(struct aac_mntinfo))) { 332135446Strhodes printf("error probing container %d", i); 333165071Sdougb continue; 334135446Strhodes } 335135446Strhodes 336193149Sdougb mir = (struct aac_mntinforesp *)&fib->data[0]; 337135446Strhodes /* XXX Need to check if count changed */ 338135446Strhodes count = mir->MntRespCount; 339135446Strhodes aac_add_container(sc, mir, 0); 340224092Sdougb i++; 341224092Sdougb } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 342224092Sdougb 343224092Sdougb aac_release_sync_fib(sc); 344224092Sdougb 345224092Sdougb /* poke the bus to actually attach the child devices */ 346224092Sdougb if (bus_generic_attach(sc->aac_dev)) 347224092Sdougb device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 348224092Sdougb 349170222Sdougb /* mark the controller up */ 350193149Sdougb sc->aac_state &= ~AAC_STATE_SUSPEND; 351135446Strhodes 352135446Strhodes /* enable interrupts now */ 353135446Strhodes AAC_UNMASK_INTERRUPTS(sc); 354135446Strhodes} 355193149Sdougb 356193149Sdougb/* 357193149Sdougb * Create a device to respresent a new container 358193149Sdougb */ 359193149Sdougbstatic void 360135446Strhodesaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 361193149Sdougb{ 362193149Sdougb struct aac_container *co; 363193149Sdougb device_t child; 364193149Sdougb 365193149Sdougb /* 366193149Sdougb * Check container volume type for validity. Note that many of 367193149Sdougb * the possible types may never show up. 368193149Sdougb */ 369193149Sdougb if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 370193149Sdougb co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 371193149Sdougb M_NOWAIT | M_ZERO); 372193149Sdougb if (co == NULL) 373193149Sdougb panic("Out of memory?!\n"); 374193149Sdougb debug(1, "id %x name '%.16s' size %u type %d", 375193149Sdougb mir->MntTable[0].ObjectId, 376193149Sdougb mir->MntTable[0].FileSystemName, 377193149Sdougb mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 378193149Sdougb 379193149Sdougb if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 380193149Sdougb device_printf(sc->aac_dev, "device_add_child failed\n"); 381193149Sdougb else 382193149Sdougb device_set_ivars(child, co); 383193149Sdougb device_set_desc(child, aac_describe_code(aac_container_types, 384193149Sdougb mir->MntTable[0].VolType)); 385193149Sdougb co->co_disk = child; 386193149Sdougb co->co_found = f; 387193149Sdougb bcopy(&mir->MntTable[0], &co->co_mntobj, 388193149Sdougb sizeof(struct aac_mntobj)); 389193149Sdougb AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 390193149Sdougb TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 391193149Sdougb AAC_LOCK_RELEASE(&sc->aac_container_lock); 392193149Sdougb } 393193149Sdougb} 394193149Sdougb 395193149Sdougb/* 396193149Sdougb * Free all of the resources associated with (sc) 397193149Sdougb * 398193149Sdougb * Should not be called if the controller is active. 399224092Sdougb */ 400224092Sdougbvoid 401224092Sdougbaac_free(struct aac_softc *sc) 402135446Strhodes{ 403224092Sdougb 404224092Sdougb debug_called(1); 405224092Sdougb 406224092Sdougb /* remove the control device */ 407224092Sdougb if (sc->aac_dev_t != NULL) 408224092Sdougb destroy_dev(sc->aac_dev_t); 409224092Sdougb 410224092Sdougb /* throw away any FIB buffers, discard the FIB DMA tag */ 411224092Sdougb aac_free_commands(sc); 412224092Sdougb if (sc->aac_fib_dmat) 413224092Sdougb bus_dma_tag_destroy(sc->aac_fib_dmat); 414224092Sdougb 415224092Sdougb free(sc->aac_commands, M_AACBUF); 416224092Sdougb 417224092Sdougb /* destroy the common area */ 418224092Sdougb if (sc->aac_common) { 419224092Sdougb bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 420224092Sdougb bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 421224092Sdougb sc->aac_common_dmamap); 422224092Sdougb } 423224092Sdougb if (sc->aac_common_dmat) 424224092Sdougb bus_dma_tag_destroy(sc->aac_common_dmat); 425224092Sdougb 426224092Sdougb /* disconnect the interrupt handler */ 427224092Sdougb if (sc->aac_intr) 428224092Sdougb bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 429224092Sdougb if (sc->aac_irq != NULL) 430224092Sdougb bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 431224092Sdougb sc->aac_irq); 432224092Sdougb 433224092Sdougb /* destroy data-transfer DMA tag */ 434224092Sdougb if (sc->aac_buffer_dmat) 435224092Sdougb bus_dma_tag_destroy(sc->aac_buffer_dmat); 436224092Sdougb 437224092Sdougb /* destroy the parent DMA tag */ 438224092Sdougb if (sc->aac_parent_dmat) 439224092Sdougb bus_dma_tag_destroy(sc->aac_parent_dmat); 440224092Sdougb 441224092Sdougb /* release the register window mapping */ 442224092Sdougb if (sc->aac_regs_resource != NULL) 443224092Sdougb bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 444224092Sdougb sc->aac_regs_rid, sc->aac_regs_resource); 445224092Sdougb} 446224092Sdougb 447224092Sdougb/* 448224092Sdougb * Disconnect from the controller completely, in preparation for unload. 449224092Sdougb */ 450224092Sdougbint 451224092Sdougbaac_detach(device_t dev) 452224092Sdougb{ 453224092Sdougb struct aac_softc *sc; 454224092Sdougb struct aac_container *co; 455224092Sdougb struct aac_sim *sim; 456224092Sdougb int error; 457224092Sdougb 458224092Sdougb debug_called(1); 459224092Sdougb 460224092Sdougb sc = device_get_softc(dev); 461224092Sdougb 462224092Sdougb if (sc->aac_state & AAC_STATE_OPEN) 463224092Sdougb return(EBUSY); 464224092Sdougb 465224092Sdougb /* Remove the child containers */ 466224092Sdougb while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 467224092Sdougb error = device_delete_child(dev, co->co_disk); 468224092Sdougb if (error) 469224092Sdougb return (error); 470224092Sdougb TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 471224092Sdougb free(co, M_AACBUF); 472224092Sdougb } 473224092Sdougb 474224092Sdougb /* Remove the CAM SIMs */ 475224092Sdougb while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 476224092Sdougb TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 477224092Sdougb error = device_delete_child(dev, sim->sim_dev); 478224092Sdougb if (error) 479224092Sdougb return (error); 480224092Sdougb free(sim, M_AACBUF); 481224092Sdougb } 482135446Strhodes 483135446Strhodes if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 484135446Strhodes sc->aifflags |= AAC_AIFFLAGS_EXIT; 485165071Sdougb wakeup(sc->aifthread); 486135446Strhodes tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 487135446Strhodes } 488135446Strhodes 489135446Strhodes if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 490135446Strhodes panic("Cannot shutdown AIF thread\n"); 491135446Strhodes 492135446Strhodes if ((error = aac_shutdown(dev))) 493135446Strhodes return(error); 494135446Strhodes 495135446Strhodes EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 496135446Strhodes 497224092Sdougb aac_free(sc); 498224092Sdougb 499135446Strhodes return(0); 500135446Strhodes} 501135446Strhodes 502135446Strhodes/* 503135446Strhodes * Bring the controller down to a dormant state and detach all child devices. 504135446Strhodes * 505224092Sdougb * This function is called before detach or system shutdown. 506224092Sdougb * 507224092Sdougb * Note that we can assume that the bioq on the controller is empty, as we won't 508224092Sdougb * allow shutdown if any device is open. 509224092Sdougb */ 510224092Sdougbint 511224092Sdougbaac_shutdown(device_t dev) 512224092Sdougb{ 513224092Sdougb struct aac_softc *sc; 514224092Sdougb struct aac_fib *fib; 515224092Sdougb struct aac_close_command *cc; 516224092Sdougb 517224092Sdougb debug_called(1); 518224092Sdougb 519135446Strhodes sc = device_get_softc(dev); 520135446Strhodes 521135446Strhodes sc->aac_state |= AAC_STATE_SUSPEND; 522165071Sdougb 523135446Strhodes /* 524135446Strhodes * Send a Container shutdown followed by a HostShutdown FIB to the 525135446Strhodes * controller to convince it that we don't want to talk to it anymore. 526135446Strhodes * We've been closed and all I/O completed already 527135446Strhodes */ 528135446Strhodes device_printf(sc->aac_dev, "shutting down controller..."); 529135446Strhodes 530135446Strhodes aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE); 531135446Strhodes cc = (struct aac_close_command *)&fib->data[0]; 532135446Strhodes 533135446Strhodes bzero(cc, sizeof(struct aac_close_command)); 534135446Strhodes cc->Command = VM_CloseAll; 535135446Strhodes cc->ContainerId = 0xffffffff; 536135446Strhodes if (aac_sync_fib(sc, ContainerCommand, 0, fib, 537135446Strhodes sizeof(struct aac_close_command))) 538135446Strhodes printf("FAILED.\n"); 539135446Strhodes else 540135446Strhodes printf("done\n"); 541135446Strhodes#if 0 542135446Strhodes else { 543135446Strhodes fib->data[0] = 0; 544135446Strhodes /* 545135446Strhodes * XXX Issuing this command to the controller makes it shut down 546135446Strhodes * but also keeps it from coming back up without a reset of the 547135446Strhodes * PCI bus. This is not desirable if you are just unloading the 548135446Strhodes * driver module with the intent to reload it later. 549135446Strhodes */ 550135446Strhodes if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 551135446Strhodes fib, 1)) { 552135446Strhodes printf("FAILED.\n"); 553135446Strhodes } else { 554170222Sdougb printf("done.\n"); 555170222Sdougb } 556170222Sdougb } 557170222Sdougb#endif 558224092Sdougb 559224092Sdougb AAC_MASK_INTERRUPTS(sc); 560170222Sdougb 561170222Sdougb return(0); 562135446Strhodes} 563135446Strhodes 564135446Strhodes/* 565135446Strhodes * Bring the controller to a quiescent state, ready for system suspend. 566135446Strhodes */ 567135446Strhodesint 568135446Strhodesaac_suspend(device_t dev) 569224092Sdougb{ 570135446Strhodes struct aac_softc *sc; 571135446Strhodes 572135446Strhodes debug_called(1); 573224092Sdougb 574135446Strhodes sc = device_get_softc(dev); 575135446Strhodes 576135446Strhodes sc->aac_state |= AAC_STATE_SUSPEND; 577135446Strhodes 578135446Strhodes AAC_MASK_INTERRUPTS(sc); 579224092Sdougb return(0); 580224092Sdougb} 581135446Strhodes 582224092Sdougb/* 583224092Sdougb * Bring the controller back to a state ready for operation. 584224092Sdougb */ 585224092Sdougbint 586224092Sdougbaac_resume(device_t dev) 587135446Strhodes{ 588135446Strhodes struct aac_softc *sc; 589224092Sdougb 590224092Sdougb debug_called(1); 591135446Strhodes 592135446Strhodes sc = device_get_softc(dev); 593135446Strhodes 594135446Strhodes sc->aac_state &= ~AAC_STATE_SUSPEND; 595135446Strhodes AAC_UNMASK_INTERRUPTS(sc); 596135446Strhodes return(0); 597135446Strhodes} 598135446Strhodes 599135446Strhodes/* 600135446Strhodes * Take an interrupt. 601224092Sdougb */ 602224092Sdougbvoid 603224092Sdougbaac_intr(void *arg) 604224092Sdougb{ 605224092Sdougb struct aac_softc *sc; 606224092Sdougb u_int16_t reason; 607224092Sdougb 608224092Sdougb debug_called(2); 609224092Sdougb 610224092Sdougb sc = (struct aac_softc *)arg; 611224092Sdougb 612224092Sdougb /* 613224092Sdougb * Read the status register directly. This is faster than taking the 614224092Sdougb * driver lock and reading the queues directly. It also saves having 615224092Sdougb * to turn parts of the driver lock into a spin mutex, which would be 616224092Sdougb * ugly. 617224092Sdougb */ 618224092Sdougb reason = AAC_GET_ISTATUS(sc); 619224092Sdougb AAC_CLEAR_ISTATUS(sc, reason); 620224092Sdougb 621224092Sdougb /* handle completion processing */ 622224092Sdougb if (reason & AAC_DB_RESPONSE_READY) 623224092Sdougb taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 624224092Sdougb 625224092Sdougb /* controller wants to talk to us */ 626224092Sdougb if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 627224092Sdougb /* 628224092Sdougb * XXX Make sure that we don't get fooled by strange messages 629224092Sdougb * that start with a NULL. 630224092Sdougb */ 631224092Sdougb if ((reason & AAC_DB_PRINTF) && 632224092Sdougb (sc->aac_common->ac_printf[0] == 0)) 633224092Sdougb sc->aac_common->ac_printf[0] = 32; 634224092Sdougb 635224092Sdougb /* 636224092Sdougb * This might miss doing the actual wakeup. However, the 637224092Sdougb * msleep that this is waking up has a timeout, so it will 638224092Sdougb * wake up eventually. AIFs and printfs are low enough 639224092Sdougb * priority that they can handle hanging out for a few seconds 640224092Sdougb * if needed. 641224092Sdougb */ 642224092Sdougb wakeup(sc->aifthread); 643224092Sdougb } 644224092Sdougb} 645224092Sdougb 646224092Sdougb/* 647224092Sdougb * Command Processing 648224092Sdougb */ 649224092Sdougb 650224092Sdougb/* 651224092Sdougb * Start as much queued I/O as possible on the controller 652224092Sdougb */ 653224092Sdougbvoid 654224092Sdougbaac_startio(struct aac_softc *sc) 655224092Sdougb{ 656170222Sdougb struct aac_command *cm; 657224092Sdougb 658135446Strhodes debug_called(2); 659135446Strhodes 660224092Sdougb if (sc->flags & AAC_QUEUE_FRZN) 661135446Strhodes return; 662135446Strhodes 663224092Sdougb for (;;) { 664224092Sdougb /* 665224092Sdougb * Try to get a command that's been put off for lack of 666224092Sdougb * resources 667135446Strhodes */ 668224092Sdougb cm = aac_dequeue_ready(sc); 669224092Sdougb 670224092Sdougb /* 671224092Sdougb * Try to build a command off the bio queue (ignore error 672224092Sdougb * return) 673224092Sdougb */ 674165071Sdougb if (cm == NULL) 675224092Sdougb aac_bio_command(sc, &cm); 676224092Sdougb 677224092Sdougb /* nothing to do? */ 678224092Sdougb if (cm == NULL) 679135446Strhodes break; 680224092Sdougb 681224092Sdougb /* 682224092Sdougb * Try to give the command to the controller. Any error is 683224092Sdougb * catastrophic since it means that bus_dmamap_load() failed. 684224092Sdougb */ 685135446Strhodes if (aac_map_command(cm) != 0) 686224092Sdougb panic("aac: error mapping command %p\n", cm); 687135446Strhodes } 688224092Sdougb} 689224092Sdougb 690224092Sdougb/* 691224092Sdougb * Deliver a command to the controller; allocate controller resources at the 692224092Sdougb * last moment when possible. 693224092Sdougb */ 694224092Sdougbstatic int 695224092Sdougbaac_map_command(struct aac_command *cm) 696135446Strhodes{ 697224092Sdougb struct aac_softc *sc; 698224092Sdougb int error; 699224092Sdougb 700224092Sdougb debug_called(2); 701224092Sdougb 702224092Sdougb sc = cm->cm_sc; 703224092Sdougb error = 0; 704224092Sdougb 705135446Strhodes /* don't map more than once */ 706224092Sdougb if (cm->cm_flags & AAC_CMD_MAPPED) 707224092Sdougb panic("aac: command %p already mapped", cm); 708224092Sdougb 709224092Sdougb if (cm->cm_datalen != 0) { 710224092Sdougb error = bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, 711224092Sdougb cm->cm_data, cm->cm_datalen, 712224092Sdougb aac_map_command_sg, cm, 0); 713224092Sdougb if (error == EINPROGRESS) { 714224092Sdougb debug(1, "freezing queue\n"); 715224092Sdougb sc->flags |= AAC_QUEUE_FRZN; 716224092Sdougb error = 0; 717224092Sdougb } 718224092Sdougb } else { 719224092Sdougb aac_map_command_sg(cm, NULL, 0, 0); 720224092Sdougb } 721224092Sdougb return (error); 722224092Sdougb} 723224092Sdougb 724224092Sdougb/* 725224092Sdougb * Handle notification of one or more FIBs coming from the controller. 726224092Sdougb */ 727224092Sdougbstatic void 728224092Sdougbaac_command_thread(struct aac_softc *sc) 729224092Sdougb{ 730224092Sdougb struct aac_fib *fib; 731224092Sdougb u_int32_t fib_size; 732224092Sdougb int size, retval; 733224092Sdougb 734224092Sdougb debug_called(2); 735224092Sdougb 736224092Sdougb AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 737224092Sdougb sc->aifflags = AAC_AIFFLAGS_RUNNING; 738224092Sdougb 739224092Sdougb while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 740135446Strhodes 741224092Sdougb retval = 0; 742224092Sdougb if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 743224092Sdougb retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 744224092Sdougb "aifthd", AAC_PERIODIC_INTERVAL * hz); 745224092Sdougb 746224092Sdougb /* 747224092Sdougb * First see if any FIBs need to be allocated. This needs 748135446Strhodes * to be called without the driver lock because contigmalloc 749135446Strhodes * will grab Giant, and would result in an LOR. 750224092Sdougb */ 751224092Sdougb if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 752224092Sdougb AAC_LOCK_RELEASE(&sc->aac_io_lock); 753186462Sdougb aac_alloc_commands(sc); 754224092Sdougb AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 755224092Sdougb sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 756224092Sdougb aac_startio(sc); 757224092Sdougb } 758224092Sdougb 759224092Sdougb /* 760224092Sdougb * While we're here, check to see if any commands are stuck. 761224092Sdougb * This is pretty low-priority, so it's ok if it doesn't 762224092Sdougb * always fire. 763224092Sdougb */ 764224092Sdougb if (retval == EWOULDBLOCK) 765224092Sdougb aac_timeout(sc); 766224092Sdougb 767224092Sdougb /* Check the hardware printf message buffer */ 768224092Sdougb if (sc->aac_common->ac_printf[0] != 0) 769224092Sdougb aac_print_printf(sc); 770224092Sdougb 771224092Sdougb /* Also check to see if the adapter has a command for us. */ 772224092Sdougb while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 773224092Sdougb &fib_size, &fib) == 0) { 774224092Sdougb 775224092Sdougb AAC_PRINT_FIB(sc, fib); 776224092Sdougb 777224092Sdougb switch (fib->Header.Command) { 778224092Sdougb case AifRequest: 779224092Sdougb aac_handle_aif(sc, fib); 780224092Sdougb break; 781224092Sdougb default: 782224092Sdougb device_printf(sc->aac_dev, "unknown command " 783224092Sdougb "from controller\n"); 784224092Sdougb break; 785224092Sdougb } 786224092Sdougb 787224092Sdougb if ((fib->Header.XferState == 0) || 788224092Sdougb (fib->Header.StructType != AAC_FIBTYPE_TFIB)) 789224092Sdougb break; 790224092Sdougb 791224092Sdougb /* Return the AIF to the controller. */ 792224092Sdougb if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 793224092Sdougb fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 794224092Sdougb *(AAC_FSAStatus*)fib->data = ST_OK; 795224092Sdougb 796224092Sdougb /* XXX Compute the Size field? */ 797224092Sdougb size = fib->Header.Size; 798224092Sdougb if (size > sizeof(struct aac_fib)) { 799224092Sdougb size = sizeof(struct aac_fib); 800224092Sdougb fib->Header.Size = size; 801224092Sdougb } 802224092Sdougb /* 803224092Sdougb * Since we did not generate this command, it 804224092Sdougb * cannot go through the normal 805135446Strhodes * enqueue->startio chain. 806135446Strhodes */ 807135446Strhodes aac_enqueue_response(sc, 808135446Strhodes AAC_ADAP_NORM_RESP_QUEUE, 809224092Sdougb fib); 810165071Sdougb } 811165071Sdougb } 812135446Strhodes } 813135446Strhodes sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 814135446Strhodes AAC_LOCK_RELEASE(&sc->aac_io_lock); 815135446Strhodes wakeup(sc->aac_dev); 816135446Strhodes 817135446Strhodes mtx_lock(&Giant); 818186462Sdougb kthread_exit(0); 819135446Strhodes} 820135446Strhodes 821135446Strhodes/* 822135446Strhodes * Process completed commands. 823135446Strhodes */ 824135446Strhodesstatic void 825135446Strhodesaac_complete(void *context, int pending) 826135446Strhodes{ 827135446Strhodes struct aac_softc *sc; 828135446Strhodes struct aac_command *cm; 829224092Sdougb struct aac_fib *fib; 830135446Strhodes u_int32_t fib_size; 831135446Strhodes 832135446Strhodes debug_called(2); 833135446Strhodes 834135446Strhodes sc = (struct aac_softc *)context; 835186462Sdougb 836135446Strhodes AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 837135446Strhodes 838135446Strhodes /* pull completed commands off the queue */ 839135446Strhodes for (;;) { 840170222Sdougb /* look for completed FIBs on our queue */ 841135446Strhodes if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 842135446Strhodes &fib)) 843135446Strhodes break; /* nothing to do */ 844165071Sdougb 845186462Sdougb /* get the command, unmap and hand off for processing */ 846186462Sdougb cm = sc->aac_commands + fib->Header.SenderData; 847135446Strhodes if (cm == NULL) { 848225361Sdougb AAC_PRINT_FIB(sc, fib); 849135446Strhodes break; 850135446Strhodes } 851135446Strhodes 852165071Sdougb aac_remove_busy(cm); 853186462Sdougb aac_unmap_command(cm); 854135446Strhodes cm->cm_flags |= AAC_CMD_COMPLETED; 855135446Strhodes 856135446Strhodes /* is there a completion handler? */ 857135446Strhodes if (cm->cm_complete != NULL) { 858135446Strhodes cm->cm_complete(cm); 859135446Strhodes } else { 860135446Strhodes /* assume that someone is sleeping on this command */ 861135446Strhodes wakeup(cm); 862135446Strhodes } 863135446Strhodes } 864135446Strhodes 865135446Strhodes /* see if we can start some more I/O */ 866135446Strhodes sc->flags &= ~AAC_QUEUE_FRZN; 867135446Strhodes aac_startio(sc); 868135446Strhodes 869135446Strhodes AAC_LOCK_RELEASE(&sc->aac_io_lock); 870135446Strhodes} 871135446Strhodes 872135446Strhodes/* 873135446Strhodes * Handle a bio submitted from a disk device. 874135446Strhodes */ 875135446Strhodesvoid 876135446Strhodesaac_submit_bio(struct bio *bp) 877135446Strhodes{ 878135446Strhodes struct aac_disk *ad; 879135446Strhodes struct aac_softc *sc; 880135446Strhodes 881135446Strhodes debug_called(2); 882135446Strhodes 883135446Strhodes ad = (struct aac_disk *)bp->bio_disk->d_drv1; 884135446Strhodes sc = ad->ad_controller; 885135446Strhodes 886135446Strhodes /* queue the BIO and try to get some work done */ 887135446Strhodes aac_enqueue_bio(sc, bp); 888135446Strhodes aac_startio(sc); 889135446Strhodes} 890135446Strhodes 891135446Strhodes/* 892135446Strhodes * Get a bio and build a command to go with it. 893135446Strhodes */ 894135446Strhodesstatic int 895135446Strhodesaac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 896135446Strhodes{ 897135446Strhodes struct aac_command *cm; 898135446Strhodes struct aac_fib *fib; 899135446Strhodes struct aac_disk *ad; 900186462Sdougb struct bio *bp; 901186462Sdougb 902186462Sdougb debug_called(2); 903186462Sdougb 904180477Sdougb /* get the resources we will need */ 905186462Sdougb cm = NULL; 906186462Sdougb bp = NULL; 907186462Sdougb if (aac_alloc_command(sc, &cm)) /* get a command */ 908186462Sdougb goto fail; 909186462Sdougb if ((bp = aac_dequeue_bio(sc)) == NULL) 910186462Sdougb goto fail; 911186462Sdougb 912180477Sdougb /* fill out the command */ 913180477Sdougb cm->cm_data = (void *)bp->bio_data; 914135446Strhodes cm->cm_datalen = bp->bio_bcount; 915135446Strhodes cm->cm_complete = aac_bio_complete; 916135446Strhodes cm->cm_private = bp; 917135446Strhodes cm->cm_timestamp = time_second; 918135446Strhodes cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 919135446Strhodes 920135446Strhodes /* build the FIB */ 921135446Strhodes fib = cm->cm_fib; 922135446Strhodes fib->Header.Size = sizeof(struct aac_fib_header); 923186462Sdougb fib->Header.XferState = 924135446Strhodes AAC_FIBSTATE_HOSTOWNED | 925135446Strhodes AAC_FIBSTATE_INITIALISED | 926135446Strhodes AAC_FIBSTATE_EMPTY | 927135446Strhodes AAC_FIBSTATE_FROMHOST | 928135446Strhodes AAC_FIBSTATE_REXPECTED | 929135446Strhodes AAC_FIBSTATE_NORM | 930135446Strhodes AAC_FIBSTATE_ASYNC | 931135446Strhodes AAC_FIBSTATE_FAST_RESPONSE; 932135446Strhodes 933135446Strhodes /* build the read/write request */ 934135446Strhodes ad = (struct aac_disk *)bp->bio_disk->d_drv1; 935135446Strhodes 936135446Strhodes if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 937135446Strhodes fib->Header.Command = ContainerCommand; 938135446Strhodes if (bp->bio_cmd == BIO_READ) { 939135446Strhodes struct aac_blockread *br; 940135446Strhodes br = (struct aac_blockread *)&fib->data[0]; 941135446Strhodes br->Command = VM_CtBlockRead; 942135446Strhodes br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 943135446Strhodes br->BlockNumber = bp->bio_pblkno; 944135446Strhodes br->ByteCount = bp->bio_bcount; 945135446Strhodes fib->Header.Size += sizeof(struct aac_blockread); 946135446Strhodes cm->cm_sgtable = &br->SgMap; 947135446Strhodes cm->cm_flags |= AAC_CMD_DATAIN; 948135446Strhodes } else { 949135446Strhodes struct aac_blockwrite *bw; 950135446Strhodes bw = (struct aac_blockwrite *)&fib->data[0]; 951135446Strhodes bw->Command = VM_CtBlockWrite; 952135446Strhodes bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 953165071Sdougb bw->BlockNumber = bp->bio_pblkno; 954135446Strhodes bw->ByteCount = bp->bio_bcount; 955135446Strhodes bw->Stable = CUNSTABLE; 956165071Sdougb fib->Header.Size += sizeof(struct aac_blockwrite); 957135446Strhodes cm->cm_flags |= AAC_CMD_DATAOUT; 958135446Strhodes cm->cm_sgtable = &bw->SgMap; 959135446Strhodes } 960135446Strhodes } else { 961135446Strhodes fib->Header.Command = ContainerCommand64; 962143731Sdougb if (bp->bio_cmd == BIO_READ) { 963135446Strhodes struct aac_blockread64 *br; 964135446Strhodes br = (struct aac_blockread64 *)&fib->data[0]; 965135446Strhodes br->Command = VM_CtHostRead64; 966135446Strhodes br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 967135446Strhodes br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 968135446Strhodes br->BlockNumber = bp->bio_pblkno; 969135446Strhodes br->Pad = 0; 970135446Strhodes br->Flags = 0; 971135446Strhodes fib->Header.Size += sizeof(struct aac_blockread64); 972135446Strhodes cm->cm_flags |= AAC_CMD_DATAOUT; 973135446Strhodes (struct aac_sg_table64 *)cm->cm_sgtable = &br->SgMap64; 974135446Strhodes } else { 975186462Sdougb struct aac_blockwrite64 *bw; 976135446Strhodes bw = (struct aac_blockwrite64 *)&fib->data[0]; 977135446Strhodes bw->Command = VM_CtHostWrite64; 978135446Strhodes bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 979143731Sdougb bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 980135446Strhodes bw->BlockNumber = bp->bio_pblkno; 981135446Strhodes bw->Pad = 0; 982135446Strhodes bw->Flags = 0; 983135446Strhodes fib->Header.Size += sizeof(struct aac_blockwrite64); 984224092Sdougb cm->cm_flags |= AAC_CMD_DATAIN; 985135446Strhodes (struct aac_sg_table64 *)cm->cm_sgtable = &bw->SgMap64; 986135446Strhodes } 987135446Strhodes } 988135446Strhodes 989135446Strhodes *cmp = cm; 990135446Strhodes return(0); 991135446Strhodes 992135446Strhodesfail: 993135446Strhodes if (bp != NULL) 994135446Strhodes aac_enqueue_bio(sc, bp); 995135446Strhodes if (cm != NULL) 996135446Strhodes aac_release_command(cm); 997135446Strhodes return(ENOMEM); 998135446Strhodes} 999135446Strhodes 1000143731Sdougb/* 1001143731Sdougb * Handle a bio-instigated command that has been completed. 1002143731Sdougb */ 1003165071Sdougbstatic void 1004143731Sdougbaac_bio_complete(struct aac_command *cm) 1005143731Sdougb{ 1006143731Sdougb struct aac_blockread_response *brr; 1007143731Sdougb struct aac_blockwrite_response *bwr; 1008143731Sdougb struct bio *bp; 1009143731Sdougb AAC_FSAStatus status; 1010143731Sdougb 1011143731Sdougb /* fetch relevant status and then release the command */ 1012135446Strhodes bp = (struct bio *)cm->cm_private; 1013135446Strhodes if (bp->bio_cmd == BIO_READ) { 1014135446Strhodes brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 1015135446Strhodes status = brr->Status; 1016135446Strhodes } else { 1017165071Sdougb bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 1018135446Strhodes status = bwr->Status; 1019135446Strhodes } 1020165071Sdougb aac_release_command(cm); 1021165071Sdougb 1022135446Strhodes /* fix up the bio based on status */ 1023170222Sdougb if (status == ST_OK) { 1024135446Strhodes bp->bio_resid = 0; 1025170222Sdougb } else { 1026135446Strhodes bp->bio_error = EIO; 1027135446Strhodes bp->bio_flags |= BIO_ERROR; 1028186462Sdougb /* pass an error string out to the disk layer */ 1029135446Strhodes bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1030135446Strhodes status); 1031135446Strhodes } 1032135446Strhodes aac_biodone(bp); 1033135446Strhodes} 1034135446Strhodes 1035135446Strhodes/* 1036135446Strhodes * Submit a command to the controller, return when it completes. 1037135446Strhodes * XXX This is very dangerous! If the card has gone out to lunch, we could 1038135446Strhodes * be stuck here forever. At the same time, signals are not caught 1039135446Strhodes * because there is a risk that a signal could wakeup the tsleep before 1040135446Strhodes * the card has a chance to complete the command. The passed in timeout 1041135446Strhodes * is ignored for the same reason. Since there is no way to cancel a 1042135446Strhodes * command in progress, we should probably create a 'dead' queue where 1043135446Strhodes * commands go that have been interrupted/timed-out/etc, that keeps them 1044135446Strhodes * out of the free pool. That way, if the card is just slow, it won't 1045135446Strhodes * spam the memory of a command that has been recycled. 1046135446Strhodes */ 1047135446Strhodesstatic int 1048193149Sdougbaac_wait_command(struct aac_command *cm, int timeout) 1049193149Sdougb{ 1050193149Sdougb struct aac_softc *sc; 1051193149Sdougb int error = 0; 1052193149Sdougb 1053135446Strhodes debug_called(2); 1054135446Strhodes 1055135446Strhodes sc = cm->cm_sc; 1056135446Strhodes 1057135446Strhodes /* Put the command on the ready queue and get things going */ 1058170222Sdougb cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 1059170222Sdougb aac_enqueue_ready(cm); 1060170222Sdougb aac_startio(sc); 1061170222Sdougb while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) { 1062170222Sdougb error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 1063170222Sdougb } 1064170222Sdougb return(error); 1065170222Sdougb} 1066170222Sdougb 1067170222Sdougb/* 1068170222Sdougb *Command Buffer Management 1069170222Sdougb */ 1070170222Sdougb 1071170222Sdougb/* 1072170222Sdougb * Allocate a command. 1073170222Sdougb */ 1074170222Sdougbint 1075170222Sdougbaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1076170222Sdougb{ 1077170222Sdougb struct aac_command *cm; 1078170222Sdougb 1079170222Sdougb debug_called(3); 1080135446Strhodes 1081135446Strhodes if ((cm = aac_dequeue_free(sc)) == NULL) { 1082135446Strhodes if (sc->total_fibs < sc->aac_max_fibs) { 1083135446Strhodes sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1084135446Strhodes wakeup(sc->aifthread); 1085135446Strhodes } 1086135446Strhodes return (EBUSY); 1087135446Strhodes } 1088135446Strhodes 1089135446Strhodes *cmp = cm; 1090135446Strhodes return(0); 1091135446Strhodes} 1092135446Strhodes 1093135446Strhodes/* 1094135446Strhodes * Release a command back to the freelist. 1095135446Strhodes */ 1096135446Strhodesvoid 1097135446Strhodesaac_release_command(struct aac_command *cm) 1098135446Strhodes{ 1099135446Strhodes debug_called(3); 1100135446Strhodes 1101135446Strhodes /* (re)initialise the command/FIB */ 1102135446Strhodes cm->cm_sgtable = NULL; 1103135446Strhodes cm->cm_flags = 0; 1104135446Strhodes cm->cm_complete = NULL; 1105135446Strhodes cm->cm_private = NULL; 1106135446Strhodes cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1107170222Sdougb cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1108135446Strhodes cm->cm_fib->Header.Flags = 0; 1109135446Strhodes cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib); 1110135446Strhodes 1111135446Strhodes /* 1112135446Strhodes * These are duplicated in aac_start to cover the case where an 1113135446Strhodes * intermediate stage may have destroyed them. They're left 1114135446Strhodes * initialised here for debugging purposes only. 1115135446Strhodes */ 1116170222Sdougb cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1117135446Strhodes cm->cm_fib->Header.SenderData = 0; 1118170222Sdougb 1119170222Sdougb aac_enqueue_free(cm); 1120170222Sdougb} 1121170222Sdougb 1122170222Sdougb/* 1123170222Sdougb * Map helper for command/FIB allocation. 1124170222Sdougb */ 1125170222Sdougbstatic void 1126170222Sdougbaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1127170222Sdougb{ 1128170222Sdougb uint32_t *fibphys; 1129170222Sdougb 1130170222Sdougb fibphys = (uint32_t *)arg; 1131170222Sdougb 1132170222Sdougb debug_called(3); 1133170222Sdougb 1134170222Sdougb *fibphys = segs[0].ds_addr; 1135170222Sdougb} 1136170222Sdougb 1137170222Sdougb/* 1138170222Sdougb * Allocate and initialise commands/FIBs for this adapter. 1139170222Sdougb */ 1140170222Sdougbstatic int 1141170222Sdougbaac_alloc_commands(struct aac_softc *sc) 1142170222Sdougb{ 1143170222Sdougb struct aac_command *cm; 1144170222Sdougb struct aac_fibmap *fm; 1145135446Strhodes uint32_t fibphys; 1146135446Strhodes int i, error; 1147135446Strhodes 1148135446Strhodes debug_called(2); 1149135446Strhodes 1150135446Strhodes if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs) 1151135446Strhodes return (ENOMEM); 1152135446Strhodes 1153135446Strhodes fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1154165071Sdougb if (fm == NULL) 1155135446Strhodes return (ENOMEM); 1156165071Sdougb 1157165071Sdougb /* allocate the FIBs in DMAable memory and load them */ 1158135446Strhodes if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1159135446Strhodes BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1160135446Strhodes device_printf(sc->aac_dev, 1161135446Strhodes "Not enough contiguous memory available.\n"); 1162135446Strhodes free(fm, M_AACBUF); 1163135446Strhodes return (ENOMEM); 1164135446Strhodes } 1165135446Strhodes 1166135446Strhodes /* Ignore errors since this doesn't bounce */ 1167135446Strhodes (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1168224092Sdougb AAC_FIB_COUNT * sizeof(struct aac_fib), 1169135446Strhodes aac_map_command_helper, &fibphys, 0); 1170135446Strhodes 1171135446Strhodes /* initialise constant fields in the command structure */ 1172135446Strhodes AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 1173135446Strhodes bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib)); 1174135446Strhodes for (i = 0; i < AAC_FIB_COUNT; i++) { 1175135446Strhodes cm = sc->aac_commands + sc->total_fibs; 1176135446Strhodes fm->aac_commands = cm; 1177135446Strhodes cm->cm_sc = sc; 1178165071Sdougb cm->cm_fib = fm->aac_fibs + i; 1179135446Strhodes cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib)); 1180135446Strhodes cm->cm_index = sc->total_fibs; 1181135446Strhodes 1182135446Strhodes if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1183135446Strhodes &cm->cm_datamap)) == 0) 1184135446Strhodes aac_release_command(cm); 1185135446Strhodes else 1186135446Strhodes break; 1187135446Strhodes sc->total_fibs++; 1188135446Strhodes } 1189135446Strhodes 1190135446Strhodes if (i > 0) { 1191135446Strhodes TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1192135446Strhodes debug(1, "total_fibs= %d\n", sc->total_fibs); 1193135446Strhodes AAC_LOCK_RELEASE(&sc->aac_io_lock); 1194135446Strhodes return (0); 1195135446Strhodes } 1196135446Strhodes 1197135446Strhodes AAC_LOCK_RELEASE(&sc->aac_io_lock); 1198135446Strhodes bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1199170222Sdougb bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1200170222Sdougb free(fm, M_AACBUF); 1201170222Sdougb return (ENOMEM); 1202170222Sdougb} 1203170222Sdougb 1204170222Sdougb/* 1205170222Sdougb * Free FIBs owned by this adapter. 1206170222Sdougb */ 1207170222Sdougbstatic void 1208170222Sdougbaac_free_commands(struct aac_softc *sc) 1209170222Sdougb{ 1210170222Sdougb struct aac_fibmap *fm; 1211186462Sdougb struct aac_command *cm; 1212170222Sdougb int i; 1213170222Sdougb 1214170222Sdougb debug_called(1); 1215170222Sdougb 1216170222Sdougb while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1217170222Sdougb 1218170222Sdougb TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1219170222Sdougb /* 1220170222Sdougb * We check against total_fibs to handle partially 1221224092Sdougb * allocated blocks. 1222170222Sdougb */ 1223170222Sdougb for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) { 1224170222Sdougb cm = fm->aac_commands + i; 1225170222Sdougb bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1226170222Sdougb } 1227170222Sdougb bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1228170222Sdougb bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1229170222Sdougb free(fm, M_AACBUF); 1230170222Sdougb } 1231170222Sdougb} 1232170222Sdougb 1233170222Sdougb/* 1234170222Sdougb * Command-mapping helper function - populate this command's s/g table. 1235170222Sdougb */ 1236170222Sdougbstatic void 1237170222Sdougbaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1238170222Sdougb{ 1239170222Sdougb struct aac_softc *sc; 1240170222Sdougb struct aac_command *cm; 1241170222Sdougb struct aac_fib *fib; 1242170222Sdougb int i; 1243170222Sdougb 1244170222Sdougb debug_called(3); 1245170222Sdougb 1246170222Sdougb cm = (struct aac_command *)arg; 1247170222Sdougb sc = cm->cm_sc; 1248170222Sdougb fib = cm->cm_fib; 1249170222Sdougb 1250170222Sdougb /* copy into the FIB */ 1251170222Sdougb if (cm->cm_sgtable != NULL) { 1252170222Sdougb if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1253170222Sdougb struct aac_sg_table *sg; 1254170222Sdougb sg = cm->cm_sgtable; 1255170222Sdougb sg->SgCount = nseg; 1256170222Sdougb for (i = 0; i < nseg; i++) { 1257170222Sdougb sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1258170222Sdougb sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1259170222Sdougb } 1260193149Sdougb /* update the FIB size for the s/g count */ 1261193149Sdougb fib->Header.Size += nseg * sizeof(struct aac_sg_entry); 1262193149Sdougb } else { 1263193149Sdougb struct aac_sg_table64 *sg; 1264170222Sdougb sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1265193149Sdougb sg->SgCount = nseg; 1266193149Sdougb for (i = 0; i < nseg; i++) { 1267193149Sdougb sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1268193149Sdougb sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1269193149Sdougb } 1270193149Sdougb /* update the FIB size for the s/g count */ 1271193149Sdougb fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1272193149Sdougb } 1273193149Sdougb } 1274193149Sdougb 1275193149Sdougb /* Fix up the address values in the FIB. Use the command array index 1276193149Sdougb * instead of a pointer since these fields are only 32 bits. Shift 1277193149Sdougb * the SenderFibAddress over to make room for the fast response bit. 1278193149Sdougb */ 1279224092Sdougb cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1); 1280224092Sdougb cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys; 1281224092Sdougb 1282224092Sdougb /* save a pointer to the command for speedy reverse-lookup */ 1283224092Sdougb cm->cm_fib->Header.SenderData = cm->cm_index; 1284224092Sdougb 1285224092Sdougb if (cm->cm_flags & AAC_CMD_DATAIN) 1286224092Sdougb bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1287224092Sdougb BUS_DMASYNC_PREREAD); 1288224092Sdougb if (cm->cm_flags & AAC_CMD_DATAOUT) 1289224092Sdougb bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1290224092Sdougb BUS_DMASYNC_PREWRITE); 1291224092Sdougb cm->cm_flags |= AAC_CMD_MAPPED; 1292224092Sdougb 1293193149Sdougb /* put the FIB on the outbound queue */ 1294193149Sdougb if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 1295193149Sdougb aac_remove_busy(cm); 1296193149Sdougb aac_unmap_command(cm); 1297193149Sdougb aac_requeue_ready(cm); 1298193149Sdougb } 1299193149Sdougb 1300193149Sdougb return; 1301193149Sdougb} 1302193149Sdougb 1303193149Sdougb/* 1304193149Sdougb * Unmap a command from controller-visible space. 1305193149Sdougb */ 1306193149Sdougbstatic void 1307193149Sdougbaac_unmap_command(struct aac_command *cm) 1308193149Sdougb{ 1309193149Sdougb struct aac_softc *sc; 1310224092Sdougb 1311224092Sdougb debug_called(2); 1312224092Sdougb 1313224092Sdougb sc = cm->cm_sc; 1314224092Sdougb 1315224092Sdougb if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1316224092Sdougb return; 1317224092Sdougb 1318224092Sdougb if (cm->cm_datalen != 0) { 1319224092Sdougb if (cm->cm_flags & AAC_CMD_DATAIN) 1320224092Sdougb bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1321224092Sdougb BUS_DMASYNC_POSTREAD); 1322224092Sdougb if (cm->cm_flags & AAC_CMD_DATAOUT) 1323224092Sdougb bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1324224092Sdougb BUS_DMASYNC_POSTWRITE); 1325224092Sdougb 1326224092Sdougb bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1327224092Sdougb } 1328224092Sdougb cm->cm_flags &= ~AAC_CMD_MAPPED; 1329224092Sdougb} 1330224092Sdougb 1331224092Sdougb/* 1332224092Sdougb * Hardware Interface 1333224092Sdougb */ 1334224092Sdougb 1335224092Sdougb/* 1336135446Strhodes * Initialise the adapter. 1337224092Sdougb */ 1338224092Sdougbstatic void 1339224092Sdougbaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1340224092Sdougb{ 1341224092Sdougb struct aac_softc *sc; 1342224092Sdougb 1343224092Sdougb debug_called(1); 1344224092Sdougb 1345224092Sdougb sc = (struct aac_softc *)arg; 1346224092Sdougb 1347224092Sdougb sc->aac_common_busaddr = segs[0].ds_addr; 1348224092Sdougb} 1349224092Sdougb 1350224092Sdougbstatic int 1351224092Sdougbaac_check_firmware(struct aac_softc *sc) 1352224092Sdougb{ 1353224092Sdougb u_int32_t major, minor, options; 1354224092Sdougb 1355224092Sdougb debug_called(1); 1356224092Sdougb 1357224092Sdougb /* 1358224092Sdougb * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1359224092Sdougb * firmware version 1.x are not compatible with this driver. 1360224092Sdougb */ 1361236374Sdougb if (sc->flags & AAC_FLAGS_PERC2QC) { 1362224092Sdougb if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1363224092Sdougb NULL)) { 1364224092Sdougb device_printf(sc->aac_dev, 1365224092Sdougb "Error reading firmware version\n"); 1366224092Sdougb return (EIO); 1367224092Sdougb } 1368224092Sdougb 1369224092Sdougb /* These numbers are stored as ASCII! */ 1370224092Sdougb major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1371224092Sdougb minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1372224092Sdougb if (major == 1) { 1373224092Sdougb device_printf(sc->aac_dev, 1374224092Sdougb "Firmware version %d.%d is not supported.\n", 1375224092Sdougb major, minor); 1376224092Sdougb return (EINVAL); 1377224092Sdougb } 1378224092Sdougb } 1379224092Sdougb 1380224092Sdougb /* 1381224092Sdougb * Retrieve the capabilities/supported options word so we know what 1382224092Sdougb * work-arounds to enable. 1383224092Sdougb */ 1384224092Sdougb if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1385224092Sdougb device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1386224092Sdougb return (EIO); 1387224092Sdougb } 1388224092Sdougb options = AAC_GET_MAILBOX(sc, 1); 1389224092Sdougb sc->supported_options = options; 1390224092Sdougb 1391224092Sdougb if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1392224092Sdougb (sc->flags & AAC_FLAGS_NO4GB) == 0) 1393224092Sdougb sc->flags |= AAC_FLAGS_4GB_WINDOW; 1394224092Sdougb if (options & AAC_SUPPORTED_NONDASD) 1395224092Sdougb sc->flags |= AAC_FLAGS_ENABLE_CAM; 1396224092Sdougb if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1397224092Sdougb && (sizeof(bus_addr_t) > 4)) { 1398224092Sdougb device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1399224092Sdougb sc->flags |= AAC_FLAGS_SG_64BIT; 1400224092Sdougb } 1401224092Sdougb 1402224092Sdougb /* Check for broken hardware that does a lower number of commands */ 1403224092Sdougb if ((sc->flags & AAC_FLAGS_256FIBS) == 0) 1404224092Sdougb sc->aac_max_fibs = AAC_MAX_FIBS; 1405224092Sdougb else 1406224092Sdougb sc->aac_max_fibs = 256; 1407224092Sdougb 1408224092Sdougb return (0); 1409224092Sdougb} 1410224092Sdougb 1411224092Sdougbstatic int 1412224092Sdougbaac_init(struct aac_softc *sc) 1413224092Sdougb{ 1414224092Sdougb struct aac_adapter_init *ip; 1415224092Sdougb time_t then; 1416224092Sdougb u_int32_t code, qoffset; 1417224092Sdougb int error; 1418224092Sdougb 1419224092Sdougb debug_called(1); 1420224092Sdougb 1421224092Sdougb /* 1422224092Sdougb * First wait for the adapter to come ready. 1423224092Sdougb */ 1424224092Sdougb then = time_second; 1425224092Sdougb do { 1426224092Sdougb code = AAC_GET_FWSTATUS(sc); 1427224092Sdougb if (code & AAC_SELF_TEST_FAILED) { 1428224092Sdougb device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 1429224092Sdougb return(ENXIO); 1430224092Sdougb } 1431224092Sdougb if (code & AAC_KERNEL_PANIC) { 1432224092Sdougb device_printf(sc->aac_dev, 1433224092Sdougb "FATAL: controller kernel panic\n"); 1434224092Sdougb return(ENXIO); 1435224092Sdougb } 1436224092Sdougb if (time_second > (then + AAC_BOOT_TIMEOUT)) { 1437224092Sdougb device_printf(sc->aac_dev, 1438224092Sdougb "FATAL: controller not coming ready, " 1439224092Sdougb "status %x\n", code); 1440224092Sdougb return(ENXIO); 1441224092Sdougb } 1442224092Sdougb } while (!(code & AAC_UP_AND_RUNNING)); 1443224092Sdougb 1444224092Sdougb error = ENOMEM; 1445224092Sdougb /* 1446224092Sdougb * Create DMA tag for mapping buffers into controller-addressable space. 1447224092Sdougb */ 1448224092Sdougb if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1449224092Sdougb 1, 0, /* algnmnt, boundary */ 1450224092Sdougb (sc->flags & AAC_FLAGS_SG_64BIT) ? 1451224092Sdougb BUS_SPACE_MAXADDR : 1452224092Sdougb BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1453224092Sdougb BUS_SPACE_MAXADDR, /* highaddr */ 1454224092Sdougb NULL, NULL, /* filter, filterarg */ 1455224092Sdougb MAXBSIZE, /* maxsize */ 1456224092Sdougb AAC_MAXSGENTRIES, /* nsegments */ 1457224092Sdougb MAXBSIZE, /* maxsegsize */ 1458224092Sdougb BUS_DMA_ALLOCNOW, /* flags */ 1459224092Sdougb busdma_lock_mutex, /* lockfunc */ 1460224092Sdougb &sc->aac_io_lock, /* lockfuncarg */ 1461224092Sdougb &sc->aac_buffer_dmat)) { 1462224092Sdougb device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1463224092Sdougb goto out; 1464224092Sdougb } 1465224092Sdougb 1466224092Sdougb /* 1467224092Sdougb * Create DMA tag for mapping FIBs into controller-addressable space.. 1468224092Sdougb */ 1469224092Sdougb if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1470224092Sdougb 1, 0, /* algnmnt, boundary */ 1471224092Sdougb (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1472224092Sdougb BUS_SPACE_MAXADDR_32BIT : 1473224092Sdougb 0x7fffffff, /* lowaddr */ 1474224092Sdougb BUS_SPACE_MAXADDR, /* highaddr */ 1475224092Sdougb NULL, NULL, /* filter, filterarg */ 1476224092Sdougb AAC_FIB_COUNT * 1477224092Sdougb sizeof(struct aac_fib), /* maxsize */ 1478224092Sdougb 1, /* nsegments */ 1479224092Sdougb AAC_FIB_COUNT * 1480224092Sdougb sizeof(struct aac_fib), /* maxsegsize */ 1481224092Sdougb BUS_DMA_ALLOCNOW, /* flags */ 1482224092Sdougb NULL, NULL, /* No locking needed */ 1483224092Sdougb &sc->aac_fib_dmat)) { 1484224092Sdougb device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1485224092Sdougb goto out; 1486224092Sdougb } 1487224092Sdougb 1488224092Sdougb /* 1489224092Sdougb * Create DMA tag for the common structure and allocate it. 1490224092Sdougb */ 1491224092Sdougb if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1492224092Sdougb 1, 0, /* algnmnt, boundary */ 1493224092Sdougb (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1494224092Sdougb BUS_SPACE_MAXADDR_32BIT : 1495224092Sdougb 0x7fffffff, /* lowaddr */ 1496224092Sdougb BUS_SPACE_MAXADDR, /* highaddr */ 1497224092Sdougb NULL, NULL, /* filter, filterarg */ 1498224092Sdougb 8192 + sizeof(struct aac_common), /* maxsize */ 1499224092Sdougb 1, /* nsegments */ 1500224092Sdougb BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1501224092Sdougb BUS_DMA_ALLOCNOW, /* flags */ 1502224092Sdougb NULL, NULL, /* No locking needed */ 1503224092Sdougb &sc->aac_common_dmat)) { 1504224092Sdougb device_printf(sc->aac_dev, 1505224092Sdougb "can't allocate common structure DMA tag\n"); 1506224092Sdougb goto out; 1507224092Sdougb } 1508224092Sdougb if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1509224092Sdougb BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 1510224092Sdougb device_printf(sc->aac_dev, "can't allocate common structure\n"); 1511224092Sdougb goto out; 1512224092Sdougb } 1513224092Sdougb 1514224092Sdougb /* 1515224092Sdougb * Work around a bug in the 2120 and 2200 that cannot DMA commands 1516224092Sdougb * below address 8192 in physical memory. 1517224092Sdougb * XXX If the padding is not needed, can it be put to use instead 1518224092Sdougb * of ignored? 1519224092Sdougb */ 1520224092Sdougb (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1521224092Sdougb sc->aac_common, 8192 + sizeof(*sc->aac_common), 1522224092Sdougb aac_common_map, sc, 0); 1523224092Sdougb 1524224092Sdougb if (sc->aac_common_busaddr < 8192) { 1525224092Sdougb (uint8_t *)sc->aac_common += 8192; 1526224092Sdougb sc->aac_common_busaddr += 8192; 1527224092Sdougb } 1528224092Sdougb bzero(sc->aac_common, sizeof(*sc->aac_common)); 1529224092Sdougb 1530224092Sdougb /* Allocate some FIBs and associated command structs */ 1531224092Sdougb TAILQ_INIT(&sc->aac_fibmap_tqh); 1532224092Sdougb sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command), 1533224092Sdougb M_AACBUF, M_WAITOK|M_ZERO); 1534224092Sdougb while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1535224092Sdougb if (aac_alloc_commands(sc) != 0) 1536224092Sdougb break; 1537224092Sdougb } 1538224092Sdougb if (sc->total_fibs == 0) 1539224092Sdougb goto out; 1540224092Sdougb 1541135446Strhodes /* 1542135446Strhodes * Fill in the init structure. This tells the adapter about the 1543135446Strhodes * physical location of various important shared data structures. 1544135446Strhodes */ 1545135446Strhodes ip = &sc->aac_common->ac_init; 1546135446Strhodes ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1547135446Strhodes ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 1548225361Sdougb 1549224092Sdougb ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1550224092Sdougb offsetof(struct aac_common, ac_fibs); 1551224092Sdougb ip->AdapterFibsVirtualAddress = 0; 1552135446Strhodes ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1553165071Sdougb ip->AdapterFibAlign = sizeof(struct aac_fib); 1554165071Sdougb 1555224092Sdougb ip->PrintfBufferAddress = sc->aac_common_busaddr + 1556165071Sdougb offsetof(struct aac_common, ac_printf); 1557165071Sdougb ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1558165071Sdougb 1559165071Sdougb /* 1560165071Sdougb * The adapter assumes that pages are 4K in size, except on some 1561165071Sdougb * broken firmware versions that do the page->byte conversion twice, 1562186462Sdougb * therefore 'assuming' that this value is in 16MB units (2^24). 1563186462Sdougb * Round up since the granularity is so high. 1564186462Sdougb */ 1565165071Sdougb ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1566165071Sdougb if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1567165071Sdougb ip->HostPhysMemPages = 1568135446Strhodes (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1569135446Strhodes } 1570135446Strhodes ip->HostElapsedSeconds = time_second; /* reset later if invalid */ 1571135446Strhodes 1572224092Sdougb /* 1573135446Strhodes * Initialise FIB queues. Note that it appears that the layout of the 1574170222Sdougb * indexes and the segmentation of the entries may be mandated by the 1575135446Strhodes * adapter, which is only told about the base of the queue index fields. 1576224092Sdougb * 1577135446Strhodes * The initial values of the indices are assumed to inform the adapter 1578225361Sdougb * of the sizes of the respective queues, and theoretically it could 1579135446Strhodes * work out the entire layout of the queue structures from this. We 1580135446Strhodes * take the easy route and just lay this area out like everyone else 1581135446Strhodes * does. 1582224092Sdougb * 1583224092Sdougb * The Linux driver uses a much more complex scheme whereby several 1584135446Strhodes * header records are kept for each queue. We use a couple of generic 1585224092Sdougb * list manipulation functions which 'know' the size of each list by 1586135446Strhodes * virtue of a table. 1587135446Strhodes */ 1588193149Sdougb qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 1589170222Sdougb qoffset &= ~(AAC_QUEUE_ALIGN - 1); 1590170222Sdougb sc->aac_queues = 1591170222Sdougb (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1592170222Sdougb ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 1593170222Sdougb 1594170222Sdougb sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1595170222Sdougb AAC_HOST_NORM_CMD_ENTRIES; 1596170222Sdougb sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1597193149Sdougb AAC_HOST_NORM_CMD_ENTRIES; 1598193149Sdougb sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1599224092Sdougb AAC_HOST_HIGH_CMD_ENTRIES; 1600224092Sdougb sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1601224092Sdougb AAC_HOST_HIGH_CMD_ENTRIES; 1602193149Sdougb sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1603224092Sdougb AAC_ADAP_NORM_CMD_ENTRIES; 1604224092Sdougb sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1605225361Sdougb AAC_ADAP_NORM_CMD_ENTRIES; 1606135446Strhodes sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1607135446Strhodes AAC_ADAP_HIGH_CMD_ENTRIES; 1608135446Strhodes sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1609135446Strhodes AAC_ADAP_HIGH_CMD_ENTRIES; 1610135446Strhodes sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1611135446Strhodes AAC_HOST_NORM_RESP_ENTRIES; 1612224092Sdougb sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1613224092Sdougb AAC_HOST_NORM_RESP_ENTRIES; 1614224092Sdougb sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1615224092Sdougb AAC_HOST_HIGH_RESP_ENTRIES; 1616224092Sdougb sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1617135446Strhodes AAC_HOST_HIGH_RESP_ENTRIES; 1618135446Strhodes sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1619135446Strhodes AAC_ADAP_NORM_RESP_ENTRIES; 1620224092Sdougb sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1621224092Sdougb AAC_ADAP_NORM_RESP_ENTRIES; 1622135446Strhodes sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1623224092Sdougb AAC_ADAP_HIGH_RESP_ENTRIES; 1624135446Strhodes sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1625224092Sdougb AAC_ADAP_HIGH_RESP_ENTRIES; 1626224092Sdougb sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1627224092Sdougb &sc->aac_queues->qt_HostNormCmdQueue[0]; 1628135446Strhodes sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1629135446Strhodes &sc->aac_queues->qt_HostHighCmdQueue[0]; 1630224092Sdougb sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1631135446Strhodes &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1632224092Sdougb sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1633224092Sdougb &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1634135446Strhodes sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1635170222Sdougb &sc->aac_queues->qt_HostNormRespQueue[0]; 1636170222Sdougb sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1637170222Sdougb &sc->aac_queues->qt_HostHighRespQueue[0]; 1638170222Sdougb sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1639225361Sdougb &sc->aac_queues->qt_AdapNormRespQueue[0]; 1640170222Sdougb sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1641170222Sdougb &sc->aac_queues->qt_AdapHighRespQueue[0]; 1642135446Strhodes 1643135446Strhodes /* 1644135446Strhodes * Do controller-type-specific initialisation 1645135446Strhodes */ 1646135446Strhodes switch (sc->aac_hwif) { 1647135446Strhodes case AAC_HWIF_I960RX: 1648135446Strhodes AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 1649170222Sdougb break; 1650170222Sdougb } 1651170222Sdougb 1652170222Sdougb /* 1653170222Sdougb * Give the init structure to the controller. 1654170222Sdougb */ 1655170222Sdougb if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1656170222Sdougb sc->aac_common_busaddr + 1657170222Sdougb offsetof(struct aac_common, ac_init), 0, 0, 0, 1658170222Sdougb NULL)) { 1659170222Sdougb device_printf(sc->aac_dev, 1660193149Sdougb "error establishing init structure\n"); 1661170222Sdougb error = EIO; 1662170222Sdougb goto out; 1663170222Sdougb } 1664170222Sdougb 1665170222Sdougb error = 0; 1666170222Sdougbout: 1667170222Sdougb return(error); 1668170222Sdougb} 1669170222Sdougb 1670170222Sdougb/* 1671170222Sdougb * Send a synchronous command to the controller and wait for a result. 1672170222Sdougb */ 1673170222Sdougbstatic int 1674170222Sdougbaac_sync_command(struct aac_softc *sc, u_int32_t command, 1675170222Sdougb u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 1676170222Sdougb u_int32_t *sp) 1677170222Sdougb{ 1678170222Sdougb time_t then; 1679170222Sdougb u_int32_t status; 1680170222Sdougb 1681170222Sdougb debug_called(3); 1682170222Sdougb 1683170222Sdougb /* populate the mailbox */ 1684170222Sdougb AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 1685170222Sdougb 1686170222Sdougb /* ensure the sync command doorbell flag is cleared */ 1687170222Sdougb AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1688170222Sdougb 1689170222Sdougb /* then set it to signal the adapter */ 1690170222Sdougb AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 1691170222Sdougb 1692170222Sdougb /* spin waiting for the command to complete */ 1693170222Sdougb then = time_second; 1694170222Sdougb do { 1695224092Sdougb if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { 1696216175Sdougb debug(1, "timed out"); 1697216175Sdougb return(EIO); 1698224092Sdougb } 1699224092Sdougb } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 1700224092Sdougb 1701216175Sdougb /* clear the completion flag */ 1702216175Sdougb AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1703170222Sdougb 1704135446Strhodes /* get the command status */ 1705135446Strhodes status = AAC_GET_MAILBOX(sc, 0); 1706135446Strhodes if (sp != NULL) 1707135446Strhodes *sp = status; 1708135446Strhodes return(0); 1709135446Strhodes} 1710135446Strhodes 1711225361Sdougb/* 1712225361Sdougb * Grab the sync fib area. 1713225361Sdougb */ 1714225361Sdougbint 1715135446Strhodesaac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags) 1716135446Strhodes{ 1717135446Strhodes 1718135446Strhodes /* 1719165071Sdougb * If the force flag is set, the system is shutting down, or in 1720135446Strhodes * trouble. Ignore the mutex. 1721224092Sdougb */ 1722135446Strhodes if (!(flags & AAC_SYNC_LOCK_FORCE)) 1723135446Strhodes AAC_LOCK_ACQUIRE(&sc->aac_sync_lock); 1724224092Sdougb 1725224092Sdougb *fib = &sc->aac_common->ac_sync_fib; 1726224092Sdougb 1727224092Sdougb return (1); 1728224092Sdougb} 1729225361Sdougb 1730225361Sdougb/* 1731224092Sdougb * Release the sync fib area. 1732224092Sdougb */ 1733224092Sdougbvoid 1734224092Sdougbaac_release_sync_fib(struct aac_softc *sc) 1735224092Sdougb{ 1736225361Sdougb 1737225361Sdougb AAC_LOCK_RELEASE(&sc->aac_sync_lock); 1738225361Sdougb} 1739225361Sdougb 1740225361Sdougb/* 1741225361Sdougb * Send a synchronous FIB to the controller and wait for a result. 1742225361Sdougb */ 1743225361Sdougbint 1744225361Sdougbaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1745225361Sdougb struct aac_fib *fib, u_int16_t datasize) 1746225361Sdougb{ 1747224092Sdougb debug_called(3); 1748224092Sdougb 1749224092Sdougb if (datasize > AAC_FIB_DATASIZE) 1750135446Strhodes return(EINVAL); 1751170222Sdougb 1752170222Sdougb /* 1753170222Sdougb * Set up the sync FIB 1754170222Sdougb */ 1755170222Sdougb fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1756170222Sdougb AAC_FIBSTATE_INITIALISED | 1757170222Sdougb AAC_FIBSTATE_EMPTY; 1758170222Sdougb fib->Header.XferState |= xferstate; 1759170222Sdougb fib->Header.Command = command; 1760170222Sdougb fib->Header.StructType = AAC_FIBTYPE_TFIB; 1761170222Sdougb fib->Header.Size = sizeof(struct aac_fib) + datasize; 1762170222Sdougb fib->Header.SenderSize = sizeof(struct aac_fib); 1763170222Sdougb fib->Header.SenderFibAddress = 0; /* Not needed */ 1764170222Sdougb fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 1765170222Sdougb offsetof(struct aac_common, 1766170222Sdougb ac_sync_fib); 1767170222Sdougb 1768170222Sdougb /* 1769186462Sdougb * Give the FIB to the controller, wait for a response. 1770170222Sdougb */ 1771170222Sdougb if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 1772170222Sdougb fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 1773170222Sdougb debug(2, "IO error"); 1774170222Sdougb return(EIO); 1775170222Sdougb } 1776170222Sdougb 1777170222Sdougb return (0); 1778170222Sdougb} 1779170222Sdougb 1780170222Sdougb/* 1781170222Sdougb * Adapter-space FIB queue manipulation 1782170222Sdougb * 1783170222Sdougb * Note that the queue implementation here is a little funky; neither the PI or 1784224092Sdougb * CI will ever be zero. This behaviour is a controller feature. 1785224092Sdougb */ 1786224092Sdougbstatic struct { 1787224092Sdougb int size; 1788224092Sdougb int notify; 1789224092Sdougb} aac_qinfo[] = { 1790224092Sdougb {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 1791224092Sdougb {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 1792170222Sdougb {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 1793170222Sdougb {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 1794170222Sdougb {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 1795170222Sdougb {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 1796193149Sdougb {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 1797193149Sdougb {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 1798193149Sdougb}; 1799224092Sdougb 1800224092Sdougb/* 1801224092Sdougb * Atomically insert an entry into the nominated queue, returns 0 on success or 1802224092Sdougb * EBUSY if the queue is full. 1803224092Sdougb * 1804224092Sdougb * Note: it would be more efficient to defer notifying the controller in 1805224092Sdougb * the case where we may be inserting several entries in rapid succession, 1806224092Sdougb * but implementing this usefully may be difficult (it would involve a 1807224092Sdougb * separate queue/notify interface). 1808224092Sdougb */ 1809224092Sdougbstatic int 1810224092Sdougbaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 1811224092Sdougb{ 1812224092Sdougb u_int32_t pi, ci; 1813224092Sdougb int error; 1814224092Sdougb u_int32_t fib_size; 1815224092Sdougb u_int32_t fib_addr; 1816224092Sdougb 1817224092Sdougb debug_called(3); 1818224092Sdougb 1819224092Sdougb fib_size = cm->cm_fib->Header.Size; 1820224092Sdougb fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 1821224092Sdougb 1822224092Sdougb /* get the producer/consumer indices */ 1823224092Sdougb pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 1824224092Sdougb ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 1825193149Sdougb 1826193149Sdougb /* wrap the queue? */ 1827193149Sdougb if (pi >= aac_qinfo[queue].size) 1828193149Sdougb pi = 0; 1829193149Sdougb 1830193149Sdougb /* check for queue full */ 1831193149Sdougb if ((pi + 1) == ci) { 1832193149Sdougb error = EBUSY; 1833193149Sdougb goto out; 1834193149Sdougb } 1835193149Sdougb 1836193149Sdougb /* populate queue entry */ 1837193149Sdougb (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 1838193149Sdougb (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 1839193149Sdougb 1840193149Sdougb /* update producer index */ 1841193149Sdougb sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 1842193149Sdougb 1843193149Sdougb /* 1844193149Sdougb * To avoid a race with its completion interrupt, place this command on 1845193149Sdougb * the busy queue prior to advertising it to the controller. 1846193149Sdougb */ 1847193149Sdougb aac_enqueue_busy(cm); 1848193149Sdougb 1849224092Sdougb /* notify the adapter if we know how */ 1850224092Sdougb if (aac_qinfo[queue].notify != 0) 1851224092Sdougb AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 1852224092Sdougb 1853224092Sdougb error = 0; 1854224092Sdougb 1855224092Sdougbout: 1856224092Sdougb return(error); 1857224092Sdougb} 1858224092Sdougb 1859224092Sdougb/* 1860224092Sdougb * Atomically remove one entry from the nominated queue, returns 0 on 1861224092Sdougb * success or ENOENT if the queue is empty. 1862224092Sdougb */ 1863224092Sdougbstatic int 1864224092Sdougbaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 1865224092Sdougb struct aac_fib **fib_addr) 1866224092Sdougb{ 1867224092Sdougb u_int32_t pi, ci; 1868224092Sdougb u_int32_t fib_index; 1869224092Sdougb int error; 1870224092Sdougb int notify; 1871224092Sdougb 1872224092Sdougb debug_called(3); 1873224092Sdougb 1874224092Sdougb /* get the producer/consumer indices */ 1875224092Sdougb pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 1876224092Sdougb ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 1877224092Sdougb 1878224092Sdougb /* check for queue empty */ 1879224092Sdougb if (ci == pi) { 1880224092Sdougb error = ENOENT; 1881224092Sdougb goto out; 1882224092Sdougb } 1883224092Sdougb 1884224092Sdougb /* wrap the pi so the following test works */ 1885224092Sdougb if (pi >= aac_qinfo[queue].size) 1886224092Sdougb pi = 0; 1887224092Sdougb 1888224092Sdougb notify = 0; 1889224092Sdougb if (ci == pi + 1) 1890224092Sdougb notify++; 1891224092Sdougb 1892224092Sdougb /* wrap the queue? */ 1893224092Sdougb if (ci >= aac_qinfo[queue].size) 1894224092Sdougb ci = 0; 1895224092Sdougb 1896224092Sdougb /* fetch the entry */ 1897224092Sdougb *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 1898224092Sdougb 1899224092Sdougb switch (queue) { 1900224092Sdougb case AAC_HOST_NORM_CMD_QUEUE: 1901224092Sdougb case AAC_HOST_HIGH_CMD_QUEUE: 1902224092Sdougb /* 1903224092Sdougb * The aq_fib_addr is only 32 bits wide so it can't be counted 1904224092Sdougb * on to hold an address. For AIF's, the adapter assumes 1905224092Sdougb * that it's giving us an address into the array of AIF fibs. 1906224092Sdougb * Therefore, we have to convert it to an index. 1907224092Sdougb */ 1908224092Sdougb fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 1909224092Sdougb sizeof(struct aac_fib); 1910224092Sdougb *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 1911224092Sdougb break; 1912224092Sdougb 1913224092Sdougb case AAC_HOST_NORM_RESP_QUEUE: 1914224092Sdougb case AAC_HOST_HIGH_RESP_QUEUE: 1915224092Sdougb { 1916224092Sdougb struct aac_command *cm; 1917224092Sdougb 1918224092Sdougb /* 1919224092Sdougb * As above, an index is used instead of an actual address. 1920224092Sdougb * Gotta shift the index to account for the fast response 1921224092Sdougb * bit. No other correction is needed since this value was 1922224092Sdougb * originally provided by the driver via the SenderFibAddress 1923224092Sdougb * field. 1924224092Sdougb */ 1925224092Sdougb fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 1926224092Sdougb cm = sc->aac_commands + (fib_index >> 1); 1927224092Sdougb *fib_addr = cm->cm_fib; 1928224092Sdougb 1929224092Sdougb /* 1930224092Sdougb * Is this a fast response? If it is, update the fib fields in 1931224092Sdougb * local memory since the whole fib isn't DMA'd back up. 1932224092Sdougb */ 1933224092Sdougb if (fib_index & 0x01) { 1934224092Sdougb (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 1935224092Sdougb *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 1936224092Sdougb } 1937224092Sdougb break; 1938224092Sdougb } 1939224092Sdougb default: 1940224092Sdougb panic("Invalid queue in aac_dequeue_fib()"); 1941224092Sdougb break; 1942224092Sdougb } 1943224092Sdougb 1944224092Sdougb /* update consumer index */ 1945224092Sdougb sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 1946224092Sdougb 1947224092Sdougb /* if we have made the queue un-full, notify the adapter */ 1948224092Sdougb if (notify && (aac_qinfo[queue].notify != 0)) 1949224092Sdougb AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 1950224092Sdougb error = 0; 1951224092Sdougb 1952193149Sdougbout: 1953193149Sdougb return(error); 1954193149Sdougb} 1955193149Sdougb 1956193149Sdougb/* 1957193149Sdougb * Put our response to an Adapter Initialed Fib on the response queue 1958193149Sdougb */ 1959224092Sdougbstatic int 1960224092Sdougbaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 1961224092Sdougb{ 1962224092Sdougb u_int32_t pi, ci; 1963224092Sdougb int error; 1964224092Sdougb u_int32_t fib_size; 1965224092Sdougb u_int32_t fib_addr; 1966193149Sdougb 1967193149Sdougb debug_called(1); 1968193149Sdougb 1969193149Sdougb /* Tell the adapter where the FIB is */ 1970193149Sdougb fib_size = fib->Header.Size; 1971193149Sdougb fib_addr = fib->Header.SenderFibAddress; 1972193149Sdougb fib->Header.ReceiverFibAddress = fib_addr; 1973193149Sdougb 1974193149Sdougb /* get the producer/consumer indices */ 1975193149Sdougb pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 1976193149Sdougb ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 1977193149Sdougb 1978193149Sdougb /* wrap the queue? */ 1979193149Sdougb if (pi >= aac_qinfo[queue].size) 1980224092Sdougb pi = 0; 1981135446Strhodes 1982224092Sdougb /* check for queue full */ 1983224092Sdougb if ((pi + 1) == ci) { 1984224092Sdougb error = EBUSY; 1985224092Sdougb goto out; 1986224092Sdougb } 1987224092Sdougb 1988224092Sdougb /* populate queue entry */ 1989224092Sdougb (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 1990224092Sdougb (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 1991224092Sdougb 1992224092Sdougb /* update producer index */ 1993193149Sdougb sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 1994193149Sdougb 1995224092Sdougb /* notify the adapter if we know how */ 1996224092Sdougb if (aac_qinfo[queue].notify != 0) 1997224092Sdougb AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 1998224092Sdougb 1999224092Sdougb error = 0; 2000224092Sdougb 2001135446Strhodesout: 2002224092Sdougb return(error); 2003224092Sdougb} 2004224092Sdougb 2005224092Sdougb/* 2006224092Sdougb * Check for commands that have been outstanding for a suspiciously long time, 2007224092Sdougb * and complain about them. 2008224092Sdougb */ 2009224092Sdougbstatic void 2010224092Sdougbaac_timeout(struct aac_softc *sc) 2011224092Sdougb{ 2012224092Sdougb struct aac_command *cm; 2013193149Sdougb time_t deadline; 2014224092Sdougb 2015224092Sdougb /* 2016193149Sdougb * Traverse the busy command list, bitch about late commands once 2017224092Sdougb * only. 2018224092Sdougb */ 2019224092Sdougb deadline = time_second - AAC_CMD_TIMEOUT; 2020193149Sdougb TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2021224092Sdougb if ((cm->cm_timestamp < deadline) 2022224092Sdougb /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 2023224092Sdougb cm->cm_flags |= AAC_CMD_TIMEDOUT; 2024224092Sdougb device_printf(sc->aac_dev, 2025224092Sdougb "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2026224092Sdougb cm, (int)(time_second-cm->cm_timestamp)); 2027224092Sdougb AAC_PRINT_FIB(sc, cm->cm_fib); 2028224092Sdougb } 2029224092Sdougb } 2030224092Sdougb 2031224092Sdougb return; 2032224092Sdougb} 2033224092Sdougb 2034224092Sdougb/* 2035224092Sdougb * Interface Function Vectors 2036224092Sdougb */ 2037224092Sdougb 2038224092Sdougb/* 2039224092Sdougb * Read the current firmware status word. 2040224092Sdougb */ 2041224092Sdougbstatic int 2042224092Sdougbaac_sa_get_fwstatus(struct aac_softc *sc) 2043224092Sdougb{ 2044224092Sdougb debug_called(3); 2045224092Sdougb 2046224092Sdougb return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 2047224092Sdougb} 2048224092Sdougb 2049224092Sdougbstatic int 2050224092Sdougbaac_rx_get_fwstatus(struct aac_softc *sc) 2051224092Sdougb{ 2052224092Sdougb debug_called(3); 2053224092Sdougb 2054224092Sdougb return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 2055224092Sdougb} 2056224092Sdougb 2057224092Sdougbstatic int 2058224092Sdougbaac_fa_get_fwstatus(struct aac_softc *sc) 2059224092Sdougb{ 2060224092Sdougb int val; 2061224092Sdougb 2062224092Sdougb debug_called(3); 2063224092Sdougb 2064224092Sdougb val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2065225361Sdougb return (val); 2066225361Sdougb} 2067225361Sdougb 2068225361Sdougb/* 2069224092Sdougb * Notify the controller of a change in a given queue 2070224092Sdougb */ 2071224092Sdougb 2072225361Sdougbstatic void 2073225361Sdougbaac_sa_qnotify(struct aac_softc *sc, int qbit) 2074225361Sdougb{ 2075224092Sdougb debug_called(3); 2076224092Sdougb 2077224092Sdougb AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 2078225361Sdougb} 2079225361Sdougb 2080224092Sdougbstatic void 2081224092Sdougbaac_rx_qnotify(struct aac_softc *sc, int qbit) 2082224092Sdougb{ 2083224092Sdougb debug_called(3); 2084224092Sdougb 2085224092Sdougb AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 2086224092Sdougb} 2087224092Sdougb 2088224092Sdougbstatic void 2089224092Sdougbaac_fa_qnotify(struct aac_softc *sc, int qbit) 2090224092Sdougb{ 2091224092Sdougb debug_called(3); 2092224092Sdougb 2093193149Sdougb AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2094224092Sdougb AAC_FA_HACK(sc); 2095135446Strhodes} 2096135446Strhodes 2097135446Strhodes/* 2098135446Strhodes * Get the interrupt reason bits 2099135446Strhodes */ 2100135446Strhodesstatic int 2101135446Strhodesaac_sa_get_istatus(struct aac_softc *sc) 2102135446Strhodes{ 2103135446Strhodes debug_called(3); 2104224092Sdougb 2105135446Strhodes return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 2106135446Strhodes} 2107135446Strhodes 2108224092Sdougbstatic int 2109135446Strhodesaac_rx_get_istatus(struct aac_softc *sc) 2110135446Strhodes{ 2111135446Strhodes debug_called(3); 2112135446Strhodes 2113135446Strhodes return(AAC_GETREG4(sc, AAC_RX_ODBR)); 2114135446Strhodes} 2115135446Strhodes 2116135446Strhodesstatic int 2117135446Strhodesaac_fa_get_istatus(struct aac_softc *sc) 2118186462Sdougb{ 2119186462Sdougb int val; 2120186462Sdougb 2121186462Sdougb debug_called(3); 2122186462Sdougb 2123186462Sdougb val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2124135446Strhodes return (val); 2125135446Strhodes} 2126135446Strhodes 2127135446Strhodes/* 2128135446Strhodes * Clear some interrupt reason bits 2129135446Strhodes */ 2130135446Strhodesstatic void 2131135446Strhodesaac_sa_clear_istatus(struct aac_softc *sc, int mask) 2132135446Strhodes{ 2133193149Sdougb debug_called(3); 2134135446Strhodes 2135135446Strhodes AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 2136193149Sdougb} 2137193149Sdougb 2138193149Sdougbstatic void 2139193149Sdougbaac_rx_clear_istatus(struct aac_softc *sc, int mask) 2140193149Sdougb{ 2141193149Sdougb debug_called(3); 2142193149Sdougb 2143193149Sdougb AAC_SETREG4(sc, AAC_RX_ODBR, mask); 2144193149Sdougb} 2145135446Strhodes 2146224092Sdougbstatic void 2147224092Sdougbaac_fa_clear_istatus(struct aac_softc *sc, int mask) 2148135446Strhodes{ 2149135446Strhodes debug_called(3); 2150135446Strhodes 2151135446Strhodes AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2152135446Strhodes AAC_FA_HACK(sc); 2153135446Strhodes} 2154224092Sdougb 2155224092Sdougb/* 2156224092Sdougb * Populate the mailbox and set the command word 2157224092Sdougb */ 2158224092Sdougbstatic void 2159224092Sdougbaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2160224092Sdougb u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2161224092Sdougb{ 2162224092Sdougb debug_called(4); 2163135446Strhodes 2164135446Strhodes AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 2165135446Strhodes AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2166135446Strhodes AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2167135446Strhodes AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2168135446Strhodes AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 2169135446Strhodes} 2170135446Strhodes 2171135446Strhodesstatic void 2172135446Strhodesaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 2173135446Strhodes u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2174135446Strhodes{ 2175135446Strhodes debug_called(4); 2176170222Sdougb 2177135446Strhodes AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 2178224092Sdougb AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2179224092Sdougb AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2180224092Sdougb AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2181224092Sdougb AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 2182224092Sdougb} 2183224092Sdougb 2184224092Sdougbstatic void 2185224092Sdougbaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2186224092Sdougb u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2187224092Sdougb{ 2188224092Sdougb debug_called(4); 2189224092Sdougb 2190135446Strhodes AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2191135446Strhodes AAC_FA_HACK(sc); 2192135446Strhodes AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2193135446Strhodes AAC_FA_HACK(sc); 2194135446Strhodes AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2195135446Strhodes AAC_FA_HACK(sc); 2196135446Strhodes AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2197135446Strhodes AAC_FA_HACK(sc); 2198135446Strhodes AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2199135446Strhodes AAC_FA_HACK(sc); 2200135446Strhodes} 2201186462Sdougb 2202135446Strhodes/* 2203170222Sdougb * Fetch the immediate command status word 2204170222Sdougb */ 2205170222Sdougbstatic int 2206170222Sdougbaac_sa_get_mailbox(struct aac_softc *sc, int mb) 2207170222Sdougb{ 2208170222Sdougb debug_called(4); 2209170222Sdougb 2210170222Sdougb return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 2211170222Sdougb} 2212170222Sdougb 2213170222Sdougbstatic int 2214170222Sdougbaac_rx_get_mailbox(struct aac_softc *sc, int mb) 2215170222Sdougb{ 2216135446Strhodes debug_called(4); 2217135446Strhodes 2218135446Strhodes return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 2219135446Strhodes} 2220135446Strhodes 2221135446Strhodesstatic int 2222135446Strhodesaac_fa_get_mailbox(struct aac_softc *sc, int mb) 2223135446Strhodes{ 2224135446Strhodes int val; 2225135446Strhodes 2226135446Strhodes debug_called(4); 2227135446Strhodes 2228135446Strhodes val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2229135446Strhodes return (val); 2230135446Strhodes} 2231135446Strhodes 2232135446Strhodes/* 2233135446Strhodes * Set/clear interrupt masks 2234135446Strhodes */ 2235135446Strhodesstatic void 2236135446Strhodesaac_sa_set_interrupts(struct aac_softc *sc, int enable) 2237135446Strhodes{ 2238186462Sdougb debug(2, "%sable interrupts", enable ? "en" : "dis"); 2239135446Strhodes 2240135446Strhodes if (enable) { 2241135446Strhodes AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2242135446Strhodes } else { 2243135446Strhodes AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 2244135446Strhodes } 2245135446Strhodes} 2246135446Strhodes 2247135446Strhodesstatic void 2248135446Strhodesaac_rx_set_interrupts(struct aac_softc *sc, int enable) 2249135446Strhodes{ 2250135446Strhodes debug(2, "%sable interrupts", enable ? "en" : "dis"); 2251135446Strhodes 2252135446Strhodes if (enable) { 2253135446Strhodes AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 2254135446Strhodes } else { 2255135446Strhodes AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 2256135446Strhodes } 2257135446Strhodes} 2258186462Sdougb 2259135446Strhodesstatic void 2260135446Strhodesaac_fa_set_interrupts(struct aac_softc *sc, int enable) 2261135446Strhodes{ 2262135446Strhodes debug(2, "%sable interrupts", enable ? "en" : "dis"); 2263135446Strhodes 2264135446Strhodes if (enable) { 2265135446Strhodes AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2266135446Strhodes AAC_FA_HACK(sc); 2267135446Strhodes } else { 2268135446Strhodes AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2269135446Strhodes AAC_FA_HACK(sc); 2270135446Strhodes } 2271135446Strhodes} 2272135446Strhodes 2273135446Strhodes/* 2274135446Strhodes * Debugging and Diagnostics 2275135446Strhodes */ 2276135446Strhodes 2277135446Strhodes/* 2278135446Strhodes * Print some information about the controller. 2279135446Strhodes */ 2280224092Sdougbstatic void 2281224092Sdougbaac_describe_controller(struct aac_softc *sc) 2282224092Sdougb{ 2283224092Sdougb struct aac_fib *fib; 2284135446Strhodes struct aac_adapter_info *info; 2285224092Sdougb 2286135446Strhodes debug_called(2); 2287135446Strhodes 2288224092Sdougb aac_alloc_sync_fib(sc, &fib, 0); 2289224092Sdougb 2290224092Sdougb fib->data[0] = 0; 2291224092Sdougb if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 2292224092Sdougb device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2293224092Sdougb aac_release_sync_fib(sc); 2294224092Sdougb return; 2295224092Sdougb } 2296224092Sdougb info = (struct aac_adapter_info *)&fib->data[0]; 2297224092Sdougb 2298224092Sdougb device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n", 2299224092Sdougb aac_describe_code(aac_cpu_variant, info->CpuVariant), 2300224092Sdougb info->ClockSpeed, info->BufferMem / (1024 * 1024), 2301224092Sdougb aac_describe_code(aac_battery_platform, 2302224092Sdougb info->batteryPlatform)); 2303224092Sdougb 2304135446Strhodes /* save the kernel revision structure for later use */ 2305135446Strhodes sc->aac_revision = info->KernelRevision; 2306135446Strhodes device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2307165071Sdougb info->KernelRevision.external.comp.major, 2308165071Sdougb info->KernelRevision.external.comp.minor, 2309135446Strhodes info->KernelRevision.external.comp.dash, 2310135446Strhodes info->KernelRevision.buildNumber, 2311135446Strhodes (u_int32_t)(info->SerialNumber & 0xffffff)); 2312135446Strhodes 2313135446Strhodes aac_release_sync_fib(sc); 2314135446Strhodes 2315135446Strhodes if (1 || bootverbose) { 2316135446Strhodes device_printf(sc->aac_dev, "Supported Options=%b\n", 2317165071Sdougb sc->supported_options, 2318135446Strhodes "\20" 2319135446Strhodes "\1SNAPSHOT" 2320135446Strhodes "\2CLUSTERS" 2321135446Strhodes "\3WCACHE" 2322135446Strhodes "\4DATA64" 2323135446Strhodes "\5HOSTTIME" 2324135446Strhodes "\6RAID50" 2325135446Strhodes "\7WINDOW4GB" 2326135446Strhodes "\10SCSIUPGD" 2327135446Strhodes "\11SOFTERR" 2328135446Strhodes "\12NORECOND" 2329135446Strhodes "\13SGMAP64" 2330135446Strhodes "\14ALARM" 2331135446Strhodes "\15NONDASD"); 2332165071Sdougb } 2333165071Sdougb} 2334135446Strhodes 2335135446Strhodes/* 2336135446Strhodes * Look up a text description of a numeric error code and return a pointer to 2337135446Strhodes * same. 2338135446Strhodes */ 2339135446Strhodesstatic char * 2340135446Strhodesaac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2341165071Sdougb{ 2342135446Strhodes int i; 2343135446Strhodes 2344135446Strhodes for (i = 0; table[i].string != NULL; i++) 2345135446Strhodes if (table[i].code == code) 2346135446Strhodes return(table[i].string); 2347135446Strhodes return(table[i + 1].string); 2348135446Strhodes} 2349135446Strhodes 2350135446Strhodes/* 2351135446Strhodes * Management Interface 2352135446Strhodes */ 2353135446Strhodes 2354135446Strhodesstatic int 2355135446Strhodesaac_open(dev_t dev, int flags, int fmt, d_thread_t *td) 2356135446Strhodes{ 2357135446Strhodes struct aac_softc *sc; 2358224092Sdougb 2359135446Strhodes debug_called(2); 2360224092Sdougb 2361224092Sdougb sc = dev->si_drv1; 2362135446Strhodes 2363135446Strhodes /* Check to make sure the device isn't already open */ 2364135446Strhodes if (sc->aac_state & AAC_STATE_OPEN) { 2365135446Strhodes return EBUSY; 2366135446Strhodes } 2367165071Sdougb sc->aac_state |= AAC_STATE_OPEN; 2368135446Strhodes 2369135446Strhodes return 0; 2370135446Strhodes} 2371135446Strhodes 2372135446Strhodesstatic int 2373135446Strhodesaac_close(dev_t dev, int flags, int fmt, d_thread_t *td) 2374135446Strhodes{ 2375135446Strhodes struct aac_softc *sc; 2376135446Strhodes 2377135446Strhodes debug_called(2); 2378135446Strhodes 2379135446Strhodes sc = dev->si_drv1; 2380135446Strhodes 2381135446Strhodes /* Mark this unit as no longer open */ 2382135446Strhodes sc->aac_state &= ~AAC_STATE_OPEN; 2383135446Strhodes 2384135446Strhodes return 0; 2385135446Strhodes} 2386135446Strhodes 2387135446Strhodesstatic int 2388135446Strhodesaac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 2389135446Strhodes{ 2390135446Strhodes union aac_statrequest *as; 2391135446Strhodes struct aac_softc *sc; 2392135446Strhodes int error = 0; 2393135446Strhodes uint32_t cookie; 2394135446Strhodes 2395135446Strhodes debug_called(2); 2396135446Strhodes 2397135446Strhodes as = (union aac_statrequest *)arg; 2398135446Strhodes sc = dev->si_drv1; 2399135446Strhodes 2400135446Strhodes switch (cmd) { 2401186462Sdougb case AACIO_STATS: 2402135446Strhodes switch (as->as_item) { 2403135446Strhodes case AACQ_FREE: 2404135446Strhodes case AACQ_BIO: 2405135446Strhodes case AACQ_READY: 2406135446Strhodes case AACQ_BUSY: 2407135446Strhodes bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2408135446Strhodes sizeof(struct aac_qstat)); 2409135446Strhodes break; 2410135446Strhodes default: 2411135446Strhodes error = ENOENT; 2412135446Strhodes break; 2413135446Strhodes } 2414135446Strhodes break; 2415135446Strhodes 2416135446Strhodes case FSACTL_SENDFIB: 2417135446Strhodes arg = *(caddr_t*)arg; 2418135446Strhodes case FSACTL_LNX_SENDFIB: 2419135446Strhodes debug(1, "FSACTL_SENDFIB"); 2420135446Strhodes error = aac_ioctl_sendfib(sc, arg); 2421135446Strhodes break; 2422135446Strhodes case FSACTL_AIF_THREAD: 2423135446Strhodes case FSACTL_LNX_AIF_THREAD: 2424135446Strhodes debug(1, "FSACTL_AIF_THREAD"); 2425135446Strhodes error = EINVAL; 2426135446Strhodes break; 2427135446Strhodes case FSACTL_OPEN_GET_ADAPTER_FIB: 2428171577Sdougb arg = *(caddr_t*)arg; 2429193149Sdougb case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2430193149Sdougb debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2431171577Sdougb /* 2432171577Sdougb * Pass the caller out an AdapterFibContext. 2433224092Sdougb * 2434216175Sdougb * Note that because we only support one opener, we 2435224092Sdougb * basically ignore this. Set the caller's context to a magic 2436216175Sdougb * number just in case. 2437216175Sdougb * 2438193149Sdougb * The Linux code hands the driver a pointer into kernel space, 2439224092Sdougb * and then trusts it when the caller hands it back. Aiee! 2440216175Sdougb * Here, we give it the proc pointer of the per-adapter aif 2441193149Sdougb * thread. It's only used as a sanity check in other calls. 2442135446Strhodes */ 2443224092Sdougb cookie = (uint32_t)(uintptr_t)sc->aifthread; 2444193149Sdougb error = copyout(&cookie, arg, sizeof(cookie)); 2445193149Sdougb break; 2446224092Sdougb case FSACTL_GET_NEXT_ADAPTER_FIB: 2447193149Sdougb arg = *(caddr_t*)arg; 2448193149Sdougb case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2449135446Strhodes debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2450135446Strhodes error = aac_getnext_aif(sc, arg); 2451171577Sdougb break; 2452171577Sdougb case FSACTL_CLOSE_GET_ADAPTER_FIB: 2453171577Sdougb case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2454171577Sdougb debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2455170222Sdougb /* don't do anything here */ 2456216175Sdougb break; 2457216175Sdougb case FSACTL_MINIPORT_REV_CHECK: 2458224092Sdougb arg = *(caddr_t*)arg; 2459224092Sdougb case FSACTL_LNX_MINIPORT_REV_CHECK: 2460224092Sdougb debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2461224092Sdougb error = aac_rev_check(sc, arg); 2462224092Sdougb break; 2463224092Sdougb case FSACTL_QUERY_DISK: 2464216175Sdougb arg = *(caddr_t*)arg; 2465224092Sdougb case FSACTL_LNX_QUERY_DISK: 2466216175Sdougb debug(1, "FSACTL_QUERY_DISK"); 2467193149Sdougb error = aac_query_disk(sc, arg); 2468216175Sdougb break; 2469216175Sdougb case FSACTL_DELETE_DISK: 2470171577Sdougb case FSACTL_LNX_DELETE_DISK: 2471171577Sdougb /* 2472193149Sdougb * We don't trust the underland to tell us when to delete a 2473193149Sdougb * container, rather we rely on an AIF coming from the 2474171577Sdougb * controller 2475170222Sdougb */ 2476171577Sdougb error = 0; 2477224092Sdougb break; 2478193149Sdougb default: 2479193149Sdougb debug(1, "unsupported cmd 0x%lx\n", cmd); 2480193149Sdougb error = EINVAL; 2481193149Sdougb break; 2482224092Sdougb } 2483193149Sdougb return(error); 2484193149Sdougb} 2485216175Sdougb 2486193149Sdougbstatic int 2487193149Sdougbaac_poll(dev_t dev, int poll_events, d_thread_t *td) 2488224092Sdougb{ 2489224092Sdougb struct aac_softc *sc; 2490224092Sdougb int revents; 2491216175Sdougb 2492224092Sdougb sc = dev->si_drv1; 2493193149Sdougb revents = 0; 2494170222Sdougb 2495193149Sdougb AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2496224092Sdougb if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2497224092Sdougb if (sc->aac_aifq_tail != sc->aac_aifq_head) 2498224092Sdougb revents |= poll_events & (POLLIN | POLLRDNORM); 2499224092Sdougb } 2500224092Sdougb AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2501224092Sdougb 2502224092Sdougb if (revents == 0) { 2503224092Sdougb if (poll_events & (POLLIN | POLLRDNORM)) 2504224092Sdougb selrecord(td, &sc->rcv_select); 2505224092Sdougb } 2506224092Sdougb 2507224092Sdougb return (revents); 2508224092Sdougb} 2509224092Sdougb 2510224092Sdougb/* 2511224092Sdougb * Send a FIB supplied from userspace 2512224092Sdougb */ 2513224092Sdougbstatic int 2514224092Sdougbaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 2515193149Sdougb{ 2516193149Sdougb struct aac_command *cm; 2517193149Sdougb int size, error; 2518193149Sdougb 2519135446Strhodes debug_called(2); 2520193149Sdougb 2521193149Sdougb cm = NULL; 2522193149Sdougb 2523193149Sdougb /* 2524193149Sdougb * Get a command 2525193149Sdougb */ 2526193149Sdougb AAC_LOCK_ACQUIRE(&sc->aac_io_lock); 2527224092Sdougb if (aac_alloc_command(sc, &cm)) { 2528193149Sdougb error = EBUSY; 2529193149Sdougb goto out; 2530193149Sdougb } 2531224092Sdougb 2532193149Sdougb /* 2533193149Sdougb * Fetch the FIB header, then re-copy to get data as well. 2534193149Sdougb */ 2535224092Sdougb if ((error = copyin(ufib, cm->cm_fib, 2536193149Sdougb sizeof(struct aac_fib_header))) != 0) 2537193149Sdougb goto out; 2538193149Sdougb size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 2539224092Sdougb if (size > sizeof(struct aac_fib)) { 2540193149Sdougb device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 2541193149Sdougb size, sizeof(struct aac_fib)); 2542135446Strhodes size = sizeof(struct aac_fib); 2543135446Strhodes } 2544135446Strhodes if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 2545135446Strhodes goto out; 2546135446Strhodes cm->cm_fib->Header.Size = size; 2547135446Strhodes cm->cm_timestamp = time_second; 2548135446Strhodes 2549135446Strhodes /* 2550135446Strhodes * Pass the FIB to the controller, wait for it to complete. 2551170222Sdougb */ 2552170222Sdougb if ((error = aac_wait_command(cm, 30)) != 0) { /* XXX user timeout? */ 2553193149Sdougb device_printf(sc->aac_dev, 2554193149Sdougb "aac_wait_command return %d\n", error); 2555193149Sdougb goto out; 2556193149Sdougb } 2557193149Sdougb 2558170222Sdougb /* 2559170222Sdougb * Copy the FIB and data back out to the caller. 2560170222Sdougb */ 2561170222Sdougb size = cm->cm_fib->Header.Size; 2562170222Sdougb if (size > sizeof(struct aac_fib)) { 2563170222Sdougb device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 2564170222Sdougb size, sizeof(struct aac_fib)); 2565170222Sdougb size = sizeof(struct aac_fib); 2566170222Sdougb } 2567170222Sdougb error = copyout(cm->cm_fib, ufib, size); 2568186462Sdougb 2569224092Sdougbout: 2570135446Strhodes if (cm != NULL) { 2571224092Sdougb aac_release_command(cm); 2572224092Sdougb } 2573224092Sdougb 2574224092Sdougb AAC_LOCK_RELEASE(&sc->aac_io_lock); 2575224092Sdougb return(error); 2576224092Sdougb} 2577224092Sdougb 2578224092Sdougb/* 2579224092Sdougb * Handle an AIF sent to us by the controller; queue it for later reference. 2580224092Sdougb * If the queue fills up, then drop the older entries. 2581224092Sdougb */ 2582224092Sdougbstatic void 2583224092Sdougbaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 2584224092Sdougb{ 2585224092Sdougb struct aac_aif_command *aif; 2586224092Sdougb struct aac_container *co, *co_next; 2587224092Sdougb struct aac_mntinfo *mi; 2588224092Sdougb struct aac_mntinforesp *mir = NULL; 2589224092Sdougb u_int16_t rsize; 2590135446Strhodes int next, found; 2591135446Strhodes int count = 0, added = 0, i = 0; 2592135446Strhodes 2593135446Strhodes debug_called(2); 2594135446Strhodes 2595224092Sdougb aif = (struct aac_aif_command*)&fib->data[0]; 2596135446Strhodes aac_print_aif(sc, aif); 2597224092Sdougb 2598224092Sdougb /* Is it an event that we should care about? */ 2599234010Sdougb switch (aif->command) { 2600224092Sdougb case AifCmdEventNotify: 2601234010Sdougb switch (aif->data.EN.type) { 2602234010Sdougb case AifEnAddContainer: 2603234010Sdougb case AifEnDeleteContainer: 2604234010Sdougb /* 2605234010Sdougb * A container was added or deleted, but the message 2606234010Sdougb * doesn't tell us anything else! Re-enumerate the 2607234010Sdougb * containers and sort things out. 2608234010Sdougb */ 2609234010Sdougb aac_alloc_sync_fib(sc, &fib, 0); 2610234010Sdougb mi = (struct aac_mntinfo *)&fib->data[0]; 2611234010Sdougb do { 2612224092Sdougb /* 2613224092Sdougb * Ask the controller for its containers one at 2614224092Sdougb * a time. 2615224092Sdougb * XXX What if the controller's list changes 2616135446Strhodes * midway through this enumaration? 2617135446Strhodes * XXX This should be done async. 2618135446Strhodes */ 2619135446Strhodes bzero(mi, sizeof(struct aac_mntinfo)); 2620135446Strhodes mi->Command = VM_NameServe; 2621135446Strhodes mi->MntType = FT_FILESYS; 2622135446Strhodes mi->MntCount = i; 2623135446Strhodes rsize = sizeof(mir); 2624135446Strhodes if (aac_sync_fib(sc, ContainerCommand, 0, fib, 2625135446Strhodes sizeof(struct aac_mntinfo))) { 2626135446Strhodes printf("Error probing container %d\n", 2627135446Strhodes i); 2628135446Strhodes continue; 2629135446Strhodes } 2630135446Strhodes mir = (struct aac_mntinforesp *)&fib->data[0]; 2631224092Sdougb /* XXX Need to check if count changed */ 2632135446Strhodes count = mir->MntRespCount; 2633135446Strhodes /* 2634135446Strhodes * Check the container against our list. 2635135446Strhodes * co->co_found was already set to 0 in a 2636135446Strhodes * previous run. 2637135446Strhodes */ 2638135446Strhodes if ((mir->Status == ST_OK) && 2639135446Strhodes (mir->MntTable[0].VolType != CT_NONE)) { 2640135446Strhodes found = 0; 2641224092Sdougb TAILQ_FOREACH(co, 2642224092Sdougb &sc->aac_container_tqh, 2643170222Sdougb co_link) { 2644170222Sdougb if (co->co_mntobj.ObjectId == 2645170222Sdougb mir->MntTable[0].ObjectId) { 2646170222Sdougb co->co_found = 1; 2647170222Sdougb found = 1; 2648135446Strhodes break; 2649135446Strhodes } 2650135446Strhodes } 2651135446Strhodes /* 2652135446Strhodes * If the container matched, continue 2653135446Strhodes * in the list. 2654135446Strhodes */ 2655135446Strhodes if (found) { 2656135446Strhodes i++; 2657135446Strhodes continue; 2658135446Strhodes } 2659135446Strhodes 2660135446Strhodes /* 2661135446Strhodes * This is a new container. Do all the 2662135446Strhodes * appropriate things to set it up. 2663135446Strhodes */ 2664135446Strhodes aac_add_container(sc, mir, 1); 2665135446Strhodes added = 1; 2666135446Strhodes } 2667135446Strhodes i++; 2668135446Strhodes } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 2669135446Strhodes aac_release_sync_fib(sc); 2670165071Sdougb 2671165071Sdougb /* 2672135446Strhodes * Go through our list of containers and see which ones 2673135446Strhodes * were not marked 'found'. Since the controller didn't 2674135446Strhodes * list them they must have been deleted. Do the 2675135446Strhodes * appropriate steps to destroy the device. Also reset 2676135446Strhodes * the co->co_found field. 2677135446Strhodes */ 2678135446Strhodes co = TAILQ_FIRST(&sc->aac_container_tqh); 2679135446Strhodes while (co != NULL) { 2680135446Strhodes if (co->co_found == 0) { 2681135446Strhodes device_delete_child(sc->aac_dev, 2682135446Strhodes co->co_disk); 2683224092Sdougb co_next = TAILQ_NEXT(co, co_link); 2684135446Strhodes AAC_LOCK_ACQUIRE(&sc-> 2685135446Strhodes aac_container_lock); 2686135446Strhodes TAILQ_REMOVE(&sc->aac_container_tqh, co, 2687135446Strhodes co_link); 2688135446Strhodes AAC_LOCK_RELEASE(&sc-> 2689135446Strhodes aac_container_lock); 2690135446Strhodes FREE(co, M_AACBUF); 2691170222Sdougb co = co_next; 2692170222Sdougb } else { 2693170222Sdougb co->co_found = 0; 2694170222Sdougb co = TAILQ_NEXT(co, co_link); 2695170222Sdougb } 2696170222Sdougb } 2697170222Sdougb 2698170222Sdougb /* Attach the newly created containers */ 2699170222Sdougb if (added) 2700170222Sdougb bus_generic_attach(sc->aac_dev); 2701170222Sdougb 2702170222Sdougb break; 2703170222Sdougb 2704170222Sdougb default: 2705170222Sdougb break; 2706170222Sdougb } 2707170222Sdougb 2708170222Sdougb default: 2709170222Sdougb break; 2710170222Sdougb } 2711170222Sdougb 2712234010Sdougb /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2713170222Sdougb AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2714170222Sdougb next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 2715170222Sdougb if (next != sc->aac_aifq_tail) { 2716170222Sdougb bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 2717170222Sdougb sc->aac_aifq_head = next; 2718170222Sdougb 2719170222Sdougb /* On the off chance that someone is sleeping for an aif... */ 2720170222Sdougb if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 2721170222Sdougb wakeup(sc->aac_aifq); 2722170222Sdougb /* Wakeup any poll()ers */ 2723170222Sdougb selwakeuppri(&sc->rcv_select, PRIBIO); 2724170222Sdougb } 2725193149Sdougb AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2726170222Sdougb 2727170222Sdougb return; 2728170222Sdougb} 2729170222Sdougb 2730170222Sdougb/* 2731170222Sdougb * Return the Revision of the driver to userspace and check to see if the 2732170222Sdougb * userspace app is possibly compatible. This is extremely bogus since 2733170222Sdougb * our driver doesn't follow Adaptec's versioning system. Cheat by just 2734170222Sdougb * returning what the card reported. 2735170222Sdougb */ 2736224092Sdougbstatic int 2737224092Sdougbaac_rev_check(struct aac_softc *sc, caddr_t udata) 2738170222Sdougb{ 2739170222Sdougb struct aac_rev_check rev_check; 2740170222Sdougb struct aac_rev_check_resp rev_check_resp; 2741170222Sdougb int error = 0; 2742170222Sdougb 2743170222Sdougb debug_called(2); 2744170222Sdougb 2745170222Sdougb /* 2746170222Sdougb * Copyin the revision struct from userspace 2747170222Sdougb */ 2748170222Sdougb if ((error = copyin(udata, (caddr_t)&rev_check, 2749170222Sdougb sizeof(struct aac_rev_check))) != 0) { 2750170222Sdougb return error; 2751224092Sdougb } 2752224092Sdougb 2753170222Sdougb debug(2, "Userland revision= %d\n", 2754170222Sdougb rev_check.callingRevision.buildNumber); 2755170222Sdougb 2756170222Sdougb /* 2757170222Sdougb * Doctor up the response struct. 2758170222Sdougb */ 2759170222Sdougb rev_check_resp.possiblyCompatible = 1; 2760193149Sdougb rev_check_resp.adapterSWRevision.external.ul = 2761193149Sdougb sc->aac_revision.external.ul; 2762193149Sdougb rev_check_resp.adapterSWRevision.buildNumber = 2763193149Sdougb sc->aac_revision.buildNumber; 2764193149Sdougb 2765170222Sdougb return(copyout((caddr_t)&rev_check_resp, udata, 2766170222Sdougb sizeof(struct aac_rev_check_resp))); 2767170222Sdougb} 2768170222Sdougb 2769170222Sdougb/* 2770170222Sdougb * Pass the caller the next AIF in their queue 2771170222Sdougb */ 2772170222Sdougbstatic int 2773170222Sdougbaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 2774170222Sdougb{ 2775170222Sdougb struct get_adapter_fib_ioctl agf; 2776170222Sdougb int error; 2777170222Sdougb 2778224092Sdougb debug_called(2); 2779224092Sdougb 2780170222Sdougb if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 2781170222Sdougb 2782170222Sdougb /* 2783170222Sdougb * Check the magic number that we gave the caller. 2784170222Sdougb */ 2785170222Sdougb if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 2786170222Sdougb error = EFAULT; 2787170222Sdougb } else { 2788170222Sdougb error = aac_return_aif(sc, agf.AifFib); 2789193149Sdougb if ((error == EAGAIN) && (agf.Wait)) { 2790170222Sdougb sc->aac_state |= AAC_STATE_AIF_SLEEPER; 2791170222Sdougb while (error == EAGAIN) { 2792170222Sdougb error = tsleep(sc->aac_aifq, PRIBIO | 2793170222Sdougb PCATCH, "aacaif", 0); 2794170222Sdougb if (error == 0) 2795170222Sdougb error = aac_return_aif(sc, 2796170222Sdougb agf.AifFib); 2797170222Sdougb } 2798170222Sdougb sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 2799170222Sdougb } 2800170222Sdougb } 2801170222Sdougb } 2802170222Sdougb return(error); 2803186462Sdougb} 2804170222Sdougb 2805170222Sdougb/* 2806170222Sdougb * Hand the next AIF off the top of the queue out to userspace. 2807170222Sdougb */ 2808170222Sdougbstatic int 2809170222Sdougbaac_return_aif(struct aac_softc *sc, caddr_t uptr) 2810186462Sdougb{ 2811170222Sdougb int next, error; 2812170222Sdougb 2813170222Sdougb debug_called(2); 2814170222Sdougb 2815170222Sdougb AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock); 2816170222Sdougb if (sc->aac_aifq_tail == sc->aac_aifq_head) { 2817170222Sdougb AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2818170222Sdougb return (EAGAIN); 2819170222Sdougb } 2820170222Sdougb 2821170222Sdougb next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 2822170222Sdougb error = copyout(&sc->aac_aifq[next], uptr, 2823170222Sdougb sizeof(struct aac_aif_command)); 2824170222Sdougb if (error) 2825170222Sdougb device_printf(sc->aac_dev, 2826170222Sdougb "aac_return_aif: copyout returned %d\n", error); 2827170222Sdougb else 2828170222Sdougb sc->aac_aifq_tail = next; 2829170222Sdougb 2830170222Sdougb AAC_LOCK_RELEASE(&sc->aac_aifq_lock); 2831170222Sdougb return(error); 2832170222Sdougb} 2833170222Sdougb 2834170222Sdougb/* 2835170222Sdougb * Give the userland some information about the container. The AAC arch 2836170222Sdougb * expects the driver to be a SCSI passthrough type driver, so it expects 2837170222Sdougb * the containers to have b:t:l numbers. Fake it. 2838170222Sdougb */ 2839174187Sdougbstatic int 2840193149Sdougbaac_query_disk(struct aac_softc *sc, caddr_t uptr) 2841193149Sdougb{ 2842170222Sdougb struct aac_query_disk query_disk; 2843170222Sdougb struct aac_container *co; 2844170222Sdougb struct aac_disk *disk; 2845170222Sdougb int error, id; 2846170222Sdougb 2847170222Sdougb debug_called(2); 2848170222Sdougb 2849170222Sdougb disk = NULL; 2850234010Sdougb 2851234010Sdougb error = copyin(uptr, (caddr_t)&query_disk, 2852170222Sdougb sizeof(struct aac_query_disk)); 2853170222Sdougb if (error) 2854193149Sdougb return (error); 2855170222Sdougb 2856186462Sdougb id = query_disk.ContainerNumber; 2857170222Sdougb if (id == -1) 2858170222Sdougb return (EINVAL); 2859193149Sdougb 2860193149Sdougb AAC_LOCK_ACQUIRE(&sc->aac_container_lock); 2861170222Sdougb TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 2862170222Sdougb if (co->co_mntobj.ObjectId == id) 2863170222Sdougb break; 2864170222Sdougb } 2865193149Sdougb 2866170222Sdougb if (co == NULL) { 2867170222Sdougb query_disk.Valid = 0; 2868170222Sdougb query_disk.Locked = 0; 2869170222Sdougb query_disk.Deleted = 1; /* XXX is this right? */ 2870170222Sdougb } else { 2871170222Sdougb disk = device_get_softc(co->co_disk); 2872170222Sdougb query_disk.Valid = 1; 2873170222Sdougb query_disk.Locked = 2874186462Sdougb (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 2875224092Sdougb query_disk.Deleted = 0; 2876224092Sdougb query_disk.Bus = device_get_unit(sc->aac_dev); 2877224092Sdougb query_disk.Target = disk->unit; 2878224092Sdougb query_disk.Lun = 0; 2879224092Sdougb query_disk.UnMapped = 0; 2880224092Sdougb sprintf(&query_disk.diskDeviceName[0], "%s%d", 2881224092Sdougb disk->ad_disk->d_name, disk->ad_disk->d_unit); 2882224092Sdougb } 2883224092Sdougb AAC_LOCK_RELEASE(&sc->aac_container_lock); 2884224092Sdougb 2885224092Sdougb error = copyout((caddr_t)&query_disk, uptr, 2886225361Sdougb sizeof(struct aac_query_disk)); 2887224092Sdougb 2888224092Sdougb return (error); 2889224092Sdougb} 2890224092Sdougb 2891224092Sdougbstatic void 2892224092Sdougbaac_get_bus_info(struct aac_softc *sc) 2893224092Sdougb{ 2894224092Sdougb struct aac_fib *fib; 2895224092Sdougb struct aac_ctcfg *c_cmd; 2896224092Sdougb struct aac_ctcfg_resp *c_resp; 2897224092Sdougb struct aac_vmioctl *vmi; 2898135446Strhodes struct aac_vmi_businf_resp *vmi_resp; 2899135446Strhodes struct aac_getbusinf businfo; 2900135446Strhodes struct aac_sim *caminf; 2901224092Sdougb device_t child; 2902224092Sdougb int i, found, error; 2903224092Sdougb 2904224092Sdougb aac_alloc_sync_fib(sc, &fib, 0); 2905224092Sdougb c_cmd = (struct aac_ctcfg *)&fib->data[0]; 2906224092Sdougb bzero(c_cmd, sizeof(struct aac_ctcfg)); 2907224092Sdougb 2908224092Sdougb c_cmd->Command = VM_ContainerConfig; 2909170222Sdougb c_cmd->cmd = CT_GET_SCSI_METHOD; 2910170222Sdougb c_cmd->param = 0; 2911135446Strhodes 2912135446Strhodes error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2913135446Strhodes sizeof(struct aac_ctcfg)); 2914135446Strhodes if (error) { 2915193149Sdougb device_printf(sc->aac_dev, "Error %d sending " 2916193149Sdougb "VM_ContainerConfig command\n", error); 2917193149Sdougb aac_release_sync_fib(sc); 2918193149Sdougb return; 2919135446Strhodes } 2920135446Strhodes 2921135446Strhodes c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 2922135446Strhodes if (c_resp->Status != ST_OK) { 2923225361Sdougb device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 2924225361Sdougb c_resp->Status); 2925135446Strhodes aac_release_sync_fib(sc); 2926135446Strhodes return; 2927135446Strhodes } 2928135446Strhodes 2929135446Strhodes sc->scsi_method_id = c_resp->param; 2930135446Strhodes 2931135446Strhodes vmi = (struct aac_vmioctl *)&fib->data[0]; 2932135446Strhodes bzero(vmi, sizeof(struct aac_vmioctl)); 2933135446Strhodes 2934135446Strhodes vmi->Command = VM_Ioctl; 2935135446Strhodes vmi->ObjType = FT_DRIVE; 2936135446Strhodes vmi->MethId = sc->scsi_method_id; 2937135446Strhodes vmi->ObjId = 0; 2938135446Strhodes vmi->IoctlCmd = GetBusInfo; 2939135446Strhodes 2940135446Strhodes error = aac_sync_fib(sc, ContainerCommand, 0, fib, 2941135446Strhodes sizeof(struct aac_vmioctl)); 2942135446Strhodes if (error) { 2943135446Strhodes device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 2944135446Strhodes error); 2945135446Strhodes aac_release_sync_fib(sc); 2946135446Strhodes return; 2947135446Strhodes } 2948165071Sdougb 2949165071Sdougb vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 2950135446Strhodes if (vmi_resp->Status != ST_OK) { 2951165071Sdougb device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 2952165071Sdougb vmi_resp->Status); 2953165071Sdougb aac_release_sync_fib(sc); 2954135446Strhodes return; 2955135446Strhodes } 2956135446Strhodes 2957135446Strhodes bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 2958135446Strhodes aac_release_sync_fib(sc); 2959135446Strhodes 2960135446Strhodes found = 0; 2961135446Strhodes for (i = 0; i < businfo.BusCount; i++) { 2962135446Strhodes if (businfo.BusValid[i] != AAC_BUS_VALID) 2963135446Strhodes continue; 2964135446Strhodes 2965135446Strhodes caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 2966135446Strhodes M_AACBUF, M_NOWAIT | M_ZERO); 2967135446Strhodes if (caminf == NULL) 2968135446Strhodes continue; 2969135446Strhodes 2970135446Strhodes child = device_add_child(sc->aac_dev, "aacp", -1); 2971135446Strhodes if (child == NULL) { 2972135446Strhodes device_printf(sc->aac_dev, "device_add_child failed\n"); 2973135446Strhodes continue; 2974135446Strhodes } 2975135446Strhodes 2976135446Strhodes caminf->TargetsPerBus = businfo.TargetsPerBus; 2977135446Strhodes caminf->BusNumber = i; 2978135446Strhodes caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 2979135446Strhodes caminf->aac_sc = sc; 2980135446Strhodes caminf->sim_dev = child; 2981135446Strhodes 2982135446Strhodes device_set_ivars(child, caminf); 2983135446Strhodes device_set_desc(child, "SCSI Passthrough Bus"); 2984135446Strhodes TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 2985135446Strhodes 2986165071Sdougb found = 1; 2987135446Strhodes } 2988135446Strhodes 2989135446Strhodes if (found) 2990135446Strhodes bus_generic_attach(sc->aac_dev); 2991135446Strhodes 2992165071Sdougb return; 2993165071Sdougb} 2994135446Strhodes