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$"); 32119418Sobrien 3365793Smsmith/* 3465793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3565793Smsmith */ 36151086Sscottl#define AAC_DRIVERNAME "aac" 3765793Smsmith 3881151Sscottl#include "opt_aac.h" 3981151Sscottl 4082527Sscottl/* #include <stddef.h> */ 4165793Smsmith#include <sys/param.h> 4265793Smsmith#include <sys/systm.h> 4365793Smsmith#include <sys/malloc.h> 4465793Smsmith#include <sys/kernel.h> 4582527Sscottl#include <sys/kthread.h> 4681154Sscottl#include <sys/sysctl.h> 4787183Sscottl#include <sys/poll.h> 48112946Sphk#include <sys/ioccom.h> 4965793Smsmith 5065793Smsmith#include <sys/bus.h> 5165793Smsmith#include <sys/conf.h> 5265793Smsmith#include <sys/signalvar.h> 5370393Smsmith#include <sys/time.h> 5482527Sscottl#include <sys/eventhandler.h> 55151086Sscottl#include <sys/rman.h> 5665793Smsmith 5765793Smsmith#include <machine/bus.h> 58143838Sscottl#include <sys/bus_dma.h> 5965793Smsmith#include <machine/resource.h> 6065793Smsmith 61151086Sscottl#include <dev/pci/pcireg.h> 62151086Sscottl#include <dev/pci/pcivar.h> 63151086Sscottl 6465793Smsmith#include <dev/aac/aacreg.h> 65138635Sscottl#include <sys/aac_ioctl.h> 6665793Smsmith#include <dev/aac/aacvar.h> 6765793Smsmith#include <dev/aac/aac_tables.h> 6865793Smsmith 6965793Smsmithstatic void aac_startup(void *arg); 7083114Sscottlstatic void aac_add_container(struct aac_softc *sc, 7195350Sscottl struct aac_mntinforesp *mir, int f); 7295536Sscottlstatic void aac_get_bus_info(struct aac_softc *sc); 73188896Sattiliostatic void aac_daemon(void *arg); 7465793Smsmith 7565793Smsmith/* Command Processing */ 7670393Smsmithstatic void aac_timeout(struct aac_softc *sc); 7765793Smsmithstatic void aac_complete(void *context, int pending); 7865793Smsmithstatic int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7965793Smsmithstatic void aac_bio_complete(struct aac_command *cm); 80128258Sscottlstatic int aac_wait_command(struct aac_command *cm); 81110426Sscottlstatic void aac_command_thread(struct aac_softc *sc); 8265793Smsmith 8365793Smsmith/* Command Buffer Management */ 84117363Sscottlstatic void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 85117363Sscottl int nseg, int error); 8681082Sscottlstatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 8781082Sscottl int nseg, int error); 8870393Smsmithstatic int aac_alloc_commands(struct aac_softc *sc); 89111141Sscottlstatic void aac_free_commands(struct aac_softc *sc); 9065793Smsmithstatic void aac_unmap_command(struct aac_command *cm); 9165793Smsmith 9265793Smsmith/* Hardware Interface */ 93177557Semastestatic int aac_alloc(struct aac_softc *sc); 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); 101177557Semastestatic int aac_setup_intr(struct aac_softc *sc); 10281082Sscottlstatic int aac_enqueue_fib(struct aac_softc *sc, int queue, 10381151Sscottl struct aac_command *cm); 10481082Sscottlstatic int aac_dequeue_fib(struct aac_softc *sc, int queue, 10583114Sscottl u_int32_t *fib_size, struct aac_fib **fib_addr); 10682527Sscottlstatic int aac_enqueue_response(struct aac_softc *sc, int queue, 10782527Sscottl struct aac_fib *fib); 10865793Smsmith 10965793Smsmith/* StrongARM interface */ 11065793Smsmithstatic int aac_sa_get_fwstatus(struct aac_softc *sc); 11165793Smsmithstatic void aac_sa_qnotify(struct aac_softc *sc, int qbit); 11265793Smsmithstatic int aac_sa_get_istatus(struct aac_softc *sc); 11365793Smsmithstatic void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 11465793Smsmithstatic void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 11581082Sscottl u_int32_t arg0, u_int32_t arg1, 11681082Sscottl u_int32_t arg2, u_int32_t arg3); 117112679Sscottlstatic int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 11865793Smsmithstatic void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 11965793Smsmith 120251070Smariusconst struct aac_interface aac_sa_interface = { 12183114Sscottl aac_sa_get_fwstatus, 12283114Sscottl aac_sa_qnotify, 12383114Sscottl aac_sa_get_istatus, 12483114Sscottl aac_sa_clear_istatus, 12583114Sscottl aac_sa_set_mailbox, 126112679Sscottl aac_sa_get_mailbox, 127151086Sscottl aac_sa_set_interrupts, 128151086Sscottl NULL, NULL, NULL 12965793Smsmith}; 13065793Smsmith 131152388Sschweikh/* i960Rx interface */ 13265793Smsmithstatic int aac_rx_get_fwstatus(struct aac_softc *sc); 13365793Smsmithstatic void aac_rx_qnotify(struct aac_softc *sc, int qbit); 13465793Smsmithstatic int aac_rx_get_istatus(struct aac_softc *sc); 13565793Smsmithstatic void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 13665793Smsmithstatic void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 13781082Sscottl u_int32_t arg0, u_int32_t arg1, 13881082Sscottl u_int32_t arg2, u_int32_t arg3); 139112679Sscottlstatic int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 14065793Smsmithstatic void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 141151086Sscottlstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 142151086Sscottlstatic int aac_rx_get_outb_queue(struct aac_softc *sc); 143151086Sscottlstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 14465793Smsmith 145251070Smariusconst struct aac_interface aac_rx_interface = { 14683114Sscottl aac_rx_get_fwstatus, 14783114Sscottl aac_rx_qnotify, 14883114Sscottl aac_rx_get_istatus, 14983114Sscottl aac_rx_clear_istatus, 15083114Sscottl aac_rx_set_mailbox, 151112679Sscottl aac_rx_get_mailbox, 152151086Sscottl aac_rx_set_interrupts, 153151086Sscottl aac_rx_send_command, 154151086Sscottl aac_rx_get_outb_queue, 155151086Sscottl aac_rx_set_outb_queue 15665793Smsmith}; 15765793Smsmith 158152388Sschweikh/* Rocket/MIPS interface */ 159133606Sscottlstatic int aac_rkt_get_fwstatus(struct aac_softc *sc); 160133606Sscottlstatic void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 161133606Sscottlstatic int aac_rkt_get_istatus(struct aac_softc *sc); 162133606Sscottlstatic void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 163133606Sscottlstatic void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 164133606Sscottl u_int32_t arg0, u_int32_t arg1, 165133606Sscottl u_int32_t arg2, u_int32_t arg3); 166133606Sscottlstatic int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 167133606Sscottlstatic void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 168151086Sscottlstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 169151086Sscottlstatic int aac_rkt_get_outb_queue(struct aac_softc *sc); 170151086Sscottlstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 171133606Sscottl 172251070Smariusconst struct aac_interface aac_rkt_interface = { 173133606Sscottl aac_rkt_get_fwstatus, 174133606Sscottl aac_rkt_qnotify, 175133606Sscottl aac_rkt_get_istatus, 176133606Sscottl aac_rkt_clear_istatus, 177133606Sscottl aac_rkt_set_mailbox, 178133606Sscottl aac_rkt_get_mailbox, 179151086Sscottl aac_rkt_set_interrupts, 180151086Sscottl aac_rkt_send_command, 181151086Sscottl aac_rkt_get_outb_queue, 182151086Sscottl aac_rkt_set_outb_queue 183133606Sscottl}; 184133606Sscottl 18565793Smsmith/* Debugging and Diagnostics */ 186251070Smariusstatic void aac_describe_controller(struct aac_softc *sc); 187251070Smariusstatic const char *aac_describe_code(const struct aac_code_lookup *table, 18881082Sscottl u_int32_t code); 18965793Smsmith 19065793Smsmith/* Management Interface */ 19165793Smsmithstatic d_open_t aac_open; 19265793Smsmithstatic d_ioctl_t aac_ioctl; 19387183Sscottlstatic d_poll_t aac_poll; 194212756Sattiliostatic void aac_cdevpriv_dtor(void *arg); 19581082Sscottlstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 196177462Semastestatic int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 19781082Sscottlstatic void aac_handle_aif(struct aac_softc *sc, 19883114Sscottl struct aac_fib *fib); 19981189Sscottlstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 200174385Semastestatic int aac_open_aif(struct aac_softc *sc, caddr_t arg); 201174385Semastestatic int aac_close_aif(struct aac_softc *sc, caddr_t arg); 20281189Sscottlstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 203174385Semastestatic int aac_return_aif(struct aac_softc *sc, 204174385Semaste struct aac_fib_context *ctx, caddr_t uptr); 20582527Sscottlstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 206151086Sscottlstatic int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 207177695Semastestatic int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 208151086Sscottlstatic void aac_ioctl_event(struct aac_softc *sc, 209198525Semaste struct aac_event *event, void *arg); 210177557Semastestatic struct aac_mntinforesp * 211177557Semaste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); 21265793Smsmith 21365793Smsmithstatic struct cdevsw aac_cdevsw = { 214126080Sphk .d_version = D_VERSION, 215212756Sattilio .d_flags = D_NEEDGIANT, 216111815Sphk .d_open = aac_open, 217111815Sphk .d_ioctl = aac_ioctl, 218111815Sphk .d_poll = aac_poll, 219111815Sphk .d_name = "aac", 22065793Smsmith}; 22165793Smsmith 222249132Smavstatic MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 22382527Sscottl 22481154Sscottl/* sysctl node */ 225251070SmariusSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 22681154Sscottl 22783114Sscottl/* 22883114Sscottl * Device Interface 22983114Sscottl */ 23065793Smsmith 23183114Sscottl/* 232177184Semaste * Initialize the controller and softc 23365793Smsmith */ 23465793Smsmithint 23565793Smsmithaac_attach(struct aac_softc *sc) 23665793Smsmith{ 23783114Sscottl int error, unit; 23865793Smsmith 239177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24065793Smsmith 24183114Sscottl /* 242177184Semaste * Initialize per-controller queues. 24383114Sscottl */ 24483114Sscottl aac_initq_free(sc); 24583114Sscottl aac_initq_ready(sc); 24683114Sscottl aac_initq_busy(sc); 24783114Sscottl aac_initq_bio(sc); 24865793Smsmith 24983114Sscottl /* 250177184Semaste * Initialize command-completion task. 25183114Sscottl */ 25283114Sscottl TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 25365793Smsmith 25483114Sscottl /* mark controller as suspended until we get ourselves organised */ 25583114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 25665793Smsmith 25783114Sscottl /* 25890275Sscottl * Check that the firmware on the card is supported. 25990275Sscottl */ 26090275Sscottl if ((error = aac_check_firmware(sc)) != 0) 26190275Sscottl return(error); 26290275Sscottl 263117126Sscottl /* 264117126Sscottl * Initialize locks 265117126Sscottl */ 266133540Sscottl mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 267133540Sscottl mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 268133540Sscottl mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 269117126Sscottl TAILQ_INIT(&sc->aac_container_tqh); 270153810Sscottl TAILQ_INIT(&sc->aac_ev_cmfree); 27195350Sscottl 272188896Sattilio /* Initialize the clock daemon callout. */ 273188896Sattilio callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 274188896Sattilio 27583114Sscottl /* 276177184Semaste * Initialize the adapter. 27783114Sscottl */ 278177557Semaste if ((error = aac_alloc(sc)) != 0) 279177557Semaste return(error); 28083114Sscottl if ((error = aac_init(sc)) != 0) 28183114Sscottl return(error); 28265793Smsmith 283152388Sschweikh /* 284151086Sscottl * Allocate and connect our interrupt. 285151086Sscottl */ 286177557Semaste if ((error = aac_setup_intr(sc)) != 0) 287177557Semaste return(error); 288151086Sscottl 289152388Sschweikh /* 29083114Sscottl * Print a little information about the controller. 29183114Sscottl */ 29283114Sscottl aac_describe_controller(sc); 29365793Smsmith 29483114Sscottl /* 295243286Semaste * Add sysctls. 296243286Semaste */ 297243286Semaste SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->aac_dev), 298243286Semaste SYSCTL_CHILDREN(device_get_sysctl_tree(sc->aac_dev)), 299243286Semaste OID_AUTO, "firmware_build", CTLFLAG_RD, 300243286Semaste &sc->aac_revision.buildNumber, 0, 301243286Semaste "firmware build number"); 302243286Semaste 303243286Semaste /* 304111532Sscottl * Register to probe our containers later. 30587183Sscottl */ 30683114Sscottl sc->aac_ich.ich_func = aac_startup; 30783114Sscottl sc->aac_ich.ich_arg = sc; 30883114Sscottl if (config_intrhook_establish(&sc->aac_ich) != 0) { 30983114Sscottl device_printf(sc->aac_dev, 31083114Sscottl "can't establish configuration hook\n"); 31183114Sscottl return(ENXIO); 31283114Sscottl } 31365793Smsmith 31483114Sscottl /* 31583114Sscottl * Make the control device. 31683114Sscottl */ 31783114Sscottl unit = device_get_unit(sc->aac_dev); 318108329Srwatson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 319108329Srwatson 0640, "aac%d", unit); 32083114Sscottl (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 32183114Sscottl (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 32283114Sscottl sc->aac_dev_t->si_drv1 = sc; 32365793Smsmith 32483114Sscottl /* Create the AIF thread */ 325172836Sjulian if (kproc_create((void(*)(void *))aac_command_thread, sc, 326151086Sscottl &sc->aifthread, 0, 0, "aac%daif", unit)) 327177635Semaste panic("Could not create AIF thread"); 32882527Sscottl 32983114Sscottl /* Register the shutdown method to only be called post-dump */ 330110427Sscottl if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 331110427Sscottl sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 332110427Sscottl device_printf(sc->aac_dev, 333110427Sscottl "shutdown event registration failed\n"); 33482527Sscottl 33595536Sscottl /* Register with CAM for the non-DASD devices */ 336112679Sscottl if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 337110426Sscottl TAILQ_INIT(&sc->aac_sim_tqh); 33895536Sscottl aac_get_bus_info(sc); 339110426Sscottl } 34095536Sscottl 341188896Sattilio mtx_lock(&sc->aac_io_lock); 342198541Semaste callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 343188896Sattilio mtx_unlock(&sc->aac_io_lock); 344188896Sattilio 34583114Sscottl return(0); 34665793Smsmith} 34765793Smsmith 348188896Sattiliostatic void 349188896Sattilioaac_daemon(void *arg) 350188896Sattilio{ 351188896Sattilio struct timeval tv; 352188896Sattilio struct aac_softc *sc; 353188896Sattilio struct aac_fib *fib; 354188896Sattilio 355188896Sattilio sc = arg; 356188896Sattilio mtx_assert(&sc->aac_io_lock, MA_OWNED); 357188896Sattilio 358188896Sattilio if (callout_pending(&sc->aac_daemontime) || 359188896Sattilio callout_active(&sc->aac_daemontime) == 0) 360188896Sattilio return; 361188896Sattilio getmicrotime(&tv); 362188896Sattilio aac_alloc_sync_fib(sc, &fib); 363188896Sattilio *(uint32_t *)fib->data = tv.tv_sec; 364188896Sattilio aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); 365188896Sattilio aac_release_sync_fib(sc); 366188896Sattilio callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 367188896Sattilio} 368188896Sattilio 369151086Sscottlvoid 370151086Sscottlaac_add_event(struct aac_softc *sc, struct aac_event *event) 371151086Sscottl{ 372151086Sscottl 373151086Sscottl switch (event->ev_type & AAC_EVENT_MASK) { 374151086Sscottl case AAC_EVENT_CMFREE: 375151086Sscottl TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 376151086Sscottl break; 377151086Sscottl default: 378151086Sscottl device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 379151086Sscottl event->ev_type); 380151086Sscottl break; 381151086Sscottl } 382151086Sscottl} 383151086Sscottl 38483114Sscottl/* 385177557Semaste * Request information of container #cid 386177557Semaste */ 387177557Semastestatic struct aac_mntinforesp * 388177557Semasteaac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) 389177557Semaste{ 390177557Semaste struct aac_mntinfo *mi; 391177557Semaste 392177557Semaste mi = (struct aac_mntinfo *)&fib->data[0]; 393177619Semaste /* use 64-bit LBA if enabled */ 394177619Semaste mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? 395177619Semaste VM_NameServe64 : VM_NameServe; 396177557Semaste mi->MntType = FT_FILESYS; 397177557Semaste mi->MntCount = cid; 398177557Semaste 399177557Semaste if (aac_sync_fib(sc, ContainerCommand, 0, fib, 400177557Semaste sizeof(struct aac_mntinfo))) { 401212773Semaste device_printf(sc->aac_dev, "Error probing container %d\n", cid); 402177557Semaste return (NULL); 403177557Semaste } 404177557Semaste 405177557Semaste return ((struct aac_mntinforesp *)&fib->data[0]); 406177557Semaste} 407177557Semaste 408177557Semaste/* 40965793Smsmith * Probe for containers, create disks. 41065793Smsmith */ 41165793Smsmithstatic void 41265793Smsmithaac_startup(void *arg) 41365793Smsmith{ 41483114Sscottl struct aac_softc *sc; 41595350Sscottl struct aac_fib *fib; 416177557Semaste struct aac_mntinforesp *mir; 417115760Sscottl int count = 0, i = 0; 41865793Smsmith 41983114Sscottl sc = (struct aac_softc *)arg; 420177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 42165793Smsmith 42283114Sscottl /* disconnect ourselves from the intrhook chain */ 42383114Sscottl config_intrhook_disestablish(&sc->aac_ich); 42465793Smsmith 425151086Sscottl mtx_lock(&sc->aac_io_lock); 426130006Sscottl aac_alloc_sync_fib(sc, &fib); 42795350Sscottl 42883114Sscottl /* loop over possible containers */ 42983114Sscottl do { 430177557Semaste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 43183114Sscottl continue; 432177557Semaste if (i == 0) 433177557Semaste count = mir->MntRespCount; 43495350Sscottl aac_add_container(sc, mir, 0); 43583114Sscottl i++; 436115760Sscottl } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 43765793Smsmith 43895350Sscottl aac_release_sync_fib(sc); 439151086Sscottl mtx_unlock(&sc->aac_io_lock); 44095350Sscottl 44183114Sscottl /* poke the bus to actually attach the child devices */ 44283114Sscottl if (bus_generic_attach(sc->aac_dev)) 44383114Sscottl device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 44465793Smsmith 44583114Sscottl /* mark the controller up */ 44683114Sscottl sc->aac_state &= ~AAC_STATE_SUSPEND; 44770393Smsmith 44883114Sscottl /* enable interrupts now */ 44983114Sscottl AAC_UNMASK_INTERRUPTS(sc); 45065793Smsmith} 45165793Smsmith 45283114Sscottl/* 453177184Semaste * Create a device to represent a new container 45483114Sscottl */ 45583114Sscottlstatic void 45695350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 45783114Sscottl{ 45883114Sscottl struct aac_container *co; 45983114Sscottl device_t child; 46083114Sscottl 461152388Sschweikh /* 46283114Sscottl * Check container volume type for validity. Note that many of 46383114Sscottl * the possible types may never show up. 46483114Sscottl */ 46583114Sscottl if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 466110428Sscottl co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 467110428Sscottl M_NOWAIT | M_ZERO); 46883114Sscottl if (co == NULL) 469177635Semaste panic("Out of memory?!"); 470177567Semaste fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", 47183114Sscottl mir->MntTable[0].ObjectId, 47283114Sscottl mir->MntTable[0].FileSystemName, 47383114Sscottl mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 474152388Sschweikh 47595536Sscottl if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 47683114Sscottl device_printf(sc->aac_dev, "device_add_child failed\n"); 47783114Sscottl else 47883114Sscottl device_set_ivars(child, co); 47983114Sscottl device_set_desc(child, aac_describe_code(aac_container_types, 48083114Sscottl mir->MntTable[0].VolType)); 48183114Sscottl co->co_disk = child; 48283114Sscottl co->co_found = f; 48383114Sscottl bcopy(&mir->MntTable[0], &co->co_mntobj, 48483114Sscottl sizeof(struct aac_mntobj)); 485133540Sscottl mtx_lock(&sc->aac_container_lock); 48683114Sscottl TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 487133540Sscottl mtx_unlock(&sc->aac_container_lock); 48883114Sscottl } 48983114Sscottl} 49083114Sscottl 49183114Sscottl/* 492177557Semaste * Allocate resources associated with (sc) 493177557Semaste */ 494177557Semastestatic int 495177557Semasteaac_alloc(struct aac_softc *sc) 496177557Semaste{ 497177567Semaste 498177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 499177567Semaste 500177557Semaste /* 501177557Semaste * Create DMA tag for mapping buffers into controller-addressable space. 502177557Semaste */ 503177557Semaste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 504177557Semaste 1, 0, /* algnmnt, boundary */ 505177557Semaste (sc->flags & AAC_FLAGS_SG_64BIT) ? 506177557Semaste BUS_SPACE_MAXADDR : 507177557Semaste BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 508177557Semaste BUS_SPACE_MAXADDR, /* highaddr */ 509177557Semaste NULL, NULL, /* filter, filterarg */ 510177557Semaste MAXBSIZE, /* maxsize */ 511177557Semaste sc->aac_sg_tablesize, /* nsegments */ 512177557Semaste MAXBSIZE, /* maxsegsize */ 513177557Semaste BUS_DMA_ALLOCNOW, /* flags */ 514177557Semaste busdma_lock_mutex, /* lockfunc */ 515177557Semaste &sc->aac_io_lock, /* lockfuncarg */ 516177557Semaste &sc->aac_buffer_dmat)) { 517177557Semaste device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 518177557Semaste return (ENOMEM); 519177557Semaste } 520177557Semaste 521177557Semaste /* 522177557Semaste * Create DMA tag for mapping FIBs into controller-addressable space.. 523177557Semaste */ 524177557Semaste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 525177557Semaste 1, 0, /* algnmnt, boundary */ 526177557Semaste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 527177557Semaste BUS_SPACE_MAXADDR_32BIT : 528177557Semaste 0x7fffffff, /* lowaddr */ 529177557Semaste BUS_SPACE_MAXADDR, /* highaddr */ 530177557Semaste NULL, NULL, /* filter, filterarg */ 531177557Semaste sc->aac_max_fibs_alloc * 532177557Semaste sc->aac_max_fib_size, /* maxsize */ 533177557Semaste 1, /* nsegments */ 534177557Semaste sc->aac_max_fibs_alloc * 535177557Semaste sc->aac_max_fib_size, /* maxsize */ 536177557Semaste 0, /* flags */ 537177557Semaste NULL, NULL, /* No locking needed */ 538177557Semaste &sc->aac_fib_dmat)) { 539201758Smbr device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 540177557Semaste return (ENOMEM); 541177557Semaste } 542177557Semaste 543177557Semaste /* 544177557Semaste * Create DMA tag for the common structure and allocate it. 545177557Semaste */ 546177557Semaste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 547177557Semaste 1, 0, /* algnmnt, boundary */ 548177557Semaste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 549177557Semaste BUS_SPACE_MAXADDR_32BIT : 550177557Semaste 0x7fffffff, /* lowaddr */ 551177557Semaste BUS_SPACE_MAXADDR, /* highaddr */ 552177557Semaste NULL, NULL, /* filter, filterarg */ 553177557Semaste 8192 + sizeof(struct aac_common), /* maxsize */ 554177557Semaste 1, /* nsegments */ 555177557Semaste BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 556177557Semaste 0, /* flags */ 557177557Semaste NULL, NULL, /* No locking needed */ 558177557Semaste &sc->aac_common_dmat)) { 559177557Semaste device_printf(sc->aac_dev, 560177557Semaste "can't allocate common structure DMA tag\n"); 561177557Semaste return (ENOMEM); 562177557Semaste } 563177557Semaste if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 564177557Semaste BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 565177557Semaste device_printf(sc->aac_dev, "can't allocate common structure\n"); 566177557Semaste return (ENOMEM); 567177557Semaste } 568177557Semaste 569177557Semaste /* 570177557Semaste * Work around a bug in the 2120 and 2200 that cannot DMA commands 571177557Semaste * below address 8192 in physical memory. 572177557Semaste * XXX If the padding is not needed, can it be put to use instead 573177557Semaste * of ignored? 574177557Semaste */ 575177557Semaste (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 576177557Semaste sc->aac_common, 8192 + sizeof(*sc->aac_common), 577177557Semaste aac_common_map, sc, 0); 578177557Semaste 579177557Semaste if (sc->aac_common_busaddr < 8192) { 580177557Semaste sc->aac_common = (struct aac_common *) 581177557Semaste ((uint8_t *)sc->aac_common + 8192); 582177557Semaste sc->aac_common_busaddr += 8192; 583177557Semaste } 584177557Semaste bzero(sc->aac_common, sizeof(*sc->aac_common)); 585177557Semaste 586177557Semaste /* Allocate some FIBs and associated command structs */ 587177557Semaste TAILQ_INIT(&sc->aac_fibmap_tqh); 588177557Semaste sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 589177557Semaste M_AACBUF, M_WAITOK|M_ZERO); 590200251Sjkim while (sc->total_fibs < sc->aac_max_fibs) { 591177557Semaste if (aac_alloc_commands(sc) != 0) 592177557Semaste break; 593177557Semaste } 594177557Semaste if (sc->total_fibs == 0) 595177557Semaste return (ENOMEM); 596177557Semaste 597177557Semaste return (0); 598177557Semaste} 599177557Semaste 600177557Semaste/* 60165793Smsmith * Free all of the resources associated with (sc) 60265793Smsmith * 60365793Smsmith * Should not be called if the controller is active. 60465793Smsmith */ 60565793Smsmithvoid 60665793Smsmithaac_free(struct aac_softc *sc) 60765793Smsmith{ 608110604Sscottl 609177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 61065793Smsmith 61183114Sscottl /* remove the control device */ 61283114Sscottl if (sc->aac_dev_t != NULL) 61383114Sscottl destroy_dev(sc->aac_dev_t); 61465793Smsmith 61583114Sscottl /* throw away any FIB buffers, discard the FIB DMA tag */ 616111141Sscottl aac_free_commands(sc); 61783114Sscottl if (sc->aac_fib_dmat) 61883114Sscottl bus_dma_tag_destroy(sc->aac_fib_dmat); 61965793Smsmith 620110604Sscottl free(sc->aac_commands, M_AACBUF); 621110604Sscottl 62283114Sscottl /* destroy the common area */ 62383114Sscottl if (sc->aac_common) { 62483114Sscottl bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 62583114Sscottl bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 62683114Sscottl sc->aac_common_dmamap); 62783114Sscottl } 62883114Sscottl if (sc->aac_common_dmat) 62983114Sscottl bus_dma_tag_destroy(sc->aac_common_dmat); 63065793Smsmith 63183114Sscottl /* disconnect the interrupt handler */ 63283114Sscottl if (sc->aac_intr) 63383114Sscottl bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 634264939Smarius if (sc->aac_irq != NULL) { 635251070Smarius bus_release_resource(sc->aac_dev, SYS_RES_IRQ, 636251070Smarius rman_get_rid(sc->aac_irq), sc->aac_irq); 637264939Smarius pci_release_msi(sc->aac_dev); 638264939Smarius } 63965793Smsmith 64083114Sscottl /* destroy data-transfer DMA tag */ 64183114Sscottl if (sc->aac_buffer_dmat) 64283114Sscottl bus_dma_tag_destroy(sc->aac_buffer_dmat); 64365793Smsmith 64483114Sscottl /* destroy the parent DMA tag */ 64583114Sscottl if (sc->aac_parent_dmat) 64683114Sscottl bus_dma_tag_destroy(sc->aac_parent_dmat); 64765793Smsmith 64883114Sscottl /* release the register window mapping */ 649188896Sattilio if (sc->aac_regs_res0 != NULL) 65083114Sscottl bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 651251070Smarius rman_get_rid(sc->aac_regs_res0), sc->aac_regs_res0); 652188896Sattilio if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) 653188896Sattilio bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 654251070Smarius rman_get_rid(sc->aac_regs_res1), sc->aac_regs_res1); 65565793Smsmith} 65665793Smsmith 65783114Sscottl/* 65865793Smsmith * Disconnect from the controller completely, in preparation for unload. 65965793Smsmith */ 66065793Smsmithint 66165793Smsmithaac_detach(device_t dev) 66265793Smsmith{ 66383114Sscottl struct aac_softc *sc; 664110426Sscottl struct aac_container *co; 665110426Sscottl struct aac_sim *sim; 66683114Sscottl int error; 66765793Smsmith 66883114Sscottl sc = device_get_softc(dev); 669177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 67083114Sscottl 671188896Sattilio callout_drain(&sc->aac_daemontime); 672188896Sattilio 673222951Sattilio mtx_lock(&sc->aac_io_lock); 674222951Sattilio while (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 675222951Sattilio sc->aifflags |= AAC_AIFFLAGS_EXIT; 676222951Sattilio wakeup(sc->aifthread); 677222951Sattilio msleep(sc->aac_dev, &sc->aac_io_lock, PUSER, "aacdch", 0); 678222951Sattilio } 679222951Sattilio mtx_unlock(&sc->aac_io_lock); 680222951Sattilio KASSERT((sc->aifflags & AAC_AIFFLAGS_RUNNING) == 0, 681222951Sattilio ("%s: invalid detach state", __func__)); 682222951Sattilio 683110426Sscottl /* Remove the child containers */ 684110428Sscottl while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 685110426Sscottl error = device_delete_child(dev, co->co_disk); 686110426Sscottl if (error) 687110426Sscottl return (error); 688111196Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 689110428Sscottl free(co, M_AACBUF); 690110426Sscottl } 691110426Sscottl 692110426Sscottl /* Remove the CAM SIMs */ 693110428Sscottl while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 694110428Sscottl TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 695110426Sscottl error = device_delete_child(dev, sim->sim_dev); 696110426Sscottl if (error) 697110426Sscottl return (error); 698110428Sscottl free(sim, M_AACBUF); 699110426Sscottl } 700110426Sscottl 70183114Sscottl if ((error = aac_shutdown(dev))) 70283114Sscottl return(error); 70365793Smsmith 704110427Sscottl EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 705110427Sscottl 70683114Sscottl aac_free(sc); 70765793Smsmith 708133542Sscottl mtx_destroy(&sc->aac_aifq_lock); 709133542Sscottl mtx_destroy(&sc->aac_io_lock); 710133542Sscottl mtx_destroy(&sc->aac_container_lock); 711133542Sscottl 71283114Sscottl return(0); 71365793Smsmith} 71465793Smsmith 71583114Sscottl/* 71665793Smsmith * Bring the controller down to a dormant state and detach all child devices. 71765793Smsmith * 71865793Smsmith * This function is called before detach or system shutdown. 71965793Smsmith * 72070393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't 72165793Smsmith * allow shutdown if any device is open. 72265793Smsmith */ 72365793Smsmithint 72465793Smsmithaac_shutdown(device_t dev) 72565793Smsmith{ 72683114Sscottl struct aac_softc *sc; 72795350Sscottl struct aac_fib *fib; 72895350Sscottl struct aac_close_command *cc; 72965793Smsmith 73083114Sscottl sc = device_get_softc(dev); 731177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 73265793Smsmith 73383114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 73465793Smsmith 735152388Sschweikh /* 73683114Sscottl * Send a Container shutdown followed by a HostShutdown FIB to the 73783114Sscottl * controller to convince it that we don't want to talk to it anymore. 73883114Sscottl * We've been closed and all I/O completed already 73982527Sscottl */ 74083114Sscottl device_printf(sc->aac_dev, "shutting down controller..."); 74183114Sscottl 742151086Sscottl mtx_lock(&sc->aac_io_lock); 743130006Sscottl aac_alloc_sync_fib(sc, &fib); 74495350Sscottl cc = (struct aac_close_command *)&fib->data[0]; 74595350Sscottl 74695966Sscottl bzero(cc, sizeof(struct aac_close_command)); 74795350Sscottl cc->Command = VM_CloseAll; 74895350Sscottl cc->ContainerId = 0xffffffff; 74995350Sscottl if (aac_sync_fib(sc, ContainerCommand, 0, fib, 75095350Sscottl sizeof(struct aac_close_command))) 75183114Sscottl printf("FAILED.\n"); 752110426Sscottl else 753110426Sscottl printf("done\n"); 754110426Sscottl#if 0 75583114Sscottl else { 75695350Sscottl fib->data[0] = 0; 75783114Sscottl /* 75883114Sscottl * XXX Issuing this command to the controller makes it shut down 75983114Sscottl * but also keeps it from coming back up without a reset of the 76083114Sscottl * PCI bus. This is not desirable if you are just unloading the 76183114Sscottl * driver module with the intent to reload it later. 76283114Sscottl */ 76395350Sscottl if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 76495350Sscottl fib, 1)) { 76583114Sscottl printf("FAILED.\n"); 76683114Sscottl } else { 76783114Sscottl printf("done.\n"); 76883114Sscottl } 76965793Smsmith } 770110426Sscottl#endif 77165793Smsmith 77283114Sscottl AAC_MASK_INTERRUPTS(sc); 773133539Sscottl aac_release_sync_fib(sc); 774151086Sscottl mtx_unlock(&sc->aac_io_lock); 77565793Smsmith 77683114Sscottl return(0); 77765793Smsmith} 77865793Smsmith 77983114Sscottl/* 78065793Smsmith * Bring the controller to a quiescent state, ready for system suspend. 78165793Smsmith */ 78265793Smsmithint 78365793Smsmithaac_suspend(device_t dev) 78465793Smsmith{ 78583114Sscottl struct aac_softc *sc; 78665793Smsmith 78783114Sscottl sc = device_get_softc(dev); 78883114Sscottl 789177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 79083114Sscottl sc->aac_state |= AAC_STATE_SUSPEND; 791152388Sschweikh 79283114Sscottl AAC_MASK_INTERRUPTS(sc); 79383114Sscottl return(0); 79465793Smsmith} 79565793Smsmith 79683114Sscottl/* 79765793Smsmith * Bring the controller back to a state ready for operation. 79865793Smsmith */ 79965793Smsmithint 80065793Smsmithaac_resume(device_t dev) 80165793Smsmith{ 80283114Sscottl struct aac_softc *sc; 80365793Smsmith 80483114Sscottl sc = device_get_softc(dev); 80583114Sscottl 806177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 80783114Sscottl sc->aac_state &= ~AAC_STATE_SUSPEND; 80883114Sscottl AAC_UNMASK_INTERRUPTS(sc); 80983114Sscottl return(0); 81065793Smsmith} 81165793Smsmith 81283114Sscottl/* 813151086Sscottl * Interrupt handler for NEW_COMM interface. 81465793Smsmith */ 81565793Smsmithvoid 816151086Sscottlaac_new_intr(void *arg) 81765793Smsmith{ 81883114Sscottl struct aac_softc *sc; 819151086Sscottl u_int32_t index, fast; 820151086Sscottl struct aac_command *cm; 821151086Sscottl struct aac_fib *fib; 822151086Sscottl int i; 823151086Sscottl 824151086Sscottl sc = (struct aac_softc *)arg; 825151086Sscottl 826177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 827151086Sscottl mtx_lock(&sc->aac_io_lock); 828151086Sscottl while (1) { 829151086Sscottl index = AAC_GET_OUTB_QUEUE(sc); 830151086Sscottl if (index == 0xffffffff) 831151086Sscottl index = AAC_GET_OUTB_QUEUE(sc); 832151086Sscottl if (index == 0xffffffff) 833151086Sscottl break; 834151086Sscottl if (index & 2) { 835151086Sscottl if (index == 0xfffffffe) { 836151086Sscottl /* XXX This means that the controller wants 837151086Sscottl * more work. Ignore it for now. 838151086Sscottl */ 839151086Sscottl continue; 840151086Sscottl } 841151086Sscottl /* AIF */ 842151086Sscottl fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 843151086Sscottl M_NOWAIT | M_ZERO); 844151086Sscottl if (fib == NULL) { 845151086Sscottl /* If we're really this short on memory, 846151086Sscottl * hopefully breaking out of the handler will 847151086Sscottl * allow something to get freed. This 848151086Sscottl * actually sucks a whole lot. 849151086Sscottl */ 850151086Sscottl break; 851151086Sscottl } 852151086Sscottl index &= ~2; 853151086Sscottl for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 854188896Sattilio ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); 855151086Sscottl aac_handle_aif(sc, fib); 856151086Sscottl free(fib, M_AACBUF); 857151086Sscottl 858151086Sscottl /* 859151086Sscottl * AIF memory is owned by the adapter, so let it 860151086Sscottl * know that we are done with it. 861151086Sscottl */ 862151086Sscottl AAC_SET_OUTB_QUEUE(sc, index); 863151086Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 864151086Sscottl } else { 865151086Sscottl fast = index & 1; 866151086Sscottl cm = sc->aac_commands + (index >> 2); 867151086Sscottl fib = cm->cm_fib; 868151086Sscottl if (fast) { 869151086Sscottl fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 870151086Sscottl *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 871151086Sscottl } 872151086Sscottl aac_remove_busy(cm); 873151086Sscottl aac_unmap_command(cm); 874151086Sscottl cm->cm_flags |= AAC_CMD_COMPLETED; 875151086Sscottl 876151086Sscottl /* is there a completion handler? */ 877151086Sscottl if (cm->cm_complete != NULL) { 878151086Sscottl cm->cm_complete(cm); 879151086Sscottl } else { 880151086Sscottl /* assume that someone is sleeping on this 881151086Sscottl * command 882151086Sscottl */ 883151086Sscottl wakeup(cm); 884151086Sscottl } 885151086Sscottl sc->flags &= ~AAC_QUEUE_FRZN; 886151086Sscottl } 887151086Sscottl } 888151086Sscottl /* see if we can start some more I/O */ 889151086Sscottl if ((sc->flags & AAC_QUEUE_FRZN) == 0) 890151086Sscottl aac_startio(sc); 891151086Sscottl 892151086Sscottl mtx_unlock(&sc->aac_io_lock); 893151086Sscottl} 894151086Sscottl 895198593Semaste/* 896198593Semaste * Interrupt filter for !NEW_COMM interface. 897198593Semaste */ 898166901Spisoint 899198593Semasteaac_filter(void *arg) 900151086Sscottl{ 901151086Sscottl struct aac_softc *sc; 90283114Sscottl u_int16_t reason; 90365793Smsmith 90483114Sscottl sc = (struct aac_softc *)arg; 90565793Smsmith 906177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 907109088Sscottl /* 908125225Sscottl * Read the status register directly. This is faster than taking the 909125225Sscottl * driver lock and reading the queues directly. It also saves having 910125225Sscottl * to turn parts of the driver lock into a spin mutex, which would be 911125225Sscottl * ugly. 912109088Sscottl */ 913125225Sscottl reason = AAC_GET_ISTATUS(sc); 914109088Sscottl AAC_CLEAR_ISTATUS(sc, reason); 91565793Smsmith 916125225Sscottl /* handle completion processing */ 917109088Sscottl if (reason & AAC_DB_RESPONSE_READY) 918125225Sscottl taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 919109088Sscottl 920125225Sscottl /* controller wants to talk to us */ 921125225Sscottl if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 922125225Sscottl /* 923125225Sscottl * XXX Make sure that we don't get fooled by strange messages 924125225Sscottl * that start with a NULL. 925125225Sscottl */ 926125225Sscottl if ((reason & AAC_DB_PRINTF) && 927151086Sscottl (sc->aac_common->ac_printf[0] == 0)) 928125225Sscottl sc->aac_common->ac_printf[0] = 32; 92965793Smsmith 930125225Sscottl /* 931125225Sscottl * This might miss doing the actual wakeup. However, the 932125542Sscottl * msleep that this is waking up has a timeout, so it will 933125225Sscottl * wake up eventually. AIFs and printfs are low enough 934125225Sscottl * priority that they can handle hanging out for a few seconds 935125225Sscottl * if needed. 936125225Sscottl */ 937125225Sscottl wakeup(sc->aifthread); 93883114Sscottl } 939166901Spiso return (FILTER_HANDLED); 940109088Sscottl} 94183114Sscottl 94283114Sscottl/* 94383114Sscottl * Command Processing 94483114Sscottl */ 94565793Smsmith 94683114Sscottl/* 94765793Smsmith * Start as much queued I/O as possible on the controller 94865793Smsmith */ 94995536Sscottlvoid 95065793Smsmithaac_startio(struct aac_softc *sc) 95165793Smsmith{ 95283114Sscottl struct aac_command *cm; 953129923Sscottl int error; 95465793Smsmith 955177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 95665793Smsmith 95783114Sscottl for (;;) { 95883114Sscottl /* 959129923Sscottl * This flag might be set if the card is out of resources. 960129923Sscottl * Checking it here prevents an infinite loop of deferrals. 961129923Sscottl */ 962129923Sscottl if (sc->flags & AAC_QUEUE_FRZN) 963129923Sscottl break; 964129923Sscottl 965129923Sscottl /* 966152388Sschweikh * Try to get a command that's been put off for lack of 96783114Sscottl * resources 96883114Sscottl */ 96983114Sscottl cm = aac_dequeue_ready(sc); 97065793Smsmith 97183114Sscottl /* 972152388Sschweikh * Try to build a command off the bio queue (ignore error 97383114Sscottl * return) 97483114Sscottl */ 97583114Sscottl if (cm == NULL) 97683114Sscottl aac_bio_command(sc, &cm); 97765793Smsmith 97883114Sscottl /* nothing to do? */ 97983114Sscottl if (cm == NULL) 98083114Sscottl break; 98165793Smsmith 982129923Sscottl /* don't map more than once */ 983129923Sscottl if (cm->cm_flags & AAC_CMD_MAPPED) 984129923Sscottl panic("aac: command %p already mapped", cm); 985129923Sscottl 986125559Sscottl /* 987129923Sscottl * Set up the command to go to the controller. If there are no 988129923Sscottl * data buffers associated with the command then it can bypass 989129923Sscottl * busdma. 990125559Sscottl */ 991129923Sscottl if (cm->cm_datalen != 0) { 992251941Smarius if (cm->cm_flags & AAC_REQ_BIO) 993251941Smarius error = bus_dmamap_load_bio( 994251941Smarius sc->aac_buffer_dmat, cm->cm_datamap, 995251941Smarius (struct bio *)cm->cm_private, 996251941Smarius aac_map_command_sg, cm, 0); 997251941Smarius else 998251941Smarius error = bus_dmamap_load(sc->aac_buffer_dmat, 999251941Smarius cm->cm_datamap, cm->cm_data, 1000251941Smarius cm->cm_datalen, aac_map_command_sg, cm, 0); 1001129923Sscottl if (error == EINPROGRESS) { 1002177567Semaste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); 1003129923Sscottl sc->flags |= AAC_QUEUE_FRZN; 1004129946Sscottl } else if (error != 0) 1005129923Sscottl panic("aac_startio: unexpected error %d from " 1006177635Semaste "busdma", error); 1007129923Sscottl } else 1008129923Sscottl aac_map_command_sg(cm, NULL, 0, 0); 100965793Smsmith } 101065793Smsmith} 101165793Smsmith 101283114Sscottl/* 101365793Smsmith * Handle notification of one or more FIBs coming from the controller. 101465793Smsmith */ 101565793Smsmithstatic void 1016110426Sscottlaac_command_thread(struct aac_softc *sc) 101765793Smsmith{ 101883114Sscottl struct aac_fib *fib; 101983114Sscottl u_int32_t fib_size; 1020125225Sscottl int size, retval; 102165793Smsmith 1022177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 102365793Smsmith 1024133540Sscottl mtx_lock(&sc->aac_io_lock); 1025125542Sscottl sc->aifflags = AAC_AIFFLAGS_RUNNING; 102665793Smsmith 1027125542Sscottl while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 102882527Sscottl 1029125542Sscottl retval = 0; 1030125542Sscottl if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1031125542Sscottl retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1032125542Sscottl "aifthd", AAC_PERIODIC_INTERVAL * hz); 1033125542Sscottl 1034125225Sscottl /* 1035125225Sscottl * First see if any FIBs need to be allocated. This needs 1036125225Sscottl * to be called without the driver lock because contigmalloc 1037222951Sattilio * can sleep. 1038125225Sscottl */ 1039125225Sscottl if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1040133540Sscottl mtx_unlock(&sc->aac_io_lock); 1041125225Sscottl aac_alloc_commands(sc); 1042133540Sscottl mtx_lock(&sc->aac_io_lock); 1043125559Sscottl sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1044125542Sscottl aac_startio(sc); 1045125225Sscottl } 1046125225Sscottl 1047125225Sscottl /* 1048125225Sscottl * While we're here, check to see if any commands are stuck. 1049125225Sscottl * This is pretty low-priority, so it's ok if it doesn't 1050125225Sscottl * always fire. 1051125225Sscottl */ 1052125225Sscottl if (retval == EWOULDBLOCK) 1053110426Sscottl aac_timeout(sc); 1054110426Sscottl 1055110426Sscottl /* Check the hardware printf message buffer */ 1056125225Sscottl if (sc->aac_common->ac_printf[0] != 0) 1057110426Sscottl aac_print_printf(sc); 1058110426Sscottl 1059125225Sscottl /* Also check to see if the adapter has a command for us. */ 1060151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 1061151086Sscottl continue; 1062151086Sscottl for (;;) { 1063151086Sscottl if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 1064152388Sschweikh &fib_size, &fib)) 1065151086Sscottl break; 1066152388Sschweikh 106783114Sscottl AAC_PRINT_FIB(sc, fib); 1068152388Sschweikh 106983114Sscottl switch (fib->Header.Command) { 107083114Sscottl case AifRequest: 107183114Sscottl aac_handle_aif(sc, fib); 107283114Sscottl break; 107383114Sscottl default: 107483114Sscottl device_printf(sc->aac_dev, "unknown command " 107583114Sscottl "from controller\n"); 107683114Sscottl break; 107783114Sscottl } 107882527Sscottl 107983114Sscottl if ((fib->Header.XferState == 0) || 1080151086Sscottl (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 108183114Sscottl break; 1082151086Sscottl } 108382527Sscottl 1084110426Sscottl /* Return the AIF to the controller. */ 108583114Sscottl if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 108683114Sscottl fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 108783114Sscottl *(AAC_FSAStatus*)fib->data = ST_OK; 108882527Sscottl 108983114Sscottl /* XXX Compute the Size field? */ 109083114Sscottl size = fib->Header.Size; 109183114Sscottl if (size > sizeof(struct aac_fib)) { 109295536Sscottl size = sizeof(struct aac_fib); 109383114Sscottl fib->Header.Size = size; 109483114Sscottl } 109583114Sscottl /* 109683114Sscottl * Since we did not generate this command, it 109783114Sscottl * cannot go through the normal 109883114Sscottl * enqueue->startio chain. 109983114Sscottl */ 110083114Sscottl aac_enqueue_response(sc, 1101151086Sscottl AAC_ADAP_NORM_RESP_QUEUE, 1102151086Sscottl fib); 110383114Sscottl } 110482527Sscottl } 110565793Smsmith } 110683114Sscottl sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1107133540Sscottl mtx_unlock(&sc->aac_io_lock); 110883114Sscottl wakeup(sc->aac_dev); 110965793Smsmith 1110172836Sjulian kproc_exit(0); 111165793Smsmith} 111265793Smsmith 111383114Sscottl/* 1114111143Sscottl * Process completed commands. 111565793Smsmith */ 111665793Smsmithstatic void 1117111143Sscottlaac_complete(void *context, int pending) 111865793Smsmith{ 1119111143Sscottl struct aac_softc *sc; 112083114Sscottl struct aac_command *cm; 112183114Sscottl struct aac_fib *fib; 112283114Sscottl u_int32_t fib_size; 112365793Smsmith 1124111143Sscottl sc = (struct aac_softc *)context; 1125177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1126111143Sscottl 1127133540Sscottl mtx_lock(&sc->aac_io_lock); 1128111532Sscottl 1129111143Sscottl /* pull completed commands off the queue */ 113083114Sscottl for (;;) { 113183114Sscottl /* look for completed FIBs on our queue */ 113283114Sscottl if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1133151086Sscottl &fib)) 113483114Sscottl break; /* nothing to do */ 1135111143Sscottl 1136125574Sscottl /* get the command, unmap and hand off for processing */ 1137111152Sscottl cm = sc->aac_commands + fib->Header.SenderData; 113883114Sscottl if (cm == NULL) { 113983114Sscottl AAC_PRINT_FIB(sc, fib); 1140111143Sscottl break; 114183114Sscottl } 1142212594Semaste if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0) 1143212594Semaste device_printf(sc->aac_dev, 1144212594Semaste "COMMAND %p COMPLETED AFTER %d SECONDS\n", 1145212594Semaste cm, (int)(time_uptime-cm->cm_timestamp)); 1146212594Semaste 1147151086Sscottl aac_remove_busy(cm); 114865793Smsmith 1149151086Sscottl aac_unmap_command(cm); 115083114Sscottl cm->cm_flags |= AAC_CMD_COMPLETED; 115183114Sscottl 115283114Sscottl /* is there a completion handler? */ 115383114Sscottl if (cm->cm_complete != NULL) { 115483114Sscottl cm->cm_complete(cm); 115583114Sscottl } else { 115683114Sscottl /* assume that someone is sleeping on this command */ 115783114Sscottl wakeup(cm); 115883114Sscottl } 115965793Smsmith } 116070393Smsmith 116183114Sscottl /* see if we can start some more I/O */ 1162117363Sscottl sc->flags &= ~AAC_QUEUE_FRZN; 116383114Sscottl aac_startio(sc); 1164111532Sscottl 1165133540Sscottl mtx_unlock(&sc->aac_io_lock); 116665793Smsmith} 116765793Smsmith 116883114Sscottl/* 116965793Smsmith * Handle a bio submitted from a disk device. 117065793Smsmith */ 117165793Smsmithvoid 117265793Smsmithaac_submit_bio(struct bio *bp) 117365793Smsmith{ 117483114Sscottl struct aac_disk *ad; 117583114Sscottl struct aac_softc *sc; 117665793Smsmith 1177111525Sscottl ad = (struct aac_disk *)bp->bio_disk->d_drv1; 117883114Sscottl sc = ad->ad_controller; 1179177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 118083114Sscottl 118183114Sscottl /* queue the BIO and try to get some work done */ 118283114Sscottl aac_enqueue_bio(sc, bp); 118383114Sscottl aac_startio(sc); 118465793Smsmith} 118565793Smsmith 118683114Sscottl/* 118765793Smsmith * Get a bio and build a command to go with it. 118865793Smsmith */ 118965793Smsmithstatic int 119065793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 119165793Smsmith{ 119283114Sscottl struct aac_command *cm; 119383114Sscottl struct aac_fib *fib; 119483114Sscottl struct aac_disk *ad; 119583114Sscottl struct bio *bp; 119665793Smsmith 1197177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 119865793Smsmith 119983114Sscottl /* get the resources we will need */ 120083114Sscottl cm = NULL; 1201125542Sscottl bp = NULL; 1202125542Sscottl if (aac_alloc_command(sc, &cm)) /* get a command */ 1203125542Sscottl goto fail; 120483114Sscottl if ((bp = aac_dequeue_bio(sc)) == NULL) 120583114Sscottl goto fail; 120665793Smsmith 120783114Sscottl /* fill out the command */ 120883114Sscottl cm->cm_datalen = bp->bio_bcount; 120983114Sscottl cm->cm_complete = aac_bio_complete; 1210251941Smarius cm->cm_flags = AAC_REQ_BIO; 121183114Sscottl cm->cm_private = bp; 1212150119Sscottl cm->cm_timestamp = time_uptime; 121365793Smsmith 121483114Sscottl /* build the FIB */ 121583114Sscottl fib = cm->cm_fib; 1216112856Sscottl fib->Header.Size = sizeof(struct aac_fib_header); 1217152388Sschweikh fib->Header.XferState = 1218152388Sschweikh AAC_FIBSTATE_HOSTOWNED | 1219152388Sschweikh AAC_FIBSTATE_INITIALISED | 1220152388Sschweikh AAC_FIBSTATE_EMPTY | 1221109088Sscottl AAC_FIBSTATE_FROMHOST | 1222109088Sscottl AAC_FIBSTATE_REXPECTED | 1223109088Sscottl AAC_FIBSTATE_NORM | 1224109088Sscottl AAC_FIBSTATE_ASYNC | 1225109088Sscottl AAC_FIBSTATE_FAST_RESPONSE; 122665793Smsmith 122783114Sscottl /* build the read/write request */ 1228111525Sscottl ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1229112856Sscottl 1230151086Sscottl if (sc->flags & AAC_FLAGS_RAW_IO) { 1231151086Sscottl struct aac_raw_io *raw; 1232151086Sscottl raw = (struct aac_raw_io *)&fib->data[0]; 1233151086Sscottl fib->Header.Command = RawIo; 1234151086Sscottl raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 1235151086Sscottl raw->ByteCount = bp->bio_bcount; 1236151086Sscottl raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1237151086Sscottl raw->BpTotal = 0; 1238151086Sscottl raw->BpComplete = 0; 1239151086Sscottl fib->Header.Size += sizeof(struct aac_raw_io); 1240151086Sscottl cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 1241151086Sscottl if (bp->bio_cmd == BIO_READ) { 1242151086Sscottl raw->Flags = 1; 1243151086Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 1244151086Sscottl } else { 1245151086Sscottl raw->Flags = 0; 1246151086Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 1247151086Sscottl } 1248151086Sscottl } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1249112856Sscottl fib->Header.Command = ContainerCommand; 1250112856Sscottl if (bp->bio_cmd == BIO_READ) { 1251112856Sscottl struct aac_blockread *br; 1252112856Sscottl br = (struct aac_blockread *)&fib->data[0]; 1253112856Sscottl br->Command = VM_CtBlockRead; 1254112856Sscottl br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1255112856Sscottl br->BlockNumber = bp->bio_pblkno; 1256112856Sscottl br->ByteCount = bp->bio_bcount; 1257112856Sscottl fib->Header.Size += sizeof(struct aac_blockread); 1258112856Sscottl cm->cm_sgtable = &br->SgMap; 1259112856Sscottl cm->cm_flags |= AAC_CMD_DATAIN; 1260112856Sscottl } else { 1261112856Sscottl struct aac_blockwrite *bw; 1262112856Sscottl bw = (struct aac_blockwrite *)&fib->data[0]; 1263112856Sscottl bw->Command = VM_CtBlockWrite; 1264112856Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1265112856Sscottl bw->BlockNumber = bp->bio_pblkno; 1266112856Sscottl bw->ByteCount = bp->bio_bcount; 1267112856Sscottl bw->Stable = CUNSTABLE; 1268112856Sscottl fib->Header.Size += sizeof(struct aac_blockwrite); 1269112856Sscottl cm->cm_flags |= AAC_CMD_DATAOUT; 1270112856Sscottl cm->cm_sgtable = &bw->SgMap; 1271112856Sscottl } 127283114Sscottl } else { 1273112856Sscottl fib->Header.Command = ContainerCommand64; 1274112856Sscottl if (bp->bio_cmd == BIO_READ) { 1275112856Sscottl struct aac_blockread64 *br; 1276112856Sscottl br = (struct aac_blockread64 *)&fib->data[0]; 1277112856Sscottl br->Command = VM_CtHostRead64; 1278112856Sscottl br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1279112856Sscottl br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1280112856Sscottl br->BlockNumber = bp->bio_pblkno; 1281112856Sscottl br->Pad = 0; 1282112856Sscottl br->Flags = 0; 1283112856Sscottl fib->Header.Size += sizeof(struct aac_blockread64); 1284177611Semaste cm->cm_flags |= AAC_CMD_DATAIN; 1285132771Skan cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1286112856Sscottl } else { 1287112856Sscottl struct aac_blockwrite64 *bw; 1288112856Sscottl bw = (struct aac_blockwrite64 *)&fib->data[0]; 1289112856Sscottl bw->Command = VM_CtHostWrite64; 1290112856Sscottl bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1291112856Sscottl bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1292112856Sscottl bw->BlockNumber = bp->bio_pblkno; 1293112856Sscottl bw->Pad = 0; 1294112856Sscottl bw->Flags = 0; 1295112856Sscottl fib->Header.Size += sizeof(struct aac_blockwrite64); 1296177611Semaste cm->cm_flags |= AAC_CMD_DATAOUT; 1297132771Skan cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1298112856Sscottl } 129983114Sscottl } 130065793Smsmith 130183114Sscottl *cmp = cm; 130283114Sscottl return(0); 130365793Smsmith 130465793Smsmithfail: 1305151086Sscottl if (bp != NULL) 1306151086Sscottl aac_enqueue_bio(sc, bp); 130783114Sscottl if (cm != NULL) 130883114Sscottl aac_release_command(cm); 130983114Sscottl return(ENOMEM); 131065793Smsmith} 131165793Smsmith 131283114Sscottl/* 131365793Smsmith * Handle a bio-instigated command that has been completed. 131465793Smsmith */ 131565793Smsmithstatic void 131665793Smsmithaac_bio_complete(struct aac_command *cm) 131765793Smsmith{ 131883114Sscottl struct aac_blockread_response *brr; 131983114Sscottl struct aac_blockwrite_response *bwr; 132083114Sscottl struct bio *bp; 132183114Sscottl AAC_FSAStatus status; 132265793Smsmith 132383114Sscottl /* fetch relevant status and then release the command */ 132483114Sscottl bp = (struct bio *)cm->cm_private; 1325111691Sscottl if (bp->bio_cmd == BIO_READ) { 132683114Sscottl brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 132783114Sscottl status = brr->Status; 132883114Sscottl } else { 132983114Sscottl bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 133083114Sscottl status = bwr->Status; 133183114Sscottl } 133283114Sscottl aac_release_command(cm); 133365793Smsmith 133483114Sscottl /* fix up the bio based on status */ 133583114Sscottl if (status == ST_OK) { 133683114Sscottl bp->bio_resid = 0; 133783114Sscottl } else { 133883114Sscottl bp->bio_error = EIO; 133983114Sscottl bp->bio_flags |= BIO_ERROR; 134083114Sscottl } 134183114Sscottl aac_biodone(bp); 134265793Smsmith} 134365793Smsmith 134483114Sscottl/* 134565793Smsmith * Submit a command to the controller, return when it completes. 134687183Sscottl * XXX This is very dangerous! If the card has gone out to lunch, we could 134787183Sscottl * be stuck here forever. At the same time, signals are not caught 1348128258Sscottl * because there is a risk that a signal could wakeup the sleep before 1349128258Sscottl * the card has a chance to complete the command. Since there is no way 1350128258Sscottl * to cancel a command that is in progress, we can't protect against the 1351128258Sscottl * card completing a command late and spamming the command and data 1352128258Sscottl * memory. So, we are held hostage until the command completes. 135365793Smsmith */ 135465793Smsmithstatic int 1355128258Sscottlaac_wait_command(struct aac_command *cm) 135665793Smsmith{ 1357111532Sscottl struct aac_softc *sc; 1358128258Sscottl int error; 135965793Smsmith 1360111532Sscottl sc = cm->cm_sc; 1361177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1362111532Sscottl 136383114Sscottl /* Put the command on the ready queue and get things going */ 136483114Sscottl aac_enqueue_ready(cm); 1365111532Sscottl aac_startio(sc); 1366128258Sscottl error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 136783114Sscottl return(error); 136865793Smsmith} 136965793Smsmith 137083114Sscottl/* 137183114Sscottl *Command Buffer Management 137283114Sscottl */ 137365793Smsmith 137483114Sscottl/* 137565793Smsmith * Allocate a command. 137665793Smsmith */ 137795536Sscottlint 137865793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 137965793Smsmith{ 138083114Sscottl struct aac_command *cm; 138165793Smsmith 1382177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 138365793Smsmith 1384110604Sscottl if ((cm = aac_dequeue_free(sc)) == NULL) { 1385112856Sscottl if (sc->total_fibs < sc->aac_max_fibs) { 1386222951Sattilio mtx_lock(&sc->aac_io_lock); 1387112856Sscottl sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1388222951Sattilio mtx_unlock(&sc->aac_io_lock); 1389112856Sscottl wakeup(sc->aifthread); 1390112856Sscottl } 1391111532Sscottl return (EBUSY); 1392110604Sscottl } 139365793Smsmith 139483114Sscottl *cmp = cm; 139583114Sscottl return(0); 139670393Smsmith} 139770393Smsmith 139883114Sscottl/* 139970393Smsmith * Release a command back to the freelist. 140070393Smsmith */ 140195536Sscottlvoid 140270393Smsmithaac_release_command(struct aac_command *cm) 140370393Smsmith{ 1404151086Sscottl struct aac_event *event; 1405151086Sscottl struct aac_softc *sc; 1406151086Sscottl 1407177567Semaste sc = cm->cm_sc; 1408177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 140970393Smsmith 1410177184Semaste /* (re)initialize the command/FIB */ 1411267076Sjhb cm->cm_datalen = 0; 141283114Sscottl cm->cm_sgtable = NULL; 141383114Sscottl cm->cm_flags = 0; 141483114Sscottl cm->cm_complete = NULL; 141583114Sscottl cm->cm_private = NULL; 1416204264Semaste cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 141783114Sscottl cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 141883114Sscottl cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 141983114Sscottl cm->cm_fib->Header.Flags = 0; 1420151086Sscottl cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 142165793Smsmith 1422152388Sschweikh /* 142383114Sscottl * These are duplicated in aac_start to cover the case where an 142483114Sscottl * intermediate stage may have destroyed them. They're left 1425177184Semaste * initialized here for debugging purposes only. 142683114Sscottl */ 1427109088Sscottl cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1428109088Sscottl cm->cm_fib->Header.SenderData = 0; 142965793Smsmith 143083114Sscottl aac_enqueue_free(cm); 1431151086Sscottl 1432218207Semaste if ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 1433151086Sscottl TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1434151086Sscottl event->ev_callback(sc, event, event->ev_arg); 1435151086Sscottl } 143665793Smsmith} 143765793Smsmith 143883114Sscottl/* 143970393Smsmith * Map helper for command/FIB allocation. 144065793Smsmith */ 144165793Smsmithstatic void 144270393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 144365793Smsmith{ 1444151086Sscottl uint64_t *fibphys; 144565793Smsmith 1446151086Sscottl fibphys = (uint64_t *)arg; 144765793Smsmith 1448110604Sscottl *fibphys = segs[0].ds_addr; 144965793Smsmith} 145065793Smsmith 145183114Sscottl/* 1452177184Semaste * Allocate and initialize commands/FIBs for this adapter. 145365793Smsmith */ 145470393Smsmithstatic int 145570393Smsmithaac_alloc_commands(struct aac_softc *sc) 145665793Smsmith{ 145783114Sscottl struct aac_command *cm; 1458110604Sscottl struct aac_fibmap *fm; 1459151086Sscottl uint64_t fibphys; 1460110604Sscottl int i, error; 1461152388Sschweikh 1462177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 146365793Smsmith 1464151086Sscottl if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1465110604Sscottl return (ENOMEM); 1466110604Sscottl 1467111141Sscottl fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1468112679Sscottl if (fm == NULL) 1469112679Sscottl return (ENOMEM); 1470110604Sscottl 147183114Sscottl /* allocate the FIBs in DMAable memory and load them */ 1472110604Sscottl if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1473110604Sscottl BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1474110426Sscottl device_printf(sc->aac_dev, 1475110426Sscottl "Not enough contiguous memory available.\n"); 1476111141Sscottl free(fm, M_AACBUF); 1477102602Sscottl return (ENOMEM); 147883114Sscottl } 1479109716Sscottl 1480117363Sscottl /* Ignore errors since this doesn't bounce */ 1481152388Sschweikh (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1482151086Sscottl sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1483117363Sscottl aac_map_command_helper, &fibphys, 0); 1484109716Sscottl 1485177184Semaste /* initialize constant fields in the command structure */ 1486151086Sscottl bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 1487151086Sscottl for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1488111141Sscottl cm = sc->aac_commands + sc->total_fibs; 1489110604Sscottl fm->aac_commands = cm; 149083114Sscottl cm->cm_sc = sc; 1491151086Sscottl cm->cm_fib = (struct aac_fib *) 1492151086Sscottl ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 1493151086Sscottl cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1494111152Sscottl cm->cm_index = sc->total_fibs; 149565793Smsmith 1496110604Sscottl if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1497157587Sscottl &cm->cm_datamap)) != 0) 1498111141Sscottl break; 1499157587Sscottl mtx_lock(&sc->aac_io_lock); 1500157587Sscottl aac_release_command(cm); 1501111141Sscottl sc->total_fibs++; 1502157587Sscottl mtx_unlock(&sc->aac_io_lock); 150383114Sscottl } 1504110604Sscottl 1505111141Sscottl if (i > 0) { 1506157587Sscottl mtx_lock(&sc->aac_io_lock); 1507111141Sscottl TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1508177567Semaste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1509133540Sscottl mtx_unlock(&sc->aac_io_lock); 1510111141Sscottl return (0); 1511152388Sschweikh } 1512110604Sscottl 1513111141Sscottl bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1514111141Sscottl bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1515111141Sscottl free(fm, M_AACBUF); 1516111141Sscottl return (ENOMEM); 151765793Smsmith} 151865793Smsmith 151983114Sscottl/* 152070393Smsmith * Free FIBs owned by this adapter. 152165793Smsmith */ 152265793Smsmithstatic void 1523111141Sscottlaac_free_commands(struct aac_softc *sc) 152465793Smsmith{ 1525111141Sscottl struct aac_fibmap *fm; 1526110604Sscottl struct aac_command *cm; 152783114Sscottl int i; 152865793Smsmith 1529177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 153065793Smsmith 1531111141Sscottl while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1532111141Sscottl 1533111141Sscottl TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1534111141Sscottl /* 1535111141Sscottl * We check against total_fibs to handle partially 1536111141Sscottl * allocated blocks. 1537111141Sscottl */ 1538151086Sscottl for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1539111141Sscottl cm = fm->aac_commands + i; 1540111141Sscottl bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1541111141Sscottl } 1542111141Sscottl bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1543111141Sscottl bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1544111141Sscottl free(fm, M_AACBUF); 1545110604Sscottl } 154665793Smsmith} 154765793Smsmith 154883114Sscottl/* 154965793Smsmith * Command-mapping helper function - populate this command's s/g table. 155065793Smsmith */ 155165793Smsmithstatic void 155265793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 155365793Smsmith{ 1554117363Sscottl struct aac_softc *sc; 155583114Sscottl struct aac_command *cm; 155683114Sscottl struct aac_fib *fib; 155783114Sscottl int i; 155865793Smsmith 155983114Sscottl cm = (struct aac_command *)arg; 1560117363Sscottl sc = cm->cm_sc; 156183114Sscottl fib = cm->cm_fib; 1562177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 156365793Smsmith 156483114Sscottl /* copy into the FIB */ 1565112856Sscottl if (cm->cm_sgtable != NULL) { 1566151086Sscottl if (fib->Header.Command == RawIo) { 1567151086Sscottl struct aac_sg_tableraw *sg; 1568151086Sscottl sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1569151086Sscottl sg->SgCount = nseg; 1570151086Sscottl for (i = 0; i < nseg; i++) { 1571151086Sscottl sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1572151086Sscottl sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1573151086Sscottl sg->SgEntryRaw[i].Next = 0; 1574151086Sscottl sg->SgEntryRaw[i].Prev = 0; 1575151086Sscottl sg->SgEntryRaw[i].Flags = 0; 1576151086Sscottl } 1577151086Sscottl /* update the FIB size for the s/g count */ 1578151086Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1579151086Sscottl } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1580112856Sscottl struct aac_sg_table *sg; 1581112856Sscottl sg = cm->cm_sgtable; 1582112856Sscottl sg->SgCount = nseg; 1583112856Sscottl for (i = 0; i < nseg; i++) { 1584112856Sscottl sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1585112856Sscottl sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1586112856Sscottl } 1587112856Sscottl /* update the FIB size for the s/g count */ 1588151086Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1589112856Sscottl } else { 1590112856Sscottl struct aac_sg_table64 *sg; 1591112856Sscottl sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1592112856Sscottl sg->SgCount = nseg; 1593112856Sscottl for (i = 0; i < nseg; i++) { 1594112856Sscottl sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1595112856Sscottl sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1596112856Sscottl } 1597112856Sscottl /* update the FIB size for the s/g count */ 1598112856Sscottl fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 159983114Sscottl } 160065793Smsmith } 160165793Smsmith 1602117363Sscottl /* Fix up the address values in the FIB. Use the command array index 1603117363Sscottl * instead of a pointer since these fields are only 32 bits. Shift 1604152388Sschweikh * the SenderFibAddress over to make room for the fast response bit 1605151086Sscottl * and for the AIF bit 1606117363Sscottl */ 1607151086Sscottl cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1608151086Sscottl cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 160965793Smsmith 1610117363Sscottl /* save a pointer to the command for speedy reverse-lookup */ 1611117363Sscottl cm->cm_fib->Header.SenderData = cm->cm_index; 161265793Smsmith 1613117363Sscottl if (cm->cm_flags & AAC_CMD_DATAIN) 1614117363Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1615117363Sscottl BUS_DMASYNC_PREREAD); 1616117363Sscottl if (cm->cm_flags & AAC_CMD_DATAOUT) 1617117363Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1618117363Sscottl BUS_DMASYNC_PREWRITE); 1619117363Sscottl cm->cm_flags |= AAC_CMD_MAPPED; 162065793Smsmith 1621151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) { 1622151086Sscottl int count = 10000000L; 1623151086Sscottl while (AAC_SEND_COMMAND(sc, cm) != 0) { 1624151086Sscottl if (--count == 0) { 1625151086Sscottl aac_unmap_command(cm); 1626151086Sscottl sc->flags |= AAC_QUEUE_FRZN; 1627151086Sscottl aac_requeue_ready(cm); 1628151086Sscottl } 1629151086Sscottl DELAY(5); /* wait 5 usec. */ 1630151086Sscottl } 1631151086Sscottl } else { 1632151086Sscottl /* Put the FIB on the outbound queue */ 1633151086Sscottl if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 1634151086Sscottl aac_unmap_command(cm); 1635151086Sscottl sc->flags |= AAC_QUEUE_FRZN; 1636151086Sscottl aac_requeue_ready(cm); 1637151086Sscottl } 1638125559Sscottl } 163965793Smsmith} 164065793Smsmith 164183114Sscottl/* 164265793Smsmith * Unmap a command from controller-visible space. 164365793Smsmith */ 164465793Smsmithstatic void 164565793Smsmithaac_unmap_command(struct aac_command *cm) 164665793Smsmith{ 164783114Sscottl struct aac_softc *sc; 164865793Smsmith 164983114Sscottl sc = cm->cm_sc; 1650177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 165165793Smsmith 165283114Sscottl if (!(cm->cm_flags & AAC_CMD_MAPPED)) 165383114Sscottl return; 165465793Smsmith 165583114Sscottl if (cm->cm_datalen != 0) { 165683114Sscottl if (cm->cm_flags & AAC_CMD_DATAIN) 165783114Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 165883114Sscottl BUS_DMASYNC_POSTREAD); 165983114Sscottl if (cm->cm_flags & AAC_CMD_DATAOUT) 166083114Sscottl bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 166183114Sscottl BUS_DMASYNC_POSTWRITE); 166283114Sscottl 166383114Sscottl bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 166483114Sscottl } 166583114Sscottl cm->cm_flags &= ~AAC_CMD_MAPPED; 166665793Smsmith} 166765793Smsmith 166883114Sscottl/* 166983114Sscottl * Hardware Interface 167083114Sscottl */ 167165793Smsmith 167283114Sscottl/* 1673177184Semaste * Initialize the adapter. 167465793Smsmith */ 167565793Smsmithstatic void 167665793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 167765793Smsmith{ 167883114Sscottl struct aac_softc *sc; 167965793Smsmith 168083114Sscottl sc = (struct aac_softc *)arg; 1681177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 168283114Sscottl 168383114Sscottl sc->aac_common_busaddr = segs[0].ds_addr; 168465793Smsmith} 168565793Smsmith 168665793Smsmithstatic int 168790275Sscottlaac_check_firmware(struct aac_softc *sc) 168890275Sscottl{ 1689177557Semaste u_int32_t code, major, minor, options = 0, atu_size = 0; 1690251070Smarius int rid, status; 1691177557Semaste time_t then; 169290275Sscottl 1693177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1694177557Semaste /* 1695177557Semaste * Wait for the adapter to come ready. 1696177557Semaste */ 1697177557Semaste then = time_uptime; 1698177557Semaste do { 1699177557Semaste code = AAC_GET_FWSTATUS(sc); 1700177557Semaste if (code & AAC_SELF_TEST_FAILED) { 1701177557Semaste device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 1702177557Semaste return(ENXIO); 1703177557Semaste } 1704177557Semaste if (code & AAC_KERNEL_PANIC) { 1705177557Semaste device_printf(sc->aac_dev, 1706177635Semaste "FATAL: controller kernel panic"); 1707177557Semaste return(ENXIO); 1708177557Semaste } 1709177557Semaste if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1710177557Semaste device_printf(sc->aac_dev, 1711177557Semaste "FATAL: controller not coming ready, " 1712177557Semaste "status %x\n", code); 1713177557Semaste return(ENXIO); 1714177557Semaste } 1715177557Semaste } while (!(code & AAC_UP_AND_RUNNING)); 171690275Sscottl 1717112679Sscottl /* 1718112679Sscottl * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1719112679Sscottl * firmware version 1.x are not compatible with this driver. 1720112679Sscottl */ 1721112679Sscottl if (sc->flags & AAC_FLAGS_PERC2QC) { 172290275Sscottl if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 172390275Sscottl NULL)) { 172490275Sscottl device_printf(sc->aac_dev, 172590275Sscottl "Error reading firmware version\n"); 172690275Sscottl return (EIO); 172790275Sscottl } 172890275Sscottl 172990275Sscottl /* These numbers are stored as ASCII! */ 1730112679Sscottl major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1731112679Sscottl minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 173290275Sscottl if (major == 1) { 173390275Sscottl device_printf(sc->aac_dev, 173490275Sscottl "Firmware version %d.%d is not supported.\n", 173590275Sscottl major, minor); 173690275Sscottl return (EINVAL); 173790275Sscottl } 173890275Sscottl } 173990275Sscottl 1740112679Sscottl /* 1741112679Sscottl * Retrieve the capabilities/supported options word so we know what 1742151330Sscottl * work-arounds to enable. Some firmware revs don't support this 1743151330Sscottl * command. 1744112679Sscottl */ 1745151330Sscottl if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1746151330Sscottl if (status != AAC_SRB_STS_INVALID_REQUEST) { 1747151330Sscottl device_printf(sc->aac_dev, 1748151330Sscottl "RequestAdapterInfo failed\n"); 1749151330Sscottl return (EIO); 1750151330Sscottl } 1751151330Sscottl } else { 1752151330Sscottl options = AAC_GET_MAILBOX(sc, 1); 1753151330Sscottl atu_size = AAC_GET_MAILBOX(sc, 2); 1754151330Sscottl sc->supported_options = options; 1755112679Sscottl 1756151330Sscottl if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1757151330Sscottl (sc->flags & AAC_FLAGS_NO4GB) == 0) 1758151330Sscottl sc->flags |= AAC_FLAGS_4GB_WINDOW; 1759151330Sscottl if (options & AAC_SUPPORTED_NONDASD) 1760151330Sscottl sc->flags |= AAC_FLAGS_ENABLE_CAM; 1761151330Sscottl if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1762151330Sscottl && (sizeof(bus_addr_t) > 4)) { 1763151330Sscottl device_printf(sc->aac_dev, 1764151330Sscottl "Enabling 64-bit address support\n"); 1765151330Sscottl sc->flags |= AAC_FLAGS_SG_64BIT; 1766151330Sscottl } 1767151330Sscottl if ((options & AAC_SUPPORTED_NEW_COMM) 1768251070Smarius && sc->aac_if->aif_send_command) 1769151330Sscottl sc->flags |= AAC_FLAGS_NEW_COMM; 1770151330Sscottl if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1771151330Sscottl sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1772112679Sscottl } 1773112679Sscottl 1774112679Sscottl /* Check for broken hardware that does a lower number of commands */ 1775152388Sschweikh sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1776151086Sscottl 1777151086Sscottl /* Remap mem. resource, if required */ 1778152388Sschweikh if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1779251070Smarius atu_size > rman_get_size(sc->aac_regs_res1)) { 1780251070Smarius rid = rman_get_rid(sc->aac_regs_res1); 1781251070Smarius bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, rid, 1782251070Smarius sc->aac_regs_res1); 1783251070Smarius sc->aac_regs_res1 = bus_alloc_resource(sc->aac_dev, 1784251070Smarius SYS_RES_MEMORY, &rid, 0ul, ~0ul, atu_size, RF_ACTIVE); 1785188896Sattilio if (sc->aac_regs_res1 == NULL) { 1786188896Sattilio sc->aac_regs_res1 = bus_alloc_resource_any( 1787251070Smarius sc->aac_dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 1788188896Sattilio if (sc->aac_regs_res1 == NULL) { 1789151086Sscottl device_printf(sc->aac_dev, 1790151109Sscottl "couldn't allocate register window\n"); 1791151086Sscottl return (ENXIO); 1792151086Sscottl } 1793151086Sscottl sc->flags &= ~AAC_FLAGS_NEW_COMM; 1794151086Sscottl } 1795188896Sattilio sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 1796188896Sattilio sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 1797188896Sattilio 1798188896Sattilio if (sc->aac_hwif == AAC_HWIF_NARK) { 1799188896Sattilio sc->aac_regs_res0 = sc->aac_regs_res1; 1800188896Sattilio sc->aac_btag0 = sc->aac_btag1; 1801188896Sattilio sc->aac_bhandle0 = sc->aac_bhandle1; 1802188896Sattilio } 1803151086Sscottl } 1804151086Sscottl 1805151086Sscottl /* Read preferred settings */ 1806151086Sscottl sc->aac_max_fib_size = sizeof(struct aac_fib); 1807151086Sscottl sc->aac_max_sectors = 128; /* 64KB */ 1808151086Sscottl if (sc->flags & AAC_FLAGS_SG_64BIT) 1809151330Sscottl sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1810172672Semaste - sizeof(struct aac_blockwrite64)) 1811172672Semaste / sizeof(struct aac_sg_entry64); 1812112679Sscottl else 1813151330Sscottl sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1814172672Semaste - sizeof(struct aac_blockwrite)) 1815172672Semaste / sizeof(struct aac_sg_entry); 1816151330Sscottl 1817151086Sscottl if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 1818151086Sscottl options = AAC_GET_MAILBOX(sc, 1); 1819151086Sscottl sc->aac_max_fib_size = (options & 0xFFFF); 1820151086Sscottl sc->aac_max_sectors = (options >> 16) << 1; 1821151086Sscottl options = AAC_GET_MAILBOX(sc, 2); 1822151086Sscottl sc->aac_sg_tablesize = (options >> 16); 1823151086Sscottl options = AAC_GET_MAILBOX(sc, 3); 1824151086Sscottl sc->aac_max_fibs = (options & 0xFFFF); 1825151086Sscottl } 1826151086Sscottl if (sc->aac_max_fib_size > PAGE_SIZE) 1827151086Sscottl sc->aac_max_fib_size = PAGE_SIZE; 1828151086Sscottl sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1829152388Sschweikh 1830177462Semaste if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1831177462Semaste sc->flags |= AAC_FLAGS_RAW_IO; 1832177462Semaste device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1833177462Semaste } 1834177619Semaste if ((sc->flags & AAC_FLAGS_RAW_IO) && 1835177619Semaste (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1836177619Semaste sc->flags |= AAC_FLAGS_LBA_64BIT; 1837177619Semaste device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1838177619Semaste } 1839177462Semaste 184090275Sscottl return (0); 184190275Sscottl} 184290275Sscottl 184390275Sscottlstatic int 184465793Smsmithaac_init(struct aac_softc *sc) 184565793Smsmith{ 184683114Sscottl struct aac_adapter_init *ip; 1847177557Semaste u_int32_t qoffset; 1848112679Sscottl int error; 184965793Smsmith 1850177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 185165793Smsmith 185283114Sscottl /* 185383114Sscottl * Fill in the init structure. This tells the adapter about the 185483114Sscottl * physical location of various important shared data structures. 185583114Sscottl */ 185683114Sscottl ip = &sc->aac_common->ac_init; 185783114Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1858151086Sscottl if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1859151086Sscottl ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1860151086Sscottl sc->flags |= AAC_FLAGS_RAW_IO; 1861151086Sscottl } 1862109088Sscottl ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 186365793Smsmith 186483114Sscottl ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 186583114Sscottl offsetof(struct aac_common, ac_fibs); 1866114151Sscottl ip->AdapterFibsVirtualAddress = 0; 186783114Sscottl ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 186883114Sscottl ip->AdapterFibAlign = sizeof(struct aac_fib); 186965793Smsmith 187083114Sscottl ip->PrintfBufferAddress = sc->aac_common_busaddr + 187183114Sscottl offsetof(struct aac_common, ac_printf); 187283114Sscottl ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 187365793Smsmith 1874152388Sschweikh /* 1875117361Sscottl * The adapter assumes that pages are 4K in size, except on some 1876117361Sscottl * broken firmware versions that do the page->byte conversion twice, 1877117361Sscottl * therefore 'assuming' that this value is in 16MB units (2^24). 1878117361Sscottl * Round up since the granularity is so high. 1879117361Sscottl */ 1880109088Sscottl ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1881117361Sscottl if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1882117361Sscottl ip->HostPhysMemPages = 1883117361Sscottl (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1884117362Sscottl } 1885150119Sscottl ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 188665793Smsmith 1887151086Sscottl ip->InitFlags = 0; 1888151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) { 1889206540Semaste ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED; 1890151086Sscottl device_printf(sc->aac_dev, "New comm. interface enabled\n"); 1891151086Sscottl } 1892151086Sscottl 1893151086Sscottl ip->MaxIoCommands = sc->aac_max_fibs; 1894151086Sscottl ip->MaxIoSize = sc->aac_max_sectors << 9; 1895151086Sscottl ip->MaxFibSize = sc->aac_max_fib_size; 1896151086Sscottl 189783114Sscottl /* 1898177184Semaste * Initialize FIB queues. Note that it appears that the layout of the 189983114Sscottl * indexes and the segmentation of the entries may be mandated by the 190083114Sscottl * adapter, which is only told about the base of the queue index fields. 190183114Sscottl * 190283114Sscottl * The initial values of the indices are assumed to inform the adapter 1903152388Sschweikh * of the sizes of the respective queues, and theoretically it could 190483114Sscottl * work out the entire layout of the queue structures from this. We 190583114Sscottl * take the easy route and just lay this area out like everyone else 190683114Sscottl * does. 190783114Sscottl * 1908152388Sschweikh * The Linux driver uses a much more complex scheme whereby several 1909152388Sschweikh * header records are kept for each queue. We use a couple of generic 191083114Sscottl * list manipulation functions which 'know' the size of each list by 191183114Sscottl * virtue of a table. 191283114Sscottl */ 1913119146Sscottl qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 1914119625Sscottl qoffset &= ~(AAC_QUEUE_ALIGN - 1); 1915119625Sscottl sc->aac_queues = 1916119625Sscottl (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1917119146Sscottl ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 191865793Smsmith 191983114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 192081082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 192183114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 192281082Sscottl AAC_HOST_NORM_CMD_ENTRIES; 192383114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 192481082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 192583114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 192681082Sscottl AAC_HOST_HIGH_CMD_ENTRIES; 192783114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 192881082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 192983114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 193081082Sscottl AAC_ADAP_NORM_CMD_ENTRIES; 193183114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 193281082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 193383114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 193481082Sscottl AAC_ADAP_HIGH_CMD_ENTRIES; 193583114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 193681082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 193783114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 193881082Sscottl AAC_HOST_NORM_RESP_ENTRIES; 193983114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 194081082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 194183114Sscottl sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 194281082Sscottl AAC_HOST_HIGH_RESP_ENTRIES; 194383114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 194481082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 194583114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 194681082Sscottl AAC_ADAP_NORM_RESP_ENTRIES; 194783114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 194881082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 194983114Sscottl sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 195081082Sscottl AAC_ADAP_HIGH_RESP_ENTRIES; 195183114Sscottl sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 195281082Sscottl &sc->aac_queues->qt_HostNormCmdQueue[0]; 195383114Sscottl sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 195481082Sscottl &sc->aac_queues->qt_HostHighCmdQueue[0]; 195583114Sscottl sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 195681082Sscottl &sc->aac_queues->qt_AdapNormCmdQueue[0]; 195783114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 195881082Sscottl &sc->aac_queues->qt_AdapHighCmdQueue[0]; 195983114Sscottl sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 196081082Sscottl &sc->aac_queues->qt_HostNormRespQueue[0]; 196183114Sscottl sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 196281082Sscottl &sc->aac_queues->qt_HostHighRespQueue[0]; 196383114Sscottl sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 196481082Sscottl &sc->aac_queues->qt_AdapNormRespQueue[0]; 196583114Sscottl sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 196681082Sscottl &sc->aac_queues->qt_AdapHighRespQueue[0]; 196765793Smsmith 196883114Sscottl /* 196983114Sscottl * Do controller-type-specific initialisation 197083114Sscottl */ 197183114Sscottl switch (sc->aac_hwif) { 197283114Sscottl case AAC_HWIF_I960RX: 1973188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); 197483114Sscottl break; 1975133606Sscottl case AAC_HWIF_RKT: 1976188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); 1977133606Sscottl break; 1978133606Sscottl default: 1979133606Sscottl break; 198083114Sscottl } 198165793Smsmith 198283114Sscottl /* 198383114Sscottl * Give the init structure to the controller. 198483114Sscottl */ 1985152388Sschweikh if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 198683114Sscottl sc->aac_common_busaddr + 198783114Sscottl offsetof(struct aac_common, ac_init), 0, 0, 0, 198883114Sscottl NULL)) { 198983114Sscottl device_printf(sc->aac_dev, 199083114Sscottl "error establishing init structure\n"); 1991112679Sscottl error = EIO; 1992112679Sscottl goto out; 199383114Sscottl } 199465793Smsmith 1995112679Sscottl error = 0; 1996112679Sscottlout: 1997112679Sscottl return(error); 199865793Smsmith} 199965793Smsmith 2000177557Semastestatic int 2001177557Semasteaac_setup_intr(struct aac_softc *sc) 2002177557Semaste{ 2003251070Smarius 2004177557Semaste if (sc->flags & AAC_FLAGS_NEW_COMM) { 2005177557Semaste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2006206534Semaste INTR_MPSAFE|INTR_TYPE_BIO, NULL, 2007177557Semaste aac_new_intr, sc, &sc->aac_intr)) { 2008177557Semaste device_printf(sc->aac_dev, "can't set up interrupt\n"); 2009177557Semaste return (EINVAL); 2010177557Semaste } 2011177557Semaste } else { 2012177557Semaste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2013198593Semaste INTR_TYPE_BIO, aac_filter, NULL, 2014177557Semaste sc, &sc->aac_intr)) { 2015177557Semaste device_printf(sc->aac_dev, 2016198593Semaste "can't set up interrupt filter\n"); 2017198593Semaste return (EINVAL); 2018177557Semaste } 2019177557Semaste } 2020177557Semaste return (0); 2021177557Semaste} 2022177557Semaste 202383114Sscottl/* 202465793Smsmith * Send a synchronous command to the controller and wait for a result. 2025151086Sscottl * Indicate if the controller completed the command with an error status. 202665793Smsmith */ 202765793Smsmithstatic int 202865793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command, 202970393Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 203070393Smsmith u_int32_t *sp) 203165793Smsmith{ 203283114Sscottl time_t then; 203383114Sscottl u_int32_t status; 203465793Smsmith 2035177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 203665793Smsmith 203783114Sscottl /* populate the mailbox */ 203883114Sscottl AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 203965793Smsmith 204083114Sscottl /* ensure the sync command doorbell flag is cleared */ 204183114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 204265793Smsmith 204383114Sscottl /* then set it to signal the adapter */ 204483114Sscottl AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 204565793Smsmith 204683114Sscottl /* spin waiting for the command to complete */ 2047150119Sscottl then = time_uptime; 204883114Sscottl do { 2049150119Sscottl if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 2050177567Semaste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 205183114Sscottl return(EIO); 205283114Sscottl } 205383114Sscottl } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 205465793Smsmith 205583114Sscottl /* clear the completion flag */ 205683114Sscottl AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 205765793Smsmith 205883114Sscottl /* get the command status */ 2059112679Sscottl status = AAC_GET_MAILBOX(sc, 0); 206083114Sscottl if (sp != NULL) 206183114Sscottl *sp = status; 2062151086Sscottl 2063151330Sscottl if (status != AAC_SRB_STS_SUCCESS) 2064151086Sscottl return (-1); 206583114Sscottl return(0); 206665793Smsmith} 206765793Smsmith 206895350Sscottlint 2069152388Sschweikhaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 207095350Sscottl struct aac_fib *fib, u_int16_t datasize) 207165793Smsmith{ 2072177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2073151086Sscottl mtx_assert(&sc->aac_io_lock, MA_OWNED); 207465793Smsmith 207583114Sscottl if (datasize > AAC_FIB_DATASIZE) 207683114Sscottl return(EINVAL); 207765793Smsmith 207883114Sscottl /* 207983114Sscottl * Set up the sync FIB 208083114Sscottl */ 208183114Sscottl fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 208283114Sscottl AAC_FIBSTATE_INITIALISED | 208383114Sscottl AAC_FIBSTATE_EMPTY; 208483114Sscottl fib->Header.XferState |= xferstate; 208583114Sscottl fib->Header.Command = command; 208683114Sscottl fib->Header.StructType = AAC_FIBTYPE_TFIB; 2087177463Semaste fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 208883114Sscottl fib->Header.SenderSize = sizeof(struct aac_fib); 2089119146Sscottl fib->Header.SenderFibAddress = 0; /* Not needed */ 209083114Sscottl fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 209183114Sscottl offsetof(struct aac_common, 209283114Sscottl ac_sync_fib); 209365793Smsmith 209483114Sscottl /* 209583114Sscottl * Give the FIB to the controller, wait for a response. 209683114Sscottl */ 209783114Sscottl if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 209883114Sscottl fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 2099177567Semaste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 210083114Sscottl return(EIO); 210183114Sscottl } 210281151Sscottl 210395350Sscottl return (0); 210465793Smsmith} 210565793Smsmith 210683114Sscottl/* 210765793Smsmith * Adapter-space FIB queue manipulation 210865793Smsmith * 210965793Smsmith * Note that the queue implementation here is a little funky; neither the PI or 211065793Smsmith * CI will ever be zero. This behaviour is a controller feature. 211165793Smsmith */ 2112251070Smariusstatic const struct { 211383114Sscottl int size; 211483114Sscottl int notify; 211565793Smsmith} aac_qinfo[] = { 211683114Sscottl {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 211783114Sscottl {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 211883114Sscottl {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 211983114Sscottl {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 212083114Sscottl {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 212183114Sscottl {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 212283114Sscottl {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 212383114Sscottl {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 212465793Smsmith}; 212565793Smsmith 212665793Smsmith/* 212781082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or 212881082Sscottl * EBUSY if the queue is full. 212965793Smsmith * 213070393Smsmith * Note: it would be more efficient to defer notifying the controller in 213183114Sscottl * the case where we may be inserting several entries in rapid succession, 213283114Sscottl * but implementing this usefully may be difficult (it would involve a 213383114Sscottl * separate queue/notify interface). 213465793Smsmith */ 213565793Smsmithstatic int 213681151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 213765793Smsmith{ 213883114Sscottl u_int32_t pi, ci; 2139111691Sscottl int error; 214083114Sscottl u_int32_t fib_size; 214183114Sscottl u_int32_t fib_addr; 214265793Smsmith 2143177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 214482527Sscottl 2145152388Sschweikh fib_size = cm->cm_fib->Header.Size; 214683114Sscottl fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 214781151Sscottl 214883114Sscottl /* get the producer/consumer indices */ 214983114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215083114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215165793Smsmith 215283114Sscottl /* wrap the queue? */ 215383114Sscottl if (pi >= aac_qinfo[queue].size) 215483114Sscottl pi = 0; 215565793Smsmith 215683114Sscottl /* check for queue full */ 215783114Sscottl if ((pi + 1) == ci) { 215883114Sscottl error = EBUSY; 215983114Sscottl goto out; 216083114Sscottl } 216165793Smsmith 2162129946Sscottl /* 2163129946Sscottl * To avoid a race with its completion interrupt, place this command on 2164129946Sscottl * the busy queue prior to advertising it to the controller. 2165129946Sscottl */ 2166129946Sscottl aac_enqueue_busy(cm); 2167129946Sscottl 216883114Sscottl /* populate queue entry */ 216983114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 217083114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 217165793Smsmith 217283114Sscottl /* update producer index */ 217383114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 217465793Smsmith 217583114Sscottl /* notify the adapter if we know how */ 217683114Sscottl if (aac_qinfo[queue].notify != 0) 217783114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 217865793Smsmith 217983114Sscottl error = 0; 218065793Smsmith 218165793Smsmithout: 218283114Sscottl return(error); 218365793Smsmith} 218465793Smsmith 218565793Smsmith/* 218682527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on 218782527Sscottl * success or ENOENT if the queue is empty. 218865793Smsmith */ 218965793Smsmithstatic int 219081082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 219181082Sscottl struct aac_fib **fib_addr) 219265793Smsmith{ 219383114Sscottl u_int32_t pi, ci; 2194114151Sscottl u_int32_t fib_index; 2195111691Sscottl int error; 219683114Sscottl int notify; 219765793Smsmith 2198177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 219965793Smsmith 220083114Sscottl /* get the producer/consumer indices */ 220183114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 220283114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 220365793Smsmith 220483114Sscottl /* check for queue empty */ 220583114Sscottl if (ci == pi) { 220683114Sscottl error = ENOENT; 220783114Sscottl goto out; 220883114Sscottl } 2209120129Sscottl 2210120129Sscottl /* wrap the pi so the following test works */ 2211120129Sscottl if (pi >= aac_qinfo[queue].size) 2212120129Sscottl pi = 0; 2213120129Sscottl 221483114Sscottl notify = 0; 221583114Sscottl if (ci == pi + 1) 221683114Sscottl notify++; 221781151Sscottl 221883114Sscottl /* wrap the queue? */ 221983114Sscottl if (ci >= aac_qinfo[queue].size) 222083114Sscottl ci = 0; 222165793Smsmith 222283114Sscottl /* fetch the entry */ 222383114Sscottl *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 222465793Smsmith 2225114151Sscottl switch (queue) { 2226114151Sscottl case AAC_HOST_NORM_CMD_QUEUE: 2227114151Sscottl case AAC_HOST_HIGH_CMD_QUEUE: 2228114151Sscottl /* 2229114151Sscottl * The aq_fib_addr is only 32 bits wide so it can't be counted 2230114151Sscottl * on to hold an address. For AIF's, the adapter assumes 2231114151Sscottl * that it's giving us an address into the array of AIF fibs. 2232114151Sscottl * Therefore, we have to convert it to an index. 2233114151Sscottl */ 2234114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2235114151Sscottl sizeof(struct aac_fib); 2236114151Sscottl *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2237114151Sscottl break; 2238114151Sscottl 2239114151Sscottl case AAC_HOST_NORM_RESP_QUEUE: 2240114151Sscottl case AAC_HOST_HIGH_RESP_QUEUE: 2241114151Sscottl { 2242114151Sscottl struct aac_command *cm; 2243114151Sscottl 2244114151Sscottl /* 2245114151Sscottl * As above, an index is used instead of an actual address. 2246114151Sscottl * Gotta shift the index to account for the fast response 2247114151Sscottl * bit. No other correction is needed since this value was 2248114151Sscottl * originally provided by the driver via the SenderFibAddress 2249114151Sscottl * field. 2250114151Sscottl */ 2251114151Sscottl fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 2252151086Sscottl cm = sc->aac_commands + (fib_index >> 2); 2253114151Sscottl *fib_addr = cm->cm_fib; 2254114151Sscottl 2255114151Sscottl /* 2256114151Sscottl * Is this a fast response? If it is, update the fib fields in 2257114151Sscottl * local memory since the whole fib isn't DMA'd back up. 2258114151Sscottl */ 2259114151Sscottl if (fib_index & 0x01) { 2260114151Sscottl (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2261114151Sscottl *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2262114151Sscottl } 2263114151Sscottl break; 2264109088Sscottl } 2265114151Sscottl default: 2266114151Sscottl panic("Invalid queue in aac_dequeue_fib()"); 2267114151Sscottl break; 2268114151Sscottl } 2269114151Sscottl 227083114Sscottl /* update consumer index */ 227183114Sscottl sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 227265793Smsmith 227383114Sscottl /* if we have made the queue un-full, notify the adapter */ 227483114Sscottl if (notify && (aac_qinfo[queue].notify != 0)) 227583114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227683114Sscottl error = 0; 227765793Smsmith 227865793Smsmithout: 227983114Sscottl return(error); 228065793Smsmith} 228165793Smsmith 228283114Sscottl/* 228382527Sscottl * Put our response to an Adapter Initialed Fib on the response queue 228482527Sscottl */ 228582527Sscottlstatic int 228682527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 228782527Sscottl{ 228883114Sscottl u_int32_t pi, ci; 2289111691Sscottl int error; 229083114Sscottl u_int32_t fib_size; 229183114Sscottl u_int32_t fib_addr; 229282527Sscottl 2293177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 229482527Sscottl 229583114Sscottl /* Tell the adapter where the FIB is */ 2296152388Sschweikh fib_size = fib->Header.Size; 229783114Sscottl fib_addr = fib->Header.SenderFibAddress; 229883114Sscottl fib->Header.ReceiverFibAddress = fib_addr; 229982527Sscottl 230083114Sscottl /* get the producer/consumer indices */ 230183114Sscottl pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 230283114Sscottl ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 230382527Sscottl 230483114Sscottl /* wrap the queue? */ 230583114Sscottl if (pi >= aac_qinfo[queue].size) 230683114Sscottl pi = 0; 230782527Sscottl 230883114Sscottl /* check for queue full */ 230983114Sscottl if ((pi + 1) == ci) { 231083114Sscottl error = EBUSY; 231183114Sscottl goto out; 231283114Sscottl } 231382527Sscottl 231483114Sscottl /* populate queue entry */ 231583114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 231683114Sscottl (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 231782527Sscottl 231883114Sscottl /* update producer index */ 231983114Sscottl sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 232082527Sscottl 232183114Sscottl /* notify the adapter if we know how */ 232283114Sscottl if (aac_qinfo[queue].notify != 0) 232383114Sscottl AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 232482527Sscottl 232583114Sscottl error = 0; 232682527Sscottl 232782527Sscottlout: 232883114Sscottl return(error); 232982527Sscottl} 233082527Sscottl 233183114Sscottl/* 233270393Smsmith * Check for commands that have been outstanding for a suspiciously long time, 233370393Smsmith * and complain about them. 233470393Smsmith */ 233570393Smsmithstatic void 233670393Smsmithaac_timeout(struct aac_softc *sc) 233770393Smsmith{ 233883114Sscottl struct aac_command *cm; 233983114Sscottl time_t deadline; 2340135289Sscottl int timedout, code; 234170393Smsmith 234283114Sscottl /* 2343110426Sscottl * Traverse the busy command list, bitch about late commands once 234483114Sscottl * only. 234583114Sscottl */ 2346135289Sscottl timedout = 0; 2347150119Sscottl deadline = time_uptime - AAC_CMD_TIMEOUT; 234883114Sscottl TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 234983114Sscottl if ((cm->cm_timestamp < deadline) 2350212594Semaste && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { 235183114Sscottl cm->cm_flags |= AAC_CMD_TIMEDOUT; 235283114Sscottl device_printf(sc->aac_dev, 2353204019Semaste "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n", 2354204019Semaste cm, cm->cm_fib->Header.Command, 2355204019Semaste (int)(time_uptime-cm->cm_timestamp)); 235683114Sscottl AAC_PRINT_FIB(sc, cm->cm_fib); 2357135289Sscottl timedout++; 235883114Sscottl } 235970393Smsmith } 236070393Smsmith 2361135289Sscottl if (timedout) { 2362135289Sscottl code = AAC_GET_FWSTATUS(sc); 2363135289Sscottl if (code != AAC_UP_AND_RUNNING) { 2364135289Sscottl device_printf(sc->aac_dev, "WARNING! Controller is no " 2365135289Sscottl "longer running! code= 0x%x\n", code); 2366135289Sscottl } 2367135289Sscottl } 236870393Smsmith} 236970393Smsmith 237083114Sscottl/* 237183114Sscottl * Interface Function Vectors 237283114Sscottl */ 237365793Smsmith 237483114Sscottl/* 237565793Smsmith * Read the current firmware status word. 237665793Smsmith */ 237765793Smsmithstatic int 237865793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc) 237965793Smsmith{ 2380177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 238165793Smsmith 2382188896Sattilio return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); 238365793Smsmith} 238465793Smsmith 238565793Smsmithstatic int 238665793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc) 238765793Smsmith{ 2388177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 238965793Smsmith 2390188940Semaste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 2391188940Semaste AAC_RX_OMR0 : AAC_RX_FWSTATUS)); 239265793Smsmith} 239365793Smsmith 239487183Sscottlstatic int 2395133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc) 2396133606Sscottl{ 2397177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2398133606Sscottl 2399188940Semaste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 2400188940Semaste AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); 2401133606Sscottl} 2402133606Sscottl 240383114Sscottl/* 240465793Smsmith * Notify the controller of a change in a given queue 240565793Smsmith */ 240665793Smsmith 240765793Smsmithstatic void 240865793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit) 240965793Smsmith{ 2410177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241165793Smsmith 2412188896Sattilio AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 241365793Smsmith} 241465793Smsmith 241565793Smsmithstatic void 241665793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit) 241765793Smsmith{ 2418177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241965793Smsmith 2420188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); 242165793Smsmith} 242265793Smsmith 242387183Sscottlstatic void 2424133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit) 2425133606Sscottl{ 2426177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2427133606Sscottl 2428188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); 2429133606Sscottl} 2430133606Sscottl 243183114Sscottl/* 243265793Smsmith * Get the interrupt reason bits 243365793Smsmith */ 243465793Smsmithstatic int 243565793Smsmithaac_sa_get_istatus(struct aac_softc *sc) 243665793Smsmith{ 2437177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 243865793Smsmith 2439188896Sattilio return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); 244065793Smsmith} 244165793Smsmith 244265793Smsmithstatic int 244365793Smsmithaac_rx_get_istatus(struct aac_softc *sc) 244465793Smsmith{ 2445177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244665793Smsmith 2447188896Sattilio return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); 244865793Smsmith} 244965793Smsmith 245087183Sscottlstatic int 2451133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc) 2452133606Sscottl{ 2453177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2454133606Sscottl 2455188896Sattilio return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); 2456133606Sscottl} 2457133606Sscottl 245883114Sscottl/* 245965793Smsmith * Clear some interrupt reason bits 246065793Smsmith */ 246165793Smsmithstatic void 246265793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask) 246365793Smsmith{ 2464177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 246565793Smsmith 2466188896Sattilio AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 246765793Smsmith} 246865793Smsmith 246965793Smsmithstatic void 247065793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask) 247165793Smsmith{ 2472177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 247365793Smsmith 2474188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); 247565793Smsmith} 247665793Smsmith 247787183Sscottlstatic void 2478133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask) 2479133606Sscottl{ 2480177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2481133606Sscottl 2482188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); 2483133606Sscottl} 2484133606Sscottl 248583114Sscottl/* 248665793Smsmith * Populate the mailbox and set the command word 248765793Smsmith */ 248865793Smsmithstatic void 248965793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 249065793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249165793Smsmith{ 2492177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 249365793Smsmith 2494188896Sattilio AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); 2495188896Sattilio AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2496188896Sattilio AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2497188896Sattilio AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2498188896Sattilio AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 249965793Smsmith} 250065793Smsmith 250165793Smsmithstatic void 250265793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 250365793Smsmith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 250465793Smsmith{ 2505177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 250665793Smsmith 2507188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); 2508188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2509188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2510188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2511188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 251265793Smsmith} 251365793Smsmith 251487183Sscottlstatic void 2515133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2516133606Sscottl u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2517133606Sscottl{ 2518177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2519133606Sscottl 2520188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); 2521188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2522188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2523188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2524188896Sattilio AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 2525133606Sscottl} 2526133606Sscottl 252783114Sscottl/* 252865793Smsmith * Fetch the immediate command status word 252965793Smsmith */ 253065793Smsmithstatic int 2531112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb) 253265793Smsmith{ 2533177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 253465793Smsmith 2535188896Sattilio return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 253665793Smsmith} 253765793Smsmith 253865793Smsmithstatic int 2539112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb) 254065793Smsmith{ 2541177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 254265793Smsmith 2543188896Sattilio return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 254465793Smsmith} 254565793Smsmith 254687183Sscottlstatic int 2547133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb) 2548133606Sscottl{ 2549177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2550133606Sscottl 2551188896Sattilio return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 2552133606Sscottl} 2553133606Sscottl 255483114Sscottl/* 255565793Smsmith * Set/clear interrupt masks 255665793Smsmith */ 255765793Smsmithstatic void 255865793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable) 255965793Smsmith{ 2560177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 256165793Smsmith 256283114Sscottl if (enable) { 2563188896Sattilio AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 256483114Sscottl } else { 2565188896Sattilio AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 256683114Sscottl } 256765793Smsmith} 256865793Smsmith 256965793Smsmithstatic void 257065793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable) 257165793Smsmith{ 2572177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 257365793Smsmith 257483114Sscottl if (enable) { 2575151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 2576188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 2577151086Sscottl else 2578188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 257983114Sscottl } else { 2580188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); 258183114Sscottl } 258265793Smsmith} 258365793Smsmith 258487183Sscottlstatic void 2585133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable) 2586133606Sscottl{ 2587177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2588133606Sscottl 2589133606Sscottl if (enable) { 2590151086Sscottl if (sc->flags & AAC_FLAGS_NEW_COMM) 2591188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 2592151086Sscottl else 2593188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 2594133606Sscottl } else { 2595188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); 2596133606Sscottl } 2597133606Sscottl} 2598133606Sscottl 259983114Sscottl/* 2600151086Sscottl * New comm. interface: Send command functions 2601151086Sscottl */ 2602151086Sscottlstatic int 2603151086Sscottlaac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 2604151086Sscottl{ 2605151086Sscottl u_int32_t index, device; 2606151086Sscottl 2607177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 2608151086Sscottl 2609188896Sattilio index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 2610151086Sscottl if (index == 0xffffffffL) 2611188896Sattilio index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 2612151086Sscottl if (index == 0xffffffffL) 2613151086Sscottl return index; 2614151086Sscottl aac_enqueue_busy(cm); 2615151086Sscottl device = index; 2616188896Sattilio AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2617151086Sscottl device += 4; 2618188896Sattilio AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2619151086Sscottl device += 4; 2620188896Sattilio AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2621188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); 2622151086Sscottl return 0; 2623151086Sscottl} 2624151086Sscottl 2625151086Sscottlstatic int 2626151086Sscottlaac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 2627151086Sscottl{ 2628151086Sscottl u_int32_t index, device; 2629151086Sscottl 2630177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 2631151086Sscottl 2632188896Sattilio index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 2633151086Sscottl if (index == 0xffffffffL) 2634188896Sattilio index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 2635151086Sscottl if (index == 0xffffffffL) 2636151086Sscottl return index; 2637151086Sscottl aac_enqueue_busy(cm); 2638151086Sscottl device = index; 2639188896Sattilio AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2640151086Sscottl device += 4; 2641188896Sattilio AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2642151086Sscottl device += 4; 2643188896Sattilio AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2644188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); 2645151086Sscottl return 0; 2646151086Sscottl} 2647151086Sscottl 2648152388Sschweikh/* 2649152388Sschweikh * New comm. interface: get, set outbound queue index 2650151086Sscottl */ 2651151086Sscottlstatic int 2652151086Sscottlaac_rx_get_outb_queue(struct aac_softc *sc) 2653151086Sscottl{ 2654177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2655151086Sscottl 2656188896Sattilio return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); 2657151086Sscottl} 2658151086Sscottl 2659151086Sscottlstatic int 2660151086Sscottlaac_rkt_get_outb_queue(struct aac_softc *sc) 2661151086Sscottl{ 2662177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2663151086Sscottl 2664188896Sattilio return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); 2665151086Sscottl} 2666151086Sscottl 2667151086Sscottlstatic void 2668151086Sscottlaac_rx_set_outb_queue(struct aac_softc *sc, int index) 2669151086Sscottl{ 2670177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2671151086Sscottl 2672188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); 2673151086Sscottl} 2674151086Sscottl 2675151086Sscottlstatic void 2676151086Sscottlaac_rkt_set_outb_queue(struct aac_softc *sc, int index) 2677151086Sscottl{ 2678177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2679151086Sscottl 2680188896Sattilio AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); 2681151086Sscottl} 2682151086Sscottl 2683151086Sscottl/* 268483114Sscottl * Debugging and Diagnostics 268583114Sscottl */ 268665793Smsmith 268783114Sscottl/* 268865793Smsmith * Print some information about the controller. 268965793Smsmith */ 269065793Smsmithstatic void 269165793Smsmithaac_describe_controller(struct aac_softc *sc) 269265793Smsmith{ 269395350Sscottl struct aac_fib *fib; 269483114Sscottl struct aac_adapter_info *info; 2695174412Semaste char *adapter_type = "Adaptec RAID controller"; 269665793Smsmith 2697177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 269865793Smsmith 2699151222Sscottl mtx_lock(&sc->aac_io_lock); 2700130006Sscottl aac_alloc_sync_fib(sc, &fib); 270195350Sscottl 270295350Sscottl fib->data[0] = 0; 270395350Sscottl if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 270483114Sscottl device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 270595536Sscottl aac_release_sync_fib(sc); 2706151222Sscottl mtx_unlock(&sc->aac_io_lock); 270783114Sscottl return; 270883114Sscottl } 270965793Smsmith 271083114Sscottl /* save the kernel revision structure for later use */ 2711152388Sschweikh info = (struct aac_adapter_info *)&fib->data[0]; 271283114Sscottl sc->aac_revision = info->KernelRevision; 271395536Sscottl 2714135095Sscottl if (bootverbose) { 2715146851Sscottl device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2716152388Sschweikh "(%dMB cache, %dMB execution), %s\n", 2717135095Sscottl aac_describe_code(aac_cpu_variant, info->CpuVariant), 2718152388Sschweikh info->ClockSpeed, info->TotalMem / (1024 * 1024), 2719146851Sscottl info->BufferMem / (1024 * 1024), 2720146851Sscottl info->ExecutionMem / (1024 * 1024), 2721135095Sscottl aac_describe_code(aac_battery_platform, 2722135095Sscottl info->batteryPlatform)); 2723112679Sscottl 2724135095Sscottl device_printf(sc->aac_dev, 2725135095Sscottl "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2726135095Sscottl info->KernelRevision.external.comp.major, 2727135095Sscottl info->KernelRevision.external.comp.minor, 2728135095Sscottl info->KernelRevision.external.comp.dash, 2729135095Sscottl info->KernelRevision.buildNumber, 2730135095Sscottl (u_int32_t)(info->SerialNumber & 0xffffff)); 2731135095Sscottl 2732112679Sscottl device_printf(sc->aac_dev, "Supported Options=%b\n", 2733112679Sscottl sc->supported_options, 2734112679Sscottl "\20" 2735112679Sscottl "\1SNAPSHOT" 2736112679Sscottl "\2CLUSTERS" 2737112679Sscottl "\3WCACHE" 2738112679Sscottl "\4DATA64" 2739112679Sscottl "\5HOSTTIME" 2740112679Sscottl "\6RAID50" 2741112679Sscottl "\7WINDOW4GB" 2742112679Sscottl "\10SCSIUPGD" 2743112679Sscottl "\11SOFTERR" 2744112679Sscottl "\12NORECOND" 2745112679Sscottl "\13SGMAP64" 2746112679Sscottl "\14ALARM" 2747151086Sscottl "\15NONDASD" 2748151086Sscottl "\16SCSIMGT" 2749151086Sscottl "\17RAIDSCSI" 2750151086Sscottl "\21ADPTINFO" 2751151086Sscottl "\22NEWCOMM" 2752151086Sscottl "\23ARRAY64BIT" 2753151086Sscottl "\24HEATSENSOR"); 2754112679Sscottl } 2755177845Semaste 2756177845Semaste if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 2757177845Semaste fib->data[0] = 0; 2758177845Semaste if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 2759177845Semaste device_printf(sc->aac_dev, 2760177845Semaste "RequestSupplementAdapterInfo failed\n"); 2761177845Semaste else 2762177845Semaste adapter_type = ((struct aac_supplement_adapter_info *) 2763177845Semaste &fib->data[0])->AdapterTypeText; 2764177845Semaste } 2765177845Semaste device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 2766177845Semaste adapter_type, 2767203885Semaste AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 2768203885Semaste AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 2769177845Semaste 2770135095Sscottl aac_release_sync_fib(sc); 2771151222Sscottl mtx_unlock(&sc->aac_io_lock); 277265793Smsmith} 277365793Smsmith 277483114Sscottl/* 277565793Smsmith * Look up a text description of a numeric error code and return a pointer to 277665793Smsmith * same. 277765793Smsmith */ 2778251070Smariusstatic const char * 2779251070Smariusaac_describe_code(const struct aac_code_lookup *table, u_int32_t code) 278065793Smsmith{ 278183114Sscottl int i; 278265793Smsmith 278383114Sscottl for (i = 0; table[i].string != NULL; i++) 278483114Sscottl if (table[i].code == code) 278583114Sscottl return(table[i].string); 278683114Sscottl return(table[i + 1].string); 278765793Smsmith} 278865793Smsmith 278983114Sscottl/* 279083114Sscottl * Management Interface 279183114Sscottl */ 279265793Smsmith 279365793Smsmithstatic int 2794192450Simpaac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 279565793Smsmith{ 279683114Sscottl struct aac_softc *sc; 279765793Smsmith 279883114Sscottl sc = dev->si_drv1; 2799177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2800212661Sattilio device_busy(sc->aac_dev); 2801212756Sattilio devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 280283114Sscottl 280383114Sscottl return 0; 280465793Smsmith} 280565793Smsmith 280665793Smsmithstatic int 2807192450Simpaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 280865793Smsmith{ 280983114Sscottl union aac_statrequest *as; 281083114Sscottl struct aac_softc *sc; 281183114Sscottl int error = 0; 281265793Smsmith 281383114Sscottl as = (union aac_statrequest *)arg; 281483114Sscottl sc = dev->si_drv1; 2815177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 281683114Sscottl 281783114Sscottl switch (cmd) { 281883114Sscottl case AACIO_STATS: 281983114Sscottl switch (as->as_item) { 282083114Sscottl case AACQ_FREE: 282183114Sscottl case AACQ_BIO: 282283114Sscottl case AACQ_READY: 282383114Sscottl case AACQ_BUSY: 282483114Sscottl bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 282583114Sscottl sizeof(struct aac_qstat)); 282683114Sscottl break; 282783114Sscottl default: 282883114Sscottl error = ENOENT; 282983114Sscottl break; 283083114Sscottl } 283183114Sscottl break; 2832152388Sschweikh 283383114Sscottl case FSACTL_SENDFIB: 2834177462Semaste case FSACTL_SEND_LARGE_FIB: 283583114Sscottl arg = *(caddr_t*)arg; 283683114Sscottl case FSACTL_LNX_SENDFIB: 2837177462Semaste case FSACTL_LNX_SEND_LARGE_FIB: 2838177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 283983114Sscottl error = aac_ioctl_sendfib(sc, arg); 284083114Sscottl break; 2841177462Semaste case FSACTL_SEND_RAW_SRB: 2842177462Semaste arg = *(caddr_t*)arg; 2843177462Semaste case FSACTL_LNX_SEND_RAW_SRB: 2844177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2845177462Semaste error = aac_ioctl_send_raw_srb(sc, arg); 2846177462Semaste break; 284783114Sscottl case FSACTL_AIF_THREAD: 284883114Sscottl case FSACTL_LNX_AIF_THREAD: 2849177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 285083114Sscottl error = EINVAL; 285183114Sscottl break; 285283114Sscottl case FSACTL_OPEN_GET_ADAPTER_FIB: 285383114Sscottl arg = *(caddr_t*)arg; 285487183Sscottl case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2855177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2856174385Semaste error = aac_open_aif(sc, arg); 285783114Sscottl break; 285883114Sscottl case FSACTL_GET_NEXT_ADAPTER_FIB: 285983114Sscottl arg = *(caddr_t*)arg; 286083114Sscottl case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2861177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 286283114Sscottl error = aac_getnext_aif(sc, arg); 286383114Sscottl break; 286483114Sscottl case FSACTL_CLOSE_GET_ADAPTER_FIB: 2865174385Semaste arg = *(caddr_t*)arg; 286683114Sscottl case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2867177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2868174385Semaste error = aac_close_aif(sc, arg); 286983114Sscottl break; 287083114Sscottl case FSACTL_MINIPORT_REV_CHECK: 287183114Sscottl arg = *(caddr_t*)arg; 287283114Sscottl case FSACTL_LNX_MINIPORT_REV_CHECK: 2873177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 287483114Sscottl error = aac_rev_check(sc, arg); 287583114Sscottl break; 287683114Sscottl case FSACTL_QUERY_DISK: 287783114Sscottl arg = *(caddr_t*)arg; 287883114Sscottl case FSACTL_LNX_QUERY_DISK: 2879177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 288083114Sscottl error = aac_query_disk(sc, arg); 2881151086Sscottl break; 288283114Sscottl case FSACTL_DELETE_DISK: 288383114Sscottl case FSACTL_LNX_DELETE_DISK: 288483114Sscottl /* 288583114Sscottl * We don't trust the underland to tell us when to delete a 2886152388Sschweikh * container, rather we rely on an AIF coming from the 288783114Sscottl * controller 288883114Sscottl */ 288983114Sscottl error = 0; 289083114Sscottl break; 2891151086Sscottl case FSACTL_GET_PCI_INFO: 2892151086Sscottl arg = *(caddr_t*)arg; 2893151086Sscottl case FSACTL_LNX_GET_PCI_INFO: 2894177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 2895151086Sscottl error = aac_get_pci_info(sc, arg); 2896151086Sscottl break; 2897177695Semaste case FSACTL_GET_FEATURES: 2898177695Semaste arg = *(caddr_t*)arg; 2899177695Semaste case FSACTL_LNX_GET_FEATURES: 2900177695Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 2901177695Semaste error = aac_supported_features(sc, arg); 2902177695Semaste break; 290370393Smsmith default: 2904177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 290583114Sscottl error = EINVAL; 290683114Sscottl break; 290770393Smsmith } 290883114Sscottl return(error); 290965793Smsmith} 291065793Smsmith 291187183Sscottlstatic int 2912192450Simpaac_poll(struct cdev *dev, int poll_events, struct thread *td) 291387183Sscottl{ 291487183Sscottl struct aac_softc *sc; 2915179969Semaste struct aac_fib_context *ctx; 291687183Sscottl int revents; 291787183Sscottl 291887183Sscottl sc = dev->si_drv1; 291987183Sscottl revents = 0; 292087183Sscottl 2921133540Sscottl mtx_lock(&sc->aac_aifq_lock); 292287183Sscottl if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2923179969Semaste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2924179969Semaste if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2925179969Semaste revents |= poll_events & (POLLIN | POLLRDNORM); 2926179969Semaste break; 2927179969Semaste } 2928179969Semaste } 292987183Sscottl } 2930133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 293187183Sscottl 293287183Sscottl if (revents == 0) { 293387183Sscottl if (poll_events & (POLLIN | POLLRDNORM)) 293487183Sscottl selrecord(td, &sc->rcv_select); 293587183Sscottl } 293687183Sscottl 293787183Sscottl return (revents); 293887183Sscottl} 293987183Sscottl 2940151086Sscottlstatic void 2941151086Sscottlaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2942151086Sscottl{ 2943151086Sscottl 2944151086Sscottl switch (event->ev_type) { 2945151086Sscottl case AAC_EVENT_CMFREE: 2946174774Semaste mtx_assert(&sc->aac_io_lock, MA_OWNED); 2947166704Sluoqi if (aac_alloc_command(sc, (struct aac_command **)arg)) { 2948151086Sscottl aac_add_event(sc, event); 2949151086Sscottl return; 2950151086Sscottl } 2951151086Sscottl free(event, M_AACBUF); 2952151109Sscottl wakeup(arg); 2953151086Sscottl break; 2954151086Sscottl default: 2955151086Sscottl break; 2956151086Sscottl } 2957151086Sscottl} 2958151086Sscottl 295983114Sscottl/* 296065793Smsmith * Send a FIB supplied from userspace 296165793Smsmith */ 296265793Smsmithstatic int 296365793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 296465793Smsmith{ 296583114Sscottl struct aac_command *cm; 296683114Sscottl int size, error; 296765793Smsmith 2968177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 296965793Smsmith 297083114Sscottl cm = NULL; 297165793Smsmith 297283114Sscottl /* 297383114Sscottl * Get a command 297483114Sscottl */ 2975133540Sscottl mtx_lock(&sc->aac_io_lock); 297683114Sscottl if (aac_alloc_command(sc, &cm)) { 2977151086Sscottl struct aac_event *event; 2978151086Sscottl 2979151086Sscottl event = malloc(sizeof(struct aac_event), M_AACBUF, 2980151086Sscottl M_NOWAIT | M_ZERO); 2981151086Sscottl if (event == NULL) { 2982151086Sscottl error = EBUSY; 2983174819Semaste mtx_unlock(&sc->aac_io_lock); 2984151086Sscottl goto out; 2985151086Sscottl } 2986151086Sscottl event->ev_type = AAC_EVENT_CMFREE; 2987151086Sscottl event->ev_callback = aac_ioctl_event; 2988151086Sscottl event->ev_arg = &cm; 2989151086Sscottl aac_add_event(sc, event); 2990151109Sscottl msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 299183114Sscottl } 2992157587Sscottl mtx_unlock(&sc->aac_io_lock); 299365793Smsmith 299483114Sscottl /* 299583114Sscottl * Fetch the FIB header, then re-copy to get data as well. 299683114Sscottl */ 299783114Sscottl if ((error = copyin(ufib, cm->cm_fib, 299883114Sscottl sizeof(struct aac_fib_header))) != 0) 299983114Sscottl goto out; 300083114Sscottl size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 3001177462Semaste if (size > sc->aac_max_fib_size) { 3002177462Semaste device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 3003177462Semaste size, sc->aac_max_fib_size); 3004177462Semaste size = sc->aac_max_fib_size; 300583114Sscottl } 300683114Sscottl if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 300783114Sscottl goto out; 300883114Sscottl cm->cm_fib->Header.Size = size; 3009150119Sscottl cm->cm_timestamp = time_uptime; 301065793Smsmith 301183114Sscottl /* 301283114Sscottl * Pass the FIB to the controller, wait for it to complete. 301383114Sscottl */ 3014157587Sscottl mtx_lock(&sc->aac_io_lock); 3015174819Semaste error = aac_wait_command(cm); 3016174819Semaste mtx_unlock(&sc->aac_io_lock); 3017174819Semaste if (error != 0) { 3018110426Sscottl device_printf(sc->aac_dev, 3019110426Sscottl "aac_wait_command return %d\n", error); 302083114Sscottl goto out; 302187183Sscottl } 302265793Smsmith 302383114Sscottl /* 302483114Sscottl * Copy the FIB and data back out to the caller. 302583114Sscottl */ 302683114Sscottl size = cm->cm_fib->Header.Size; 3027177462Semaste if (size > sc->aac_max_fib_size) { 3028177462Semaste device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 3029177462Semaste size, sc->aac_max_fib_size); 3030177462Semaste size = sc->aac_max_fib_size; 303183114Sscottl } 303283114Sscottl error = copyout(cm->cm_fib, ufib, size); 303365793Smsmith 303465793Smsmithout: 303583114Sscottl if (cm != NULL) { 3036174819Semaste mtx_lock(&sc->aac_io_lock); 303783114Sscottl aac_release_command(cm); 3038174819Semaste mtx_unlock(&sc->aac_io_lock); 303983114Sscottl } 304083114Sscottl return(error); 304165793Smsmith} 304265793Smsmith 304383114Sscottl/* 3044177462Semaste * Send a passthrough FIB supplied from userspace 3045177462Semaste */ 3046177462Semastestatic int 3047177462Semasteaac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 3048177462Semaste{ 3049205160Sattilio struct aac_command *cm; 3050205160Sattilio struct aac_event *event; 3051205160Sattilio struct aac_fib *fib; 3052205160Sattilio struct aac_srb *srbcmd, *user_srb; 3053205160Sattilio struct aac_sg_entry *sge; 3054205160Sattilio struct aac_sg_entry64 *sge64; 3055205160Sattilio void *srb_sg_address, *ureply; 3056205160Sattilio uint32_t fibsize, srb_sg_bytecount; 3057205160Sattilio int error, transfer_data; 3058205160Sattilio 3059205160Sattilio fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3060205160Sattilio 3061205160Sattilio cm = NULL; 3062205160Sattilio transfer_data = 0; 3063205160Sattilio fibsize = 0; 3064205160Sattilio user_srb = (struct aac_srb *)arg; 3065205160Sattilio 3066205160Sattilio mtx_lock(&sc->aac_io_lock); 3067205160Sattilio if (aac_alloc_command(sc, &cm)) { 3068205160Sattilio event = malloc(sizeof(struct aac_event), M_AACBUF, 3069205160Sattilio M_NOWAIT | M_ZERO); 3070205160Sattilio if (event == NULL) { 3071205160Sattilio error = EBUSY; 3072205160Sattilio mtx_unlock(&sc->aac_io_lock); 3073205160Sattilio goto out; 3074205160Sattilio } 3075205160Sattilio event->ev_type = AAC_EVENT_CMFREE; 3076205160Sattilio event->ev_callback = aac_ioctl_event; 3077205160Sattilio event->ev_arg = &cm; 3078205160Sattilio aac_add_event(sc, event); 3079205160Sattilio msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0); 3080205160Sattilio } 3081205160Sattilio mtx_unlock(&sc->aac_io_lock); 3082205160Sattilio 3083205160Sattilio cm->cm_data = NULL; 3084205160Sattilio fib = cm->cm_fib; 3085205160Sattilio srbcmd = (struct aac_srb *)fib->data; 3086205160Sattilio error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t)); 3087205160Sattilio if (error != 0) 3088205160Sattilio goto out; 3089205160Sattilio if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) { 3090205160Sattilio error = EINVAL; 3091205160Sattilio goto out; 3092205160Sattilio } 3093205160Sattilio error = copyin(user_srb, srbcmd, fibsize); 3094205160Sattilio if (error != 0) 3095205160Sattilio goto out; 3096205160Sattilio srbcmd->function = 0; 3097205160Sattilio srbcmd->retry_limit = 0; 3098205160Sattilio if (srbcmd->sg_map.SgCount > 1) { 3099205160Sattilio error = EINVAL; 3100205160Sattilio goto out; 3101205160Sattilio } 3102205160Sattilio 3103205160Sattilio /* Retrieve correct SG entries. */ 3104205160Sattilio if (fibsize == (sizeof(struct aac_srb) + 3105205160Sattilio srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 3106205160Sattilio sge = srbcmd->sg_map.SgEntry; 3107205160Sattilio sge64 = NULL; 3108205160Sattilio srb_sg_bytecount = sge->SgByteCount; 3109205167Sattilio srb_sg_address = (void *)(uintptr_t)sge->SgAddress; 3110205160Sattilio } 3111205160Sattilio#ifdef __amd64__ 3112205160Sattilio else if (fibsize == (sizeof(struct aac_srb) + 3113205160Sattilio srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 3114205160Sattilio sge = NULL; 3115205160Sattilio sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 3116205160Sattilio srb_sg_bytecount = sge64->SgByteCount; 3117205160Sattilio srb_sg_address = (void *)sge64->SgAddress; 3118205160Sattilio if (sge64->SgAddress > 0xffffffffull && 3119205160Sattilio (sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 3120205160Sattilio error = EINVAL; 3121205160Sattilio goto out; 3122205160Sattilio } 3123205160Sattilio } 3124205160Sattilio#endif 3125205160Sattilio else { 3126205160Sattilio error = EINVAL; 3127205160Sattilio goto out; 3128205160Sattilio } 3129205160Sattilio ureply = (char *)arg + fibsize; 3130205160Sattilio srbcmd->data_len = srb_sg_bytecount; 3131205160Sattilio if (srbcmd->sg_map.SgCount == 1) 3132205160Sattilio transfer_data = 1; 3133205160Sattilio 3134205160Sattilio cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 3135205160Sattilio if (transfer_data) { 3136205160Sattilio cm->cm_datalen = srb_sg_bytecount; 3137205160Sattilio cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT); 3138205160Sattilio if (cm->cm_data == NULL) { 3139205160Sattilio error = ENOMEM; 3140205160Sattilio goto out; 3141205160Sattilio } 3142205160Sattilio if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 3143205160Sattilio cm->cm_flags |= AAC_CMD_DATAIN; 3144205160Sattilio if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 3145205160Sattilio cm->cm_flags |= AAC_CMD_DATAOUT; 3146205160Sattilio error = copyin(srb_sg_address, cm->cm_data, 3147205160Sattilio cm->cm_datalen); 3148205160Sattilio if (error != 0) 3149205160Sattilio goto out; 3150205160Sattilio } 3151205160Sattilio } 3152205160Sattilio 3153205160Sattilio fib->Header.Size = sizeof(struct aac_fib_header) + 3154205160Sattilio sizeof(struct aac_srb); 3155205160Sattilio fib->Header.XferState = 3156205160Sattilio AAC_FIBSTATE_HOSTOWNED | 3157205160Sattilio AAC_FIBSTATE_INITIALISED | 3158205160Sattilio AAC_FIBSTATE_EMPTY | 3159205160Sattilio AAC_FIBSTATE_FROMHOST | 3160205160Sattilio AAC_FIBSTATE_REXPECTED | 3161205160Sattilio AAC_FIBSTATE_NORM | 3162205160Sattilio AAC_FIBSTATE_ASYNC | 3163205160Sattilio AAC_FIBSTATE_FAST_RESPONSE; 3164205160Sattilio fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ? 3165205160Sattilio ScsiPortCommandU64 : ScsiPortCommand; 3166205160Sattilio 3167205160Sattilio mtx_lock(&sc->aac_io_lock); 3168205160Sattilio aac_wait_command(cm); 3169205160Sattilio mtx_unlock(&sc->aac_io_lock); 3170205160Sattilio 3171205160Sattilio if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) { 3172205160Sattilio error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen); 3173205160Sattilio if (error != 0) 3174205160Sattilio goto out; 3175205160Sattilio } 3176205160Sattilio error = copyout(fib->data, ureply, sizeof(struct aac_srb_response)); 3177205160Sattilioout: 3178205160Sattilio if (cm != NULL) { 3179205160Sattilio if (cm->cm_data != NULL) 3180205160Sattilio free(cm->cm_data, M_AACBUF); 3181205160Sattilio mtx_lock(&sc->aac_io_lock); 3182205160Sattilio aac_release_command(cm); 3183205160Sattilio mtx_unlock(&sc->aac_io_lock); 3184205160Sattilio } 3185205160Sattilio return(error); 3186177462Semaste} 3187177462Semaste 3188177462Semaste/* 3189212756Sattilio * cdevpriv interface private destructor. 3190212756Sattilio */ 3191212756Sattiliostatic void 3192212756Sattilioaac_cdevpriv_dtor(void *arg) 3193212756Sattilio{ 3194212756Sattilio struct aac_softc *sc; 3195212756Sattilio 3196212756Sattilio sc = arg; 3197212756Sattilio fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3198212756Sattilio mtx_lock(&Giant); 3199212756Sattilio device_unbusy(sc->aac_dev); 3200212756Sattilio mtx_unlock(&Giant); 3201212756Sattilio} 3202212756Sattilio 3203212756Sattilio/* 320465793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference. 320582527Sscottl * If the queue fills up, then drop the older entries. 320665793Smsmith */ 320765793Smsmithstatic void 320882527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 320965793Smsmith{ 321083114Sscottl struct aac_aif_command *aif; 321183114Sscottl struct aac_container *co, *co_next; 3212174385Semaste struct aac_fib_context *ctx; 3213177557Semaste struct aac_mntinforesp *mir; 3214174385Semaste int next, current, found; 3215115760Sscottl int count = 0, added = 0, i = 0; 3216213272Semaste uint32_t channel; 321765793Smsmith 3218177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 321965793Smsmith 322083114Sscottl aif = (struct aac_aif_command*)&fib->data[0]; 322183114Sscottl aac_print_aif(sc, aif); 322282527Sscottl 322383114Sscottl /* Is it an event that we should care about? */ 322483114Sscottl switch (aif->command) { 322583114Sscottl case AifCmdEventNotify: 322683114Sscottl switch (aif->data.EN.type) { 322783114Sscottl case AifEnAddContainer: 322883114Sscottl case AifEnDeleteContainer: 322983114Sscottl /* 3230152388Sschweikh * A container was added or deleted, but the message 323183114Sscottl * doesn't tell us anything else! Re-enumerate the 323283114Sscottl * containers and sort things out. 323383114Sscottl */ 3234130006Sscottl aac_alloc_sync_fib(sc, &fib); 323583114Sscottl do { 323683114Sscottl /* 323783114Sscottl * Ask the controller for its containers one at 323883114Sscottl * a time. 323983114Sscottl * XXX What if the controller's list changes 324083114Sscottl * midway through this enumaration? 324183114Sscottl * XXX This should be done async. 324283114Sscottl */ 3243177557Semaste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 324483114Sscottl continue; 3245177557Semaste if (i == 0) 3246177557Semaste count = mir->MntRespCount; 324783114Sscottl /* 324883114Sscottl * Check the container against our list. 324983114Sscottl * co->co_found was already set to 0 in a 325083114Sscottl * previous run. 325183114Sscottl */ 325295350Sscottl if ((mir->Status == ST_OK) && 325395350Sscottl (mir->MntTable[0].VolType != CT_NONE)) { 325483114Sscottl found = 0; 325583114Sscottl TAILQ_FOREACH(co, 3256152388Sschweikh &sc->aac_container_tqh, 325783114Sscottl co_link) { 325883114Sscottl if (co->co_mntobj.ObjectId == 325995350Sscottl mir->MntTable[0].ObjectId) { 326083114Sscottl co->co_found = 1; 326183114Sscottl found = 1; 326283114Sscottl break; 326383114Sscottl } 326483114Sscottl } 326583114Sscottl /* 326683114Sscottl * If the container matched, continue 326783114Sscottl * in the list. 326883114Sscottl */ 326983114Sscottl if (found) { 327083114Sscottl i++; 327183114Sscottl continue; 327283114Sscottl } 327383114Sscottl 327483114Sscottl /* 327583114Sscottl * This is a new container. Do all the 3276110426Sscottl * appropriate things to set it up. 3277110426Sscottl */ 327895350Sscottl aac_add_container(sc, mir, 1); 327983114Sscottl added = 1; 328083114Sscottl } 328183114Sscottl i++; 3282115760Sscottl } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 328395350Sscottl aac_release_sync_fib(sc); 328483114Sscottl 328583114Sscottl /* 328683114Sscottl * Go through our list of containers and see which ones 328783114Sscottl * were not marked 'found'. Since the controller didn't 328883114Sscottl * list them they must have been deleted. Do the 328983114Sscottl * appropriate steps to destroy the device. Also reset 329083114Sscottl * the co->co_found field. 329183114Sscottl */ 329283114Sscottl co = TAILQ_FIRST(&sc->aac_container_tqh); 329383114Sscottl while (co != NULL) { 329483114Sscottl if (co->co_found == 0) { 3295151086Sscottl mtx_unlock(&sc->aac_io_lock); 3296196403Sjhb mtx_lock(&Giant); 329783114Sscottl device_delete_child(sc->aac_dev, 329883114Sscottl co->co_disk); 3299196403Sjhb mtx_unlock(&Giant); 3300151086Sscottl mtx_lock(&sc->aac_io_lock); 330183114Sscottl co_next = TAILQ_NEXT(co, co_link); 3302133540Sscottl mtx_lock(&sc->aac_container_lock); 330383114Sscottl TAILQ_REMOVE(&sc->aac_container_tqh, co, 330483114Sscottl co_link); 3305133540Sscottl mtx_unlock(&sc->aac_container_lock); 3306133541Sscottl free(co, M_AACBUF); 330783114Sscottl co = co_next; 330883114Sscottl } else { 330983114Sscottl co->co_found = 0; 331083114Sscottl co = TAILQ_NEXT(co, co_link); 331183114Sscottl } 331282527Sscottl } 331382527Sscottl 331483114Sscottl /* Attach the newly created containers */ 3315151086Sscottl if (added) { 3316151086Sscottl mtx_unlock(&sc->aac_io_lock); 3317196403Sjhb mtx_lock(&Giant); 331883114Sscottl bus_generic_attach(sc->aac_dev); 3319196403Sjhb mtx_unlock(&Giant); 3320151086Sscottl mtx_lock(&sc->aac_io_lock); 3321151086Sscottl } 3322152388Sschweikh 3323105528Sphk break; 332482527Sscottl 3325213272Semaste case AifEnEnclosureManagement: 3326213272Semaste switch (aif->data.EN.data.EEE.eventType) { 3327213272Semaste case AIF_EM_DRIVE_INSERTION: 3328213272Semaste case AIF_EM_DRIVE_REMOVAL: 3329213272Semaste channel = aif->data.EN.data.EEE.unitID; 3330213272Semaste if (sc->cam_rescan_cb != NULL) 3331213272Semaste sc->cam_rescan_cb(sc, 3332213272Semaste (channel >> 24) & 0xF, 3333213272Semaste (channel & 0xFFFF)); 3334213272Semaste break; 3335213272Semaste } 3336213272Semaste break; 3337213272Semaste 3338213272Semaste case AifEnAddJBOD: 3339213272Semaste case AifEnDeleteJBOD: 3340213272Semaste channel = aif->data.EN.data.ECE.container; 3341213272Semaste if (sc->cam_rescan_cb != NULL) 3342213272Semaste sc->cam_rescan_cb(sc, (channel >> 24) & 0xF, 3343213272Semaste AAC_CAM_TARGET_WILDCARD); 3344213272Semaste break; 3345213272Semaste 334683114Sscottl default: 334783114Sscottl break; 334882527Sscottl } 334982527Sscottl 335082527Sscottl default: 335183114Sscottl break; 335282527Sscottl } 335382527Sscottl 335483114Sscottl /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3355133540Sscottl mtx_lock(&sc->aac_aifq_lock); 3356174385Semaste current = sc->aifq_idx; 3357174385Semaste next = (current + 1) % AAC_AIFQ_LENGTH; 3358174385Semaste if (next == 0) 3359174385Semaste sc->aifq_filled = 1; 3360174385Semaste bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3361174385Semaste /* modify AIF contexts */ 3362174385Semaste if (sc->aifq_filled) { 3363174385Semaste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3364174385Semaste if (next == ctx->ctx_idx) 3365174385Semaste ctx->ctx_wrap = 1; 3366174385Semaste else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3367174385Semaste ctx->ctx_idx = next; 3368174385Semaste } 336983114Sscottl } 3370174385Semaste sc->aifq_idx = next; 3371174385Semaste /* On the off chance that someone is sleeping for an aif... */ 3372174385Semaste if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 3373174385Semaste wakeup(sc->aac_aifq); 3374174385Semaste /* Wakeup any poll()ers */ 3375174385Semaste selwakeuppri(&sc->rcv_select, PRIBIO); 3376133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 337765793Smsmith} 337865793Smsmith 337983114Sscottl/* 338070393Smsmith * Return the Revision of the driver to userspace and check to see if the 338182527Sscottl * userspace app is possibly compatible. This is extremely bogus since 338282527Sscottl * our driver doesn't follow Adaptec's versioning system. Cheat by just 338382527Sscottl * returning what the card reported. 338465793Smsmith */ 338565793Smsmithstatic int 338681189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata) 338765793Smsmith{ 338883114Sscottl struct aac_rev_check rev_check; 338983114Sscottl struct aac_rev_check_resp rev_check_resp; 339083114Sscottl int error = 0; 339165793Smsmith 3392177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 339365793Smsmith 339483114Sscottl /* 339583114Sscottl * Copyin the revision struct from userspace 339683114Sscottl */ 339783114Sscottl if ((error = copyin(udata, (caddr_t)&rev_check, 339881082Sscottl sizeof(struct aac_rev_check))) != 0) { 339983114Sscottl return error; 340083114Sscottl } 340165793Smsmith 3402177567Semaste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 340383114Sscottl rev_check.callingRevision.buildNumber); 340465793Smsmith 340583114Sscottl /* 340683114Sscottl * Doctor up the response struct. 340783114Sscottl */ 340883114Sscottl rev_check_resp.possiblyCompatible = 1; 3409203885Semaste rev_check_resp.adapterSWRevision.external.comp.major = 3410203885Semaste AAC_DRIVER_MAJOR_VERSION; 3411203885Semaste rev_check_resp.adapterSWRevision.external.comp.minor = 3412203885Semaste AAC_DRIVER_MINOR_VERSION; 3413203885Semaste rev_check_resp.adapterSWRevision.external.comp.type = 3414203885Semaste AAC_DRIVER_TYPE; 3415203885Semaste rev_check_resp.adapterSWRevision.external.comp.dash = 3416203885Semaste AAC_DRIVER_BUGFIX_LEVEL; 341783114Sscottl rev_check_resp.adapterSWRevision.buildNumber = 3418203885Semaste AAC_DRIVER_BUILD; 341965793Smsmith 342083114Sscottl return(copyout((caddr_t)&rev_check_resp, udata, 342183114Sscottl sizeof(struct aac_rev_check_resp))); 342265793Smsmith} 342365793Smsmith 342483114Sscottl/* 3425174385Semaste * Pass the fib context to the caller 3426174385Semaste */ 3427174385Semastestatic int 3428174385Semasteaac_open_aif(struct aac_softc *sc, caddr_t arg) 3429174385Semaste{ 3430174385Semaste struct aac_fib_context *fibctx, *ctx; 3431174385Semaste int error = 0; 3432174385Semaste 3433177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3434174385Semaste 3435174385Semaste fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3436174385Semaste if (fibctx == NULL) 3437174385Semaste return (ENOMEM); 3438174385Semaste 3439174385Semaste mtx_lock(&sc->aac_aifq_lock); 3440174385Semaste /* all elements are already 0, add to queue */ 3441174385Semaste if (sc->fibctx == NULL) 3442174385Semaste sc->fibctx = fibctx; 3443174385Semaste else { 3444174385Semaste for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3445174385Semaste ; 3446174385Semaste ctx->next = fibctx; 3447174385Semaste fibctx->prev = ctx; 3448174385Semaste } 3449174385Semaste 3450174385Semaste /* evaluate unique value */ 3451174385Semaste fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3452174385Semaste ctx = sc->fibctx; 3453174385Semaste while (ctx != fibctx) { 3454174385Semaste if (ctx->unique == fibctx->unique) { 3455174385Semaste fibctx->unique++; 3456174385Semaste ctx = sc->fibctx; 3457174385Semaste } else { 3458174385Semaste ctx = ctx->next; 3459174385Semaste } 3460174385Semaste } 3461174385Semaste mtx_unlock(&sc->aac_aifq_lock); 3462174385Semaste 3463174385Semaste error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3464174385Semaste if (error) 3465174385Semaste aac_close_aif(sc, (caddr_t)ctx); 3466174385Semaste return error; 3467174385Semaste} 3468174385Semaste 3469174385Semaste/* 3470174385Semaste * Close the caller's fib context 3471174385Semaste */ 3472174385Semastestatic int 3473174385Semasteaac_close_aif(struct aac_softc *sc, caddr_t arg) 3474174385Semaste{ 3475174385Semaste struct aac_fib_context *ctx; 3476174385Semaste 3477177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3478174385Semaste 3479174385Semaste mtx_lock(&sc->aac_aifq_lock); 3480174385Semaste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3481174385Semaste if (ctx->unique == *(uint32_t *)&arg) { 3482174385Semaste if (ctx == sc->fibctx) 3483174385Semaste sc->fibctx = NULL; 3484174385Semaste else { 3485174385Semaste ctx->prev->next = ctx->next; 3486174385Semaste if (ctx->next) 3487174385Semaste ctx->next->prev = ctx->prev; 3488174385Semaste } 3489174385Semaste break; 3490174385Semaste } 3491174385Semaste } 3492174385Semaste mtx_unlock(&sc->aac_aifq_lock); 3493174385Semaste if (ctx) 3494174385Semaste free(ctx, M_AACBUF); 3495174385Semaste 3496174385Semaste return 0; 3497174385Semaste} 3498174385Semaste 3499174385Semaste/* 350065793Smsmith * Pass the caller the next AIF in their queue 350165793Smsmith */ 350265793Smsmithstatic int 350381189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 350465793Smsmith{ 350583114Sscottl struct get_adapter_fib_ioctl agf; 3506174385Semaste struct aac_fib_context *ctx; 3507111691Sscottl int error; 350865793Smsmith 3509177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 351065793Smsmith 351183114Sscottl if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3512174385Semaste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3513174385Semaste if (agf.AdapterFibContext == ctx->unique) 3514174385Semaste break; 3515174385Semaste } 3516174385Semaste if (!ctx) 3517174385Semaste return (EFAULT); 351865793Smsmith 3519174385Semaste error = aac_return_aif(sc, ctx, agf.AifFib); 3520174385Semaste if (error == EAGAIN && agf.Wait) { 3521177567Semaste fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 3522174385Semaste sc->aac_state |= AAC_STATE_AIF_SLEEPER; 3523174385Semaste while (error == EAGAIN) { 3524174385Semaste error = tsleep(sc->aac_aifq, PRIBIO | 3525174385Semaste PCATCH, "aacaif", 0); 3526174385Semaste if (error == 0) 3527174385Semaste error = aac_return_aif(sc, ctx, agf.AifFib); 352883114Sscottl } 3529174385Semaste sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 353065793Smsmith } 353165793Smsmith } 353283114Sscottl return(error); 353365793Smsmith} 353465793Smsmith 353583114Sscottl/* 353670393Smsmith * Hand the next AIF off the top of the queue out to userspace. 353770393Smsmith */ 353870393Smsmithstatic int 3539174385Semasteaac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 354070393Smsmith{ 3541174385Semaste int current, error; 354270393Smsmith 3543177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 354470393Smsmith 3545133540Sscottl mtx_lock(&sc->aac_aifq_lock); 3546174385Semaste current = ctx->ctx_idx; 3547174385Semaste if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3548174385Semaste /* empty */ 3549133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 3550121173Sscottl return (EAGAIN); 355183114Sscottl } 3552174385Semaste error = 3553174385Semaste copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 3554121173Sscottl if (error) 3555121173Sscottl device_printf(sc->aac_dev, 3556121173Sscottl "aac_return_aif: copyout returned %d\n", error); 3557174385Semaste else { 3558174385Semaste ctx->ctx_wrap = 0; 3559174385Semaste ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3560174385Semaste } 3561133540Sscottl mtx_unlock(&sc->aac_aifq_lock); 356283114Sscottl return(error); 356370393Smsmith} 356482527Sscottl 3565151086Sscottlstatic int 3566151086Sscottlaac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3567151086Sscottl{ 3568151086Sscottl struct aac_pci_info { 3569151086Sscottl u_int32_t bus; 3570151086Sscottl u_int32_t slot; 3571151086Sscottl } pciinf; 3572151086Sscottl int error; 3573151086Sscottl 3574177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3575151086Sscottl 3576151086Sscottl pciinf.bus = pci_get_bus(sc->aac_dev); 3577151086Sscottl pciinf.slot = pci_get_slot(sc->aac_dev); 3578151086Sscottl 3579151086Sscottl error = copyout((caddr_t)&pciinf, uptr, 3580151086Sscottl sizeof(struct aac_pci_info)); 3581151086Sscottl 3582151086Sscottl return (error); 3583151086Sscottl} 3584151086Sscottl 3585177695Semastestatic int 3586177695Semasteaac_supported_features(struct aac_softc *sc, caddr_t uptr) 3587177695Semaste{ 3588177695Semaste struct aac_features f; 3589177695Semaste int error; 3590177695Semaste 3591177695Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3592177695Semaste 3593177695Semaste if ((error = copyin(uptr, &f, sizeof (f))) != 0) 3594177695Semaste return (error); 3595177695Semaste 3596177695Semaste /* 3597177695Semaste * When the management driver receives FSACTL_GET_FEATURES ioctl with 3598177695Semaste * ALL zero in the featuresState, the driver will return the current 3599177695Semaste * state of all the supported features, the data field will not be 3600177695Semaste * valid. 3601177695Semaste * When the management driver receives FSACTL_GET_FEATURES ioctl with 3602177695Semaste * a specific bit set in the featuresState, the driver will return the 3603177695Semaste * current state of this specific feature and whatever data that are 3604177695Semaste * associated with the feature in the data field or perform whatever 3605177695Semaste * action needed indicates in the data field. 3606177695Semaste */ 3607197016Semaste if (f.feat.fValue == 0) { 3608177695Semaste f.feat.fBits.largeLBA = 3609177695Semaste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3610177695Semaste /* TODO: In the future, add other features state here as well */ 3611177695Semaste } else { 3612177695Semaste if (f.feat.fBits.largeLBA) 3613177695Semaste f.feat.fBits.largeLBA = 3614177695Semaste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3615177695Semaste /* TODO: Add other features state and data in the future */ 3616177695Semaste } 3617177695Semaste 3618177695Semaste error = copyout(&f, uptr, sizeof (f)); 3619177695Semaste return (error); 3620177695Semaste} 3621177695Semaste 362283114Sscottl/* 362382527Sscottl * Give the userland some information about the container. The AAC arch 362482527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects 362582527Sscottl * the containers to have b:t:l numbers. Fake it. 362682527Sscottl */ 362782527Sscottlstatic int 362882527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr) 362982527Sscottl{ 363083114Sscottl struct aac_query_disk query_disk; 363183114Sscottl struct aac_container *co; 363283114Sscottl struct aac_disk *disk; 363383114Sscottl int error, id; 363482527Sscottl 3635177567Semaste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 363682527Sscottl 363783114Sscottl disk = NULL; 363882527Sscottl 363983114Sscottl error = copyin(uptr, (caddr_t)&query_disk, 364083114Sscottl sizeof(struct aac_query_disk)); 364183114Sscottl if (error) 364283114Sscottl return (error); 364382527Sscottl 364483114Sscottl id = query_disk.ContainerNumber; 364583114Sscottl if (id == -1) 364683114Sscottl return (EINVAL); 364782527Sscottl 3648133540Sscottl mtx_lock(&sc->aac_container_lock); 364983114Sscottl TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 365083114Sscottl if (co->co_mntobj.ObjectId == id) 365183114Sscottl break; 365283114Sscottl } 365382527Sscottl 3654105528Sphk if (co == NULL) { 365583114Sscottl query_disk.Valid = 0; 365683114Sscottl query_disk.Locked = 0; 365783114Sscottl query_disk.Deleted = 1; /* XXX is this right? */ 3658105528Sphk } else { 3659105528Sphk disk = device_get_softc(co->co_disk); 3660105528Sphk query_disk.Valid = 1; 3661105528Sphk query_disk.Locked = 3662105528Sphk (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 3663105528Sphk query_disk.Deleted = 0; 3664105528Sphk query_disk.Bus = device_get_unit(sc->aac_dev); 3665105528Sphk query_disk.Target = disk->unit; 3666105528Sphk query_disk.Lun = 0; 3667105528Sphk query_disk.UnMapped = 0; 3668111525Sscottl sprintf(&query_disk.diskDeviceName[0], "%s%d", 3669198525Semaste disk->ad_disk->d_name, disk->ad_disk->d_unit); 3670105528Sphk } 3671133540Sscottl mtx_unlock(&sc->aac_container_lock); 367282527Sscottl 367383114Sscottl error = copyout((caddr_t)&query_disk, uptr, 367483114Sscottl sizeof(struct aac_query_disk)); 367583114Sscottl 367683114Sscottl return (error); 367782527Sscottl} 367882527Sscottl 367995536Sscottlstatic void 368095536Sscottlaac_get_bus_info(struct aac_softc *sc) 368195536Sscottl{ 368295536Sscottl struct aac_fib *fib; 368395536Sscottl struct aac_ctcfg *c_cmd; 368495536Sscottl struct aac_ctcfg_resp *c_resp; 368595536Sscottl struct aac_vmioctl *vmi; 368695536Sscottl struct aac_vmi_businf_resp *vmi_resp; 368795536Sscottl struct aac_getbusinf businfo; 3688110426Sscottl struct aac_sim *caminf; 368995536Sscottl device_t child; 369095536Sscottl int i, found, error; 369195536Sscottl 3692151893Scsjp mtx_lock(&sc->aac_io_lock); 3693130006Sscottl aac_alloc_sync_fib(sc, &fib); 369495536Sscottl c_cmd = (struct aac_ctcfg *)&fib->data[0]; 369595966Sscottl bzero(c_cmd, sizeof(struct aac_ctcfg)); 369695536Sscottl 369795536Sscottl c_cmd->Command = VM_ContainerConfig; 369895536Sscottl c_cmd->cmd = CT_GET_SCSI_METHOD; 369995536Sscottl c_cmd->param = 0; 370095536Sscottl 370195536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 370295536Sscottl sizeof(struct aac_ctcfg)); 370395536Sscottl if (error) { 370495536Sscottl device_printf(sc->aac_dev, "Error %d sending " 370595536Sscottl "VM_ContainerConfig command\n", error); 370695536Sscottl aac_release_sync_fib(sc); 3707151893Scsjp mtx_unlock(&sc->aac_io_lock); 370895536Sscottl return; 370995536Sscottl } 371095536Sscottl 371195536Sscottl c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 371295536Sscottl if (c_resp->Status != ST_OK) { 371395536Sscottl device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 371495536Sscottl c_resp->Status); 371595536Sscottl aac_release_sync_fib(sc); 3716151893Scsjp mtx_unlock(&sc->aac_io_lock); 371795536Sscottl return; 371895536Sscottl } 371995536Sscottl 372095536Sscottl sc->scsi_method_id = c_resp->param; 372195536Sscottl 372295536Sscottl vmi = (struct aac_vmioctl *)&fib->data[0]; 372395966Sscottl bzero(vmi, sizeof(struct aac_vmioctl)); 372495966Sscottl 372595536Sscottl vmi->Command = VM_Ioctl; 372695536Sscottl vmi->ObjType = FT_DRIVE; 372795536Sscottl vmi->MethId = sc->scsi_method_id; 372895536Sscottl vmi->ObjId = 0; 372995536Sscottl vmi->IoctlCmd = GetBusInfo; 373095536Sscottl 373195536Sscottl error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3732177463Semaste sizeof(struct aac_vmi_businf_resp)); 373395536Sscottl if (error) { 373495536Sscottl device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 373595536Sscottl error); 373695536Sscottl aac_release_sync_fib(sc); 3737151893Scsjp mtx_unlock(&sc->aac_io_lock); 373895536Sscottl return; 373995536Sscottl } 374095536Sscottl 374195536Sscottl vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 374295536Sscottl if (vmi_resp->Status != ST_OK) { 374395536Sscottl device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 374495536Sscottl vmi_resp->Status); 374595536Sscottl aac_release_sync_fib(sc); 3746151893Scsjp mtx_unlock(&sc->aac_io_lock); 374795536Sscottl return; 374895536Sscottl } 374995536Sscottl 375095536Sscottl bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 375195536Sscottl aac_release_sync_fib(sc); 3752151893Scsjp mtx_unlock(&sc->aac_io_lock); 375395536Sscottl 375495536Sscottl found = 0; 375595536Sscottl for (i = 0; i < businfo.BusCount; i++) { 375695536Sscottl if (businfo.BusValid[i] != AAC_BUS_VALID) 375795536Sscottl continue; 375895536Sscottl 3759110428Sscottl caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3760110428Sscottl M_AACBUF, M_NOWAIT | M_ZERO); 3761143838Sscottl if (caminf == NULL) { 3762143838Sscottl device_printf(sc->aac_dev, 3763143838Sscottl "No memory to add passthrough bus %d\n", i); 3764143838Sscottl break; 3765151086Sscottl }; 376695536Sscottl 376795536Sscottl child = device_add_child(sc->aac_dev, "aacp", -1); 376895536Sscottl if (child == NULL) { 3769143838Sscottl device_printf(sc->aac_dev, 3770143838Sscottl "device_add_child failed for passthrough bus %d\n", 3771143838Sscottl i); 3772143838Sscottl free(caminf, M_AACBUF); 3773152388Sschweikh break; 377495536Sscottl } 377595536Sscottl 377695536Sscottl caminf->TargetsPerBus = businfo.TargetsPerBus; 377795536Sscottl caminf->BusNumber = i; 377895536Sscottl caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 377995536Sscottl caminf->aac_sc = sc; 3780110432Sscottl caminf->sim_dev = child; 378195536Sscottl 378295536Sscottl device_set_ivars(child, caminf); 378395536Sscottl device_set_desc(child, "SCSI Passthrough Bus"); 3784110426Sscottl TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 378595536Sscottl 378695536Sscottl found = 1; 378795536Sscottl } 378895536Sscottl 378995536Sscottl if (found) 379095536Sscottl bus_generic_attach(sc->aac_dev); 379195536Sscottl} 3792