1250963Sachim/*- 2250963Sachim * Copyright (c) 2000 Michael Smith 3250963Sachim * Copyright (c) 2001 Scott Long 4250963Sachim * Copyright (c) 2000 BSDi 5250963Sachim * Copyright (c) 2001-2010 Adaptec, Inc. 6250963Sachim * Copyright (c) 2010-2012 PMC-Sierra, Inc. 7250963Sachim * All rights reserved. 8250963Sachim * 9250963Sachim * Redistribution and use in source and binary forms, with or without 10250963Sachim * modification, are permitted provided that the following conditions 11250963Sachim * are met: 12250963Sachim * 1. Redistributions of source code must retain the above copyright 13250963Sachim * notice, this list of conditions and the following disclaimer. 14250963Sachim * 2. Redistributions in binary form must reproduce the above copyright 15250963Sachim * notice, this list of conditions and the following disclaimer in the 16250963Sachim * documentation and/or other materials provided with the distribution. 17250963Sachim * 18250963Sachim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19250963Sachim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20250963Sachim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21250963Sachim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22250963Sachim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23250963Sachim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24250963Sachim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25250963Sachim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26250963Sachim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27250963Sachim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28250963Sachim * SUCH DAMAGE. 29250963Sachim */ 30250963Sachim 31250963Sachim#include <sys/cdefs.h> 32250963Sachim__FBSDID("$FreeBSD$"); 33250963Sachim 34250963Sachim/* 35250963Sachim * Driver for the Adaptec by PMC Series 6,7,8,... families of RAID controllers 36250963Sachim */ 37250963Sachim#define AAC_DRIVERNAME "aacraid" 38250963Sachim 39250963Sachim#include "opt_aacraid.h" 40250963Sachim 41250963Sachim/* #include <stddef.h> */ 42250963Sachim#include <sys/param.h> 43250963Sachim#include <sys/systm.h> 44250963Sachim#include <sys/malloc.h> 45250963Sachim#include <sys/kernel.h> 46250963Sachim#include <sys/kthread.h> 47250963Sachim#include <sys/sysctl.h> 48250963Sachim#include <sys/poll.h> 49250963Sachim#include <sys/ioccom.h> 50250963Sachim 51250963Sachim#include <sys/bus.h> 52250963Sachim#include <sys/conf.h> 53250963Sachim#include <sys/signalvar.h> 54250963Sachim#include <sys/time.h> 55250963Sachim#include <sys/eventhandler.h> 56250963Sachim#include <sys/rman.h> 57250963Sachim 58250963Sachim#include <machine/bus.h> 59250963Sachim#include <sys/bus_dma.h> 60250963Sachim#include <machine/resource.h> 61250963Sachim 62250963Sachim#include <dev/pci/pcireg.h> 63250963Sachim#include <dev/pci/pcivar.h> 64250963Sachim 65250963Sachim#include <dev/aacraid/aacraid_reg.h> 66250963Sachim#include <sys/aac_ioctl.h> 67250963Sachim#include <dev/aacraid/aacraid_debug.h> 68250963Sachim#include <dev/aacraid/aacraid_var.h> 69250963Sachim 70250963Sachim#ifndef FILTER_HANDLED 71250963Sachim#define FILTER_HANDLED 0x02 72250963Sachim#endif 73250963Sachim 74250963Sachimstatic void aac_add_container(struct aac_softc *sc, 75250963Sachim struct aac_mntinforesp *mir, int f, 76250963Sachim u_int32_t uid); 77250963Sachimstatic void aac_get_bus_info(struct aac_softc *sc); 78250963Sachimstatic void aac_container_bus(struct aac_softc *sc); 79250963Sachimstatic void aac_daemon(void *arg); 80250963Sachimstatic int aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 81250963Sachim int pages, int nseg, int nseg_new); 82250963Sachim 83250963Sachim/* Command Processing */ 84250963Sachimstatic void aac_timeout(struct aac_softc *sc); 85250963Sachimstatic void aac_command_thread(struct aac_softc *sc); 86250963Sachimstatic int aac_sync_fib(struct aac_softc *sc, u_int32_t command, 87250963Sachim u_int32_t xferstate, struct aac_fib *fib, 88250963Sachim u_int16_t datasize); 89250963Sachim/* Command Buffer Management */ 90250963Sachimstatic void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 91250963Sachim int nseg, int error); 92250963Sachimstatic int aac_alloc_commands(struct aac_softc *sc); 93250963Sachimstatic void aac_free_commands(struct aac_softc *sc); 94250963Sachimstatic void aac_unmap_command(struct aac_command *cm); 95250963Sachim 96250963Sachim/* Hardware Interface */ 97250963Sachimstatic int aac_alloc(struct aac_softc *sc); 98250963Sachimstatic void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 99250963Sachim int error); 100250963Sachimstatic int aac_check_firmware(struct aac_softc *sc); 101250963Sachimstatic int aac_init(struct aac_softc *sc); 102250963Sachimstatic int aac_setup_intr(struct aac_softc *sc); 103250963Sachim 104250963Sachim/* PMC SRC interface */ 105250963Sachimstatic int aac_src_get_fwstatus(struct aac_softc *sc); 106250963Sachimstatic void aac_src_qnotify(struct aac_softc *sc, int qbit); 107250963Sachimstatic int aac_src_get_istatus(struct aac_softc *sc); 108250963Sachimstatic void aac_src_clear_istatus(struct aac_softc *sc, int mask); 109250963Sachimstatic void aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, 110250963Sachim u_int32_t arg0, u_int32_t arg1, 111250963Sachim u_int32_t arg2, u_int32_t arg3); 112250963Sachimstatic int aac_src_get_mailbox(struct aac_softc *sc, int mb); 113250963Sachimstatic void aac_src_set_interrupts(struct aac_softc *sc, int enable); 114250963Sachimstatic int aac_src_send_command(struct aac_softc *sc, struct aac_command *cm); 115250963Sachimstatic int aac_src_get_outb_queue(struct aac_softc *sc); 116250963Sachimstatic void aac_src_set_outb_queue(struct aac_softc *sc, int index); 117250963Sachim 118250963Sachimstruct aac_interface aacraid_src_interface = { 119250963Sachim aac_src_get_fwstatus, 120250963Sachim aac_src_qnotify, 121250963Sachim aac_src_get_istatus, 122250963Sachim aac_src_clear_istatus, 123250963Sachim aac_src_set_mailbox, 124250963Sachim aac_src_get_mailbox, 125250963Sachim aac_src_set_interrupts, 126250963Sachim aac_src_send_command, 127250963Sachim aac_src_get_outb_queue, 128250963Sachim aac_src_set_outb_queue 129250963Sachim}; 130250963Sachim 131250963Sachim/* PMC SRCv interface */ 132250963Sachimstatic void aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, 133250963Sachim u_int32_t arg0, u_int32_t arg1, 134250963Sachim u_int32_t arg2, u_int32_t arg3); 135250963Sachimstatic int aac_srcv_get_mailbox(struct aac_softc *sc, int mb); 136250963Sachim 137250963Sachimstruct aac_interface aacraid_srcv_interface = { 138250963Sachim aac_src_get_fwstatus, 139250963Sachim aac_src_qnotify, 140250963Sachim aac_src_get_istatus, 141250963Sachim aac_src_clear_istatus, 142250963Sachim aac_srcv_set_mailbox, 143250963Sachim aac_srcv_get_mailbox, 144250963Sachim aac_src_set_interrupts, 145250963Sachim aac_src_send_command, 146250963Sachim aac_src_get_outb_queue, 147250963Sachim aac_src_set_outb_queue 148250963Sachim}; 149250963Sachim 150250963Sachim/* Debugging and Diagnostics */ 151250963Sachimstatic struct aac_code_lookup aac_cpu_variant[] = { 152250963Sachim {"i960JX", CPUI960_JX}, 153250963Sachim {"i960CX", CPUI960_CX}, 154250963Sachim {"i960HX", CPUI960_HX}, 155250963Sachim {"i960RX", CPUI960_RX}, 156250963Sachim {"i960 80303", CPUI960_80303}, 157250963Sachim {"StrongARM SA110", CPUARM_SA110}, 158250963Sachim {"PPC603e", CPUPPC_603e}, 159250963Sachim {"XScale 80321", CPU_XSCALE_80321}, 160250963Sachim {"MIPS 4KC", CPU_MIPS_4KC}, 161250963Sachim {"MIPS 5KC", CPU_MIPS_5KC}, 162250963Sachim {"Unknown StrongARM", CPUARM_xxx}, 163250963Sachim {"Unknown PowerPC", CPUPPC_xxx}, 164250963Sachim {NULL, 0}, 165250963Sachim {"Unknown processor", 0} 166250963Sachim}; 167250963Sachim 168250963Sachimstatic struct aac_code_lookup aac_battery_platform[] = { 169250963Sachim {"required battery present", PLATFORM_BAT_REQ_PRESENT}, 170250963Sachim {"REQUIRED BATTERY NOT PRESENT", PLATFORM_BAT_REQ_NOTPRESENT}, 171250963Sachim {"optional battery present", PLATFORM_BAT_OPT_PRESENT}, 172250963Sachim {"optional battery not installed", PLATFORM_BAT_OPT_NOTPRESENT}, 173250963Sachim {"no battery support", PLATFORM_BAT_NOT_SUPPORTED}, 174250963Sachim {NULL, 0}, 175250963Sachim {"unknown battery platform", 0} 176250963Sachim}; 177250963Sachimstatic void aac_describe_controller(struct aac_softc *sc); 178250963Sachimstatic char *aac_describe_code(struct aac_code_lookup *table, 179250963Sachim u_int32_t code); 180250963Sachim 181250963Sachim/* Management Interface */ 182250963Sachimstatic d_open_t aac_open; 183250963Sachimstatic d_ioctl_t aac_ioctl; 184250963Sachimstatic d_poll_t aac_poll; 185250963Sachim#if __FreeBSD_version >= 702000 186250963Sachimstatic void aac_cdevpriv_dtor(void *arg); 187250963Sachim#else 188250963Sachimstatic d_close_t aac_close; 189250963Sachim#endif 190250963Sachimstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 191250963Sachimstatic int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 192250963Sachimstatic void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); 193250963Sachimstatic void aac_request_aif(struct aac_softc *sc); 194250963Sachimstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 195250963Sachimstatic int aac_open_aif(struct aac_softc *sc, caddr_t arg); 196250963Sachimstatic int aac_close_aif(struct aac_softc *sc, caddr_t arg); 197250963Sachimstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 198250963Sachimstatic int aac_return_aif(struct aac_softc *sc, 199250963Sachim struct aac_fib_context *ctx, caddr_t uptr); 200250963Sachimstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 201250963Sachimstatic int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 202250963Sachimstatic int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 203250963Sachimstatic void aac_ioctl_event(struct aac_softc *sc, 204250963Sachim struct aac_event *event, void *arg); 205250963Sachimstatic int aac_reset_adapter(struct aac_softc *sc); 206250963Sachimstatic int aac_get_container_info(struct aac_softc *sc, 207250963Sachim struct aac_fib *fib, int cid, 208250963Sachim struct aac_mntinforesp *mir, 209250963Sachim u_int32_t *uid); 210250963Sachimstatic u_int32_t 211250963Sachim aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled); 212250963Sachim 213250963Sachimstatic struct cdevsw aacraid_cdevsw = { 214250963Sachim .d_version = D_VERSION, 215250963Sachim .d_flags = D_NEEDGIANT, 216250963Sachim .d_open = aac_open, 217250963Sachim#if __FreeBSD_version < 702000 218250963Sachim .d_close = aac_close, 219250963Sachim#endif 220250963Sachim .d_ioctl = aac_ioctl, 221250963Sachim .d_poll = aac_poll, 222250963Sachim .d_name = "aacraid", 223250963Sachim}; 224250963Sachim 225250963SachimMALLOC_DEFINE(M_AACRAIDBUF, "aacraid_buf", "Buffers for the AACRAID driver"); 226250963Sachim 227250963Sachim/* sysctl node */ 228250963SachimSYSCTL_NODE(_hw, OID_AUTO, aacraid, CTLFLAG_RD, 0, "AACRAID driver parameters"); 229250963Sachim 230250963Sachim/* 231250963Sachim * Device Interface 232250963Sachim */ 233250963Sachim 234250963Sachim/* 235250963Sachim * Initialize the controller and softc 236250963Sachim */ 237250963Sachimint 238250963Sachimaacraid_attach(struct aac_softc *sc) 239250963Sachim{ 240250963Sachim int error, unit; 241250963Sachim struct aac_fib *fib; 242250963Sachim struct aac_mntinforesp mir; 243250963Sachim int count = 0, i = 0; 244250963Sachim u_int32_t uid; 245250963Sachim 246250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 247250963Sachim sc->hint_flags = device_get_flags(sc->aac_dev); 248250963Sachim /* 249250963Sachim * Initialize per-controller queues. 250250963Sachim */ 251250963Sachim aac_initq_free(sc); 252250963Sachim aac_initq_ready(sc); 253250963Sachim aac_initq_busy(sc); 254250963Sachim 255250963Sachim /* mark controller as suspended until we get ourselves organised */ 256250963Sachim sc->aac_state |= AAC_STATE_SUSPEND; 257250963Sachim 258250963Sachim /* 259250963Sachim * Check that the firmware on the card is supported. 260250963Sachim */ 261250963Sachim if ((error = aac_check_firmware(sc)) != 0) 262250963Sachim return(error); 263250963Sachim 264250963Sachim /* 265250963Sachim * Initialize locks 266250963Sachim */ 267250963Sachim mtx_init(&sc->aac_io_lock, "AACRAID I/O lock", NULL, MTX_DEF); 268250963Sachim TAILQ_INIT(&sc->aac_container_tqh); 269250963Sachim TAILQ_INIT(&sc->aac_ev_cmfree); 270250963Sachim 271250963Sachim#if __FreeBSD_version >= 800000 272250963Sachim /* Initialize the clock daemon callout. */ 273250963Sachim callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 274250963Sachim#endif 275250963Sachim /* 276250963Sachim * Initialize the adapter. 277250963Sachim */ 278250963Sachim if ((error = aac_alloc(sc)) != 0) 279250963Sachim return(error); 280250963Sachim if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 281250963Sachim if ((error = aac_init(sc)) != 0) 282250963Sachim return(error); 283250963Sachim } 284250963Sachim 285250963Sachim /* 286250963Sachim * Allocate and connect our interrupt. 287250963Sachim */ 288250963Sachim if ((error = aac_setup_intr(sc)) != 0) 289250963Sachim return(error); 290250963Sachim 291250963Sachim /* 292250963Sachim * Print a little information about the controller. 293250963Sachim */ 294250963Sachim aac_describe_controller(sc); 295250963Sachim 296250963Sachim /* 297250963Sachim * Make the control device. 298250963Sachim */ 299250963Sachim unit = device_get_unit(sc->aac_dev); 300250963Sachim sc->aac_dev_t = make_dev(&aacraid_cdevsw, unit, UID_ROOT, GID_OPERATOR, 301250963Sachim 0640, "aacraid%d", unit); 302250963Sachim sc->aac_dev_t->si_drv1 = sc; 303250963Sachim 304250963Sachim /* Create the AIF thread */ 305250963Sachim if (aac_kthread_create((void(*)(void *))aac_command_thread, sc, 306250963Sachim &sc->aifthread, 0, 0, "aacraid%daif", unit)) 307250963Sachim panic("Could not create AIF thread"); 308250963Sachim 309250963Sachim /* Register the shutdown method to only be called post-dump */ 310250963Sachim if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aacraid_shutdown, 311250963Sachim sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 312250963Sachim device_printf(sc->aac_dev, 313250963Sachim "shutdown event registration failed\n"); 314250963Sachim 315250963Sachim /* Find containers */ 316250963Sachim mtx_lock(&sc->aac_io_lock); 317250963Sachim aac_alloc_sync_fib(sc, &fib); 318250963Sachim /* loop over possible containers */ 319250963Sachim do { 320250963Sachim if ((aac_get_container_info(sc, fib, i, &mir, &uid)) != 0) 321250963Sachim continue; 322250963Sachim if (i == 0) 323250963Sachim count = mir.MntRespCount; 324250963Sachim aac_add_container(sc, &mir, 0, uid); 325250963Sachim i++; 326250963Sachim } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 327250963Sachim aac_release_sync_fib(sc); 328250963Sachim mtx_unlock(&sc->aac_io_lock); 329250963Sachim 330250963Sachim /* Register with CAM for the containers */ 331250963Sachim TAILQ_INIT(&sc->aac_sim_tqh); 332250963Sachim aac_container_bus(sc); 333250963Sachim /* Register with CAM for the non-DASD devices */ 334250963Sachim if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) 335250963Sachim aac_get_bus_info(sc); 336250963Sachim 337250963Sachim /* poke the bus to actually attach the child devices */ 338250963Sachim bus_generic_attach(sc->aac_dev); 339250963Sachim 340250963Sachim /* mark the controller up */ 341250963Sachim sc->aac_state &= ~AAC_STATE_SUSPEND; 342250963Sachim 343250963Sachim /* enable interrupts now */ 344250963Sachim AAC_UNMASK_INTERRUPTS(sc); 345250963Sachim 346250963Sachim#if __FreeBSD_version >= 800000 347250963Sachim mtx_lock(&sc->aac_io_lock); 348250963Sachim callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 349250963Sachim mtx_unlock(&sc->aac_io_lock); 350250963Sachim#else 351250963Sachim { 352250963Sachim struct timeval tv; 353250963Sachim tv.tv_sec = 60; 354250963Sachim tv.tv_usec = 0; 355250963Sachim sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 356250963Sachim } 357250963Sachim#endif 358250963Sachim 359250963Sachim return(0); 360250963Sachim} 361250963Sachim 362250963Sachimstatic void 363250963Sachimaac_daemon(void *arg) 364250963Sachim{ 365250963Sachim struct aac_softc *sc; 366250963Sachim struct timeval tv; 367250963Sachim struct aac_command *cm; 368250963Sachim struct aac_fib *fib; 369250963Sachim 370250963Sachim sc = arg; 371250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 372250963Sachim 373250963Sachim#if __FreeBSD_version >= 800000 374250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 375250963Sachim if (callout_pending(&sc->aac_daemontime) || 376250963Sachim callout_active(&sc->aac_daemontime) == 0) 377250963Sachim return; 378250963Sachim#else 379250963Sachim mtx_lock(&sc->aac_io_lock); 380250963Sachim#endif 381250963Sachim getmicrotime(&tv); 382250963Sachim 383250963Sachim if (!aacraid_alloc_command(sc, &cm)) { 384250963Sachim fib = cm->cm_fib; 385250963Sachim cm->cm_timestamp = time_uptime; 386250963Sachim cm->cm_datalen = 0; 387250963Sachim cm->cm_flags |= AAC_CMD_WAIT; 388250963Sachim 389250963Sachim fib->Header.Size = 390250963Sachim sizeof(struct aac_fib_header) + sizeof(u_int32_t); 391250963Sachim fib->Header.XferState = 392250963Sachim AAC_FIBSTATE_HOSTOWNED | 393250963Sachim AAC_FIBSTATE_INITIALISED | 394250963Sachim AAC_FIBSTATE_EMPTY | 395250963Sachim AAC_FIBSTATE_FROMHOST | 396250963Sachim AAC_FIBSTATE_REXPECTED | 397250963Sachim AAC_FIBSTATE_NORM | 398250963Sachim AAC_FIBSTATE_ASYNC | 399250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 400250963Sachim fib->Header.Command = SendHostTime; 401250963Sachim *(uint32_t *)fib->data = tv.tv_sec; 402250963Sachim 403250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 404250963Sachim aacraid_release_command(cm); 405250963Sachim } 406250963Sachim 407250963Sachim#if __FreeBSD_version >= 800000 408250963Sachim callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 409250963Sachim#else 410250963Sachim mtx_unlock(&sc->aac_io_lock); 411250963Sachim tv.tv_sec = 30 * 60; 412250963Sachim tv.tv_usec = 0; 413250963Sachim sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 414250963Sachim#endif 415250963Sachim} 416250963Sachim 417250963Sachimvoid 418250963Sachimaacraid_add_event(struct aac_softc *sc, struct aac_event *event) 419250963Sachim{ 420250963Sachim 421250963Sachim switch (event->ev_type & AAC_EVENT_MASK) { 422250963Sachim case AAC_EVENT_CMFREE: 423250963Sachim TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 424250963Sachim break; 425250963Sachim default: 426250963Sachim device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 427250963Sachim event->ev_type); 428250963Sachim break; 429250963Sachim } 430250963Sachim 431250963Sachim return; 432250963Sachim} 433250963Sachim 434250963Sachim/* 435250963Sachim * Request information of container #cid 436250963Sachim */ 437250963Sachimstatic int 438250963Sachimaac_get_container_info(struct aac_softc *sc, struct aac_fib *sync_fib, int cid, 439250963Sachim struct aac_mntinforesp *mir, u_int32_t *uid) 440250963Sachim{ 441250963Sachim struct aac_command *cm; 442250963Sachim struct aac_fib *fib; 443250963Sachim struct aac_mntinfo *mi; 444250963Sachim struct aac_cnt_config *ccfg; 445250963Sachim 446250963Sachim if (sync_fib == NULL) { 447250963Sachim if (aacraid_alloc_command(sc, &cm)) { 448250963Sachim device_printf(sc->aac_dev, 449250963Sachim "Warning, no free command available\n"); 450250963Sachim return (-1); 451250963Sachim } 452250963Sachim fib = cm->cm_fib; 453250963Sachim } else { 454250963Sachim fib = sync_fib; 455250963Sachim } 456250963Sachim 457250963Sachim mi = (struct aac_mntinfo *)&fib->data[0]; 458250963Sachim /* 4KB support?, 64-bit LBA? */ 459250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE) 460250963Sachim mi->Command = VM_NameServeAllBlk; 461250963Sachim else if (sc->flags & AAC_FLAGS_LBA_64BIT) 462250963Sachim mi->Command = VM_NameServe64; 463250963Sachim else 464250963Sachim mi->Command = VM_NameServe; 465250963Sachim mi->MntType = FT_FILESYS; 466250963Sachim mi->MntCount = cid; 467250963Sachim 468250963Sachim if (sync_fib) { 469250963Sachim if (aac_sync_fib(sc, ContainerCommand, 0, fib, 470250963Sachim sizeof(struct aac_mntinfo))) { 471250963Sachim device_printf(sc->aac_dev, "Error probing container %d\n", cid); 472250963Sachim return (-1); 473250963Sachim } 474250963Sachim } else { 475250963Sachim cm->cm_timestamp = time_uptime; 476250963Sachim cm->cm_datalen = 0; 477250963Sachim 478250963Sachim fib->Header.Size = 479250963Sachim sizeof(struct aac_fib_header) + sizeof(struct aac_mntinfo); 480250963Sachim fib->Header.XferState = 481250963Sachim AAC_FIBSTATE_HOSTOWNED | 482250963Sachim AAC_FIBSTATE_INITIALISED | 483250963Sachim AAC_FIBSTATE_EMPTY | 484250963Sachim AAC_FIBSTATE_FROMHOST | 485250963Sachim AAC_FIBSTATE_REXPECTED | 486250963Sachim AAC_FIBSTATE_NORM | 487250963Sachim AAC_FIBSTATE_ASYNC | 488250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 489250963Sachim fib->Header.Command = ContainerCommand; 490250963Sachim if (aacraid_wait_command(cm) != 0) { 491250963Sachim device_printf(sc->aac_dev, "Error probing container %d\n", cid); 492250963Sachim aacraid_release_command(cm); 493250963Sachim return (-1); 494250963Sachim } 495250963Sachim } 496250963Sachim bcopy(&fib->data[0], mir, sizeof(struct aac_mntinforesp)); 497250963Sachim 498250963Sachim /* UID */ 499250963Sachim *uid = cid; 500250963Sachim if (mir->MntTable[0].VolType != CT_NONE && 501250963Sachim !(mir->MntTable[0].ContentState & AAC_FSCS_HIDDEN)) { 502250963Sachim if (!(sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)) 503250963Sachim mir->MntTable[0].ObjExtension.BlockSize = 0x200; 504250963Sachim 505250963Sachim ccfg = (struct aac_cnt_config *)&fib->data[0]; 506250963Sachim bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 507250963Sachim ccfg->Command = VM_ContainerConfig; 508250963Sachim ccfg->CTCommand.command = CT_CID_TO_32BITS_UID; 509250963Sachim ccfg->CTCommand.param[0] = cid; 510250963Sachim 511250963Sachim if (sync_fib) { 512250963Sachim if (aac_sync_fib(sc, ContainerCommand, 0, fib, 513250963Sachim sizeof(struct aac_cnt_config) == 0) && 514250963Sachim ccfg->CTCommand.param[0] == ST_OK && 515250963Sachim mir->MntTable[0].VolType != CT_PASSTHRU) 516250963Sachim *uid = ccfg->CTCommand.param[1]; 517250963Sachim } else { 518250963Sachim fib->Header.Size = 519250963Sachim sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config); 520250963Sachim fib->Header.XferState = 521250963Sachim AAC_FIBSTATE_HOSTOWNED | 522250963Sachim AAC_FIBSTATE_INITIALISED | 523250963Sachim AAC_FIBSTATE_EMPTY | 524250963Sachim AAC_FIBSTATE_FROMHOST | 525250963Sachim AAC_FIBSTATE_REXPECTED | 526250963Sachim AAC_FIBSTATE_NORM | 527250963Sachim AAC_FIBSTATE_ASYNC | 528250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 529250963Sachim fib->Header.Command = ContainerCommand; 530250963Sachim if (aacraid_wait_command(cm) == 0 && 531250963Sachim ccfg->CTCommand.param[0] == ST_OK && 532250963Sachim mir->MntTable[0].VolType != CT_PASSTHRU) 533250963Sachim *uid = ccfg->CTCommand.param[1]; 534250963Sachim aacraid_release_command(cm); 535250963Sachim } 536250963Sachim } 537250963Sachim 538250963Sachim return (0); 539250963Sachim} 540250963Sachim 541250963Sachim/* 542250963Sachim * Create a device to represent a new container 543250963Sachim */ 544250963Sachimstatic void 545250963Sachimaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f, 546250963Sachim u_int32_t uid) 547250963Sachim{ 548250963Sachim struct aac_container *co; 549250963Sachim 550250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 551250963Sachim 552250963Sachim /* 553250963Sachim * Check container volume type for validity. Note that many of 554250963Sachim * the possible types may never show up. 555250963Sachim */ 556250963Sachim if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 557250963Sachim co = (struct aac_container *)malloc(sizeof *co, M_AACRAIDBUF, 558250963Sachim M_NOWAIT | M_ZERO); 559250963Sachim if (co == NULL) { 560250963Sachim panic("Out of memory?!"); 561250963Sachim } 562250963Sachim 563250963Sachim co->co_found = f; 564250963Sachim bcopy(&mir->MntTable[0], &co->co_mntobj, 565250963Sachim sizeof(struct aac_mntobj)); 566250963Sachim co->co_uid = uid; 567250963Sachim TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 568250963Sachim } 569250963Sachim} 570250963Sachim 571250963Sachim/* 572250963Sachim * Allocate resources associated with (sc) 573250963Sachim */ 574250963Sachimstatic int 575250963Sachimaac_alloc(struct aac_softc *sc) 576250963Sachim{ 577250963Sachim bus_size_t maxsize; 578250963Sachim 579250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 580250963Sachim 581250963Sachim /* 582250963Sachim * Create DMA tag for mapping buffers into controller-addressable space. 583250963Sachim */ 584250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 585250963Sachim 1, 0, /* algnmnt, boundary */ 586250963Sachim (sc->flags & AAC_FLAGS_SG_64BIT) ? 587250963Sachim BUS_SPACE_MAXADDR : 588250963Sachim BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 589250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 590250963Sachim NULL, NULL, /* filter, filterarg */ 591250963Sachim MAXBSIZE, /* maxsize */ 592250963Sachim sc->aac_sg_tablesize, /* nsegments */ 593250963Sachim MAXBSIZE, /* maxsegsize */ 594250963Sachim BUS_DMA_ALLOCNOW, /* flags */ 595250963Sachim busdma_lock_mutex, /* lockfunc */ 596250963Sachim &sc->aac_io_lock, /* lockfuncarg */ 597250963Sachim &sc->aac_buffer_dmat)) { 598250963Sachim device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 599250963Sachim return (ENOMEM); 600250963Sachim } 601250963Sachim 602250963Sachim /* 603250963Sachim * Create DMA tag for mapping FIBs into controller-addressable space.. 604250963Sachim */ 605250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 606250963Sachim maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 607250963Sachim sizeof(struct aac_fib_xporthdr) + 31); 608250963Sachim else 609250963Sachim maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 31); 610250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 611250963Sachim 1, 0, /* algnmnt, boundary */ 612250963Sachim (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 613250963Sachim BUS_SPACE_MAXADDR_32BIT : 614250963Sachim 0x7fffffff, /* lowaddr */ 615250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 616250963Sachim NULL, NULL, /* filter, filterarg */ 617250963Sachim maxsize, /* maxsize */ 618250963Sachim 1, /* nsegments */ 619250963Sachim maxsize, /* maxsize */ 620250963Sachim 0, /* flags */ 621250963Sachim NULL, NULL, /* No locking needed */ 622250963Sachim &sc->aac_fib_dmat)) { 623250963Sachim device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 624250963Sachim return (ENOMEM); 625250963Sachim } 626250963Sachim 627250963Sachim /* 628250963Sachim * Create DMA tag for the common structure and allocate it. 629250963Sachim */ 630250963Sachim maxsize = sizeof(struct aac_common); 631250963Sachim maxsize += sc->aac_max_fibs * sizeof(u_int32_t); 632250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 633250963Sachim 1, 0, /* algnmnt, boundary */ 634250963Sachim (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 635250963Sachim BUS_SPACE_MAXADDR_32BIT : 636250963Sachim 0x7fffffff, /* lowaddr */ 637250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 638250963Sachim NULL, NULL, /* filter, filterarg */ 639250963Sachim maxsize, /* maxsize */ 640250963Sachim 1, /* nsegments */ 641250963Sachim maxsize, /* maxsegsize */ 642250963Sachim 0, /* flags */ 643250963Sachim NULL, NULL, /* No locking needed */ 644250963Sachim &sc->aac_common_dmat)) { 645250963Sachim device_printf(sc->aac_dev, 646250963Sachim "can't allocate common structure DMA tag\n"); 647250963Sachim return (ENOMEM); 648250963Sachim } 649250963Sachim if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 650250963Sachim BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 651250963Sachim device_printf(sc->aac_dev, "can't allocate common structure\n"); 652250963Sachim return (ENOMEM); 653250963Sachim } 654250963Sachim 655250963Sachim (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 656250963Sachim sc->aac_common, maxsize, 657250963Sachim aac_common_map, sc, 0); 658250963Sachim bzero(sc->aac_common, maxsize); 659250963Sachim 660250963Sachim /* Allocate some FIBs and associated command structs */ 661250963Sachim TAILQ_INIT(&sc->aac_fibmap_tqh); 662250963Sachim sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 663250963Sachim M_AACRAIDBUF, M_WAITOK|M_ZERO); 664250963Sachim mtx_lock(&sc->aac_io_lock); 665250963Sachim while (sc->total_fibs < sc->aac_max_fibs) { 666250963Sachim if (aac_alloc_commands(sc) != 0) 667250963Sachim break; 668250963Sachim } 669250963Sachim mtx_unlock(&sc->aac_io_lock); 670250963Sachim if (sc->total_fibs == 0) 671250963Sachim return (ENOMEM); 672250963Sachim 673250963Sachim return (0); 674250963Sachim} 675250963Sachim 676250963Sachim/* 677250963Sachim * Free all of the resources associated with (sc) 678250963Sachim * 679250963Sachim * Should not be called if the controller is active. 680250963Sachim */ 681250963Sachimvoid 682250963Sachimaacraid_free(struct aac_softc *sc) 683250963Sachim{ 684250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 685250963Sachim 686250963Sachim /* remove the control device */ 687250963Sachim if (sc->aac_dev_t != NULL) 688250963Sachim destroy_dev(sc->aac_dev_t); 689250963Sachim 690250963Sachim /* throw away any FIB buffers, discard the FIB DMA tag */ 691250963Sachim aac_free_commands(sc); 692250963Sachim if (sc->aac_fib_dmat) 693250963Sachim bus_dma_tag_destroy(sc->aac_fib_dmat); 694250963Sachim 695250963Sachim free(sc->aac_commands, M_AACRAIDBUF); 696250963Sachim 697250963Sachim /* destroy the common area */ 698250963Sachim if (sc->aac_common) { 699250963Sachim bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 700250963Sachim bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 701250963Sachim sc->aac_common_dmamap); 702250963Sachim } 703250963Sachim if (sc->aac_common_dmat) 704250963Sachim bus_dma_tag_destroy(sc->aac_common_dmat); 705250963Sachim 706250963Sachim /* disconnect the interrupt handler */ 707250963Sachim if (sc->aac_intr) 708250963Sachim bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 709250963Sachim if (sc->aac_irq != NULL) 710250963Sachim bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 711250963Sachim sc->aac_irq); 712250963Sachim 713250963Sachim /* destroy data-transfer DMA tag */ 714250963Sachim if (sc->aac_buffer_dmat) 715250963Sachim bus_dma_tag_destroy(sc->aac_buffer_dmat); 716250963Sachim 717250963Sachim /* destroy the parent DMA tag */ 718250963Sachim if (sc->aac_parent_dmat) 719250963Sachim bus_dma_tag_destroy(sc->aac_parent_dmat); 720250963Sachim 721250963Sachim /* release the register window mapping */ 722250963Sachim if (sc->aac_regs_res0 != NULL) 723250963Sachim bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 724250963Sachim sc->aac_regs_rid0, sc->aac_regs_res0); 725250963Sachim if (sc->aac_regs_res1 != NULL) 726250963Sachim bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 727250963Sachim sc->aac_regs_rid1, sc->aac_regs_res1); 728250963Sachim} 729250963Sachim 730250963Sachim/* 731250963Sachim * Disconnect from the controller completely, in preparation for unload. 732250963Sachim */ 733250963Sachimint 734250963Sachimaacraid_detach(device_t dev) 735250963Sachim{ 736250963Sachim struct aac_softc *sc; 737250963Sachim struct aac_container *co; 738250963Sachim struct aac_sim *sim; 739250963Sachim int error; 740250963Sachim 741250963Sachim sc = device_get_softc(dev); 742250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 743250963Sachim 744250963Sachim#if __FreeBSD_version >= 800000 745250963Sachim callout_drain(&sc->aac_daemontime); 746250963Sachim#else 747250963Sachim untimeout(aac_daemon, (void *)sc, sc->timeout_id); 748250963Sachim#endif 749250963Sachim /* Remove the child containers */ 750250963Sachim while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 751250963Sachim TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 752250963Sachim free(co, M_AACRAIDBUF); 753250963Sachim } 754250963Sachim 755250963Sachim /* Remove the CAM SIMs */ 756250963Sachim while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 757250963Sachim TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 758250963Sachim error = device_delete_child(dev, sim->sim_dev); 759250963Sachim if (error) 760250963Sachim return (error); 761250963Sachim free(sim, M_AACRAIDBUF); 762250963Sachim } 763250963Sachim 764250963Sachim if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 765250963Sachim sc->aifflags |= AAC_AIFFLAGS_EXIT; 766250963Sachim wakeup(sc->aifthread); 767250963Sachim tsleep(sc->aac_dev, PUSER | PCATCH, "aac_dch", 30 * hz); 768250963Sachim } 769250963Sachim 770250963Sachim if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 771250963Sachim panic("Cannot shutdown AIF thread"); 772250963Sachim 773250963Sachim if ((error = aacraid_shutdown(dev))) 774250963Sachim return(error); 775250963Sachim 776250963Sachim EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 777250963Sachim 778250963Sachim aacraid_free(sc); 779250963Sachim 780250963Sachim mtx_destroy(&sc->aac_io_lock); 781250963Sachim 782250963Sachim return(0); 783250963Sachim} 784250963Sachim 785250963Sachim/* 786250963Sachim * Bring the controller down to a dormant state and detach all child devices. 787250963Sachim * 788250963Sachim * This function is called before detach or system shutdown. 789250963Sachim * 790250963Sachim * Note that we can assume that the bioq on the controller is empty, as we won't 791250963Sachim * allow shutdown if any device is open. 792250963Sachim */ 793250963Sachimint 794250963Sachimaacraid_shutdown(device_t dev) 795250963Sachim{ 796250963Sachim struct aac_softc *sc; 797250963Sachim struct aac_fib *fib; 798250963Sachim struct aac_close_command *cc; 799250963Sachim 800250963Sachim sc = device_get_softc(dev); 801250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 802250963Sachim 803250963Sachim sc->aac_state |= AAC_STATE_SUSPEND; 804250963Sachim 805250963Sachim /* 806250963Sachim * Send a Container shutdown followed by a HostShutdown FIB to the 807250963Sachim * controller to convince it that we don't want to talk to it anymore. 808250963Sachim * We've been closed and all I/O completed already 809250963Sachim */ 810250963Sachim device_printf(sc->aac_dev, "shutting down controller..."); 811250963Sachim 812250963Sachim mtx_lock(&sc->aac_io_lock); 813250963Sachim aac_alloc_sync_fib(sc, &fib); 814250963Sachim cc = (struct aac_close_command *)&fib->data[0]; 815250963Sachim 816250963Sachim bzero(cc, sizeof(struct aac_close_command)); 817250963Sachim cc->Command = VM_CloseAll; 818250963Sachim cc->ContainerId = 0xffffffff; 819250963Sachim if (aac_sync_fib(sc, ContainerCommand, 0, fib, 820250963Sachim sizeof(struct aac_close_command))) 821250963Sachim printf("FAILED.\n"); 822250963Sachim else 823250963Sachim printf("done\n"); 824250963Sachim 825250963Sachim AAC_MASK_INTERRUPTS(sc); 826250963Sachim aac_release_sync_fib(sc); 827250963Sachim mtx_unlock(&sc->aac_io_lock); 828250963Sachim 829250963Sachim return(0); 830250963Sachim} 831250963Sachim 832250963Sachim/* 833250963Sachim * Bring the controller to a quiescent state, ready for system suspend. 834250963Sachim */ 835250963Sachimint 836250963Sachimaacraid_suspend(device_t dev) 837250963Sachim{ 838250963Sachim struct aac_softc *sc; 839250963Sachim 840250963Sachim sc = device_get_softc(dev); 841250963Sachim 842250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 843250963Sachim sc->aac_state |= AAC_STATE_SUSPEND; 844250963Sachim 845250963Sachim AAC_MASK_INTERRUPTS(sc); 846250963Sachim return(0); 847250963Sachim} 848250963Sachim 849250963Sachim/* 850250963Sachim * Bring the controller back to a state ready for operation. 851250963Sachim */ 852250963Sachimint 853250963Sachimaacraid_resume(device_t dev) 854250963Sachim{ 855250963Sachim struct aac_softc *sc; 856250963Sachim 857250963Sachim sc = device_get_softc(dev); 858250963Sachim 859250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 860250963Sachim sc->aac_state &= ~AAC_STATE_SUSPEND; 861250963Sachim AAC_UNMASK_INTERRUPTS(sc); 862250963Sachim return(0); 863250963Sachim} 864250963Sachim 865250963Sachim/* 866250963Sachim * Interrupt handler for NEW_COMM_TYPE1, NEW_COMM_TYPE2, NEW_COMM_TYPE34 interface. 867250963Sachim */ 868250963Sachimvoid 869250963Sachimaacraid_new_intr_type1(void *arg) 870250963Sachim{ 871250963Sachim struct aac_softc *sc; 872250963Sachim struct aac_command *cm; 873250963Sachim struct aac_fib *fib; 874250963Sachim u_int32_t bellbits, bellbits_shifted, index, handle; 875250963Sachim int isFastResponse, isAif, noMoreAif; 876250963Sachim 877250963Sachim sc = (struct aac_softc *)arg; 878250963Sachim 879250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 880250963Sachim mtx_lock(&sc->aac_io_lock); 881250963Sachim bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); 882250963Sachim if (bellbits & AAC_DB_RESPONSE_SENT_NS) { 883250963Sachim bellbits = AAC_DB_RESPONSE_SENT_NS; 884250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 885250963Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); /* ODR readback,Prep #238630 */ 886250963Sachim /* handle async. status */ 887250963Sachim index = sc->aac_host_rrq_idx; 888250963Sachim for (;;) { 889250963Sachim isFastResponse = isAif = noMoreAif = 0; 890250963Sachim /* remove toggle bit (31) */ 891250963Sachim handle = (sc->aac_common->ac_host_rrq[index] & 0x7fffffff); 892250963Sachim /* check fast response bit (30) */ 893250963Sachim if (handle & 0x40000000) 894250963Sachim isFastResponse = 1; 895250963Sachim /* check AIF bit (23) */ 896250963Sachim else if (handle & 0x00800000) 897250963Sachim isAif = TRUE; 898250963Sachim handle &= 0x0000ffff; 899250963Sachim if (handle == 0) 900250963Sachim break; 901250963Sachim 902250963Sachim cm = sc->aac_commands + (handle - 1); 903250963Sachim fib = cm->cm_fib; 904250963Sachim if (isAif) { 905250963Sachim noMoreAif = (fib->Header.XferState & AAC_FIBSTATE_NOMOREAIF) ? 1:0; 906250963Sachim if (!noMoreAif) 907250963Sachim aac_handle_aif(sc, fib); 908250963Sachim aac_remove_busy(cm); 909250963Sachim aacraid_release_command(cm); 910250963Sachim } else { 911250963Sachim if (isFastResponse) { 912250963Sachim fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 913250963Sachim *((u_int32_t *)(fib->data)) = ST_OK; 914250963Sachim cm->cm_flags |= AAC_CMD_FASTRESP; 915250963Sachim } 916250963Sachim aac_remove_busy(cm); 917250963Sachim aac_unmap_command(cm); 918250963Sachim cm->cm_flags |= AAC_CMD_COMPLETED; 919250963Sachim 920250963Sachim /* is there a completion handler? */ 921250963Sachim if (cm->cm_complete != NULL) { 922250963Sachim cm->cm_complete(cm); 923250963Sachim } else { 924250963Sachim /* assume that someone is sleeping on this command */ 925250963Sachim wakeup(cm); 926250963Sachim } 927250963Sachim sc->flags &= ~AAC_QUEUE_FRZN; 928250963Sachim } 929250963Sachim 930250963Sachim sc->aac_common->ac_host_rrq[index++] = 0; 931250963Sachim if (index == sc->aac_max_fibs) 932250963Sachim index = 0; 933250963Sachim sc->aac_host_rrq_idx = index; 934250963Sachim 935250963Sachim if ((isAif && !noMoreAif) || sc->aif_pending) 936250963Sachim aac_request_aif(sc); 937250963Sachim } 938250963Sachim } else { 939250963Sachim bellbits_shifted = (bellbits >> AAC_SRC_ODR_SHIFT); 940250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 941250963Sachim if (bellbits_shifted & AAC_DB_AIF_PENDING) { 942250963Sachim /* handle AIF */ 943250963Sachim aac_request_aif(sc); 944250963Sachim } else if (bellbits_shifted & AAC_DB_SYNC_COMMAND) { 945250963Sachim if (sc->aac_sync_cm) { 946250963Sachim cm = sc->aac_sync_cm; 947250963Sachim cm->cm_flags |= AAC_CMD_COMPLETED; 948250963Sachim /* is there a completion handler? */ 949250963Sachim if (cm->cm_complete != NULL) { 950250963Sachim cm->cm_complete(cm); 951250963Sachim } else { 952250963Sachim /* assume that someone is sleeping on this command */ 953250963Sachim wakeup(cm); 954250963Sachim } 955250963Sachim sc->flags &= ~AAC_QUEUE_FRZN; 956250963Sachim sc->aac_sync_cm = NULL; 957250963Sachim } 958250963Sachim } 959250963Sachim } 960250963Sachim 961250963Sachim /* see if we can start some more I/O */ 962250963Sachim if ((sc->flags & AAC_QUEUE_FRZN) == 0) 963250963Sachim aacraid_startio(sc); 964250963Sachim mtx_unlock(&sc->aac_io_lock); 965250963Sachim} 966250963Sachim 967250963Sachim/* 968250963Sachim * Handle notification of one or more FIBs coming from the controller. 969250963Sachim */ 970250963Sachimstatic void 971250963Sachimaac_command_thread(struct aac_softc *sc) 972250963Sachim{ 973250963Sachim int retval; 974250963Sachim 975250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 976250963Sachim 977250963Sachim mtx_lock(&sc->aac_io_lock); 978250963Sachim sc->aifflags = AAC_AIFFLAGS_RUNNING; 979250963Sachim 980250963Sachim while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 981250963Sachim 982250963Sachim retval = 0; 983250963Sachim if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 984250963Sachim retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 985250963Sachim "aacraid_aifthd", AAC_PERIODIC_INTERVAL * hz); 986250963Sachim 987250963Sachim /* 988250963Sachim * First see if any FIBs need to be allocated. This needs 989250963Sachim * to be called without the driver lock because contigmalloc 990250963Sachim * will grab Giant, and would result in an LOR. 991250963Sachim */ 992250963Sachim if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 993250963Sachim aac_alloc_commands(sc); 994250963Sachim sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 995250963Sachim aacraid_startio(sc); 996250963Sachim } 997250963Sachim 998250963Sachim /* 999250963Sachim * While we're here, check to see if any commands are stuck. 1000250963Sachim * This is pretty low-priority, so it's ok if it doesn't 1001250963Sachim * always fire. 1002250963Sachim */ 1003250963Sachim if (retval == EWOULDBLOCK) 1004250963Sachim aac_timeout(sc); 1005250963Sachim 1006250963Sachim /* Check the hardware printf message buffer */ 1007250963Sachim if (sc->aac_common->ac_printf[0] != 0) 1008250963Sachim aac_print_printf(sc); 1009250963Sachim } 1010250963Sachim sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1011250963Sachim mtx_unlock(&sc->aac_io_lock); 1012250963Sachim wakeup(sc->aac_dev); 1013250963Sachim 1014250963Sachim aac_kthread_exit(0); 1015250963Sachim} 1016250963Sachim 1017250963Sachim/* 1018250963Sachim * Submit a command to the controller, return when it completes. 1019250963Sachim * XXX This is very dangerous! If the card has gone out to lunch, we could 1020250963Sachim * be stuck here forever. At the same time, signals are not caught 1021250963Sachim * because there is a risk that a signal could wakeup the sleep before 1022250963Sachim * the card has a chance to complete the command. Since there is no way 1023250963Sachim * to cancel a command that is in progress, we can't protect against the 1024250963Sachim * card completing a command late and spamming the command and data 1025250963Sachim * memory. So, we are held hostage until the command completes. 1026250963Sachim */ 1027250963Sachimint 1028250963Sachimaacraid_wait_command(struct aac_command *cm) 1029250963Sachim{ 1030250963Sachim struct aac_softc *sc; 1031250963Sachim int error; 1032250963Sachim 1033250963Sachim sc = cm->cm_sc; 1034250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1035250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1036250963Sachim 1037250963Sachim /* Put the command on the ready queue and get things going */ 1038250963Sachim aac_enqueue_ready(cm); 1039250963Sachim aacraid_startio(sc); 1040250963Sachim error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacraid_wait", 0); 1041250963Sachim return(error); 1042250963Sachim} 1043250963Sachim 1044250963Sachim/* 1045250963Sachim *Command Buffer Management 1046250963Sachim */ 1047250963Sachim 1048250963Sachim/* 1049250963Sachim * Allocate a command. 1050250963Sachim */ 1051250963Sachimint 1052250963Sachimaacraid_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1053250963Sachim{ 1054250963Sachim struct aac_command *cm; 1055250963Sachim 1056250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1057250963Sachim 1058250963Sachim if ((cm = aac_dequeue_free(sc)) == NULL) { 1059250963Sachim if (sc->total_fibs < sc->aac_max_fibs) { 1060250963Sachim sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1061250963Sachim wakeup(sc->aifthread); 1062250963Sachim } 1063250963Sachim return (EBUSY); 1064250963Sachim } 1065250963Sachim 1066250963Sachim *cmp = cm; 1067250963Sachim return(0); 1068250963Sachim} 1069250963Sachim 1070250963Sachim/* 1071250963Sachim * Release a command back to the freelist. 1072250963Sachim */ 1073250963Sachimvoid 1074250963Sachimaacraid_release_command(struct aac_command *cm) 1075250963Sachim{ 1076250963Sachim struct aac_event *event; 1077250963Sachim struct aac_softc *sc; 1078250963Sachim 1079250963Sachim sc = cm->cm_sc; 1080250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1081250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1082250963Sachim 1083250963Sachim /* (re)initialize the command/FIB */ 1084250963Sachim cm->cm_sgtable = NULL; 1085250963Sachim cm->cm_flags = 0; 1086250963Sachim cm->cm_complete = NULL; 1087250963Sachim cm->cm_ccb = NULL; 1088250963Sachim cm->cm_passthr_dmat = 0; 1089250963Sachim cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1090250963Sachim cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1091250963Sachim cm->cm_fib->Header.Unused = 0; 1092250963Sachim cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 1093250963Sachim 1094250963Sachim /* 1095250963Sachim * These are duplicated in aac_start to cover the case where an 1096250963Sachim * intermediate stage may have destroyed them. They're left 1097250963Sachim * initialized here for debugging purposes only. 1098250963Sachim */ 1099250963Sachim cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1100250963Sachim cm->cm_fib->Header.Handle = 0; 1101250963Sachim 1102250963Sachim aac_enqueue_free(cm); 1103250963Sachim 1104250963Sachim /* 1105250963Sachim * Dequeue all events so that there's no risk of events getting 1106250963Sachim * stranded. 1107250963Sachim */ 1108250963Sachim while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 1109250963Sachim TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1110250963Sachim event->ev_callback(sc, event, event->ev_arg); 1111250963Sachim } 1112250963Sachim} 1113250963Sachim 1114250963Sachim/* 1115250963Sachim * Map helper for command/FIB allocation. 1116250963Sachim */ 1117250963Sachimstatic void 1118250963Sachimaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1119250963Sachim{ 1120250963Sachim uint64_t *fibphys; 1121250963Sachim 1122250963Sachim fibphys = (uint64_t *)arg; 1123250963Sachim 1124250963Sachim *fibphys = segs[0].ds_addr; 1125250963Sachim} 1126250963Sachim 1127250963Sachim/* 1128250963Sachim * Allocate and initialize commands/FIBs for this adapter. 1129250963Sachim */ 1130250963Sachimstatic int 1131250963Sachimaac_alloc_commands(struct aac_softc *sc) 1132250963Sachim{ 1133250963Sachim struct aac_command *cm; 1134250963Sachim struct aac_fibmap *fm; 1135250963Sachim uint64_t fibphys; 1136250963Sachim int i, error; 1137250963Sachim u_int32_t maxsize; 1138250963Sachim 1139250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1140250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1141250963Sachim 1142250963Sachim if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1143250963Sachim return (ENOMEM); 1144250963Sachim 1145250963Sachim fm = malloc(sizeof(struct aac_fibmap), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1146250963Sachim if (fm == NULL) 1147250963Sachim return (ENOMEM); 1148250963Sachim 1149250963Sachim mtx_unlock(&sc->aac_io_lock); 1150250963Sachim /* allocate the FIBs in DMAable memory and load them */ 1151250963Sachim if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1152250963Sachim BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1153250963Sachim device_printf(sc->aac_dev, 1154250963Sachim "Not enough contiguous memory available.\n"); 1155250963Sachim free(fm, M_AACRAIDBUF); 1156250963Sachim mtx_lock(&sc->aac_io_lock); 1157250963Sachim return (ENOMEM); 1158250963Sachim } 1159250963Sachim 1160250963Sachim maxsize = sc->aac_max_fib_size + 31; 1161250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1162250963Sachim maxsize += sizeof(struct aac_fib_xporthdr); 1163250963Sachim /* Ignore errors since this doesn't bounce */ 1164250963Sachim (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1165250963Sachim sc->aac_max_fibs_alloc * maxsize, 1166250963Sachim aac_map_command_helper, &fibphys, 0); 1167250963Sachim mtx_lock(&sc->aac_io_lock); 1168250963Sachim 1169250963Sachim /* initialize constant fields in the command structure */ 1170250963Sachim bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * maxsize); 1171250963Sachim for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1172250963Sachim cm = sc->aac_commands + sc->total_fibs; 1173250963Sachim fm->aac_commands = cm; 1174250963Sachim cm->cm_sc = sc; 1175250963Sachim cm->cm_fib = (struct aac_fib *) 1176250963Sachim ((u_int8_t *)fm->aac_fibs + i * maxsize); 1177250963Sachim cm->cm_fibphys = fibphys + i * maxsize; 1178250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1179250963Sachim u_int64_t fibphys_aligned; 1180250963Sachim fibphys_aligned = 1181250963Sachim (cm->cm_fibphys + sizeof(struct aac_fib_xporthdr) + 31) & ~31; 1182250963Sachim cm->cm_fib = (struct aac_fib *) 1183250963Sachim ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1184250963Sachim cm->cm_fibphys = fibphys_aligned; 1185250963Sachim } else { 1186250963Sachim u_int64_t fibphys_aligned; 1187250963Sachim fibphys_aligned = (cm->cm_fibphys + 31) & ~31; 1188250963Sachim cm->cm_fib = (struct aac_fib *) 1189250963Sachim ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1190250963Sachim cm->cm_fibphys = fibphys_aligned; 1191250963Sachim } 1192250963Sachim cm->cm_index = sc->total_fibs; 1193250963Sachim 1194250963Sachim if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1195250963Sachim &cm->cm_datamap)) != 0) 1196250963Sachim break; 1197250963Sachim if (sc->aac_max_fibs <= 1 || sc->aac_max_fibs - sc->total_fibs > 1) 1198250963Sachim aacraid_release_command(cm); 1199250963Sachim sc->total_fibs++; 1200250963Sachim } 1201250963Sachim 1202250963Sachim if (i > 0) { 1203250963Sachim TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1204250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1205250963Sachim return (0); 1206250963Sachim } 1207250963Sachim 1208250963Sachim bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1209250963Sachim bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1210250963Sachim free(fm, M_AACRAIDBUF); 1211250963Sachim return (ENOMEM); 1212250963Sachim} 1213250963Sachim 1214250963Sachim/* 1215250963Sachim * Free FIBs owned by this adapter. 1216250963Sachim */ 1217250963Sachimstatic void 1218250963Sachimaac_free_commands(struct aac_softc *sc) 1219250963Sachim{ 1220250963Sachim struct aac_fibmap *fm; 1221250963Sachim struct aac_command *cm; 1222250963Sachim int i; 1223250963Sachim 1224250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1225250963Sachim 1226250963Sachim while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1227250963Sachim 1228250963Sachim TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1229250963Sachim /* 1230250963Sachim * We check against total_fibs to handle partially 1231250963Sachim * allocated blocks. 1232250963Sachim */ 1233250963Sachim for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1234250963Sachim cm = fm->aac_commands + i; 1235250963Sachim bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1236250963Sachim } 1237250963Sachim bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1238250963Sachim bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1239250963Sachim free(fm, M_AACRAIDBUF); 1240250963Sachim } 1241250963Sachim} 1242250963Sachim 1243250963Sachim/* 1244250963Sachim * Command-mapping helper function - populate this command's s/g table. 1245250963Sachim */ 1246250963Sachimvoid 1247250963Sachimaacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1248250963Sachim{ 1249250963Sachim struct aac_softc *sc; 1250250963Sachim struct aac_command *cm; 1251250963Sachim struct aac_fib *fib; 1252250963Sachim int i; 1253250963Sachim 1254250963Sachim cm = (struct aac_command *)arg; 1255250963Sachim sc = cm->cm_sc; 1256250963Sachim fib = cm->cm_fib; 1257250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "nseg %d", nseg); 1258250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1259250963Sachim 1260250963Sachim /* copy into the FIB */ 1261250963Sachim if (cm->cm_sgtable != NULL) { 1262250963Sachim if (fib->Header.Command == RawIo2) { 1263250963Sachim struct aac_raw_io2 *raw; 1264250963Sachim struct aac_sge_ieee1212 *sg; 1265250963Sachim u_int32_t min_size = PAGE_SIZE, cur_size; 1266250963Sachim int conformable = TRUE; 1267250963Sachim 1268250963Sachim raw = (struct aac_raw_io2 *)&fib->data[0]; 1269250963Sachim sg = (struct aac_sge_ieee1212 *)cm->cm_sgtable; 1270250963Sachim raw->sgeCnt = nseg; 1271250963Sachim 1272250963Sachim for (i = 0; i < nseg; i++) { 1273250963Sachim cur_size = segs[i].ds_len; 1274250963Sachim sg[i].addrHigh = 0; 1275250963Sachim *(bus_addr_t *)&sg[i].addrLow = segs[i].ds_addr; 1276250963Sachim sg[i].length = cur_size; 1277250963Sachim sg[i].flags = 0; 1278250963Sachim if (i == 0) { 1279250963Sachim raw->sgeFirstSize = cur_size; 1280250963Sachim } else if (i == 1) { 1281250963Sachim raw->sgeNominalSize = cur_size; 1282250963Sachim min_size = cur_size; 1283250963Sachim } else if ((i+1) < nseg && 1284250963Sachim cur_size != raw->sgeNominalSize) { 1285250963Sachim conformable = FALSE; 1286250963Sachim if (cur_size < min_size) 1287250963Sachim min_size = cur_size; 1288250963Sachim } 1289250963Sachim } 1290250963Sachim 1291250963Sachim /* not conformable: evaluate required sg elements */ 1292250963Sachim if (!conformable) { 1293250963Sachim int j, err_found, nseg_new = nseg; 1294250963Sachim for (i = min_size / PAGE_SIZE; i >= 1; --i) { 1295250963Sachim err_found = FALSE; 1296250963Sachim nseg_new = 2; 1297250963Sachim for (j = 1; j < nseg - 1; ++j) { 1298250963Sachim if (sg[j].length % (i*PAGE_SIZE)) { 1299250963Sachim err_found = TRUE; 1300250963Sachim break; 1301250963Sachim } 1302250963Sachim nseg_new += (sg[j].length / (i*PAGE_SIZE)); 1303250963Sachim } 1304250963Sachim if (!err_found) 1305250963Sachim break; 1306250963Sachim } 1307250963Sachim if (i>0 && nseg_new<=sc->aac_sg_tablesize && 1308250963Sachim !(sc->hint_flags & 4)) 1309250963Sachim nseg = aac_convert_sgraw2(sc, 1310250963Sachim raw, i, nseg, nseg_new); 1311250963Sachim } else { 1312250963Sachim raw->flags |= RIO2_SGL_CONFORMANT; 1313250963Sachim } 1314250963Sachim 1315250963Sachim /* update the FIB size for the s/g count */ 1316250963Sachim fib->Header.Size += nseg * 1317250963Sachim sizeof(struct aac_sge_ieee1212); 1318250963Sachim 1319250963Sachim } else if (fib->Header.Command == RawIo) { 1320250963Sachim struct aac_sg_tableraw *sg; 1321250963Sachim sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1322250963Sachim sg->SgCount = nseg; 1323250963Sachim for (i = 0; i < nseg; i++) { 1324250963Sachim sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1325250963Sachim sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1326250963Sachim sg->SgEntryRaw[i].Next = 0; 1327250963Sachim sg->SgEntryRaw[i].Prev = 0; 1328250963Sachim sg->SgEntryRaw[i].Flags = 0; 1329250963Sachim } 1330250963Sachim /* update the FIB size for the s/g count */ 1331250963Sachim fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1332250963Sachim } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1333250963Sachim struct aac_sg_table *sg; 1334250963Sachim sg = cm->cm_sgtable; 1335250963Sachim sg->SgCount = nseg; 1336250963Sachim for (i = 0; i < nseg; i++) { 1337250963Sachim sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1338250963Sachim sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1339250963Sachim } 1340250963Sachim /* update the FIB size for the s/g count */ 1341250963Sachim fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1342250963Sachim } else { 1343250963Sachim struct aac_sg_table64 *sg; 1344250963Sachim sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1345250963Sachim sg->SgCount = nseg; 1346250963Sachim for (i = 0; i < nseg; i++) { 1347250963Sachim sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1348250963Sachim sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1349250963Sachim } 1350250963Sachim /* update the FIB size for the s/g count */ 1351250963Sachim fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1352250963Sachim } 1353250963Sachim } 1354250963Sachim 1355250963Sachim /* Fix up the address values in the FIB. Use the command array index 1356250963Sachim * instead of a pointer since these fields are only 32 bits. Shift 1357250963Sachim * the SenderFibAddress over to make room for the fast response bit 1358250963Sachim * and for the AIF bit 1359250963Sachim */ 1360250963Sachim cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1361250963Sachim cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1362250963Sachim 1363250963Sachim /* save a pointer to the command for speedy reverse-lookup */ 1364250963Sachim cm->cm_fib->Header.Handle += cm->cm_index + 1; 1365250963Sachim 1366250963Sachim if (cm->cm_passthr_dmat == 0) { 1367250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 1368250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1369250963Sachim BUS_DMASYNC_PREREAD); 1370250963Sachim if (cm->cm_flags & AAC_CMD_DATAOUT) 1371250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1372250963Sachim BUS_DMASYNC_PREWRITE); 1373250963Sachim } 1374250963Sachim 1375250963Sachim cm->cm_flags |= AAC_CMD_MAPPED; 1376250963Sachim 1377250963Sachim if (sc->flags & AAC_FLAGS_SYNC_MODE) { 1378250963Sachim u_int32_t wait = 0; 1379250963Sachim aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, &wait, NULL); 1380250963Sachim } else if (cm->cm_flags & AAC_CMD_WAIT) { 1381250963Sachim aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, NULL, NULL); 1382250963Sachim } else { 1383250963Sachim int count = 10000000L; 1384250963Sachim while (AAC_SEND_COMMAND(sc, cm) != 0) { 1385250963Sachim if (--count == 0) { 1386250963Sachim aac_unmap_command(cm); 1387250963Sachim sc->flags |= AAC_QUEUE_FRZN; 1388250963Sachim aac_requeue_ready(cm); 1389250963Sachim } 1390250963Sachim DELAY(5); /* wait 5 usec. */ 1391250963Sachim } 1392250963Sachim } 1393250963Sachim} 1394250963Sachim 1395250963Sachim 1396250963Sachimstatic int 1397250963Sachimaac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 1398250963Sachim int pages, int nseg, int nseg_new) 1399250963Sachim{ 1400250963Sachim struct aac_sge_ieee1212 *sge; 1401250963Sachim int i, j, pos; 1402250963Sachim u_int32_t addr_low; 1403250963Sachim 1404250963Sachim sge = malloc(nseg_new * sizeof(struct aac_sge_ieee1212), 1405250963Sachim M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1406250963Sachim if (sge == NULL) 1407250963Sachim return nseg; 1408250963Sachim 1409250963Sachim for (i = 1, pos = 1; i < nseg - 1; ++i) { 1410250963Sachim for (j = 0; j < raw->sge[i].length / (pages*PAGE_SIZE); ++j) { 1411250963Sachim addr_low = raw->sge[i].addrLow + j * pages * PAGE_SIZE; 1412250963Sachim sge[pos].addrLow = addr_low; 1413250963Sachim sge[pos].addrHigh = raw->sge[i].addrHigh; 1414250963Sachim if (addr_low < raw->sge[i].addrLow) 1415250963Sachim sge[pos].addrHigh++; 1416250963Sachim sge[pos].length = pages * PAGE_SIZE; 1417250963Sachim sge[pos].flags = 0; 1418250963Sachim pos++; 1419250963Sachim } 1420250963Sachim } 1421250963Sachim sge[pos] = raw->sge[nseg-1]; 1422250963Sachim for (i = 1; i < nseg_new; ++i) 1423250963Sachim raw->sge[i] = sge[i]; 1424250963Sachim 1425250963Sachim free(sge, M_AACRAIDBUF); 1426250963Sachim raw->sgeCnt = nseg_new; 1427250963Sachim raw->flags |= RIO2_SGL_CONFORMANT; 1428250963Sachim raw->sgeNominalSize = pages * PAGE_SIZE; 1429250963Sachim return nseg_new; 1430250963Sachim} 1431250963Sachim 1432250963Sachim 1433250963Sachim/* 1434250963Sachim * Unmap a command from controller-visible space. 1435250963Sachim */ 1436250963Sachimstatic void 1437250963Sachimaac_unmap_command(struct aac_command *cm) 1438250963Sachim{ 1439250963Sachim struct aac_softc *sc; 1440250963Sachim 1441250963Sachim sc = cm->cm_sc; 1442250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1443250963Sachim 1444250963Sachim if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1445250963Sachim return; 1446250963Sachim 1447250963Sachim if (cm->cm_datalen != 0 && cm->cm_passthr_dmat == 0) { 1448250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 1449250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1450250963Sachim BUS_DMASYNC_POSTREAD); 1451250963Sachim if (cm->cm_flags & AAC_CMD_DATAOUT) 1452250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1453250963Sachim BUS_DMASYNC_POSTWRITE); 1454250963Sachim 1455250963Sachim bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1456250963Sachim } 1457250963Sachim cm->cm_flags &= ~AAC_CMD_MAPPED; 1458250963Sachim} 1459250963Sachim 1460250963Sachim/* 1461250963Sachim * Hardware Interface 1462250963Sachim */ 1463250963Sachim 1464250963Sachim/* 1465250963Sachim * Initialize the adapter. 1466250963Sachim */ 1467250963Sachimstatic void 1468250963Sachimaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1469250963Sachim{ 1470250963Sachim struct aac_softc *sc; 1471250963Sachim 1472250963Sachim sc = (struct aac_softc *)arg; 1473250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1474250963Sachim 1475250963Sachim sc->aac_common_busaddr = segs[0].ds_addr; 1476250963Sachim} 1477250963Sachim 1478250963Sachimstatic int 1479250963Sachimaac_check_firmware(struct aac_softc *sc) 1480250963Sachim{ 1481250963Sachim u_int32_t code, major, minor, maxsize; 1482250963Sachim u_int32_t options = 0, atu_size = 0, status; 1483250963Sachim time_t then; 1484250963Sachim 1485250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1486250963Sachim /* 1487250963Sachim * Wait for the adapter to come ready. 1488250963Sachim */ 1489250963Sachim then = time_uptime; 1490250963Sachim do { 1491250963Sachim code = AAC_GET_FWSTATUS(sc); 1492250963Sachim if (code & AAC_SELF_TEST_FAILED) { 1493250963Sachim device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 1494250963Sachim return(ENXIO); 1495250963Sachim } 1496250963Sachim if (code & AAC_KERNEL_PANIC) { 1497250963Sachim device_printf(sc->aac_dev, 1498250963Sachim "FATAL: controller kernel panic"); 1499250963Sachim return(ENXIO); 1500250963Sachim } 1501250963Sachim if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1502250963Sachim device_printf(sc->aac_dev, 1503250963Sachim "FATAL: controller not coming ready, " 1504250963Sachim "status %x\n", code); 1505250963Sachim return(ENXIO); 1506250963Sachim } 1507250963Sachim } while (!(code & AAC_UP_AND_RUNNING)); 1508250963Sachim 1509250963Sachim /* 1510250963Sachim * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1511250963Sachim * firmware version 1.x are not compatible with this driver. 1512250963Sachim */ 1513250963Sachim if (sc->flags & AAC_FLAGS_PERC2QC) { 1514250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1515250963Sachim NULL, NULL)) { 1516250963Sachim device_printf(sc->aac_dev, 1517250963Sachim "Error reading firmware version\n"); 1518250963Sachim return (EIO); 1519250963Sachim } 1520250963Sachim 1521250963Sachim /* These numbers are stored as ASCII! */ 1522250963Sachim major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1523250963Sachim minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1524250963Sachim if (major == 1) { 1525250963Sachim device_printf(sc->aac_dev, 1526250963Sachim "Firmware version %d.%d is not supported.\n", 1527250963Sachim major, minor); 1528250963Sachim return (EINVAL); 1529250963Sachim } 1530250963Sachim } 1531250963Sachim /* 1532250963Sachim * Retrieve the capabilities/supported options word so we know what 1533250963Sachim * work-arounds to enable. Some firmware revs don't support this 1534250963Sachim * command. 1535250963Sachim */ 1536250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status, NULL)) { 1537250963Sachim if (status != AAC_SRB_STS_INVALID_REQUEST) { 1538250963Sachim device_printf(sc->aac_dev, 1539250963Sachim "RequestAdapterInfo failed\n"); 1540250963Sachim return (EIO); 1541250963Sachim } 1542250963Sachim } else { 1543250963Sachim options = AAC_GET_MAILBOX(sc, 1); 1544250963Sachim atu_size = AAC_GET_MAILBOX(sc, 2); 1545250963Sachim sc->supported_options = options; 1546250963Sachim 1547250963Sachim if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1548250963Sachim (sc->flags & AAC_FLAGS_NO4GB) == 0) 1549250963Sachim sc->flags |= AAC_FLAGS_4GB_WINDOW; 1550250963Sachim if (options & AAC_SUPPORTED_NONDASD) 1551250963Sachim sc->flags |= AAC_FLAGS_ENABLE_CAM; 1552250963Sachim if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1553250963Sachim && (sizeof(bus_addr_t) > 4) 1554250963Sachim && (sc->hint_flags & 0x1)) { 1555250963Sachim device_printf(sc->aac_dev, 1556250963Sachim "Enabling 64-bit address support\n"); 1557250963Sachim sc->flags |= AAC_FLAGS_SG_64BIT; 1558250963Sachim } 1559250963Sachim if (sc->aac_if.aif_send_command) { 1560250963Sachim if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) || 1561250963Sachim (options & AAC_SUPPORTED_NEW_COMM_TYPE4)) 1562250963Sachim sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34; 1563250963Sachim else if (options & AAC_SUPPORTED_NEW_COMM_TYPE1) 1564250963Sachim sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE1; 1565250963Sachim else if (options & AAC_SUPPORTED_NEW_COMM_TYPE2) 1566250963Sachim sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2; 1567250963Sachim } 1568250963Sachim if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1569250963Sachim sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1570250963Sachim } 1571250963Sachim 1572250963Sachim if (!(sc->flags & AAC_FLAGS_NEW_COMM)) { 1573250963Sachim device_printf(sc->aac_dev, "Communication interface not supported!\n"); 1574250963Sachim return (ENXIO); 1575250963Sachim } 1576250963Sachim 1577250963Sachim if (sc->hint_flags & 2) { 1578250963Sachim device_printf(sc->aac_dev, 1579250963Sachim "Sync. mode enforced by driver parameter. This will cause a significant performance decrease!\n"); 1580250963Sachim sc->flags |= AAC_FLAGS_SYNC_MODE; 1581250963Sachim } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE34) { 1582250963Sachim device_printf(sc->aac_dev, 1583250963Sachim "Async. mode not supported by current driver, sync. mode enforced.\nPlease update driver to get full performance.\n"); 1584250963Sachim sc->flags |= AAC_FLAGS_SYNC_MODE; 1585250963Sachim } 1586250963Sachim 1587250963Sachim /* Check for broken hardware that does a lower number of commands */ 1588250963Sachim sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1589250963Sachim 1590250963Sachim /* Remap mem. resource, if required */ 1591250963Sachim if (atu_size > rman_get_size(sc->aac_regs_res0)) { 1592250963Sachim bus_release_resource( 1593250963Sachim sc->aac_dev, SYS_RES_MEMORY, 1594250963Sachim sc->aac_regs_rid0, sc->aac_regs_res0); 1595250963Sachim sc->aac_regs_res0 = bus_alloc_resource( 1596250963Sachim sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid0, 1597250963Sachim 0ul, ~0ul, atu_size, RF_ACTIVE); 1598250963Sachim if (sc->aac_regs_res0 == NULL) { 1599250963Sachim sc->aac_regs_res0 = bus_alloc_resource_any( 1600250963Sachim sc->aac_dev, SYS_RES_MEMORY, 1601250963Sachim &sc->aac_regs_rid0, RF_ACTIVE); 1602250963Sachim if (sc->aac_regs_res0 == NULL) { 1603250963Sachim device_printf(sc->aac_dev, 1604250963Sachim "couldn't allocate register window\n"); 1605250963Sachim return (ENXIO); 1606250963Sachim } 1607250963Sachim } 1608250963Sachim sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); 1609250963Sachim sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); 1610250963Sachim } 1611250963Sachim 1612250963Sachim /* Read preferred settings */ 1613250963Sachim sc->aac_max_fib_size = sizeof(struct aac_fib); 1614250963Sachim sc->aac_max_sectors = 128; /* 64KB */ 1615250963Sachim sc->aac_max_aif = 1; 1616250963Sachim if (sc->flags & AAC_FLAGS_SG_64BIT) 1617250963Sachim sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1618250963Sachim - sizeof(struct aac_blockwrite64)) 1619250963Sachim / sizeof(struct aac_sg_entry64); 1620250963Sachim else 1621250963Sachim sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1622250963Sachim - sizeof(struct aac_blockwrite)) 1623250963Sachim / sizeof(struct aac_sg_entry); 1624250963Sachim 1625250963Sachim if (!aacraid_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL, NULL)) { 1626250963Sachim options = AAC_GET_MAILBOX(sc, 1); 1627250963Sachim sc->aac_max_fib_size = (options & 0xFFFF); 1628250963Sachim sc->aac_max_sectors = (options >> 16) << 1; 1629250963Sachim options = AAC_GET_MAILBOX(sc, 2); 1630250963Sachim sc->aac_sg_tablesize = (options >> 16); 1631250963Sachim options = AAC_GET_MAILBOX(sc, 3); 1632250963Sachim sc->aac_max_fibs = (options & 0xFFFF); 1633250963Sachim options = AAC_GET_MAILBOX(sc, 4); 1634250963Sachim sc->aac_max_aif = (options & 0xFFFF); 1635250963Sachim } 1636250963Sachim 1637250963Sachim maxsize = sc->aac_max_fib_size + 31; 1638250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1639250963Sachim maxsize += sizeof(struct aac_fib_xporthdr); 1640250963Sachim if (maxsize > PAGE_SIZE) { 1641250963Sachim sc->aac_max_fib_size -= (maxsize - PAGE_SIZE); 1642250963Sachim maxsize = PAGE_SIZE; 1643250963Sachim } 1644250963Sachim sc->aac_max_fibs_alloc = PAGE_SIZE / maxsize; 1645250963Sachim 1646250963Sachim if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1647250963Sachim sc->flags |= AAC_FLAGS_RAW_IO; 1648250963Sachim device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1649250963Sachim } 1650250963Sachim if ((sc->flags & AAC_FLAGS_RAW_IO) && 1651250963Sachim (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1652250963Sachim sc->flags |= AAC_FLAGS_LBA_64BIT; 1653250963Sachim device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1654250963Sachim } 1655250963Sachim 1656250963Sachim aacraid_get_fw_debug_buffer(sc); 1657250963Sachim return (0); 1658250963Sachim} 1659250963Sachim 1660250963Sachimstatic int 1661250963Sachimaac_init(struct aac_softc *sc) 1662250963Sachim{ 1663250963Sachim struct aac_adapter_init *ip; 1664250963Sachim int error; 1665250963Sachim 1666250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1667250963Sachim 1668250963Sachim /* reset rrq index */ 1669250963Sachim sc->aac_host_rrq_idx = 0; 1670250963Sachim 1671250963Sachim /* 1672250963Sachim * Fill in the init structure. This tells the adapter about the 1673250963Sachim * physical location of various important shared data structures. 1674250963Sachim */ 1675250963Sachim ip = &sc->aac_common->ac_init; 1676250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1677250963Sachim if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1678250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1679250963Sachim sc->flags |= AAC_FLAGS_RAW_IO; 1680250963Sachim } 1681250963Sachim ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 1682250963Sachim 1683250963Sachim ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1684250963Sachim offsetof(struct aac_common, ac_fibs); 1685250963Sachim ip->AdapterFibsVirtualAddress = 0; 1686250963Sachim ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1687250963Sachim ip->AdapterFibAlign = sizeof(struct aac_fib); 1688250963Sachim 1689250963Sachim ip->PrintfBufferAddress = sc->aac_common_busaddr + 1690250963Sachim offsetof(struct aac_common, ac_printf); 1691250963Sachim ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1692250963Sachim 1693250963Sachim /* 1694250963Sachim * The adapter assumes that pages are 4K in size, except on some 1695250963Sachim * broken firmware versions that do the page->byte conversion twice, 1696250963Sachim * therefore 'assuming' that this value is in 16MB units (2^24). 1697250963Sachim * Round up since the granularity is so high. 1698250963Sachim */ 1699250963Sachim ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1700250963Sachim if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1701250963Sachim ip->HostPhysMemPages = 1702250963Sachim (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1703250963Sachim } 1704250963Sachim ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 1705250963Sachim 1706250963Sachim ip->InitFlags = AAC_INITFLAGS_NEW_COMM_SUPPORTED; 1707250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1708250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_6; 1709250963Sachim ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | 1710250963Sachim AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1711250963Sachim ip->MiniPortRevision = 0L; 1712250963Sachim device_printf(sc->aac_dev, "New comm. interface type1 enabled\n"); 1713250963Sachim } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 1714250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_7; 1715250963Sachim ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | 1716250963Sachim AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1717250963Sachim device_printf(sc->aac_dev, "New comm. interface type2 enabled\n"); 1718250963Sachim } 1719250963Sachim ip->MaxNumAif = sc->aac_max_aif; 1720250963Sachim ip->HostRRQ_AddrLow = 1721250963Sachim sc->aac_common_busaddr + offsetof(struct aac_common, ac_host_rrq); 1722250963Sachim /* always 32-bit address */ 1723250963Sachim ip->HostRRQ_AddrHigh = 0; 1724250963Sachim 1725250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) { 1726250963Sachim ip->InitFlags |= AAC_INITFLAGS_DRIVER_SUPPORTS_PM; 1727250963Sachim ip->InitFlags |= AAC_INITFLAGS_DRIVER_USES_UTC_TIME; 1728250963Sachim device_printf(sc->aac_dev, "Power Management enabled\n"); 1729250963Sachim } 1730250963Sachim 1731250963Sachim ip->MaxIoCommands = sc->aac_max_fibs; 1732250963Sachim ip->MaxIoSize = sc->aac_max_sectors << 9; 1733250963Sachim ip->MaxFibSize = sc->aac_max_fib_size; 1734250963Sachim 1735250963Sachim /* 1736250963Sachim * Do controller-type-specific initialisation 1737250963Sachim */ 1738250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, ~0); 1739250963Sachim 1740250963Sachim /* 1741250963Sachim * Give the init structure to the controller. 1742250963Sachim */ 1743250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_INITSTRUCT, 1744250963Sachim sc->aac_common_busaddr + 1745250963Sachim offsetof(struct aac_common, ac_init), 0, 0, 0, 1746250963Sachim NULL, NULL)) { 1747250963Sachim device_printf(sc->aac_dev, 1748250963Sachim "error establishing init structure\n"); 1749250963Sachim error = EIO; 1750250963Sachim goto out; 1751250963Sachim } 1752250963Sachim 1753250963Sachim error = 0; 1754250963Sachimout: 1755250963Sachim return(error); 1756250963Sachim} 1757250963Sachim 1758250963Sachimstatic int 1759250963Sachimaac_setup_intr(struct aac_softc *sc) 1760250963Sachim{ 1761250963Sachim sc->aac_irq_rid = 0; 1762250963Sachim if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 1763250963Sachim &sc->aac_irq_rid, 1764250963Sachim RF_SHAREABLE | 1765250963Sachim RF_ACTIVE)) == NULL) { 1766250963Sachim device_printf(sc->aac_dev, "can't allocate interrupt\n"); 1767250963Sachim return (EINVAL); 1768250963Sachim } 1769250963Sachim if (aac_bus_setup_intr(sc->aac_dev, sc->aac_irq, 1770250963Sachim INTR_MPSAFE|INTR_TYPE_BIO, NULL, 1771250963Sachim aacraid_new_intr_type1, sc, &sc->aac_intr)) { 1772250963Sachim device_printf(sc->aac_dev, "can't set up interrupt\n"); 1773250963Sachim return (EINVAL); 1774250963Sachim } 1775250963Sachim return (0); 1776250963Sachim} 1777250963Sachim 1778250963Sachim/* 1779250963Sachim * Send a synchronous command to the controller and wait for a result. 1780250963Sachim * Indicate if the controller completed the command with an error status. 1781250963Sachim */ 1782250963Sachimint 1783250963Sachimaacraid_sync_command(struct aac_softc *sc, u_int32_t command, 1784250963Sachim u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 1785250963Sachim u_int32_t *sp, u_int32_t *r1) 1786250963Sachim{ 1787250963Sachim time_t then; 1788250963Sachim u_int32_t status; 1789250963Sachim 1790250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1791250963Sachim 1792250963Sachim /* populate the mailbox */ 1793250963Sachim AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 1794250963Sachim 1795250963Sachim /* ensure the sync command doorbell flag is cleared */ 1796250963Sachim AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1797250963Sachim 1798250963Sachim /* then set it to signal the adapter */ 1799250963Sachim AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 1800250963Sachim 1801250963Sachim if ((command != AAC_MONKER_SYNCFIB) || (sp == NULL) || (*sp != 0)) { 1802250963Sachim /* spin waiting for the command to complete */ 1803250963Sachim then = time_uptime; 1804250963Sachim do { 1805250963Sachim if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 1806250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 1807250963Sachim return(EIO); 1808250963Sachim } 1809250963Sachim } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 1810250963Sachim 1811250963Sachim /* clear the completion flag */ 1812250963Sachim AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1813250963Sachim 1814250963Sachim /* get the command status */ 1815250963Sachim status = AAC_GET_MAILBOX(sc, 0); 1816250963Sachim if (sp != NULL) 1817250963Sachim *sp = status; 1818250963Sachim 1819250963Sachim /* return parameter */ 1820250963Sachim if (r1 != NULL) 1821250963Sachim *r1 = AAC_GET_MAILBOX(sc, 1); 1822250963Sachim 1823250963Sachim if (status != AAC_SRB_STS_SUCCESS) 1824250963Sachim return (-1); 1825250963Sachim } 1826250963Sachim return(0); 1827250963Sachim} 1828250963Sachim 1829250963Sachimstatic int 1830250963Sachimaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1831250963Sachim struct aac_fib *fib, u_int16_t datasize) 1832250963Sachim{ 1833250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1834250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1835250963Sachim 1836250963Sachim if (datasize > AAC_FIB_DATASIZE) 1837250963Sachim return(EINVAL); 1838250963Sachim 1839250963Sachim /* 1840250963Sachim * Set up the sync FIB 1841250963Sachim */ 1842250963Sachim fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1843250963Sachim AAC_FIBSTATE_INITIALISED | 1844250963Sachim AAC_FIBSTATE_EMPTY; 1845250963Sachim fib->Header.XferState |= xferstate; 1846250963Sachim fib->Header.Command = command; 1847250963Sachim fib->Header.StructType = AAC_FIBTYPE_TFIB; 1848250963Sachim fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 1849250963Sachim fib->Header.SenderSize = sizeof(struct aac_fib); 1850250963Sachim fib->Header.SenderFibAddress = 0; /* Not needed */ 1851250963Sachim fib->Header.u.ReceiverFibAddress = sc->aac_common_busaddr + 1852250963Sachim offsetof(struct aac_common, 1853250963Sachim ac_sync_fib); 1854250963Sachim 1855250963Sachim /* 1856250963Sachim * Give the FIB to the controller, wait for a response. 1857250963Sachim */ 1858250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, 1859250963Sachim fib->Header.u.ReceiverFibAddress, 0, 0, 0, NULL, NULL)) { 1860250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 1861250963Sachim return(EIO); 1862250963Sachim } 1863250963Sachim 1864250963Sachim return (0); 1865250963Sachim} 1866250963Sachim 1867250963Sachim/* 1868250963Sachim * Check for commands that have been outstanding for a suspiciously long time, 1869250963Sachim * and complain about them. 1870250963Sachim */ 1871250963Sachimstatic void 1872250963Sachimaac_timeout(struct aac_softc *sc) 1873250963Sachim{ 1874250963Sachim struct aac_command *cm; 1875250963Sachim time_t deadline; 1876250963Sachim int timedout, code; 1877250963Sachim 1878250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1879250963Sachim /* 1880250963Sachim * Traverse the busy command list, bitch about late commands once 1881250963Sachim * only. 1882250963Sachim */ 1883250963Sachim timedout = 0; 1884250963Sachim deadline = time_uptime - AAC_CMD_TIMEOUT; 1885250963Sachim TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1886250963Sachim if ((cm->cm_timestamp < deadline) 1887250963Sachim /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 1888250963Sachim cm->cm_flags |= AAC_CMD_TIMEDOUT; 1889250963Sachim device_printf(sc->aac_dev, 1890250963Sachim "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1891250963Sachim cm, (int)(time_uptime-cm->cm_timestamp)); 1892250963Sachim AAC_PRINT_FIB(sc, cm->cm_fib); 1893250963Sachim timedout++; 1894250963Sachim } 1895250963Sachim } 1896250963Sachim 1897250963Sachim if (timedout) { 1898250963Sachim code = AAC_GET_FWSTATUS(sc); 1899250963Sachim if (code != AAC_UP_AND_RUNNING) { 1900250963Sachim device_printf(sc->aac_dev, "WARNING! Controller is no " 1901250963Sachim "longer running! code= 0x%x\n", code); 1902250963Sachim aac_reset_adapter(sc); 1903250963Sachim } 1904250963Sachim } 1905250963Sachim aacraid_print_queues(sc); 1906250963Sachim} 1907250963Sachim 1908250963Sachim/* 1909250963Sachim * Interface Function Vectors 1910250963Sachim */ 1911250963Sachim 1912250963Sachim/* 1913250963Sachim * Read the current firmware status word. 1914250963Sachim */ 1915250963Sachimstatic int 1916250963Sachimaac_src_get_fwstatus(struct aac_softc *sc) 1917250963Sachim{ 1918250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1919250963Sachim 1920250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRC_OMR)); 1921250963Sachim} 1922250963Sachim 1923250963Sachim/* 1924250963Sachim * Notify the controller of a change in a given queue 1925250963Sachim */ 1926250963Sachimstatic void 1927250963Sachimaac_src_qnotify(struct aac_softc *sc, int qbit) 1928250963Sachim{ 1929250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1930250963Sachim 1931250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, qbit << AAC_SRC_IDR_SHIFT); 1932250963Sachim} 1933250963Sachim 1934250963Sachim/* 1935250963Sachim * Get the interrupt reason bits 1936250963Sachim */ 1937250963Sachimstatic int 1938250963Sachimaac_src_get_istatus(struct aac_softc *sc) 1939250963Sachim{ 1940250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1941250963Sachim 1942250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R) >> AAC_SRC_ODR_SHIFT); 1943250963Sachim} 1944250963Sachim 1945250963Sachim/* 1946250963Sachim * Clear some interrupt reason bits 1947250963Sachim */ 1948250963Sachimstatic void 1949250963Sachimaac_src_clear_istatus(struct aac_softc *sc, int mask) 1950250963Sachim{ 1951250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1952250963Sachim 1953250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, mask << AAC_SRC_ODR_SHIFT); 1954250963Sachim} 1955250963Sachim 1956250963Sachim/* 1957250963Sachim * Populate the mailbox and set the command word 1958250963Sachim */ 1959250963Sachimstatic void 1960250963Sachimaac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 1961250963Sachim u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1962250963Sachim{ 1963250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1964250963Sachim 1965250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX, command); 1966250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 4, arg0); 1967250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 8, arg1); 1968250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 12, arg2); 1969250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 16, arg3); 1970250963Sachim} 1971250963Sachim 1972250963Sachimstatic void 1973250963Sachimaac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 1974250963Sachim u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1975250963Sachim{ 1976250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1977250963Sachim 1978250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX, command); 1979250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 4, arg0); 1980250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 8, arg1); 1981250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 12, arg2); 1982250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 16, arg3); 1983250963Sachim} 1984250963Sachim 1985250963Sachim/* 1986250963Sachim * Fetch the immediate command status word 1987250963Sachim */ 1988250963Sachimstatic int 1989250963Sachimaac_src_get_mailbox(struct aac_softc *sc, int mb) 1990250963Sachim{ 1991250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1992250963Sachim 1993250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRC_MAILBOX + (mb * 4))); 1994250963Sachim} 1995250963Sachim 1996250963Sachimstatic int 1997250963Sachimaac_srcv_get_mailbox(struct aac_softc *sc, int mb) 1998250963Sachim{ 1999250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2000250963Sachim 2001250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRCV_MAILBOX + (mb * 4))); 2002250963Sachim} 2003250963Sachim 2004250963Sachim/* 2005250963Sachim * Set/clear interrupt masks 2006250963Sachim */ 2007250963Sachimstatic void 2008250963Sachimaac_src_set_interrupts(struct aac_softc *sc, int enable) 2009250963Sachim{ 2010250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2011250963Sachim 2012250963Sachim if (enable) { 2013250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, ~AAC_DB_INT_NEW_COMM_TYPE1); 2014250963Sachim } else { 2015250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, ~0); 2016250963Sachim } 2017250963Sachim} 2018250963Sachim 2019250963Sachim/* 2020250963Sachim * New comm. interface: Send command functions 2021250963Sachim */ 2022250963Sachimstatic int 2023250963Sachimaac_src_send_command(struct aac_softc *sc, struct aac_command *cm) 2024250963Sachim{ 2025250963Sachim struct aac_fib_xporthdr *pFibX; 2026250963Sachim u_int32_t fibsize, high_addr; 2027250963Sachim u_int64_t address; 2028250963Sachim 2029250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm. type1)"); 2030250963Sachim 2031250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 2032250963Sachim /* Calculate the amount to the fibsize bits */ 2033250963Sachim fibsize = (cm->cm_fib->Header.Size + 127) / 128 - 1; 2034250963Sachim /* Fill new FIB header */ 2035250963Sachim address = cm->cm_fibphys; 2036250963Sachim high_addr = (u_int32_t)(address >> 32); 2037250963Sachim if (high_addr == 0L) { 2038250963Sachim cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2; 2039250963Sachim cm->cm_fib->Header.u.TimeStamp = 0L; 2040250963Sachim } else { 2041250963Sachim cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2_64; 2042250963Sachim cm->cm_fib->Header.u.SenderFibAddressHigh = high_addr; 2043250963Sachim } 2044250963Sachim cm->cm_fib->Header.SenderFibAddress = (u_int32_t)address; 2045250963Sachim } else { 2046250963Sachim /* Calculate the amount to the fibsize bits */ 2047250963Sachim fibsize = (sizeof(struct aac_fib_xporthdr) + 2048250963Sachim cm->cm_fib->Header.Size + 127) / 128 - 1; 2049250963Sachim /* Fill XPORT header */ 2050250963Sachim pFibX = (struct aac_fib_xporthdr *) 2051250963Sachim ((unsigned char *)cm->cm_fib - sizeof(struct aac_fib_xporthdr)); 2052250963Sachim pFibX->Handle = cm->cm_fib->Header.Handle; 2053250963Sachim pFibX->HostAddress = cm->cm_fibphys; 2054250963Sachim pFibX->Size = cm->cm_fib->Header.Size; 2055250963Sachim address = cm->cm_fibphys - sizeof(struct aac_fib_xporthdr); 2056250963Sachim high_addr = (u_int32_t)(address >> 32); 2057250963Sachim } 2058250963Sachim 2059250963Sachim if (fibsize > 31) 2060250963Sachim fibsize = 31; 2061250963Sachim aac_enqueue_busy(cm); 2062250963Sachim if (high_addr) { 2063250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_H, high_addr); 2064250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_L, (u_int32_t)address + fibsize); 2065250963Sachim } else { 2066250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE32, (u_int32_t)address + fibsize); 2067250963Sachim } 2068250963Sachim return 0; 2069250963Sachim} 2070250963Sachim 2071250963Sachim/* 2072250963Sachim * New comm. interface: get, set outbound queue index 2073250963Sachim */ 2074250963Sachimstatic int 2075250963Sachimaac_src_get_outb_queue(struct aac_softc *sc) 2076250963Sachim{ 2077250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2078250963Sachim 2079250963Sachim return(-1); 2080250963Sachim} 2081250963Sachim 2082250963Sachimstatic void 2083250963Sachimaac_src_set_outb_queue(struct aac_softc *sc, int index) 2084250963Sachim{ 2085250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2086250963Sachim} 2087250963Sachim 2088250963Sachim/* 2089250963Sachim * Debugging and Diagnostics 2090250963Sachim */ 2091250963Sachim 2092250963Sachim/* 2093250963Sachim * Print some information about the controller. 2094250963Sachim */ 2095250963Sachimstatic void 2096250963Sachimaac_describe_controller(struct aac_softc *sc) 2097250963Sachim{ 2098250963Sachim struct aac_fib *fib; 2099250963Sachim struct aac_adapter_info *info; 2100250963Sachim char *adapter_type = "Adaptec RAID controller"; 2101250963Sachim 2102250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2103250963Sachim 2104250963Sachim mtx_lock(&sc->aac_io_lock); 2105250963Sachim aac_alloc_sync_fib(sc, &fib); 2106250963Sachim 2107250963Sachim if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 2108250963Sachim fib->data[0] = 0; 2109250963Sachim if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 2110250963Sachim device_printf(sc->aac_dev, "RequestSupplementAdapterInfo failed\n"); 2111250963Sachim else { 2112250963Sachim struct aac_supplement_adapter_info *supp_info; 2113250963Sachim 2114250963Sachim supp_info = ((struct aac_supplement_adapter_info *)&fib->data[0]); 2115250963Sachim adapter_type = (char *)supp_info->AdapterTypeText; 2116250963Sachim sc->aac_feature_bits = supp_info->FeatureBits; 2117250963Sachim sc->aac_support_opt2 = supp_info->SupportedOptions2; 2118250963Sachim } 2119250963Sachim } 2120250963Sachim device_printf(sc->aac_dev, "%s, aacraid driver %d.%d.%d-%d\n", 2121250963Sachim adapter_type, 2122250963Sachim AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 2123250963Sachim AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 2124250963Sachim 2125250963Sachim fib->data[0] = 0; 2126250963Sachim if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 2127250963Sachim device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2128250963Sachim aac_release_sync_fib(sc); 2129250963Sachim mtx_unlock(&sc->aac_io_lock); 2130250963Sachim return; 2131250963Sachim } 2132250963Sachim 2133250963Sachim /* save the kernel revision structure for later use */ 2134250963Sachim info = (struct aac_adapter_info *)&fib->data[0]; 2135250963Sachim sc->aac_revision = info->KernelRevision; 2136250963Sachim 2137250963Sachim if (bootverbose) { 2138250963Sachim device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2139250963Sachim "(%dMB cache, %dMB execution), %s\n", 2140250963Sachim aac_describe_code(aac_cpu_variant, info->CpuVariant), 2141250963Sachim info->ClockSpeed, info->TotalMem / (1024 * 1024), 2142250963Sachim info->BufferMem / (1024 * 1024), 2143250963Sachim info->ExecutionMem / (1024 * 1024), 2144250963Sachim aac_describe_code(aac_battery_platform, 2145250963Sachim info->batteryPlatform)); 2146250963Sachim 2147250963Sachim device_printf(sc->aac_dev, 2148250963Sachim "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2149250963Sachim info->KernelRevision.external.comp.major, 2150250963Sachim info->KernelRevision.external.comp.minor, 2151250963Sachim info->KernelRevision.external.comp.dash, 2152250963Sachim info->KernelRevision.buildNumber, 2153250963Sachim (u_int32_t)(info->SerialNumber & 0xffffff)); 2154250963Sachim 2155250963Sachim device_printf(sc->aac_dev, "Supported Options=%b\n", 2156250963Sachim sc->supported_options, 2157250963Sachim "\20" 2158250963Sachim "\1SNAPSHOT" 2159250963Sachim "\2CLUSTERS" 2160250963Sachim "\3WCACHE" 2161250963Sachim "\4DATA64" 2162250963Sachim "\5HOSTTIME" 2163250963Sachim "\6RAID50" 2164250963Sachim "\7WINDOW4GB" 2165250963Sachim "\10SCSIUPGD" 2166250963Sachim "\11SOFTERR" 2167250963Sachim "\12NORECOND" 2168250963Sachim "\13SGMAP64" 2169250963Sachim "\14ALARM" 2170250963Sachim "\15NONDASD" 2171250963Sachim "\16SCSIMGT" 2172250963Sachim "\17RAIDSCSI" 2173250963Sachim "\21ADPTINFO" 2174250963Sachim "\22NEWCOMM" 2175250963Sachim "\23ARRAY64BIT" 2176250963Sachim "\24HEATSENSOR"); 2177250963Sachim } 2178250963Sachim 2179250963Sachim aac_release_sync_fib(sc); 2180250963Sachim mtx_unlock(&sc->aac_io_lock); 2181250963Sachim} 2182250963Sachim 2183250963Sachim/* 2184250963Sachim * Look up a text description of a numeric error code and return a pointer to 2185250963Sachim * same. 2186250963Sachim */ 2187250963Sachimstatic char * 2188250963Sachimaac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2189250963Sachim{ 2190250963Sachim int i; 2191250963Sachim 2192250963Sachim for (i = 0; table[i].string != NULL; i++) 2193250963Sachim if (table[i].code == code) 2194250963Sachim return(table[i].string); 2195250963Sachim return(table[i + 1].string); 2196250963Sachim} 2197250963Sachim 2198250963Sachim/* 2199250963Sachim * Management Interface 2200250963Sachim */ 2201250963Sachim 2202250963Sachimstatic int 2203250963Sachimaac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2204250963Sachim{ 2205250963Sachim struct aac_softc *sc; 2206250963Sachim 2207250963Sachim sc = dev->si_drv1; 2208250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2209250963Sachim#if __FreeBSD_version >= 702000 2210250963Sachim device_busy(sc->aac_dev); 2211250963Sachim devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 2212250963Sachim#endif 2213250963Sachim return 0; 2214250963Sachim} 2215250963Sachim 2216250963Sachimstatic int 2217250963Sachimaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2218250963Sachim{ 2219250963Sachim union aac_statrequest *as; 2220250963Sachim struct aac_softc *sc; 2221250963Sachim int error = 0; 2222250963Sachim 2223250963Sachim as = (union aac_statrequest *)arg; 2224250963Sachim sc = dev->si_drv1; 2225250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2226250963Sachim 2227250963Sachim switch (cmd) { 2228250963Sachim case AACIO_STATS: 2229250963Sachim switch (as->as_item) { 2230250963Sachim case AACQ_FREE: 2231250963Sachim case AACQ_READY: 2232250963Sachim case AACQ_BUSY: 2233250963Sachim bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2234250963Sachim sizeof(struct aac_qstat)); 2235250963Sachim break; 2236250963Sachim default: 2237250963Sachim error = ENOENT; 2238250963Sachim break; 2239250963Sachim } 2240250963Sachim break; 2241250963Sachim 2242250963Sachim case FSACTL_SENDFIB: 2243250963Sachim case FSACTL_SEND_LARGE_FIB: 2244250963Sachim arg = *(caddr_t*)arg; 2245250963Sachim case FSACTL_LNX_SENDFIB: 2246250963Sachim case FSACTL_LNX_SEND_LARGE_FIB: 2247250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 2248250963Sachim error = aac_ioctl_sendfib(sc, arg); 2249250963Sachim break; 2250250963Sachim case FSACTL_SEND_RAW_SRB: 2251250963Sachim arg = *(caddr_t*)arg; 2252250963Sachim case FSACTL_LNX_SEND_RAW_SRB: 2253250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2254250963Sachim error = aac_ioctl_send_raw_srb(sc, arg); 2255250963Sachim break; 2256250963Sachim case FSACTL_AIF_THREAD: 2257250963Sachim case FSACTL_LNX_AIF_THREAD: 2258250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 2259250963Sachim error = EINVAL; 2260250963Sachim break; 2261250963Sachim case FSACTL_OPEN_GET_ADAPTER_FIB: 2262250963Sachim arg = *(caddr_t*)arg; 2263250963Sachim case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2264250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2265250963Sachim error = aac_open_aif(sc, arg); 2266250963Sachim break; 2267250963Sachim case FSACTL_GET_NEXT_ADAPTER_FIB: 2268250963Sachim arg = *(caddr_t*)arg; 2269250963Sachim case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2270250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2271250963Sachim error = aac_getnext_aif(sc, arg); 2272250963Sachim break; 2273250963Sachim case FSACTL_CLOSE_GET_ADAPTER_FIB: 2274250963Sachim arg = *(caddr_t*)arg; 2275250963Sachim case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2276250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2277250963Sachim error = aac_close_aif(sc, arg); 2278250963Sachim break; 2279250963Sachim case FSACTL_MINIPORT_REV_CHECK: 2280250963Sachim arg = *(caddr_t*)arg; 2281250963Sachim case FSACTL_LNX_MINIPORT_REV_CHECK: 2282250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2283250963Sachim error = aac_rev_check(sc, arg); 2284250963Sachim break; 2285250963Sachim case FSACTL_QUERY_DISK: 2286250963Sachim arg = *(caddr_t*)arg; 2287250963Sachim case FSACTL_LNX_QUERY_DISK: 2288250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 2289250963Sachim error = aac_query_disk(sc, arg); 2290250963Sachim break; 2291250963Sachim case FSACTL_DELETE_DISK: 2292250963Sachim case FSACTL_LNX_DELETE_DISK: 2293250963Sachim /* 2294250963Sachim * We don't trust the underland to tell us when to delete a 2295250963Sachim * container, rather we rely on an AIF coming from the 2296250963Sachim * controller 2297250963Sachim */ 2298250963Sachim error = 0; 2299250963Sachim break; 2300250963Sachim case FSACTL_GET_PCI_INFO: 2301250963Sachim arg = *(caddr_t*)arg; 2302250963Sachim case FSACTL_LNX_GET_PCI_INFO: 2303250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 2304250963Sachim error = aac_get_pci_info(sc, arg); 2305250963Sachim break; 2306250963Sachim case FSACTL_GET_FEATURES: 2307250963Sachim arg = *(caddr_t*)arg; 2308250963Sachim case FSACTL_LNX_GET_FEATURES: 2309250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 2310250963Sachim error = aac_supported_features(sc, arg); 2311250963Sachim break; 2312250963Sachim default: 2313250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 2314250963Sachim error = EINVAL; 2315250963Sachim break; 2316250963Sachim } 2317250963Sachim return(error); 2318250963Sachim} 2319250963Sachim 2320250963Sachimstatic int 2321250963Sachimaac_poll(struct cdev *dev, int poll_events, struct thread *td) 2322250963Sachim{ 2323250963Sachim struct aac_softc *sc; 2324250963Sachim struct aac_fib_context *ctx; 2325250963Sachim int revents; 2326250963Sachim 2327250963Sachim sc = dev->si_drv1; 2328250963Sachim revents = 0; 2329250963Sachim 2330250963Sachim mtx_lock(&sc->aac_io_lock); 2331250963Sachim if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2332250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2333250963Sachim if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2334250963Sachim revents |= poll_events & (POLLIN | POLLRDNORM); 2335250963Sachim break; 2336250963Sachim } 2337250963Sachim } 2338250963Sachim } 2339250963Sachim mtx_unlock(&sc->aac_io_lock); 2340250963Sachim 2341250963Sachim if (revents == 0) { 2342250963Sachim if (poll_events & (POLLIN | POLLRDNORM)) 2343250963Sachim selrecord(td, &sc->rcv_select); 2344250963Sachim } 2345250963Sachim 2346250963Sachim return (revents); 2347250963Sachim} 2348250963Sachim 2349250963Sachimstatic void 2350250963Sachimaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2351250963Sachim{ 2352250963Sachim 2353250963Sachim switch (event->ev_type) { 2354250963Sachim case AAC_EVENT_CMFREE: 2355250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 2356250963Sachim if (aacraid_alloc_command(sc, (struct aac_command **)arg)) { 2357250963Sachim aacraid_add_event(sc, event); 2358250963Sachim return; 2359250963Sachim } 2360250963Sachim free(event, M_AACRAIDBUF); 2361250963Sachim wakeup(arg); 2362250963Sachim break; 2363250963Sachim default: 2364250963Sachim break; 2365250963Sachim } 2366250963Sachim} 2367250963Sachim 2368250963Sachim/* 2369250963Sachim * Send a FIB supplied from userspace 2370250963Sachim */ 2371250963Sachimstatic int 2372250963Sachimaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 2373250963Sachim{ 2374250963Sachim struct aac_command *cm; 2375250963Sachim int size, error; 2376250963Sachim 2377250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2378250963Sachim 2379250963Sachim cm = NULL; 2380250963Sachim 2381250963Sachim /* 2382250963Sachim * Get a command 2383250963Sachim */ 2384250963Sachim mtx_lock(&sc->aac_io_lock); 2385250963Sachim if (aacraid_alloc_command(sc, &cm)) { 2386250963Sachim struct aac_event *event; 2387250963Sachim 2388250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2389250963Sachim M_NOWAIT | M_ZERO); 2390250963Sachim if (event == NULL) { 2391250963Sachim error = EBUSY; 2392250963Sachim mtx_unlock(&sc->aac_io_lock); 2393250963Sachim goto out; 2394250963Sachim } 2395250963Sachim event->ev_type = AAC_EVENT_CMFREE; 2396250963Sachim event->ev_callback = aac_ioctl_event; 2397250963Sachim event->ev_arg = &cm; 2398250963Sachim aacraid_add_event(sc, event); 2399250963Sachim msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsfib", 0); 2400250963Sachim } 2401250963Sachim mtx_unlock(&sc->aac_io_lock); 2402250963Sachim 2403250963Sachim /* 2404250963Sachim * Fetch the FIB header, then re-copy to get data as well. 2405250963Sachim */ 2406250963Sachim if ((error = copyin(ufib, cm->cm_fib, 2407250963Sachim sizeof(struct aac_fib_header))) != 0) 2408250963Sachim goto out; 2409250963Sachim size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 2410250963Sachim if (size > sc->aac_max_fib_size) { 2411250963Sachim device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2412250963Sachim size, sc->aac_max_fib_size); 2413250963Sachim size = sc->aac_max_fib_size; 2414250963Sachim } 2415250963Sachim if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 2416250963Sachim goto out; 2417250963Sachim cm->cm_fib->Header.Size = size; 2418250963Sachim cm->cm_timestamp = time_uptime; 2419250963Sachim cm->cm_datalen = 0; 2420250963Sachim 2421250963Sachim /* 2422250963Sachim * Pass the FIB to the controller, wait for it to complete. 2423250963Sachim */ 2424250963Sachim mtx_lock(&sc->aac_io_lock); 2425250963Sachim error = aacraid_wait_command(cm); 2426250963Sachim mtx_unlock(&sc->aac_io_lock); 2427250963Sachim if (error != 0) { 2428250963Sachim device_printf(sc->aac_dev, 2429250963Sachim "aacraid_wait_command return %d\n", error); 2430250963Sachim goto out; 2431250963Sachim } 2432250963Sachim 2433250963Sachim /* 2434250963Sachim * Copy the FIB and data back out to the caller. 2435250963Sachim */ 2436250963Sachim size = cm->cm_fib->Header.Size; 2437250963Sachim if (size > sc->aac_max_fib_size) { 2438250963Sachim device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2439250963Sachim size, sc->aac_max_fib_size); 2440250963Sachim size = sc->aac_max_fib_size; 2441250963Sachim } 2442250963Sachim error = copyout(cm->cm_fib, ufib, size); 2443250963Sachim 2444250963Sachimout: 2445250963Sachim if (cm != NULL) { 2446250963Sachim mtx_lock(&sc->aac_io_lock); 2447250963Sachim aacraid_release_command(cm); 2448250963Sachim mtx_unlock(&sc->aac_io_lock); 2449250963Sachim } 2450250963Sachim return(error); 2451250963Sachim} 2452250963Sachim 2453250963Sachim/* 2454250963Sachim * Send a passthrough FIB supplied from userspace 2455250963Sachim */ 2456250963Sachimstatic int 2457250963Sachimaac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 2458250963Sachim{ 2459250963Sachim struct aac_command *cm; 2460250963Sachim struct aac_fib *fib; 2461250963Sachim struct aac_srb *srbcmd; 2462250963Sachim struct aac_srb *user_srb = (struct aac_srb *)arg; 2463250963Sachim void *user_reply; 2464250963Sachim int error, transfer_data = 0; 2465250963Sachim bus_dmamap_t orig_map = 0; 2466250963Sachim u_int32_t fibsize = 0; 2467250963Sachim u_int64_t srb_sg_address; 2468250963Sachim u_int32_t srb_sg_bytecount; 2469250963Sachim 2470250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2471250963Sachim 2472250963Sachim cm = NULL; 2473250963Sachim 2474250963Sachim mtx_lock(&sc->aac_io_lock); 2475250963Sachim if (aacraid_alloc_command(sc, &cm)) { 2476250963Sachim struct aac_event *event; 2477250963Sachim 2478250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2479250963Sachim M_NOWAIT | M_ZERO); 2480250963Sachim if (event == NULL) { 2481250963Sachim error = EBUSY; 2482250963Sachim mtx_unlock(&sc->aac_io_lock); 2483250963Sachim goto out; 2484250963Sachim } 2485250963Sachim event->ev_type = AAC_EVENT_CMFREE; 2486250963Sachim event->ev_callback = aac_ioctl_event; 2487250963Sachim event->ev_arg = &cm; 2488250963Sachim aacraid_add_event(sc, event); 2489250963Sachim msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsraw", 0); 2490250963Sachim } 2491250963Sachim mtx_unlock(&sc->aac_io_lock); 2492250963Sachim 2493250963Sachim cm->cm_data = NULL; 2494250963Sachim /* save original dma map */ 2495250963Sachim orig_map = cm->cm_datamap; 2496250963Sachim 2497250963Sachim fib = cm->cm_fib; 2498250963Sachim srbcmd = (struct aac_srb *)fib->data; 2499250963Sachim if ((error = copyin((void *)&user_srb->data_len, &fibsize, 2500250963Sachim sizeof (u_int32_t)) != 0)) 2501250963Sachim goto out; 2502250963Sachim if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) { 2503250963Sachim error = EINVAL; 2504250963Sachim goto out; 2505250963Sachim } 2506250963Sachim if ((error = copyin((void *)user_srb, srbcmd, fibsize) != 0)) 2507250963Sachim goto out; 2508250963Sachim 2509250963Sachim srbcmd->function = 0; /* SRBF_ExecuteScsi */ 2510250963Sachim srbcmd->retry_limit = 0; /* obsolete */ 2511250963Sachim 2512250963Sachim /* only one sg element from userspace supported */ 2513250963Sachim if (srbcmd->sg_map.SgCount > 1) { 2514250963Sachim error = EINVAL; 2515250963Sachim goto out; 2516250963Sachim } 2517250963Sachim /* check fibsize */ 2518250963Sachim if (fibsize == (sizeof(struct aac_srb) + 2519250963Sachim srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 2520250963Sachim struct aac_sg_entry *sgp = srbcmd->sg_map.SgEntry; 2521250963Sachim srb_sg_bytecount = sgp->SgByteCount; 2522250963Sachim srb_sg_address = (u_int64_t)sgp->SgAddress; 2523250963Sachim } else if (fibsize == (sizeof(struct aac_srb) + 2524250963Sachim srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 2525251013Smarcel#ifdef __LP64__ 2526250963Sachim struct aac_sg_entry64 *sgp = 2527250963Sachim (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 2528250963Sachim srb_sg_bytecount = sgp->SgByteCount; 2529250963Sachim srb_sg_address = sgp->SgAddress; 2530250963Sachim if (srb_sg_address > 0xffffffffull && 2531250963Sachim !(sc->flags & AAC_FLAGS_SG_64BIT)) 2532250963Sachim#endif 2533250963Sachim { 2534250963Sachim error = EINVAL; 2535250963Sachim goto out; 2536250963Sachim } 2537250963Sachim } else { 2538250963Sachim error = EINVAL; 2539250963Sachim goto out; 2540250963Sachim } 2541250963Sachim user_reply = (char *)arg + fibsize; 2542250963Sachim srbcmd->data_len = srb_sg_bytecount; 2543250963Sachim if (srbcmd->sg_map.SgCount == 1) 2544250963Sachim transfer_data = 1; 2545250963Sachim 2546250963Sachim if (transfer_data) { 2547250963Sachim /* 2548250963Sachim * Create DMA tag for the passthr. data buffer and allocate it. 2549250963Sachim */ 2550250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 2551250963Sachim 1, 0, /* algnmnt, boundary */ 2552250963Sachim (sc->flags & AAC_FLAGS_SG_64BIT) ? 2553250963Sachim BUS_SPACE_MAXADDR_32BIT : 2554250963Sachim 0x7fffffff, /* lowaddr */ 2555250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 2556250963Sachim NULL, NULL, /* filter, filterarg */ 2557250963Sachim srb_sg_bytecount, /* size */ 2558250963Sachim sc->aac_sg_tablesize, /* nsegments */ 2559250963Sachim srb_sg_bytecount, /* maxsegsize */ 2560250963Sachim 0, /* flags */ 2561250963Sachim NULL, NULL, /* No locking needed */ 2562250963Sachim &cm->cm_passthr_dmat)) { 2563250963Sachim error = ENOMEM; 2564250963Sachim goto out; 2565250963Sachim } 2566250963Sachim if (bus_dmamem_alloc(cm->cm_passthr_dmat, (void **)&cm->cm_data, 2567250963Sachim BUS_DMA_NOWAIT, &cm->cm_datamap)) { 2568250963Sachim error = ENOMEM; 2569250963Sachim goto out; 2570250963Sachim } 2571250963Sachim /* fill some cm variables */ 2572250963Sachim cm->cm_datalen = srb_sg_bytecount; 2573250963Sachim if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 2574250963Sachim cm->cm_flags |= AAC_CMD_DATAIN; 2575250963Sachim if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) 2576250963Sachim cm->cm_flags |= AAC_CMD_DATAOUT; 2577250963Sachim 2578250963Sachim if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 2579251013Smarcel if ((error = copyin((void *)(uintptr_t)srb_sg_address, 2580250963Sachim cm->cm_data, cm->cm_datalen)) != 0) 2581250963Sachim goto out; 2582250963Sachim /* sync required for bus_dmamem_alloc() alloc. mem.? */ 2583250963Sachim bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2584250963Sachim BUS_DMASYNC_PREWRITE); 2585250963Sachim } 2586250963Sachim } 2587250963Sachim 2588250963Sachim /* build the FIB */ 2589250963Sachim fib->Header.Size = sizeof(struct aac_fib_header) + 2590250963Sachim sizeof(struct aac_srb); 2591250963Sachim fib->Header.XferState = 2592250963Sachim AAC_FIBSTATE_HOSTOWNED | 2593250963Sachim AAC_FIBSTATE_INITIALISED | 2594250963Sachim AAC_FIBSTATE_EMPTY | 2595250963Sachim AAC_FIBSTATE_FROMHOST | 2596250963Sachim AAC_FIBSTATE_REXPECTED | 2597250963Sachim AAC_FIBSTATE_NORM | 2598250963Sachim AAC_FIBSTATE_ASYNC; 2599250963Sachim 2600250963Sachim fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? 2601250963Sachim ScsiPortCommandU64 : ScsiPortCommand; 2602250963Sachim cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 2603250963Sachim 2604250963Sachim /* send command */ 2605250963Sachim if (transfer_data) { 2606250963Sachim bus_dmamap_load(cm->cm_passthr_dmat, 2607250963Sachim cm->cm_datamap, cm->cm_data, 2608250963Sachim cm->cm_datalen, 2609250963Sachim aacraid_map_command_sg, cm, 0); 2610250963Sachim } else { 2611250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 2612250963Sachim } 2613250963Sachim 2614250963Sachim /* wait for completion */ 2615250963Sachim mtx_lock(&sc->aac_io_lock); 2616250963Sachim while (!(cm->cm_flags & AAC_CMD_COMPLETED)) 2617250963Sachim msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsrw2", 0); 2618250963Sachim mtx_unlock(&sc->aac_io_lock); 2619250963Sachim 2620250963Sachim /* copy data */ 2621250963Sachim if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)) { 2622251013Smarcel if ((error = copyout(cm->cm_data, 2623251013Smarcel (void *)(uintptr_t)srb_sg_address, 2624250963Sachim cm->cm_datalen)) != 0) 2625250963Sachim goto out; 2626250963Sachim /* sync required for bus_dmamem_alloc() allocated mem.? */ 2627250963Sachim bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2628250963Sachim BUS_DMASYNC_POSTREAD); 2629250963Sachim } 2630250963Sachim 2631250963Sachim /* status */ 2632250963Sachim error = copyout(fib->data, user_reply, sizeof(struct aac_srb_response)); 2633250963Sachim 2634250963Sachimout: 2635250963Sachim if (cm && cm->cm_data) { 2636250963Sachim if (transfer_data) 2637250963Sachim bus_dmamap_unload(cm->cm_passthr_dmat, cm->cm_datamap); 2638250963Sachim bus_dmamem_free(cm->cm_passthr_dmat, cm->cm_data, cm->cm_datamap); 2639250963Sachim cm->cm_datamap = orig_map; 2640250963Sachim } 2641250963Sachim if (cm && cm->cm_passthr_dmat) 2642250963Sachim bus_dma_tag_destroy(cm->cm_passthr_dmat); 2643250963Sachim if (cm) { 2644250963Sachim mtx_lock(&sc->aac_io_lock); 2645250963Sachim aacraid_release_command(cm); 2646250963Sachim mtx_unlock(&sc->aac_io_lock); 2647250963Sachim } 2648250963Sachim return(error); 2649250963Sachim} 2650250963Sachim 2651250963Sachim/* 2652250963Sachim * Request an AIF from the controller (new comm. type1) 2653250963Sachim */ 2654250963Sachimstatic void 2655250963Sachimaac_request_aif(struct aac_softc *sc) 2656250963Sachim{ 2657250963Sachim struct aac_command *cm; 2658250963Sachim struct aac_fib *fib; 2659250963Sachim 2660250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2661250963Sachim 2662250963Sachim if (aacraid_alloc_command(sc, &cm)) { 2663250963Sachim sc->aif_pending = 1; 2664250963Sachim return; 2665250963Sachim } 2666250963Sachim sc->aif_pending = 0; 2667250963Sachim 2668250963Sachim /* build the FIB */ 2669250963Sachim fib = cm->cm_fib; 2670250963Sachim fib->Header.Size = sizeof(struct aac_fib); 2671250963Sachim fib->Header.XferState = 2672250963Sachim AAC_FIBSTATE_HOSTOWNED | 2673250963Sachim AAC_FIBSTATE_INITIALISED | 2674250963Sachim AAC_FIBSTATE_EMPTY | 2675250963Sachim AAC_FIBSTATE_FROMHOST | 2676250963Sachim AAC_FIBSTATE_REXPECTED | 2677250963Sachim AAC_FIBSTATE_NORM | 2678250963Sachim AAC_FIBSTATE_ASYNC; 2679250963Sachim /* set AIF marker */ 2680250963Sachim fib->Header.Handle = 0x00800000; 2681250963Sachim fib->Header.Command = AifRequest; 2682250963Sachim ((struct aac_aif_command *)fib->data)->command = AifReqEvent; 2683250963Sachim 2684250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 2685250963Sachim} 2686250963Sachim 2687250963Sachim 2688250963Sachim#if __FreeBSD_version >= 702000 2689250963Sachim/* 2690250963Sachim * cdevpriv interface private destructor. 2691250963Sachim */ 2692250963Sachimstatic void 2693250963Sachimaac_cdevpriv_dtor(void *arg) 2694250963Sachim{ 2695250963Sachim struct aac_softc *sc; 2696250963Sachim 2697250963Sachim sc = arg; 2698250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2699250963Sachim mtx_lock(&Giant); 2700250963Sachim device_unbusy(sc->aac_dev); 2701250963Sachim mtx_unlock(&Giant); 2702250963Sachim} 2703250963Sachim#else 2704250963Sachimstatic int 2705250963Sachimaac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2706250963Sachim{ 2707250963Sachim struct aac_softc *sc; 2708250963Sachim 2709250963Sachim sc = dev->si_drv1; 2710250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2711250963Sachim return 0; 2712250963Sachim} 2713250963Sachim#endif 2714250963Sachim 2715250963Sachim/* 2716250963Sachim * Handle an AIF sent to us by the controller; queue it for later reference. 2717250963Sachim * If the queue fills up, then drop the older entries. 2718250963Sachim */ 2719250963Sachimstatic void 2720250963Sachimaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 2721250963Sachim{ 2722250963Sachim struct aac_aif_command *aif; 2723250963Sachim struct aac_container *co, *co_next; 2724250963Sachim struct aac_fib_context *ctx; 2725250963Sachim struct aac_fib *sync_fib; 2726250963Sachim struct aac_mntinforesp mir; 2727250963Sachim int next, current, found; 2728250963Sachim int count = 0, changed = 0, i = 0; 2729250963Sachim u_int32_t channel, uid; 2730250963Sachim 2731250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2732250963Sachim 2733250963Sachim aif = (struct aac_aif_command*)&fib->data[0]; 2734250963Sachim aacraid_print_aif(sc, aif); 2735250963Sachim 2736250963Sachim /* Is it an event that we should care about? */ 2737250963Sachim switch (aif->command) { 2738250963Sachim case AifCmdEventNotify: 2739250963Sachim switch (aif->data.EN.type) { 2740250963Sachim case AifEnAddContainer: 2741250963Sachim case AifEnDeleteContainer: 2742250963Sachim /* 2743250963Sachim * A container was added or deleted, but the message 2744250963Sachim * doesn't tell us anything else! Re-enumerate the 2745250963Sachim * containers and sort things out. 2746250963Sachim */ 2747250963Sachim aac_alloc_sync_fib(sc, &sync_fib); 2748250963Sachim do { 2749250963Sachim /* 2750250963Sachim * Ask the controller for its containers one at 2751250963Sachim * a time. 2752250963Sachim * XXX What if the controller's list changes 2753250963Sachim * midway through this enumaration? 2754250963Sachim * XXX This should be done async. 2755250963Sachim */ 2756250963Sachim if (aac_get_container_info(sc, sync_fib, i, 2757250963Sachim &mir, &uid) != 0) 2758250963Sachim continue; 2759250963Sachim if (i == 0) 2760250963Sachim count = mir.MntRespCount; 2761250963Sachim /* 2762250963Sachim * Check the container against our list. 2763250963Sachim * co->co_found was already set to 0 in a 2764250963Sachim * previous run. 2765250963Sachim */ 2766250963Sachim if ((mir.Status == ST_OK) && 2767250963Sachim (mir.MntTable[0].VolType != CT_NONE)) { 2768250963Sachim found = 0; 2769250963Sachim TAILQ_FOREACH(co, 2770250963Sachim &sc->aac_container_tqh, 2771250963Sachim co_link) { 2772250963Sachim if (co->co_mntobj.ObjectId == 2773250963Sachim mir.MntTable[0].ObjectId) { 2774250963Sachim co->co_found = 1; 2775250963Sachim found = 1; 2776250963Sachim break; 2777250963Sachim } 2778250963Sachim } 2779250963Sachim /* 2780250963Sachim * If the container matched, continue 2781250963Sachim * in the list. 2782250963Sachim */ 2783250963Sachim if (found) { 2784250963Sachim i++; 2785250963Sachim continue; 2786250963Sachim } 2787250963Sachim 2788250963Sachim /* 2789250963Sachim * This is a new container. Do all the 2790250963Sachim * appropriate things to set it up. 2791250963Sachim */ 2792250963Sachim aac_add_container(sc, &mir, 1, uid); 2793250963Sachim changed = 1; 2794250963Sachim } 2795250963Sachim i++; 2796250963Sachim } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 2797250963Sachim aac_release_sync_fib(sc); 2798250963Sachim 2799250963Sachim /* 2800250963Sachim * Go through our list of containers and see which ones 2801250963Sachim * were not marked 'found'. Since the controller didn't 2802250963Sachim * list them they must have been deleted. Do the 2803250963Sachim * appropriate steps to destroy the device. Also reset 2804250963Sachim * the co->co_found field. 2805250963Sachim */ 2806250963Sachim co = TAILQ_FIRST(&sc->aac_container_tqh); 2807250963Sachim while (co != NULL) { 2808250963Sachim if (co->co_found == 0) { 2809250963Sachim co_next = TAILQ_NEXT(co, co_link); 2810250963Sachim TAILQ_REMOVE(&sc->aac_container_tqh, co, 2811250963Sachim co_link); 2812250963Sachim free(co, M_AACRAIDBUF); 2813250963Sachim changed = 1; 2814250963Sachim co = co_next; 2815250963Sachim } else { 2816250963Sachim co->co_found = 0; 2817250963Sachim co = TAILQ_NEXT(co, co_link); 2818250963Sachim } 2819250963Sachim } 2820250963Sachim 2821250963Sachim /* Attach the newly created containers */ 2822250963Sachim if (changed) { 2823250963Sachim if (sc->cam_rescan_cb != NULL) 2824250963Sachim sc->cam_rescan_cb(sc, 0, 2825250963Sachim AAC_CAM_TARGET_WILDCARD); 2826250963Sachim } 2827250963Sachim 2828250963Sachim break; 2829250963Sachim 2830250963Sachim case AifEnEnclosureManagement: 2831250963Sachim switch (aif->data.EN.data.EEE.eventType) { 2832250963Sachim case AIF_EM_DRIVE_INSERTION: 2833250963Sachim case AIF_EM_DRIVE_REMOVAL: 2834250963Sachim channel = aif->data.EN.data.EEE.unitID; 2835250963Sachim if (sc->cam_rescan_cb != NULL) 2836250963Sachim sc->cam_rescan_cb(sc, 2837250963Sachim ((channel>>24) & 0xF) + 1, 2838250963Sachim (channel & 0xFFFF)); 2839250963Sachim break; 2840250963Sachim } 2841250963Sachim break; 2842250963Sachim 2843250963Sachim case AifEnAddJBOD: 2844250963Sachim case AifEnDeleteJBOD: 2845250963Sachim case AifRawDeviceRemove: 2846250963Sachim channel = aif->data.EN.data.ECE.container; 2847250963Sachim if (sc->cam_rescan_cb != NULL) 2848250963Sachim sc->cam_rescan_cb(sc, ((channel>>24) & 0xF) + 1, 2849250963Sachim AAC_CAM_TARGET_WILDCARD); 2850250963Sachim break; 2851250963Sachim 2852250963Sachim default: 2853250963Sachim break; 2854250963Sachim } 2855250963Sachim 2856250963Sachim default: 2857250963Sachim break; 2858250963Sachim } 2859250963Sachim 2860250963Sachim /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2861250963Sachim current = sc->aifq_idx; 2862250963Sachim next = (current + 1) % AAC_AIFQ_LENGTH; 2863250963Sachim if (next == 0) 2864250963Sachim sc->aifq_filled = 1; 2865250963Sachim bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 2866250963Sachim /* modify AIF contexts */ 2867250963Sachim if (sc->aifq_filled) { 2868250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2869250963Sachim if (next == ctx->ctx_idx) 2870250963Sachim ctx->ctx_wrap = 1; 2871250963Sachim else if (current == ctx->ctx_idx && ctx->ctx_wrap) 2872250963Sachim ctx->ctx_idx = next; 2873250963Sachim } 2874250963Sachim } 2875250963Sachim sc->aifq_idx = next; 2876250963Sachim /* On the off chance that someone is sleeping for an aif... */ 2877250963Sachim if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 2878250963Sachim wakeup(sc->aac_aifq); 2879250963Sachim /* Wakeup any poll()ers */ 2880250963Sachim selwakeuppri(&sc->rcv_select, PRIBIO); 2881250963Sachim 2882250963Sachim return; 2883250963Sachim} 2884250963Sachim 2885250963Sachim/* 2886250963Sachim * Return the Revision of the driver to userspace and check to see if the 2887250963Sachim * userspace app is possibly compatible. This is extremely bogus since 2888250963Sachim * our driver doesn't follow Adaptec's versioning system. Cheat by just 2889250963Sachim * returning what the card reported. 2890250963Sachim */ 2891250963Sachimstatic int 2892250963Sachimaac_rev_check(struct aac_softc *sc, caddr_t udata) 2893250963Sachim{ 2894250963Sachim struct aac_rev_check rev_check; 2895250963Sachim struct aac_rev_check_resp rev_check_resp; 2896250963Sachim int error = 0; 2897250963Sachim 2898250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2899250963Sachim 2900250963Sachim /* 2901250963Sachim * Copyin the revision struct from userspace 2902250963Sachim */ 2903250963Sachim if ((error = copyin(udata, (caddr_t)&rev_check, 2904250963Sachim sizeof(struct aac_rev_check))) != 0) { 2905250963Sachim return error; 2906250963Sachim } 2907250963Sachim 2908250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 2909250963Sachim rev_check.callingRevision.buildNumber); 2910250963Sachim 2911250963Sachim /* 2912250963Sachim * Doctor up the response struct. 2913250963Sachim */ 2914250963Sachim rev_check_resp.possiblyCompatible = 1; 2915250963Sachim rev_check_resp.adapterSWRevision.external.comp.major = 2916250963Sachim AAC_DRIVER_MAJOR_VERSION; 2917250963Sachim rev_check_resp.adapterSWRevision.external.comp.minor = 2918250963Sachim AAC_DRIVER_MINOR_VERSION; 2919250963Sachim rev_check_resp.adapterSWRevision.external.comp.type = 2920250963Sachim AAC_DRIVER_TYPE; 2921250963Sachim rev_check_resp.adapterSWRevision.external.comp.dash = 2922250963Sachim AAC_DRIVER_BUGFIX_LEVEL; 2923250963Sachim rev_check_resp.adapterSWRevision.buildNumber = 2924250963Sachim AAC_DRIVER_BUILD; 2925250963Sachim 2926250963Sachim return(copyout((caddr_t)&rev_check_resp, udata, 2927250963Sachim sizeof(struct aac_rev_check_resp))); 2928250963Sachim} 2929250963Sachim 2930250963Sachim/* 2931250963Sachim * Pass the fib context to the caller 2932250963Sachim */ 2933250963Sachimstatic int 2934250963Sachimaac_open_aif(struct aac_softc *sc, caddr_t arg) 2935250963Sachim{ 2936250963Sachim struct aac_fib_context *fibctx, *ctx; 2937250963Sachim int error = 0; 2938250963Sachim 2939250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2940250963Sachim 2941250963Sachim fibctx = malloc(sizeof(struct aac_fib_context), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 2942250963Sachim if (fibctx == NULL) 2943250963Sachim return (ENOMEM); 2944250963Sachim 2945250963Sachim mtx_lock(&sc->aac_io_lock); 2946250963Sachim /* all elements are already 0, add to queue */ 2947250963Sachim if (sc->fibctx == NULL) 2948250963Sachim sc->fibctx = fibctx; 2949250963Sachim else { 2950250963Sachim for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 2951250963Sachim ; 2952250963Sachim ctx->next = fibctx; 2953250963Sachim fibctx->prev = ctx; 2954250963Sachim } 2955250963Sachim 2956250963Sachim /* evaluate unique value */ 2957250963Sachim fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 2958250963Sachim ctx = sc->fibctx; 2959250963Sachim while (ctx != fibctx) { 2960250963Sachim if (ctx->unique == fibctx->unique) { 2961250963Sachim fibctx->unique++; 2962250963Sachim ctx = sc->fibctx; 2963250963Sachim } else { 2964250963Sachim ctx = ctx->next; 2965250963Sachim } 2966250963Sachim } 2967250963Sachim 2968250963Sachim error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 2969250963Sachim mtx_unlock(&sc->aac_io_lock); 2970250963Sachim if (error) 2971250963Sachim aac_close_aif(sc, (caddr_t)ctx); 2972250963Sachim return error; 2973250963Sachim} 2974250963Sachim 2975250963Sachim/* 2976250963Sachim * Close the caller's fib context 2977250963Sachim */ 2978250963Sachimstatic int 2979250963Sachimaac_close_aif(struct aac_softc *sc, caddr_t arg) 2980250963Sachim{ 2981250963Sachim struct aac_fib_context *ctx; 2982250963Sachim 2983250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2984250963Sachim 2985250963Sachim mtx_lock(&sc->aac_io_lock); 2986250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2987250963Sachim if (ctx->unique == *(uint32_t *)&arg) { 2988250963Sachim if (ctx == sc->fibctx) 2989250963Sachim sc->fibctx = NULL; 2990250963Sachim else { 2991250963Sachim ctx->prev->next = ctx->next; 2992250963Sachim if (ctx->next) 2993250963Sachim ctx->next->prev = ctx->prev; 2994250963Sachim } 2995250963Sachim break; 2996250963Sachim } 2997250963Sachim } 2998250963Sachim if (ctx) 2999250963Sachim free(ctx, M_AACRAIDBUF); 3000250963Sachim 3001250963Sachim mtx_unlock(&sc->aac_io_lock); 3002250963Sachim return 0; 3003250963Sachim} 3004250963Sachim 3005250963Sachim/* 3006250963Sachim * Pass the caller the next AIF in their queue 3007250963Sachim */ 3008250963Sachimstatic int 3009250963Sachimaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 3010250963Sachim{ 3011250963Sachim struct get_adapter_fib_ioctl agf; 3012250963Sachim struct aac_fib_context *ctx; 3013250963Sachim int error; 3014250963Sachim 3015250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3016250963Sachim 3017250963Sachim mtx_lock(&sc->aac_io_lock); 3018250963Sachim if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3019250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3020250963Sachim if (agf.AdapterFibContext == ctx->unique) 3021250963Sachim break; 3022250963Sachim } 3023250963Sachim if (!ctx) { 3024250963Sachim mtx_unlock(&sc->aac_io_lock); 3025250963Sachim return (EFAULT); 3026250963Sachim } 3027250963Sachim 3028250963Sachim error = aac_return_aif(sc, ctx, agf.AifFib); 3029250963Sachim if (error == EAGAIN && agf.Wait) { 3030250963Sachim fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 3031250963Sachim sc->aac_state |= AAC_STATE_AIF_SLEEPER; 3032250963Sachim while (error == EAGAIN) { 3033250963Sachim mtx_unlock(&sc->aac_io_lock); 3034250963Sachim error = tsleep(sc->aac_aifq, PRIBIO | 3035250963Sachim PCATCH, "aacaif", 0); 3036250963Sachim mtx_lock(&sc->aac_io_lock); 3037250963Sachim if (error == 0) 3038250963Sachim error = aac_return_aif(sc, ctx, agf.AifFib); 3039250963Sachim } 3040250963Sachim sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 3041250963Sachim } 3042250963Sachim } 3043250963Sachim mtx_unlock(&sc->aac_io_lock); 3044250963Sachim return(error); 3045250963Sachim} 3046250963Sachim 3047250963Sachim/* 3048250963Sachim * Hand the next AIF off the top of the queue out to userspace. 3049250963Sachim */ 3050250963Sachimstatic int 3051250963Sachimaac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 3052250963Sachim{ 3053250963Sachim int current, error; 3054250963Sachim 3055250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3056250963Sachim 3057250963Sachim current = ctx->ctx_idx; 3058250963Sachim if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3059250963Sachim /* empty */ 3060250963Sachim return (EAGAIN); 3061250963Sachim } 3062250963Sachim error = 3063250963Sachim copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 3064250963Sachim if (error) 3065250963Sachim device_printf(sc->aac_dev, 3066250963Sachim "aac_return_aif: copyout returned %d\n", error); 3067250963Sachim else { 3068250963Sachim ctx->ctx_wrap = 0; 3069250963Sachim ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3070250963Sachim } 3071250963Sachim return(error); 3072250963Sachim} 3073250963Sachim 3074250963Sachimstatic int 3075250963Sachimaac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3076250963Sachim{ 3077250963Sachim struct aac_pci_info { 3078250963Sachim u_int32_t bus; 3079250963Sachim u_int32_t slot; 3080250963Sachim } pciinf; 3081250963Sachim int error; 3082250963Sachim 3083250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3084250963Sachim 3085250963Sachim pciinf.bus = pci_get_bus(sc->aac_dev); 3086250963Sachim pciinf.slot = pci_get_slot(sc->aac_dev); 3087250963Sachim 3088250963Sachim error = copyout((caddr_t)&pciinf, uptr, 3089250963Sachim sizeof(struct aac_pci_info)); 3090250963Sachim 3091250963Sachim return (error); 3092250963Sachim} 3093250963Sachim 3094250963Sachimstatic int 3095250963Sachimaac_supported_features(struct aac_softc *sc, caddr_t uptr) 3096250963Sachim{ 3097250963Sachim struct aac_features f; 3098250963Sachim int error; 3099250963Sachim 3100250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3101250963Sachim 3102250963Sachim if ((error = copyin(uptr, &f, sizeof (f))) != 0) 3103250963Sachim return (error); 3104250963Sachim 3105250963Sachim /* 3106250963Sachim * When the management driver receives FSACTL_GET_FEATURES ioctl with 3107250963Sachim * ALL zero in the featuresState, the driver will return the current 3108250963Sachim * state of all the supported features, the data field will not be 3109250963Sachim * valid. 3110250963Sachim * When the management driver receives FSACTL_GET_FEATURES ioctl with 3111250963Sachim * a specific bit set in the featuresState, the driver will return the 3112250963Sachim * current state of this specific feature and whatever data that are 3113250963Sachim * associated with the feature in the data field or perform whatever 3114250963Sachim * action needed indicates in the data field. 3115250963Sachim */ 3116250963Sachim if (f.feat.fValue == 0) { 3117250963Sachim f.feat.fBits.largeLBA = 3118250963Sachim (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3119250963Sachim f.feat.fBits.JBODSupport = 1; 3120250963Sachim /* TODO: In the future, add other features state here as well */ 3121250963Sachim } else { 3122250963Sachim if (f.feat.fBits.largeLBA) 3123250963Sachim f.feat.fBits.largeLBA = 3124250963Sachim (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3125250963Sachim /* TODO: Add other features state and data in the future */ 3126250963Sachim } 3127250963Sachim 3128250963Sachim error = copyout(&f, uptr, sizeof (f)); 3129250963Sachim return (error); 3130250963Sachim} 3131250963Sachim 3132250963Sachim/* 3133250963Sachim * Give the userland some information about the container. The AAC arch 3134250963Sachim * expects the driver to be a SCSI passthrough type driver, so it expects 3135250963Sachim * the containers to have b:t:l numbers. Fake it. 3136250963Sachim */ 3137250963Sachimstatic int 3138250963Sachimaac_query_disk(struct aac_softc *sc, caddr_t uptr) 3139250963Sachim{ 3140250963Sachim struct aac_query_disk query_disk; 3141250963Sachim struct aac_container *co; 3142250963Sachim int error, id; 3143250963Sachim 3144250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3145250963Sachim 3146250963Sachim mtx_lock(&sc->aac_io_lock); 3147250963Sachim error = copyin(uptr, (caddr_t)&query_disk, 3148250963Sachim sizeof(struct aac_query_disk)); 3149250963Sachim if (error) { 3150250963Sachim mtx_unlock(&sc->aac_io_lock); 3151250963Sachim return (error); 3152250963Sachim } 3153250963Sachim 3154250963Sachim id = query_disk.ContainerNumber; 3155250963Sachim if (id == -1) { 3156250963Sachim mtx_unlock(&sc->aac_io_lock); 3157250963Sachim return (EINVAL); 3158250963Sachim } 3159250963Sachim 3160250963Sachim TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 3161250963Sachim if (co->co_mntobj.ObjectId == id) 3162250963Sachim break; 3163250963Sachim } 3164250963Sachim 3165250963Sachim if (co == NULL) { 3166250963Sachim query_disk.Valid = 0; 3167250963Sachim query_disk.Locked = 0; 3168250963Sachim query_disk.Deleted = 1; /* XXX is this right? */ 3169250963Sachim } else { 3170250963Sachim query_disk.Valid = 1; 3171250963Sachim query_disk.Locked = 1; 3172250963Sachim query_disk.Deleted = 0; 3173250963Sachim query_disk.Bus = device_get_unit(sc->aac_dev); 3174250963Sachim query_disk.Target = 0; 3175250963Sachim query_disk.Lun = 0; 3176250963Sachim query_disk.UnMapped = 0; 3177250963Sachim } 3178250963Sachim 3179250963Sachim error = copyout((caddr_t)&query_disk, uptr, 3180250963Sachim sizeof(struct aac_query_disk)); 3181250963Sachim 3182250963Sachim mtx_unlock(&sc->aac_io_lock); 3183250963Sachim return (error); 3184250963Sachim} 3185250963Sachim 3186250963Sachimstatic void 3187250963Sachimaac_container_bus(struct aac_softc *sc) 3188250963Sachim{ 3189250963Sachim struct aac_sim *sim; 3190250963Sachim device_t child; 3191250963Sachim 3192250963Sachim sim =(struct aac_sim *)malloc(sizeof(struct aac_sim), 3193250963Sachim M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3194250963Sachim if (sim == NULL) { 3195250963Sachim device_printf(sc->aac_dev, 3196250963Sachim "No memory to add container bus\n"); 3197250963Sachim panic("Out of memory?!"); 3198250963Sachim }; 3199250963Sachim child = device_add_child(sc->aac_dev, "aacraidp", -1); 3200250963Sachim if (child == NULL) { 3201250963Sachim device_printf(sc->aac_dev, 3202250963Sachim "device_add_child failed for container bus\n"); 3203250963Sachim free(sim, M_AACRAIDBUF); 3204250963Sachim panic("Out of memory?!"); 3205250963Sachim } 3206250963Sachim 3207250963Sachim sim->TargetsPerBus = AAC_MAX_CONTAINERS; 3208250963Sachim sim->BusNumber = 0; 3209250963Sachim sim->BusType = CONTAINER_BUS; 3210250963Sachim sim->InitiatorBusId = -1; 3211250963Sachim sim->aac_sc = sc; 3212250963Sachim sim->sim_dev = child; 3213250963Sachim sim->aac_cam = NULL; 3214250963Sachim 3215250963Sachim device_set_ivars(child, sim); 3216250963Sachim device_set_desc(child, "Container Bus"); 3217250963Sachim TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, sim, sim_link); 3218250963Sachim /* 3219250963Sachim device_set_desc(child, aac_describe_code(aac_container_types, 3220250963Sachim mir->MntTable[0].VolType)); 3221250963Sachim */ 3222250963Sachim bus_generic_attach(sc->aac_dev); 3223250963Sachim} 3224250963Sachim 3225250963Sachimstatic void 3226250963Sachimaac_get_bus_info(struct aac_softc *sc) 3227250963Sachim{ 3228250963Sachim struct aac_fib *fib; 3229250963Sachim struct aac_ctcfg *c_cmd; 3230250963Sachim struct aac_ctcfg_resp *c_resp; 3231250963Sachim struct aac_vmioctl *vmi; 3232250963Sachim struct aac_vmi_businf_resp *vmi_resp; 3233250963Sachim struct aac_getbusinf businfo; 3234250963Sachim struct aac_sim *caminf; 3235250963Sachim device_t child; 3236250963Sachim int i, error; 3237250963Sachim 3238250963Sachim mtx_lock(&sc->aac_io_lock); 3239250963Sachim aac_alloc_sync_fib(sc, &fib); 3240250963Sachim c_cmd = (struct aac_ctcfg *)&fib->data[0]; 3241250963Sachim bzero(c_cmd, sizeof(struct aac_ctcfg)); 3242250963Sachim 3243250963Sachim c_cmd->Command = VM_ContainerConfig; 3244250963Sachim c_cmd->cmd = CT_GET_SCSI_METHOD; 3245250963Sachim c_cmd->param = 0; 3246250963Sachim 3247250963Sachim error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3248250963Sachim sizeof(struct aac_ctcfg)); 3249250963Sachim if (error) { 3250250963Sachim device_printf(sc->aac_dev, "Error %d sending " 3251250963Sachim "VM_ContainerConfig command\n", error); 3252250963Sachim aac_release_sync_fib(sc); 3253250963Sachim mtx_unlock(&sc->aac_io_lock); 3254250963Sachim return; 3255250963Sachim } 3256250963Sachim 3257250963Sachim c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3258250963Sachim if (c_resp->Status != ST_OK) { 3259250963Sachim device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3260250963Sachim c_resp->Status); 3261250963Sachim aac_release_sync_fib(sc); 3262250963Sachim mtx_unlock(&sc->aac_io_lock); 3263250963Sachim return; 3264250963Sachim } 3265250963Sachim 3266250963Sachim sc->scsi_method_id = c_resp->param; 3267250963Sachim 3268250963Sachim vmi = (struct aac_vmioctl *)&fib->data[0]; 3269250963Sachim bzero(vmi, sizeof(struct aac_vmioctl)); 3270250963Sachim 3271250963Sachim vmi->Command = VM_Ioctl; 3272250963Sachim vmi->ObjType = FT_DRIVE; 3273250963Sachim vmi->MethId = sc->scsi_method_id; 3274250963Sachim vmi->ObjId = 0; 3275250963Sachim vmi->IoctlCmd = GetBusInfo; 3276250963Sachim 3277250963Sachim error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3278250963Sachim sizeof(struct aac_vmi_businf_resp)); 3279250963Sachim if (error) { 3280250963Sachim device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3281250963Sachim error); 3282250963Sachim aac_release_sync_fib(sc); 3283250963Sachim mtx_unlock(&sc->aac_io_lock); 3284250963Sachim return; 3285250963Sachim } 3286250963Sachim 3287250963Sachim vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3288250963Sachim if (vmi_resp->Status != ST_OK) { 3289250963Sachim device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3290250963Sachim vmi_resp->Status); 3291250963Sachim aac_release_sync_fib(sc); 3292250963Sachim mtx_unlock(&sc->aac_io_lock); 3293250963Sachim return; 3294250963Sachim } 3295250963Sachim 3296250963Sachim bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3297250963Sachim aac_release_sync_fib(sc); 3298250963Sachim mtx_unlock(&sc->aac_io_lock); 3299250963Sachim 3300250963Sachim for (i = 0; i < businfo.BusCount; i++) { 3301250963Sachim if (businfo.BusValid[i] != AAC_BUS_VALID) 3302250963Sachim continue; 3303250963Sachim 3304250963Sachim caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3305250963Sachim M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3306250963Sachim if (caminf == NULL) { 3307250963Sachim device_printf(sc->aac_dev, 3308250963Sachim "No memory to add passthrough bus %d\n", i); 3309250963Sachim break; 3310250963Sachim }; 3311250963Sachim 3312250963Sachim child = device_add_child(sc->aac_dev, "aacraidp", -1); 3313250963Sachim if (child == NULL) { 3314250963Sachim device_printf(sc->aac_dev, 3315250963Sachim "device_add_child failed for passthrough bus %d\n", 3316250963Sachim i); 3317250963Sachim free(caminf, M_AACRAIDBUF); 3318250963Sachim break; 3319250963Sachim } 3320250963Sachim 3321250963Sachim caminf->TargetsPerBus = businfo.TargetsPerBus; 3322250963Sachim caminf->BusNumber = i+1; 3323250963Sachim caminf->BusType = PASSTHROUGH_BUS; 3324250963Sachim caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3325250963Sachim caminf->aac_sc = sc; 3326250963Sachim caminf->sim_dev = child; 3327250963Sachim caminf->aac_cam = NULL; 3328250963Sachim 3329250963Sachim device_set_ivars(child, caminf); 3330250963Sachim device_set_desc(child, "SCSI Passthrough Bus"); 3331250963Sachim TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3332250963Sachim } 3333250963Sachim} 3334250963Sachim 3335250963Sachim/* 3336250963Sachim * Check to see if the kernel is up and running. If we are in a 3337250963Sachim * BlinkLED state, return the BlinkLED code. 3338250963Sachim */ 3339250963Sachimstatic u_int32_t 3340250963Sachimaac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled) 3341250963Sachim{ 3342250963Sachim u_int32_t ret; 3343250963Sachim 3344250963Sachim ret = AAC_GET_FWSTATUS(sc); 3345250963Sachim 3346250963Sachim if (ret & AAC_UP_AND_RUNNING) 3347250963Sachim ret = 0; 3348250963Sachim else if (ret & AAC_KERNEL_PANIC && bled) 3349250963Sachim *bled = (ret >> 16) & 0xff; 3350250963Sachim 3351250963Sachim return (ret); 3352250963Sachim} 3353250963Sachim 3354250963Sachim/* 3355250963Sachim * Once do an IOP reset, basically have to re-initialize the card as 3356250963Sachim * if coming up from a cold boot, and the driver is responsible for 3357250963Sachim * any IO that was outstanding to the adapter at the time of the IOP 3358250963Sachim * RESET. And prepare the driver for IOP RESET by making the init code 3359250963Sachim * modular with the ability to call it from multiple places. 3360250963Sachim */ 3361250963Sachimstatic int 3362250963Sachimaac_reset_adapter(struct aac_softc *sc) 3363250963Sachim{ 3364250963Sachim struct aac_command *cm; 3365250963Sachim struct aac_fib *fib; 3366250963Sachim struct aac_pause_command *pc; 3367250963Sachim u_int32_t status, old_flags, reset_mask, waitCount; 3368250963Sachim 3369250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3370250963Sachim 3371250963Sachim if (sc->aac_state & AAC_STATE_RESET) { 3372250963Sachim device_printf(sc->aac_dev, "aac_reset_adapter() already in progress\n"); 3373250963Sachim return (EINVAL); 3374250963Sachim } 3375250963Sachim sc->aac_state |= AAC_STATE_RESET; 3376250963Sachim 3377250963Sachim /* disable interrupt */ 3378250963Sachim AAC_MASK_INTERRUPTS(sc); 3379250963Sachim 3380250963Sachim /* 3381250963Sachim * Abort all pending commands: 3382250963Sachim * a) on the controller 3383250963Sachim */ 3384250963Sachim while ((cm = aac_dequeue_busy(sc)) != NULL) { 3385250963Sachim cm->cm_flags |= AAC_CMD_RESET; 3386250963Sachim 3387250963Sachim /* is there a completion handler? */ 3388250963Sachim if (cm->cm_complete != NULL) { 3389250963Sachim cm->cm_complete(cm); 3390250963Sachim } else { 3391250963Sachim /* assume that someone is sleeping on this 3392250963Sachim * command 3393250963Sachim */ 3394250963Sachim wakeup(cm); 3395250963Sachim } 3396250963Sachim } 3397250963Sachim 3398250963Sachim /* b) in the waiting queues */ 3399250963Sachim while ((cm = aac_dequeue_ready(sc)) != NULL) { 3400250963Sachim cm->cm_flags |= AAC_CMD_RESET; 3401250963Sachim 3402250963Sachim /* is there a completion handler? */ 3403250963Sachim if (cm->cm_complete != NULL) { 3404250963Sachim cm->cm_complete(cm); 3405250963Sachim } else { 3406250963Sachim /* assume that someone is sleeping on this 3407250963Sachim * command 3408250963Sachim */ 3409250963Sachim wakeup(cm); 3410250963Sachim } 3411250963Sachim } 3412250963Sachim 3413250963Sachim /* flush drives */ 3414250963Sachim if (aac_check_adapter_health(sc, NULL) == 0) { 3415250963Sachim mtx_unlock(&sc->aac_io_lock); 3416250963Sachim (void) aacraid_shutdown(sc->aac_dev); 3417250963Sachim mtx_lock(&sc->aac_io_lock); 3418250963Sachim } 3419250963Sachim 3420250963Sachim /* execute IOP reset */ 3421250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_MU_RESET) { 3422250963Sachim AAC_MEM0_SETREG4(sc, AAC_IRCSR, AAC_IRCSR_CORES_RST); 3423250963Sachim 3424250963Sachim /* We need to wait for 5 seconds before accessing the MU again 3425250963Sachim * 10000 * 100us = 1000,000us = 1000ms = 1s 3426250963Sachim */ 3427250963Sachim waitCount = 5 * 10000; 3428250963Sachim while (waitCount) { 3429250963Sachim DELAY(100); /* delay 100 microseconds */ 3430250963Sachim waitCount--; 3431250963Sachim } 3432250963Sachim } else if ((aacraid_sync_command(sc, 3433250963Sachim AAC_IOP_RESET_ALWAYS, 0, 0, 0, 0, &status, &reset_mask)) != 0) { 3434250963Sachim /* call IOP_RESET for older firmware */ 3435250963Sachim if ((aacraid_sync_command(sc, 3436250963Sachim AAC_IOP_RESET, 0, 0, 0, 0, &status, NULL)) != 0) { 3437250963Sachim 3438250963Sachim if (status == AAC_SRB_STS_INVALID_REQUEST) 3439250963Sachim device_printf(sc->aac_dev, "IOP_RESET not supported\n"); 3440250963Sachim else 3441250963Sachim /* probably timeout */ 3442250963Sachim device_printf(sc->aac_dev, "IOP_RESET failed\n"); 3443250963Sachim 3444250963Sachim /* unwind aac_shutdown() */ 3445250963Sachim aac_alloc_sync_fib(sc, &fib); 3446250963Sachim pc = (struct aac_pause_command *)&fib->data[0]; 3447250963Sachim pc->Command = VM_ContainerConfig; 3448250963Sachim pc->Type = CT_PAUSE_IO; 3449250963Sachim pc->Timeout = 1; 3450250963Sachim pc->Min = 1; 3451250963Sachim pc->NoRescan = 1; 3452250963Sachim 3453250963Sachim (void) aac_sync_fib(sc, ContainerCommand, 0, fib, 3454250963Sachim sizeof (struct aac_pause_command)); 3455250963Sachim aac_release_sync_fib(sc); 3456250963Sachim 3457250963Sachim goto finish; 3458250963Sachim } 3459250963Sachim } else if (sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET) { 3460250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask); 3461250963Sachim /* We need to wait for 5 seconds before accessing the doorbell again 3462250963Sachim * 10000 * 100us = 1000,000us = 1000ms = 1s 3463250963Sachim */ 3464250963Sachim waitCount = 5 * 10000; 3465250963Sachim while (waitCount) { 3466250963Sachim DELAY(100); /* delay 100 microseconds */ 3467250963Sachim waitCount--; 3468250963Sachim } 3469250963Sachim } 3470250963Sachim 3471250963Sachim /* 3472250963Sachim * Re-read and renegotiate the FIB parameters, as one of the actions 3473250963Sachim * that can result from an IOP reset is the running of a new firmware 3474250963Sachim * image. 3475250963Sachim */ 3476250963Sachim old_flags = sc->flags; 3477250963Sachim /* 3478250963Sachim * Initialize the adapter. 3479250963Sachim */ 3480250963Sachim if (aac_check_firmware(sc) != 0) 3481250963Sachim goto finish; 3482250963Sachim if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 3483250963Sachim if (aac_init(sc) != 0) 3484250963Sachim goto finish; 3485250963Sachim } 3486250963Sachim 3487250963Sachimfinish: 3488250963Sachim sc->aac_state &= ~AAC_STATE_RESET; 3489250963Sachim AAC_UNMASK_INTERRUPTS(sc); 3490250963Sachim aacraid_startio(sc); 3491250963Sachim return (0); 3492250963Sachim} 3493