aac.c revision 196037
1170530Ssam/*- 2178354Ssam * Copyright (c) 2000 Michael Smith 3170530Ssam * Copyright (c) 2001 Scott Long 4170530Ssam * Copyright (c) 2000 BSDi 5170530Ssam * Copyright (c) 2001 Adaptec, Inc. 6170530Ssam * All rights reserved. 7170530Ssam * 8170530Ssam * Redistribution and use in source and binary forms, with or without 9170530Ssam * modification, are permitted provided that the following conditions 10170530Ssam * are met: 11170530Ssam * 1. Redistributions of source code must retain the above copyright 12170530Ssam * notice, this list of conditions and the following disclaimer. 13170530Ssam * 2. Redistributions in binary form must reproduce the above copyright 14170530Ssam * notice, this list of conditions and the following disclaimer in the 15170530Ssam * documentation and/or other materials provided with the distribution. 16170530Ssam * 17170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18170530Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19170530Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20170530Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21170530Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22170530Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23170530Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24170530Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25170530Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26170530Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27170530Ssam * SUCH DAMAGE. 28170530Ssam */ 29170530Ssam 30170530Ssam#include <sys/cdefs.h> 31170530Ssam__FBSDID("$FreeBSD: head/sys/dev/aac/aac.c 196037 2009-08-02 14:28:40Z attilio $"); 32170530Ssam 33170530Ssam/* 34170530Ssam * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 35170530Ssam */ 36178354Ssam#define AAC_DRIVER_VERSION 0x02000000 37170530Ssam#define AAC_DRIVERNAME "aac" 38170530Ssam 39170530Ssam#include "opt_aac.h" 40170530Ssam 41170530Ssam/* #include <stddef.h> */ 42170530Ssam#include <sys/param.h> 43170530Ssam#include <sys/systm.h> 44170530Ssam#include <sys/malloc.h> 45170530Ssam#include <sys/kernel.h> 46170530Ssam#include <sys/kthread.h> 47170530Ssam#include <sys/sysctl.h> 48170530Ssam#include <sys/poll.h> 49170530Ssam#include <sys/ioccom.h> 50178354Ssam 51170530Ssam#include <sys/bus.h> 52170530Ssam#include <sys/conf.h> 53170530Ssam#include <sys/signalvar.h> 54170530Ssam#include <sys/time.h> 55170530Ssam#include <sys/eventhandler.h> 56178354Ssam#include <sys/rman.h> 57178354Ssam 58178354Ssam#include <machine/bus.h> 59178354Ssam#include <sys/bus_dma.h> 60178354Ssam#include <machine/resource.h> 61178354Ssam 62178354Ssam#include <dev/pci/pcireg.h> 63178354Ssam#include <dev/pci/pcivar.h> 64178354Ssam 65178354Ssam#include <dev/aac/aacreg.h> 66178354Ssam#include <sys/aac_ioctl.h> 67178354Ssam#include <dev/aac/aacvar.h> 68178354Ssam#include <dev/aac/aac_tables.h> 69178354Ssam 70178354Ssamstatic void aac_startup(void *arg); 71178354Ssamstatic void aac_add_container(struct aac_softc *sc, 72178354Ssam struct aac_mntinforesp *mir, int f); 73170530Ssamstatic void aac_get_bus_info(struct aac_softc *sc); 74170530Ssamstatic void aac_daemon(void *arg); 75170530Ssam 76170530Ssam/* Command Processing */ 77170530Ssamstatic void aac_timeout(struct aac_softc *sc); 78170530Ssamstatic void aac_complete(void *context, int pending); 79170530Ssamstatic int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 80170530Ssamstatic void aac_bio_complete(struct aac_command *cm); 81173273Ssamstatic int aac_wait_command(struct aac_command *cm); 82173273Ssamstatic void aac_command_thread(struct aac_softc *sc); 83173273Ssam 84173273Ssam/* Command Buffer Management */ 85173273Ssamstatic void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 86178354Ssam int nseg, int error); 87178354Ssamstatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 88178354Ssam int nseg, int error); 89173273Ssamstatic int aac_alloc_commands(struct aac_softc *sc); 90178354Ssamstatic void aac_free_commands(struct aac_softc *sc); 91178354Ssamstatic void aac_unmap_command(struct aac_command *cm); 92178354Ssam 93178354Ssam/* Hardware Interface */ 94178354Ssamstatic int aac_alloc(struct aac_softc *sc); 95178354Ssamstatic void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 96178354Ssam int error); 97178354Ssamstatic int aac_check_firmware(struct aac_softc *sc); 98178354Ssamstatic int aac_init(struct aac_softc *sc); 99178354Ssamstatic int aac_sync_command(struct aac_softc *sc, u_int32_t command, 100178354Ssam u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 101178354Ssam u_int32_t arg3, u_int32_t *sp); 102178354Ssamstatic int aac_setup_intr(struct aac_softc *sc); 103170530Ssamstatic int aac_enqueue_fib(struct aac_softc *sc, int queue, 104178354Ssam struct aac_command *cm); 105178354Ssamstatic int aac_dequeue_fib(struct aac_softc *sc, int queue, 106170530Ssam u_int32_t *fib_size, struct aac_fib **fib_addr); 107170530Ssamstatic int aac_enqueue_response(struct aac_softc *sc, int queue, 108170530Ssam struct aac_fib *fib); 109170530Ssam 110170530Ssam/* Falcon/PPC interface */ 111170530Ssamstatic int aac_fa_get_fwstatus(struct aac_softc *sc); 112170530Ssamstatic void aac_fa_qnotify(struct aac_softc *sc, int qbit); 113170530Ssamstatic int aac_fa_get_istatus(struct aac_softc *sc); 114170530Ssamstatic void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 115170530Ssamstatic void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 116170530Ssam u_int32_t arg0, u_int32_t arg1, 117170530Ssam u_int32_t arg2, u_int32_t arg3); 118170530Ssamstatic int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 119170530Ssamstatic void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 120170530Ssam 121170530Ssamstruct aac_interface aac_fa_interface = { 122170530Ssam aac_fa_get_fwstatus, 123178354Ssam aac_fa_qnotify, 124170530Ssam aac_fa_get_istatus, 125170530Ssam aac_fa_clear_istatus, 126170530Ssam aac_fa_set_mailbox, 127170530Ssam aac_fa_get_mailbox, 128173273Ssam aac_fa_set_interrupts, 129173273Ssam NULL, NULL, NULL 130178354Ssam}; 131173273Ssam 132178354Ssam/* StrongARM interface */ 133178354Ssamstatic int aac_sa_get_fwstatus(struct aac_softc *sc); 134178354Ssamstatic void aac_sa_qnotify(struct aac_softc *sc, int qbit); 135178354Ssamstatic int aac_sa_get_istatus(struct aac_softc *sc); 136173273Ssamstatic void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 137178354Ssamstatic void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 138178354Ssam u_int32_t arg0, u_int32_t arg1, 139178354Ssam u_int32_t arg2, u_int32_t arg3); 140178354Ssamstatic int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 141178354Ssamstatic void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 142178354Ssam 143178354Ssamstruct aac_interface aac_sa_interface = { 144178354Ssam aac_sa_get_fwstatus, 145178354Ssam aac_sa_qnotify, 146178354Ssam aac_sa_get_istatus, 147178354Ssam aac_sa_clear_istatus, 148178354Ssam aac_sa_set_mailbox, 149178354Ssam aac_sa_get_mailbox, 150178354Ssam aac_sa_set_interrupts, 151178354Ssam NULL, NULL, NULL 152178354Ssam}; 153170530Ssam 154173273Ssam/* i960Rx interface */ 155173273Ssamstatic int aac_rx_get_fwstatus(struct aac_softc *sc); 156170530Ssamstatic void aac_rx_qnotify(struct aac_softc *sc, int qbit); 157170530Ssamstatic int aac_rx_get_istatus(struct aac_softc *sc); 158178354Ssamstatic void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 159178354Ssamstatic void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 160178354Ssam u_int32_t arg0, u_int32_t arg1, 161178354Ssam u_int32_t arg2, u_int32_t arg3); 162178354Ssamstatic int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 163173273Ssamstatic void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 164178354Ssamstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 165178354Ssamstatic int aac_rx_get_outb_queue(struct aac_softc *sc); 166178354Ssamstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 167178354Ssam 168170530Ssamstruct aac_interface aac_rx_interface = { 169183256Ssam aac_rx_get_fwstatus, 170183256Ssam aac_rx_qnotify, 171183256Ssam aac_rx_get_istatus, 172183256Ssam aac_rx_clear_istatus, 173170530Ssam aac_rx_set_mailbox, 174178354Ssam aac_rx_get_mailbox, 175178354Ssam aac_rx_set_interrupts, 176178354Ssam aac_rx_send_command, 177178354Ssam aac_rx_get_outb_queue, 178178354Ssam aac_rx_set_outb_queue 179178354Ssam}; 180170530Ssam 181178354Ssam/* Rocket/MIPS interface */ 182178354Ssamstatic int aac_rkt_get_fwstatus(struct aac_softc *sc); 183178354Ssamstatic void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 184170530Ssamstatic int aac_rkt_get_istatus(struct aac_softc *sc); 185170530Ssamstatic void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 186170530Ssamstatic void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 187178354Ssam u_int32_t arg0, u_int32_t arg1, 188170530Ssam u_int32_t arg2, u_int32_t arg3); 189170530Ssamstatic int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 190170530Ssamstatic void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 191170530Ssamstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 192170530Ssamstatic int aac_rkt_get_outb_queue(struct aac_softc *sc); 193170530Ssamstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 194170530Ssam 195170530Ssamstruct aac_interface aac_rkt_interface = { 196170530Ssam aac_rkt_get_fwstatus, 197170530Ssam aac_rkt_qnotify, 198170530Ssam aac_rkt_get_istatus, 199170530Ssam aac_rkt_clear_istatus, 200172226Ssam aac_rkt_set_mailbox, 201172226Ssam aac_rkt_get_mailbox, 202170530Ssam aac_rkt_set_interrupts, 203170530Ssam aac_rkt_send_command, 204178354Ssam aac_rkt_get_outb_queue, 205170530Ssam aac_rkt_set_outb_queue 206170530Ssam}; 207170530Ssam 208170530Ssam/* Debugging and Diagnostics */ 209170530Ssamstatic void aac_describe_controller(struct aac_softc *sc); 210170530Ssamstatic char *aac_describe_code(struct aac_code_lookup *table, 211170530Ssam u_int32_t code); 212170530Ssam 213170530Ssam/* Management Interface */ 214170530Ssamstatic d_open_t aac_open; 215170530Ssamstatic d_close_t aac_close; 216170530Ssamstatic d_ioctl_t aac_ioctl; 217170530Ssamstatic d_poll_t aac_poll; 218170530Ssamstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 219170530Ssamstatic int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 220170530Ssamstatic void aac_handle_aif(struct aac_softc *sc, 221170530Ssam struct aac_fib *fib); 222170530Ssamstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 223170530Ssamstatic int aac_open_aif(struct aac_softc *sc, caddr_t arg); 224173273Ssamstatic int aac_close_aif(struct aac_softc *sc, caddr_t arg); 225170530Ssamstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 226170530Ssamstatic int aac_return_aif(struct aac_softc *sc, 227170530Ssam struct aac_fib_context *ctx, caddr_t uptr); 228170530Ssamstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 229170530Ssamstatic int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 230170530Ssamstatic int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 231170530Ssamstatic void aac_ioctl_event(struct aac_softc *sc, 232170530Ssam struct aac_event *event, void *arg); 233170530Ssamstatic struct aac_mntinforesp * 234170530Ssam aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); 235170530Ssam 236170530Ssamstatic struct cdevsw aac_cdevsw = { 237170530Ssam .d_version = D_VERSION, 238170530Ssam .d_flags = D_NEEDGIANT, 239178354Ssam .d_open = aac_open, 240173462Ssam .d_close = aac_close, 241170530Ssam .d_ioctl = aac_ioctl, 242170530Ssam .d_poll = aac_poll, 243170530Ssam .d_name = "aac", 244170530Ssam}; 245170530Ssam 246178354SsamMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 247170530Ssam 248170530Ssam/* sysctl node */ 249170530SsamSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 250170530Ssam 251170530Ssam/* 252170530Ssam * Device Interface 253170530Ssam */ 254170530Ssam 255170530Ssam/* 256170530Ssam * Initialize the controller and softc 257178354Ssam */ 258173462Ssamint 259178354Ssamaac_attach(struct aac_softc *sc) 260170530Ssam{ 261170530Ssam int error, unit; 262173462Ssam 263170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 264170530Ssam 265170530Ssam /* 266178354Ssam * Initialize per-controller queues. 267170530Ssam */ 268170530Ssam aac_initq_free(sc); 269178354Ssam aac_initq_ready(sc); 270170530Ssam aac_initq_busy(sc); 271170530Ssam aac_initq_bio(sc); 272170530Ssam 273178354Ssam /* 274170530Ssam * Initialize command-completion task. 275170530Ssam */ 276170530Ssam TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 277170530Ssam 278170530Ssam /* mark controller as suspended until we get ourselves organised */ 279170530Ssam sc->aac_state |= AAC_STATE_SUSPEND; 280170530Ssam 281170530Ssam /* 282170530Ssam * Check that the firmware on the card is supported. 283170530Ssam */ 284170530Ssam if ((error = aac_check_firmware(sc)) != 0) 285170530Ssam return(error); 286170530Ssam 287170530Ssam /* 288170530Ssam * Initialize locks 289170530Ssam */ 290170530Ssam mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 291170530Ssam mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 292170530Ssam mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 293170530Ssam TAILQ_INIT(&sc->aac_container_tqh); 294170530Ssam TAILQ_INIT(&sc->aac_ev_cmfree); 295170530Ssam 296170530Ssam /* Initialize the clock daemon callout. */ 297170530Ssam callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 298170530Ssam 299170530Ssam /* 300170530Ssam * Initialize the adapter. 301170530Ssam */ 302170530Ssam if ((error = aac_alloc(sc)) != 0) 303170530Ssam return(error); 304170530Ssam if ((error = aac_init(sc)) != 0) 305170530Ssam return(error); 306170530Ssam 307170530Ssam /* 308170530Ssam * Allocate and connect our interrupt. 309170530Ssam */ 310178354Ssam if ((error = aac_setup_intr(sc)) != 0) 311178354Ssam return(error); 312178354Ssam 313178354Ssam /* 314178354Ssam * Print a little information about the controller. 315178354Ssam */ 316178354Ssam aac_describe_controller(sc); 317178354Ssam 318178354Ssam /* 319178354Ssam * Register to probe our containers later. 320178354Ssam */ 321178354Ssam sc->aac_ich.ich_func = aac_startup; 322178354Ssam sc->aac_ich.ich_arg = sc; 323178354Ssam if (config_intrhook_establish(&sc->aac_ich) != 0) { 324178354Ssam device_printf(sc->aac_dev, 325178354Ssam "can't establish configuration hook\n"); 326178354Ssam return(ENXIO); 327178354Ssam } 328178354Ssam 329178354Ssam /* 330170530Ssam * Make the control device. 331170530Ssam */ 332170530Ssam unit = device_get_unit(sc->aac_dev); 333170530Ssam sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 334170530Ssam 0640, "aac%d", unit); 335170530Ssam (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 336178354Ssam (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 337170530Ssam sc->aac_dev_t->si_drv1 = sc; 338170530Ssam 339170530Ssam /* Create the AIF thread */ 340170530Ssam if (kproc_create((void(*)(void *))aac_command_thread, sc, 341170530Ssam &sc->aifthread, 0, 0, "aac%daif", unit)) 342183247Ssam panic("Could not create AIF thread"); 343170530Ssam 344170530Ssam /* Register the shutdown method to only be called post-dump */ 345170530Ssam if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 346170530Ssam sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 347170530Ssam device_printf(sc->aac_dev, 348183247Ssam "shutdown event registration failed\n"); 349183247Ssam 350178354Ssam /* Register with CAM for the non-DASD devices */ 351170530Ssam if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 352170530Ssam TAILQ_INIT(&sc->aac_sim_tqh); 353170530Ssam aac_get_bus_info(sc); 354170530Ssam } 355170530Ssam 356170530Ssam mtx_lock(&sc->aac_io_lock); 357170530Ssam callout_reset(&sc->aac_daemontime, 30 * 60 * hz, aac_daemon, sc); 358170530Ssam mtx_unlock(&sc->aac_io_lock); 359170530Ssam 360170530Ssam return(0); 361170530Ssam} 362170530Ssam 363170530Ssamstatic void 364178354Ssamaac_daemon(void *arg) 365170530Ssam{ 366170530Ssam struct timeval tv; 367170530Ssam struct aac_softc *sc; 368170530Ssam struct aac_fib *fib; 369170530Ssam 370170530Ssam sc = arg; 371170530Ssam mtx_assert(&sc->aac_io_lock, MA_OWNED); 372170530Ssam 373170530Ssam if (callout_pending(&sc->aac_daemontime) || 374170530Ssam callout_active(&sc->aac_daemontime) == 0) 375170530Ssam return; 376170530Ssam getmicrotime(&tv); 377170530Ssam aac_alloc_sync_fib(sc, &fib); 378170530Ssam *(uint32_t *)fib->data = tv.tv_sec; 379170530Ssam aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); 380170530Ssam aac_release_sync_fib(sc); 381170530Ssam callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 382170530Ssam} 383170530Ssam 384170530Ssamvoid 385170530Ssamaac_add_event(struct aac_softc *sc, struct aac_event *event) 386170530Ssam{ 387170530Ssam 388170530Ssam switch (event->ev_type & AAC_EVENT_MASK) { 389170530Ssam case AAC_EVENT_CMFREE: 390170530Ssam TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 391170530Ssam break; 392170530Ssam default: 393170530Ssam device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 394178354Ssam event->ev_type); 395170530Ssam break; 396173273Ssam } 397173273Ssam 398173273Ssam return; 399173273Ssam} 400173273Ssam 401178354Ssam/* 402170530Ssam * Request information of container #cid 403170530Ssam */ 404173273Ssamstatic struct aac_mntinforesp * 405170530Ssamaac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) 406173273Ssam{ 407170530Ssam struct aac_mntinfo *mi; 408170530Ssam 409173273Ssam mi = (struct aac_mntinfo *)&fib->data[0]; 410170530Ssam /* use 64-bit LBA if enabled */ 411178354Ssam mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? 412170530Ssam VM_NameServe64 : VM_NameServe; 413170530Ssam mi->MntType = FT_FILESYS; 414170530Ssam mi->MntCount = cid; 415173273Ssam 416170530Ssam if (aac_sync_fib(sc, ContainerCommand, 0, fib, 417170530Ssam sizeof(struct aac_mntinfo))) { 418170530Ssam printf("Error probing container %d\n", cid); 419170530Ssam return (NULL); 420170530Ssam } 421173273Ssam 422178354Ssam return ((struct aac_mntinforesp *)&fib->data[0]); 423173273Ssam} 424170530Ssam 425173273Ssam/* 426170530Ssam * Probe for containers, create disks. 427170530Ssam */ 428170530Ssamstatic void 429173273Ssamaac_startup(void *arg) 430170530Ssam{ 431170530Ssam struct aac_softc *sc; 432173273Ssam struct aac_fib *fib; 433173273Ssam struct aac_mntinforesp *mir; 434173273Ssam int count = 0, i = 0; 435173273Ssam 436173273Ssam sc = (struct aac_softc *)arg; 437173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 438173273Ssam 439173273Ssam /* disconnect ourselves from the intrhook chain */ 440178354Ssam config_intrhook_disestablish(&sc->aac_ich); 441173273Ssam 442173273Ssam mtx_lock(&sc->aac_io_lock); 443173273Ssam aac_alloc_sync_fib(sc, &fib); 444173273Ssam 445173273Ssam /* loop over possible containers */ 446173273Ssam do { 447173273Ssam if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 448173273Ssam continue; 449173273Ssam if (i == 0) 450173273Ssam count = mir->MntRespCount; 451173273Ssam aac_add_container(sc, mir, 0); 452173273Ssam i++; 453173273Ssam } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 454173273Ssam 455173273Ssam aac_release_sync_fib(sc); 456173273Ssam mtx_unlock(&sc->aac_io_lock); 457173273Ssam 458173273Ssam /* poke the bus to actually attach the child devices */ 459178354Ssam if (bus_generic_attach(sc->aac_dev)) 460173273Ssam device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 461173273Ssam 462173273Ssam /* mark the controller up */ 463173273Ssam sc->aac_state &= ~AAC_STATE_SUSPEND; 464173273Ssam 465173273Ssam /* enable interrupts now */ 466173273Ssam AAC_UNMASK_INTERRUPTS(sc); 467173273Ssam} 468173273Ssam 469173273Ssam/* 470173273Ssam * Create a device to represent a new container 471173273Ssam */ 472173273Ssamstatic void 473173273Ssamaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 474178354Ssam{ 475178354Ssam struct aac_container *co; 476178354Ssam device_t child; 477178354Ssam 478173273Ssam /* 479173273Ssam * Check container volume type for validity. Note that many of 480173273Ssam * the possible types may never show up. 481173273Ssam */ 482173273Ssam if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 483173273Ssam co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 484173273Ssam M_NOWAIT | M_ZERO); 485173273Ssam if (co == NULL) 486173273Ssam panic("Out of memory?!"); 487173273Ssam fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", 488173273Ssam mir->MntTable[0].ObjectId, 489173273Ssam mir->MntTable[0].FileSystemName, 490173273Ssam mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 491178354Ssam 492173273Ssam if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 493173273Ssam device_printf(sc->aac_dev, "device_add_child failed\n"); 494173273Ssam else 495173273Ssam device_set_ivars(child, co); 496173273Ssam device_set_desc(child, aac_describe_code(aac_container_types, 497173273Ssam mir->MntTable[0].VolType)); 498173273Ssam co->co_disk = child; 499173273Ssam co->co_found = f; 500173273Ssam bcopy(&mir->MntTable[0], &co->co_mntobj, 501173273Ssam sizeof(struct aac_mntobj)); 502173273Ssam mtx_lock(&sc->aac_container_lock); 503170530Ssam TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 504170530Ssam mtx_unlock(&sc->aac_container_lock); 505170530Ssam } 506173273Ssam} 507170530Ssam 508170530Ssam/* 509170530Ssam * Allocate resources associated with (sc) 510170530Ssam */ 511170530Ssamstatic int 512170530Ssamaac_alloc(struct aac_softc *sc) 513170530Ssam{ 514170530Ssam 515173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 516173273Ssam 517178354Ssam /* 518170530Ssam * Create DMA tag for mapping buffers into controller-addressable space. 519170530Ssam */ 520170530Ssam if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 521170530Ssam 1, 0, /* algnmnt, boundary */ 522170530Ssam (sc->flags & AAC_FLAGS_SG_64BIT) ? 523170530Ssam BUS_SPACE_MAXADDR : 524183247Ssam BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 525183247Ssam BUS_SPACE_MAXADDR, /* highaddr */ 526170530Ssam NULL, NULL, /* filter, filterarg */ 527170530Ssam MAXBSIZE, /* maxsize */ 528170530Ssam sc->aac_sg_tablesize, /* nsegments */ 529170530Ssam MAXBSIZE, /* maxsegsize */ 530183247Ssam BUS_DMA_ALLOCNOW, /* flags */ 531183247Ssam busdma_lock_mutex, /* lockfunc */ 532183247Ssam &sc->aac_io_lock, /* lockfuncarg */ 533183247Ssam &sc->aac_buffer_dmat)) { 534183247Ssam device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 535183247Ssam return (ENOMEM); 536183247Ssam } 537170530Ssam 538173273Ssam /* 539173273Ssam * Create DMA tag for mapping FIBs into controller-addressable space.. 540173273Ssam */ 541173273Ssam if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 542173273Ssam 1, 0, /* algnmnt, boundary */ 543170530Ssam (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 544170530Ssam BUS_SPACE_MAXADDR_32BIT : 545170530Ssam 0x7fffffff, /* lowaddr */ 546170530Ssam BUS_SPACE_MAXADDR, /* highaddr */ 547170530Ssam NULL, NULL, /* filter, filterarg */ 548173273Ssam sc->aac_max_fibs_alloc * 549170530Ssam sc->aac_max_fib_size, /* maxsize */ 550182827Ssam 1, /* nsegments */ 551182827Ssam sc->aac_max_fibs_alloc * 552182827Ssam sc->aac_max_fib_size, /* maxsize */ 553182827Ssam 0, /* flags */ 554182827Ssam NULL, NULL, /* No locking needed */ 555182827Ssam &sc->aac_fib_dmat)) { 556182827Ssam device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 557182827Ssam return (ENOMEM); 558182827Ssam } 559182827Ssam 560182827Ssam /* 561182827Ssam * Create DMA tag for the common structure and allocate it. 562182827Ssam */ 563182827Ssam if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 564182827Ssam 1, 0, /* algnmnt, boundary */ 565173273Ssam (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 566173273Ssam BUS_SPACE_MAXADDR_32BIT : 567170530Ssam 0x7fffffff, /* lowaddr */ 568170530Ssam BUS_SPACE_MAXADDR, /* highaddr */ 569170530Ssam NULL, NULL, /* filter, filterarg */ 570170530Ssam 8192 + sizeof(struct aac_common), /* maxsize */ 571170530Ssam 1, /* nsegments */ 572170530Ssam BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 573170530Ssam 0, /* flags */ 574170530Ssam NULL, NULL, /* No locking needed */ 575170530Ssam &sc->aac_common_dmat)) { 576170530Ssam device_printf(sc->aac_dev, 577170530Ssam "can't allocate common structure DMA tag\n"); 578173273Ssam return (ENOMEM); 579170530Ssam } 580170530Ssam if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 581170530Ssam BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 582170530Ssam device_printf(sc->aac_dev, "can't allocate common structure\n"); 583170530Ssam return (ENOMEM); 584170530Ssam } 585173273Ssam 586170530Ssam /* 587170530Ssam * Work around a bug in the 2120 and 2200 that cannot DMA commands 588170530Ssam * below address 8192 in physical memory. 589173273Ssam * XXX If the padding is not needed, can it be put to use instead 590170530Ssam * of ignored? 591170530Ssam */ 592170530Ssam (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 593173273Ssam sc->aac_common, 8192 + sizeof(*sc->aac_common), 594170530Ssam aac_common_map, sc, 0); 595173273Ssam 596173273Ssam if (sc->aac_common_busaddr < 8192) { 597173273Ssam sc->aac_common = (struct aac_common *) 598173273Ssam ((uint8_t *)sc->aac_common + 8192); 599173273Ssam sc->aac_common_busaddr += 8192; 600173273Ssam } 601173273Ssam bzero(sc->aac_common, sizeof(*sc->aac_common)); 602173273Ssam 603173273Ssam /* Allocate some FIBs and associated command structs */ 604173273Ssam TAILQ_INIT(&sc->aac_fibmap_tqh); 605173273Ssam sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 606173273Ssam M_AACBUF, M_WAITOK|M_ZERO); 607173273Ssam while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 608173273Ssam if (aac_alloc_commands(sc) != 0) 609170530Ssam break; 610173273Ssam } 611173273Ssam if (sc->total_fibs == 0) 612173273Ssam return (ENOMEM); 613173273Ssam 614173273Ssam return (0); 615170530Ssam} 616173273Ssam 617173273Ssam/* 618173273Ssam * Free all of the resources associated with (sc) 619173273Ssam * 620173273Ssam * Should not be called if the controller is active. 621173273Ssam */ 622173273Ssamvoid 623173273Ssamaac_free(struct aac_softc *sc) 624178354Ssam{ 625173273Ssam 626173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 627173273Ssam 628173273Ssam /* remove the control device */ 629173273Ssam if (sc->aac_dev_t != NULL) 630173273Ssam destroy_dev(sc->aac_dev_t); 631173273Ssam 632173273Ssam /* throw away any FIB buffers, discard the FIB DMA tag */ 633173273Ssam aac_free_commands(sc); 634173273Ssam if (sc->aac_fib_dmat) 635173273Ssam bus_dma_tag_destroy(sc->aac_fib_dmat); 636173273Ssam 637173273Ssam free(sc->aac_commands, M_AACBUF); 638173273Ssam 639173273Ssam /* destroy the common area */ 640173273Ssam if (sc->aac_common) { 641173273Ssam bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 642173273Ssam bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 643178354Ssam sc->aac_common_dmamap); 644173273Ssam } 645178354Ssam if (sc->aac_common_dmat) 646173273Ssam bus_dma_tag_destroy(sc->aac_common_dmat); 647173273Ssam 648173273Ssam /* disconnect the interrupt handler */ 649173273Ssam if (sc->aac_intr) 650173273Ssam bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 651178354Ssam if (sc->aac_irq != NULL) 652173273Ssam bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 653173273Ssam sc->aac_irq); 654173273Ssam 655173273Ssam /* destroy data-transfer DMA tag */ 656173273Ssam if (sc->aac_buffer_dmat) 657173273Ssam bus_dma_tag_destroy(sc->aac_buffer_dmat); 658173273Ssam 659173273Ssam /* destroy the parent DMA tag */ 660173273Ssam if (sc->aac_parent_dmat) 661173273Ssam bus_dma_tag_destroy(sc->aac_parent_dmat); 662173273Ssam 663178354Ssam /* release the register window mapping */ 664173273Ssam if (sc->aac_regs_res0 != NULL) 665170530Ssam bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 666173273Ssam sc->aac_regs_rid0, sc->aac_regs_res0); 667170530Ssam if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) 668178354Ssam bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 669170530Ssam sc->aac_regs_rid1, sc->aac_regs_res1); 670173273Ssam} 671173273Ssam 672173273Ssam/* 673173273Ssam * Disconnect from the controller completely, in preparation for unload. 674173273Ssam */ 675173273Ssamint 676173273Ssamaac_detach(device_t dev) 677173273Ssam{ 678173273Ssam struct aac_softc *sc; 679173273Ssam struct aac_container *co; 680173273Ssam struct aac_sim *sim; 681173273Ssam int error; 682170530Ssam 683170530Ssam sc = device_get_softc(dev); 684173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 685173273Ssam 686170530Ssam if (sc->aac_state & AAC_STATE_OPEN) 687178354Ssam return(EBUSY); 688173273Ssam 689178354Ssam callout_drain(&sc->aac_daemontime); 690173273Ssam 691173273Ssam /* Remove the child containers */ 692173273Ssam while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 693173273Ssam error = device_delete_child(dev, co->co_disk); 694178354Ssam if (error) 695173273Ssam return (error); 696170530Ssam TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 697173273Ssam free(co, M_AACBUF); 698170530Ssam } 699173273Ssam 700173273Ssam /* Remove the CAM SIMs */ 701170530Ssam while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 702170530Ssam TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 703170530Ssam error = device_delete_child(dev, sim->sim_dev); 704170530Ssam if (error) 705170530Ssam return (error); 706170530Ssam free(sim, M_AACBUF); 707173273Ssam } 708170530Ssam 709170530Ssam if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 710170530Ssam sc->aifflags |= AAC_AIFFLAGS_EXIT; 711170530Ssam wakeup(sc->aifthread); 712178354Ssam tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 713170530Ssam } 714170530Ssam 715170530Ssam if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 716170530Ssam panic("Cannot shutdown AIF thread"); 717170530Ssam 718173273Ssam if ((error = aac_shutdown(dev))) 719173273Ssam return(error); 720178354Ssam 721173273Ssam EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 722173273Ssam 723178354Ssam aac_free(sc); 724173273Ssam 725173273Ssam mtx_destroy(&sc->aac_aifq_lock); 726170530Ssam mtx_destroy(&sc->aac_io_lock); 727170530Ssam mtx_destroy(&sc->aac_container_lock); 728170530Ssam 729170530Ssam return(0); 730170530Ssam} 731170530Ssam 732170530Ssam/* 733170530Ssam * Bring the controller down to a dormant state and detach all child devices. 734178354Ssam * 735170530Ssam * This function is called before detach or system shutdown. 736170530Ssam * 737178354Ssam * Note that we can assume that the bioq on the controller is empty, as we won't 738170530Ssam * allow shutdown if any device is open. 739170530Ssam */ 740178354Ssamint 741170530Ssamaac_shutdown(device_t dev) 742173273Ssam{ 743173273Ssam struct aac_softc *sc; 744170530Ssam struct aac_fib *fib; 745170530Ssam struct aac_close_command *cc; 746173273Ssam 747170530Ssam sc = device_get_softc(dev); 748173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 749173273Ssam 750170530Ssam sc->aac_state |= AAC_STATE_SUSPEND; 751178354Ssam 752173273Ssam /* 753170530Ssam * Send a Container shutdown followed by a HostShutdown FIB to the 754173273Ssam * controller to convince it that we don't want to talk to it anymore. 755173273Ssam * We've been closed and all I/O completed already 756178354Ssam */ 757173273Ssam device_printf(sc->aac_dev, "shutting down controller..."); 758173273Ssam 759173273Ssam mtx_lock(&sc->aac_io_lock); 760173273Ssam aac_alloc_sync_fib(sc, &fib); 761173273Ssam cc = (struct aac_close_command *)&fib->data[0]; 762173273Ssam 763173273Ssam bzero(cc, sizeof(struct aac_close_command)); 764173273Ssam cc->Command = VM_CloseAll; 765173273Ssam cc->ContainerId = 0xffffffff; 766170530Ssam if (aac_sync_fib(sc, ContainerCommand, 0, fib, 767173273Ssam sizeof(struct aac_close_command))) 768170530Ssam printf("FAILED.\n"); 769173273Ssam else 770173273Ssam printf("done\n"); 771170530Ssam#if 0 772178354Ssam else { 773173273Ssam fib->data[0] = 0; 774173273Ssam /* 775173273Ssam * XXX Issuing this command to the controller makes it shut down 776173273Ssam * but also keeps it from coming back up without a reset of the 777173273Ssam * PCI bus. This is not desirable if you are just unloading the 778173273Ssam * driver module with the intent to reload it later. 779178354Ssam */ 780173273Ssam if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 781170530Ssam fib, 1)) { 782170530Ssam printf("FAILED.\n"); 783170530Ssam } else { 784170530Ssam printf("done.\n"); 785170530Ssam } 786170530Ssam } 787170530Ssam#endif 788170530Ssam 789170530Ssam AAC_MASK_INTERRUPTS(sc); 790183254Ssam aac_release_sync_fib(sc); 791170530Ssam mtx_unlock(&sc->aac_io_lock); 792170530Ssam 793170530Ssam return(0); 794170530Ssam} 795173273Ssam 796173273Ssam/* 797173273Ssam * Bring the controller to a quiescent state, ready for system suspend. 798173273Ssam */ 799173273Ssamint 800173273Ssamaac_suspend(device_t dev) 801173273Ssam{ 802173273Ssam struct aac_softc *sc; 803170530Ssam 804170530Ssam sc = device_get_softc(dev); 805170530Ssam 806173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 807170530Ssam sc->aac_state |= AAC_STATE_SUSPEND; 808173273Ssam 809170530Ssam AAC_MASK_INTERRUPTS(sc); 810170530Ssam return(0); 811170530Ssam} 812170530Ssam 813170530Ssam/* 814170530Ssam * Bring the controller back to a state ready for operation. 815170530Ssam */ 816170530Ssamint 817170530Ssamaac_resume(device_t dev) 818170530Ssam{ 819170530Ssam struct aac_softc *sc; 820170530Ssam 821170530Ssam sc = device_get_softc(dev); 822170530Ssam 823170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 824170530Ssam sc->aac_state &= ~AAC_STATE_SUSPEND; 825170530Ssam AAC_UNMASK_INTERRUPTS(sc); 826173273Ssam return(0); 827173273Ssam} 828173273Ssam 829173273Ssam/* 830173273Ssam * Interrupt handler for NEW_COMM interface. 831170530Ssam */ 832178354Ssamvoid 833178354Ssamaac_new_intr(void *arg) 834173273Ssam{ 835173273Ssam struct aac_softc *sc; 836173273Ssam u_int32_t index, fast; 837173273Ssam struct aac_command *cm; 838170530Ssam struct aac_fib *fib; 839170530Ssam int i; 840170530Ssam 841170530Ssam sc = (struct aac_softc *)arg; 842170530Ssam 843182828Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 844170530Ssam mtx_lock(&sc->aac_io_lock); 845170530Ssam while (1) { 846178354Ssam index = AAC_GET_OUTB_QUEUE(sc); 847178354Ssam if (index == 0xffffffff) 848178354Ssam index = AAC_GET_OUTB_QUEUE(sc); 849178354Ssam if (index == 0xffffffff) 850178354Ssam break; 851178354Ssam if (index & 2) { 852178354Ssam if (index == 0xfffffffe) { 853178354Ssam /* XXX This means that the controller wants 854178354Ssam * more work. Ignore it for now. 855178354Ssam */ 856178354Ssam continue; 857178354Ssam } 858178354Ssam /* AIF */ 859178354Ssam fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 860178354Ssam M_NOWAIT | M_ZERO); 861178354Ssam if (fib == NULL) { 862178354Ssam /* If we're really this short on memory, 863178354Ssam * hopefully breaking out of the handler will 864178354Ssam * allow something to get freed. This 865178354Ssam * actually sucks a whole lot. 866178354Ssam */ 867178354Ssam break; 868178354Ssam } 869178354Ssam index &= ~2; 870178354Ssam for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 871178354Ssam ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); 872178354Ssam aac_handle_aif(sc, fib); 873178354Ssam free(fib, M_AACBUF); 874178354Ssam 875178354Ssam /* 876178354Ssam * AIF memory is owned by the adapter, so let it 877178354Ssam * know that we are done with it. 878178354Ssam */ 879178354Ssam AAC_SET_OUTB_QUEUE(sc, index); 880178354Ssam AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 881178354Ssam } else { 882178354Ssam fast = index & 1; 883178354Ssam cm = sc->aac_commands + (index >> 2); 884178354Ssam fib = cm->cm_fib; 885173273Ssam if (fast) { 886173273Ssam fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 887173273Ssam *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 888173273Ssam } 889173273Ssam aac_remove_busy(cm); 890173273Ssam aac_unmap_command(cm); 891173273Ssam cm->cm_flags |= AAC_CMD_COMPLETED; 892173273Ssam 893173273Ssam /* is there a completion handler? */ 894173273Ssam if (cm->cm_complete != NULL) { 895173273Ssam cm->cm_complete(cm); 896173273Ssam } else { 897173273Ssam /* assume that someone is sleeping on this 898173273Ssam * command 899173273Ssam */ 900173273Ssam wakeup(cm); 901173273Ssam } 902173273Ssam sc->flags &= ~AAC_QUEUE_FRZN; 903173273Ssam } 904173273Ssam } 905173273Ssam /* see if we can start some more I/O */ 906173273Ssam if ((sc->flags & AAC_QUEUE_FRZN) == 0) 907173273Ssam aac_startio(sc); 908173273Ssam 909173273Ssam mtx_unlock(&sc->aac_io_lock); 910173273Ssam} 911173273Ssam 912173273Ssamint 913173273Ssamaac_fast_intr(void *arg) 914173273Ssam{ 915173273Ssam struct aac_softc *sc; 916173273Ssam u_int16_t reason; 917173273Ssam 918173273Ssam sc = (struct aac_softc *)arg; 919173273Ssam 920173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 921173273Ssam /* 922173273Ssam * Read the status register directly. This is faster than taking the 923173273Ssam * driver lock and reading the queues directly. It also saves having 924173273Ssam * to turn parts of the driver lock into a spin mutex, which would be 925173273Ssam * ugly. 926173273Ssam */ 927173273Ssam reason = AAC_GET_ISTATUS(sc); 928173273Ssam AAC_CLEAR_ISTATUS(sc, reason); 929173273Ssam 930173273Ssam /* handle completion processing */ 931173273Ssam if (reason & AAC_DB_RESPONSE_READY) 932173273Ssam taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 933173273Ssam 934173273Ssam /* controller wants to talk to us */ 935173273Ssam if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 936173273Ssam /* 937178354Ssam * XXX Make sure that we don't get fooled by strange messages 938173273Ssam * that start with a NULL. 939173273Ssam */ 940173273Ssam if ((reason & AAC_DB_PRINTF) && 941178354Ssam (sc->aac_common->ac_printf[0] == 0)) 942173273Ssam sc->aac_common->ac_printf[0] = 32; 943173273Ssam 944173273Ssam /* 945173273Ssam * This might miss doing the actual wakeup. However, the 946173273Ssam * msleep that this is waking up has a timeout, so it will 947173273Ssam * wake up eventually. AIFs and printfs are low enough 948173273Ssam * priority that they can handle hanging out for a few seconds 949173273Ssam * if needed. 950178354Ssam */ 951178354Ssam wakeup(sc->aifthread); 952173273Ssam } 953173273Ssam return (FILTER_HANDLED); 954178354Ssam} 955173273Ssam 956173273Ssam/* 957173273Ssam * Command Processing 958173273Ssam */ 959173273Ssam 960173273Ssam/* 961173273Ssam * Start as much queued I/O as possible on the controller 962173273Ssam */ 963178354Ssamvoid 964173273Ssamaac_startio(struct aac_softc *sc) 965173273Ssam{ 966173273Ssam struct aac_command *cm; 967173273Ssam int error; 968173273Ssam 969173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 970183256Ssam 971183256Ssam for (;;) { 972183256Ssam /* 973173273Ssam * This flag might be set if the card is out of resources. 974173273Ssam * Checking it here prevents an infinite loop of deferrals. 975173273Ssam */ 976173273Ssam if (sc->flags & AAC_QUEUE_FRZN) 977173273Ssam break; 978173273Ssam 979173273Ssam /* 980173273Ssam * Try to get a command that's been put off for lack of 981173273Ssam * resources 982173273Ssam */ 983173273Ssam cm = aac_dequeue_ready(sc); 984173273Ssam 985173273Ssam /* 986173273Ssam * Try to build a command off the bio queue (ignore error 987173273Ssam * return) 988173273Ssam */ 989173273Ssam if (cm == NULL) 990173273Ssam aac_bio_command(sc, &cm); 991178354Ssam 992178354Ssam /* nothing to do? */ 993178354Ssam if (cm == NULL) 994178354Ssam break; 995178354Ssam 996178354Ssam /* don't map more than once */ 997178354Ssam if (cm->cm_flags & AAC_CMD_MAPPED) 998178354Ssam panic("aac: command %p already mapped", cm); 999183253Ssam 1000183253Ssam /* 1001183253Ssam * Set up the command to go to the controller. If there are no 1002178354Ssam * data buffers associated with the command then it can bypass 1003178354Ssam * busdma. 1004178354Ssam */ 1005178354Ssam if (cm->cm_datalen != 0) { 1006178354Ssam error = bus_dmamap_load(sc->aac_buffer_dmat, 1007178354Ssam cm->cm_datamap, cm->cm_data, 1008178354Ssam cm->cm_datalen, 1009178354Ssam aac_map_command_sg, cm, 0); 1010178354Ssam if (error == EINPROGRESS) { 1011178354Ssam fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); 1012178354Ssam sc->flags |= AAC_QUEUE_FRZN; 1013178354Ssam error = 0; 1014178354Ssam } else if (error != 0) 1015178354Ssam panic("aac_startio: unexpected error %d from " 1016178354Ssam "busdma", error); 1017178354Ssam } else 1018173273Ssam aac_map_command_sg(cm, NULL, 0, 0); 1019173273Ssam } 1020173273Ssam} 1021173273Ssam 1022173273Ssam/* 1023173273Ssam * Handle notification of one or more FIBs coming from the controller. 1024173273Ssam */ 1025173273Ssamstatic void 1026173273Ssamaac_command_thread(struct aac_softc *sc) 1027173273Ssam{ 1028173273Ssam struct aac_fib *fib; 1029178354Ssam u_int32_t fib_size; 1030178354Ssam int size, retval; 1031178354Ssam 1032178354Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1033173273Ssam 1034178354Ssam mtx_lock(&sc->aac_io_lock); 1035178354Ssam sc->aifflags = AAC_AIFFLAGS_RUNNING; 1036178354Ssam 1037173273Ssam while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1038173273Ssam 1039173273Ssam retval = 0; 1040173273Ssam if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1041173273Ssam retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1042173273Ssam "aifthd", AAC_PERIODIC_INTERVAL * hz); 1043173273Ssam 1044173273Ssam /* 1045173273Ssam * First see if any FIBs need to be allocated. This needs 1046173273Ssam * to be called without the driver lock because contigmalloc 1047173273Ssam * will grab Giant, and would result in an LOR. 1048173273Ssam */ 1049173273Ssam if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1050173273Ssam mtx_unlock(&sc->aac_io_lock); 1051173273Ssam aac_alloc_commands(sc); 1052173273Ssam mtx_lock(&sc->aac_io_lock); 1053173273Ssam sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1054173273Ssam aac_startio(sc); 1055173273Ssam } 1056173273Ssam 1057173273Ssam /* 1058173273Ssam * While we're here, check to see if any commands are stuck. 1059173273Ssam * This is pretty low-priority, so it's ok if it doesn't 1060173273Ssam * always fire. 1061173273Ssam */ 1062173273Ssam if (retval == EWOULDBLOCK) 1063173273Ssam aac_timeout(sc); 1064173273Ssam 1065173273Ssam /* Check the hardware printf message buffer */ 1066173273Ssam if (sc->aac_common->ac_printf[0] != 0) 1067173273Ssam aac_print_printf(sc); 1068173273Ssam 1069173273Ssam /* Also check to see if the adapter has a command for us. */ 1070173273Ssam if (sc->flags & AAC_FLAGS_NEW_COMM) 1071173273Ssam continue; 1072173273Ssam for (;;) { 1073173273Ssam if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 1074173273Ssam &fib_size, &fib)) 1075173273Ssam break; 1076173273Ssam 1077173273Ssam AAC_PRINT_FIB(sc, fib); 1078173273Ssam 1079173273Ssam switch (fib->Header.Command) { 1080173273Ssam case AifRequest: 1081173273Ssam aac_handle_aif(sc, fib); 1082173273Ssam break; 1083173273Ssam default: 1084173273Ssam device_printf(sc->aac_dev, "unknown command " 1085173273Ssam "from controller\n"); 1086178354Ssam break; 1087178354Ssam } 1088178354Ssam 1089178354Ssam if ((fib->Header.XferState == 0) || 1090178354Ssam (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 1091178354Ssam break; 1092178354Ssam } 1093178354Ssam 1094178354Ssam /* Return the AIF to the controller. */ 1095173273Ssam if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 1096173273Ssam fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 1097178354Ssam *(AAC_FSAStatus*)fib->data = ST_OK; 1098173273Ssam 1099178354Ssam /* XXX Compute the Size field? */ 1100183246Ssam size = fib->Header.Size; 1101178354Ssam if (size > sizeof(struct aac_fib)) { 1102178354Ssam size = sizeof(struct aac_fib); 1103178354Ssam fib->Header.Size = size; 1104183246Ssam } 1105178354Ssam /* 1106178354Ssam * Since we did not generate this command, it 1107178354Ssam * cannot go through the normal 1108183246Ssam * enqueue->startio chain. 1109183246Ssam */ 1110183246Ssam aac_enqueue_response(sc, 1111183246Ssam AAC_ADAP_NORM_RESP_QUEUE, 1112183246Ssam fib); 1113183246Ssam } 1114183246Ssam } 1115181197Ssam } 1116178354Ssam sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1117173273Ssam mtx_unlock(&sc->aac_io_lock); 1118173273Ssam wakeup(sc->aac_dev); 1119173273Ssam 1120173273Ssam kproc_exit(0); 1121173273Ssam} 1122173273Ssam 1123173273Ssam/* 1124173273Ssam * Process completed commands. 1125173273Ssam */ 1126173273Ssamstatic void 1127173273Ssamaac_complete(void *context, int pending) 1128173273Ssam{ 1129173273Ssam struct aac_softc *sc; 1130173273Ssam struct aac_command *cm; 1131173273Ssam struct aac_fib *fib; 1132173273Ssam u_int32_t fib_size; 1133173273Ssam 1134173273Ssam sc = (struct aac_softc *)context; 1135178354Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1136173273Ssam 1137173273Ssam mtx_lock(&sc->aac_io_lock); 1138173273Ssam 1139173273Ssam /* pull completed commands off the queue */ 1140173273Ssam for (;;) { 1141173273Ssam /* look for completed FIBs on our queue */ 1142173273Ssam if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1143170530Ssam &fib)) 1144170530Ssam break; /* nothing to do */ 1145170530Ssam 1146170530Ssam /* get the command, unmap and hand off for processing */ 1147170530Ssam cm = sc->aac_commands + fib->Header.SenderData; 1148170530Ssam if (cm == NULL) { 1149170530Ssam AAC_PRINT_FIB(sc, fib); 1150170530Ssam break; 1151170530Ssam } 1152170530Ssam aac_remove_busy(cm); 1153170530Ssam 1154170530Ssam aac_unmap_command(cm); 1155170530Ssam cm->cm_flags |= AAC_CMD_COMPLETED; 1156170530Ssam 1157170530Ssam /* is there a completion handler? */ 1158170530Ssam if (cm->cm_complete != NULL) { 1159170530Ssam cm->cm_complete(cm); 1160170530Ssam } else { 1161170530Ssam /* assume that someone is sleeping on this command */ 1162170530Ssam wakeup(cm); 1163170530Ssam } 1164170530Ssam } 1165170530Ssam 1166170530Ssam /* see if we can start some more I/O */ 1167170530Ssam sc->flags &= ~AAC_QUEUE_FRZN; 1168170530Ssam aac_startio(sc); 1169170530Ssam 1170170530Ssam mtx_unlock(&sc->aac_io_lock); 1171183254Ssam} 1172183254Ssam 1173183254Ssam/* 1174170530Ssam * Handle a bio submitted from a disk device. 1175170530Ssam */ 1176170530Ssamvoid 1177170530Ssamaac_submit_bio(struct bio *bp) 1178170530Ssam{ 1179172055Ssam struct aac_disk *ad; 1180170530Ssam struct aac_softc *sc; 1181170530Ssam 1182170530Ssam ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1183183254Ssam sc = ad->ad_controller; 1184183254Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1185183254Ssam 1186183254Ssam /* queue the BIO and try to get some work done */ 1187183254Ssam aac_enqueue_bio(sc, bp); 1188183254Ssam aac_startio(sc); 1189183254Ssam} 1190183254Ssam 1191183254Ssam/* 1192183254Ssam * Get a bio and build a command to go with it. 1193183254Ssam */ 1194183254Ssamstatic int 1195183254Ssamaac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 1196183254Ssam{ 1197183254Ssam struct aac_command *cm; 1198183254Ssam struct aac_fib *fib; 1199183254Ssam struct aac_disk *ad; 1200183254Ssam struct bio *bp; 1201183254Ssam 1202183254Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1203183254Ssam 1204183254Ssam /* get the resources we will need */ 1205183254Ssam cm = NULL; 1206183254Ssam bp = NULL; 1207183254Ssam if (aac_alloc_command(sc, &cm)) /* get a command */ 1208183254Ssam goto fail; 1209183254Ssam if ((bp = aac_dequeue_bio(sc)) == NULL) 1210183254Ssam goto fail; 1211183254Ssam 1212183254Ssam /* fill out the command */ 1213183254Ssam cm->cm_data = (void *)bp->bio_data; 1214173273Ssam cm->cm_datalen = bp->bio_bcount; 1215173273Ssam cm->cm_complete = aac_bio_complete; 1216183254Ssam cm->cm_private = bp; 1217173273Ssam cm->cm_timestamp = time_uptime; 1218178354Ssam cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 1219173273Ssam 1220173273Ssam /* build the FIB */ 1221173273Ssam fib = cm->cm_fib; 1222173273Ssam fib->Header.Size = sizeof(struct aac_fib_header); 1223173273Ssam fib->Header.XferState = 1224183254Ssam AAC_FIBSTATE_HOSTOWNED | 1225183254Ssam AAC_FIBSTATE_INITIALISED | 1226173273Ssam AAC_FIBSTATE_EMPTY | 1227173273Ssam AAC_FIBSTATE_FROMHOST | 1228173273Ssam AAC_FIBSTATE_REXPECTED | 1229183254Ssam AAC_FIBSTATE_NORM | 1230173273Ssam AAC_FIBSTATE_ASYNC | 1231173273Ssam AAC_FIBSTATE_FAST_RESPONSE; 1232173273Ssam 1233183254Ssam /* build the read/write request */ 1234173273Ssam ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1235173273Ssam 1236173273Ssam if (sc->flags & AAC_FLAGS_RAW_IO) { 1237173273Ssam struct aac_raw_io *raw; 1238173273Ssam raw = (struct aac_raw_io *)&fib->data[0]; 1239173273Ssam fib->Header.Command = RawIo; 1240173273Ssam raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 1241173273Ssam raw->ByteCount = bp->bio_bcount; 1242173273Ssam raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1243173273Ssam raw->BpTotal = 0; 1244170530Ssam raw->BpComplete = 0; 1245170530Ssam fib->Header.Size += sizeof(struct aac_raw_io); 1246170530Ssam cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 1247183255Ssam if (bp->bio_cmd == BIO_READ) { 1248183255Ssam raw->Flags = 1; 1249183255Ssam cm->cm_flags |= AAC_CMD_DATAIN; 1250183255Ssam } else { 1251183255Ssam raw->Flags = 0; 1252183255Ssam cm->cm_flags |= AAC_CMD_DATAOUT; 1253183255Ssam } 1254183255Ssam } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1255183255Ssam fib->Header.Command = ContainerCommand; 1256183255Ssam if (bp->bio_cmd == BIO_READ) { 1257183255Ssam struct aac_blockread *br; 1258183255Ssam br = (struct aac_blockread *)&fib->data[0]; 1259183255Ssam br->Command = VM_CtBlockRead; 1260183255Ssam br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1261183255Ssam br->BlockNumber = bp->bio_pblkno; 1262183255Ssam br->ByteCount = bp->bio_bcount; 1263183255Ssam fib->Header.Size += sizeof(struct aac_blockread); 1264183255Ssam cm->cm_sgtable = &br->SgMap; 1265183255Ssam cm->cm_flags |= AAC_CMD_DATAIN; 1266183255Ssam } else { 1267183255Ssam struct aac_blockwrite *bw; 1268183255Ssam bw = (struct aac_blockwrite *)&fib->data[0]; 1269183255Ssam bw->Command = VM_CtBlockWrite; 1270183255Ssam bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1271183255Ssam bw->BlockNumber = bp->bio_pblkno; 1272183255Ssam bw->ByteCount = bp->bio_bcount; 1273183254Ssam bw->Stable = CUNSTABLE; 1274183254Ssam fib->Header.Size += sizeof(struct aac_blockwrite); 1275183254Ssam cm->cm_flags |= AAC_CMD_DATAOUT; 1276183254Ssam cm->cm_sgtable = &bw->SgMap; 1277183254Ssam } 1278183254Ssam } else { 1279183254Ssam fib->Header.Command = ContainerCommand64; 1280183254Ssam if (bp->bio_cmd == BIO_READ) { 1281183254Ssam struct aac_blockread64 *br; 1282183254Ssam br = (struct aac_blockread64 *)&fib->data[0]; 1283183254Ssam br->Command = VM_CtHostRead64; 1284183254Ssam br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1285183255Ssam br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1286183255Ssam br->BlockNumber = bp->bio_pblkno; 1287183254Ssam br->Pad = 0; 1288183254Ssam br->Flags = 0; 1289183254Ssam fib->Header.Size += sizeof(struct aac_blockread64); 1290183254Ssam cm->cm_flags |= AAC_CMD_DATAIN; 1291183254Ssam cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1292183254Ssam } else { 1293183254Ssam struct aac_blockwrite64 *bw; 1294183254Ssam bw = (struct aac_blockwrite64 *)&fib->data[0]; 1295183254Ssam bw->Command = VM_CtHostWrite64; 1296183254Ssam bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1297183254Ssam bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1298183254Ssam bw->BlockNumber = bp->bio_pblkno; 1299183254Ssam bw->Pad = 0; 1300183254Ssam bw->Flags = 0; 1301183254Ssam fib->Header.Size += sizeof(struct aac_blockwrite64); 1302183254Ssam cm->cm_flags |= AAC_CMD_DATAOUT; 1303183254Ssam cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1304183256Ssam } 1305183256Ssam } 1306183256Ssam 1307183256Ssam *cmp = cm; 1308183256Ssam return(0); 1309183256Ssam 1310183254Ssamfail: 1311183254Ssam if (bp != NULL) 1312183254Ssam aac_enqueue_bio(sc, bp); 1313183254Ssam if (cm != NULL) 1314183254Ssam aac_release_command(cm); 1315183254Ssam return(ENOMEM); 1316183254Ssam} 1317183254Ssam 1318183254Ssam/* 1319183254Ssam * Handle a bio-instigated command that has been completed. 1320183254Ssam */ 1321183254Ssamstatic void 1322183254Ssamaac_bio_complete(struct aac_command *cm) 1323183255Ssam{ 1324183255Ssam struct aac_blockread_response *brr; 1325183254Ssam struct aac_blockwrite_response *bwr; 1326183254Ssam struct bio *bp; 1327183254Ssam AAC_FSAStatus status; 1328183254Ssam 1329183254Ssam /* fetch relevant status and then release the command */ 1330183254Ssam bp = (struct bio *)cm->cm_private; 1331183254Ssam if (bp->bio_cmd == BIO_READ) { 1332183254Ssam brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 1333183254Ssam status = brr->Status; 1334183254Ssam } else { 1335183254Ssam bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 1336183254Ssam status = bwr->Status; 1337183254Ssam } 1338183254Ssam aac_release_command(cm); 1339183254Ssam 1340183254Ssam /* fix up the bio based on status */ 1341170530Ssam if (status == ST_OK) { 1342170530Ssam bp->bio_resid = 0; 1343170530Ssam } else { 1344170530Ssam bp->bio_error = EIO; 1345170530Ssam bp->bio_flags |= BIO_ERROR; 1346178354Ssam /* pass an error string out to the disk layer */ 1347170530Ssam bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1348170530Ssam status); 1349170530Ssam } 1350170530Ssam aac_biodone(bp); 1351170530Ssam} 1352170530Ssam 1353170530Ssam/* 1354170530Ssam * Submit a command to the controller, return when it completes. 1355170530Ssam * XXX This is very dangerous! If the card has gone out to lunch, we could 1356170530Ssam * be stuck here forever. At the same time, signals are not caught 1357170530Ssam * because there is a risk that a signal could wakeup the sleep before 1358170530Ssam * the card has a chance to complete the command. Since there is no way 1359170530Ssam * to cancel a command that is in progress, we can't protect against the 1360170530Ssam * card completing a command late and spamming the command and data 1361178354Ssam * memory. So, we are held hostage until the command completes. 1362170530Ssam */ 1363170530Ssamstatic int 1364170530Ssamaac_wait_command(struct aac_command *cm) 1365178354Ssam{ 1366170530Ssam struct aac_softc *sc; 1367170530Ssam int error; 1368170530Ssam 1369170530Ssam sc = cm->cm_sc; 1370170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1371170530Ssam 1372170530Ssam /* Put the command on the ready queue and get things going */ 1373170530Ssam cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 1374170530Ssam aac_enqueue_ready(cm); 1375170530Ssam aac_startio(sc); 1376170530Ssam error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 1377170530Ssam return(error); 1378170530Ssam} 1379170530Ssam 1380170530Ssam/* 1381170530Ssam *Command Buffer Management 1382170530Ssam */ 1383170530Ssam 1384170530Ssam/* 1385170530Ssam * Allocate a command. 1386170530Ssam */ 1387170530Ssamint 1388170530Ssamaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1389170530Ssam{ 1390178354Ssam struct aac_command *cm; 1391170530Ssam 1392170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1393170530Ssam 1394170530Ssam if ((cm = aac_dequeue_free(sc)) == NULL) { 1395170530Ssam if (sc->total_fibs < sc->aac_max_fibs) { 1396170530Ssam sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1397170530Ssam wakeup(sc->aifthread); 1398170530Ssam } 1399170530Ssam return (EBUSY); 1400170530Ssam } 1401170530Ssam 1402170530Ssam *cmp = cm; 1403170530Ssam return(0); 1404170530Ssam} 1405170530Ssam 1406170530Ssam/* 1407170530Ssam * Release a command back to the freelist. 1408170530Ssam */ 1409170530Ssamvoid 1410170530Ssamaac_release_command(struct aac_command *cm) 1411170530Ssam{ 1412170530Ssam struct aac_event *event; 1413170530Ssam struct aac_softc *sc; 1414170530Ssam 1415170530Ssam sc = cm->cm_sc; 1416170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1417170530Ssam 1418178354Ssam /* (re)initialize the command/FIB */ 1419170530Ssam cm->cm_sgtable = NULL; 1420170530Ssam cm->cm_flags = 0; 1421178354Ssam cm->cm_complete = NULL; 1422170530Ssam cm->cm_private = NULL; 1423170530Ssam cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1424170530Ssam cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1425170530Ssam cm->cm_fib->Header.Flags = 0; 1426170530Ssam cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 1427170530Ssam 1428170530Ssam /* 1429170530Ssam * These are duplicated in aac_start to cover the case where an 1430170530Ssam * intermediate stage may have destroyed them. They're left 1431170530Ssam * initialized here for debugging purposes only. 1432170530Ssam */ 1433170530Ssam cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1434170530Ssam cm->cm_fib->Header.SenderData = 0; 1435170530Ssam 1436170530Ssam aac_enqueue_free(cm); 1437170530Ssam 1438170530Ssam /* 1439170530Ssam * Dequeue all events so that there's no risk of events getting 1440170530Ssam * stranded. 1441170530Ssam */ 1442170530Ssam while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 1443170530Ssam TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1444170530Ssam event->ev_callback(sc, event, event->ev_arg); 1445170530Ssam } 1446170530Ssam} 1447170530Ssam 1448170530Ssam/* 1449183245Ssam * Map helper for command/FIB allocation. 1450170530Ssam */ 1451170530Ssamstatic void 1452170530Ssamaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1453170530Ssam{ 1454170530Ssam uint64_t *fibphys; 1455170530Ssam 1456170530Ssam fibphys = (uint64_t *)arg; 1457170530Ssam 1458170530Ssam *fibphys = segs[0].ds_addr; 1459170530Ssam} 1460170530Ssam 1461170530Ssam/* 1462170530Ssam * Allocate and initialize commands/FIBs for this adapter. 1463170530Ssam */ 1464170530Ssamstatic int 1465170530Ssamaac_alloc_commands(struct aac_softc *sc) 1466170530Ssam{ 1467170530Ssam struct aac_command *cm; 1468170530Ssam struct aac_fibmap *fm; 1469170530Ssam uint64_t fibphys; 1470170530Ssam int i, error; 1471170530Ssam 1472170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1473170530Ssam 1474170530Ssam if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1475170530Ssam return (ENOMEM); 1476170530Ssam 1477173273Ssam fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1478173273Ssam if (fm == NULL) 1479173273Ssam return (ENOMEM); 1480170530Ssam 1481170530Ssam /* allocate the FIBs in DMAable memory and load them */ 1482170530Ssam if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1483170530Ssam BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1484170530Ssam device_printf(sc->aac_dev, 1485170530Ssam "Not enough contiguous memory available.\n"); 1486170530Ssam free(fm, M_AACBUF); 1487170530Ssam return (ENOMEM); 1488170530Ssam } 1489170530Ssam 1490170530Ssam /* Ignore errors since this doesn't bounce */ 1491170530Ssam (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1492170530Ssam sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1493170530Ssam aac_map_command_helper, &fibphys, 0); 1494182830Ssam 1495170530Ssam /* initialize constant fields in the command structure */ 1496170530Ssam bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 1497170530Ssam for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1498170530Ssam cm = sc->aac_commands + sc->total_fibs; 1499170530Ssam fm->aac_commands = cm; 1500170530Ssam cm->cm_sc = sc; 1501170530Ssam cm->cm_fib = (struct aac_fib *) 1502170530Ssam ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 1503170530Ssam cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1504170530Ssam cm->cm_index = sc->total_fibs; 1505170530Ssam 1506170530Ssam if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1507170530Ssam &cm->cm_datamap)) != 0) 1508170530Ssam break; 1509170530Ssam mtx_lock(&sc->aac_io_lock); 1510170530Ssam aac_release_command(cm); 1511178354Ssam sc->total_fibs++; 1512170530Ssam mtx_unlock(&sc->aac_io_lock); 1513170530Ssam } 1514170530Ssam 1515182829Ssam if (i > 0) { 1516170530Ssam mtx_lock(&sc->aac_io_lock); 1517170530Ssam TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1518170530Ssam fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1519170530Ssam mtx_unlock(&sc->aac_io_lock); 1520170530Ssam return (0); 1521170530Ssam } 1522170530Ssam 1523170530Ssam bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1524170530Ssam bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1525170530Ssam free(fm, M_AACBUF); 1526170530Ssam return (ENOMEM); 1527170530Ssam} 1528170530Ssam 1529170530Ssam/* 1530170530Ssam * Free FIBs owned by this adapter. 1531170530Ssam */ 1532170530Ssamstatic void 1533178354Ssamaac_free_commands(struct aac_softc *sc) 1534170530Ssam{ 1535170530Ssam struct aac_fibmap *fm; 1536170530Ssam struct aac_command *cm; 1537173273Ssam int i; 1538173273Ssam 1539173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1540173273Ssam 1541170530Ssam while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1542170530Ssam 1543170530Ssam TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1544170530Ssam /* 1545170530Ssam * We check against total_fibs to handle partially 1546173273Ssam * allocated blocks. 1547173273Ssam */ 1548173273Ssam for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1549173273Ssam cm = fm->aac_commands + i; 1550173273Ssam bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1551173273Ssam } 1552178354Ssam bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1553170530Ssam bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1554170530Ssam free(fm, M_AACBUF); 1555170530Ssam } 1556170530Ssam} 1557173273Ssam 1558178354Ssam/* 1559173273Ssam * Command-mapping helper function - populate this command's s/g table. 1560173273Ssam */ 1561173273Ssamstatic void 1562173273Ssamaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1563173273Ssam{ 1564178354Ssam struct aac_softc *sc; 1565170530Ssam struct aac_command *cm; 1566173273Ssam struct aac_fib *fib; 1567170530Ssam int i; 1568170530Ssam 1569170530Ssam cm = (struct aac_command *)arg; 1570170530Ssam sc = cm->cm_sc; 1571170530Ssam fib = cm->cm_fib; 1572170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1573170530Ssam 1574170530Ssam /* copy into the FIB */ 1575170530Ssam if (cm->cm_sgtable != NULL) { 1576170530Ssam if (fib->Header.Command == RawIo) { 1577170530Ssam struct aac_sg_tableraw *sg; 1578170530Ssam sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1579170530Ssam sg->SgCount = nseg; 1580170530Ssam for (i = 0; i < nseg; i++) { 1581170530Ssam sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1582170530Ssam sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1583182829Ssam sg->SgEntryRaw[i].Next = 0; 1584170530Ssam sg->SgEntryRaw[i].Prev = 0; 1585170530Ssam sg->SgEntryRaw[i].Flags = 0; 1586173273Ssam } 1587173273Ssam /* update the FIB size for the s/g count */ 1588175877Ssam fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1589178354Ssam } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1590173273Ssam struct aac_sg_table *sg; 1591173273Ssam sg = cm->cm_sgtable; 1592173273Ssam sg->SgCount = nseg; 1593173273Ssam for (i = 0; i < nseg; i++) { 1594178354Ssam sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1595173273Ssam sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1596173273Ssam } 1597173273Ssam /* update the FIB size for the s/g count */ 1598178354Ssam fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1599173273Ssam } else { 1600173273Ssam struct aac_sg_table64 *sg; 1601173273Ssam sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1602173273Ssam sg->SgCount = nseg; 1603173273Ssam for (i = 0; i < nseg; i++) { 1604178354Ssam sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1605173273Ssam sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1606173273Ssam } 1607182829Ssam /* update the FIB size for the s/g count */ 1608182829Ssam fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1609182829Ssam } 1610182829Ssam } 1611182829Ssam 1612182829Ssam /* Fix up the address values in the FIB. Use the command array index 1613182829Ssam * instead of a pointer since these fields are only 32 bits. Shift 1614182829Ssam * the SenderFibAddress over to make room for the fast response bit 1615182829Ssam * and for the AIF bit 1616182829Ssam */ 1617182829Ssam cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1618182829Ssam cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1619182829Ssam 1620182829Ssam /* save a pointer to the command for speedy reverse-lookup */ 1621182829Ssam cm->cm_fib->Header.SenderData = cm->cm_index; 1622182829Ssam 1623182829Ssam if (cm->cm_flags & AAC_CMD_DATAIN) 1624182829Ssam bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1625182829Ssam BUS_DMASYNC_PREREAD); 1626182829Ssam if (cm->cm_flags & AAC_CMD_DATAOUT) 1627182829Ssam bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1628182829Ssam BUS_DMASYNC_PREWRITE); 1629182829Ssam cm->cm_flags |= AAC_CMD_MAPPED; 1630182829Ssam 1631182829Ssam if (sc->flags & AAC_FLAGS_NEW_COMM) { 1632173273Ssam int count = 10000000L; 1633178354Ssam while (AAC_SEND_COMMAND(sc, cm) != 0) { 1634170530Ssam if (--count == 0) { 1635170530Ssam aac_unmap_command(cm); 1636170530Ssam sc->flags |= AAC_QUEUE_FRZN; 1637170530Ssam aac_requeue_ready(cm); 1638170530Ssam } 1639170530Ssam DELAY(5); /* wait 5 usec. */ 1640170530Ssam } 1641170530Ssam } else { 1642170530Ssam /* Put the FIB on the outbound queue */ 1643170530Ssam if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 1644170530Ssam aac_unmap_command(cm); 1645170530Ssam sc->flags |= AAC_QUEUE_FRZN; 1646170530Ssam aac_requeue_ready(cm); 1647170530Ssam } 1648170530Ssam } 1649178354Ssam 1650170530Ssam return; 1651170530Ssam} 1652170530Ssam 1653170530Ssam/* 1654170530Ssam * Unmap a command from controller-visible space. 1655170530Ssam */ 1656170530Ssamstatic void 1657170530Ssamaac_unmap_command(struct aac_command *cm) 1658170530Ssam{ 1659170530Ssam struct aac_softc *sc; 1660170530Ssam 1661170530Ssam sc = cm->cm_sc; 1662170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1663170530Ssam 1664170530Ssam if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1665170530Ssam return; 1666170530Ssam 1667173273Ssam if (cm->cm_datalen != 0) { 1668170530Ssam if (cm->cm_flags & AAC_CMD_DATAIN) 1669170530Ssam bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1670170530Ssam BUS_DMASYNC_POSTREAD); 1671170530Ssam if (cm->cm_flags & AAC_CMD_DATAOUT) 1672170530Ssam bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1673170530Ssam BUS_DMASYNC_POSTWRITE); 1674170530Ssam 1675170530Ssam bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1676170530Ssam } 1677170530Ssam cm->cm_flags &= ~AAC_CMD_MAPPED; 1678170530Ssam} 1679170530Ssam 1680178354Ssam/* 1681170530Ssam * Hardware Interface 1682170530Ssam */ 1683170530Ssam 1684170530Ssam/* 1685170530Ssam * Initialize the adapter. 1686170530Ssam */ 1687178354Ssamstatic void 1688170530Ssamaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1689170530Ssam{ 1690170530Ssam struct aac_softc *sc; 1691178354Ssam 1692170530Ssam sc = (struct aac_softc *)arg; 1693170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1694170530Ssam 1695170530Ssam sc->aac_common_busaddr = segs[0].ds_addr; 1696170530Ssam} 1697182831Ssam 1698182831Ssamstatic int 1699182831Ssamaac_check_firmware(struct aac_softc *sc) 1700182831Ssam{ 1701170530Ssam u_int32_t code, major, minor, options = 0, atu_size = 0; 1702170530Ssam int status; 1703182831Ssam time_t then; 1704170530Ssam 1705170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1706183255Ssam /* 1707183255Ssam * Wait for the adapter to come ready. 1708183255Ssam */ 1709183255Ssam then = time_uptime; 1710183255Ssam do { 1711183255Ssam code = AAC_GET_FWSTATUS(sc); 1712183255Ssam if (code & AAC_SELF_TEST_FAILED) { 1713183255Ssam device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 1714183255Ssam return(ENXIO); 1715183255Ssam } 1716183255Ssam if (code & AAC_KERNEL_PANIC) { 1717183255Ssam device_printf(sc->aac_dev, 1718183255Ssam "FATAL: controller kernel panic"); 1719178354Ssam return(ENXIO); 1720173273Ssam } 1721183255Ssam if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1722183255Ssam device_printf(sc->aac_dev, 1723183255Ssam "FATAL: controller not coming ready, " 1724183255Ssam "status %x\n", code); 1725183255Ssam return(ENXIO); 1726183255Ssam } 1727173273Ssam } while (!(code & AAC_UP_AND_RUNNING)); 1728183255Ssam 1729170530Ssam /* 1730178354Ssam * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1731170530Ssam * firmware version 1.x are not compatible with this driver. 1732170530Ssam */ 1733170530Ssam if (sc->flags & AAC_FLAGS_PERC2QC) { 1734178354Ssam if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1735170530Ssam NULL)) { 1736170530Ssam device_printf(sc->aac_dev, 1737170530Ssam "Error reading firmware version\n"); 1738170530Ssam return (EIO); 1739178354Ssam } 1740170530Ssam 1741170530Ssam /* These numbers are stored as ASCII! */ 1742170530Ssam major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1743178354Ssam minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1744170530Ssam if (major == 1) { 1745170530Ssam device_printf(sc->aac_dev, 1746170530Ssam "Firmware version %d.%d is not supported.\n", 1747170530Ssam major, minor); 1748170530Ssam return (EINVAL); 1749170530Ssam } 1750170530Ssam } 1751170530Ssam 1752170530Ssam /* 1753178354Ssam * Retrieve the capabilities/supported options word so we know what 1754178354Ssam * work-arounds to enable. Some firmware revs don't support this 1755178354Ssam * command. 1756178354Ssam */ 1757178354Ssam if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1758178354Ssam if (status != AAC_SRB_STS_INVALID_REQUEST) { 1759178354Ssam device_printf(sc->aac_dev, 1760178354Ssam "RequestAdapterInfo failed\n"); 1761178354Ssam return (EIO); 1762178354Ssam } 1763178354Ssam } else { 1764178354Ssam options = AAC_GET_MAILBOX(sc, 1); 1765178354Ssam atu_size = AAC_GET_MAILBOX(sc, 2); 1766178354Ssam sc->supported_options = options; 1767178354Ssam 1768178354Ssam if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1769178354Ssam (sc->flags & AAC_FLAGS_NO4GB) == 0) 1770178354Ssam sc->flags |= AAC_FLAGS_4GB_WINDOW; 1771178354Ssam if (options & AAC_SUPPORTED_NONDASD) 1772178354Ssam sc->flags |= AAC_FLAGS_ENABLE_CAM; 1773178354Ssam if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1774178354Ssam && (sizeof(bus_addr_t) > 4)) { 1775178354Ssam device_printf(sc->aac_dev, 1776178354Ssam "Enabling 64-bit address support\n"); 1777178354Ssam sc->flags |= AAC_FLAGS_SG_64BIT; 1778178354Ssam } 1779183249Ssam if ((options & AAC_SUPPORTED_NEW_COMM) 1780183249Ssam && sc->aac_if.aif_send_command) 1781178354Ssam sc->flags |= AAC_FLAGS_NEW_COMM; 1782178354Ssam if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1783178354Ssam sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1784178354Ssam } 1785170530Ssam 1786170530Ssam /* Check for broken hardware that does a lower number of commands */ 1787170530Ssam sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1788170530Ssam 1789170530Ssam /* Remap mem. resource, if required */ 1790170530Ssam if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1791170530Ssam atu_size > rman_get_size(sc->aac_regs_res1)) { 1792170530Ssam bus_release_resource( 1793170530Ssam sc->aac_dev, SYS_RES_MEMORY, 1794170530Ssam sc->aac_regs_rid1, sc->aac_regs_res1); 1795170530Ssam sc->aac_regs_res1 = bus_alloc_resource( 1796170530Ssam sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1, 1797170530Ssam 0ul, ~0ul, atu_size, RF_ACTIVE); 1798170530Ssam if (sc->aac_regs_res1 == NULL) { 1799170530Ssam sc->aac_regs_res1 = bus_alloc_resource_any( 1800170530Ssam sc->aac_dev, SYS_RES_MEMORY, 1801170530Ssam &sc->aac_regs_rid1, RF_ACTIVE); 1802170530Ssam if (sc->aac_regs_res1 == NULL) { 1803170530Ssam device_printf(sc->aac_dev, 1804173273Ssam "couldn't allocate register window\n"); 1805173273Ssam return (ENXIO); 1806173273Ssam } 1807170530Ssam sc->flags &= ~AAC_FLAGS_NEW_COMM; 1808183245Ssam } 1809183245Ssam sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 1810170530Ssam sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 1811170530Ssam 1812170530Ssam if (sc->aac_hwif == AAC_HWIF_NARK) { 1813170530Ssam sc->aac_regs_res0 = sc->aac_regs_res1; 1814170530Ssam sc->aac_regs_rid0 = sc->aac_regs_rid1; 1815170530Ssam sc->aac_btag0 = sc->aac_btag1; 1816170530Ssam sc->aac_bhandle0 = sc->aac_bhandle1; 1817170530Ssam } 1818170530Ssam } 1819170530Ssam 1820170530Ssam /* Read preferred settings */ 1821178354Ssam sc->aac_max_fib_size = sizeof(struct aac_fib); 1822173273Ssam sc->aac_max_sectors = 128; /* 64KB */ 1823173273Ssam if (sc->flags & AAC_FLAGS_SG_64BIT) 1824173273Ssam sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1825178354Ssam - sizeof(struct aac_blockwrite64)) 1826178354Ssam / sizeof(struct aac_sg_entry64); 1827178354Ssam else 1828178354Ssam sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1829170530Ssam - sizeof(struct aac_blockwrite)) 1830170530Ssam / sizeof(struct aac_sg_entry); 1831170530Ssam 1832183245Ssam if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 1833183245Ssam options = AAC_GET_MAILBOX(sc, 1); 1834178953Ssam sc->aac_max_fib_size = (options & 0xFFFF); 1835178953Ssam sc->aac_max_sectors = (options >> 16) << 1; 1836170530Ssam options = AAC_GET_MAILBOX(sc, 2); 1837170530Ssam sc->aac_sg_tablesize = (options >> 16); 1838170530Ssam options = AAC_GET_MAILBOX(sc, 3); 1839170530Ssam sc->aac_max_fibs = (options & 0xFFFF); 1840170530Ssam } 1841173273Ssam if (sc->aac_max_fib_size > PAGE_SIZE) 1842173273Ssam sc->aac_max_fib_size = PAGE_SIZE; 1843173273Ssam sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1844173273Ssam 1845183250Ssam if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1846183250Ssam sc->flags |= AAC_FLAGS_RAW_IO; 1847173273Ssam device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1848173273Ssam } 1849178354Ssam if ((sc->flags & AAC_FLAGS_RAW_IO) && 1850173273Ssam (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1851173273Ssam sc->flags |= AAC_FLAGS_LBA_64BIT; 1852173273Ssam device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1853173273Ssam } 1854178354Ssam 1855183250Ssam return (0); 1856183250Ssam} 1857178354Ssam 1858173273Ssamstatic int 1859173273Ssamaac_init(struct aac_softc *sc) 1860173273Ssam{ 1861173273Ssam struct aac_adapter_init *ip; 1862183250Ssam u_int32_t qoffset; 1863173273Ssam int error; 1864173273Ssam 1865173273Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1866178354Ssam 1867183250Ssam /* 1868183250Ssam * Fill in the init structure. This tells the adapter about the 1869178354Ssam * physical location of various important shared data structures. 1870173273Ssam */ 1871173273Ssam ip = &sc->aac_common->ac_init; 1872173273Ssam ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1873173273Ssam if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1874170530Ssam ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1875170530Ssam sc->flags |= AAC_FLAGS_RAW_IO; 1876170530Ssam } 1877170530Ssam ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 1878170530Ssam 1879170530Ssam ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1880170530Ssam offsetof(struct aac_common, ac_fibs); 1881170530Ssam ip->AdapterFibsVirtualAddress = 0; 1882178354Ssam ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1883170530Ssam ip->AdapterFibAlign = sizeof(struct aac_fib); 1884170530Ssam 1885170530Ssam ip->PrintfBufferAddress = sc->aac_common_busaddr + 1886170530Ssam offsetof(struct aac_common, ac_printf); 1887170530Ssam ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1888178354Ssam 1889170530Ssam /* 1890170530Ssam * The adapter assumes that pages are 4K in size, except on some 1891170530Ssam * broken firmware versions that do the page->byte conversion twice, 1892170530Ssam * therefore 'assuming' that this value is in 16MB units (2^24). 1893170530Ssam * Round up since the granularity is so high. 1894170530Ssam */ 1895170530Ssam ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1896170530Ssam if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1897170530Ssam ip->HostPhysMemPages = 1898170530Ssam (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1899170530Ssam } 1900170530Ssam ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 1901170530Ssam 1902170530Ssam ip->InitFlags = 0; 1903170530Ssam if (sc->flags & AAC_FLAGS_NEW_COMM) { 1904170530Ssam ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 1905170530Ssam device_printf(sc->aac_dev, "New comm. interface enabled\n"); 1906170530Ssam } 1907170530Ssam 1908170530Ssam ip->MaxIoCommands = sc->aac_max_fibs; 1909170530Ssam ip->MaxIoSize = sc->aac_max_sectors << 9; 1910178354Ssam ip->MaxFibSize = sc->aac_max_fib_size; 1911170530Ssam 1912170530Ssam /* 1913170530Ssam * Initialize FIB queues. Note that it appears that the layout of the 1914170530Ssam * indexes and the segmentation of the entries may be mandated by the 1915170530Ssam * adapter, which is only told about the base of the queue index fields. 1916170530Ssam * 1917170530Ssam * The initial values of the indices are assumed to inform the adapter 1918170530Ssam * of the sizes of the respective queues, and theoretically it could 1919170530Ssam * work out the entire layout of the queue structures from this. We 1920170530Ssam * take the easy route and just lay this area out like everyone else 1921170530Ssam * does. 1922170530Ssam * 1923170530Ssam * The Linux driver uses a much more complex scheme whereby several 1924170530Ssam * header records are kept for each queue. We use a couple of generic 1925170530Ssam * list manipulation functions which 'know' the size of each list by 1926178354Ssam * virtue of a table. 1927178354Ssam */ 1928170530Ssam qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 1929170530Ssam qoffset &= ~(AAC_QUEUE_ALIGN - 1); 1930178354Ssam sc->aac_queues = 1931173273Ssam (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1932173273Ssam ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 1933170530Ssam 1934178354Ssam sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1935170530Ssam AAC_HOST_NORM_CMD_ENTRIES; 1936170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1937170530Ssam AAC_HOST_NORM_CMD_ENTRIES; 1938170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1939170530Ssam AAC_HOST_HIGH_CMD_ENTRIES; 1940170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1941170530Ssam AAC_HOST_HIGH_CMD_ENTRIES; 1942170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1943170530Ssam AAC_ADAP_NORM_CMD_ENTRIES; 1944170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1945170530Ssam AAC_ADAP_NORM_CMD_ENTRIES; 1946170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1947170530Ssam AAC_ADAP_HIGH_CMD_ENTRIES; 1948170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1949170530Ssam AAC_ADAP_HIGH_CMD_ENTRIES; 1950170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1951178354Ssam AAC_HOST_NORM_RESP_ENTRIES; 1952170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1953170530Ssam AAC_HOST_NORM_RESP_ENTRIES; 1954170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1955170530Ssam AAC_HOST_HIGH_RESP_ENTRIES; 1956170530Ssam sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1957178354Ssam AAC_HOST_HIGH_RESP_ENTRIES; 1958170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1959170530Ssam AAC_ADAP_NORM_RESP_ENTRIES; 1960170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1961170530Ssam AAC_ADAP_NORM_RESP_ENTRIES; 1962170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1963170530Ssam AAC_ADAP_HIGH_RESP_ENTRIES; 1964170530Ssam sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1965170530Ssam AAC_ADAP_HIGH_RESP_ENTRIES; 1966170530Ssam sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1967170530Ssam &sc->aac_queues->qt_HostNormCmdQueue[0]; 1968170530Ssam sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1969170530Ssam &sc->aac_queues->qt_HostHighCmdQueue[0]; 1970170530Ssam sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1971178354Ssam &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1972170530Ssam sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1973170530Ssam &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1974170530Ssam sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1975170530Ssam &sc->aac_queues->qt_HostNormRespQueue[0]; 1976170530Ssam sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1977170530Ssam &sc->aac_queues->qt_HostHighRespQueue[0]; 1978170530Ssam sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1979170530Ssam &sc->aac_queues->qt_AdapNormRespQueue[0]; 1980170530Ssam sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1981170530Ssam &sc->aac_queues->qt_AdapHighRespQueue[0]; 1982170530Ssam 1983170530Ssam /* 1984170530Ssam * Do controller-type-specific initialisation 1985170530Ssam */ 1986170530Ssam switch (sc->aac_hwif) { 1987170530Ssam case AAC_HWIF_I960RX: 1988170530Ssam AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); 1989170530Ssam break; 1990170530Ssam case AAC_HWIF_RKT: 1991170530Ssam AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); 1992170530Ssam break; 1993178354Ssam default: 1994170530Ssam break; 1995173273Ssam } 1996173273Ssam 1997173273Ssam /* 1998173273Ssam * Give the init structure to the controller. 1999170530Ssam */ 2000170530Ssam if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 2001170530Ssam sc->aac_common_busaddr + 2002170530Ssam offsetof(struct aac_common, ac_init), 0, 0, 0, 2003170530Ssam NULL)) { 2004170530Ssam device_printf(sc->aac_dev, 2005170530Ssam "error establishing init structure\n"); 2006178354Ssam error = EIO; 2007170530Ssam goto out; 2008170530Ssam } 2009170530Ssam 2010170530Ssam error = 0; 2011170530Ssamout: 2012170530Ssam return(error); 2013170530Ssam} 2014170530Ssam 2015170530Ssamstatic int 2016170530Ssamaac_setup_intr(struct aac_softc *sc) 2017170530Ssam{ 2018170530Ssam sc->aac_irq_rid = 0; 2019170530Ssam if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 2020170530Ssam &sc->aac_irq_rid, 2021180309Ssam RF_SHAREABLE | 2022170530Ssam RF_ACTIVE)) == NULL) { 2023170530Ssam device_printf(sc->aac_dev, "can't allocate interrupt\n"); 2024170530Ssam return (EINVAL); 2025170530Ssam } 2026178354Ssam if (sc->flags & AAC_FLAGS_NEW_COMM) { 2027170530Ssam if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2028170530Ssam INTR_MPSAFE|INTR_TYPE_BIO, NULL, 2029170530Ssam aac_new_intr, sc, &sc->aac_intr)) { 2030170530Ssam device_printf(sc->aac_dev, "can't set up interrupt\n"); 2031170530Ssam return (EINVAL); 2032170530Ssam } 2033170530Ssam } else { 2034170530Ssam if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2035170530Ssam INTR_TYPE_BIO, aac_fast_intr, NULL, 2036170530Ssam sc, &sc->aac_intr)) { 2037170530Ssam device_printf(sc->aac_dev, 2038178354Ssam "can't set up FAST interrupt\n"); 2039170530Ssam if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2040170530Ssam INTR_MPSAFE|INTR_TYPE_BIO, 2041178354Ssam NULL, (driver_intr_t *)aac_fast_intr, 2042170530Ssam sc, &sc->aac_intr)) { 2043178354Ssam device_printf(sc->aac_dev, 2044170530Ssam "can't set up MPSAFE interrupt\n"); 2045170530Ssam return (EINVAL); 2046170530Ssam } 2047170530Ssam } 2048170530Ssam } 2049170530Ssam return (0); 2050170530Ssam} 2051170530Ssam 2052170530Ssam/* 2053178354Ssam * Send a synchronous command to the controller and wait for a result. 2054170530Ssam * Indicate if the controller completed the command with an error status. 2055170530Ssam */ 2056170530Ssamstatic int 2057170530Ssamaac_sync_command(struct aac_softc *sc, u_int32_t command, 2058170530Ssam u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 2059170530Ssam u_int32_t *sp) 2060170530Ssam{ 2061170530Ssam time_t then; 2062178354Ssam u_int32_t status; 2063170530Ssam 2064170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2065178354Ssam 2066178354Ssam /* populate the mailbox */ 2067170530Ssam AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 2068170530Ssam 2069170530Ssam /* ensure the sync command doorbell flag is cleared */ 2070170530Ssam AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 2071170530Ssam 2072170530Ssam /* then set it to signal the adapter */ 2073170530Ssam AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 2074170530Ssam 2075170530Ssam /* spin waiting for the command to complete */ 2076170530Ssam then = time_uptime; 2077170530Ssam do { 2078170530Ssam if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 2079170530Ssam fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 2080170530Ssam return(EIO); 2081170530Ssam } 2082170530Ssam } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 2083170530Ssam 2084170530Ssam /* clear the completion flag */ 2085170530Ssam AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 2086170530Ssam 2087170530Ssam /* get the command status */ 2088170530Ssam status = AAC_GET_MAILBOX(sc, 0); 2089170530Ssam if (sp != NULL) 2090170530Ssam *sp = status; 2091170530Ssam 2092170530Ssam if (status != AAC_SRB_STS_SUCCESS) 2093170530Ssam return (-1); 2094170530Ssam return(0); 2095170530Ssam} 2096170530Ssam 2097170530Ssamint 2098170530Ssamaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2099170530Ssam struct aac_fib *fib, u_int16_t datasize) 2100170530Ssam{ 2101178354Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2102170530Ssam mtx_assert(&sc->aac_io_lock, MA_OWNED); 2103173865Ssam 2104170530Ssam if (datasize > AAC_FIB_DATASIZE) 2105170530Ssam return(EINVAL); 2106178354Ssam 2107173273Ssam /* 2108173273Ssam * Set up the sync FIB 2109173273Ssam */ 2110173273Ssam fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2111173273Ssam AAC_FIBSTATE_INITIALISED | 2112173273Ssam AAC_FIBSTATE_EMPTY; 2113173273Ssam fib->Header.XferState |= xferstate; 2114173273Ssam fib->Header.Command = command; 2115178354Ssam fib->Header.StructType = AAC_FIBTYPE_TFIB; 2116173273Ssam fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 2117178354Ssam fib->Header.SenderSize = sizeof(struct aac_fib); 2118173273Ssam fib->Header.SenderFibAddress = 0; /* Not needed */ 2119173273Ssam fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2120173273Ssam offsetof(struct aac_common, 2121173865Ssam ac_sync_fib); 2122173865Ssam 2123173865Ssam /* 2124173273Ssam * Give the FIB to the controller, wait for a response. 2125173273Ssam */ 2126178354Ssam if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2127173273Ssam fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 2128173273Ssam fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 2129173273Ssam return(EIO); 2130178354Ssam } 2131178354Ssam 2132173273Ssam return (0); 2133170530Ssam} 2134178354Ssam 2135170530Ssam/* 2136178354Ssam * Adapter-space FIB queue manipulation 2137170530Ssam * 2138170530Ssam * Note that the queue implementation here is a little funky; neither the PI or 2139170530Ssam * CI will ever be zero. This behaviour is a controller feature. 2140170530Ssam */ 2141170530Ssamstatic struct { 2142173865Ssam int size; 2143173865Ssam int notify; 2144173273Ssam} aac_qinfo[] = { 2145170530Ssam {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 2146170530Ssam {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 2147170530Ssam {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 2148170530Ssam {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 2149170530Ssam {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 2150170530Ssam {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 2151170530Ssam {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 2152173273Ssam {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 2153173273Ssam}; 2154173273Ssam 2155173273Ssam/* 2156173273Ssam * Atomically insert an entry into the nominated queue, returns 0 on success or 2157173273Ssam * EBUSY if the queue is full. 2158173273Ssam * 2159170530Ssam * Note: it would be more efficient to defer notifying the controller in 2160170530Ssam * the case where we may be inserting several entries in rapid succession, 2161170530Ssam * but implementing this usefully may be difficult (it would involve a 2162170530Ssam * separate queue/notify interface). 2163170530Ssam */ 2164170530Ssamstatic int 2165170530Ssamaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 2166170530Ssam{ 2167170530Ssam u_int32_t pi, ci; 2168170530Ssam int error; 2169170530Ssam u_int32_t fib_size; 2170170530Ssam u_int32_t fib_addr; 2171170530Ssam 2172170530Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2173170530Ssam 2174170530Ssam fib_size = cm->cm_fib->Header.Size; 2175170530Ssam fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 2176170530Ssam 2177170530Ssam /* get the producer/consumer indices */ 2178170530Ssam pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 2179170530Ssam ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 2180170530Ssam 2181170530Ssam /* wrap the queue? */ 2182170530Ssam if (pi >= aac_qinfo[queue].size) 2183170530Ssam pi = 0; 2184170530Ssam 2185170530Ssam /* check for queue full */ 2186170530Ssam if ((pi + 1) == ci) { 2187170530Ssam error = EBUSY; 2188170530Ssam goto out; 2189170530Ssam } 2190170530Ssam 2191170530Ssam /* 2192170530Ssam * To avoid a race with its completion interrupt, place this command on 2193170530Ssam * the busy queue prior to advertising it to the controller. 2194170530Ssam */ 2195170530Ssam aac_enqueue_busy(cm); 2196170530Ssam 2197170530Ssam /* populate queue entry */ 2198170530Ssam (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 2199170530Ssam (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 2200170530Ssam 2201170530Ssam /* update producer index */ 2202170530Ssam sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 2203170530Ssam 2204170530Ssam /* notify the adapter if we know how */ 2205170530Ssam if (aac_qinfo[queue].notify != 0) 2206170530Ssam AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 2207170530Ssam 2208170530Ssam error = 0; 2209170530Ssam 2210170530Ssamout: 2211170530Ssam return(error); 2212170530Ssam} 2213172211Ssam 2214172211Ssam/* 2215172211Ssam * Atomically remove one entry from the nominated queue, returns 0 on 2216178354Ssam * success or ENOENT if the queue is empty. 2217172211Ssam */ 2218172211Ssamstatic int 2219172211Ssamaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2220178354Ssam struct aac_fib **fib_addr) 2221178354Ssam{ 2222172211Ssam u_int32_t pi, ci; 2223172211Ssam u_int32_t fib_index; 2224172211Ssam int error; 2225172211Ssam int notify; 2226178354Ssam 2227183256Ssam fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2228183256Ssam 2229183256Ssam /* get the producer/consumer indices */ 2230183256Ssam pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 2231178354Ssam ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 2232172211Ssam 2233178354Ssam /* check for queue empty */ 2234172211Ssam if (ci == pi) { 2235172211Ssam error = ENOENT; 2236172211Ssam goto out; 2237178354Ssam } 2238172211Ssam 2239172211Ssam /* wrap the pi so the following test works */ 2240172211Ssam if (pi >= aac_qinfo[queue].size) 2241172211Ssam pi = 0; 2242172211Ssam 2243172211Ssam notify = 0; 2244172211Ssam if (ci == pi + 1) 2245172211Ssam notify++; 2246172211Ssam 2247172211Ssam /* wrap the queue? */ 2248170530Ssam if (ci >= aac_qinfo[queue].size) 2249173273Ssam ci = 0; 2250173273Ssam 2251173273Ssam /* fetch the entry */ 2252173273Ssam *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2253170530Ssam 2254170530Ssam switch (queue) { 2255170530Ssam case AAC_HOST_NORM_CMD_QUEUE: 2256170530Ssam case AAC_HOST_HIGH_CMD_QUEUE: 2257183256Ssam /* 2258170530Ssam * The aq_fib_addr is only 32 bits wide so it can't be counted 2259170530Ssam * on to hold an address. For AIF's, the adapter assumes 2260170530Ssam * that it's giving us an address into the array of AIF fibs. 2261170530Ssam * Therefore, we have to convert it to an index. 2262170530Ssam */ 2263170530Ssam fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2264178354Ssam sizeof(struct aac_fib); 2265170530Ssam *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2266183256Ssam break; 2267183256Ssam 2268183256Ssam case AAC_HOST_NORM_RESP_QUEUE: 2269183256Ssam case AAC_HOST_HIGH_RESP_QUEUE: 2270178354Ssam { 2271170530Ssam struct aac_command *cm; 2272178354Ssam 2273170530Ssam /* 2274170530Ssam * As above, an index is used instead of an actual address. 2275170530Ssam * Gotta shift the index to account for the fast response 2276178354Ssam * bit. No other correction is needed since this value was 2277170530Ssam * originally provided by the driver via the SenderFibAddress 2278170530Ssam * field. 2279172211Ssam */ 2280170530Ssam fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 2281170530Ssam cm = sc->aac_commands + (fib_index >> 2); 2282170530Ssam *fib_addr = cm->cm_fib; 2283170530Ssam 2284170530Ssam /* 2285170530Ssam * Is this a fast response? If it is, update the fib fields in 2286170530Ssam * local memory since the whole fib isn't DMA'd back up. 2287170530Ssam */ 2288170530Ssam if (fib_index & 0x01) { 2289170530Ssam (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2290170530Ssam *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2291170530Ssam } 2292170530Ssam break; 2293170530Ssam } 2294170530Ssam default: 2295170530Ssam panic("Invalid queue in aac_dequeue_fib()"); 2296170530Ssam break; 2297170530Ssam } 2298170530Ssam 2299170530Ssam /* update consumer index */ 2300170530Ssam sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 2301170530Ssam 2302170530Ssam /* if we have made the queue un-full, notify the adapter */ 2303170530Ssam if (notify && (aac_qinfo[queue].notify != 0)) 2304170530Ssam AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 2305170530Ssam error = 0; 2306170530Ssam 2307170530Ssamout: 2308170530Ssam return(error); 2309170530Ssam} 2310170530Ssam 2311170530Ssam/* 2312170530Ssam * Put our response to an Adapter Initialed Fib on the response queue 2313170530Ssam */ 2314170530Ssamstatic int 2315170530Ssamaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 2316{ 2317 u_int32_t pi, ci; 2318 int error; 2319 u_int32_t fib_size; 2320 u_int32_t fib_addr; 2321 2322 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2323 2324 /* Tell the adapter where the FIB is */ 2325 fib_size = fib->Header.Size; 2326 fib_addr = fib->Header.SenderFibAddress; 2327 fib->Header.ReceiverFibAddress = fib_addr; 2328 2329 /* get the producer/consumer indices */ 2330 pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 2331 ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 2332 2333 /* wrap the queue? */ 2334 if (pi >= aac_qinfo[queue].size) 2335 pi = 0; 2336 2337 /* check for queue full */ 2338 if ((pi + 1) == ci) { 2339 error = EBUSY; 2340 goto out; 2341 } 2342 2343 /* populate queue entry */ 2344 (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 2345 (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 2346 2347 /* update producer index */ 2348 sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 2349 2350 /* notify the adapter if we know how */ 2351 if (aac_qinfo[queue].notify != 0) 2352 AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 2353 2354 error = 0; 2355 2356out: 2357 return(error); 2358} 2359 2360/* 2361 * Check for commands that have been outstanding for a suspiciously long time, 2362 * and complain about them. 2363 */ 2364static void 2365aac_timeout(struct aac_softc *sc) 2366{ 2367 struct aac_command *cm; 2368 time_t deadline; 2369 int timedout, code; 2370 2371 /* 2372 * Traverse the busy command list, bitch about late commands once 2373 * only. 2374 */ 2375 timedout = 0; 2376 deadline = time_uptime - AAC_CMD_TIMEOUT; 2377 TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2378 if ((cm->cm_timestamp < deadline) 2379 /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 2380 cm->cm_flags |= AAC_CMD_TIMEDOUT; 2381 device_printf(sc->aac_dev, 2382 "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2383 cm, (int)(time_uptime-cm->cm_timestamp)); 2384 AAC_PRINT_FIB(sc, cm->cm_fib); 2385 timedout++; 2386 } 2387 } 2388 2389 if (timedout) { 2390 code = AAC_GET_FWSTATUS(sc); 2391 if (code != AAC_UP_AND_RUNNING) { 2392 device_printf(sc->aac_dev, "WARNING! Controller is no " 2393 "longer running! code= 0x%x\n", code); 2394 } 2395 } 2396 return; 2397} 2398 2399/* 2400 * Interface Function Vectors 2401 */ 2402 2403/* 2404 * Read the current firmware status word. 2405 */ 2406static int 2407aac_sa_get_fwstatus(struct aac_softc *sc) 2408{ 2409 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2410 2411 return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); 2412} 2413 2414static int 2415aac_rx_get_fwstatus(struct aac_softc *sc) 2416{ 2417 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2418 2419 return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 2420 AAC_RX_OMR0 : AAC_RX_FWSTATUS)); 2421} 2422 2423static int 2424aac_fa_get_fwstatus(struct aac_softc *sc) 2425{ 2426 int val; 2427 2428 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2429 2430 val = AAC_MEM0_GETREG4(sc, AAC_FA_FWSTATUS); 2431 return (val); 2432} 2433 2434static int 2435aac_rkt_get_fwstatus(struct aac_softc *sc) 2436{ 2437 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2438 2439 return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 2440 AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); 2441} 2442 2443/* 2444 * Notify the controller of a change in a given queue 2445 */ 2446 2447static void 2448aac_sa_qnotify(struct aac_softc *sc, int qbit) 2449{ 2450 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2451 2452 AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 2453} 2454 2455static void 2456aac_rx_qnotify(struct aac_softc *sc, int qbit) 2457{ 2458 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2459 2460 AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); 2461} 2462 2463static void 2464aac_fa_qnotify(struct aac_softc *sc, int qbit) 2465{ 2466 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2467 2468 AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2469 AAC_FA_HACK(sc); 2470} 2471 2472static void 2473aac_rkt_qnotify(struct aac_softc *sc, int qbit) 2474{ 2475 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2476 2477 AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); 2478} 2479 2480/* 2481 * Get the interrupt reason bits 2482 */ 2483static int 2484aac_sa_get_istatus(struct aac_softc *sc) 2485{ 2486 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2487 2488 return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); 2489} 2490 2491static int 2492aac_rx_get_istatus(struct aac_softc *sc) 2493{ 2494 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2495 2496 return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); 2497} 2498 2499static int 2500aac_fa_get_istatus(struct aac_softc *sc) 2501{ 2502 int val; 2503 2504 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2505 2506 val = AAC_MEM0_GETREG2(sc, AAC_FA_DOORBELL0); 2507 return (val); 2508} 2509 2510static int 2511aac_rkt_get_istatus(struct aac_softc *sc) 2512{ 2513 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2514 2515 return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); 2516} 2517 2518/* 2519 * Clear some interrupt reason bits 2520 */ 2521static void 2522aac_sa_clear_istatus(struct aac_softc *sc, int mask) 2523{ 2524 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2525 2526 AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 2527} 2528 2529static void 2530aac_rx_clear_istatus(struct aac_softc *sc, int mask) 2531{ 2532 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2533 2534 AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); 2535} 2536 2537static void 2538aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2539{ 2540 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2541 2542 AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2543 AAC_FA_HACK(sc); 2544} 2545 2546static void 2547aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 2548{ 2549 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2550 2551 AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); 2552} 2553 2554/* 2555 * Populate the mailbox and set the command word 2556 */ 2557static void 2558aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2559 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2560{ 2561 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2562 2563 AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); 2564 AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2565 AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2566 AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2567 AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 2568} 2569 2570static void 2571aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 2572 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2573{ 2574 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2575 2576 AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); 2577 AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2578 AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2579 AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2580 AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 2581} 2582 2583static void 2584aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2585 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2586{ 2587 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2588 2589 AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX, command); 2590 AAC_FA_HACK(sc); 2591 AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2592 AAC_FA_HACK(sc); 2593 AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2594 AAC_FA_HACK(sc); 2595 AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2596 AAC_FA_HACK(sc); 2597 AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2598 AAC_FA_HACK(sc); 2599} 2600 2601static void 2602aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2603 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2604{ 2605 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2606 2607 AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); 2608 AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2609 AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2610 AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2611 AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 2612} 2613 2614/* 2615 * Fetch the immediate command status word 2616 */ 2617static int 2618aac_sa_get_mailbox(struct aac_softc *sc, int mb) 2619{ 2620 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2621 2622 return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 2623} 2624 2625static int 2626aac_rx_get_mailbox(struct aac_softc *sc, int mb) 2627{ 2628 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2629 2630 return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 2631} 2632 2633static int 2634aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2635{ 2636 int val; 2637 2638 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2639 2640 val = AAC_MEM1_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2641 return (val); 2642} 2643 2644static int 2645aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 2646{ 2647 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2648 2649 return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 2650} 2651 2652/* 2653 * Set/clear interrupt masks 2654 */ 2655static void 2656aac_sa_set_interrupts(struct aac_softc *sc, int enable) 2657{ 2658 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2659 2660 if (enable) { 2661 AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2662 } else { 2663 AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 2664 } 2665} 2666 2667static void 2668aac_rx_set_interrupts(struct aac_softc *sc, int enable) 2669{ 2670 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2671 2672 if (enable) { 2673 if (sc->flags & AAC_FLAGS_NEW_COMM) 2674 AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 2675 else 2676 AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 2677 } else { 2678 AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); 2679 } 2680} 2681 2682static void 2683aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2684{ 2685 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2686 2687 if (enable) { 2688 AAC_MEM0_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2689 AAC_FA_HACK(sc); 2690 } else { 2691 AAC_MEM0_SETREG2((sc), AAC_FA_MASK0, ~0); 2692 AAC_FA_HACK(sc); 2693 } 2694} 2695 2696static void 2697aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 2698{ 2699 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2700 2701 if (enable) { 2702 if (sc->flags & AAC_FLAGS_NEW_COMM) 2703 AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 2704 else 2705 AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 2706 } else { 2707 AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); 2708 } 2709} 2710 2711/* 2712 * New comm. interface: Send command functions 2713 */ 2714static int 2715aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 2716{ 2717 u_int32_t index, device; 2718 2719 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 2720 2721 index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 2722 if (index == 0xffffffffL) 2723 index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 2724 if (index == 0xffffffffL) 2725 return index; 2726 aac_enqueue_busy(cm); 2727 device = index; 2728 AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2729 device += 4; 2730 AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2731 device += 4; 2732 AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2733 AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); 2734 return 0; 2735} 2736 2737static int 2738aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 2739{ 2740 u_int32_t index, device; 2741 2742 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 2743 2744 index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 2745 if (index == 0xffffffffL) 2746 index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 2747 if (index == 0xffffffffL) 2748 return index; 2749 aac_enqueue_busy(cm); 2750 device = index; 2751 AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 2752 device += 4; 2753 AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 2754 device += 4; 2755 AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2756 AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); 2757 return 0; 2758} 2759 2760/* 2761 * New comm. interface: get, set outbound queue index 2762 */ 2763static int 2764aac_rx_get_outb_queue(struct aac_softc *sc) 2765{ 2766 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2767 2768 return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); 2769} 2770 2771static int 2772aac_rkt_get_outb_queue(struct aac_softc *sc) 2773{ 2774 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2775 2776 return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); 2777} 2778 2779static void 2780aac_rx_set_outb_queue(struct aac_softc *sc, int index) 2781{ 2782 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2783 2784 AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); 2785} 2786 2787static void 2788aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 2789{ 2790 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2791 2792 AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); 2793} 2794 2795/* 2796 * Debugging and Diagnostics 2797 */ 2798 2799/* 2800 * Print some information about the controller. 2801 */ 2802static void 2803aac_describe_controller(struct aac_softc *sc) 2804{ 2805 struct aac_fib *fib; 2806 struct aac_adapter_info *info; 2807 char *adapter_type = "Adaptec RAID controller"; 2808 2809 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2810 2811 mtx_lock(&sc->aac_io_lock); 2812 aac_alloc_sync_fib(sc, &fib); 2813 2814 fib->data[0] = 0; 2815 if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 2816 device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2817 aac_release_sync_fib(sc); 2818 mtx_unlock(&sc->aac_io_lock); 2819 return; 2820 } 2821 2822 /* save the kernel revision structure for later use */ 2823 info = (struct aac_adapter_info *)&fib->data[0]; 2824 sc->aac_revision = info->KernelRevision; 2825 2826 if (bootverbose) { 2827 device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2828 "(%dMB cache, %dMB execution), %s\n", 2829 aac_describe_code(aac_cpu_variant, info->CpuVariant), 2830 info->ClockSpeed, info->TotalMem / (1024 * 1024), 2831 info->BufferMem / (1024 * 1024), 2832 info->ExecutionMem / (1024 * 1024), 2833 aac_describe_code(aac_battery_platform, 2834 info->batteryPlatform)); 2835 2836 device_printf(sc->aac_dev, 2837 "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2838 info->KernelRevision.external.comp.major, 2839 info->KernelRevision.external.comp.minor, 2840 info->KernelRevision.external.comp.dash, 2841 info->KernelRevision.buildNumber, 2842 (u_int32_t)(info->SerialNumber & 0xffffff)); 2843 2844 device_printf(sc->aac_dev, "Supported Options=%b\n", 2845 sc->supported_options, 2846 "\20" 2847 "\1SNAPSHOT" 2848 "\2CLUSTERS" 2849 "\3WCACHE" 2850 "\4DATA64" 2851 "\5HOSTTIME" 2852 "\6RAID50" 2853 "\7WINDOW4GB" 2854 "\10SCSIUPGD" 2855 "\11SOFTERR" 2856 "\12NORECOND" 2857 "\13SGMAP64" 2858 "\14ALARM" 2859 "\15NONDASD" 2860 "\16SCSIMGT" 2861 "\17RAIDSCSI" 2862 "\21ADPTINFO" 2863 "\22NEWCOMM" 2864 "\23ARRAY64BIT" 2865 "\24HEATSENSOR"); 2866 } 2867 2868 if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 2869 fib->data[0] = 0; 2870 if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 2871 device_printf(sc->aac_dev, 2872 "RequestSupplementAdapterInfo failed\n"); 2873 else 2874 adapter_type = ((struct aac_supplement_adapter_info *) 2875 &fib->data[0])->AdapterTypeText; 2876 } 2877 device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 2878 adapter_type, 2879 AAC_DRIVER_VERSION >> 24, 2880 (AAC_DRIVER_VERSION >> 16) & 0xFF, 2881 AAC_DRIVER_VERSION & 0xFF, 2882 AAC_DRIVER_BUILD); 2883 2884 aac_release_sync_fib(sc); 2885 mtx_unlock(&sc->aac_io_lock); 2886} 2887 2888/* 2889 * Look up a text description of a numeric error code and return a pointer to 2890 * same. 2891 */ 2892static char * 2893aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2894{ 2895 int i; 2896 2897 for (i = 0; table[i].string != NULL; i++) 2898 if (table[i].code == code) 2899 return(table[i].string); 2900 return(table[i + 1].string); 2901} 2902 2903/* 2904 * Management Interface 2905 */ 2906 2907static int 2908aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2909{ 2910 struct aac_softc *sc; 2911 2912 sc = dev->si_drv1; 2913 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2914 sc->aac_open_cnt++; 2915 sc->aac_state |= AAC_STATE_OPEN; 2916 2917 return 0; 2918} 2919 2920static int 2921aac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2922{ 2923 struct aac_softc *sc; 2924 2925 sc = dev->si_drv1; 2926 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2927 sc->aac_open_cnt--; 2928 /* Mark this unit as no longer open */ 2929 if (sc->aac_open_cnt == 0) 2930 sc->aac_state &= ~AAC_STATE_OPEN; 2931 2932 return 0; 2933} 2934 2935static int 2936aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2937{ 2938 union aac_statrequest *as; 2939 struct aac_softc *sc; 2940 int error = 0; 2941 2942 as = (union aac_statrequest *)arg; 2943 sc = dev->si_drv1; 2944 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2945 2946 switch (cmd) { 2947 case AACIO_STATS: 2948 switch (as->as_item) { 2949 case AACQ_FREE: 2950 case AACQ_BIO: 2951 case AACQ_READY: 2952 case AACQ_BUSY: 2953 bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2954 sizeof(struct aac_qstat)); 2955 break; 2956 default: 2957 error = ENOENT; 2958 break; 2959 } 2960 break; 2961 2962 case FSACTL_SENDFIB: 2963 case FSACTL_SEND_LARGE_FIB: 2964 arg = *(caddr_t*)arg; 2965 case FSACTL_LNX_SENDFIB: 2966 case FSACTL_LNX_SEND_LARGE_FIB: 2967 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 2968 error = aac_ioctl_sendfib(sc, arg); 2969 break; 2970 case FSACTL_SEND_RAW_SRB: 2971 arg = *(caddr_t*)arg; 2972 case FSACTL_LNX_SEND_RAW_SRB: 2973 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2974 error = aac_ioctl_send_raw_srb(sc, arg); 2975 break; 2976 case FSACTL_AIF_THREAD: 2977 case FSACTL_LNX_AIF_THREAD: 2978 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 2979 error = EINVAL; 2980 break; 2981 case FSACTL_OPEN_GET_ADAPTER_FIB: 2982 arg = *(caddr_t*)arg; 2983 case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2984 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2985 error = aac_open_aif(sc, arg); 2986 break; 2987 case FSACTL_GET_NEXT_ADAPTER_FIB: 2988 arg = *(caddr_t*)arg; 2989 case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2990 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2991 error = aac_getnext_aif(sc, arg); 2992 break; 2993 case FSACTL_CLOSE_GET_ADAPTER_FIB: 2994 arg = *(caddr_t*)arg; 2995 case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2996 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2997 error = aac_close_aif(sc, arg); 2998 break; 2999 case FSACTL_MINIPORT_REV_CHECK: 3000 arg = *(caddr_t*)arg; 3001 case FSACTL_LNX_MINIPORT_REV_CHECK: 3002 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 3003 error = aac_rev_check(sc, arg); 3004 break; 3005 case FSACTL_QUERY_DISK: 3006 arg = *(caddr_t*)arg; 3007 case FSACTL_LNX_QUERY_DISK: 3008 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 3009 error = aac_query_disk(sc, arg); 3010 break; 3011 case FSACTL_DELETE_DISK: 3012 case FSACTL_LNX_DELETE_DISK: 3013 /* 3014 * We don't trust the underland to tell us when to delete a 3015 * container, rather we rely on an AIF coming from the 3016 * controller 3017 */ 3018 error = 0; 3019 break; 3020 case FSACTL_GET_PCI_INFO: 3021 arg = *(caddr_t*)arg; 3022 case FSACTL_LNX_GET_PCI_INFO: 3023 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 3024 error = aac_get_pci_info(sc, arg); 3025 break; 3026 case FSACTL_GET_FEATURES: 3027 arg = *(caddr_t*)arg; 3028 case FSACTL_LNX_GET_FEATURES: 3029 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 3030 error = aac_supported_features(sc, arg); 3031 break; 3032 default: 3033 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 3034 error = EINVAL; 3035 break; 3036 } 3037 return(error); 3038} 3039 3040static int 3041aac_poll(struct cdev *dev, int poll_events, struct thread *td) 3042{ 3043 struct aac_softc *sc; 3044 struct aac_fib_context *ctx; 3045 int revents; 3046 3047 sc = dev->si_drv1; 3048 revents = 0; 3049 3050 mtx_lock(&sc->aac_aifq_lock); 3051 if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 3052 for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3053 if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 3054 revents |= poll_events & (POLLIN | POLLRDNORM); 3055 break; 3056 } 3057 } 3058 } 3059 mtx_unlock(&sc->aac_aifq_lock); 3060 3061 if (revents == 0) { 3062 if (poll_events & (POLLIN | POLLRDNORM)) 3063 selrecord(td, &sc->rcv_select); 3064 } 3065 3066 return (revents); 3067} 3068 3069static void 3070aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 3071{ 3072 3073 switch (event->ev_type) { 3074 case AAC_EVENT_CMFREE: 3075 mtx_assert(&sc->aac_io_lock, MA_OWNED); 3076 if (aac_alloc_command(sc, (struct aac_command **)arg)) { 3077 aac_add_event(sc, event); 3078 return; 3079 } 3080 free(event, M_AACBUF); 3081 wakeup(arg); 3082 break; 3083 default: 3084 break; 3085 } 3086} 3087 3088/* 3089 * Send a FIB supplied from userspace 3090 */ 3091static int 3092aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 3093{ 3094 struct aac_command *cm; 3095 int size, error; 3096 3097 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3098 3099 cm = NULL; 3100 3101 /* 3102 * Get a command 3103 */ 3104 mtx_lock(&sc->aac_io_lock); 3105 if (aac_alloc_command(sc, &cm)) { 3106 struct aac_event *event; 3107 3108 event = malloc(sizeof(struct aac_event), M_AACBUF, 3109 M_NOWAIT | M_ZERO); 3110 if (event == NULL) { 3111 error = EBUSY; 3112 mtx_unlock(&sc->aac_io_lock); 3113 goto out; 3114 } 3115 event->ev_type = AAC_EVENT_CMFREE; 3116 event->ev_callback = aac_ioctl_event; 3117 event->ev_arg = &cm; 3118 aac_add_event(sc, event); 3119 msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 3120 } 3121 mtx_unlock(&sc->aac_io_lock); 3122 3123 /* 3124 * Fetch the FIB header, then re-copy to get data as well. 3125 */ 3126 if ((error = copyin(ufib, cm->cm_fib, 3127 sizeof(struct aac_fib_header))) != 0) 3128 goto out; 3129 size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 3130 if (size > sc->aac_max_fib_size) { 3131 device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 3132 size, sc->aac_max_fib_size); 3133 size = sc->aac_max_fib_size; 3134 } 3135 if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 3136 goto out; 3137 cm->cm_fib->Header.Size = size; 3138 cm->cm_timestamp = time_uptime; 3139 3140 /* 3141 * Pass the FIB to the controller, wait for it to complete. 3142 */ 3143 mtx_lock(&sc->aac_io_lock); 3144 error = aac_wait_command(cm); 3145 mtx_unlock(&sc->aac_io_lock); 3146 if (error != 0) { 3147 device_printf(sc->aac_dev, 3148 "aac_wait_command return %d\n", error); 3149 goto out; 3150 } 3151 3152 /* 3153 * Copy the FIB and data back out to the caller. 3154 */ 3155 size = cm->cm_fib->Header.Size; 3156 if (size > sc->aac_max_fib_size) { 3157 device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 3158 size, sc->aac_max_fib_size); 3159 size = sc->aac_max_fib_size; 3160 } 3161 error = copyout(cm->cm_fib, ufib, size); 3162 3163out: 3164 if (cm != NULL) { 3165 mtx_lock(&sc->aac_io_lock); 3166 aac_release_command(cm); 3167 mtx_unlock(&sc->aac_io_lock); 3168 } 3169 return(error); 3170} 3171 3172/* 3173 * Send a passthrough FIB supplied from userspace 3174 */ 3175static int 3176aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 3177{ 3178 return (EINVAL); 3179} 3180 3181/* 3182 * Handle an AIF sent to us by the controller; queue it for later reference. 3183 * If the queue fills up, then drop the older entries. 3184 */ 3185static void 3186aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 3187{ 3188 struct aac_aif_command *aif; 3189 struct aac_container *co, *co_next; 3190 struct aac_fib_context *ctx; 3191 struct aac_mntinforesp *mir; 3192 int next, current, found; 3193 int count = 0, added = 0, i = 0; 3194 3195 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3196 3197 aif = (struct aac_aif_command*)&fib->data[0]; 3198 aac_print_aif(sc, aif); 3199 3200 /* Is it an event that we should care about? */ 3201 switch (aif->command) { 3202 case AifCmdEventNotify: 3203 switch (aif->data.EN.type) { 3204 case AifEnAddContainer: 3205 case AifEnDeleteContainer: 3206 /* 3207 * A container was added or deleted, but the message 3208 * doesn't tell us anything else! Re-enumerate the 3209 * containers and sort things out. 3210 */ 3211 aac_alloc_sync_fib(sc, &fib); 3212 do { 3213 /* 3214 * Ask the controller for its containers one at 3215 * a time. 3216 * XXX What if the controller's list changes 3217 * midway through this enumaration? 3218 * XXX This should be done async. 3219 */ 3220 if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 3221 continue; 3222 if (i == 0) 3223 count = mir->MntRespCount; 3224 /* 3225 * Check the container against our list. 3226 * co->co_found was already set to 0 in a 3227 * previous run. 3228 */ 3229 if ((mir->Status == ST_OK) && 3230 (mir->MntTable[0].VolType != CT_NONE)) { 3231 found = 0; 3232 TAILQ_FOREACH(co, 3233 &sc->aac_container_tqh, 3234 co_link) { 3235 if (co->co_mntobj.ObjectId == 3236 mir->MntTable[0].ObjectId) { 3237 co->co_found = 1; 3238 found = 1; 3239 break; 3240 } 3241 } 3242 /* 3243 * If the container matched, continue 3244 * in the list. 3245 */ 3246 if (found) { 3247 i++; 3248 continue; 3249 } 3250 3251 /* 3252 * This is a new container. Do all the 3253 * appropriate things to set it up. 3254 */ 3255 aac_add_container(sc, mir, 1); 3256 added = 1; 3257 } 3258 i++; 3259 } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3260 aac_release_sync_fib(sc); 3261 3262 /* 3263 * Go through our list of containers and see which ones 3264 * were not marked 'found'. Since the controller didn't 3265 * list them they must have been deleted. Do the 3266 * appropriate steps to destroy the device. Also reset 3267 * the co->co_found field. 3268 */ 3269 co = TAILQ_FIRST(&sc->aac_container_tqh); 3270 while (co != NULL) { 3271 if (co->co_found == 0) { 3272 mtx_unlock(&sc->aac_io_lock); 3273 newbus_xlock(); 3274 device_delete_child(sc->aac_dev, 3275 co->co_disk); 3276 newbus_xunlock(); 3277 mtx_lock(&sc->aac_io_lock); 3278 co_next = TAILQ_NEXT(co, co_link); 3279 mtx_lock(&sc->aac_container_lock); 3280 TAILQ_REMOVE(&sc->aac_container_tqh, co, 3281 co_link); 3282 mtx_unlock(&sc->aac_container_lock); 3283 free(co, M_AACBUF); 3284 co = co_next; 3285 } else { 3286 co->co_found = 0; 3287 co = TAILQ_NEXT(co, co_link); 3288 } 3289 } 3290 3291 /* Attach the newly created containers */ 3292 if (added) { 3293 mtx_unlock(&sc->aac_io_lock); 3294 newbus_xlock(); 3295 bus_generic_attach(sc->aac_dev); 3296 newbus_xunlock(); 3297 mtx_lock(&sc->aac_io_lock); 3298 } 3299 3300 break; 3301 3302 default: 3303 break; 3304 } 3305 3306 default: 3307 break; 3308 } 3309 3310 /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3311 mtx_lock(&sc->aac_aifq_lock); 3312 current = sc->aifq_idx; 3313 next = (current + 1) % AAC_AIFQ_LENGTH; 3314 if (next == 0) 3315 sc->aifq_filled = 1; 3316 bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3317 /* modify AIF contexts */ 3318 if (sc->aifq_filled) { 3319 for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3320 if (next == ctx->ctx_idx) 3321 ctx->ctx_wrap = 1; 3322 else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3323 ctx->ctx_idx = next; 3324 } 3325 } 3326 sc->aifq_idx = next; 3327 /* On the off chance that someone is sleeping for an aif... */ 3328 if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 3329 wakeup(sc->aac_aifq); 3330 /* Wakeup any poll()ers */ 3331 selwakeuppri(&sc->rcv_select, PRIBIO); 3332 mtx_unlock(&sc->aac_aifq_lock); 3333 3334 return; 3335} 3336 3337/* 3338 * Return the Revision of the driver to userspace and check to see if the 3339 * userspace app is possibly compatible. This is extremely bogus since 3340 * our driver doesn't follow Adaptec's versioning system. Cheat by just 3341 * returning what the card reported. 3342 */ 3343static int 3344aac_rev_check(struct aac_softc *sc, caddr_t udata) 3345{ 3346 struct aac_rev_check rev_check; 3347 struct aac_rev_check_resp rev_check_resp; 3348 int error = 0; 3349 3350 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3351 3352 /* 3353 * Copyin the revision struct from userspace 3354 */ 3355 if ((error = copyin(udata, (caddr_t)&rev_check, 3356 sizeof(struct aac_rev_check))) != 0) { 3357 return error; 3358 } 3359 3360 fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3361 rev_check.callingRevision.buildNumber); 3362 3363 /* 3364 * Doctor up the response struct. 3365 */ 3366 rev_check_resp.possiblyCompatible = 1; 3367 rev_check_resp.adapterSWRevision.external.ul = 3368 sc->aac_revision.external.ul; 3369 rev_check_resp.adapterSWRevision.buildNumber = 3370 sc->aac_revision.buildNumber; 3371 3372 return(copyout((caddr_t)&rev_check_resp, udata, 3373 sizeof(struct aac_rev_check_resp))); 3374} 3375 3376/* 3377 * Pass the fib context to the caller 3378 */ 3379static int 3380aac_open_aif(struct aac_softc *sc, caddr_t arg) 3381{ 3382 struct aac_fib_context *fibctx, *ctx; 3383 int error = 0; 3384 3385 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3386 3387 fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3388 if (fibctx == NULL) 3389 return (ENOMEM); 3390 3391 mtx_lock(&sc->aac_aifq_lock); 3392 /* all elements are already 0, add to queue */ 3393 if (sc->fibctx == NULL) 3394 sc->fibctx = fibctx; 3395 else { 3396 for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3397 ; 3398 ctx->next = fibctx; 3399 fibctx->prev = ctx; 3400 } 3401 3402 /* evaluate unique value */ 3403 fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3404 ctx = sc->fibctx; 3405 while (ctx != fibctx) { 3406 if (ctx->unique == fibctx->unique) { 3407 fibctx->unique++; 3408 ctx = sc->fibctx; 3409 } else { 3410 ctx = ctx->next; 3411 } 3412 } 3413 mtx_unlock(&sc->aac_aifq_lock); 3414 3415 error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3416 if (error) 3417 aac_close_aif(sc, (caddr_t)ctx); 3418 return error; 3419} 3420 3421/* 3422 * Close the caller's fib context 3423 */ 3424static int 3425aac_close_aif(struct aac_softc *sc, caddr_t arg) 3426{ 3427 struct aac_fib_context *ctx; 3428 3429 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3430 3431 mtx_lock(&sc->aac_aifq_lock); 3432 for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3433 if (ctx->unique == *(uint32_t *)&arg) { 3434 if (ctx == sc->fibctx) 3435 sc->fibctx = NULL; 3436 else { 3437 ctx->prev->next = ctx->next; 3438 if (ctx->next) 3439 ctx->next->prev = ctx->prev; 3440 } 3441 break; 3442 } 3443 } 3444 mtx_unlock(&sc->aac_aifq_lock); 3445 if (ctx) 3446 free(ctx, M_AACBUF); 3447 3448 return 0; 3449} 3450 3451/* 3452 * Pass the caller the next AIF in their queue 3453 */ 3454static int 3455aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 3456{ 3457 struct get_adapter_fib_ioctl agf; 3458 struct aac_fib_context *ctx; 3459 int error; 3460 3461 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3462 3463 if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3464 for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3465 if (agf.AdapterFibContext == ctx->unique) 3466 break; 3467 } 3468 if (!ctx) 3469 return (EFAULT); 3470 3471 error = aac_return_aif(sc, ctx, agf.AifFib); 3472 if (error == EAGAIN && agf.Wait) { 3473 fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 3474 sc->aac_state |= AAC_STATE_AIF_SLEEPER; 3475 while (error == EAGAIN) { 3476 error = tsleep(sc->aac_aifq, PRIBIO | 3477 PCATCH, "aacaif", 0); 3478 if (error == 0) 3479 error = aac_return_aif(sc, ctx, agf.AifFib); 3480 } 3481 sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 3482 } 3483 } 3484 return(error); 3485} 3486 3487/* 3488 * Hand the next AIF off the top of the queue out to userspace. 3489 */ 3490static int 3491aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 3492{ 3493 int current, error; 3494 3495 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3496 3497 mtx_lock(&sc->aac_aifq_lock); 3498 current = ctx->ctx_idx; 3499 if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3500 /* empty */ 3501 mtx_unlock(&sc->aac_aifq_lock); 3502 return (EAGAIN); 3503 } 3504 error = 3505 copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 3506 if (error) 3507 device_printf(sc->aac_dev, 3508 "aac_return_aif: copyout returned %d\n", error); 3509 else { 3510 ctx->ctx_wrap = 0; 3511 ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3512 } 3513 mtx_unlock(&sc->aac_aifq_lock); 3514 return(error); 3515} 3516 3517static int 3518aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3519{ 3520 struct aac_pci_info { 3521 u_int32_t bus; 3522 u_int32_t slot; 3523 } pciinf; 3524 int error; 3525 3526 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3527 3528 pciinf.bus = pci_get_bus(sc->aac_dev); 3529 pciinf.slot = pci_get_slot(sc->aac_dev); 3530 3531 error = copyout((caddr_t)&pciinf, uptr, 3532 sizeof(struct aac_pci_info)); 3533 3534 return (error); 3535} 3536 3537static int 3538aac_supported_features(struct aac_softc *sc, caddr_t uptr) 3539{ 3540 struct aac_features f; 3541 int error; 3542 3543 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3544 3545 if ((error = copyin(uptr, &f, sizeof (f))) != 0) 3546 return (error); 3547 3548 /* 3549 * When the management driver receives FSACTL_GET_FEATURES ioctl with 3550 * ALL zero in the featuresState, the driver will return the current 3551 * state of all the supported features, the data field will not be 3552 * valid. 3553 * When the management driver receives FSACTL_GET_FEATURES ioctl with 3554 * a specific bit set in the featuresState, the driver will return the 3555 * current state of this specific feature and whatever data that are 3556 * associated with the feature in the data field or perform whatever 3557 * action needed indicates in the data field. 3558 */ 3559 if (f.feat.fValue == 0) { 3560 f.feat.fBits.largeLBA = 3561 (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3562 /* TODO: In the future, add other features state here as well */ 3563 } else { 3564 if (f.feat.fBits.largeLBA) 3565 f.feat.fBits.largeLBA = 3566 (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3567 /* TODO: Add other features state and data in the future */ 3568 } 3569 3570 error = copyout(&f, uptr, sizeof (f)); 3571 return (error); 3572} 3573 3574/* 3575 * Give the userland some information about the container. The AAC arch 3576 * expects the driver to be a SCSI passthrough type driver, so it expects 3577 * the containers to have b:t:l numbers. Fake it. 3578 */ 3579static int 3580aac_query_disk(struct aac_softc *sc, caddr_t uptr) 3581{ 3582 struct aac_query_disk query_disk; 3583 struct aac_container *co; 3584 struct aac_disk *disk; 3585 int error, id; 3586 3587 fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3588 3589 disk = NULL; 3590 3591 error = copyin(uptr, (caddr_t)&query_disk, 3592 sizeof(struct aac_query_disk)); 3593 if (error) 3594 return (error); 3595 3596 id = query_disk.ContainerNumber; 3597 if (id == -1) 3598 return (EINVAL); 3599 3600 mtx_lock(&sc->aac_container_lock); 3601 TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 3602 if (co->co_mntobj.ObjectId == id) 3603 break; 3604 } 3605 3606 if (co == NULL) { 3607 query_disk.Valid = 0; 3608 query_disk.Locked = 0; 3609 query_disk.Deleted = 1; /* XXX is this right? */ 3610 } else { 3611 disk = device_get_softc(co->co_disk); 3612 query_disk.Valid = 1; 3613 query_disk.Locked = 3614 (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 3615 query_disk.Deleted = 0; 3616 query_disk.Bus = device_get_unit(sc->aac_dev); 3617 query_disk.Target = disk->unit; 3618 query_disk.Lun = 0; 3619 query_disk.UnMapped = 0; 3620 sprintf(&query_disk.diskDeviceName[0], "%s%d", 3621 disk->ad_disk->d_name, disk->ad_disk->d_unit); 3622 } 3623 mtx_unlock(&sc->aac_container_lock); 3624 3625 error = copyout((caddr_t)&query_disk, uptr, 3626 sizeof(struct aac_query_disk)); 3627 3628 return (error); 3629} 3630 3631static void 3632aac_get_bus_info(struct aac_softc *sc) 3633{ 3634 struct aac_fib *fib; 3635 struct aac_ctcfg *c_cmd; 3636 struct aac_ctcfg_resp *c_resp; 3637 struct aac_vmioctl *vmi; 3638 struct aac_vmi_businf_resp *vmi_resp; 3639 struct aac_getbusinf businfo; 3640 struct aac_sim *caminf; 3641 device_t child; 3642 int i, found, error; 3643 3644 mtx_lock(&sc->aac_io_lock); 3645 aac_alloc_sync_fib(sc, &fib); 3646 c_cmd = (struct aac_ctcfg *)&fib->data[0]; 3647 bzero(c_cmd, sizeof(struct aac_ctcfg)); 3648 3649 c_cmd->Command = VM_ContainerConfig; 3650 c_cmd->cmd = CT_GET_SCSI_METHOD; 3651 c_cmd->param = 0; 3652 3653 error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3654 sizeof(struct aac_ctcfg)); 3655 if (error) { 3656 device_printf(sc->aac_dev, "Error %d sending " 3657 "VM_ContainerConfig command\n", error); 3658 aac_release_sync_fib(sc); 3659 mtx_unlock(&sc->aac_io_lock); 3660 return; 3661 } 3662 3663 c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3664 if (c_resp->Status != ST_OK) { 3665 device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3666 c_resp->Status); 3667 aac_release_sync_fib(sc); 3668 mtx_unlock(&sc->aac_io_lock); 3669 return; 3670 } 3671 3672 sc->scsi_method_id = c_resp->param; 3673 3674 vmi = (struct aac_vmioctl *)&fib->data[0]; 3675 bzero(vmi, sizeof(struct aac_vmioctl)); 3676 3677 vmi->Command = VM_Ioctl; 3678 vmi->ObjType = FT_DRIVE; 3679 vmi->MethId = sc->scsi_method_id; 3680 vmi->ObjId = 0; 3681 vmi->IoctlCmd = GetBusInfo; 3682 3683 error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3684 sizeof(struct aac_vmi_businf_resp)); 3685 if (error) { 3686 device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3687 error); 3688 aac_release_sync_fib(sc); 3689 mtx_unlock(&sc->aac_io_lock); 3690 return; 3691 } 3692 3693 vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3694 if (vmi_resp->Status != ST_OK) { 3695 device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3696 vmi_resp->Status); 3697 aac_release_sync_fib(sc); 3698 mtx_unlock(&sc->aac_io_lock); 3699 return; 3700 } 3701 3702 bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3703 aac_release_sync_fib(sc); 3704 mtx_unlock(&sc->aac_io_lock); 3705 3706 found = 0; 3707 for (i = 0; i < businfo.BusCount; i++) { 3708 if (businfo.BusValid[i] != AAC_BUS_VALID) 3709 continue; 3710 3711 caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3712 M_AACBUF, M_NOWAIT | M_ZERO); 3713 if (caminf == NULL) { 3714 device_printf(sc->aac_dev, 3715 "No memory to add passthrough bus %d\n", i); 3716 break; 3717 }; 3718 3719 child = device_add_child(sc->aac_dev, "aacp", -1); 3720 if (child == NULL) { 3721 device_printf(sc->aac_dev, 3722 "device_add_child failed for passthrough bus %d\n", 3723 i); 3724 free(caminf, M_AACBUF); 3725 break; 3726 } 3727 3728 caminf->TargetsPerBus = businfo.TargetsPerBus; 3729 caminf->BusNumber = i; 3730 caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3731 caminf->aac_sc = sc; 3732 caminf->sim_dev = child; 3733 3734 device_set_ivars(child, caminf); 3735 device_set_desc(child, "SCSI Passthrough Bus"); 3736 TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3737 3738 found = 1; 3739 } 3740 3741 if (found) 3742 bus_generic_attach(sc->aac_dev); 3743 3744 return; 3745} 3746