aac.c revision 151330
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 151330 2005-10-14 16:22:45Z 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{ 1577151330Sscottl u_int32_t major, minor, options = 0, atu_size = 0; 1578151330Sscottl int status; 157990275Sscottl 158090275Sscottl debug_called(1); 158190275Sscottl 1582112679Sscottl /* 1583112679Sscottl * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1584112679Sscottl * firmware version 1.x are not compatible with this driver. 1585112679Sscottl */ 1586112679Sscottl if (sc->flags & AAC_FLAGS_PERC2QC) { 158790275Sscottl if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 158890275Sscottl NULL)) { 158990275Sscottl device_printf(sc->aac_dev, 159090275Sscottl "Error reading firmware version\n"); 159190275Sscottl return (EIO); 159290275Sscottl } 159390275Sscottl 159490275Sscottl /* These numbers are stored as ASCII! */ 1595112679Sscottl major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1596112679Sscottl minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 159790275Sscottl if (major == 1) { 159890275Sscottl device_printf(sc->aac_dev, 159990275Sscottl "Firmware version %d.%d is not supported.\n", 160090275Sscottl major, minor); 160190275Sscottl return (EINVAL); 160290275Sscottl } 160390275Sscottl } 160490275Sscottl 1605112679Sscottl /* 1606112679Sscottl * Retrieve the capabilities/supported options word so we know what 1607151330Sscottl * work-arounds to enable. Some firmware revs don't support this 1608151330Sscottl * command. 1609112679Sscottl */ 1610151330Sscottl if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1611151330Sscottl if (status != AAC_SRB_STS_INVALID_REQUEST) { 1612151330Sscottl device_printf(sc->aac_dev, 1613151330Sscottl "RequestAdapterInfo failed\n"); 1614151330Sscottl return (EIO); 1615151330Sscottl } 1616151330Sscottl } else { 1617151330Sscottl options = AAC_GET_MAILBOX(sc, 1); 1618151330Sscottl atu_size = AAC_GET_MAILBOX(sc, 2); 1619151330Sscottl sc->supported_options = options; 1620112679Sscottl 1621151330Sscottl if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1622151330Sscottl (sc->flags & AAC_FLAGS_NO4GB) == 0) 1623151330Sscottl sc->flags |= AAC_FLAGS_4GB_WINDOW; 1624151330Sscottl if (options & AAC_SUPPORTED_NONDASD) 1625151330Sscottl sc->flags |= AAC_FLAGS_ENABLE_CAM; 1626151330Sscottl if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1627151330Sscottl && (sizeof(bus_addr_t) > 4)) { 1628151330Sscottl device_printf(sc->aac_dev, 1629151330Sscottl "Enabling 64-bit address support\n"); 1630151330Sscottl sc->flags |= AAC_FLAGS_SG_64BIT; 1631151330Sscottl } 1632151330Sscottl if ((options & AAC_SUPPORTED_NEW_COMM) 1633151330Sscottl && sc->aac_if.aif_send_command) 1634151330Sscottl sc->flags |= AAC_FLAGS_NEW_COMM; 1635151330Sscottl if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1636151330Sscottl sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1637112679Sscottl } 1638112679Sscottl 1639112679Sscottl /* Check for broken hardware that does a lower number of commands */ 1640151086Sscottl sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1641151086Sscottl 1642151086Sscottl /* Remap mem. resource, if required */ 1643151086Sscottl if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1644151086Sscottl atu_size > rman_get_size(sc->aac_regs_resource)) { 1645151086Sscottl bus_release_resource( 1646151086Sscottl sc->aac_dev, SYS_RES_MEMORY, 1647151086Sscottl sc->aac_regs_rid, sc->aac_regs_resource); 1648151086Sscottl sc->aac_regs_resource = bus_alloc_resource( 1649151086Sscottl sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid, 1650151086Sscottl 0ul, ~0ul, atu_size, RF_ACTIVE); 1651151086Sscottl if (sc->aac_regs_resource == NULL) { 1652151086Sscottl sc->aac_regs_resource = bus_alloc_resource_any( 1653151086Sscottl sc->aac_dev, SYS_RES_MEMORY, 1654151086Sscottl &sc->aac_regs_rid, RF_ACTIVE); 1655151086Sscottl if (sc->aac_regs_resource == NULL) { 1656151086Sscottl device_printf(sc->aac_dev, 1657151109Sscottl "couldn't allocate register window\n"); 1658151086Sscottl return (ENXIO); 1659151086Sscottl } 1660151086Sscottl sc->flags &= ~AAC_FLAGS_NEW_COMM; 1661151086Sscottl } 1662151086Sscottl sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); 1663151086Sscottl sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); 1664151086Sscottl } 1665151086Sscottl 1666151086Sscottl /* Read preferred settings */ 1667151086Sscottl sc->aac_max_fib_size = sizeof(struct aac_fib); 1668151086Sscottl sc->aac_max_sectors = 128; /* 64KB */ 1669151086Sscottl if (sc->flags & AAC_FLAGS_SG_64BIT) 1670151330Sscottl sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1671151330Sscottl - sizeof(struct aac_blockwrite64) 1672151330Sscottl + sizeof(struct aac_sg_table64)) 1673151330Sscottl / sizeof(struct aac_sg_table64); 1674112679Sscottl else 1675151330Sscottl sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1676151330Sscottl - sizeof(struct aac_blockwrite) 1677151330Sscottl + sizeof(struct aac_sg_table)) 1678151330Sscottl / sizeof(struct aac_sg_table); 1679151330Sscottl 1680151086Sscottl if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 1681151086Sscottl options = AAC_GET_MAILBOX(sc, 1); 1682151086Sscottl sc->aac_max_fib_size = (options & 0xFFFF); 1683151086Sscottl sc->aac_max_sectors = (options >> 16) << 1; 1684151086Sscottl options = AAC_GET_MAILBOX(sc, 2); 1685151086Sscottl sc->aac_sg_tablesize = (options >> 16); 1686151086Sscottl options = AAC_GET_MAILBOX(sc, 3); 1687151086Sscottl sc->aac_max_fibs = (options & 0xFFFF); 1688151086Sscottl } 1689151086Sscottl if (sc->aac_max_fib_size > PAGE_SIZE) 1690151086Sscottl sc->aac_max_fib_size = PAGE_SIZE; 1691151086Sscottl sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1692151086Sscottl 169390275Sscottl return (0); 169490275Sscottl} 169590275Sscottl 169690275Sscottlstatic int 169765793Smsmithaac_init(struct aac_softc *sc) 169865793Smsmith{ 169983114Sscottl struct aac_adapter_init *ip; 170083114Sscottl time_t then; 1701119146Sscottl u_int32_t code, qoffset; 1702112679Sscottl int error; 170365793Smsmith 170483114Sscottl debug_called(1); 170565793Smsmith 170683114Sscottl /* 170783114Sscottl * First wait for the adapter to come ready. 170883114Sscottl */ 1709150119Sscottl then = time_uptime; 171083114Sscottl do { 171183114Sscottl code = AAC_GET_FWSTATUS(sc); 171283114Sscottl if (code & AAC_SELF_TEST_FAILED) { 171383114Sscottl device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 171483114Sscottl return(ENXIO); 171583114Sscottl } 171683114Sscottl if (code & AAC_KERNEL_PANIC) { 171783114Sscottl device_printf(sc->aac_dev, 171883114Sscottl "FATAL: controller kernel panic\n"); 171983114Sscottl return(ENXIO); 172083114Sscottl } 1721150119Sscottl if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 172283114Sscottl device_printf(sc->aac_dev, 172383114Sscottl "FATAL: controller not coming ready, " 172483114Sscottl "status %x\n", code); 172583114Sscottl return(ENXIO); 172683114Sscottl } 172783114Sscottl } while (!(code & AAC_UP_AND_RUNNING)); 172883114Sscottl 1729112679Sscottl error = ENOMEM; 173083114Sscottl /* 1731112679Sscottl * Create DMA tag for mapping buffers into controller-addressable space. 1732112679Sscottl */ 1733112679Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1734112679Sscottl 1, 0, /* algnmnt, boundary */ 1735112679Sscottl (sc->flags & AAC_FLAGS_SG_64BIT) ? 1736112679Sscottl BUS_SPACE_MAXADDR : 1737112679Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1738112679Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 1739112679Sscottl NULL, NULL, /* filter, filterarg */ 1740112679Sscottl MAXBSIZE, /* maxsize */ 1741151086Sscottl sc->aac_sg_tablesize, /* nsegments */ 1742112679Sscottl MAXBSIZE, /* maxsegsize */ 1743112679Sscottl BUS_DMA_ALLOCNOW, /* flags */ 1744117126Sscottl busdma_lock_mutex, /* lockfunc */ 1745117126Sscottl &sc->aac_io_lock, /* lockfuncarg */ 1746112679Sscottl &sc->aac_buffer_dmat)) { 1747112679Sscottl device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1748112679Sscottl goto out; 1749112679Sscottl } 1750112679Sscottl 1751112679Sscottl /* 1752112679Sscottl * Create DMA tag for mapping FIBs into controller-addressable space.. 1753112679Sscottl */ 1754112679Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1755112679Sscottl 1, 0, /* algnmnt, boundary */ 1756112679Sscottl (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1757112679Sscottl BUS_SPACE_MAXADDR_32BIT : 1758112679Sscottl 0x7fffffff, /* lowaddr */ 1759112679Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 1760112679Sscottl NULL, NULL, /* filter, filterarg */ 1761151086Sscottl sc->aac_max_fibs_alloc * 1762151086Sscottl sc->aac_max_fib_size, /* maxsize */ 1763112679Sscottl 1, /* nsegments */ 1764151086Sscottl sc->aac_max_fibs_alloc * 1765151086Sscottl sc->aac_max_fib_size, /* maxsegsize */ 1766137962Sscottl 0, /* flags */ 1767117126Sscottl NULL, NULL, /* No locking needed */ 1768112679Sscottl &sc->aac_fib_dmat)) { 1769112679Sscottl device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1770112679Sscottl goto out; 1771112679Sscottl } 1772112679Sscottl 1773112679Sscottl /* 177483114Sscottl * Create DMA tag for the common structure and allocate it. 177583114Sscottl */ 177683114Sscottl if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 177795536Sscottl 1, 0, /* algnmnt, boundary */ 1778112679Sscottl (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1779112679Sscottl BUS_SPACE_MAXADDR_32BIT : 1780112679Sscottl 0x7fffffff, /* lowaddr */ 178183114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 178283114Sscottl NULL, NULL, /* filter, filterarg */ 1783110604Sscottl 8192 + sizeof(struct aac_common), /* maxsize */ 178483114Sscottl 1, /* nsegments */ 178583114Sscottl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1786137962Sscottl 0, /* flags */ 1787117126Sscottl NULL, NULL, /* No locking needed */ 178883114Sscottl &sc->aac_common_dmat)) { 178983114Sscottl device_printf(sc->aac_dev, 179083114Sscottl "can't allocate common structure DMA tag\n"); 1791112679Sscottl goto out; 179265793Smsmith } 179383114Sscottl if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 179483114Sscottl BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 179583114Sscottl device_printf(sc->aac_dev, "can't allocate common structure\n"); 1796112679Sscottl goto out; 179765793Smsmith } 1798110604Sscottl 1799110604Sscottl /* 1800110604Sscottl * Work around a bug in the 2120 and 2200 that cannot DMA commands 1801110604Sscottl * below address 8192 in physical memory. 1802110604Sscottl * XXX If the padding is not needed, can it be put to use instead 1803110604Sscottl * of ignored? 1804110604Sscottl */ 1805117363Sscottl (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1806110604Sscottl sc->aac_common, 8192 + sizeof(*sc->aac_common), 1807110604Sscottl aac_common_map, sc, 0); 1808110604Sscottl 1809110604Sscottl if (sc->aac_common_busaddr < 8192) { 1810132771Skan sc->aac_common = (struct aac_common *) 1811132771Skan ((uint8_t *)sc->aac_common + 8192); 1812110604Sscottl sc->aac_common_busaddr += 8192; 1813110604Sscottl } 181483114Sscottl bzero(sc->aac_common, sizeof(*sc->aac_common)); 1815110604Sscottl 1816110604Sscottl /* Allocate some FIBs and associated command structs */ 1817110604Sscottl TAILQ_INIT(&sc->aac_fibmap_tqh); 1818151086Sscottl sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 1819111141Sscottl M_AACBUF, M_WAITOK|M_ZERO); 1820111141Sscottl while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1821110604Sscottl if (aac_alloc_commands(sc) != 0) 1822110604Sscottl break; 1823110604Sscottl } 1824110604Sscottl if (sc->total_fibs == 0) 1825112679Sscottl goto out; 182683114Sscottl 182783114Sscottl /* 182883114Sscottl * Fill in the init structure. This tells the adapter about the 182983114Sscottl * physical location of various important shared data structures. 183083114Sscottl */ 183183114Sscottl ip = &sc->aac_common->ac_init; 183283114Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1833151086Sscottl if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1834151086Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1835151086Sscottl sc->flags |= AAC_FLAGS_RAW_IO; 1836151086Sscottl } 1837109088Sscottl ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 183865793Smsmith 183983114Sscottl ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 184083114Sscottl offsetof(struct aac_common, ac_fibs); 1841114151Sscottl ip->AdapterFibsVirtualAddress = 0; 184283114Sscottl ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 184383114Sscottl ip->AdapterFibAlign = sizeof(struct aac_fib); 184465793Smsmith 184583114Sscottl ip->PrintfBufferAddress = sc->aac_common_busaddr + 184683114Sscottl offsetof(struct aac_common, ac_printf); 184783114Sscottl ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 184865793Smsmith 1849117361Sscottl /* 1850117361Sscottl * The adapter assumes that pages are 4K in size, except on some 1851117361Sscottl * broken firmware versions that do the page->byte conversion twice, 1852117361Sscottl * therefore 'assuming' that this value is in 16MB units (2^24). 1853117361Sscottl * Round up since the granularity is so high. 1854117361Sscottl */ 1855109088Sscottl ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1856117361Sscottl if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1857117361Sscottl ip->HostPhysMemPages = 1858117361Sscottl (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1859117362Sscottl } 1860150119Sscottl ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 186165793Smsmith 1862151086Sscottl ip->InitFlags = 0; 1863151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) { 1864151086Sscottl ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 1865151086Sscottl device_printf(sc->aac_dev, "New comm. interface enabled\n"); 1866151086Sscottl } 1867151086Sscottl 1868151086Sscottl ip->MaxIoCommands = sc->aac_max_fibs; 1869151086Sscottl ip->MaxIoSize = sc->aac_max_sectors << 9; 1870151086Sscottl ip->MaxFibSize = sc->aac_max_fib_size; 1871151086Sscottl 187283114Sscottl /* 187383114Sscottl * Initialise FIB queues. Note that it appears that the layout of the 187483114Sscottl * indexes and the segmentation of the entries may be mandated by the 187583114Sscottl * adapter, which is only told about the base of the queue index fields. 187683114Sscottl * 187783114Sscottl * The initial values of the indices are assumed to inform the adapter 187883114Sscottl * of the sizes of the respective queues, and theoretically it could 187983114Sscottl * work out the entire layout of the queue structures from this. We 188083114Sscottl * take the easy route and just lay this area out like everyone else 188183114Sscottl * does. 188283114Sscottl * 188383114Sscottl * The Linux driver uses a much more complex scheme whereby several 188483114Sscottl * header records are kept for each queue. We use a couple of generic 188583114Sscottl * list manipulation functions which 'know' the size of each list by 188683114Sscottl * virtue of a table. 188783114Sscottl */ 1888119146Sscottl qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 1889119625Sscottl qoffset &= ~(AAC_QUEUE_ALIGN - 1); 1890119625Sscottl sc->aac_queues = 1891119625Sscottl (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1892119146Sscottl ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 189365793Smsmith 189483114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 189581082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 189683114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 189781082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 189883114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 189981082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 190083114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 190181082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 190283114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 190381082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 190483114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 190581082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 190683114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 190781082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 190883114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 190981082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 191083114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 191181082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 191283114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 191381082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 191483114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 191581082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 191683114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 191781082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 191883114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 191981082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 192083114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 192181082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 192283114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 192381082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 192483114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 192581082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 192683114Sscottl sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 192781082Sscottl &sc->aac_queues->qt_HostNormCmdQueue[0]; 192883114Sscottl sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 192981082Sscottl &sc->aac_queues->qt_HostHighCmdQueue[0]; 193083114Sscottl sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 193181082Sscottl &sc->aac_queues->qt_AdapNormCmdQueue[0]; 193283114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 193381082Sscottl &sc->aac_queues->qt_AdapHighCmdQueue[0]; 193483114Sscottl sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 193581082Sscottl &sc->aac_queues->qt_HostNormRespQueue[0]; 193683114Sscottl sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 193781082Sscottl &sc->aac_queues->qt_HostHighRespQueue[0]; 193883114Sscottl sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 193981082Sscottl &sc->aac_queues->qt_AdapNormRespQueue[0]; 194083114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 194181082Sscottl &sc->aac_queues->qt_AdapHighRespQueue[0]; 194265793Smsmith 194383114Sscottl /* 194483114Sscottl * Do controller-type-specific initialisation 194583114Sscottl */ 194683114Sscottl switch (sc->aac_hwif) { 194783114Sscottl case AAC_HWIF_I960RX: 194883114Sscottl AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 194983114Sscottl break; 1950133606Sscottl case AAC_HWIF_RKT: 1951133606Sscottl AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); 1952133606Sscottl break; 1953133606Sscottl default: 1954133606Sscottl break; 195583114Sscottl } 195665793Smsmith 195783114Sscottl /* 195883114Sscottl * Give the init structure to the controller. 195983114Sscottl */ 196083114Sscottl if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 196183114Sscottl sc->aac_common_busaddr + 196283114Sscottl offsetof(struct aac_common, ac_init), 0, 0, 0, 196383114Sscottl NULL)) { 196483114Sscottl device_printf(sc->aac_dev, 196583114Sscottl "error establishing init structure\n"); 1966112679Sscottl error = EIO; 1967112679Sscottl goto out; 196883114Sscottl } 196965793Smsmith 1970112679Sscottl error = 0; 1971112679Sscottlout: 1972112679Sscottl return(error); 197365793Smsmith} 197465793Smsmith 197583114Sscottl/* 197665793Smsmith * Send a synchronous command to the controller and wait for a result. 1977151086Sscottl * Indicate if the controller completed the command with an error status. 197865793Smsmith */ 197965793Smsmithstatic int 198065793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command, 198170393Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 198270393Smsmith u_int32_t *sp) 198365793Smsmith{ 198483114Sscottl time_t then; 198583114Sscottl u_int32_t status; 198665793Smsmith 198783114Sscottl debug_called(3); 198865793Smsmith 198983114Sscottl /* populate the mailbox */ 199083114Sscottl AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 199165793Smsmith 199283114Sscottl /* ensure the sync command doorbell flag is cleared */ 199383114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 199465793Smsmith 199583114Sscottl /* then set it to signal the adapter */ 199683114Sscottl AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 199765793Smsmith 199883114Sscottl /* spin waiting for the command to complete */ 1999150119Sscottl then = time_uptime; 200083114Sscottl do { 2001150119Sscottl if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 2002112679Sscottl debug(1, "timed out"); 200383114Sscottl return(EIO); 200483114Sscottl } 200583114Sscottl } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 200665793Smsmith 200783114Sscottl /* clear the completion flag */ 200883114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 200965793Smsmith 201083114Sscottl /* get the command status */ 2011112679Sscottl status = AAC_GET_MAILBOX(sc, 0); 201283114Sscottl if (sp != NULL) 201383114Sscottl *sp = status; 2014151086Sscottl 2015151330Sscottl if (status != AAC_SRB_STS_SUCCESS) 2016151086Sscottl return (-1); 201783114Sscottl return(0); 201865793Smsmith} 201965793Smsmith 202095350Sscottlint 202165793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 202295350Sscottl struct aac_fib *fib, u_int16_t datasize) 202365793Smsmith{ 202483114Sscottl debug_called(3); 2025151086Sscottl mtx_assert(&sc->aac_io_lock, MA_OWNED); 202665793Smsmith 202783114Sscottl if (datasize > AAC_FIB_DATASIZE) 202883114Sscottl return(EINVAL); 202965793Smsmith 203083114Sscottl /* 203183114Sscottl * Set up the sync FIB 203283114Sscottl */ 203383114Sscottl fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 203483114Sscottl AAC_FIBSTATE_INITIALISED | 203583114Sscottl AAC_FIBSTATE_EMPTY; 203683114Sscottl fib->Header.XferState |= xferstate; 203783114Sscottl fib->Header.Command = command; 203883114Sscottl fib->Header.StructType = AAC_FIBTYPE_TFIB; 203983114Sscottl fib->Header.Size = sizeof(struct aac_fib) + datasize; 204083114Sscottl fib->Header.SenderSize = sizeof(struct aac_fib); 2041119146Sscottl fib->Header.SenderFibAddress = 0; /* Not needed */ 204283114Sscottl fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 204383114Sscottl offsetof(struct aac_common, 204483114Sscottl ac_sync_fib); 204565793Smsmith 204683114Sscottl /* 204783114Sscottl * Give the FIB to the controller, wait for a response. 204883114Sscottl */ 204983114Sscottl if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 205083114Sscottl fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 205183114Sscottl debug(2, "IO error"); 205283114Sscottl return(EIO); 205383114Sscottl } 205481151Sscottl 205595350Sscottl return (0); 205665793Smsmith} 205765793Smsmith 205883114Sscottl/* 205965793Smsmith * Adapter-space FIB queue manipulation 206065793Smsmith * 206165793Smsmith * Note that the queue implementation here is a little funky; neither the PI or 206265793Smsmith * CI will ever be zero. This behaviour is a controller feature. 206365793Smsmith */ 206465793Smsmithstatic struct { 206583114Sscottl int size; 206683114Sscottl int notify; 206765793Smsmith} aac_qinfo[] = { 206883114Sscottl {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 206983114Sscottl {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 207083114Sscottl {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 207183114Sscottl {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 207283114Sscottl {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 207383114Sscottl {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 207483114Sscottl {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 207583114Sscottl {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 207665793Smsmith}; 207765793Smsmith 207865793Smsmith/* 207981082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or 208081082Sscottl * EBUSY if the queue is full. 208165793Smsmith * 208270393Smsmith * Note: it would be more efficient to defer notifying the controller in 208383114Sscottl * the case where we may be inserting several entries in rapid succession, 208483114Sscottl * but implementing this usefully may be difficult (it would involve a 208583114Sscottl * separate queue/notify interface). 208665793Smsmith */ 208765793Smsmithstatic int 208881151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 208965793Smsmith{ 209083114Sscottl u_int32_t pi, ci; 2091111691Sscottl int error; 209283114Sscottl u_int32_t fib_size; 209383114Sscottl u_int32_t fib_addr; 209465793Smsmith 209583114Sscottl debug_called(3); 209682527Sscottl 209783114Sscottl fib_size = cm->cm_fib->Header.Size; 209883114Sscottl fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 209981151Sscottl 210083114Sscottl /* get the producer/consumer indices */ 210183114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 210283114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 210365793Smsmith 210483114Sscottl /* wrap the queue? */ 210583114Sscottl if (pi >= aac_qinfo[queue].size) 210683114Sscottl pi = 0; 210765793Smsmith 210883114Sscottl /* check for queue full */ 210983114Sscottl if ((pi + 1) == ci) { 211083114Sscottl error = EBUSY; 211183114Sscottl goto out; 211283114Sscottl } 211365793Smsmith 2114129946Sscottl /* 2115129946Sscottl * To avoid a race with its completion interrupt, place this command on 2116129946Sscottl * the busy queue prior to advertising it to the controller. 2117129946Sscottl */ 2118129946Sscottl aac_enqueue_busy(cm); 2119129946Sscottl 212083114Sscottl /* populate queue entry */ 212183114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 212283114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 212365793Smsmith 212483114Sscottl /* update producer index */ 212583114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 212665793Smsmith 212783114Sscottl /* notify the adapter if we know how */ 212883114Sscottl if (aac_qinfo[queue].notify != 0) 212983114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 213065793Smsmith 213183114Sscottl error = 0; 213265793Smsmith 213365793Smsmithout: 213483114Sscottl return(error); 213565793Smsmith} 213665793Smsmith 213765793Smsmith/* 213882527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on 213982527Sscottl * success or ENOENT if the queue is empty. 214065793Smsmith */ 214165793Smsmithstatic int 214281082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 214381082Sscottl struct aac_fib **fib_addr) 214465793Smsmith{ 214583114Sscottl u_int32_t pi, ci; 2146114151Sscottl u_int32_t fib_index; 2147111691Sscottl int error; 214883114Sscottl int notify; 214965793Smsmith 215083114Sscottl debug_called(3); 215165793Smsmith 215283114Sscottl /* get the producer/consumer indices */ 215383114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215483114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215565793Smsmith 215683114Sscottl /* check for queue empty */ 215783114Sscottl if (ci == pi) { 215883114Sscottl error = ENOENT; 215983114Sscottl goto out; 216083114Sscottl } 2161120129Sscottl 2162120129Sscottl /* wrap the pi so the following test works */ 2163120129Sscottl if (pi >= aac_qinfo[queue].size) 2164120129Sscottl pi = 0; 2165120129Sscottl 216683114Sscottl notify = 0; 216783114Sscottl if (ci == pi + 1) 216883114Sscottl notify++; 216981151Sscottl 217083114Sscottl /* wrap the queue? */ 217183114Sscottl if (ci >= aac_qinfo[queue].size) 217283114Sscottl ci = 0; 217365793Smsmith 217483114Sscottl /* fetch the entry */ 217583114Sscottl *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 217665793Smsmith 2177114151Sscottl switch (queue) { 2178114151Sscottl case AAC_HOST_NORM_CMD_QUEUE: 2179114151Sscottl case AAC_HOST_HIGH_CMD_QUEUE: 2180114151Sscottl /* 2181114151Sscottl * The aq_fib_addr is only 32 bits wide so it can't be counted 2182114151Sscottl * on to hold an address. For AIF's, the adapter assumes 2183114151Sscottl * that it's giving us an address into the array of AIF fibs. 2184114151Sscottl * Therefore, we have to convert it to an index. 2185114151Sscottl */ 2186114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2187114151Sscottl sizeof(struct aac_fib); 2188114151Sscottl *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2189114151Sscottl break; 2190114151Sscottl 2191114151Sscottl case AAC_HOST_NORM_RESP_QUEUE: 2192114151Sscottl case AAC_HOST_HIGH_RESP_QUEUE: 2193114151Sscottl { 2194114151Sscottl struct aac_command *cm; 2195114151Sscottl 2196114151Sscottl /* 2197114151Sscottl * As above, an index is used instead of an actual address. 2198114151Sscottl * Gotta shift the index to account for the fast response 2199114151Sscottl * bit. No other correction is needed since this value was 2200114151Sscottl * originally provided by the driver via the SenderFibAddress 2201114151Sscottl * field. 2202114151Sscottl */ 2203114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 2204151086Sscottl cm = sc->aac_commands + (fib_index >> 2); 2205114151Sscottl *fib_addr = cm->cm_fib; 2206114151Sscottl 2207114151Sscottl /* 2208114151Sscottl * Is this a fast response? If it is, update the fib fields in 2209114151Sscottl * local memory since the whole fib isn't DMA'd back up. 2210114151Sscottl */ 2211114151Sscottl if (fib_index & 0x01) { 2212114151Sscottl (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2213114151Sscottl *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2214114151Sscottl } 2215114151Sscottl break; 2216109088Sscottl } 2217114151Sscottl default: 2218114151Sscottl panic("Invalid queue in aac_dequeue_fib()"); 2219114151Sscottl break; 2220114151Sscottl } 2221114151Sscottl 222283114Sscottl /* update consumer index */ 222383114Sscottl sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 222465793Smsmith 222583114Sscottl /* if we have made the queue un-full, notify the adapter */ 222683114Sscottl if (notify && (aac_qinfo[queue].notify != 0)) 222783114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 222883114Sscottl error = 0; 222965793Smsmith 223065793Smsmithout: 223183114Sscottl return(error); 223265793Smsmith} 223365793Smsmith 223483114Sscottl/* 223582527Sscottl * Put our response to an Adapter Initialed Fib on the response queue 223682527Sscottl */ 223782527Sscottlstatic int 223882527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 223982527Sscottl{ 224083114Sscottl u_int32_t pi, ci; 2241111691Sscottl int error; 224283114Sscottl u_int32_t fib_size; 224383114Sscottl u_int32_t fib_addr; 224482527Sscottl 224583114Sscottl debug_called(1); 224682527Sscottl 224783114Sscottl /* Tell the adapter where the FIB is */ 224883114Sscottl fib_size = fib->Header.Size; 224983114Sscottl fib_addr = fib->Header.SenderFibAddress; 225083114Sscottl fib->Header.ReceiverFibAddress = fib_addr; 225182527Sscottl 225283114Sscottl /* get the producer/consumer indices */ 225383114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 225483114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 225582527Sscottl 225683114Sscottl /* wrap the queue? */ 225783114Sscottl if (pi >= aac_qinfo[queue].size) 225883114Sscottl pi = 0; 225982527Sscottl 226083114Sscottl /* check for queue full */ 226183114Sscottl if ((pi + 1) == ci) { 226283114Sscottl error = EBUSY; 226383114Sscottl goto out; 226483114Sscottl } 226582527Sscottl 226683114Sscottl /* populate queue entry */ 226783114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 226883114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 226982527Sscottl 227083114Sscottl /* update producer index */ 227183114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 227282527Sscottl 227383114Sscottl /* notify the adapter if we know how */ 227483114Sscottl if (aac_qinfo[queue].notify != 0) 227583114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227682527Sscottl 227783114Sscottl error = 0; 227882527Sscottl 227982527Sscottlout: 228083114Sscottl return(error); 228182527Sscottl} 228282527Sscottl 228383114Sscottl/* 228470393Smsmith * Check for commands that have been outstanding for a suspiciously long time, 228570393Smsmith * and complain about them. 228670393Smsmith */ 228770393Smsmithstatic void 228870393Smsmithaac_timeout(struct aac_softc *sc) 228970393Smsmith{ 229083114Sscottl struct aac_command *cm; 229183114Sscottl time_t deadline; 2292135289Sscottl int timedout, code; 229370393Smsmith 229483114Sscottl /* 2295110426Sscottl * Traverse the busy command list, bitch about late commands once 229683114Sscottl * only. 229783114Sscottl */ 2298135289Sscottl timedout = 0; 2299150119Sscottl deadline = time_uptime - AAC_CMD_TIMEOUT; 230083114Sscottl TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 230183114Sscottl if ((cm->cm_timestamp < deadline) 230283114Sscottl /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 230383114Sscottl cm->cm_flags |= AAC_CMD_TIMEDOUT; 230483114Sscottl device_printf(sc->aac_dev, 230583114Sscottl "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2306150119Sscottl cm, (int)(time_uptime-cm->cm_timestamp)); 230783114Sscottl AAC_PRINT_FIB(sc, cm->cm_fib); 2308135289Sscottl timedout++; 230983114Sscottl } 231070393Smsmith } 231170393Smsmith 2312135289Sscottl if (timedout) { 2313135289Sscottl code = AAC_GET_FWSTATUS(sc); 2314135289Sscottl if (code != AAC_UP_AND_RUNNING) { 2315135289Sscottl device_printf(sc->aac_dev, "WARNING! Controller is no " 2316135289Sscottl "longer running! code= 0x%x\n", code); 2317135289Sscottl } 2318135289Sscottl } 231983114Sscottl return; 232070393Smsmith} 232170393Smsmith 232283114Sscottl/* 232383114Sscottl * Interface Function Vectors 232483114Sscottl */ 232565793Smsmith 232683114Sscottl/* 232765793Smsmith * Read the current firmware status word. 232865793Smsmith */ 232965793Smsmithstatic int 233065793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc) 233165793Smsmith{ 233283114Sscottl debug_called(3); 233365793Smsmith 233483114Sscottl return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 233565793Smsmith} 233665793Smsmith 233765793Smsmithstatic int 233865793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc) 233965793Smsmith{ 234083114Sscottl debug_called(3); 234165793Smsmith 234283114Sscottl return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 234365793Smsmith} 234465793Smsmith 234587183Sscottlstatic int 234687183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc) 234787183Sscottl{ 234887183Sscottl int val; 234987183Sscottl 235087183Sscottl debug_called(3); 235187183Sscottl 235287183Sscottl val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 235387183Sscottl return (val); 235487183Sscottl} 235587183Sscottl 2356133606Sscottlstatic int 2357133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc) 2358133606Sscottl{ 2359133606Sscottl debug_called(3); 2360133606Sscottl 2361133606Sscottl return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); 2362133606Sscottl} 2363133606Sscottl 236483114Sscottl/* 236565793Smsmith * Notify the controller of a change in a given queue 236665793Smsmith */ 236765793Smsmith 236865793Smsmithstatic void 236965793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit) 237065793Smsmith{ 237183114Sscottl debug_called(3); 237265793Smsmith 237383114Sscottl AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 237465793Smsmith} 237565793Smsmith 237665793Smsmithstatic void 237765793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit) 237865793Smsmith{ 237983114Sscottl debug_called(3); 238065793Smsmith 238183114Sscottl AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 238265793Smsmith} 238365793Smsmith 238487183Sscottlstatic void 238587183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit) 238687183Sscottl{ 238787183Sscottl debug_called(3); 238887183Sscottl 238987183Sscottl AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 239087183Sscottl AAC_FA_HACK(sc); 239187183Sscottl} 239287183Sscottl 2393133606Sscottlstatic void 2394133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit) 2395133606Sscottl{ 2396133606Sscottl debug_called(3); 2397133606Sscottl 2398133606Sscottl AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); 2399133606Sscottl} 2400133606Sscottl 240183114Sscottl/* 240265793Smsmith * Get the interrupt reason bits 240365793Smsmith */ 240465793Smsmithstatic int 240565793Smsmithaac_sa_get_istatus(struct aac_softc *sc) 240665793Smsmith{ 240783114Sscottl debug_called(3); 240865793Smsmith 240983114Sscottl return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 241065793Smsmith} 241165793Smsmith 241265793Smsmithstatic int 241365793Smsmithaac_rx_get_istatus(struct aac_softc *sc) 241465793Smsmith{ 241583114Sscottl debug_called(3); 241665793Smsmith 241783114Sscottl return(AAC_GETREG4(sc, AAC_RX_ODBR)); 241865793Smsmith} 241965793Smsmith 242087183Sscottlstatic int 242187183Sscottlaac_fa_get_istatus(struct aac_softc *sc) 242287183Sscottl{ 242387183Sscottl int val; 242487183Sscottl 242587183Sscottl debug_called(3); 242687183Sscottl 242787183Sscottl val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 242887183Sscottl return (val); 242987183Sscottl} 243087183Sscottl 2431133606Sscottlstatic int 2432133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc) 2433133606Sscottl{ 2434133606Sscottl debug_called(3); 2435133606Sscottl 2436133606Sscottl return(AAC_GETREG4(sc, AAC_RKT_ODBR)); 2437133606Sscottl} 2438133606Sscottl 243983114Sscottl/* 244065793Smsmith * Clear some interrupt reason bits 244165793Smsmith */ 244265793Smsmithstatic void 244365793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask) 244465793Smsmith{ 244583114Sscottl debug_called(3); 244665793Smsmith 244783114Sscottl AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 244865793Smsmith} 244965793Smsmith 245065793Smsmithstatic void 245165793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask) 245265793Smsmith{ 245383114Sscottl debug_called(3); 245465793Smsmith 245583114Sscottl AAC_SETREG4(sc, AAC_RX_ODBR, mask); 245665793Smsmith} 245765793Smsmith 245887183Sscottlstatic void 245987183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask) 246087183Sscottl{ 246187183Sscottl debug_called(3); 246287183Sscottl 246387183Sscottl AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 246487183Sscottl AAC_FA_HACK(sc); 246587183Sscottl} 246687183Sscottl 2467133606Sscottlstatic void 2468133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask) 2469133606Sscottl{ 2470133606Sscottl debug_called(3); 2471133606Sscottl 2472133606Sscottl AAC_SETREG4(sc, AAC_RKT_ODBR, mask); 2473133606Sscottl} 2474133606Sscottl 247583114Sscottl/* 247665793Smsmith * Populate the mailbox and set the command word 247765793Smsmith */ 247865793Smsmithstatic void 247965793Smsmithaac_sa_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_SA_MAILBOX, command); 248583114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 248683114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 248783114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 248883114Sscottl AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 248965793Smsmith} 249065793Smsmith 249165793Smsmithstatic void 249265793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 249365793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249465793Smsmith{ 249583114Sscottl debug_called(4); 249665793Smsmith 249783114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 249883114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 249983114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 250083114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 250183114Sscottl AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 250265793Smsmith} 250365793Smsmith 250487183Sscottlstatic void 250587183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 250687183Sscottl u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 250787183Sscottl{ 250887183Sscottl debug_called(4); 250987183Sscottl 251087183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 251187183Sscottl AAC_FA_HACK(sc); 251287183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 251387183Sscottl AAC_FA_HACK(sc); 251487183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 251587183Sscottl AAC_FA_HACK(sc); 251687183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 251787183Sscottl AAC_FA_HACK(sc); 251887183Sscottl AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 251987183Sscottl AAC_FA_HACK(sc); 252087183Sscottl} 252187183Sscottl 2522133606Sscottlstatic void 2523133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2524133606Sscottl u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2525133606Sscottl{ 2526133606Sscottl debug_called(4); 2527133606Sscottl 2528133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); 2529133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2530133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2531133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2532133606Sscottl AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 2533133606Sscottl} 2534133606Sscottl 253583114Sscottl/* 253665793Smsmith * Fetch the immediate command status word 253765793Smsmith */ 253865793Smsmithstatic int 2539112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb) 254065793Smsmith{ 254183114Sscottl debug_called(4); 254265793Smsmith 2543112679Sscottl return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 254465793Smsmith} 254565793Smsmith 254665793Smsmithstatic int 2547112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb) 254865793Smsmith{ 254983114Sscottl debug_called(4); 255065793Smsmith 2551112679Sscottl return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 255265793Smsmith} 255365793Smsmith 255487183Sscottlstatic int 2555112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb) 255687183Sscottl{ 255787183Sscottl int val; 255887183Sscottl 255987183Sscottl debug_called(4); 256087183Sscottl 2561112679Sscottl val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 256287183Sscottl return (val); 256387183Sscottl} 256487183Sscottl 2565133606Sscottlstatic int 2566133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb) 2567133606Sscottl{ 2568133606Sscottl debug_called(4); 2569133606Sscottl 2570133606Sscottl return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 2571133606Sscottl} 2572133606Sscottl 257383114Sscottl/* 257465793Smsmith * Set/clear interrupt masks 257565793Smsmith */ 257665793Smsmithstatic void 257765793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable) 257865793Smsmith{ 257983114Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 258065793Smsmith 258183114Sscottl if (enable) { 258283114Sscottl AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 258383114Sscottl } else { 258483114Sscottl AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 258583114Sscottl } 258665793Smsmith} 258765793Smsmith 258865793Smsmithstatic void 258965793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable) 259065793Smsmith{ 259183114Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 259265793Smsmith 259383114Sscottl if (enable) { 2594151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 2595151086Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 2596151086Sscottl else 2597151086Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 259883114Sscottl } else { 259983114Sscottl AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 260083114Sscottl } 260165793Smsmith} 260265793Smsmith 260387183Sscottlstatic void 260487183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable) 260587183Sscottl{ 260687183Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 260787183Sscottl 260887183Sscottl if (enable) { 260987183Sscottl AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 261087183Sscottl AAC_FA_HACK(sc); 261187183Sscottl } else { 261287183Sscottl AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 261387183Sscottl AAC_FA_HACK(sc); 261487183Sscottl } 261587183Sscottl} 261687183Sscottl 2617133606Sscottlstatic void 2618133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable) 2619133606Sscottl{ 2620133606Sscottl debug(2, "%sable interrupts", enable ? "en" : "dis"); 2621133606Sscottl 2622133606Sscottl if (enable) { 2623151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 2624151086Sscottl AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 2625151086Sscottl else 2626151086Sscottl AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 2627133606Sscottl } else { 2628133606Sscottl AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); 2629133606Sscottl } 2630133606Sscottl} 2631133606Sscottl 263283114Sscottl/* 2633151086Sscottl * New comm. interface: Send command functions 2634151086Sscottl */ 2635151086Sscottlstatic int 2636151086Sscottlaac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 2637151086Sscottl{ 2638151086Sscottl u_int32_t index, device; 2639151086Sscottl 2640151086Sscottl debug(2, "send command (new comm.)"); 2641151086Sscottl 2642151086Sscottl index = AAC_GETREG4(sc, AAC_RX_IQUE); 2643151086Sscottl if (index == 0xffffffffL) 2644151086Sscottl index = AAC_GETREG4(sc, AAC_RX_IQUE); 2645151086Sscottl if (index == 0xffffffffL) 2646151086Sscottl return index; 2647151086Sscottl aac_enqueue_busy(cm); 2648151086Sscottl device = index; 2649151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2650151086Sscottl device += 4; 2651151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2652151086Sscottl device += 4; 2653151086Sscottl AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 2654151086Sscottl AAC_SETREG4(sc, AAC_RX_IQUE, index); 2655151086Sscottl return 0; 2656151086Sscottl} 2657151086Sscottl 2658151086Sscottlstatic int 2659151086Sscottlaac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 2660151086Sscottl{ 2661151086Sscottl u_int32_t index, device; 2662151086Sscottl 2663151086Sscottl debug(2, "send command (new comm.)"); 2664151086Sscottl 2665151086Sscottl index = AAC_GETREG4(sc, AAC_RKT_IQUE); 2666151086Sscottl if (index == 0xffffffffL) 2667151086Sscottl index = AAC_GETREG4(sc, AAC_RKT_IQUE); 2668151086Sscottl if (index == 0xffffffffL) 2669151086Sscottl return index; 2670151086Sscottl aac_enqueue_busy(cm); 2671151086Sscottl device = index; 2672151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2673151086Sscottl device += 4; 2674151086Sscottl AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2675151086Sscottl device += 4; 2676151086Sscottl AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 2677151086Sscottl AAC_SETREG4(sc, AAC_RKT_IQUE, index); 2678151086Sscottl return 0; 2679151086Sscottl} 2680151086Sscottl 2681151086Sscottl/* 2682151086Sscottl * New comm. interface: get, set outbound queue index 2683151086Sscottl */ 2684151086Sscottlstatic int 2685151086Sscottlaac_rx_get_outb_queue(struct aac_softc *sc) 2686151086Sscottl{ 2687151086Sscottl debug_called(3); 2688151086Sscottl 2689151086Sscottl return(AAC_GETREG4(sc, AAC_RX_OQUE)); 2690151086Sscottl} 2691151086Sscottl 2692151086Sscottlstatic int 2693151086Sscottlaac_rkt_get_outb_queue(struct aac_softc *sc) 2694151086Sscottl{ 2695151086Sscottl debug_called(3); 2696151086Sscottl 2697151086Sscottl return(AAC_GETREG4(sc, AAC_RKT_OQUE)); 2698151086Sscottl} 2699151086Sscottl 2700151086Sscottlstatic void 2701151086Sscottlaac_rx_set_outb_queue(struct aac_softc *sc, int index) 2702151086Sscottl{ 2703151086Sscottl debug_called(3); 2704151086Sscottl 2705151086Sscottl AAC_SETREG4(sc, AAC_RX_OQUE, index); 2706151086Sscottl} 2707151086Sscottl 2708151086Sscottlstatic void 2709151086Sscottlaac_rkt_set_outb_queue(struct aac_softc *sc, int index) 2710151086Sscottl{ 2711151086Sscottl debug_called(3); 2712151086Sscottl 2713151086Sscottl AAC_SETREG4(sc, AAC_RKT_OQUE, index); 2714151086Sscottl} 2715151086Sscottl 2716151086Sscottl/* 271783114Sscottl * Debugging and Diagnostics 271883114Sscottl */ 271965793Smsmith 272083114Sscottl/* 272165793Smsmith * Print some information about the controller. 272265793Smsmith */ 272365793Smsmithstatic void 272465793Smsmithaac_describe_controller(struct aac_softc *sc) 272565793Smsmith{ 272695350Sscottl struct aac_fib *fib; 272783114Sscottl struct aac_adapter_info *info; 272865793Smsmith 272983114Sscottl debug_called(2); 273065793Smsmith 2731151222Sscottl mtx_lock(&sc->aac_io_lock); 2732130006Sscottl aac_alloc_sync_fib(sc, &fib); 273395350Sscottl 273495350Sscottl fib->data[0] = 0; 273595350Sscottl if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 273683114Sscottl device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 273795536Sscottl aac_release_sync_fib(sc); 2738151222Sscottl mtx_unlock(&sc->aac_io_lock); 273983114Sscottl return; 274083114Sscottl } 274165793Smsmith 274283114Sscottl /* save the kernel revision structure for later use */ 2743135095Sscottl info = (struct aac_adapter_info *)&fib->data[0]; 274483114Sscottl sc->aac_revision = info->KernelRevision; 274595536Sscottl 2746151086Sscottl device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n", 2747151086Sscottl AAC_DRIVER_VERSION >> 24, 2748151086Sscottl (AAC_DRIVER_VERSION >> 16) & 0xFF, 2749151086Sscottl AAC_DRIVER_VERSION & 0xFF, 2750151086Sscottl AAC_DRIVER_BUILD); 2751151086Sscottl 2752135095Sscottl if (bootverbose) { 2753146851Sscottl device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2754146851Sscottl "(%dMB cache, %dMB execution), %s\n", 2755135095Sscottl aac_describe_code(aac_cpu_variant, info->CpuVariant), 2756146851Sscottl info->ClockSpeed, info->TotalMem / (1024 * 1024), 2757146851Sscottl info->BufferMem / (1024 * 1024), 2758146851Sscottl info->ExecutionMem / (1024 * 1024), 2759135095Sscottl aac_describe_code(aac_battery_platform, 2760135095Sscottl info->batteryPlatform)); 2761112679Sscottl 2762135095Sscottl device_printf(sc->aac_dev, 2763135095Sscottl "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2764135095Sscottl info->KernelRevision.external.comp.major, 2765135095Sscottl info->KernelRevision.external.comp.minor, 2766135095Sscottl info->KernelRevision.external.comp.dash, 2767135095Sscottl info->KernelRevision.buildNumber, 2768135095Sscottl (u_int32_t)(info->SerialNumber & 0xffffff)); 2769135095Sscottl 2770112679Sscottl device_printf(sc->aac_dev, "Supported Options=%b\n", 2771112679Sscottl sc->supported_options, 2772112679Sscottl "\20" 2773112679Sscottl "\1SNAPSHOT" 2774112679Sscottl "\2CLUSTERS" 2775112679Sscottl "\3WCACHE" 2776112679Sscottl "\4DATA64" 2777112679Sscottl "\5HOSTTIME" 2778112679Sscottl "\6RAID50" 2779112679Sscottl "\7WINDOW4GB" 2780112679Sscottl "\10SCSIUPGD" 2781112679Sscottl "\11SOFTERR" 2782112679Sscottl "\12NORECOND" 2783112679Sscottl "\13SGMAP64" 2784112679Sscottl "\14ALARM" 2785151086Sscottl "\15NONDASD" 2786151086Sscottl "\16SCSIMGT" 2787151086Sscottl "\17RAIDSCSI" 2788151086Sscottl "\21ADPTINFO" 2789151086Sscottl "\22NEWCOMM" 2790151086Sscottl "\23ARRAY64BIT" 2791151086Sscottl "\24HEATSENSOR"); 2792112679Sscottl } 2793135095Sscottl aac_release_sync_fib(sc); 2794151222Sscottl mtx_unlock(&sc->aac_io_lock); 279565793Smsmith} 279665793Smsmith 279783114Sscottl/* 279865793Smsmith * Look up a text description of a numeric error code and return a pointer to 279965793Smsmith * same. 280065793Smsmith */ 280165793Smsmithstatic char * 280265793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code) 280365793Smsmith{ 280483114Sscottl int i; 280565793Smsmith 280683114Sscottl for (i = 0; table[i].string != NULL; i++) 280783114Sscottl if (table[i].code == code) 280883114Sscottl return(table[i].string); 280983114Sscottl return(table[i + 1].string); 281065793Smsmith} 281165793Smsmith 281283114Sscottl/* 281383114Sscottl * Management Interface 281483114Sscottl */ 281565793Smsmith 281665793Smsmithstatic int 2817130585Sphkaac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 281865793Smsmith{ 281983114Sscottl struct aac_softc *sc; 282065793Smsmith 282183114Sscottl debug_called(2); 282265793Smsmith 282383114Sscottl sc = dev->si_drv1; 282465793Smsmith 282583114Sscottl /* Check to make sure the device isn't already open */ 282683114Sscottl if (sc->aac_state & AAC_STATE_OPEN) { 282783114Sscottl return EBUSY; 282883114Sscottl } 282983114Sscottl sc->aac_state |= AAC_STATE_OPEN; 283083114Sscottl 283183114Sscottl return 0; 283265793Smsmith} 283365793Smsmith 283465793Smsmithstatic int 2835130585Sphkaac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 283665793Smsmith{ 283783114Sscottl struct aac_softc *sc; 283865793Smsmith 283983114Sscottl debug_called(2); 284065793Smsmith 284183114Sscottl sc = dev->si_drv1; 284265793Smsmith 284383114Sscottl /* Mark this unit as no longer open */ 284483114Sscottl sc->aac_state &= ~AAC_STATE_OPEN; 284583114Sscottl 284683114Sscottl return 0; 284765793Smsmith} 284865793Smsmith 284965793Smsmithstatic int 2850130585Sphkaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 285165793Smsmith{ 285283114Sscottl union aac_statrequest *as; 285383114Sscottl struct aac_softc *sc; 285483114Sscottl int error = 0; 2855119146Sscottl uint32_t cookie; 285665793Smsmith 285783114Sscottl debug_called(2); 285865793Smsmith 285983114Sscottl as = (union aac_statrequest *)arg; 286083114Sscottl sc = dev->si_drv1; 286183114Sscottl 286283114Sscottl switch (cmd) { 286383114Sscottl case AACIO_STATS: 286483114Sscottl switch (as->as_item) { 286583114Sscottl case AACQ_FREE: 286683114Sscottl case AACQ_BIO: 286783114Sscottl case AACQ_READY: 286883114Sscottl case AACQ_BUSY: 286983114Sscottl bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 287083114Sscottl sizeof(struct aac_qstat)); 287183114Sscottl break; 287283114Sscottl default: 287383114Sscottl error = ENOENT; 287483114Sscottl break; 287583114Sscottl } 287683114Sscottl break; 287783114Sscottl 287883114Sscottl case FSACTL_SENDFIB: 287983114Sscottl arg = *(caddr_t*)arg; 288083114Sscottl case FSACTL_LNX_SENDFIB: 288183114Sscottl debug(1, "FSACTL_SENDFIB"); 288283114Sscottl error = aac_ioctl_sendfib(sc, arg); 288383114Sscottl break; 288483114Sscottl case FSACTL_AIF_THREAD: 288583114Sscottl case FSACTL_LNX_AIF_THREAD: 288683114Sscottl debug(1, "FSACTL_AIF_THREAD"); 288783114Sscottl error = EINVAL; 288883114Sscottl break; 288983114Sscottl case FSACTL_OPEN_GET_ADAPTER_FIB: 289083114Sscottl arg = *(caddr_t*)arg; 289187183Sscottl case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 289283114Sscottl debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 289383114Sscottl /* 289483114Sscottl * Pass the caller out an AdapterFibContext. 289583114Sscottl * 289683114Sscottl * Note that because we only support one opener, we 289783114Sscottl * basically ignore this. Set the caller's context to a magic 289883114Sscottl * number just in case. 289983114Sscottl * 290083114Sscottl * The Linux code hands the driver a pointer into kernel space, 290183114Sscottl * and then trusts it when the caller hands it back. Aiee! 290283114Sscottl * Here, we give it the proc pointer of the per-adapter aif 290383114Sscottl * thread. It's only used as a sanity check in other calls. 290483114Sscottl */ 2905119146Sscottl cookie = (uint32_t)(uintptr_t)sc->aifthread; 2906119146Sscottl error = copyout(&cookie, arg, sizeof(cookie)); 290783114Sscottl break; 290883114Sscottl case FSACTL_GET_NEXT_ADAPTER_FIB: 290983114Sscottl arg = *(caddr_t*)arg; 291083114Sscottl case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 291183114Sscottl debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 291283114Sscottl error = aac_getnext_aif(sc, arg); 291383114Sscottl break; 291483114Sscottl case FSACTL_CLOSE_GET_ADAPTER_FIB: 291583114Sscottl case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 291683114Sscottl debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 291783114Sscottl /* don't do anything here */ 291883114Sscottl break; 291983114Sscottl case FSACTL_MINIPORT_REV_CHECK: 292083114Sscottl arg = *(caddr_t*)arg; 292183114Sscottl case FSACTL_LNX_MINIPORT_REV_CHECK: 292283114Sscottl debug(1, "FSACTL_MINIPORT_REV_CHECK"); 292383114Sscottl error = aac_rev_check(sc, arg); 292483114Sscottl break; 292583114Sscottl case FSACTL_QUERY_DISK: 292683114Sscottl arg = *(caddr_t*)arg; 292783114Sscottl case FSACTL_LNX_QUERY_DISK: 292883114Sscottl debug(1, "FSACTL_QUERY_DISK"); 292983114Sscottl error = aac_query_disk(sc, arg); 2930151086Sscottl break; 293183114Sscottl case FSACTL_DELETE_DISK: 293283114Sscottl case FSACTL_LNX_DELETE_DISK: 293383114Sscottl /* 293483114Sscottl * We don't trust the underland to tell us when to delete a 293583114Sscottl * container, rather we rely on an AIF coming from the 293683114Sscottl * controller 293783114Sscottl */ 293883114Sscottl error = 0; 293983114Sscottl break; 2940151086Sscottl case FSACTL_GET_PCI_INFO: 2941151086Sscottl arg = *(caddr_t*)arg; 2942151086Sscottl case FSACTL_LNX_GET_PCI_INFO: 2943151086Sscottl debug(1, "FSACTL_GET_PCI_INFO"); 2944151086Sscottl error = aac_get_pci_info(sc, arg); 2945151086Sscottl break; 294670393Smsmith default: 294787183Sscottl debug(1, "unsupported cmd 0x%lx\n", cmd); 294883114Sscottl error = EINVAL; 294983114Sscottl break; 295070393Smsmith } 295183114Sscottl return(error); 295265793Smsmith} 295365793Smsmith 295487183Sscottlstatic int 2955130585Sphkaac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 295687183Sscottl{ 295787183Sscottl struct aac_softc *sc; 295887183Sscottl int revents; 295987183Sscottl 296087183Sscottl sc = dev->si_drv1; 296187183Sscottl revents = 0; 296287183Sscottl 2963133540Sscottl mtx_lock(&sc->aac_aifq_lock); 296487183Sscottl if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 296587183Sscottl if (sc->aac_aifq_tail != sc->aac_aifq_head) 296687183Sscottl revents |= poll_events & (POLLIN | POLLRDNORM); 296787183Sscottl } 2968133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 296987183Sscottl 297087183Sscottl if (revents == 0) { 297187183Sscottl if (poll_events & (POLLIN | POLLRDNORM)) 297287183Sscottl selrecord(td, &sc->rcv_select); 297387183Sscottl } 297487183Sscottl 297587183Sscottl return (revents); 297687183Sscottl} 297787183Sscottl 2978151086Sscottlstatic void 2979151086Sscottlaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2980151086Sscottl{ 2981151086Sscottl 2982151086Sscottl switch (event->ev_type) { 2983151086Sscottl case AAC_EVENT_CMFREE: 2984151086Sscottl mtx_lock(&sc->aac_io_lock); 2985151086Sscottl if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) { 2986151086Sscottl aac_add_event(sc, event); 2987151086Sscottl mtx_unlock(&sc->aac_io_lock); 2988151086Sscottl return; 2989151086Sscottl } 2990151086Sscottl free(event, M_AACBUF); 2991151109Sscottl wakeup(arg); 2992151086Sscottl mtx_unlock(&sc->aac_io_lock); 2993151086Sscottl break; 2994151086Sscottl default: 2995151086Sscottl break; 2996151086Sscottl } 2997151086Sscottl} 2998151086Sscottl 299983114Sscottl/* 300065793Smsmith * Send a FIB supplied from userspace 300165793Smsmith */ 300265793Smsmithstatic int 300365793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 300465793Smsmith{ 300583114Sscottl struct aac_command *cm; 300683114Sscottl int size, error; 300765793Smsmith 300883114Sscottl debug_called(2); 300965793Smsmith 301083114Sscottl cm = NULL; 301165793Smsmith 301283114Sscottl /* 301383114Sscottl * Get a command 301483114Sscottl */ 3015133540Sscottl mtx_lock(&sc->aac_io_lock); 301683114Sscottl if (aac_alloc_command(sc, &cm)) { 3017151086Sscottl struct aac_event *event; 3018151086Sscottl 3019151086Sscottl event = malloc(sizeof(struct aac_event), M_AACBUF, 3020151086Sscottl M_NOWAIT | M_ZERO); 3021151086Sscottl if (event == NULL) { 3022151086Sscottl error = EBUSY; 3023151086Sscottl goto out; 3024151086Sscottl } 3025151086Sscottl event->ev_type = AAC_EVENT_CMFREE; 3026151086Sscottl event->ev_callback = aac_ioctl_event; 3027151086Sscottl event->ev_arg = &cm; 3028151086Sscottl aac_add_event(sc, event); 3029151109Sscottl msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 303083114Sscottl } 303165793Smsmith 303283114Sscottl /* 303383114Sscottl * Fetch the FIB header, then re-copy to get data as well. 303483114Sscottl */ 303583114Sscottl if ((error = copyin(ufib, cm->cm_fib, 303683114Sscottl sizeof(struct aac_fib_header))) != 0) 303783114Sscottl goto out; 303883114Sscottl size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 303983114Sscottl if (size > sizeof(struct aac_fib)) { 3040119146Sscottl device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 304183114Sscottl size, sizeof(struct aac_fib)); 304283114Sscottl size = sizeof(struct aac_fib); 304383114Sscottl } 304483114Sscottl if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 304583114Sscottl goto out; 304683114Sscottl cm->cm_fib->Header.Size = size; 3047150119Sscottl cm->cm_timestamp = time_uptime; 304865793Smsmith 304983114Sscottl /* 305083114Sscottl * Pass the FIB to the controller, wait for it to complete. 305183114Sscottl */ 3052128258Sscottl if ((error = aac_wait_command(cm)) != 0) { 3053110426Sscottl device_printf(sc->aac_dev, 3054110426Sscottl "aac_wait_command return %d\n", error); 305583114Sscottl goto out; 305687183Sscottl } 305765793Smsmith 305883114Sscottl /* 305983114Sscottl * Copy the FIB and data back out to the caller. 306083114Sscottl */ 306183114Sscottl size = cm->cm_fib->Header.Size; 306283114Sscottl if (size > sizeof(struct aac_fib)) { 3063119146Sscottl device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 306483114Sscottl size, sizeof(struct aac_fib)); 306583114Sscottl size = sizeof(struct aac_fib); 306683114Sscottl } 306783114Sscottl error = copyout(cm->cm_fib, ufib, size); 306865793Smsmith 306965793Smsmithout: 307083114Sscottl if (cm != NULL) { 307183114Sscottl aac_release_command(cm); 307283114Sscottl } 3073111532Sscottl 3074133540Sscottl mtx_unlock(&sc->aac_io_lock); 307583114Sscottl return(error); 307665793Smsmith} 307765793Smsmith 307883114Sscottl/* 307965793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference. 308082527Sscottl * If the queue fills up, then drop the older entries. 308165793Smsmith */ 308265793Smsmithstatic void 308382527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 308465793Smsmith{ 308583114Sscottl struct aac_aif_command *aif; 308683114Sscottl struct aac_container *co, *co_next; 308795350Sscottl struct aac_mntinfo *mi; 308895350Sscottl struct aac_mntinforesp *mir = NULL; 308983114Sscottl u_int16_t rsize; 309087183Sscottl int next, found; 3091115760Sscottl int count = 0, added = 0, i = 0; 309265793Smsmith 309383114Sscottl debug_called(2); 309465793Smsmith 309583114Sscottl aif = (struct aac_aif_command*)&fib->data[0]; 309683114Sscottl aac_print_aif(sc, aif); 309782527Sscottl 309883114Sscottl /* Is it an event that we should care about? */ 309983114Sscottl switch (aif->command) { 310083114Sscottl case AifCmdEventNotify: 310183114Sscottl switch (aif->data.EN.type) { 310283114Sscottl case AifEnAddContainer: 310383114Sscottl case AifEnDeleteContainer: 310483114Sscottl /* 310583114Sscottl * A container was added or deleted, but the message 310683114Sscottl * doesn't tell us anything else! Re-enumerate the 310783114Sscottl * containers and sort things out. 310883114Sscottl */ 3109130006Sscottl aac_alloc_sync_fib(sc, &fib); 311095350Sscottl mi = (struct aac_mntinfo *)&fib->data[0]; 311183114Sscottl do { 311283114Sscottl /* 311383114Sscottl * Ask the controller for its containers one at 311483114Sscottl * a time. 311583114Sscottl * XXX What if the controller's list changes 311683114Sscottl * midway through this enumaration? 311783114Sscottl * XXX This should be done async. 311883114Sscottl */ 311995966Sscottl bzero(mi, sizeof(struct aac_mntinfo)); 312095966Sscottl mi->Command = VM_NameServe; 312195966Sscottl mi->MntType = FT_FILESYS; 312295350Sscottl mi->MntCount = i; 312383114Sscottl rsize = sizeof(mir); 312495350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 312595350Sscottl sizeof(struct aac_mntinfo))) { 3126115760Sscottl printf("Error probing container %d\n", 312783114Sscottl i); 312883114Sscottl continue; 312983114Sscottl } 313095350Sscottl mir = (struct aac_mntinforesp *)&fib->data[0]; 3131115760Sscottl /* XXX Need to check if count changed */ 3132115760Sscottl count = mir->MntRespCount; 313383114Sscottl /* 313483114Sscottl * Check the container against our list. 313583114Sscottl * co->co_found was already set to 0 in a 313683114Sscottl * previous run. 313783114Sscottl */ 313895350Sscottl if ((mir->Status == ST_OK) && 313995350Sscottl (mir->MntTable[0].VolType != CT_NONE)) { 314083114Sscottl found = 0; 314183114Sscottl TAILQ_FOREACH(co, 314283114Sscottl &sc->aac_container_tqh, 314383114Sscottl co_link) { 314483114Sscottl if (co->co_mntobj.ObjectId == 314595350Sscottl mir->MntTable[0].ObjectId) { 314683114Sscottl co->co_found = 1; 314783114Sscottl found = 1; 314883114Sscottl break; 314983114Sscottl } 315083114Sscottl } 315183114Sscottl /* 315283114Sscottl * If the container matched, continue 315383114Sscottl * in the list. 315483114Sscottl */ 315583114Sscottl if (found) { 315683114Sscottl i++; 315783114Sscottl continue; 315883114Sscottl } 315983114Sscottl 316083114Sscottl /* 316183114Sscottl * This is a new container. Do all the 3162110426Sscottl * appropriate things to set it up. 3163110426Sscottl */ 316495350Sscottl aac_add_container(sc, mir, 1); 316583114Sscottl added = 1; 316683114Sscottl } 316783114Sscottl i++; 3168115760Sscottl } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 316995350Sscottl aac_release_sync_fib(sc); 317083114Sscottl 317183114Sscottl /* 317283114Sscottl * Go through our list of containers and see which ones 317383114Sscottl * were not marked 'found'. Since the controller didn't 317483114Sscottl * list them they must have been deleted. Do the 317583114Sscottl * appropriate steps to destroy the device. Also reset 317683114Sscottl * the co->co_found field. 317783114Sscottl */ 317883114Sscottl co = TAILQ_FIRST(&sc->aac_container_tqh); 317983114Sscottl while (co != NULL) { 318083114Sscottl if (co->co_found == 0) { 3181151086Sscottl mtx_unlock(&sc->aac_io_lock); 3182151086Sscottl mtx_lock(&Giant); 318383114Sscottl device_delete_child(sc->aac_dev, 318483114Sscottl co->co_disk); 3185151086Sscottl mtx_unlock(&Giant); 3186151086Sscottl mtx_lock(&sc->aac_io_lock); 318783114Sscottl co_next = TAILQ_NEXT(co, co_link); 3188133540Sscottl mtx_lock(&sc->aac_container_lock); 318983114Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, 319083114Sscottl co_link); 3191133540Sscottl mtx_unlock(&sc->aac_container_lock); 3192133541Sscottl free(co, M_AACBUF); 319383114Sscottl co = co_next; 319483114Sscottl } else { 319583114Sscottl co->co_found = 0; 319683114Sscottl co = TAILQ_NEXT(co, co_link); 319783114Sscottl } 319882527Sscottl } 319982527Sscottl 320083114Sscottl /* Attach the newly created containers */ 3201151086Sscottl if (added) { 3202151086Sscottl mtx_unlock(&sc->aac_io_lock); 3203151086Sscottl mtx_lock(&Giant); 320483114Sscottl bus_generic_attach(sc->aac_dev); 3205151086Sscottl mtx_unlock(&Giant); 3206151086Sscottl mtx_lock(&sc->aac_io_lock); 3207151086Sscottl } 320883114Sscottl 3209105528Sphk break; 321082527Sscottl 321183114Sscottl default: 321283114Sscottl break; 321382527Sscottl } 321482527Sscottl 321582527Sscottl default: 321683114Sscottl break; 321782527Sscottl } 321882527Sscottl 321983114Sscottl /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3220133540Sscottl mtx_lock(&sc->aac_aifq_lock); 322183114Sscottl next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 322283114Sscottl if (next != sc->aac_aifq_tail) { 322383114Sscottl bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 322487183Sscottl sc->aac_aifq_head = next; 322587183Sscottl 322687183Sscottl /* On the off chance that someone is sleeping for an aif... */ 322787183Sscottl if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 322887183Sscottl wakeup(sc->aac_aifq); 322987183Sscottl /* Wakeup any poll()ers */ 3230122352Stanimura selwakeuppri(&sc->rcv_select, PRIBIO); 323183114Sscottl } 3232133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 323382527Sscottl 323483114Sscottl return; 323565793Smsmith} 323665793Smsmith 323783114Sscottl/* 323870393Smsmith * Return the Revision of the driver to userspace and check to see if the 323982527Sscottl * userspace app is possibly compatible. This is extremely bogus since 324082527Sscottl * our driver doesn't follow Adaptec's versioning system. Cheat by just 324182527Sscottl * returning what the card reported. 324265793Smsmith */ 324365793Smsmithstatic int 324481189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata) 324565793Smsmith{ 324683114Sscottl struct aac_rev_check rev_check; 324783114Sscottl struct aac_rev_check_resp rev_check_resp; 324883114Sscottl int error = 0; 324965793Smsmith 325083114Sscottl debug_called(2); 325165793Smsmith 325283114Sscottl /* 325383114Sscottl * Copyin the revision struct from userspace 325483114Sscottl */ 325583114Sscottl if ((error = copyin(udata, (caddr_t)&rev_check, 325681082Sscottl sizeof(struct aac_rev_check))) != 0) { 325783114Sscottl return error; 325883114Sscottl } 325965793Smsmith 326083114Sscottl debug(2, "Userland revision= %d\n", 326183114Sscottl rev_check.callingRevision.buildNumber); 326265793Smsmith 326383114Sscottl /* 326483114Sscottl * Doctor up the response struct. 326583114Sscottl */ 326683114Sscottl rev_check_resp.possiblyCompatible = 1; 326783114Sscottl rev_check_resp.adapterSWRevision.external.ul = 326883114Sscottl sc->aac_revision.external.ul; 326983114Sscottl rev_check_resp.adapterSWRevision.buildNumber = 327083114Sscottl sc->aac_revision.buildNumber; 327165793Smsmith 327283114Sscottl return(copyout((caddr_t)&rev_check_resp, udata, 327383114Sscottl sizeof(struct aac_rev_check_resp))); 327465793Smsmith} 327565793Smsmith 327683114Sscottl/* 327765793Smsmith * Pass the caller the next AIF in their queue 327865793Smsmith */ 327965793Smsmithstatic int 328081189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 328165793Smsmith{ 328283114Sscottl struct get_adapter_fib_ioctl agf; 3283111691Sscottl int error; 328465793Smsmith 328583114Sscottl debug_called(2); 328665793Smsmith 328783114Sscottl if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 328865793Smsmith 328983114Sscottl /* 329083114Sscottl * Check the magic number that we gave the caller. 329183114Sscottl */ 3292119146Sscottl if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 329383114Sscottl error = EFAULT; 329483114Sscottl } else { 329581189Sscottl error = aac_return_aif(sc, agf.AifFib); 329683114Sscottl if ((error == EAGAIN) && (agf.Wait)) { 329783114Sscottl sc->aac_state |= AAC_STATE_AIF_SLEEPER; 329883114Sscottl while (error == EAGAIN) { 329983114Sscottl error = tsleep(sc->aac_aifq, PRIBIO | 330083114Sscottl PCATCH, "aacaif", 0); 330183114Sscottl if (error == 0) 330283114Sscottl error = aac_return_aif(sc, 330383114Sscottl agf.AifFib); 330483114Sscottl } 330583114Sscottl sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 330683114Sscottl } 330765793Smsmith } 330865793Smsmith } 330983114Sscottl return(error); 331065793Smsmith} 331165793Smsmith 331283114Sscottl/* 331370393Smsmith * Hand the next AIF off the top of the queue out to userspace. 331470393Smsmith */ 331570393Smsmithstatic int 331681189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr) 331770393Smsmith{ 3318121173Sscottl int next, error; 331970393Smsmith 332083114Sscottl debug_called(2); 332170393Smsmith 3322133540Sscottl mtx_lock(&sc->aac_aifq_lock); 332383114Sscottl if (sc->aac_aifq_tail == sc->aac_aifq_head) { 3324133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 3325121173Sscottl return (EAGAIN); 332683114Sscottl } 3327121173Sscottl 3328121173Sscottl next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 3329121173Sscottl error = copyout(&sc->aac_aifq[next], uptr, 3330121173Sscottl sizeof(struct aac_aif_command)); 3331121173Sscottl if (error) 3332121173Sscottl device_printf(sc->aac_dev, 3333121173Sscottl "aac_return_aif: copyout returned %d\n", error); 3334121173Sscottl else 3335121173Sscottl sc->aac_aifq_tail = next; 3336121173Sscottl 3337133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 333883114Sscottl return(error); 333970393Smsmith} 334082527Sscottl 3341151086Sscottlstatic int 3342151086Sscottlaac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3343151086Sscottl{ 3344151086Sscottl struct aac_pci_info { 3345151086Sscottl u_int32_t bus; 3346151086Sscottl u_int32_t slot; 3347151086Sscottl } pciinf; 3348151086Sscottl int error; 3349151086Sscottl 3350151086Sscottl debug_called(2); 3351151086Sscottl 3352151086Sscottl pciinf.bus = pci_get_bus(sc->aac_dev); 3353151086Sscottl pciinf.slot = pci_get_slot(sc->aac_dev); 3354151086Sscottl 3355151086Sscottl error = copyout((caddr_t)&pciinf, uptr, 3356151086Sscottl sizeof(struct aac_pci_info)); 3357151086Sscottl 3358151086Sscottl return (error); 3359151086Sscottl} 3360151086Sscottl 336183114Sscottl/* 336282527Sscottl * Give the userland some information about the container. The AAC arch 336382527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects 336482527Sscottl * the containers to have b:t:l numbers. Fake it. 336582527Sscottl */ 336682527Sscottlstatic int 336782527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr) 336882527Sscottl{ 336983114Sscottl struct aac_query_disk query_disk; 337083114Sscottl struct aac_container *co; 337183114Sscottl struct aac_disk *disk; 337283114Sscottl int error, id; 337382527Sscottl 337483114Sscottl debug_called(2); 337582527Sscottl 337683114Sscottl disk = NULL; 337782527Sscottl 337883114Sscottl error = copyin(uptr, (caddr_t)&query_disk, 337983114Sscottl sizeof(struct aac_query_disk)); 338083114Sscottl if (error) 338183114Sscottl return (error); 338282527Sscottl 338383114Sscottl id = query_disk.ContainerNumber; 338483114Sscottl if (id == -1) 338583114Sscottl return (EINVAL); 338682527Sscottl 3387133540Sscottl mtx_lock(&sc->aac_container_lock); 338883114Sscottl TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 338983114Sscottl if (co->co_mntobj.ObjectId == id) 339083114Sscottl break; 339183114Sscottl } 339282527Sscottl 3393105528Sphk if (co == NULL) { 339483114Sscottl query_disk.Valid = 0; 339583114Sscottl query_disk.Locked = 0; 339683114Sscottl query_disk.Deleted = 1; /* XXX is this right? */ 3397105528Sphk } else { 3398105528Sphk disk = device_get_softc(co->co_disk); 3399105528Sphk query_disk.Valid = 1; 3400105528Sphk query_disk.Locked = 3401105528Sphk (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 3402105528Sphk query_disk.Deleted = 0; 3403105528Sphk query_disk.Bus = device_get_unit(sc->aac_dev); 3404105528Sphk query_disk.Target = disk->unit; 3405105528Sphk query_disk.Lun = 0; 3406105528Sphk query_disk.UnMapped = 0; 3407111525Sscottl sprintf(&query_disk.diskDeviceName[0], "%s%d", 3408125975Sphk disk->ad_disk->d_name, disk->ad_disk->d_unit); 3409105528Sphk } 3410133540Sscottl mtx_unlock(&sc->aac_container_lock); 341182527Sscottl 341283114Sscottl error = copyout((caddr_t)&query_disk, uptr, 341383114Sscottl sizeof(struct aac_query_disk)); 341483114Sscottl 341583114Sscottl return (error); 341682527Sscottl} 341782527Sscottl 341895536Sscottlstatic void 341995536Sscottlaac_get_bus_info(struct aac_softc *sc) 342095536Sscottl{ 342195536Sscottl struct aac_fib *fib; 342295536Sscottl struct aac_ctcfg *c_cmd; 342395536Sscottl struct aac_ctcfg_resp *c_resp; 342495536Sscottl struct aac_vmioctl *vmi; 342595536Sscottl struct aac_vmi_businf_resp *vmi_resp; 342695536Sscottl struct aac_getbusinf businfo; 3427110426Sscottl struct aac_sim *caminf; 342895536Sscottl device_t child; 342995536Sscottl int i, found, error; 343095536Sscottl 3431130006Sscottl aac_alloc_sync_fib(sc, &fib); 343295536Sscottl c_cmd = (struct aac_ctcfg *)&fib->data[0]; 343395966Sscottl bzero(c_cmd, sizeof(struct aac_ctcfg)); 343495536Sscottl 343595536Sscottl c_cmd->Command = VM_ContainerConfig; 343695536Sscottl c_cmd->cmd = CT_GET_SCSI_METHOD; 343795536Sscottl c_cmd->param = 0; 343895536Sscottl 343995536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 344095536Sscottl sizeof(struct aac_ctcfg)); 344195536Sscottl if (error) { 344295536Sscottl device_printf(sc->aac_dev, "Error %d sending " 344395536Sscottl "VM_ContainerConfig command\n", error); 344495536Sscottl aac_release_sync_fib(sc); 344595536Sscottl return; 344695536Sscottl } 344795536Sscottl 344895536Sscottl c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 344995536Sscottl if (c_resp->Status != ST_OK) { 345095536Sscottl device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 345195536Sscottl c_resp->Status); 345295536Sscottl aac_release_sync_fib(sc); 345395536Sscottl return; 345495536Sscottl } 345595536Sscottl 345695536Sscottl sc->scsi_method_id = c_resp->param; 345795536Sscottl 345895536Sscottl vmi = (struct aac_vmioctl *)&fib->data[0]; 345995966Sscottl bzero(vmi, sizeof(struct aac_vmioctl)); 346095966Sscottl 346195536Sscottl vmi->Command = VM_Ioctl; 346295536Sscottl vmi->ObjType = FT_DRIVE; 346395536Sscottl vmi->MethId = sc->scsi_method_id; 346495536Sscottl vmi->ObjId = 0; 346595536Sscottl vmi->IoctlCmd = GetBusInfo; 346695536Sscottl 346795536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 346895536Sscottl sizeof(struct aac_vmioctl)); 346995536Sscottl if (error) { 347095536Sscottl device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 347195536Sscottl error); 347295536Sscottl aac_release_sync_fib(sc); 347395536Sscottl return; 347495536Sscottl } 347595536Sscottl 347695536Sscottl vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 347795536Sscottl if (vmi_resp->Status != ST_OK) { 347895536Sscottl device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 347995536Sscottl vmi_resp->Status); 348095536Sscottl aac_release_sync_fib(sc); 348195536Sscottl return; 348295536Sscottl } 348395536Sscottl 348495536Sscottl bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 348595536Sscottl aac_release_sync_fib(sc); 348695536Sscottl 348795536Sscottl found = 0; 348895536Sscottl for (i = 0; i < businfo.BusCount; i++) { 348995536Sscottl if (businfo.BusValid[i] != AAC_BUS_VALID) 349095536Sscottl continue; 349195536Sscottl 3492110428Sscottl caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3493110428Sscottl M_AACBUF, M_NOWAIT | M_ZERO); 3494143838Sscottl if (caminf == NULL) { 3495143838Sscottl device_printf(sc->aac_dev, 3496143838Sscottl "No memory to add passthrough bus %d\n", i); 3497143838Sscottl break; 3498151086Sscottl }; 349995536Sscottl 350095536Sscottl child = device_add_child(sc->aac_dev, "aacp", -1); 350195536Sscottl if (child == NULL) { 3502143838Sscottl device_printf(sc->aac_dev, 3503143838Sscottl "device_add_child failed for passthrough bus %d\n", 3504143838Sscottl i); 3505143838Sscottl free(caminf, M_AACBUF); 3506151086Sscottl break; 350795536Sscottl } 350895536Sscottl 350995536Sscottl caminf->TargetsPerBus = businfo.TargetsPerBus; 351095536Sscottl caminf->BusNumber = i; 351195536Sscottl caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 351295536Sscottl caminf->aac_sc = sc; 3513110432Sscottl caminf->sim_dev = child; 351495536Sscottl 351595536Sscottl device_set_ivars(child, caminf); 351695536Sscottl device_set_desc(child, "SCSI Passthrough Bus"); 3517110426Sscottl TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 351895536Sscottl 351995536Sscottl found = 1; 352095536Sscottl } 352195536Sscottl 352295536Sscottl if (found) 352395536Sscottl bus_generic_attach(sc->aac_dev); 352495536Sscottl 352595536Sscottl return; 352695536Sscottl} 3527