aac.c revision 151086
165793Smsmith/*- 265793Smsmith * Copyright (c) 2000 Michael Smith 381082Sscottl * Copyright (c) 2001 Scott Long 465793Smsmith * Copyright (c) 2000 BSDi 581082Sscottl * Copyright (c) 2001 Adaptec, Inc. 665793Smsmith * All rights reserved. 765793Smsmith * 865793Smsmith * Redistribution and use in source and binary forms, with or without 965793Smsmith * modification, are permitted provided that the following conditions 1065793Smsmith * are met: 1165793Smsmith * 1. Redistributions of source code must retain the above copyright 1265793Smsmith * notice, this list of conditions and the following disclaimer. 1365793Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1465793Smsmith * notice, this list of conditions and the following disclaimer in the 1565793Smsmith * documentation and/or other materials provided with the distribution. 1665793Smsmith * 1765793Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1865793Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965793Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065793Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2165793Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265793Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365793Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465793Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565793Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665793Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765793Smsmith * SUCH DAMAGE. 2865793Smsmith */ 2965793Smsmith 30119418Sobrien#include <sys/cdefs.h> 31119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aac/aac.c 151086 2005-10-08 15:55:09Z scottl $"); 32119418Sobrien 3365793Smsmith/* 3465793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3565793Smsmith */ 36151086Sscottl#define AAC_DRIVER_VERSION 0x02000000 37151086Sscottl#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__ 38151086Sscottl#define AAC_DRIVERNAME "aac" 3965793Smsmith 4081151Sscottl#include "opt_aac.h" 4181151Sscottl 4282527Sscottl/* #include <stddef.h> */ 4365793Smsmith#include <sys/param.h> 4465793Smsmith#include <sys/systm.h> 4565793Smsmith#include <sys/malloc.h> 4665793Smsmith#include <sys/kernel.h> 4782527Sscottl#include <sys/kthread.h> 4881154Sscottl#include <sys/sysctl.h> 4987183Sscottl#include <sys/poll.h> 50112946Sphk#include <sys/ioccom.h> 5165793Smsmith 5265793Smsmith#include <sys/bus.h> 5365793Smsmith#include <sys/conf.h> 5465793Smsmith#include <sys/signalvar.h> 5570393Smsmith#include <sys/time.h> 5682527Sscottl#include <sys/eventhandler.h> 57151086Sscottl#include <sys/rman.h> 5865793Smsmith 5965793Smsmith#include <machine/bus.h> 60143838Sscottl#include <sys/bus_dma.h> 6165793Smsmith#include <machine/resource.h> 6265793Smsmith 63151086Sscottl#include <dev/pci/pcireg.h> 64151086Sscottl#include <dev/pci/pcivar.h> 65151086Sscottl 6665793Smsmith#include <dev/aac/aacreg.h> 67138635Sscottl#include <sys/aac_ioctl.h> 6865793Smsmith#include <dev/aac/aacvar.h> 6965793Smsmith#include <dev/aac/aac_tables.h> 7065793Smsmith 7165793Smsmithstatic void aac_startup(void *arg); 7283114Sscottlstatic void aac_add_container(struct aac_softc *sc, 7395350Sscottl struct aac_mntinforesp *mir, int f); 7495536Sscottlstatic void aac_get_bus_info(struct aac_softc *sc); 7565793Smsmith 7665793Smsmith/* Command Processing */ 7770393Smsmithstatic void aac_timeout(struct aac_softc *sc); 7865793Smsmithstatic void aac_complete(void *context, int pending); 7965793Smsmithstatic int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8065793Smsmithstatic void aac_bio_complete(struct aac_command *cm); 81128258Sscottlstatic int aac_wait_command(struct aac_command *cm); 82110426Sscottlstatic void aac_command_thread(struct aac_softc *sc); 8365793Smsmith 8465793Smsmith/* Command Buffer Management */ 85117363Sscottlstatic void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 86117363Sscottl int nseg, int error); 8781082Sscottlstatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 8881082Sscottl int nseg, int error); 8970393Smsmithstatic int aac_alloc_commands(struct aac_softc *sc); 90111141Sscottlstatic void aac_free_commands(struct aac_softc *sc); 9165793Smsmithstatic void aac_unmap_command(struct aac_command *cm); 9265793Smsmith 9365793Smsmith/* Hardware Interface */ 9481082Sscottlstatic void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 9581082Sscottl int error); 9690275Sscottlstatic int aac_check_firmware(struct aac_softc *sc); 9765793Smsmithstatic int aac_init(struct aac_softc *sc); 9865793Smsmithstatic int aac_sync_command(struct aac_softc *sc, u_int32_t command, 9981082Sscottl u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 10081082Sscottl u_int32_t arg3, u_int32_t *sp); 10181082Sscottlstatic int aac_enqueue_fib(struct aac_softc *sc, int queue, 10281151Sscottl struct aac_command *cm); 10381082Sscottlstatic int aac_dequeue_fib(struct aac_softc *sc, int queue, 10483114Sscottl u_int32_t *fib_size, struct aac_fib **fib_addr); 10582527Sscottlstatic int aac_enqueue_response(struct aac_softc *sc, int queue, 10682527Sscottl struct aac_fib *fib); 10765793Smsmith 10887183Sscottl/* Falcon/PPC interface */ 10987183Sscottlstatic int aac_fa_get_fwstatus(struct aac_softc *sc); 11087183Sscottlstatic void aac_fa_qnotify(struct aac_softc *sc, int qbit); 11187183Sscottlstatic int aac_fa_get_istatus(struct aac_softc *sc); 11287183Sscottlstatic void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 11387183Sscottlstatic void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 11487183Sscottl u_int32_t arg0, u_int32_t arg1, 11587183Sscottl u_int32_t arg2, u_int32_t arg3); 116112679Sscottlstatic int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 11787183Sscottlstatic void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 11887183Sscottl 11987183Sscottlstruct aac_interface aac_fa_interface = { 12087183Sscottl aac_fa_get_fwstatus, 12187183Sscottl aac_fa_qnotify, 12287183Sscottl aac_fa_get_istatus, 12387183Sscottl aac_fa_clear_istatus, 12487183Sscottl aac_fa_set_mailbox, 125112679Sscottl aac_fa_get_mailbox, 126151086Sscottl aac_fa_set_interrupts, 127151086Sscottl NULL, NULL, NULL 12887183Sscottl}; 12987183Sscottl 13065793Smsmith/* StrongARM interface */ 13165793Smsmithstatic int aac_sa_get_fwstatus(struct aac_softc *sc); 13265793Smsmithstatic void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13365793Smsmithstatic int aac_sa_get_istatus(struct aac_softc *sc); 13465793Smsmithstatic void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13565793Smsmithstatic void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 13681082Sscottl u_int32_t arg0, u_int32_t arg1, 13781082Sscottl u_int32_t arg2, u_int32_t arg3); 138112679Sscottlstatic int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13965793Smsmithstatic void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 14065793Smsmith 14165793Smsmithstruct aac_interface aac_sa_interface = { 14283114Sscottl aac_sa_get_fwstatus, 14383114Sscottl aac_sa_qnotify, 14483114Sscottl aac_sa_get_istatus, 14583114Sscottl aac_sa_clear_istatus, 14683114Sscottl aac_sa_set_mailbox, 147112679Sscottl aac_sa_get_mailbox, 148151086Sscottl aac_sa_set_interrupts, 149151086Sscottl NULL, NULL, NULL 15065793Smsmith}; 15165793Smsmith 15283114Sscottl/* i960Rx interface */ 15365793Smsmithstatic int aac_rx_get_fwstatus(struct aac_softc *sc); 15465793Smsmithstatic void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15565793Smsmithstatic int aac_rx_get_istatus(struct aac_softc *sc); 15665793Smsmithstatic void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15765793Smsmithstatic void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 15881082Sscottl u_int32_t arg0, u_int32_t arg1, 15981082Sscottl u_int32_t arg2, u_int32_t arg3); 160112679Sscottlstatic int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 16165793Smsmithstatic void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 162151086Sscottlstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 163151086Sscottlstatic int aac_rx_get_outb_queue(struct aac_softc *sc); 164151086Sscottlstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 16565793Smsmith 16665793Smsmithstruct aac_interface aac_rx_interface = { 16783114Sscottl aac_rx_get_fwstatus, 16883114Sscottl aac_rx_qnotify, 16983114Sscottl aac_rx_get_istatus, 17083114Sscottl aac_rx_clear_istatus, 17183114Sscottl aac_rx_set_mailbox, 172112679Sscottl aac_rx_get_mailbox, 173151086Sscottl aac_rx_set_interrupts, 174151086Sscottl aac_rx_send_command, 175151086Sscottl aac_rx_get_outb_queue, 176151086Sscottl aac_rx_set_outb_queue 17765793Smsmith}; 17865793Smsmith 179133606Sscottl/* Rocket/MIPS interface */ 180133606Sscottlstatic int aac_rkt_get_fwstatus(struct aac_softc *sc); 181133606Sscottlstatic void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 182133606Sscottlstatic int aac_rkt_get_istatus(struct aac_softc *sc); 183133606Sscottlstatic void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 184133606Sscottlstatic void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 185133606Sscottl u_int32_t arg0, u_int32_t arg1, 186133606Sscottl u_int32_t arg2, u_int32_t arg3); 187133606Sscottlstatic int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 188133606Sscottlstatic void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 189151086Sscottlstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 190151086Sscottlstatic int aac_rkt_get_outb_queue(struct aac_softc *sc); 191151086Sscottlstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 192133606Sscottl 193133606Sscottlstruct aac_interface aac_rkt_interface = { 194133606Sscottl aac_rkt_get_fwstatus, 195133606Sscottl aac_rkt_qnotify, 196133606Sscottl aac_rkt_get_istatus, 197133606Sscottl aac_rkt_clear_istatus, 198133606Sscottl aac_rkt_set_mailbox, 199133606Sscottl aac_rkt_get_mailbox, 200151086Sscottl aac_rkt_set_interrupts, 201151086Sscottl aac_rkt_send_command, 202151086Sscottl aac_rkt_get_outb_queue, 203151086Sscottl aac_rkt_set_outb_queue 204133606Sscottl}; 205133606Sscottl 20665793Smsmith/* Debugging and Diagnostics */ 20765793Smsmithstatic void aac_describe_controller(struct aac_softc *sc); 20882567Sscottlstatic char *aac_describe_code(struct aac_code_lookup *table, 20981082Sscottl u_int32_t code); 21065793Smsmith 21165793Smsmith/* Management Interface */ 21265793Smsmithstatic d_open_t aac_open; 21365793Smsmithstatic d_close_t aac_close; 21465793Smsmithstatic d_ioctl_t aac_ioctl; 21587183Sscottlstatic d_poll_t aac_poll; 21681082Sscottlstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 21781082Sscottlstatic void aac_handle_aif(struct aac_softc *sc, 21883114Sscottl struct aac_fib *fib); 21981189Sscottlstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 22081189Sscottlstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 22181189Sscottlstatic int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 22282527Sscottlstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 223151086Sscottlstatic int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 224151086Sscottlstatic void aac_ioctl_event(struct aac_softc *sc, 225151086Sscottl struct aac_event *event, void *arg); 22665793Smsmith 22765793Smsmithstatic struct cdevsw aac_cdevsw = { 228126080Sphk .d_version = D_VERSION, 229126080Sphk .d_flags = D_NEEDGIANT, 230111815Sphk .d_open = aac_open, 231111815Sphk .d_close = aac_close, 232111815Sphk .d_ioctl = aac_ioctl, 233111815Sphk .d_poll = aac_poll, 234111815Sphk .d_name = "aac", 23565793Smsmith}; 23665793Smsmith 23782527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 23882527Sscottl 23981154Sscottl/* sysctl node */ 24081154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 24181154Sscottl 24283114Sscottl/* 24383114Sscottl * Device Interface 24483114Sscottl */ 24565793Smsmith 24683114Sscottl/* 24765793Smsmith * Initialise the controller and softc 24865793Smsmith */ 24965793Smsmithint 25065793Smsmithaac_attach(struct aac_softc *sc) 25165793Smsmith{ 25283114Sscottl int error, unit; 25365793Smsmith 25483114Sscottl debug_called(1); 25565793Smsmith 25683114Sscottl /* 25783114Sscottl * Initialise per-controller queues. 25883114Sscottl */ 25983114Sscottl aac_initq_free(sc); 26083114Sscottl aac_initq_ready(sc); 26183114Sscottl aac_initq_busy(sc); 26283114Sscottl aac_initq_bio(sc); 26365793Smsmith 26483114Sscottl /* 26583114Sscottl * Initialise command-completion task. 26683114Sscottl */ 26783114Sscottl TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 26865793Smsmith 26983114Sscottl /* mark controller as suspended until we get ourselves organised */ 27083114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 27165793Smsmith 27283114Sscottl /* 27390275Sscottl * Check that the firmware on the card is supported. 27490275Sscottl */ 27590275Sscottl if ((error = aac_check_firmware(sc)) != 0) 27690275Sscottl return(error); 27790275Sscottl 278117126Sscottl /* 279117126Sscottl * Initialize locks 280117126Sscottl */ 281133540Sscottl mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 282133540Sscottl mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 283133540Sscottl mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 284117126Sscottl TAILQ_INIT(&sc->aac_container_tqh); 28595350Sscottl 286121173Sscottl /* Initialize the local AIF queue pointers */ 287121173Sscottl sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; 288117126Sscottl 28983114Sscottl /* 29083114Sscottl * Initialise the adapter. 29183114Sscottl */ 29283114Sscottl if ((error = aac_init(sc)) != 0) 29383114Sscottl return(error); 29465793Smsmith 29583114Sscottl /* 296151086Sscottl * Allocate and connect our interrupt. 297151086Sscottl */ 298151086Sscottl sc->aac_irq_rid = 0; 299151086Sscottl if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 300151086Sscottl &sc->aac_irq_rid, 301151086Sscottl RF_SHAREABLE | 302151086Sscottl RF_ACTIVE)) == NULL) { 303151086Sscottl device_printf(sc->aac_dev, "can't allocate interrupt\n"); 304151086Sscottl return (EINVAL); 305151086Sscottl } 306151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) { 307151086Sscottl if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 308151086Sscottl INTR_MPSAFE|INTR_TYPE_BIO, aac_new_intr, 309151086Sscottl sc, &sc->aac_intr)) { 310151086Sscottl device_printf(sc->aac_dev, "can't set up interrupt\n"); 311151086Sscottl return (EINVAL); 312151086Sscottl } 313151086Sscottl } else { 314151086Sscottl if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 315151086Sscottl INTR_FAST|INTR_TYPE_BIO, aac_fast_intr, 316151086Sscottl sc, &sc->aac_intr)) { 317151086Sscottl device_printf(sc->aac_dev, 318151086Sscottl "can't set up FAST interrupt\n"); 319151086Sscottl if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 320151086Sscottl INTR_MPSAFE|INTR_TYPE_BIO, 321151086Sscottl aac_fast_intr, sc, &sc->aac_intr)) { 322151086Sscottl device_printf(sc->aac_dev, 323151086Sscottl "can't set up MPSAFE interrupt\n"); 324151086Sscottl return (EINVAL); 325151086Sscottl } 326151086Sscottl } 327151086Sscottl } 328151086Sscottl 329151086Sscottl /* 33083114Sscottl * Print a little information about the controller. 33183114Sscottl */ 33283114Sscottl aac_describe_controller(sc); 33365793Smsmith 33483114Sscottl /* 335111532Sscottl * Register to probe our containers later. 33687183Sscottl */ 33783114Sscottl sc->aac_ich.ich_func = aac_startup; 33883114Sscottl sc->aac_ich.ich_arg = sc; 33983114Sscottl if (config_intrhook_establish(&sc->aac_ich) != 0) { 34083114Sscottl device_printf(sc->aac_dev, 34183114Sscottl "can't establish configuration hook\n"); 34283114Sscottl return(ENXIO); 34383114Sscottl } 34465793Smsmith 34583114Sscottl /* 34683114Sscottl * Make the control device. 34783114Sscottl */ 34883114Sscottl unit = device_get_unit(sc->aac_dev); 349108329Srwatson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 350108329Srwatson 0640, "aac%d", unit); 35183114Sscottl (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 35283114Sscottl (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 35383114Sscottl sc->aac_dev_t->si_drv1 = sc; 35465793Smsmith 35583114Sscottl /* Create the AIF thread */ 356110426Sscottl if (kthread_create((void(*)(void *))aac_command_thread, sc, 357151086Sscottl &sc->aifthread, 0, 0, "aac%daif", unit)) 35883114Sscottl panic("Could not create AIF thread\n"); 35982527Sscottl 36083114Sscottl /* Register the shutdown method to only be called post-dump */ 361110427Sscottl if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 362110427Sscottl sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 363110427Sscottl device_printf(sc->aac_dev, 364110427Sscottl "shutdown event registration failed\n"); 36582527Sscottl 36695536Sscottl /* Register with CAM for the non-DASD devices */ 367112679Sscottl if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 368110426Sscottl TAILQ_INIT(&sc->aac_sim_tqh); 36995536Sscottl aac_get_bus_info(sc); 370110426Sscottl } 37195536Sscottl 37283114Sscottl return(0); 37365793Smsmith} 37465793Smsmith 375151086Sscottlvoid 376151086Sscottlaac_add_event(struct aac_softc *sc, struct aac_event *event) 377151086Sscottl{ 378151086Sscottl 379151086Sscottl switch (event->ev_type & AAC_EVENT_MASK) { 380151086Sscottl case AAC_EVENT_CMFREE: 381151086Sscottl TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 382151086Sscottl break; 383151086Sscottl default: 384151086Sscottl device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 385151086Sscottl event->ev_type); 386151086Sscottl break; 387151086Sscottl } 388151086Sscottl 389151086Sscottl return; 390151086Sscottl} 391151086Sscottl 39283114Sscottl/* 39365793Smsmith * Probe for containers, create disks. 39465793Smsmith */ 39565793Smsmithstatic void 39665793Smsmithaac_startup(void *arg) 39765793Smsmith{ 39883114Sscottl struct aac_softc *sc; 39995350Sscottl struct aac_fib *fib; 40095350Sscottl struct aac_mntinfo *mi; 40195350Sscottl struct aac_mntinforesp *mir = NULL; 402115760Sscottl int count = 0, i = 0; 40365793Smsmith 40483114Sscottl debug_called(1); 40565793Smsmith 40683114Sscottl sc = (struct aac_softc *)arg; 40765793Smsmith 40883114Sscottl /* disconnect ourselves from the intrhook chain */ 40983114Sscottl config_intrhook_disestablish(&sc->aac_ich); 41065793Smsmith 411151086Sscottl mtx_lock(&sc->aac_io_lock); 412130006Sscottl aac_alloc_sync_fib(sc, &fib); 41395350Sscottl mi = (struct aac_mntinfo *)&fib->data[0]; 41495350Sscottl 41583114Sscottl /* loop over possible containers */ 41683114Sscottl do { 41783114Sscottl /* request information on this container */ 41895966Sscottl bzero(mi, sizeof(struct aac_mntinfo)); 41995966Sscottl mi->Command = VM_NameServe; 42095966Sscottl mi->MntType = FT_FILESYS; 42195350Sscottl mi->MntCount = i; 42295350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 42395350Sscottl sizeof(struct aac_mntinfo))) { 424115760Sscottl printf("error probing container %d", i); 42583114Sscottl continue; 42683114Sscottl } 42765793Smsmith 42895350Sscottl mir = (struct aac_mntinforesp *)&fib->data[0]; 429115760Sscottl /* XXX Need to check if count changed */ 430115760Sscottl count = mir->MntRespCount; 43195350Sscottl aac_add_container(sc, mir, 0); 43283114Sscottl i++; 433115760Sscottl } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 43465793Smsmith 43595350Sscottl aac_release_sync_fib(sc); 436151086Sscottl mtx_unlock(&sc->aac_io_lock); 43795350Sscottl 43883114Sscottl /* poke the bus to actually attach the child devices */ 43983114Sscottl if (bus_generic_attach(sc->aac_dev)) 44083114Sscottl device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 44165793Smsmith 44283114Sscottl /* mark the controller up */ 44383114Sscottl sc->aac_state &= ~AAC_STATE_SUSPEND; 44470393Smsmith 44583114Sscottl /* enable interrupts now */ 44683114Sscottl AAC_UNMASK_INTERRUPTS(sc); 44765793Smsmith} 44865793Smsmith 44983114Sscottl/* 45083114Sscottl * Create a device to respresent a new container 45183114Sscottl */ 45283114Sscottlstatic void 45395350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 45483114Sscottl{ 45583114Sscottl struct aac_container *co; 45683114Sscottl device_t child; 45783114Sscottl 45883114Sscottl /* 45983114Sscottl * Check container volume type for validity. Note that many of 46083114Sscottl * the possible types may never show up. 46183114Sscottl */ 46283114Sscottl if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 463110428Sscottl co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 464110428Sscottl M_NOWAIT | M_ZERO); 46583114Sscottl if (co == NULL) 46683114Sscottl panic("Out of memory?!\n"); 46783114Sscottl debug(1, "id %x name '%.16s' size %u type %d", 46883114Sscottl mir->MntTable[0].ObjectId, 46983114Sscottl mir->MntTable[0].FileSystemName, 47083114Sscottl mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 47183114Sscottl 47295536Sscottl if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 47383114Sscottl device_printf(sc->aac_dev, "device_add_child failed\n"); 47483114Sscottl else 47583114Sscottl device_set_ivars(child, co); 47683114Sscottl device_set_desc(child, aac_describe_code(aac_container_types, 47783114Sscottl mir->MntTable[0].VolType)); 47883114Sscottl co->co_disk = child; 47983114Sscottl co->co_found = f; 48083114Sscottl bcopy(&mir->MntTable[0], &co->co_mntobj, 48183114Sscottl sizeof(struct aac_mntobj)); 482133540Sscottl mtx_lock(&sc->aac_container_lock); 48383114Sscottl TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 484133540Sscottl mtx_unlock(&sc->aac_container_lock); 48583114Sscottl } 48683114Sscottl} 48783114Sscottl 48883114Sscottl/* 48965793Smsmith * Free all of the resources associated with (sc) 49065793Smsmith * 49165793Smsmith * Should not be called if the controller is active. 49265793Smsmith */ 49365793Smsmithvoid 49465793Smsmithaac_free(struct aac_softc *sc) 49565793Smsmith{ 496110604Sscottl 49783114Sscottl debug_called(1); 49865793Smsmith 49983114Sscottl /* remove the control device */ 50083114Sscottl if (sc->aac_dev_t != NULL) 50183114Sscottl destroy_dev(sc->aac_dev_t); 50265793Smsmith 50383114Sscottl /* throw away any FIB buffers, discard the FIB DMA tag */ 504111141Sscottl aac_free_commands(sc); 50583114Sscottl if (sc->aac_fib_dmat) 50683114Sscottl bus_dma_tag_destroy(sc->aac_fib_dmat); 50765793Smsmith 508110604Sscottl free(sc->aac_commands, M_AACBUF); 509110604Sscottl 51083114Sscottl /* destroy the common area */ 51183114Sscottl if (sc->aac_common) { 51283114Sscottl bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 51383114Sscottl bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 51483114Sscottl sc->aac_common_dmamap); 51583114Sscottl } 51683114Sscottl if (sc->aac_common_dmat) 51783114Sscottl bus_dma_tag_destroy(sc->aac_common_dmat); 51865793Smsmith 51983114Sscottl /* disconnect the interrupt handler */ 52083114Sscottl if (sc->aac_intr) 52183114Sscottl bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 52283114Sscottl if (sc->aac_irq != NULL) 52383114Sscottl bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 52483114Sscottl sc->aac_irq); 52565793Smsmith 52683114Sscottl /* destroy data-transfer DMA tag */ 52783114Sscottl if (sc->aac_buffer_dmat) 52883114Sscottl bus_dma_tag_destroy(sc->aac_buffer_dmat); 52965793Smsmith 53083114Sscottl /* destroy the parent DMA tag */ 53183114Sscottl if (sc->aac_parent_dmat) 53283114Sscottl bus_dma_tag_destroy(sc->aac_parent_dmat); 53365793Smsmith 53483114Sscottl /* release the register window mapping */ 53583114Sscottl if (sc->aac_regs_resource != NULL) 53683114Sscottl bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 53783114Sscottl sc->aac_regs_rid, sc->aac_regs_resource); 53865793Smsmith} 53965793Smsmith 54083114Sscottl/* 54165793Smsmith * Disconnect from the controller completely, in preparation for unload. 54265793Smsmith */ 54365793Smsmithint 54465793Smsmithaac_detach(device_t dev) 54565793Smsmith{ 54683114Sscottl struct aac_softc *sc; 547110426Sscottl struct aac_container *co; 548110426Sscottl struct aac_sim *sim; 54983114Sscottl int error; 55065793Smsmith 55183114Sscottl debug_called(1); 55265793Smsmith 55383114Sscottl sc = device_get_softc(dev); 55483114Sscottl 55583114Sscottl if (sc->aac_state & AAC_STATE_OPEN) 556110426Sscottl return(EBUSY); 55765793Smsmith 558110426Sscottl /* Remove the child containers */ 559110428Sscottl while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 560110426Sscottl error = device_delete_child(dev, co->co_disk); 561110426Sscottl if (error) 562110426Sscottl return (error); 563111196Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 564110428Sscottl free(co, M_AACBUF); 565110426Sscottl } 566110426Sscottl 567110426Sscottl /* Remove the CAM SIMs */ 568110428Sscottl while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 569110428Sscottl TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 570110426Sscottl error = device_delete_child(dev, sim->sim_dev); 571110426Sscottl if (error) 572110426Sscottl return (error); 573110428Sscottl free(sim, M_AACBUF); 574110426Sscottl } 575110426Sscottl 57683114Sscottl if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 57783114Sscottl sc->aifflags |= AAC_AIFFLAGS_EXIT; 57883114Sscottl wakeup(sc->aifthread); 57983114Sscottl tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 58083114Sscottl } 58182527Sscottl 58283114Sscottl if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 58383114Sscottl panic("Cannot shutdown AIF thread\n"); 58482527Sscottl 58583114Sscottl if ((error = aac_shutdown(dev))) 58683114Sscottl return(error); 58765793Smsmith 588110427Sscottl EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 589110427Sscottl 59083114Sscottl aac_free(sc); 59165793Smsmith 592133542Sscottl mtx_destroy(&sc->aac_aifq_lock); 593133542Sscottl mtx_destroy(&sc->aac_io_lock); 594133542Sscottl mtx_destroy(&sc->aac_container_lock); 595133542Sscottl 59683114Sscottl return(0); 59765793Smsmith} 59865793Smsmith 59983114Sscottl/* 60065793Smsmith * Bring the controller down to a dormant state and detach all child devices. 60165793Smsmith * 60265793Smsmith * This function is called before detach or system shutdown. 60365793Smsmith * 60470393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't 60565793Smsmith * allow shutdown if any device is open. 60665793Smsmith */ 60765793Smsmithint 60865793Smsmithaac_shutdown(device_t dev) 60965793Smsmith{ 61083114Sscottl struct aac_softc *sc; 61195350Sscottl struct aac_fib *fib; 61295350Sscottl struct aac_close_command *cc; 61365793Smsmith 61483114Sscottl debug_called(1); 61565793Smsmith 61683114Sscottl sc = device_get_softc(dev); 61765793Smsmith 61883114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 61965793Smsmith 62083114Sscottl /* 62183114Sscottl * Send a Container shutdown followed by a HostShutdown FIB to the 62283114Sscottl * controller to convince it that we don't want to talk to it anymore. 62383114Sscottl * We've been closed and all I/O completed already 62482527Sscottl */ 62583114Sscottl device_printf(sc->aac_dev, "shutting down controller..."); 62683114Sscottl 627151086Sscottl mtx_lock(&sc->aac_io_lock); 628130006Sscottl aac_alloc_sync_fib(sc, &fib); 62995350Sscottl cc = (struct aac_close_command *)&fib->data[0]; 63095350Sscottl 63195966Sscottl bzero(cc, sizeof(struct aac_close_command)); 63295350Sscottl cc->Command = VM_CloseAll; 63395350Sscottl cc->ContainerId = 0xffffffff; 63495350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 63595350Sscottl sizeof(struct aac_close_command))) 63683114Sscottl printf("FAILED.\n"); 637110426Sscottl else 638110426Sscottl printf("done\n"); 639110426Sscottl#if 0 64083114Sscottl else { 64195350Sscottl fib->data[0] = 0; 64283114Sscottl /* 64383114Sscottl * XXX Issuing this command to the controller makes it shut down 64483114Sscottl * but also keeps it from coming back up without a reset of the 64583114Sscottl * PCI bus. This is not desirable if you are just unloading the 64683114Sscottl * driver module with the intent to reload it later. 64783114Sscottl */ 64895350Sscottl if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 64995350Sscottl fib, 1)) { 65083114Sscottl printf("FAILED.\n"); 65183114Sscottl } else { 65283114Sscottl printf("done.\n"); 65383114Sscottl } 65465793Smsmith } 655110426Sscottl#endif 65665793Smsmith 65783114Sscottl AAC_MASK_INTERRUPTS(sc); 658133539Sscottl aac_release_sync_fib(sc); 659151086Sscottl mtx_unlock(&sc->aac_io_lock); 66065793Smsmith 66183114Sscottl return(0); 66265793Smsmith} 66365793Smsmith 66483114Sscottl/* 66565793Smsmith * Bring the controller to a quiescent state, ready for system suspend. 66665793Smsmith */ 66765793Smsmithint 66865793Smsmithaac_suspend(device_t dev) 66965793Smsmith{ 67083114Sscottl struct aac_softc *sc; 67165793Smsmith 67283114Sscottl debug_called(1); 67365793Smsmith 67483114Sscottl sc = device_get_softc(dev); 67583114Sscottl 67683114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 67783114Sscottl 67883114Sscottl AAC_MASK_INTERRUPTS(sc); 67983114Sscottl return(0); 68065793Smsmith} 68165793Smsmith 68283114Sscottl/* 68365793Smsmith * Bring the controller back to a state ready for operation. 68465793Smsmith */ 68565793Smsmithint 68665793Smsmithaac_resume(device_t dev) 68765793Smsmith{ 68883114Sscottl struct aac_softc *sc; 68965793Smsmith 69083114Sscottl debug_called(1); 69183114Sscottl 69283114Sscottl sc = device_get_softc(dev); 69383114Sscottl 69483114Sscottl sc->aac_state &= ~AAC_STATE_SUSPEND; 69583114Sscottl AAC_UNMASK_INTERRUPTS(sc); 69683114Sscottl return(0); 69765793Smsmith} 69865793Smsmith 69983114Sscottl/* 700151086Sscottl * Interrupt handler for NEW_COMM interface. 70165793Smsmith */ 70265793Smsmithvoid 703151086Sscottlaac_new_intr(void *arg) 70465793Smsmith{ 70583114Sscottl struct aac_softc *sc; 706151086Sscottl u_int32_t index, fast; 707151086Sscottl struct aac_command *cm; 708151086Sscottl struct aac_fib *fib; 709151086Sscottl int i; 710151086Sscottl 711151086Sscottl debug_called(2); 712151086Sscottl 713151086Sscottl sc = (struct aac_softc *)arg; 714151086Sscottl 715151086Sscottl mtx_lock(&sc->aac_io_lock); 716151086Sscottl while (1) { 717151086Sscottl index = AAC_GET_OUTB_QUEUE(sc); 718151086Sscottl if (index == 0xffffffff) 719151086Sscottl index = AAC_GET_OUTB_QUEUE(sc); 720151086Sscottl if (index == 0xffffffff) 721151086Sscottl break; 722151086Sscottl if (index & 2) { 723151086Sscottl if (index == 0xfffffffe) { 724151086Sscottl /* XXX This means that the controller wants 725151086Sscottl * more work. Ignore it for now. 726151086Sscottl */ 727151086Sscottl continue; 728151086Sscottl } 729151086Sscottl /* AIF */ 730151086Sscottl fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 731151086Sscottl M_NOWAIT | M_ZERO); 732151086Sscottl if (fib == NULL) { 733151086Sscottl /* If we're really this short on memory, 734151086Sscottl * hopefully breaking out of the handler will 735151086Sscottl * allow something to get freed. This 736151086Sscottl * actually sucks a whole lot. 737151086Sscottl */ 738151086Sscottl break; 739151086Sscottl } 740151086Sscottl index &= ~2; 741151086Sscottl for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 742151086Sscottl ((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4); 743151086Sscottl aac_handle_aif(sc, fib); 744151086Sscottl free(fib, M_AACBUF); 745151086Sscottl 746151086Sscottl /* 747151086Sscottl * AIF memory is owned by the adapter, so let it 748151086Sscottl * know that we are done with it. 749151086Sscottl */ 750151086Sscottl AAC_SET_OUTB_QUEUE(sc, index); 751151086Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 752151086Sscottl } else { 753151086Sscottl fast = index & 1; 754151086Sscottl cm = sc->aac_commands + (index >> 2); 755151086Sscottl fib = cm->cm_fib; 756151086Sscottl if (fast) { 757151086Sscottl fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 758151086Sscottl *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 759151086Sscottl } 760151086Sscottl aac_remove_busy(cm); 761151086Sscottl aac_unmap_command(cm); 762151086Sscottl cm->cm_flags |= AAC_CMD_COMPLETED; 763151086Sscottl 764151086Sscottl /* is there a completion handler? */ 765151086Sscottl if (cm->cm_complete != NULL) { 766151086Sscottl cm->cm_complete(cm); 767151086Sscottl } else { 768151086Sscottl /* assume that someone is sleeping on this 769151086Sscottl * command 770151086Sscottl */ 771151086Sscottl wakeup(cm); 772151086Sscottl } 773151086Sscottl sc->flags &= ~AAC_QUEUE_FRZN; 774151086Sscottl } 775151086Sscottl } 776151086Sscottl /* see if we can start some more I/O */ 777151086Sscottl if ((sc->flags & AAC_QUEUE_FRZN) == 0) 778151086Sscottl aac_startio(sc); 779151086Sscottl 780151086Sscottl mtx_unlock(&sc->aac_io_lock); 781151086Sscottl} 782151086Sscottl 783151086Sscottlvoid 784151086Sscottlaac_fast_intr(void *arg) 785151086Sscottl{ 786151086Sscottl struct aac_softc *sc; 78783114Sscottl u_int16_t reason; 78865793Smsmith 78983114Sscottl debug_called(2); 79065793Smsmith 79183114Sscottl sc = (struct aac_softc *)arg; 79265793Smsmith 793109088Sscottl /* 794125225Sscottl * Read the status register directly. This is faster than taking the 795125225Sscottl * driver lock and reading the queues directly. It also saves having 796125225Sscottl * to turn parts of the driver lock into a spin mutex, which would be 797125225Sscottl * ugly. 798109088Sscottl */ 799125225Sscottl reason = AAC_GET_ISTATUS(sc); 800109088Sscottl AAC_CLEAR_ISTATUS(sc, reason); 80165793Smsmith 802125225Sscottl /* handle completion processing */ 803109088Sscottl if (reason & AAC_DB_RESPONSE_READY) 804125225Sscottl taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 805109088Sscottl 806125225Sscottl /* controller wants to talk to us */ 807125225Sscottl if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 808125225Sscottl /* 809125225Sscottl * XXX Make sure that we don't get fooled by strange messages 810125225Sscottl * that start with a NULL. 811125225Sscottl */ 812125225Sscottl if ((reason & AAC_DB_PRINTF) && 813151086Sscottl (sc->aac_common->ac_printf[0] == 0)) 814125225Sscottl sc->aac_common->ac_printf[0] = 32; 81565793Smsmith 816125225Sscottl /* 817125225Sscottl * This might miss doing the actual wakeup. However, the 818125542Sscottl * msleep that this is waking up has a timeout, so it will 819125225Sscottl * wake up eventually. AIFs and printfs are low enough 820125225Sscottl * priority that they can handle hanging out for a few seconds 821125225Sscottl * if needed. 822125225Sscottl */ 823125225Sscottl wakeup(sc->aifthread); 82483114Sscottl } 825109088Sscottl} 82683114Sscottl 82783114Sscottl/* 82883114Sscottl * Command Processing 82983114Sscottl */ 83065793Smsmith 83183114Sscottl/* 83265793Smsmith * Start as much queued I/O as possible on the controller 83365793Smsmith */ 83495536Sscottlvoid 83565793Smsmithaac_startio(struct aac_softc *sc) 83665793Smsmith{ 83783114Sscottl struct aac_command *cm; 838129923Sscottl int error; 83965793Smsmith 84083114Sscottl debug_called(2); 84165793Smsmith 84283114Sscottl for (;;) { 84383114Sscottl /* 844129923Sscottl * This flag might be set if the card is out of resources. 845129923Sscottl * Checking it here prevents an infinite loop of deferrals. 846129923Sscottl */ 847129923Sscottl if (sc->flags & AAC_QUEUE_FRZN) 848129923Sscottl break; 849129923Sscottl 850129923Sscottl /* 85183114Sscottl * Try to get a command that's been put off for lack of 85283114Sscottl * resources 85383114Sscottl */ 85483114Sscottl cm = aac_dequeue_ready(sc); 85565793Smsmith 85683114Sscottl /* 85783114Sscottl * Try to build a command off the bio queue (ignore error 85883114Sscottl * return) 85983114Sscottl */ 86083114Sscottl if (cm == NULL) 86183114Sscottl aac_bio_command(sc, &cm); 86265793Smsmith 86383114Sscottl /* nothing to do? */ 86483114Sscottl if (cm == NULL) 86583114Sscottl break; 86665793Smsmith 867129923Sscottl /* don't map more than once */ 868129923Sscottl if (cm->cm_flags & AAC_CMD_MAPPED) 869129923Sscottl panic("aac: command %p already mapped", cm); 870129923Sscottl 871125559Sscottl /* 872129923Sscottl * Set up the command to go to the controller. If there are no 873129923Sscottl * data buffers associated with the command then it can bypass 874129923Sscottl * busdma. 875125559Sscottl */ 876129923Sscottl if (cm->cm_datalen != 0) { 877129923Sscottl error = bus_dmamap_load(sc->aac_buffer_dmat, 878129923Sscottl cm->cm_datamap, cm->cm_data, 879129923Sscottl cm->cm_datalen, 880129923Sscottl aac_map_command_sg, cm, 0); 881129923Sscottl if (error == EINPROGRESS) { 882129923Sscottl debug(1, "freezing queue\n"); 883129923Sscottl sc->flags |= AAC_QUEUE_FRZN; 884129923Sscottl error = 0; 885129946Sscottl } else if (error != 0) 886129923Sscottl panic("aac_startio: unexpected error %d from " 887129923Sscottl "busdma\n", error); 888129923Sscottl } else 889129923Sscottl aac_map_command_sg(cm, NULL, 0, 0); 89065793Smsmith } 89165793Smsmith} 89265793Smsmith 89383114Sscottl/* 89465793Smsmith * Handle notification of one or more FIBs coming from the controller. 89565793Smsmith */ 89665793Smsmithstatic void 897110426Sscottlaac_command_thread(struct aac_softc *sc) 89865793Smsmith{ 89983114Sscottl struct aac_fib *fib; 90083114Sscottl u_int32_t fib_size; 901125225Sscottl int size, retval; 90265793Smsmith 90383114Sscottl debug_called(2); 90465793Smsmith 905133540Sscottl mtx_lock(&sc->aac_io_lock); 906125542Sscottl sc->aifflags = AAC_AIFFLAGS_RUNNING; 90765793Smsmith 908125542Sscottl while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 90982527Sscottl 910125542Sscottl retval = 0; 911125542Sscottl if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 912125542Sscottl retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 913125542Sscottl "aifthd", AAC_PERIODIC_INTERVAL * hz); 914125542Sscottl 915125225Sscottl /* 916125225Sscottl * First see if any FIBs need to be allocated. This needs 917125225Sscottl * to be called without the driver lock because contigmalloc 918125225Sscottl * will grab Giant, and would result in an LOR. 919125225Sscottl */ 920125225Sscottl if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 921133540Sscottl mtx_unlock(&sc->aac_io_lock); 922125225Sscottl aac_alloc_commands(sc); 923133540Sscottl mtx_lock(&sc->aac_io_lock); 924125559Sscottl sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 925125542Sscottl aac_startio(sc); 926125225Sscottl } 927125225Sscottl 928125225Sscottl /* 929125225Sscottl * While we're here, check to see if any commands are stuck. 930125225Sscottl * This is pretty low-priority, so it's ok if it doesn't 931125225Sscottl * always fire. 932125225Sscottl */ 933125225Sscottl if (retval == EWOULDBLOCK) 934110426Sscottl aac_timeout(sc); 935110426Sscottl 936110426Sscottl /* Check the hardware printf message buffer */ 937125225Sscottl if (sc->aac_common->ac_printf[0] != 0) 938110426Sscottl aac_print_printf(sc); 939110426Sscottl 940125225Sscottl /* Also check to see if the adapter has a command for us. */ 941151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 942151086Sscottl continue; 943151086Sscottl for (;;) { 944151086Sscottl if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 945151086Sscottl &fib_size, &fib)) 946151086Sscottl break; 94783114Sscottl 94883114Sscottl AAC_PRINT_FIB(sc, fib); 94983114Sscottl 95083114Sscottl switch (fib->Header.Command) { 95183114Sscottl case AifRequest: 95283114Sscottl aac_handle_aif(sc, fib); 95383114Sscottl break; 95483114Sscottl default: 95583114Sscottl device_printf(sc->aac_dev, "unknown command " 95683114Sscottl "from controller\n"); 95783114Sscottl break; 95883114Sscottl } 95982527Sscottl 96083114Sscottl if ((fib->Header.XferState == 0) || 961151086Sscottl (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 96283114Sscottl break; 963151086Sscottl } 96482527Sscottl 965110426Sscottl /* Return the AIF to the controller. */ 96683114Sscottl if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 96783114Sscottl fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 96883114Sscottl *(AAC_FSAStatus*)fib->data = ST_OK; 96982527Sscottl 97083114Sscottl /* XXX Compute the Size field? */ 97183114Sscottl size = fib->Header.Size; 97283114Sscottl if (size > sizeof(struct aac_fib)) { 97395536Sscottl size = sizeof(struct aac_fib); 97483114Sscottl fib->Header.Size = size; 97583114Sscottl } 97683114Sscottl /* 97783114Sscottl * Since we did not generate this command, it 97883114Sscottl * cannot go through the normal 97983114Sscottl * enqueue->startio chain. 98083114Sscottl */ 98183114Sscottl aac_enqueue_response(sc, 982151086Sscottl AAC_ADAP_NORM_RESP_QUEUE, 983151086Sscottl fib); 98483114Sscottl } 98582527Sscottl } 98665793Smsmith } 98783114Sscottl sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 988133540Sscottl mtx_unlock(&sc->aac_io_lock); 98983114Sscottl wakeup(sc->aac_dev); 99065793Smsmith 99183114Sscottl kthread_exit(0); 99265793Smsmith} 99365793Smsmith 99483114Sscottl/* 995111143Sscottl * Process completed commands. 99665793Smsmith */ 99765793Smsmithstatic void 998111143Sscottlaac_complete(void *context, int pending) 99965793Smsmith{ 1000111143Sscottl struct aac_softc *sc; 100183114Sscottl struct aac_command *cm; 100283114Sscottl struct aac_fib *fib; 100383114Sscottl u_int32_t fib_size; 100465793Smsmith 100583114Sscottl debug_called(2); 100665793Smsmith 1007111143Sscottl sc = (struct aac_softc *)context; 1008111143Sscottl 1009133540Sscottl mtx_lock(&sc->aac_io_lock); 1010111532Sscottl 1011111143Sscottl /* pull completed commands off the queue */ 101283114Sscottl for (;;) { 101383114Sscottl /* look for completed FIBs on our queue */ 101483114Sscottl if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1015151086Sscottl &fib)) 101683114Sscottl break; /* nothing to do */ 1017111143Sscottl 1018125574Sscottl /* get the command, unmap and hand off for processing */ 1019111152Sscottl cm = sc->aac_commands + fib->Header.SenderData; 102083114Sscottl if (cm == NULL) { 102183114Sscottl AAC_PRINT_FIB(sc, fib); 1022111143Sscottl break; 102383114Sscottl } 1024151086Sscottl aac_remove_busy(cm); 102565793Smsmith 1026151086Sscottl aac_unmap_command(cm); 102783114Sscottl cm->cm_flags |= AAC_CMD_COMPLETED; 102883114Sscottl 102983114Sscottl /* is there a completion handler? */ 103083114Sscottl if (cm->cm_complete != NULL) { 103183114Sscottl cm->cm_complete(cm); 103283114Sscottl } else { 103383114Sscottl /* assume that someone is sleeping on this command */ 103483114Sscottl wakeup(cm); 103583114Sscottl } 103665793Smsmith } 103770393Smsmith 103883114Sscottl /* see if we can start some more I/O */ 1039117363Sscottl sc->flags &= ~AAC_QUEUE_FRZN; 104083114Sscottl aac_startio(sc); 1041111532Sscottl 1042133540Sscottl mtx_unlock(&sc->aac_io_lock); 104365793Smsmith} 104465793Smsmith 104583114Sscottl/* 104665793Smsmith * Handle a bio submitted from a disk device. 104765793Smsmith */ 104865793Smsmithvoid 104965793Smsmithaac_submit_bio(struct bio *bp) 105065793Smsmith{ 105183114Sscottl struct aac_disk *ad; 105283114Sscottl struct aac_softc *sc; 105365793Smsmith 105483114Sscottl debug_called(2); 105565793Smsmith 1056111525Sscottl ad = (struct aac_disk *)bp->bio_disk->d_drv1; 105783114Sscottl sc = ad->ad_controller; 105883114Sscottl 105983114Sscottl /* queue the BIO and try to get some work done */ 106083114Sscottl aac_enqueue_bio(sc, bp); 106183114Sscottl aac_startio(sc); 106265793Smsmith} 106365793Smsmith 106483114Sscottl/* 106565793Smsmith * Get a bio and build a command to go with it. 106665793Smsmith */ 106765793Smsmithstatic int 106865793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 106965793Smsmith{ 107083114Sscottl struct aac_command *cm; 107183114Sscottl struct aac_fib *fib; 107283114Sscottl struct aac_disk *ad; 107383114Sscottl struct bio *bp; 107465793Smsmith 107583114Sscottl debug_called(2); 107665793Smsmith 107783114Sscottl /* get the resources we will need */ 107883114Sscottl cm = NULL; 1079125542Sscottl bp = NULL; 1080125542Sscottl if (aac_alloc_command(sc, &cm)) /* get a command */ 1081125542Sscottl goto fail; 108283114Sscottl if ((bp = aac_dequeue_bio(sc)) == NULL) 108383114Sscottl goto fail; 108465793Smsmith 108583114Sscottl /* fill out the command */ 108683114Sscottl cm->cm_data = (void *)bp->bio_data; 108783114Sscottl cm->cm_datalen = bp->bio_bcount; 108883114Sscottl cm->cm_complete = aac_bio_complete; 108983114Sscottl cm->cm_private = bp; 1090150119Sscottl cm->cm_timestamp = time_uptime; 109183114Sscottl cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 109265793Smsmith 109383114Sscottl /* build the FIB */ 109483114Sscottl fib = cm->cm_fib; 1095112856Sscottl fib->Header.Size = sizeof(struct aac_fib_header); 109683114Sscottl fib->Header.XferState = 1097109088Sscottl AAC_FIBSTATE_HOSTOWNED | 1098109088Sscottl AAC_FIBSTATE_INITIALISED | 1099109088Sscottl AAC_FIBSTATE_EMPTY | 1100109088Sscottl AAC_FIBSTATE_FROMHOST | 1101109088Sscottl AAC_FIBSTATE_REXPECTED | 1102109088Sscottl AAC_FIBSTATE_NORM | 1103109088Sscottl AAC_FIBSTATE_ASYNC | 1104109088Sscottl AAC_FIBSTATE_FAST_RESPONSE; 110565793Smsmith 110683114Sscottl /* build the read/write request */ 1107111525Sscottl ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1108112856Sscottl 1109151086Sscottl if (sc->flags & AAC_FLAGS_RAW_IO) { 1110151086Sscottl struct aac_raw_io *raw; 1111151086Sscottl raw = (struct aac_raw_io *)&fib->data[0]; 1112151086Sscottl fib->Header.Command = RawIo; 1113151086Sscottl raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 1114151086Sscottl raw->ByteCount = bp->bio_bcount; 1115151086Sscottl raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1116151086Sscottl raw->BpTotal = 0; 1117151086Sscottl raw->BpComplete = 0; 1118151086Sscottl fib->Header.Size += sizeof(struct aac_raw_io); 1119151086Sscottl cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 1120151086Sscottl if (bp->bio_cmd == BIO_READ) { 1121151086Sscottl raw->Flags = 1; 1122151086Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 1123151086Sscottl } else { 1124151086Sscottl raw->Flags = 0; 1125151086Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 1126151086Sscottl } 1127151086Sscottl } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1128112856Sscottl fib->Header.Command = ContainerCommand; 1129112856Sscottl if (bp->bio_cmd == BIO_READ) { 1130112856Sscottl struct aac_blockread *br; 1131112856Sscottl br = (struct aac_blockread *)&fib->data[0]; 1132112856Sscottl br->Command = VM_CtBlockRead; 1133112856Sscottl br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1134112856Sscottl br->BlockNumber = bp->bio_pblkno; 1135112856Sscottl br->ByteCount = bp->bio_bcount; 1136112856Sscottl fib->Header.Size += sizeof(struct aac_blockread); 1137112856Sscottl cm->cm_sgtable = &br->SgMap; 1138112856Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 1139112856Sscottl } else { 1140112856Sscottl struct aac_blockwrite *bw; 1141112856Sscottl bw = (struct aac_blockwrite *)&fib->data[0]; 1142112856Sscottl bw->Command = VM_CtBlockWrite; 1143112856Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1144112856Sscottl bw->BlockNumber = bp->bio_pblkno; 1145112856Sscottl bw->ByteCount = bp->bio_bcount; 1146112856Sscottl bw->Stable = CUNSTABLE; 1147112856Sscottl fib->Header.Size += sizeof(struct aac_blockwrite); 1148112856Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 1149112856Sscottl cm->cm_sgtable = &bw->SgMap; 1150112856Sscottl } 115183114Sscottl } else { 1152112856Sscottl fib->Header.Command = ContainerCommand64; 1153112856Sscottl if (bp->bio_cmd == BIO_READ) { 1154112856Sscottl struct aac_blockread64 *br; 1155112856Sscottl br = (struct aac_blockread64 *)&fib->data[0]; 1156112856Sscottl br->Command = VM_CtHostRead64; 1157112856Sscottl br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1158112856Sscottl br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1159112856Sscottl br->BlockNumber = bp->bio_pblkno; 1160112856Sscottl br->Pad = 0; 1161112856Sscottl br->Flags = 0; 1162112856Sscottl fib->Header.Size += sizeof(struct aac_blockread64); 1163112856Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 1164132771Skan cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1165112856Sscottl } else { 1166112856Sscottl struct aac_blockwrite64 *bw; 1167112856Sscottl bw = (struct aac_blockwrite64 *)&fib->data[0]; 1168112856Sscottl bw->Command = VM_CtHostWrite64; 1169112856Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1170112856Sscottl bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1171112856Sscottl bw->BlockNumber = bp->bio_pblkno; 1172112856Sscottl bw->Pad = 0; 1173112856Sscottl bw->Flags = 0; 1174112856Sscottl fib->Header.Size += sizeof(struct aac_blockwrite64); 1175112856Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 1176132771Skan cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1177112856Sscottl } 117883114Sscottl } 117965793Smsmith 118083114Sscottl *cmp = cm; 118183114Sscottl return(0); 118265793Smsmith 118365793Smsmithfail: 1184151086Sscottl if (bp != NULL) 1185151086Sscottl aac_enqueue_bio(sc, bp); 118683114Sscottl if (cm != NULL) 118783114Sscottl aac_release_command(cm); 118883114Sscottl return(ENOMEM); 118965793Smsmith} 119065793Smsmith 119183114Sscottl/* 119265793Smsmith * Handle a bio-instigated command that has been completed. 119365793Smsmith */ 119465793Smsmithstatic void 119565793Smsmithaac_bio_complete(struct aac_command *cm) 119665793Smsmith{ 119783114Sscottl struct aac_blockread_response *brr; 119883114Sscottl struct aac_blockwrite_response *bwr; 119983114Sscottl struct bio *bp; 120083114Sscottl AAC_FSAStatus status; 120165793Smsmith 120283114Sscottl /* fetch relevant status and then release the command */ 120383114Sscottl bp = (struct bio *)cm->cm_private; 1204111691Sscottl if (bp->bio_cmd == BIO_READ) { 120583114Sscottl brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 120683114Sscottl status = brr->Status; 120783114Sscottl } else { 120883114Sscottl bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 120983114Sscottl status = bwr->Status; 121083114Sscottl } 121183114Sscottl aac_release_command(cm); 121265793Smsmith 121383114Sscottl /* fix up the bio based on status */ 121483114Sscottl if (status == ST_OK) { 121583114Sscottl bp->bio_resid = 0; 121683114Sscottl } else { 121783114Sscottl bp->bio_error = EIO; 121883114Sscottl bp->bio_flags |= BIO_ERROR; 121983114Sscottl /* pass an error string out to the disk layer */ 122083114Sscottl bp->bio_driver1 = aac_describe_code(aac_command_status_table, 122183114Sscottl status); 122283114Sscottl } 122383114Sscottl aac_biodone(bp); 122465793Smsmith} 122565793Smsmith 122683114Sscottl/* 122765793Smsmith * Submit a command to the controller, return when it completes. 122887183Sscottl * XXX This is very dangerous! If the card has gone out to lunch, we could 122987183Sscottl * be stuck here forever. At the same time, signals are not caught 1230128258Sscottl * because there is a risk that a signal could wakeup the sleep before 1231128258Sscottl * the card has a chance to complete the command. Since there is no way 1232128258Sscottl * to cancel a command that is in progress, we can't protect against the 1233128258Sscottl * card completing a command late and spamming the command and data 1234128258Sscottl * memory. So, we are held hostage until the command completes. 123565793Smsmith */ 123665793Smsmithstatic int 1237128258Sscottlaac_wait_command(struct aac_command *cm) 123865793Smsmith{ 1239111532Sscottl struct aac_softc *sc; 1240128258Sscottl int error; 124165793Smsmith 124283114Sscottl debug_called(2); 124365793Smsmith 1244111532Sscottl sc = cm->cm_sc; 1245111532Sscottl 124683114Sscottl /* Put the command on the ready queue and get things going */ 124783114Sscottl cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 124883114Sscottl aac_enqueue_ready(cm); 1249111532Sscottl aac_startio(sc); 1250128258Sscottl error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 125183114Sscottl return(error); 125265793Smsmith} 125365793Smsmith 125483114Sscottl/* 125583114Sscottl *Command Buffer Management 125683114Sscottl */ 125765793Smsmith 125883114Sscottl/* 125965793Smsmith * Allocate a command. 126065793Smsmith */ 126195536Sscottlint 126265793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 126365793Smsmith{ 126483114Sscottl struct aac_command *cm; 126565793Smsmith 126683114Sscottl debug_called(3); 126765793Smsmith 1268110604Sscottl if ((cm = aac_dequeue_free(sc)) == NULL) { 1269112856Sscottl if (sc->total_fibs < sc->aac_max_fibs) { 1270112856Sscottl sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1271112856Sscottl wakeup(sc->aifthread); 1272112856Sscottl } 1273111532Sscottl return (EBUSY); 1274110604Sscottl } 127565793Smsmith 127683114Sscottl *cmp = cm; 127783114Sscottl return(0); 127870393Smsmith} 127970393Smsmith 128083114Sscottl/* 128170393Smsmith * Release a command back to the freelist. 128270393Smsmith */ 128395536Sscottlvoid 128470393Smsmithaac_release_command(struct aac_command *cm) 128570393Smsmith{ 1286151086Sscottl struct aac_event *event; 1287151086Sscottl struct aac_softc *sc; 1288151086Sscottl 128983114Sscottl debug_called(3); 129070393Smsmith 129183114Sscottl /* (re)initialise the command/FIB */ 129283114Sscottl cm->cm_sgtable = NULL; 129383114Sscottl cm->cm_flags = 0; 129483114Sscottl cm->cm_complete = NULL; 129583114Sscottl cm->cm_private = NULL; 129683114Sscottl cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 129783114Sscottl cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 129883114Sscottl cm->cm_fib->Header.Flags = 0; 1299151086Sscottl cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 130065793Smsmith 130183114Sscottl /* 130283114Sscottl * These are duplicated in aac_start to cover the case where an 130383114Sscottl * intermediate stage may have destroyed them. They're left 130483114Sscottl * initialised here for debugging purposes only. 130583114Sscottl */ 1306109088Sscottl cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1307109088Sscottl cm->cm_fib->Header.SenderData = 0; 130865793Smsmith 130983114Sscottl aac_enqueue_free(cm); 1310151086Sscottl 1311151086Sscottl sc = cm->cm_sc; 1312151086Sscottl event = TAILQ_FIRST(&sc->aac_ev_cmfree); 1313151086Sscottl if (event != NULL) { 1314151086Sscottl TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1315151086Sscottl event->ev_callback(sc, event, event->ev_arg); 1316151086Sscottl } 131765793Smsmith} 131865793Smsmith 131983114Sscottl/* 132070393Smsmith * Map helper for command/FIB allocation. 132165793Smsmith */ 132265793Smsmithstatic void 132370393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 132465793Smsmith{ 1325151086Sscottl uint64_t *fibphys; 132665793Smsmith 1327151086Sscottl fibphys = (uint64_t *)arg; 132865793Smsmith 132983114Sscottl debug_called(3); 133083114Sscottl 1331110604Sscottl *fibphys = segs[0].ds_addr; 133265793Smsmith} 133365793Smsmith 133483114Sscottl/* 133570393Smsmith * Allocate and initialise commands/FIBs for this adapter. 133665793Smsmith */ 133770393Smsmithstatic int 133870393Smsmithaac_alloc_commands(struct aac_softc *sc) 133965793Smsmith{ 134083114Sscottl struct aac_command *cm; 1341110604Sscottl struct aac_fibmap *fm; 1342151086Sscottl uint64_t fibphys; 1343110604Sscottl int i, error; 134465793Smsmith 1345112679Sscottl debug_called(2); 134665793Smsmith 1347151086Sscottl if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1348110604Sscottl return (ENOMEM); 1349110604Sscottl 1350111141Sscottl fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1351112679Sscottl if (fm == NULL) 1352112679Sscottl return (ENOMEM); 1353110604Sscottl 135483114Sscottl /* allocate the FIBs in DMAable memory and load them */ 1355110604Sscottl if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1356110604Sscottl BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1357110426Sscottl device_printf(sc->aac_dev, 1358110426Sscottl "Not enough contiguous memory available.\n"); 1359111141Sscottl free(fm, M_AACBUF); 1360102602Sscottl return (ENOMEM); 136183114Sscottl } 1362109716Sscottl 1363117363Sscottl /* Ignore errors since this doesn't bounce */ 1364117363Sscottl (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1365151086Sscottl sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1366117363Sscottl aac_map_command_helper, &fibphys, 0); 1367109716Sscottl 1368109716Sscottl /* initialise constant fields in the command structure */ 1369133540Sscottl mtx_lock(&sc->aac_io_lock); 1370151086Sscottl bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 1371151086Sscottl for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1372111141Sscottl cm = sc->aac_commands + sc->total_fibs; 1373110604Sscottl fm->aac_commands = cm; 137483114Sscottl cm->cm_sc = sc; 1375151086Sscottl cm->cm_fib = (struct aac_fib *) 1376151086Sscottl ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 1377151086Sscottl cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1378111152Sscottl cm->cm_index = sc->total_fibs; 137965793Smsmith 1380110604Sscottl if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1381110604Sscottl &cm->cm_datamap)) == 0) 138283114Sscottl aac_release_command(cm); 1383111141Sscottl else 1384111141Sscottl break; 1385111141Sscottl sc->total_fibs++; 138683114Sscottl } 1387110604Sscottl 1388111141Sscottl if (i > 0) { 1389111141Sscottl TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1390112679Sscottl debug(1, "total_fibs= %d\n", sc->total_fibs); 1391133540Sscottl mtx_unlock(&sc->aac_io_lock); 1392111141Sscottl return (0); 1393111141Sscottl } 1394110604Sscottl 1395133540Sscottl mtx_unlock(&sc->aac_io_lock); 1396111141Sscottl bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1397111141Sscottl bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1398111141Sscottl free(fm, M_AACBUF); 1399111141Sscottl return (ENOMEM); 140065793Smsmith} 140165793Smsmith 140283114Sscottl/* 140370393Smsmith * Free FIBs owned by this adapter. 140465793Smsmith */ 140565793Smsmithstatic void 1406111141Sscottlaac_free_commands(struct aac_softc *sc) 140765793Smsmith{ 1408111141Sscottl struct aac_fibmap *fm; 1409110604Sscottl struct aac_command *cm; 141083114Sscottl int i; 141165793Smsmith 141283114Sscottl debug_called(1); 141365793Smsmith 1414111141Sscottl while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1415111141Sscottl 1416111141Sscottl TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1417111141Sscottl /* 1418111141Sscottl * We check against total_fibs to handle partially 1419111141Sscottl * allocated blocks. 1420111141Sscottl */ 1421151086Sscottl for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1422111141Sscottl cm = fm->aac_commands + i; 1423111141Sscottl bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1424111141Sscottl } 1425111141Sscottl bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1426111141Sscottl bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1427111141Sscottl free(fm, M_AACBUF); 1428110604Sscottl } 142965793Smsmith} 143065793Smsmith 143183114Sscottl/* 143265793Smsmith * Command-mapping helper function - populate this command's s/g table. 143365793Smsmith */ 143465793Smsmithstatic void 143565793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 143665793Smsmith{ 1437117363Sscottl struct aac_softc *sc; 143883114Sscottl struct aac_command *cm; 143983114Sscottl struct aac_fib *fib; 144083114Sscottl int i; 144165793Smsmith 144283114Sscottl debug_called(3); 144365793Smsmith 144483114Sscottl cm = (struct aac_command *)arg; 1445117363Sscottl sc = cm->cm_sc; 144683114Sscottl fib = cm->cm_fib; 144765793Smsmith 144883114Sscottl /* copy into the FIB */ 1449112856Sscottl if (cm->cm_sgtable != NULL) { 1450151086Sscottl if (fib->Header.Command == RawIo) { 1451151086Sscottl struct aac_sg_tableraw *sg; 1452151086Sscottl sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1453151086Sscottl sg->SgCount = nseg; 1454151086Sscottl for (i = 0; i < nseg; i++) { 1455151086Sscottl sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1456151086Sscottl sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1457151086Sscottl sg->SgEntryRaw[i].Next = 0; 1458151086Sscottl sg->SgEntryRaw[i].Prev = 0; 1459151086Sscottl sg->SgEntryRaw[i].Flags = 0; 1460151086Sscottl } 1461151086Sscottl /* update the FIB size for the s/g count */ 1462151086Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1463151086Sscottl } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1464112856Sscottl struct aac_sg_table *sg; 1465112856Sscottl sg = cm->cm_sgtable; 1466112856Sscottl sg->SgCount = nseg; 1467112856Sscottl for (i = 0; i < nseg; i++) { 1468112856Sscottl sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1469112856Sscottl sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1470112856Sscottl } 1471112856Sscottl /* update the FIB size for the s/g count */ 1472151086Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1473112856Sscottl } else { 1474112856Sscottl struct aac_sg_table64 *sg; 1475112856Sscottl sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1476112856Sscottl sg->SgCount = nseg; 1477112856Sscottl for (i = 0; i < nseg; i++) { 1478112856Sscottl sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1479112856Sscottl sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1480112856Sscottl } 1481112856Sscottl /* update the FIB size for the s/g count */ 1482112856Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 148383114Sscottl } 148465793Smsmith } 148565793Smsmith 1486117363Sscottl /* Fix up the address values in the FIB. Use the command array index 1487117363Sscottl * instead of a pointer since these fields are only 32 bits. Shift 1488151086Sscottl * the SenderFibAddress over to make room for the fast response bit 1489151086Sscottl * and for the AIF bit 1490117363Sscottl */ 1491151086Sscottl cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1492151086Sscottl cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 149365793Smsmith 1494117363Sscottl /* save a pointer to the command for speedy reverse-lookup */ 1495117363Sscottl cm->cm_fib->Header.SenderData = cm->cm_index; 149665793Smsmith 1497117363Sscottl if (cm->cm_flags & AAC_CMD_DATAIN) 1498117363Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1499117363Sscottl BUS_DMASYNC_PREREAD); 1500117363Sscottl if (cm->cm_flags & AAC_CMD_DATAOUT) 1501117363Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1502117363Sscottl BUS_DMASYNC_PREWRITE); 1503117363Sscottl cm->cm_flags |= AAC_CMD_MAPPED; 150465793Smsmith 1505151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) { 1506151086Sscottl int count = 10000000L; 1507151086Sscottl while (AAC_SEND_COMMAND(sc, cm) != 0) { 1508151086Sscottl if (--count == 0) { 1509151086Sscottl aac_unmap_command(cm); 1510151086Sscottl sc->flags |= AAC_QUEUE_FRZN; 1511151086Sscottl aac_requeue_ready(cm); 1512151086Sscottl } 1513151086Sscottl DELAY(5); /* wait 5 usec. */ 1514151086Sscottl } 1515151086Sscottl } else { 1516151086Sscottl /* Put the FIB on the outbound queue */ 1517151086Sscottl if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 1518151086Sscottl aac_unmap_command(cm); 1519151086Sscottl sc->flags |= AAC_QUEUE_FRZN; 1520151086Sscottl aac_requeue_ready(cm); 1521151086Sscottl } 1522125559Sscottl } 152365793Smsmith 1524117363Sscottl return; 152565793Smsmith} 152665793Smsmith 152783114Sscottl/* 152865793Smsmith * Unmap a command from controller-visible space. 152965793Smsmith */ 153065793Smsmithstatic void 153165793Smsmithaac_unmap_command(struct aac_command *cm) 153265793Smsmith{ 153383114Sscottl struct aac_softc *sc; 153465793Smsmith 153583114Sscottl debug_called(2); 153665793Smsmith 153783114Sscottl sc = cm->cm_sc; 153865793Smsmith 153983114Sscottl if (!(cm->cm_flags & AAC_CMD_MAPPED)) 154083114Sscottl return; 154165793Smsmith 154283114Sscottl if (cm->cm_datalen != 0) { 154383114Sscottl if (cm->cm_flags & AAC_CMD_DATAIN) 154483114Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 154583114Sscottl BUS_DMASYNC_POSTREAD); 154683114Sscottl if (cm->cm_flags & AAC_CMD_DATAOUT) 154783114Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 154883114Sscottl BUS_DMASYNC_POSTWRITE); 154983114Sscottl 155083114Sscottl bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 155183114Sscottl } 155283114Sscottl cm->cm_flags &= ~AAC_CMD_MAPPED; 155365793Smsmith} 155465793Smsmith 155583114Sscottl/* 155683114Sscottl * Hardware Interface 155783114Sscottl */ 155865793Smsmith 155983114Sscottl/* 156065793Smsmith * Initialise the adapter. 156165793Smsmith */ 156265793Smsmithstatic void 156365793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 156465793Smsmith{ 156583114Sscottl struct aac_softc *sc; 156665793Smsmith 156783114Sscottl debug_called(1); 156865793Smsmith 156983114Sscottl sc = (struct aac_softc *)arg; 157083114Sscottl 157183114Sscottl sc->aac_common_busaddr = segs[0].ds_addr; 157265793Smsmith} 157365793Smsmith 157465793Smsmithstatic int 157590275Sscottlaac_check_firmware(struct aac_softc *sc) 157690275Sscottl{ 1577151086Sscottl u_int32_t major, minor, options, atu_size; 157890275Sscottl 157990275Sscottl debug_called(1); 158090275Sscottl 1581112679Sscottl /* 1582112679Sscottl * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1583112679Sscottl * firmware version 1.x are not compatible with this driver. 1584112679Sscottl */ 1585112679Sscottl if (sc->flags & AAC_FLAGS_PERC2QC) { 158690275Sscottl if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 158790275Sscottl NULL)) { 158890275Sscottl device_printf(sc->aac_dev, 158990275Sscottl "Error reading firmware version\n"); 159090275Sscottl return (EIO); 159190275Sscottl } 159290275Sscottl 159390275Sscottl /* These numbers are stored as ASCII! */ 1594112679Sscottl major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1595112679Sscottl minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 159690275Sscottl if (major == 1) { 159790275Sscottl device_printf(sc->aac_dev, 159890275Sscottl "Firmware version %d.%d is not supported.\n", 159990275Sscottl major, minor); 160090275Sscottl return (EINVAL); 160190275Sscottl } 160290275Sscottl } 160390275Sscottl 1604112679Sscottl /* 1605112679Sscottl * Retrieve the capabilities/supported options word so we know what 1606112679Sscottl * work-arounds to enable. 1607112679Sscottl */ 1608112679Sscottl if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1609112679Sscottl device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1610112679Sscottl return (EIO); 1611112679Sscottl } 1612112679Sscottl options = AAC_GET_MAILBOX(sc, 1); 1613151086Sscottl atu_size = AAC_GET_MAILBOX(sc, 2); 1614112679Sscottl sc->supported_options = options; 1615112679Sscottl 1616112679Sscottl if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1617112679Sscottl (sc->flags & AAC_FLAGS_NO4GB) == 0) 1618112679Sscottl sc->flags |= AAC_FLAGS_4GB_WINDOW; 1619112679Sscottl if (options & AAC_SUPPORTED_NONDASD) 1620112679Sscottl sc->flags |= AAC_FLAGS_ENABLE_CAM; 1621117363Sscottl if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1622117363Sscottl && (sizeof(bus_addr_t) > 4)) { 1623112679Sscottl device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1624112679Sscottl sc->flags |= AAC_FLAGS_SG_64BIT; 1625112679Sscottl } 1626151086Sscottl if ((options & AAC_SUPPORTED_NEW_COMM) && sc->aac_if.aif_send_command) 1627151086Sscottl sc->flags |= AAC_FLAGS_NEW_COMM; 1628151086Sscottl if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1629151086Sscottl sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1630112679Sscottl 1631112679Sscottl /* Check for broken hardware that does a lower number of commands */ 1632151086Sscottl sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1633151086Sscottl 1634151086Sscottl /* Remap mem. resource, if required */ 1635151086Sscottl if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1636151086Sscottl atu_size > rman_get_size(sc->aac_regs_resource)) { 1637151086Sscottl bus_release_resource( 1638151086Sscottl sc->aac_dev, SYS_RES_MEMORY, 1639151086Sscottl sc->aac_regs_rid, sc->aac_regs_resource); 1640151086Sscottl sc->aac_regs_resource = bus_alloc_resource( 1641151086Sscottl sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid, 1642151086Sscottl 0ul, ~0ul, atu_size, RF_ACTIVE); 1643151086Sscottl if (sc->aac_regs_resource == NULL) { 1644151086Sscottl sc->aac_regs_resource = bus_alloc_resource_any( 1645151086Sscottl sc->aac_dev, SYS_RES_MEMORY, 1646151086Sscottl &sc->aac_regs_rid, RF_ACTIVE); 1647151086Sscottl if (sc->aac_regs_resource == NULL) { 1648151086Sscottl device_printf(sc->aac_dev, 1649151086Sscottl "couldn't allocate register window\n"); 1650151086Sscottl return (ENXIO); 1651151086Sscottl } 1652151086Sscottl sc->flags &= ~AAC_FLAGS_NEW_COMM; 1653151086Sscottl } 1654151086Sscottl sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); 1655151086Sscottl sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); 1656151086Sscottl } 1657151086Sscottl 1658151086Sscottl /* Read preferred settings */ 1659151086Sscottl sc->aac_max_fib_size = sizeof(struct aac_fib); 1660151086Sscottl sc->aac_max_sectors = 128; /* 64KB */ 1661151086Sscottl if (sc->flags & AAC_FLAGS_SG_64BIT) 1662151086Sscottl sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite64) 1663151086Sscottl + sizeof(struct aac_sg_table64)) / sizeof(struct aac_sg_table64); 1664112679Sscottl else 1665151086Sscottl sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite) 1666151086Sscottl + sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_table); 1667151086Sscottl if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 1668151086Sscottl options = AAC_GET_MAILBOX(sc, 1); 1669151086Sscottl sc->aac_max_fib_size = (options & 0xFFFF); 1670151086Sscottl sc->aac_max_sectors = (options >> 16) << 1; 1671151086Sscottl options = AAC_GET_MAILBOX(sc, 2); 1672151086Sscottl sc->aac_sg_tablesize = (options >> 16); 1673151086Sscottl options = AAC_GET_MAILBOX(sc, 3); 1674151086Sscottl sc->aac_max_fibs = (options & 0xFFFF); 1675151086Sscottl } 1676151086Sscottl if (sc->aac_max_fib_size > PAGE_SIZE) 1677151086Sscottl sc->aac_max_fib_size = PAGE_SIZE; 1678151086Sscottl sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1679151086Sscottl 168090275Sscottl return (0); 168190275Sscottl} 168290275Sscottl 168390275Sscottlstatic int 168465793Smsmithaac_init(struct aac_softc *sc) 168565793Smsmith{ 168683114Sscottl struct aac_adapter_init *ip; 168783114Sscottl time_t then; 1688119146Sscottl u_int32_t code, qoffset; 1689112679Sscottl int error; 169065793Smsmith 169183114Sscottl debug_called(1); 169265793Smsmith 169383114Sscottl /* 169483114Sscottl * First wait for the adapter to come ready. 169583114Sscottl */ 1696150119Sscottl then = time_uptime; 169783114Sscottl do { 169883114Sscottl code = AAC_GET_FWSTATUS(sc); 169983114Sscottl if (code & AAC_SELF_TEST_FAILED) { 170083114Sscottl device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 170183114Sscottl return(ENXIO); 170283114Sscottl } 170383114Sscottl if (code & AAC_KERNEL_PANIC) { 170483114Sscottl device_printf(sc->aac_dev, 170583114Sscottl "FATAL: controller kernel panic\n"); 170683114Sscottl return(ENXIO); 170783114Sscottl } 1708150119Sscottl if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 170983114Sscottl device_printf(sc->aac_dev, 171083114Sscottl "FATAL: controller not coming ready, " 171183114Sscottl "status %x\n", code); 171283114Sscottl return(ENXIO); 171383114Sscottl } 171483114Sscottl } while (!(code & AAC_UP_AND_RUNNING)); 171583114Sscottl 1716112679Sscottl error = ENOMEM; 171783114Sscottl /* 1718112679Sscottl * Create DMA tag for mapping buffers into controller-addressable space. 1719112679Sscottl */ 1720112679Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1721112679Sscottl 1, 0, /* algnmnt, boundary */ 1722112679Sscottl (sc->flags & AAC_FLAGS_SG_64BIT) ? 1723112679Sscottl BUS_SPACE_MAXADDR : 1724112679Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1725112679Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 1726112679Sscottl NULL, NULL, /* filter, filterarg */ 1727112679Sscottl MAXBSIZE, /* maxsize */ 1728151086Sscottl sc->aac_sg_tablesize, /* nsegments */ 1729112679Sscottl MAXBSIZE, /* maxsegsize */ 1730112679Sscottl BUS_DMA_ALLOCNOW, /* flags */ 1731117126Sscottl busdma_lock_mutex, /* lockfunc */ 1732117126Sscottl &sc->aac_io_lock, /* lockfuncarg */ 1733112679Sscottl &sc->aac_buffer_dmat)) { 1734112679Sscottl device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1735112679Sscottl goto out; 1736112679Sscottl } 1737112679Sscottl 1738112679Sscottl /* 1739112679Sscottl * Create DMA tag for mapping FIBs into controller-addressable space.. 1740112679Sscottl */ 1741112679Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1742112679Sscottl 1, 0, /* algnmnt, boundary */ 1743112679Sscottl (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1744112679Sscottl BUS_SPACE_MAXADDR_32BIT : 1745112679Sscottl 0x7fffffff, /* lowaddr */ 1746112679Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 1747112679Sscottl NULL, NULL, /* filter, filterarg */ 1748151086Sscottl sc->aac_max_fibs_alloc * 1749151086Sscottl sc->aac_max_fib_size, /* maxsize */ 1750112679Sscottl 1, /* nsegments */ 1751151086Sscottl sc->aac_max_fibs_alloc * 1752151086Sscottl sc->aac_max_fib_size, /* maxsegsize */ 1753137962Sscottl 0, /* flags */ 1754117126Sscottl NULL, NULL, /* No locking needed */ 1755112679Sscottl &sc->aac_fib_dmat)) { 1756112679Sscottl device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1757112679Sscottl goto out; 1758112679Sscottl } 1759112679Sscottl 1760112679Sscottl /* 176183114Sscottl * Create DMA tag for the common structure and allocate it. 176283114Sscottl */ 176383114Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 176495536Sscottl 1, 0, /* algnmnt, boundary */ 1765112679Sscottl (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1766112679Sscottl BUS_SPACE_MAXADDR_32BIT : 1767112679Sscottl 0x7fffffff, /* lowaddr */ 176883114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 176983114Sscottl NULL, NULL, /* filter, filterarg */ 1770110604Sscottl 8192 + sizeof(struct aac_common), /* maxsize */ 177183114Sscottl 1, /* nsegments */ 177283114Sscottl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1773137962Sscottl 0, /* flags */ 1774117126Sscottl NULL, NULL, /* No locking needed */ 177583114Sscottl &sc->aac_common_dmat)) { 177683114Sscottl device_printf(sc->aac_dev, 177783114Sscottl "can't allocate common structure DMA tag\n"); 1778112679Sscottl goto out; 177965793Smsmith } 178083114Sscottl if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 178183114Sscottl BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 178283114Sscottl device_printf(sc->aac_dev, "can't allocate common structure\n"); 1783112679Sscottl goto out; 178465793Smsmith } 1785110604Sscottl 1786110604Sscottl /* 1787110604Sscottl * Work around a bug in the 2120 and 2200 that cannot DMA commands 1788110604Sscottl * below address 8192 in physical memory. 1789110604Sscottl * XXX If the padding is not needed, can it be put to use instead 1790110604Sscottl * of ignored? 1791110604Sscottl */ 1792117363Sscottl (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1793110604Sscottl sc->aac_common, 8192 + sizeof(*sc->aac_common), 1794110604Sscottl aac_common_map, sc, 0); 1795110604Sscottl 1796110604Sscottl if (sc->aac_common_busaddr < 8192) { 1797132771Skan sc->aac_common = (struct aac_common *) 1798132771Skan ((uint8_t *)sc->aac_common + 8192); 1799110604Sscottl sc->aac_common_busaddr += 8192; 1800110604Sscottl } 180183114Sscottl bzero(sc->aac_common, sizeof(*sc->aac_common)); 1802110604Sscottl 1803110604Sscottl /* Allocate some FIBs and associated command structs */ 1804110604Sscottl TAILQ_INIT(&sc->aac_fibmap_tqh); 1805151086Sscottl sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 1806111141Sscottl M_AACBUF, M_WAITOK|M_ZERO); 1807111141Sscottl while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1808110604Sscottl if (aac_alloc_commands(sc) != 0) 1809110604Sscottl break; 1810110604Sscottl } 1811110604Sscottl if (sc->total_fibs == 0) 1812112679Sscottl goto out; 181383114Sscottl 181483114Sscottl /* 181583114Sscottl * Fill in the init structure. This tells the adapter about the 181683114Sscottl * physical location of various important shared data structures. 181783114Sscottl */ 181883114Sscottl ip = &sc->aac_common->ac_init; 181983114Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1820151086Sscottl if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1821151086Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1822151086Sscottl sc->flags |= AAC_FLAGS_RAW_IO; 1823151086Sscottl } 1824109088Sscottl ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 182565793Smsmith 182683114Sscottl ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 182783114Sscottl offsetof(struct aac_common, ac_fibs); 1828114151Sscottl ip->AdapterFibsVirtualAddress = 0; 182983114Sscottl ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 183083114Sscottl ip->AdapterFibAlign = sizeof(struct aac_fib); 183165793Smsmith 183283114Sscottl ip->PrintfBufferAddress = sc->aac_common_busaddr + 183383114Sscottl offsetof(struct aac_common, ac_printf); 183483114Sscottl ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 183565793Smsmith 1836117361Sscottl /* 1837117361Sscottl * The adapter assumes that pages are 4K in size, except on some 1838117361Sscottl * broken firmware versions that do the page->byte conversion twice, 1839117361Sscottl * therefore 'assuming' that this value is in 16MB units (2^24). 1840117361Sscottl * Round up since the granularity is so high. 1841117361Sscottl */ 1842109088Sscottl ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1843117361Sscottl if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1844117361Sscottl ip->HostPhysMemPages = 1845117361Sscottl (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1846117362Sscottl } 1847150119Sscottl ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 184865793Smsmith 1849151086Sscottl ip->InitFlags = 0; 1850151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) { 1851151086Sscottl ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 1852151086Sscottl device_printf(sc->aac_dev, "New comm. interface enabled\n"); 1853151086Sscottl } 1854151086Sscottl 1855151086Sscottl ip->MaxIoCommands = sc->aac_max_fibs; 1856151086Sscottl ip->MaxIoSize = sc->aac_max_sectors << 9; 1857151086Sscottl ip->MaxFibSize = sc->aac_max_fib_size; 1858151086Sscottl 185983114Sscottl /* 186083114Sscottl * Initialise FIB queues. Note that it appears that the layout of the 186183114Sscottl * indexes and the segmentation of the entries may be mandated by the 186283114Sscottl * adapter, which is only told about the base of the queue index fields. 186383114Sscottl * 186483114Sscottl * The initial values of the indices are assumed to inform the adapter 186583114Sscottl * of the sizes of the respective queues, and theoretically it could 186683114Sscottl * work out the entire layout of the queue structures from this. We 186783114Sscottl * take the easy route and just lay this area out like everyone else 186883114Sscottl * does. 186983114Sscottl * 187083114Sscottl * The Linux driver uses a much more complex scheme whereby several 187183114Sscottl * header records are kept for each queue. We use a couple of generic 187283114Sscottl * list manipulation functions which 'know' the size of each list by 187383114Sscottl * virtue of a table. 187483114Sscottl */ 1875119146Sscottl qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 1876119625Sscottl qoffset &= ~(AAC_QUEUE_ALIGN - 1); 1877119625Sscottl sc->aac_queues = 1878119625Sscottl (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1879119146Sscottl ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 188065793Smsmith 188183114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 188281082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 188383114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 188481082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 188583114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 188681082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 188783114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 188881082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 188983114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 189081082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 189183114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 189281082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 189383114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 189481082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 189583114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 189681082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 189783114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 189881082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 189983114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 190081082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 190183114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 190281082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 190383114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 190481082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 190583114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 190681082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 190783114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 190881082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 190983114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 191081082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 191183114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 191281082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 191383114Sscottl sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 191481082Sscottl &sc->aac_queues->qt_HostNormCmdQueue[0]; 191583114Sscottl sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 191681082Sscottl &sc->aac_queues->qt_HostHighCmdQueue[0]; 191783114Sscottl sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 191881082Sscottl &sc->aac_queues->qt_AdapNormCmdQueue[0]; 191983114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 192081082Sscottl &sc->aac_queues->qt_AdapHighCmdQueue[0]; 192183114Sscottl sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 192281082Sscottl &sc->aac_queues->qt_HostNormRespQueue[0]; 192383114Sscottl sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 192481082Sscottl &sc->aac_queues->qt_HostHighRespQueue[0]; 192583114Sscottl sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 192681082Sscottl &sc->aac_queues->qt_AdapNormRespQueue[0]; 192783114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 192881082Sscottl &sc->aac_queues->qt_AdapHighRespQueue[0]; 192965793Smsmith 193083114Sscottl /* 193183114Sscottl * Do controller-type-specific initialisation 193283114Sscottl */ 193383114Sscottl switch (sc->aac_hwif) { 193483114Sscottl case AAC_HWIF_I960RX: 193583114Sscottl AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 193683114Sscottl break; 1937133606Sscottl case AAC_HWIF_RKT: 1938133606Sscottl AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); 1939133606Sscottl break; 1940133606Sscottl default: 1941133606Sscottl break; 194283114Sscottl } 194365793Smsmith 194483114Sscottl /* 194583114Sscottl * Give the init structure to the controller. 194683114Sscottl */ 194783114Sscottl if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 194883114Sscottl sc->aac_common_busaddr + 194983114Sscottl offsetof(struct aac_common, ac_init), 0, 0, 0, 195083114Sscottl NULL)) { 195183114Sscottl device_printf(sc->aac_dev, 195283114Sscottl "error establishing init structure\n"); 1953112679Sscottl error = EIO; 1954112679Sscottl goto out; 195583114Sscottl } 195665793Smsmith 1957112679Sscottl error = 0; 1958112679Sscottlout: 1959112679Sscottl return(error); 196065793Smsmith} 196165793Smsmith 196283114Sscottl/* 196365793Smsmith * Send a synchronous command to the controller and wait for a result. 1964151086Sscottl * Indicate if the controller completed the command with an error status. 196565793Smsmith */ 196665793Smsmithstatic int 196765793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command, 196870393Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 196970393Smsmith u_int32_t *sp) 197065793Smsmith{ 197183114Sscottl time_t then; 197283114Sscottl u_int32_t status; 197365793Smsmith 197483114Sscottl debug_called(3); 197565793Smsmith 197683114Sscottl /* populate the mailbox */ 197783114Sscottl AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 197865793Smsmith 197983114Sscottl /* ensure the sync command doorbell flag is cleared */ 198083114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 198165793Smsmith 198283114Sscottl /* then set it to signal the adapter */ 198383114Sscottl AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 198465793Smsmith 198583114Sscottl /* spin waiting for the command to complete */ 1986150119Sscottl then = time_uptime; 198783114Sscottl do { 1988150119Sscottl if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 1989112679Sscottl debug(1, "timed out"); 199083114Sscottl return(EIO); 199183114Sscottl } 199283114Sscottl } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 199365793Smsmith 199483114Sscottl /* clear the completion flag */ 199583114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 199665793Smsmith 199783114Sscottl /* get the command status */ 1998112679Sscottl status = AAC_GET_MAILBOX(sc, 0); 199983114Sscottl if (sp != NULL) 200083114Sscottl *sp = status; 2001151086Sscottl 2002151086Sscottl if (status != 0x01) 2003151086Sscottl return (-1); 200483114Sscottl return(0); 200565793Smsmith} 200665793Smsmith 200795350Sscottlint 200865793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 200995350Sscottl struct aac_fib *fib, u_int16_t datasize) 201065793Smsmith{ 201183114Sscottl debug_called(3); 2012151086Sscottl mtx_assert(&sc->aac_io_lock, MA_OWNED); 201365793Smsmith 201483114Sscottl if (datasize > AAC_FIB_DATASIZE) 201583114Sscottl return(EINVAL); 201665793Smsmith 201783114Sscottl /* 201883114Sscottl * Set up the sync FIB 201983114Sscottl */ 202083114Sscottl fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 202183114Sscottl AAC_FIBSTATE_INITIALISED | 202283114Sscottl AAC_FIBSTATE_EMPTY; 202383114Sscottl fib->Header.XferState |= xferstate; 202483114Sscottl fib->Header.Command = command; 202583114Sscottl fib->Header.StructType = AAC_FIBTYPE_TFIB; 202683114Sscottl fib->Header.Size = sizeof(struct aac_fib) + datasize; 202783114Sscottl fib->Header.SenderSize = sizeof(struct aac_fib); 2028119146Sscottl fib->Header.SenderFibAddress = 0; /* Not needed */ 202983114Sscottl fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 203083114Sscottl offsetof(struct aac_common, 203183114Sscottl ac_sync_fib); 203265793Smsmith 203383114Sscottl /* 203483114Sscottl * Give the FIB to the controller, wait for a response. 203583114Sscottl */ 203683114Sscottl if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 203783114Sscottl fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 203883114Sscottl debug(2, "IO error"); 203983114Sscottl return(EIO); 204083114Sscottl } 204181151Sscottl 204295350Sscottl return (0); 204365793Smsmith} 204465793Smsmith 204583114Sscottl/* 204665793Smsmith * Adapter-space FIB queue manipulation 204765793Smsmith * 204865793Smsmith * Note that the queue implementation here is a little funky; neither the PI or 204965793Smsmith * CI will ever be zero. This behaviour is a controller feature. 205065793Smsmith */ 205165793Smsmithstatic struct { 205283114Sscottl int size; 205383114Sscottl int notify; 205465793Smsmith} aac_qinfo[] = { 205583114Sscottl {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 205683114Sscottl {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 205783114Sscottl {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 205883114Sscottl {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 205983114Sscottl {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 206083114Sscottl {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 206183114Sscottl {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 206283114Sscottl {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 206365793Smsmith}; 206465793Smsmith 206565793Smsmith/* 206681082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or 206781082Sscottl * EBUSY if the queue is full. 206865793Smsmith * 206970393Smsmith * Note: it would be more efficient to defer notifying the controller in 207083114Sscottl * the case where we may be inserting several entries in rapid succession, 207183114Sscottl * but implementing this usefully may be difficult (it would involve a 207283114Sscottl * separate queue/notify interface). 207365793Smsmith */ 207465793Smsmithstatic int 207581151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 207665793Smsmith{ 207783114Sscottl u_int32_t pi, ci; 2078111691Sscottl int error; 207983114Sscottl u_int32_t fib_size; 208083114Sscottl u_int32_t fib_addr; 208165793Smsmith 208283114Sscottl debug_called(3); 208382527Sscottl 208483114Sscottl fib_size = cm->cm_fib->Header.Size; 208583114Sscottl fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 208681151Sscottl 208783114Sscottl /* get the producer/consumer indices */ 208883114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 208983114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 209065793Smsmith 209183114Sscottl /* wrap the queue? */ 209283114Sscottl if (pi >= aac_qinfo[queue].size) 209383114Sscottl pi = 0; 209465793Smsmith 209583114Sscottl /* check for queue full */ 209683114Sscottl if ((pi + 1) == ci) { 209783114Sscottl error = EBUSY; 209883114Sscottl goto out; 209983114Sscottl } 210065793Smsmith 2101129946Sscottl /* 2102129946Sscottl * To avoid a race with its completion interrupt, place this command on 2103129946Sscottl * the busy queue prior to advertising it to the controller. 2104129946Sscottl */ 2105129946Sscottl aac_enqueue_busy(cm); 2106129946Sscottl 210783114Sscottl /* populate queue entry */ 210883114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 210983114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 211065793Smsmith 211183114Sscottl /* update producer index */ 211283114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 211365793Smsmith 211483114Sscottl /* notify the adapter if we know how */ 211583114Sscottl if (aac_qinfo[queue].notify != 0) 211683114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 211765793Smsmith 211883114Sscottl error = 0; 211965793Smsmith 212065793Smsmithout: 212183114Sscottl return(error); 212265793Smsmith} 212365793Smsmith 212465793Smsmith/* 212582527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on 212682527Sscottl * success or ENOENT if the queue is empty. 212765793Smsmith */ 212865793Smsmithstatic int 212981082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 213081082Sscottl struct aac_fib **fib_addr) 213165793Smsmith{ 213283114Sscottl u_int32_t pi, ci; 2133114151Sscottl u_int32_t fib_index; 2134111691Sscottl int error; 213583114Sscottl int notify; 213665793Smsmith 213783114Sscottl debug_called(3); 213865793Smsmith 213983114Sscottl /* get the producer/consumer indices */ 214083114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 214183114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 214265793Smsmith 214383114Sscottl /* check for queue empty */ 214483114Sscottl if (ci == pi) { 214583114Sscottl error = ENOENT; 214683114Sscottl goto out; 214783114Sscottl } 2148120129Sscottl 2149120129Sscottl /* wrap the pi so the following test works */ 2150120129Sscottl if (pi >= aac_qinfo[queue].size) 2151120129Sscottl pi = 0; 2152120129Sscottl 215383114Sscottl notify = 0; 215483114Sscottl if (ci == pi + 1) 215583114Sscottl notify++; 215681151Sscottl 215783114Sscottl /* wrap the queue? */ 215883114Sscottl if (ci >= aac_qinfo[queue].size) 215983114Sscottl ci = 0; 216065793Smsmith 216183114Sscottl /* fetch the entry */ 216283114Sscottl *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 216365793Smsmith 2164114151Sscottl switch (queue) { 2165114151Sscottl case AAC_HOST_NORM_CMD_QUEUE: 2166114151Sscottl case AAC_HOST_HIGH_CMD_QUEUE: 2167114151Sscottl /* 2168114151Sscottl * The aq_fib_addr is only 32 bits wide so it can't be counted 2169114151Sscottl * on to hold an address. For AIF's, the adapter assumes 2170114151Sscottl * that it's giving us an address into the array of AIF fibs. 2171114151Sscottl * Therefore, we have to convert it to an index. 2172114151Sscottl */ 2173114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2174114151Sscottl sizeof(struct aac_fib); 2175114151Sscottl *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2176114151Sscottl break; 2177114151Sscottl 2178114151Sscottl case AAC_HOST_NORM_RESP_QUEUE: 2179114151Sscottl case AAC_HOST_HIGH_RESP_QUEUE: 2180114151Sscottl { 2181114151Sscottl struct aac_command *cm; 2182114151Sscottl 2183114151Sscottl /* 2184114151Sscottl * As above, an index is used instead of an actual address. 2185114151Sscottl * Gotta shift the index to account for the fast response 2186114151Sscottl * bit. No other correction is needed since this value was 2187114151Sscottl * originally provided by the driver via the SenderFibAddress 2188114151Sscottl * field. 2189114151Sscottl */ 2190114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 2191151086Sscottl cm = sc->aac_commands + (fib_index >> 2); 2192114151Sscottl *fib_addr = cm->cm_fib; 2193114151Sscottl 2194114151Sscottl /* 2195114151Sscottl * Is this a fast response? If it is, update the fib fields in 2196114151Sscottl * local memory since the whole fib isn't DMA'd back up. 2197114151Sscottl */ 2198114151Sscottl if (fib_index & 0x01) { 2199114151Sscottl (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2200114151Sscottl *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2201114151Sscottl } 2202114151Sscottl break; 2203109088Sscottl } 2204114151Sscottl default: 2205114151Sscottl panic("Invalid queue in aac_dequeue_fib()"); 2206114151Sscottl break; 2207114151Sscottl } 2208114151Sscottl 220983114Sscottl /* update consumer index */ 221083114Sscottl sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 221165793Smsmith 221283114Sscottl /* if we have made the queue un-full, notify the adapter */ 221383114Sscottl if (notify && (aac_qinfo[queue].notify != 0)) 221483114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 221583114Sscottl error = 0; 221665793Smsmith 221765793Smsmithout: 221883114Sscottl return(error); 221965793Smsmith} 222065793Smsmith 222183114Sscottl/* 222282527Sscottl * Put our response to an Adapter Initialed Fib on the response queue 222382527Sscottl */ 222482527Sscottlstatic int 222582527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 222682527Sscottl{ 222783114Sscottl u_int32_t pi, ci; 2228111691Sscottl int error; 222983114Sscottl u_int32_t fib_size; 223083114Sscottl u_int32_t fib_addr; 223182527Sscottl 223283114Sscottl debug_called(1); 223382527Sscottl 223483114Sscottl /* Tell the adapter where the FIB is */ 223583114Sscottl fib_size = fib->Header.Size; 223683114Sscottl fib_addr = fib->Header.SenderFibAddress; 223783114Sscottl fib->Header.ReceiverFibAddress = fib_addr; 223882527Sscottl 223983114Sscottl /* get the producer/consumer indices */ 224083114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 224183114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 224282527Sscottl 224383114Sscottl /* wrap the queue? */ 224483114Sscottl if (pi >= aac_qinfo[queue].size) 224583114Sscottl pi = 0; 224682527Sscottl 224783114Sscottl /* check for queue full */ 224883114Sscottl if ((pi + 1) == ci) { 224983114Sscottl error = EBUSY; 225083114Sscottl goto out; 225183114Sscottl } 225282527Sscottl 225383114Sscottl /* populate queue entry */ 225483114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 225583114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 225682527Sscottl 225783114Sscottl /* update producer index */ 225883114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 225982527Sscottl 226083114Sscottl /* notify the adapter if we know how */ 226183114Sscottl if (aac_qinfo[queue].notify != 0) 226283114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 226382527Sscottl 226483114Sscottl error = 0; 226582527Sscottl 226682527Sscottlout: 226783114Sscottl return(error); 226882527Sscottl} 226982527Sscottl 227083114Sscottl/* 227170393Smsmith * Check for commands that have been outstanding for a suspiciously long time, 227270393Smsmith * and complain about them. 227370393Smsmith */ 227470393Smsmithstatic void 227570393Smsmithaac_timeout(struct aac_softc *sc) 227670393Smsmith{ 227783114Sscottl struct aac_command *cm; 227883114Sscottl time_t deadline; 2279135289Sscottl int timedout, code; 228070393Smsmith 228183114Sscottl /* 2282110426Sscottl * Traverse the busy command list, bitch about late commands once 228383114Sscottl * only. 228483114Sscottl */ 2285135289Sscottl timedout = 0; 2286150119Sscottl deadline = time_uptime - AAC_CMD_TIMEOUT; 228783114Sscottl TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 228883114Sscottl if ((cm->cm_timestamp < deadline) 228983114Sscottl /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 229083114Sscottl cm->cm_flags |= AAC_CMD_TIMEDOUT; 229183114Sscottl device_printf(sc->aac_dev, 229283114Sscottl "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2293150119Sscottl cm, (int)(time_uptime-cm->cm_timestamp)); 229483114Sscottl AAC_PRINT_FIB(sc, cm->cm_fib); 2295135289Sscottl timedout++; 229683114Sscottl } 229770393Smsmith } 229870393Smsmith 2299135289Sscottl if (timedout) { 2300135289Sscottl code = AAC_GET_FWSTATUS(sc); 2301135289Sscottl if (code != AAC_UP_AND_RUNNING) { 2302135289Sscottl device_printf(sc->aac_dev, "WARNING! Controller is no " 2303135289Sscottl "longer running! code= 0x%x\n", code); 2304135289Sscottl } 2305135289Sscottl } 230683114Sscottl return; 230770393Smsmith} 230870393Smsmith 230983114Sscottl/* 231083114Sscottl * Interface Function Vectors 231183114Sscottl */ 231265793Smsmith 231383114Sscottl/* 231465793Smsmith * Read the current firmware status word. 231565793Smsmith */ 231665793Smsmithstatic int 231765793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc) 231865793Smsmith{ 231983114Sscottl debug_called(3); 232065793Smsmith 232183114Sscottl return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 232265793Smsmith} 232365793Smsmith 232465793Smsmithstatic int 232565793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc) 232665793Smsmith{ 232783114Sscottl debug_called(3); 232865793Smsmith 232983114Sscottl return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 233065793Smsmith} 233165793Smsmith 233287183Sscottlstatic int 233387183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc) 233487183Sscottl{ 233587183Sscottl int val; 233687183Sscottl 233787183Sscottl debug_called(3); 233887183Sscottl 233987183Sscottl val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 234087183Sscottl return (val); 234187183Sscottl} 234287183Sscottl 2343133606Sscottlstatic int 2344133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc) 2345133606Sscottl{ 2346133606Sscottl debug_called(3); 2347133606Sscottl 2348133606Sscottl return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); 2349133606Sscottl} 2350133606Sscottl 235183114Sscottl/* 235265793Smsmith * Notify the controller of a change in a given queue 235365793Smsmith */ 235465793Smsmith 235565793Smsmithstatic void 235665793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit) 235765793Smsmith{ 235883114Sscottl debug_called(3); 235965793Smsmith 236083114Sscottl AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 236165793Smsmith} 236265793Smsmith 236365793Smsmithstatic void 236465793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit) 236565793Smsmith{ 236683114Sscottl debug_called(3); 236765793Smsmith 236883114Sscottl AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 236965793Smsmith} 237065793Smsmith 237187183Sscottlstatic void 237287183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit) 237387183Sscottl{ 237487183Sscottl debug_called(3); 237587183Sscottl 237687183Sscottl AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 237787183Sscottl AAC_FA_HACK(sc); 237887183Sscottl} 237987183Sscottl 2380133606Sscottlstatic void 2381133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit) 2382133606Sscottl{ 2383133606Sscottl debug_called(3); 2384133606Sscottl 2385133606Sscottl AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); 2386133606Sscottl} 2387133606Sscottl 238883114Sscottl/* 238965793Smsmith * Get the interrupt reason bits 239065793Smsmith */ 239165793Smsmithstatic int 239265793Smsmithaac_sa_get_istatus(struct aac_softc *sc) 239365793Smsmith{ 239483114Sscottl debug_called(3); 239565793Smsmith 239683114Sscottl return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 239765793Smsmith} 239865793Smsmith 239965793Smsmithstatic int 240065793Smsmithaac_rx_get_istatus(struct aac_softc *sc) 240165793Smsmith{ 240283114Sscottl debug_called(3); 240365793Smsmith 240483114Sscottl return(AAC_GETREG4(sc, AAC_RX_ODBR)); 240565793Smsmith} 240665793Smsmith 240787183Sscottlstatic int 240887183Sscottlaac_fa_get_istatus(struct aac_softc *sc) 240987183Sscottl{ 241087183Sscottl int val; 241187183Sscottl 241287183Sscottl debug_called(3); 241387183Sscottl 241487183Sscottl val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 241587183Sscottl return (val); 241687183Sscottl} 241787183Sscottl 2418133606Sscottlstatic int 2419133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc) 2420133606Sscottl{ 2421133606Sscottl debug_called(3); 2422133606Sscottl 2423133606Sscottl return(AAC_GETREG4(sc, AAC_RKT_ODBR)); 2424133606Sscottl} 2425133606Sscottl 242683114Sscottl/* 242765793Smsmith * Clear some interrupt reason bits 242865793Smsmith */ 242965793Smsmithstatic void 243065793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask) 243165793Smsmith{ 243283114Sscottl debug_called(3); 243365793Smsmith 243483114Sscottl AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 243565793Smsmith} 243665793Smsmith 243765793Smsmithstatic void 243865793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask) 243965793Smsmith{ 244083114Sscottl debug_called(3); 244165793Smsmith 244283114Sscottl AAC_SETREG4(sc, AAC_RX_ODBR, mask); 244365793Smsmith} 244465793Smsmith 244587183Sscottlstatic void 244687183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask) 244787183Sscottl{ 244887183Sscottl debug_called(3); 244987183Sscottl 245087183Sscottl AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 245187183Sscottl AAC_FA_HACK(sc); 245287183Sscottl} 245387183Sscottl 2454133606Sscottlstatic void 2455133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask) 2456133606Sscottl{ 2457133606Sscottl debug_called(3); 2458133606Sscottl 2459133606Sscottl AAC_SETREG4(sc, AAC_RKT_ODBR, mask); 2460133606Sscottl} 2461133606Sscottl 246283114Sscottl/* 246365793Smsmith * Populate the mailbox and set the command word 246465793Smsmith */ 246565793Smsmithstatic void 246665793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 246765793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 246865793Smsmith{ 246983114Sscottl debug_called(4); 247065793Smsmith 247183114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 247283114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 247383114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 247483114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 247583114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 247665793Smsmith} 247765793Smsmith 247865793Smsmithstatic void 247965793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 248065793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 248165793Smsmith{ 248283114Sscottl debug_called(4); 248365793Smsmith 248483114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 248583114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 248683114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 248783114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 248883114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 248965793Smsmith} 249065793Smsmith 249187183Sscottlstatic void 249287183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 249387183Sscottl u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249487183Sscottl{ 249587183Sscottl debug_called(4); 249687183Sscottl 249787183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 249887183Sscottl AAC_FA_HACK(sc); 249987183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 250087183Sscottl AAC_FA_HACK(sc); 250187183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 250287183Sscottl AAC_FA_HACK(sc); 250387183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 250487183Sscottl AAC_FA_HACK(sc); 250587183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 250687183Sscottl AAC_FA_HACK(sc); 250787183Sscottl} 250887183Sscottl 2509133606Sscottlstatic void 2510133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2511133606Sscottl u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2512133606Sscottl{ 2513133606Sscottl debug_called(4); 2514133606Sscottl 2515133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); 2516133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2517133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2518133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2519133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 2520133606Sscottl} 2521133606Sscottl 252283114Sscottl/* 252365793Smsmith * Fetch the immediate command status word 252465793Smsmith */ 252565793Smsmithstatic int 2526112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb) 252765793Smsmith{ 252883114Sscottl debug_called(4); 252965793Smsmith 2530112679Sscottl return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 253165793Smsmith} 253265793Smsmith 253365793Smsmithstatic int 2534112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb) 253565793Smsmith{ 253683114Sscottl debug_called(4); 253765793Smsmith 2538112679Sscottl return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 253965793Smsmith} 254065793Smsmith 254187183Sscottlstatic int 2542112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb) 254387183Sscottl{ 254487183Sscottl int val; 254587183Sscottl 254687183Sscottl debug_called(4); 254787183Sscottl 2548112679Sscottl val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 254987183Sscottl return (val); 255087183Sscottl} 255187183Sscottl 2552133606Sscottlstatic int 2553133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb) 2554133606Sscottl{ 2555133606Sscottl debug_called(4); 2556133606Sscottl 2557133606Sscottl return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 2558133606Sscottl} 2559133606Sscottl 256083114Sscottl/* 256165793Smsmith * Set/clear interrupt masks 256265793Smsmith */ 256365793Smsmithstatic void 256465793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable) 256565793Smsmith{ 256683114Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 256765793Smsmith 256883114Sscottl if (enable) { 256983114Sscottl AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 257083114Sscottl } else { 257183114Sscottl AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 257283114Sscottl } 257365793Smsmith} 257465793Smsmith 257565793Smsmithstatic void 257665793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable) 257765793Smsmith{ 257883114Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 257965793Smsmith 258083114Sscottl if (enable) { 2581151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 2582151086Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 2583151086Sscottl else 2584151086Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 258583114Sscottl } else { 258683114Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 258783114Sscottl } 258865793Smsmith} 258965793Smsmith 259087183Sscottlstatic void 259187183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable) 259287183Sscottl{ 259387183Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 259487183Sscottl 259587183Sscottl if (enable) { 259687183Sscottl AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 259787183Sscottl AAC_FA_HACK(sc); 259887183Sscottl } else { 259987183Sscottl AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 260087183Sscottl AAC_FA_HACK(sc); 260187183Sscottl } 260287183Sscottl} 260387183Sscottl 2604133606Sscottlstatic void 2605133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable) 2606133606Sscottl{ 2607133606Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 2608133606Sscottl 2609133606Sscottl if (enable) { 2610151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 2611151086Sscottl AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 2612151086Sscottl else 2613151086Sscottl AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 2614133606Sscottl } else { 2615133606Sscottl AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); 2616133606Sscottl } 2617133606Sscottl} 2618133606Sscottl 261983114Sscottl/* 2620151086Sscottl * New comm. interface: Send command functions 2621151086Sscottl */ 2622151086Sscottlstatic int 2623151086Sscottlaac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 2624151086Sscottl{ 2625151086Sscottl u_int32_t index, device; 2626151086Sscottl 2627151086Sscottl debug(2, "send command (new comm.)"); 2628151086Sscottl 2629151086Sscottl index = AAC_GETREG4(sc, AAC_RX_IQUE); 2630151086Sscottl if (index == 0xffffffffL) 2631151086Sscottl index = AAC_GETREG4(sc, AAC_RX_IQUE); 2632151086Sscottl if (index == 0xffffffffL) 2633151086Sscottl return index; 2634151086Sscottl aac_enqueue_busy(cm); 2635151086Sscottl device = index; 2636151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2637151086Sscottl device += 4; 2638151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2639151086Sscottl device += 4; 2640151086Sscottl AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 2641151086Sscottl AAC_SETREG4(sc, AAC_RX_IQUE, index); 2642151086Sscottl return 0; 2643151086Sscottl} 2644151086Sscottl 2645151086Sscottlstatic int 2646151086Sscottlaac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 2647151086Sscottl{ 2648151086Sscottl u_int32_t index, device; 2649151086Sscottl 2650151086Sscottl debug(2, "send command (new comm.)"); 2651151086Sscottl 2652151086Sscottl index = AAC_GETREG4(sc, AAC_RKT_IQUE); 2653151086Sscottl if (index == 0xffffffffL) 2654151086Sscottl index = AAC_GETREG4(sc, AAC_RKT_IQUE); 2655151086Sscottl if (index == 0xffffffffL) 2656151086Sscottl return index; 2657151086Sscottl aac_enqueue_busy(cm); 2658151086Sscottl device = index; 2659151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2660151086Sscottl device += 4; 2661151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2662151086Sscottl device += 4; 2663151086Sscottl AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 2664151086Sscottl AAC_SETREG4(sc, AAC_RKT_IQUE, index); 2665151086Sscottl return 0; 2666151086Sscottl} 2667151086Sscottl 2668151086Sscottl/* 2669151086Sscottl * New comm. interface: get, set outbound queue index 2670151086Sscottl */ 2671151086Sscottlstatic int 2672151086Sscottlaac_rx_get_outb_queue(struct aac_softc *sc) 2673151086Sscottl{ 2674151086Sscottl debug_called(3); 2675151086Sscottl 2676151086Sscottl return(AAC_GETREG4(sc, AAC_RX_OQUE)); 2677151086Sscottl} 2678151086Sscottl 2679151086Sscottlstatic int 2680151086Sscottlaac_rkt_get_outb_queue(struct aac_softc *sc) 2681151086Sscottl{ 2682151086Sscottl debug_called(3); 2683151086Sscottl 2684151086Sscottl return(AAC_GETREG4(sc, AAC_RKT_OQUE)); 2685151086Sscottl} 2686151086Sscottl 2687151086Sscottlstatic void 2688151086Sscottlaac_rx_set_outb_queue(struct aac_softc *sc, int index) 2689151086Sscottl{ 2690151086Sscottl debug_called(3); 2691151086Sscottl 2692151086Sscottl AAC_SETREG4(sc, AAC_RX_OQUE, index); 2693151086Sscottl} 2694151086Sscottl 2695151086Sscottlstatic void 2696151086Sscottlaac_rkt_set_outb_queue(struct aac_softc *sc, int index) 2697151086Sscottl{ 2698151086Sscottl debug_called(3); 2699151086Sscottl 2700151086Sscottl AAC_SETREG4(sc, AAC_RKT_OQUE, index); 2701151086Sscottl} 2702151086Sscottl 2703151086Sscottl/* 270483114Sscottl * Debugging and Diagnostics 270583114Sscottl */ 270665793Smsmith 270783114Sscottl/* 270865793Smsmith * Print some information about the controller. 270965793Smsmith */ 271065793Smsmithstatic void 271165793Smsmithaac_describe_controller(struct aac_softc *sc) 271265793Smsmith{ 271395350Sscottl struct aac_fib *fib; 271483114Sscottl struct aac_adapter_info *info; 271565793Smsmith 271683114Sscottl debug_called(2); 271765793Smsmith 2718130006Sscottl aac_alloc_sync_fib(sc, &fib); 271995350Sscottl 272095350Sscottl fib->data[0] = 0; 272195350Sscottl if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 272283114Sscottl device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 272395536Sscottl aac_release_sync_fib(sc); 272483114Sscottl return; 272583114Sscottl } 272665793Smsmith 272783114Sscottl /* save the kernel revision structure for later use */ 2728135095Sscottl info = (struct aac_adapter_info *)&fib->data[0]; 272983114Sscottl sc->aac_revision = info->KernelRevision; 273095536Sscottl 2731151086Sscottl device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n", 2732151086Sscottl AAC_DRIVER_VERSION >> 24, 2733151086Sscottl (AAC_DRIVER_VERSION >> 16) & 0xFF, 2734151086Sscottl AAC_DRIVER_VERSION & 0xFF, 2735151086Sscottl AAC_DRIVER_BUILD); 2736151086Sscottl 2737135095Sscottl if (bootverbose) { 2738146851Sscottl device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2739146851Sscottl "(%dMB cache, %dMB execution), %s\n", 2740135095Sscottl aac_describe_code(aac_cpu_variant, info->CpuVariant), 2741146851Sscottl info->ClockSpeed, info->TotalMem / (1024 * 1024), 2742146851Sscottl info->BufferMem / (1024 * 1024), 2743146851Sscottl info->ExecutionMem / (1024 * 1024), 2744135095Sscottl aac_describe_code(aac_battery_platform, 2745135095Sscottl info->batteryPlatform)); 2746112679Sscottl 2747135095Sscottl device_printf(sc->aac_dev, 2748135095Sscottl "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2749135095Sscottl info->KernelRevision.external.comp.major, 2750135095Sscottl info->KernelRevision.external.comp.minor, 2751135095Sscottl info->KernelRevision.external.comp.dash, 2752135095Sscottl info->KernelRevision.buildNumber, 2753135095Sscottl (u_int32_t)(info->SerialNumber & 0xffffff)); 2754135095Sscottl 2755112679Sscottl device_printf(sc->aac_dev, "Supported Options=%b\n", 2756112679Sscottl sc->supported_options, 2757112679Sscottl "\20" 2758112679Sscottl "\1SNAPSHOT" 2759112679Sscottl "\2CLUSTERS" 2760112679Sscottl "\3WCACHE" 2761112679Sscottl "\4DATA64" 2762112679Sscottl "\5HOSTTIME" 2763112679Sscottl "\6RAID50" 2764112679Sscottl "\7WINDOW4GB" 2765112679Sscottl "\10SCSIUPGD" 2766112679Sscottl "\11SOFTERR" 2767112679Sscottl "\12NORECOND" 2768112679Sscottl "\13SGMAP64" 2769112679Sscottl "\14ALARM" 2770151086Sscottl "\15NONDASD" 2771151086Sscottl "\16SCSIMGT" 2772151086Sscottl "\17RAIDSCSI" 2773151086Sscottl "\21ADPTINFO" 2774151086Sscottl "\22NEWCOMM" 2775151086Sscottl "\23ARRAY64BIT" 2776151086Sscottl "\24HEATSENSOR"); 2777112679Sscottl } 2778135095Sscottl aac_release_sync_fib(sc); 277965793Smsmith} 278065793Smsmith 278183114Sscottl/* 278265793Smsmith * Look up a text description of a numeric error code and return a pointer to 278365793Smsmith * same. 278465793Smsmith */ 278565793Smsmithstatic char * 278665793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code) 278765793Smsmith{ 278883114Sscottl int i; 278965793Smsmith 279083114Sscottl for (i = 0; table[i].string != NULL; i++) 279183114Sscottl if (table[i].code == code) 279283114Sscottl return(table[i].string); 279383114Sscottl return(table[i + 1].string); 279465793Smsmith} 279565793Smsmith 279683114Sscottl/* 279783114Sscottl * Management Interface 279883114Sscottl */ 279965793Smsmith 280065793Smsmithstatic int 2801130585Sphkaac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 280265793Smsmith{ 280383114Sscottl struct aac_softc *sc; 280465793Smsmith 280583114Sscottl debug_called(2); 280665793Smsmith 280783114Sscottl sc = dev->si_drv1; 280865793Smsmith 280983114Sscottl /* Check to make sure the device isn't already open */ 281083114Sscottl if (sc->aac_state & AAC_STATE_OPEN) { 281183114Sscottl return EBUSY; 281283114Sscottl } 281383114Sscottl sc->aac_state |= AAC_STATE_OPEN; 281483114Sscottl 281583114Sscottl return 0; 281665793Smsmith} 281765793Smsmith 281865793Smsmithstatic int 2819130585Sphkaac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 282065793Smsmith{ 282183114Sscottl struct aac_softc *sc; 282265793Smsmith 282383114Sscottl debug_called(2); 282465793Smsmith 282583114Sscottl sc = dev->si_drv1; 282665793Smsmith 282783114Sscottl /* Mark this unit as no longer open */ 282883114Sscottl sc->aac_state &= ~AAC_STATE_OPEN; 282983114Sscottl 283083114Sscottl return 0; 283165793Smsmith} 283265793Smsmith 283365793Smsmithstatic int 2834130585Sphkaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 283565793Smsmith{ 283683114Sscottl union aac_statrequest *as; 283783114Sscottl struct aac_softc *sc; 283883114Sscottl int error = 0; 2839119146Sscottl uint32_t cookie; 284065793Smsmith 284183114Sscottl debug_called(2); 284265793Smsmith 284383114Sscottl as = (union aac_statrequest *)arg; 284483114Sscottl sc = dev->si_drv1; 284583114Sscottl 284683114Sscottl switch (cmd) { 284783114Sscottl case AACIO_STATS: 284883114Sscottl switch (as->as_item) { 284983114Sscottl case AACQ_FREE: 285083114Sscottl case AACQ_BIO: 285183114Sscottl case AACQ_READY: 285283114Sscottl case AACQ_BUSY: 285383114Sscottl bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 285483114Sscottl sizeof(struct aac_qstat)); 285583114Sscottl break; 285683114Sscottl default: 285783114Sscottl error = ENOENT; 285883114Sscottl break; 285983114Sscottl } 286083114Sscottl break; 286183114Sscottl 286283114Sscottl case FSACTL_SENDFIB: 286383114Sscottl arg = *(caddr_t*)arg; 286483114Sscottl case FSACTL_LNX_SENDFIB: 286583114Sscottl debug(1, "FSACTL_SENDFIB"); 286683114Sscottl error = aac_ioctl_sendfib(sc, arg); 286783114Sscottl break; 286883114Sscottl case FSACTL_AIF_THREAD: 286983114Sscottl case FSACTL_LNX_AIF_THREAD: 287083114Sscottl debug(1, "FSACTL_AIF_THREAD"); 287183114Sscottl error = EINVAL; 287283114Sscottl break; 287383114Sscottl case FSACTL_OPEN_GET_ADAPTER_FIB: 287483114Sscottl arg = *(caddr_t*)arg; 287587183Sscottl case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 287683114Sscottl debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 287783114Sscottl /* 287883114Sscottl * Pass the caller out an AdapterFibContext. 287983114Sscottl * 288083114Sscottl * Note that because we only support one opener, we 288183114Sscottl * basically ignore this. Set the caller's context to a magic 288283114Sscottl * number just in case. 288383114Sscottl * 288483114Sscottl * The Linux code hands the driver a pointer into kernel space, 288583114Sscottl * and then trusts it when the caller hands it back. Aiee! 288683114Sscottl * Here, we give it the proc pointer of the per-adapter aif 288783114Sscottl * thread. It's only used as a sanity check in other calls. 288883114Sscottl */ 2889119146Sscottl cookie = (uint32_t)(uintptr_t)sc->aifthread; 2890119146Sscottl error = copyout(&cookie, arg, sizeof(cookie)); 289183114Sscottl break; 289283114Sscottl case FSACTL_GET_NEXT_ADAPTER_FIB: 289383114Sscottl arg = *(caddr_t*)arg; 289483114Sscottl case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 289583114Sscottl debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 289683114Sscottl error = aac_getnext_aif(sc, arg); 289783114Sscottl break; 289883114Sscottl case FSACTL_CLOSE_GET_ADAPTER_FIB: 289983114Sscottl case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 290083114Sscottl debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 290183114Sscottl /* don't do anything here */ 290283114Sscottl break; 290383114Sscottl case FSACTL_MINIPORT_REV_CHECK: 290483114Sscottl arg = *(caddr_t*)arg; 290583114Sscottl case FSACTL_LNX_MINIPORT_REV_CHECK: 290683114Sscottl debug(1, "FSACTL_MINIPORT_REV_CHECK"); 290783114Sscottl error = aac_rev_check(sc, arg); 290883114Sscottl break; 290983114Sscottl case FSACTL_QUERY_DISK: 291083114Sscottl arg = *(caddr_t*)arg; 291183114Sscottl case FSACTL_LNX_QUERY_DISK: 291283114Sscottl debug(1, "FSACTL_QUERY_DISK"); 291383114Sscottl error = aac_query_disk(sc, arg); 2914151086Sscottl break; 291583114Sscottl case FSACTL_DELETE_DISK: 291683114Sscottl case FSACTL_LNX_DELETE_DISK: 291783114Sscottl /* 291883114Sscottl * We don't trust the underland to tell us when to delete a 291983114Sscottl * container, rather we rely on an AIF coming from the 292083114Sscottl * controller 292183114Sscottl */ 292283114Sscottl error = 0; 292383114Sscottl break; 2924151086Sscottl case FSACTL_GET_PCI_INFO: 2925151086Sscottl arg = *(caddr_t*)arg; 2926151086Sscottl case FSACTL_LNX_GET_PCI_INFO: 2927151086Sscottl debug(1, "FSACTL_GET_PCI_INFO"); 2928151086Sscottl error = aac_get_pci_info(sc, arg); 2929151086Sscottl break; 293070393Smsmith default: 293187183Sscottl debug(1, "unsupported cmd 0x%lx\n", cmd); 293283114Sscottl error = EINVAL; 293383114Sscottl break; 293470393Smsmith } 293583114Sscottl return(error); 293665793Smsmith} 293765793Smsmith 293887183Sscottlstatic int 2939130585Sphkaac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 294087183Sscottl{ 294187183Sscottl struct aac_softc *sc; 294287183Sscottl int revents; 294387183Sscottl 294487183Sscottl sc = dev->si_drv1; 294587183Sscottl revents = 0; 294687183Sscottl 2947133540Sscottl mtx_lock(&sc->aac_aifq_lock); 294887183Sscottl if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 294987183Sscottl if (sc->aac_aifq_tail != sc->aac_aifq_head) 295087183Sscottl revents |= poll_events & (POLLIN | POLLRDNORM); 295187183Sscottl } 2952133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 295387183Sscottl 295487183Sscottl if (revents == 0) { 295587183Sscottl if (poll_events & (POLLIN | POLLRDNORM)) 295687183Sscottl selrecord(td, &sc->rcv_select); 295787183Sscottl } 295887183Sscottl 295987183Sscottl return (revents); 296087183Sscottl} 296187183Sscottl 2962151086Sscottlstatic void 2963151086Sscottlaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2964151086Sscottl{ 2965151086Sscottl 2966151086Sscottl switch (event->ev_type) { 2967151086Sscottl case AAC_EVENT_CMFREE: 2968151086Sscottl mtx_lock(&sc->aac_io_lock); 2969151086Sscottl if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) { 2970151086Sscottl aac_add_event(sc, event); 2971151086Sscottl mtx_unlock(&sc->aac_io_lock); 2972151086Sscottl return; 2973151086Sscottl } 2974151086Sscottl free(event, M_AACBUF); 2975151086Sscottl wakeup(aac_ioctl_sendfib); 2976151086Sscottl mtx_unlock(&sc->aac_io_lock); 2977151086Sscottl break; 2978151086Sscottl default: 2979151086Sscottl break; 2980151086Sscottl } 2981151086Sscottl} 2982151086Sscottl 298383114Sscottl/* 298465793Smsmith * Send a FIB supplied from userspace 298565793Smsmith */ 298665793Smsmithstatic int 298765793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 298865793Smsmith{ 298983114Sscottl struct aac_command *cm; 299083114Sscottl int size, error; 299165793Smsmith 299283114Sscottl debug_called(2); 299365793Smsmith 299483114Sscottl cm = NULL; 299565793Smsmith 299683114Sscottl /* 299783114Sscottl * Get a command 299883114Sscottl */ 2999133540Sscottl mtx_lock(&sc->aac_io_lock); 300083114Sscottl if (aac_alloc_command(sc, &cm)) { 3001151086Sscottl struct aac_event *event; 3002151086Sscottl 3003151086Sscottl event = malloc(sizeof(struct aac_event), M_AACBUF, 3004151086Sscottl M_NOWAIT | M_ZERO); 3005151086Sscottl if (event == NULL) { 3006151086Sscottl error = EBUSY; 3007151086Sscottl goto out; 3008151086Sscottl } 3009151086Sscottl event->ev_type = AAC_EVENT_CMFREE; 3010151086Sscottl event->ev_callback = aac_ioctl_event; 3011151086Sscottl event->ev_arg = &cm; 3012151086Sscottl aac_add_event(sc, event); 3013151086Sscottl msleep(aac_ioctl_sendfib, &sc->aac_io_lock, 0, "sendfib", 0); 301483114Sscottl } 301565793Smsmith 301683114Sscottl /* 301783114Sscottl * Fetch the FIB header, then re-copy to get data as well. 301883114Sscottl */ 301983114Sscottl if ((error = copyin(ufib, cm->cm_fib, 302083114Sscottl sizeof(struct aac_fib_header))) != 0) 302183114Sscottl goto out; 302283114Sscottl size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 302383114Sscottl if (size > sizeof(struct aac_fib)) { 3024119146Sscottl device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 302583114Sscottl size, sizeof(struct aac_fib)); 302683114Sscottl size = sizeof(struct aac_fib); 302783114Sscottl } 302883114Sscottl if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 302983114Sscottl goto out; 303083114Sscottl cm->cm_fib->Header.Size = size; 3031150119Sscottl cm->cm_timestamp = time_uptime; 303265793Smsmith 303383114Sscottl /* 303483114Sscottl * Pass the FIB to the controller, wait for it to complete. 303583114Sscottl */ 3036128258Sscottl if ((error = aac_wait_command(cm)) != 0) { 3037110426Sscottl device_printf(sc->aac_dev, 3038110426Sscottl "aac_wait_command return %d\n", error); 303983114Sscottl goto out; 304087183Sscottl } 304165793Smsmith 304283114Sscottl /* 304383114Sscottl * Copy the FIB and data back out to the caller. 304483114Sscottl */ 304583114Sscottl size = cm->cm_fib->Header.Size; 304683114Sscottl if (size > sizeof(struct aac_fib)) { 3047119146Sscottl device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 304883114Sscottl size, sizeof(struct aac_fib)); 304983114Sscottl size = sizeof(struct aac_fib); 305083114Sscottl } 305183114Sscottl error = copyout(cm->cm_fib, ufib, size); 305265793Smsmith 305365793Smsmithout: 305483114Sscottl if (cm != NULL) { 305583114Sscottl aac_release_command(cm); 305683114Sscottl } 3057111532Sscottl 3058133540Sscottl mtx_unlock(&sc->aac_io_lock); 305983114Sscottl return(error); 306065793Smsmith} 306165793Smsmith 306283114Sscottl/* 306365793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference. 306482527Sscottl * If the queue fills up, then drop the older entries. 306565793Smsmith */ 306665793Smsmithstatic void 306782527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 306865793Smsmith{ 306983114Sscottl struct aac_aif_command *aif; 307083114Sscottl struct aac_container *co, *co_next; 307195350Sscottl struct aac_mntinfo *mi; 307295350Sscottl struct aac_mntinforesp *mir = NULL; 307383114Sscottl u_int16_t rsize; 307487183Sscottl int next, found; 3075115760Sscottl int count = 0, added = 0, i = 0; 307665793Smsmith 307783114Sscottl debug_called(2); 307865793Smsmith 307983114Sscottl aif = (struct aac_aif_command*)&fib->data[0]; 308083114Sscottl aac_print_aif(sc, aif); 308182527Sscottl 308283114Sscottl /* Is it an event that we should care about? */ 308383114Sscottl switch (aif->command) { 308483114Sscottl case AifCmdEventNotify: 308583114Sscottl switch (aif->data.EN.type) { 308683114Sscottl case AifEnAddContainer: 308783114Sscottl case AifEnDeleteContainer: 308883114Sscottl /* 308983114Sscottl * A container was added or deleted, but the message 309083114Sscottl * doesn't tell us anything else! Re-enumerate the 309183114Sscottl * containers and sort things out. 309283114Sscottl */ 3093130006Sscottl aac_alloc_sync_fib(sc, &fib); 309495350Sscottl mi = (struct aac_mntinfo *)&fib->data[0]; 309583114Sscottl do { 309683114Sscottl /* 309783114Sscottl * Ask the controller for its containers one at 309883114Sscottl * a time. 309983114Sscottl * XXX What if the controller's list changes 310083114Sscottl * midway through this enumaration? 310183114Sscottl * XXX This should be done async. 310283114Sscottl */ 310395966Sscottl bzero(mi, sizeof(struct aac_mntinfo)); 310495966Sscottl mi->Command = VM_NameServe; 310595966Sscottl mi->MntType = FT_FILESYS; 310695350Sscottl mi->MntCount = i; 310783114Sscottl rsize = sizeof(mir); 310895350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 310995350Sscottl sizeof(struct aac_mntinfo))) { 3110115760Sscottl printf("Error probing container %d\n", 311183114Sscottl i); 311283114Sscottl continue; 311383114Sscottl } 311495350Sscottl mir = (struct aac_mntinforesp *)&fib->data[0]; 3115115760Sscottl /* XXX Need to check if count changed */ 3116115760Sscottl count = mir->MntRespCount; 311783114Sscottl /* 311883114Sscottl * Check the container against our list. 311983114Sscottl * co->co_found was already set to 0 in a 312083114Sscottl * previous run. 312183114Sscottl */ 312295350Sscottl if ((mir->Status == ST_OK) && 312395350Sscottl (mir->MntTable[0].VolType != CT_NONE)) { 312483114Sscottl found = 0; 312583114Sscottl TAILQ_FOREACH(co, 312683114Sscottl &sc->aac_container_tqh, 312783114Sscottl co_link) { 312883114Sscottl if (co->co_mntobj.ObjectId == 312995350Sscottl mir->MntTable[0].ObjectId) { 313083114Sscottl co->co_found = 1; 313183114Sscottl found = 1; 313283114Sscottl break; 313383114Sscottl } 313483114Sscottl } 313583114Sscottl /* 313683114Sscottl * If the container matched, continue 313783114Sscottl * in the list. 313883114Sscottl */ 313983114Sscottl if (found) { 314083114Sscottl i++; 314183114Sscottl continue; 314283114Sscottl } 314383114Sscottl 314483114Sscottl /* 314583114Sscottl * This is a new container. Do all the 3146110426Sscottl * appropriate things to set it up. 3147110426Sscottl */ 314895350Sscottl aac_add_container(sc, mir, 1); 314983114Sscottl added = 1; 315083114Sscottl } 315183114Sscottl i++; 3152115760Sscottl } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 315395350Sscottl aac_release_sync_fib(sc); 315483114Sscottl 315583114Sscottl /* 315683114Sscottl * Go through our list of containers and see which ones 315783114Sscottl * were not marked 'found'. Since the controller didn't 315883114Sscottl * list them they must have been deleted. Do the 315983114Sscottl * appropriate steps to destroy the device. Also reset 316083114Sscottl * the co->co_found field. 316183114Sscottl */ 316283114Sscottl co = TAILQ_FIRST(&sc->aac_container_tqh); 316383114Sscottl while (co != NULL) { 316483114Sscottl if (co->co_found == 0) { 3165151086Sscottl mtx_unlock(&sc->aac_io_lock); 3166151086Sscottl mtx_lock(&Giant); 316783114Sscottl device_delete_child(sc->aac_dev, 316883114Sscottl co->co_disk); 3169151086Sscottl mtx_unlock(&Giant); 3170151086Sscottl mtx_lock(&sc->aac_io_lock); 317183114Sscottl co_next = TAILQ_NEXT(co, co_link); 3172133540Sscottl mtx_lock(&sc->aac_container_lock); 317383114Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, 317483114Sscottl co_link); 3175133540Sscottl mtx_unlock(&sc->aac_container_lock); 3176133541Sscottl free(co, M_AACBUF); 317783114Sscottl co = co_next; 317883114Sscottl } else { 317983114Sscottl co->co_found = 0; 318083114Sscottl co = TAILQ_NEXT(co, co_link); 318183114Sscottl } 318282527Sscottl } 318382527Sscottl 318483114Sscottl /* Attach the newly created containers */ 3185151086Sscottl if (added) { 3186151086Sscottl mtx_unlock(&sc->aac_io_lock); 3187151086Sscottl mtx_lock(&Giant); 318883114Sscottl bus_generic_attach(sc->aac_dev); 3189151086Sscottl mtx_unlock(&Giant); 3190151086Sscottl mtx_lock(&sc->aac_io_lock); 3191151086Sscottl } 319283114Sscottl 3193105528Sphk break; 319482527Sscottl 319583114Sscottl default: 319683114Sscottl break; 319782527Sscottl } 319882527Sscottl 319982527Sscottl default: 320083114Sscottl break; 320182527Sscottl } 320282527Sscottl 320383114Sscottl /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3204133540Sscottl mtx_lock(&sc->aac_aifq_lock); 320583114Sscottl next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 320683114Sscottl if (next != sc->aac_aifq_tail) { 320783114Sscottl bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 320887183Sscottl sc->aac_aifq_head = next; 320987183Sscottl 321087183Sscottl /* On the off chance that someone is sleeping for an aif... */ 321187183Sscottl if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 321287183Sscottl wakeup(sc->aac_aifq); 321387183Sscottl /* Wakeup any poll()ers */ 3214122352Stanimura selwakeuppri(&sc->rcv_select, PRIBIO); 321583114Sscottl } 3216133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 321782527Sscottl 321883114Sscottl return; 321965793Smsmith} 322065793Smsmith 322183114Sscottl/* 322270393Smsmith * Return the Revision of the driver to userspace and check to see if the 322382527Sscottl * userspace app is possibly compatible. This is extremely bogus since 322482527Sscottl * our driver doesn't follow Adaptec's versioning system. Cheat by just 322582527Sscottl * returning what the card reported. 322665793Smsmith */ 322765793Smsmithstatic int 322881189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata) 322965793Smsmith{ 323083114Sscottl struct aac_rev_check rev_check; 323183114Sscottl struct aac_rev_check_resp rev_check_resp; 323283114Sscottl int error = 0; 323365793Smsmith 323483114Sscottl debug_called(2); 323565793Smsmith 323683114Sscottl /* 323783114Sscottl * Copyin the revision struct from userspace 323883114Sscottl */ 323983114Sscottl if ((error = copyin(udata, (caddr_t)&rev_check, 324081082Sscottl sizeof(struct aac_rev_check))) != 0) { 324183114Sscottl return error; 324283114Sscottl } 324365793Smsmith 324483114Sscottl debug(2, "Userland revision= %d\n", 324583114Sscottl rev_check.callingRevision.buildNumber); 324665793Smsmith 324783114Sscottl /* 324883114Sscottl * Doctor up the response struct. 324983114Sscottl */ 325083114Sscottl rev_check_resp.possiblyCompatible = 1; 325183114Sscottl rev_check_resp.adapterSWRevision.external.ul = 325283114Sscottl sc->aac_revision.external.ul; 325383114Sscottl rev_check_resp.adapterSWRevision.buildNumber = 325483114Sscottl sc->aac_revision.buildNumber; 325565793Smsmith 325683114Sscottl return(copyout((caddr_t)&rev_check_resp, udata, 325783114Sscottl sizeof(struct aac_rev_check_resp))); 325865793Smsmith} 325965793Smsmith 326083114Sscottl/* 326165793Smsmith * Pass the caller the next AIF in their queue 326265793Smsmith */ 326365793Smsmithstatic int 326481189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 326565793Smsmith{ 326683114Sscottl struct get_adapter_fib_ioctl agf; 3267111691Sscottl int error; 326865793Smsmith 326983114Sscottl debug_called(2); 327065793Smsmith 327183114Sscottl if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 327265793Smsmith 327383114Sscottl /* 327483114Sscottl * Check the magic number that we gave the caller. 327583114Sscottl */ 3276119146Sscottl if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 327783114Sscottl error = EFAULT; 327883114Sscottl } else { 327981189Sscottl error = aac_return_aif(sc, agf.AifFib); 328083114Sscottl if ((error == EAGAIN) && (agf.Wait)) { 328183114Sscottl sc->aac_state |= AAC_STATE_AIF_SLEEPER; 328283114Sscottl while (error == EAGAIN) { 328383114Sscottl error = tsleep(sc->aac_aifq, PRIBIO | 328483114Sscottl PCATCH, "aacaif", 0); 328583114Sscottl if (error == 0) 328683114Sscottl error = aac_return_aif(sc, 328783114Sscottl agf.AifFib); 328883114Sscottl } 328983114Sscottl sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 329083114Sscottl } 329165793Smsmith } 329265793Smsmith } 329383114Sscottl return(error); 329465793Smsmith} 329565793Smsmith 329683114Sscottl/* 329770393Smsmith * Hand the next AIF off the top of the queue out to userspace. 329870393Smsmith */ 329970393Smsmithstatic int 330081189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr) 330170393Smsmith{ 3302121173Sscottl int next, error; 330370393Smsmith 330483114Sscottl debug_called(2); 330570393Smsmith 3306133540Sscottl mtx_lock(&sc->aac_aifq_lock); 330783114Sscottl if (sc->aac_aifq_tail == sc->aac_aifq_head) { 3308133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 3309121173Sscottl return (EAGAIN); 331083114Sscottl } 3311121173Sscottl 3312121173Sscottl next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 3313121173Sscottl error = copyout(&sc->aac_aifq[next], uptr, 3314121173Sscottl sizeof(struct aac_aif_command)); 3315121173Sscottl if (error) 3316121173Sscottl device_printf(sc->aac_dev, 3317121173Sscottl "aac_return_aif: copyout returned %d\n", error); 3318121173Sscottl else 3319121173Sscottl sc->aac_aifq_tail = next; 3320121173Sscottl 3321133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 332283114Sscottl return(error); 332370393Smsmith} 332482527Sscottl 3325151086Sscottlstatic int 3326151086Sscottlaac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3327151086Sscottl{ 3328151086Sscottl struct aac_pci_info { 3329151086Sscottl u_int32_t bus; 3330151086Sscottl u_int32_t slot; 3331151086Sscottl } pciinf; 3332151086Sscottl int error; 3333151086Sscottl 3334151086Sscottl debug_called(2); 3335151086Sscottl 3336151086Sscottl pciinf.bus = pci_get_bus(sc->aac_dev); 3337151086Sscottl pciinf.slot = pci_get_slot(sc->aac_dev); 3338151086Sscottl 3339151086Sscottl error = copyout((caddr_t)&pciinf, uptr, 3340151086Sscottl sizeof(struct aac_pci_info)); 3341151086Sscottl 3342151086Sscottl return (error); 3343151086Sscottl} 3344151086Sscottl 334583114Sscottl/* 334682527Sscottl * Give the userland some information about the container. The AAC arch 334782527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects 334882527Sscottl * the containers to have b:t:l numbers. Fake it. 334982527Sscottl */ 335082527Sscottlstatic int 335182527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr) 335282527Sscottl{ 335383114Sscottl struct aac_query_disk query_disk; 335483114Sscottl struct aac_container *co; 335583114Sscottl struct aac_disk *disk; 335683114Sscottl int error, id; 335782527Sscottl 335883114Sscottl debug_called(2); 335982527Sscottl 336083114Sscottl disk = NULL; 336182527Sscottl 336283114Sscottl error = copyin(uptr, (caddr_t)&query_disk, 336383114Sscottl sizeof(struct aac_query_disk)); 336483114Sscottl if (error) 336583114Sscottl return (error); 336682527Sscottl 336783114Sscottl id = query_disk.ContainerNumber; 336883114Sscottl if (id == -1) 336983114Sscottl return (EINVAL); 337082527Sscottl 3371133540Sscottl mtx_lock(&sc->aac_container_lock); 337283114Sscottl TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 337383114Sscottl if (co->co_mntobj.ObjectId == id) 337483114Sscottl break; 337583114Sscottl } 337682527Sscottl 3377105528Sphk if (co == NULL) { 337883114Sscottl query_disk.Valid = 0; 337983114Sscottl query_disk.Locked = 0; 338083114Sscottl query_disk.Deleted = 1; /* XXX is this right? */ 3381105528Sphk } else { 3382105528Sphk disk = device_get_softc(co->co_disk); 3383105528Sphk query_disk.Valid = 1; 3384105528Sphk query_disk.Locked = 3385105528Sphk (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 3386105528Sphk query_disk.Deleted = 0; 3387105528Sphk query_disk.Bus = device_get_unit(sc->aac_dev); 3388105528Sphk query_disk.Target = disk->unit; 3389105528Sphk query_disk.Lun = 0; 3390105528Sphk query_disk.UnMapped = 0; 3391111525Sscottl sprintf(&query_disk.diskDeviceName[0], "%s%d", 3392125975Sphk disk->ad_disk->d_name, disk->ad_disk->d_unit); 3393105528Sphk } 3394133540Sscottl mtx_unlock(&sc->aac_container_lock); 339582527Sscottl 339683114Sscottl error = copyout((caddr_t)&query_disk, uptr, 339783114Sscottl sizeof(struct aac_query_disk)); 339883114Sscottl 339983114Sscottl return (error); 340082527Sscottl} 340182527Sscottl 340295536Sscottlstatic void 340395536Sscottlaac_get_bus_info(struct aac_softc *sc) 340495536Sscottl{ 340595536Sscottl struct aac_fib *fib; 340695536Sscottl struct aac_ctcfg *c_cmd; 340795536Sscottl struct aac_ctcfg_resp *c_resp; 340895536Sscottl struct aac_vmioctl *vmi; 340995536Sscottl struct aac_vmi_businf_resp *vmi_resp; 341095536Sscottl struct aac_getbusinf businfo; 3411110426Sscottl struct aac_sim *caminf; 341295536Sscottl device_t child; 341395536Sscottl int i, found, error; 341495536Sscottl 3415130006Sscottl aac_alloc_sync_fib(sc, &fib); 341695536Sscottl c_cmd = (struct aac_ctcfg *)&fib->data[0]; 341795966Sscottl bzero(c_cmd, sizeof(struct aac_ctcfg)); 341895536Sscottl 341995536Sscottl c_cmd->Command = VM_ContainerConfig; 342095536Sscottl c_cmd->cmd = CT_GET_SCSI_METHOD; 342195536Sscottl c_cmd->param = 0; 342295536Sscottl 342395536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 342495536Sscottl sizeof(struct aac_ctcfg)); 342595536Sscottl if (error) { 342695536Sscottl device_printf(sc->aac_dev, "Error %d sending " 342795536Sscottl "VM_ContainerConfig command\n", error); 342895536Sscottl aac_release_sync_fib(sc); 342995536Sscottl return; 343095536Sscottl } 343195536Sscottl 343295536Sscottl c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 343395536Sscottl if (c_resp->Status != ST_OK) { 343495536Sscottl device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 343595536Sscottl c_resp->Status); 343695536Sscottl aac_release_sync_fib(sc); 343795536Sscottl return; 343895536Sscottl } 343995536Sscottl 344095536Sscottl sc->scsi_method_id = c_resp->param; 344195536Sscottl 344295536Sscottl vmi = (struct aac_vmioctl *)&fib->data[0]; 344395966Sscottl bzero(vmi, sizeof(struct aac_vmioctl)); 344495966Sscottl 344595536Sscottl vmi->Command = VM_Ioctl; 344695536Sscottl vmi->ObjType = FT_DRIVE; 344795536Sscottl vmi->MethId = sc->scsi_method_id; 344895536Sscottl vmi->ObjId = 0; 344995536Sscottl vmi->IoctlCmd = GetBusInfo; 345095536Sscottl 345195536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 345295536Sscottl sizeof(struct aac_vmioctl)); 345395536Sscottl if (error) { 345495536Sscottl device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 345595536Sscottl error); 345695536Sscottl aac_release_sync_fib(sc); 345795536Sscottl return; 345895536Sscottl } 345995536Sscottl 346095536Sscottl vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 346195536Sscottl if (vmi_resp->Status != ST_OK) { 346295536Sscottl device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 346395536Sscottl vmi_resp->Status); 346495536Sscottl aac_release_sync_fib(sc); 346595536Sscottl return; 346695536Sscottl } 346795536Sscottl 346895536Sscottl bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 346995536Sscottl aac_release_sync_fib(sc); 347095536Sscottl 347195536Sscottl found = 0; 347295536Sscottl for (i = 0; i < businfo.BusCount; i++) { 347395536Sscottl if (businfo.BusValid[i] != AAC_BUS_VALID) 347495536Sscottl continue; 347595536Sscottl 3476110428Sscottl caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3477110428Sscottl M_AACBUF, M_NOWAIT | M_ZERO); 3478143838Sscottl if (caminf == NULL) { 3479143838Sscottl device_printf(sc->aac_dev, 3480143838Sscottl "No memory to add passthrough bus %d\n", i); 3481143838Sscottl break; 3482151086Sscottl }; 348395536Sscottl 348495536Sscottl child = device_add_child(sc->aac_dev, "aacp", -1); 348595536Sscottl if (child == NULL) { 3486143838Sscottl device_printf(sc->aac_dev, 3487143838Sscottl "device_add_child failed for passthrough bus %d\n", 3488143838Sscottl i); 3489143838Sscottl free(caminf, M_AACBUF); 3490151086Sscottl break; 349195536Sscottl } 349295536Sscottl 349395536Sscottl caminf->TargetsPerBus = businfo.TargetsPerBus; 349495536Sscottl caminf->BusNumber = i; 349595536Sscottl caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 349695536Sscottl caminf->aac_sc = sc; 3497110432Sscottl caminf->sim_dev = child; 349895536Sscottl 349995536Sscottl device_set_ivars(child, caminf); 350095536Sscottl device_set_desc(child, "SCSI Passthrough Bus"); 3501110426Sscottl TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 350295536Sscottl 350395536Sscottl found = 1; 350495536Sscottl } 350595536Sscottl 350695536Sscottl if (found) 350795536Sscottl bus_generic_attach(sc->aac_dev); 350895536Sscottl 350995536Sscottl return; 351095536Sscottl} 3511