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); 101263340Sachimstatic void aac_define_int_mode(struct aac_softc *sc); 102250963Sachimstatic int aac_init(struct aac_softc *sc); 103263340Sachimstatic int aac_find_pci_capability(struct aac_softc *sc, int cap); 104250963Sachimstatic int aac_setup_intr(struct aac_softc *sc); 105263340Sachimstatic int aac_check_config(struct aac_softc *sc); 106250963Sachim 107250963Sachim/* PMC SRC interface */ 108250963Sachimstatic int aac_src_get_fwstatus(struct aac_softc *sc); 109250963Sachimstatic void aac_src_qnotify(struct aac_softc *sc, int qbit); 110250963Sachimstatic int aac_src_get_istatus(struct aac_softc *sc); 111250963Sachimstatic void aac_src_clear_istatus(struct aac_softc *sc, int mask); 112250963Sachimstatic void aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, 113250963Sachim u_int32_t arg0, u_int32_t arg1, 114250963Sachim u_int32_t arg2, u_int32_t arg3); 115250963Sachimstatic int aac_src_get_mailbox(struct aac_softc *sc, int mb); 116263340Sachimstatic void aac_src_access_devreg(struct aac_softc *sc, int mode); 117250963Sachimstatic int aac_src_send_command(struct aac_softc *sc, struct aac_command *cm); 118250963Sachimstatic int aac_src_get_outb_queue(struct aac_softc *sc); 119250963Sachimstatic void aac_src_set_outb_queue(struct aac_softc *sc, int index); 120250963Sachim 121250963Sachimstruct aac_interface aacraid_src_interface = { 122250963Sachim aac_src_get_fwstatus, 123250963Sachim aac_src_qnotify, 124250963Sachim aac_src_get_istatus, 125250963Sachim aac_src_clear_istatus, 126250963Sachim aac_src_set_mailbox, 127250963Sachim aac_src_get_mailbox, 128263340Sachim aac_src_access_devreg, 129250963Sachim aac_src_send_command, 130250963Sachim aac_src_get_outb_queue, 131250963Sachim aac_src_set_outb_queue 132250963Sachim}; 133250963Sachim 134250963Sachim/* PMC SRCv interface */ 135250963Sachimstatic void aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, 136250963Sachim u_int32_t arg0, u_int32_t arg1, 137250963Sachim u_int32_t arg2, u_int32_t arg3); 138250963Sachimstatic int aac_srcv_get_mailbox(struct aac_softc *sc, int mb); 139250963Sachim 140250963Sachimstruct aac_interface aacraid_srcv_interface = { 141250963Sachim aac_src_get_fwstatus, 142250963Sachim aac_src_qnotify, 143250963Sachim aac_src_get_istatus, 144250963Sachim aac_src_clear_istatus, 145250963Sachim aac_srcv_set_mailbox, 146250963Sachim aac_srcv_get_mailbox, 147263340Sachim aac_src_access_devreg, 148250963Sachim aac_src_send_command, 149250963Sachim aac_src_get_outb_queue, 150250963Sachim aac_src_set_outb_queue 151250963Sachim}; 152250963Sachim 153250963Sachim/* Debugging and Diagnostics */ 154250963Sachimstatic struct aac_code_lookup aac_cpu_variant[] = { 155250963Sachim {"i960JX", CPUI960_JX}, 156250963Sachim {"i960CX", CPUI960_CX}, 157250963Sachim {"i960HX", CPUI960_HX}, 158250963Sachim {"i960RX", CPUI960_RX}, 159250963Sachim {"i960 80303", CPUI960_80303}, 160250963Sachim {"StrongARM SA110", CPUARM_SA110}, 161250963Sachim {"PPC603e", CPUPPC_603e}, 162250963Sachim {"XScale 80321", CPU_XSCALE_80321}, 163250963Sachim {"MIPS 4KC", CPU_MIPS_4KC}, 164250963Sachim {"MIPS 5KC", CPU_MIPS_5KC}, 165250963Sachim {"Unknown StrongARM", CPUARM_xxx}, 166250963Sachim {"Unknown PowerPC", CPUPPC_xxx}, 167250963Sachim {NULL, 0}, 168250963Sachim {"Unknown processor", 0} 169250963Sachim}; 170250963Sachim 171250963Sachimstatic struct aac_code_lookup aac_battery_platform[] = { 172250963Sachim {"required battery present", PLATFORM_BAT_REQ_PRESENT}, 173250963Sachim {"REQUIRED BATTERY NOT PRESENT", PLATFORM_BAT_REQ_NOTPRESENT}, 174250963Sachim {"optional battery present", PLATFORM_BAT_OPT_PRESENT}, 175250963Sachim {"optional battery not installed", PLATFORM_BAT_OPT_NOTPRESENT}, 176250963Sachim {"no battery support", PLATFORM_BAT_NOT_SUPPORTED}, 177250963Sachim {NULL, 0}, 178250963Sachim {"unknown battery platform", 0} 179250963Sachim}; 180250963Sachimstatic void aac_describe_controller(struct aac_softc *sc); 181250963Sachimstatic char *aac_describe_code(struct aac_code_lookup *table, 182250963Sachim u_int32_t code); 183250963Sachim 184250963Sachim/* Management Interface */ 185250963Sachimstatic d_open_t aac_open; 186250963Sachimstatic d_ioctl_t aac_ioctl; 187250963Sachimstatic d_poll_t aac_poll; 188250963Sachim#if __FreeBSD_version >= 702000 189250963Sachimstatic void aac_cdevpriv_dtor(void *arg); 190250963Sachim#else 191250963Sachimstatic d_close_t aac_close; 192250963Sachim#endif 193250963Sachimstatic int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 194250963Sachimstatic int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 195250963Sachimstatic void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); 196250963Sachimstatic void aac_request_aif(struct aac_softc *sc); 197250963Sachimstatic int aac_rev_check(struct aac_softc *sc, caddr_t udata); 198250963Sachimstatic int aac_open_aif(struct aac_softc *sc, caddr_t arg); 199250963Sachimstatic int aac_close_aif(struct aac_softc *sc, caddr_t arg); 200250963Sachimstatic int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 201250963Sachimstatic int aac_return_aif(struct aac_softc *sc, 202250963Sachim struct aac_fib_context *ctx, caddr_t uptr); 203250963Sachimstatic int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 204250963Sachimstatic int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 205250963Sachimstatic int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 206250963Sachimstatic void aac_ioctl_event(struct aac_softc *sc, 207250963Sachim struct aac_event *event, void *arg); 208250963Sachimstatic int aac_reset_adapter(struct aac_softc *sc); 209250963Sachimstatic int aac_get_container_info(struct aac_softc *sc, 210250963Sachim struct aac_fib *fib, int cid, 211250963Sachim struct aac_mntinforesp *mir, 212250963Sachim u_int32_t *uid); 213250963Sachimstatic u_int32_t 214250963Sachim aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled); 215250963Sachim 216250963Sachimstatic struct cdevsw aacraid_cdevsw = { 217250963Sachim .d_version = D_VERSION, 218250963Sachim .d_flags = D_NEEDGIANT, 219250963Sachim .d_open = aac_open, 220250963Sachim#if __FreeBSD_version < 702000 221250963Sachim .d_close = aac_close, 222250963Sachim#endif 223250963Sachim .d_ioctl = aac_ioctl, 224250963Sachim .d_poll = aac_poll, 225250963Sachim .d_name = "aacraid", 226250963Sachim}; 227250963Sachim 228250963SachimMALLOC_DEFINE(M_AACRAIDBUF, "aacraid_buf", "Buffers for the AACRAID driver"); 229250963Sachim 230250963Sachim/* sysctl node */ 231250963SachimSYSCTL_NODE(_hw, OID_AUTO, aacraid, CTLFLAG_RD, 0, "AACRAID driver parameters"); 232250963Sachim 233250963Sachim/* 234250963Sachim * Device Interface 235250963Sachim */ 236250963Sachim 237250963Sachim/* 238250963Sachim * Initialize the controller and softc 239250963Sachim */ 240250963Sachimint 241250963Sachimaacraid_attach(struct aac_softc *sc) 242250963Sachim{ 243250963Sachim int error, unit; 244250963Sachim struct aac_fib *fib; 245250963Sachim struct aac_mntinforesp mir; 246250963Sachim int count = 0, i = 0; 247250963Sachim u_int32_t uid; 248250963Sachim 249250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 250250963Sachim sc->hint_flags = device_get_flags(sc->aac_dev); 251250963Sachim /* 252250963Sachim * Initialize per-controller queues. 253250963Sachim */ 254250963Sachim aac_initq_free(sc); 255250963Sachim aac_initq_ready(sc); 256250963Sachim aac_initq_busy(sc); 257250963Sachim 258250963Sachim /* mark controller as suspended until we get ourselves organised */ 259250963Sachim sc->aac_state |= AAC_STATE_SUSPEND; 260250963Sachim 261250963Sachim /* 262250963Sachim * Check that the firmware on the card is supported. 263250963Sachim */ 264263340Sachim sc->msi_enabled = FALSE; 265250963Sachim if ((error = aac_check_firmware(sc)) != 0) 266250963Sachim return(error); 267250963Sachim 268250963Sachim /* 269250963Sachim * Initialize locks 270250963Sachim */ 271250963Sachim mtx_init(&sc->aac_io_lock, "AACRAID I/O lock", NULL, MTX_DEF); 272250963Sachim TAILQ_INIT(&sc->aac_container_tqh); 273250963Sachim TAILQ_INIT(&sc->aac_ev_cmfree); 274250963Sachim 275250963Sachim#if __FreeBSD_version >= 800000 276250963Sachim /* Initialize the clock daemon callout. */ 277250963Sachim callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 278250963Sachim#endif 279250963Sachim /* 280250963Sachim * Initialize the adapter. 281250963Sachim */ 282250963Sachim if ((error = aac_alloc(sc)) != 0) 283250963Sachim return(error); 284250963Sachim if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 285263340Sachim aac_define_int_mode(sc); 286250963Sachim if ((error = aac_init(sc)) != 0) 287250963Sachim return(error); 288250963Sachim } 289250963Sachim 290250963Sachim /* 291250963Sachim * Allocate and connect our interrupt. 292250963Sachim */ 293250963Sachim if ((error = aac_setup_intr(sc)) != 0) 294250963Sachim return(error); 295250963Sachim 296250963Sachim /* 297250963Sachim * Print a little information about the controller. 298250963Sachim */ 299250963Sachim aac_describe_controller(sc); 300250963Sachim 301250963Sachim /* 302250963Sachim * Make the control device. 303250963Sachim */ 304250963Sachim unit = device_get_unit(sc->aac_dev); 305250963Sachim sc->aac_dev_t = make_dev(&aacraid_cdevsw, unit, UID_ROOT, GID_OPERATOR, 306250963Sachim 0640, "aacraid%d", unit); 307250963Sachim sc->aac_dev_t->si_drv1 = sc; 308250963Sachim 309250963Sachim /* Create the AIF thread */ 310250963Sachim if (aac_kthread_create((void(*)(void *))aac_command_thread, sc, 311250963Sachim &sc->aifthread, 0, 0, "aacraid%daif", unit)) 312250963Sachim panic("Could not create AIF thread"); 313250963Sachim 314250963Sachim /* Register the shutdown method to only be called post-dump */ 315250963Sachim if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aacraid_shutdown, 316250963Sachim sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 317250963Sachim device_printf(sc->aac_dev, 318250963Sachim "shutdown event registration failed\n"); 319250963Sachim 320250963Sachim /* Find containers */ 321250963Sachim mtx_lock(&sc->aac_io_lock); 322250963Sachim aac_alloc_sync_fib(sc, &fib); 323250963Sachim /* loop over possible containers */ 324250963Sachim do { 325250963Sachim if ((aac_get_container_info(sc, fib, i, &mir, &uid)) != 0) 326250963Sachim continue; 327250963Sachim if (i == 0) 328250963Sachim count = mir.MntRespCount; 329250963Sachim aac_add_container(sc, &mir, 0, uid); 330250963Sachim i++; 331250963Sachim } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 332250963Sachim aac_release_sync_fib(sc); 333250963Sachim mtx_unlock(&sc->aac_io_lock); 334250963Sachim 335250963Sachim /* Register with CAM for the containers */ 336250963Sachim TAILQ_INIT(&sc->aac_sim_tqh); 337250963Sachim aac_container_bus(sc); 338250963Sachim /* Register with CAM for the non-DASD devices */ 339250963Sachim if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) 340250963Sachim aac_get_bus_info(sc); 341250963Sachim 342250963Sachim /* poke the bus to actually attach the child devices */ 343250963Sachim bus_generic_attach(sc->aac_dev); 344250963Sachim 345250963Sachim /* mark the controller up */ 346250963Sachim sc->aac_state &= ~AAC_STATE_SUSPEND; 347250963Sachim 348250963Sachim /* enable interrupts now */ 349263340Sachim AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT); 350250963Sachim 351250963Sachim#if __FreeBSD_version >= 800000 352250963Sachim mtx_lock(&sc->aac_io_lock); 353250963Sachim callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 354250963Sachim mtx_unlock(&sc->aac_io_lock); 355250963Sachim#else 356250963Sachim { 357250963Sachim struct timeval tv; 358250963Sachim tv.tv_sec = 60; 359250963Sachim tv.tv_usec = 0; 360250963Sachim sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 361250963Sachim } 362250963Sachim#endif 363250963Sachim 364250963Sachim return(0); 365250963Sachim} 366250963Sachim 367250963Sachimstatic void 368250963Sachimaac_daemon(void *arg) 369250963Sachim{ 370250963Sachim struct aac_softc *sc; 371250963Sachim struct timeval tv; 372250963Sachim struct aac_command *cm; 373250963Sachim struct aac_fib *fib; 374250963Sachim 375250963Sachim sc = arg; 376250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 377250963Sachim 378250963Sachim#if __FreeBSD_version >= 800000 379250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 380250963Sachim if (callout_pending(&sc->aac_daemontime) || 381250963Sachim callout_active(&sc->aac_daemontime) == 0) 382250963Sachim return; 383250963Sachim#else 384250963Sachim mtx_lock(&sc->aac_io_lock); 385250963Sachim#endif 386250963Sachim getmicrotime(&tv); 387250963Sachim 388250963Sachim if (!aacraid_alloc_command(sc, &cm)) { 389250963Sachim fib = cm->cm_fib; 390250963Sachim cm->cm_timestamp = time_uptime; 391250963Sachim cm->cm_datalen = 0; 392250963Sachim cm->cm_flags |= AAC_CMD_WAIT; 393250963Sachim 394250963Sachim fib->Header.Size = 395250963Sachim sizeof(struct aac_fib_header) + sizeof(u_int32_t); 396250963Sachim fib->Header.XferState = 397250963Sachim AAC_FIBSTATE_HOSTOWNED | 398250963Sachim AAC_FIBSTATE_INITIALISED | 399250963Sachim AAC_FIBSTATE_EMPTY | 400250963Sachim AAC_FIBSTATE_FROMHOST | 401250963Sachim AAC_FIBSTATE_REXPECTED | 402250963Sachim AAC_FIBSTATE_NORM | 403250963Sachim AAC_FIBSTATE_ASYNC | 404250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 405250963Sachim fib->Header.Command = SendHostTime; 406250963Sachim *(uint32_t *)fib->data = tv.tv_sec; 407250963Sachim 408250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 409250963Sachim aacraid_release_command(cm); 410250963Sachim } 411250963Sachim 412250963Sachim#if __FreeBSD_version >= 800000 413250963Sachim callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 414250963Sachim#else 415250963Sachim mtx_unlock(&sc->aac_io_lock); 416250963Sachim tv.tv_sec = 30 * 60; 417250963Sachim tv.tv_usec = 0; 418250963Sachim sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 419250963Sachim#endif 420250963Sachim} 421250963Sachim 422250963Sachimvoid 423250963Sachimaacraid_add_event(struct aac_softc *sc, struct aac_event *event) 424250963Sachim{ 425250963Sachim 426250963Sachim switch (event->ev_type & AAC_EVENT_MASK) { 427250963Sachim case AAC_EVENT_CMFREE: 428250963Sachim TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 429250963Sachim break; 430250963Sachim default: 431250963Sachim device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 432250963Sachim event->ev_type); 433250963Sachim break; 434250963Sachim } 435250963Sachim 436250963Sachim return; 437250963Sachim} 438250963Sachim 439250963Sachim/* 440250963Sachim * Request information of container #cid 441250963Sachim */ 442250963Sachimstatic int 443250963Sachimaac_get_container_info(struct aac_softc *sc, struct aac_fib *sync_fib, int cid, 444250963Sachim struct aac_mntinforesp *mir, u_int32_t *uid) 445250963Sachim{ 446250963Sachim struct aac_command *cm; 447250963Sachim struct aac_fib *fib; 448250963Sachim struct aac_mntinfo *mi; 449250963Sachim struct aac_cnt_config *ccfg; 450263340Sachim int rval; 451250963Sachim 452250963Sachim if (sync_fib == NULL) { 453250963Sachim if (aacraid_alloc_command(sc, &cm)) { 454250963Sachim device_printf(sc->aac_dev, 455250963Sachim "Warning, no free command available\n"); 456250963Sachim return (-1); 457250963Sachim } 458250963Sachim fib = cm->cm_fib; 459250963Sachim } else { 460250963Sachim fib = sync_fib; 461250963Sachim } 462250963Sachim 463250963Sachim mi = (struct aac_mntinfo *)&fib->data[0]; 464250963Sachim /* 4KB support?, 64-bit LBA? */ 465250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE) 466250963Sachim mi->Command = VM_NameServeAllBlk; 467250963Sachim else if (sc->flags & AAC_FLAGS_LBA_64BIT) 468250963Sachim mi->Command = VM_NameServe64; 469250963Sachim else 470250963Sachim mi->Command = VM_NameServe; 471250963Sachim mi->MntType = FT_FILESYS; 472250963Sachim mi->MntCount = cid; 473250963Sachim 474250963Sachim if (sync_fib) { 475250963Sachim if (aac_sync_fib(sc, ContainerCommand, 0, fib, 476250963Sachim sizeof(struct aac_mntinfo))) { 477250963Sachim device_printf(sc->aac_dev, "Error probing container %d\n", cid); 478250963Sachim return (-1); 479250963Sachim } 480250963Sachim } else { 481250963Sachim cm->cm_timestamp = time_uptime; 482250963Sachim cm->cm_datalen = 0; 483250963Sachim 484250963Sachim fib->Header.Size = 485250963Sachim sizeof(struct aac_fib_header) + sizeof(struct aac_mntinfo); 486250963Sachim fib->Header.XferState = 487250963Sachim AAC_FIBSTATE_HOSTOWNED | 488250963Sachim AAC_FIBSTATE_INITIALISED | 489250963Sachim AAC_FIBSTATE_EMPTY | 490250963Sachim AAC_FIBSTATE_FROMHOST | 491250963Sachim AAC_FIBSTATE_REXPECTED | 492250963Sachim AAC_FIBSTATE_NORM | 493250963Sachim AAC_FIBSTATE_ASYNC | 494250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 495250963Sachim fib->Header.Command = ContainerCommand; 496250963Sachim if (aacraid_wait_command(cm) != 0) { 497250963Sachim device_printf(sc->aac_dev, "Error probing container %d\n", cid); 498250963Sachim aacraid_release_command(cm); 499250963Sachim return (-1); 500250963Sachim } 501250963Sachim } 502250963Sachim bcopy(&fib->data[0], mir, sizeof(struct aac_mntinforesp)); 503250963Sachim 504250963Sachim /* UID */ 505250963Sachim *uid = cid; 506250963Sachim if (mir->MntTable[0].VolType != CT_NONE && 507250963Sachim !(mir->MntTable[0].ContentState & AAC_FSCS_HIDDEN)) { 508263340Sachim if (!(sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)) { 509263340Sachim mir->MntTable[0].ObjExtension.BlockDevice.BlockSize = 0x200; 510263340Sachim mir->MntTable[0].ObjExtension.BlockDevice.bdLgclPhysMap = 0; 511263340Sachim } 512250963Sachim ccfg = (struct aac_cnt_config *)&fib->data[0]; 513250963Sachim bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 514250963Sachim ccfg->Command = VM_ContainerConfig; 515250963Sachim ccfg->CTCommand.command = CT_CID_TO_32BITS_UID; 516250963Sachim ccfg->CTCommand.param[0] = cid; 517250963Sachim 518250963Sachim if (sync_fib) { 519263340Sachim rval = aac_sync_fib(sc, ContainerCommand, 0, fib, 520263340Sachim sizeof(struct aac_cnt_config)); 521263340Sachim if (rval == 0 && ccfg->Command == ST_OK && 522263340Sachim ccfg->CTCommand.param[0] == CT_OK && 523250963Sachim mir->MntTable[0].VolType != CT_PASSTHRU) 524250963Sachim *uid = ccfg->CTCommand.param[1]; 525250963Sachim } else { 526250963Sachim fib->Header.Size = 527250963Sachim sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config); 528250963Sachim fib->Header.XferState = 529250963Sachim AAC_FIBSTATE_HOSTOWNED | 530250963Sachim AAC_FIBSTATE_INITIALISED | 531250963Sachim AAC_FIBSTATE_EMPTY | 532250963Sachim AAC_FIBSTATE_FROMHOST | 533250963Sachim AAC_FIBSTATE_REXPECTED | 534250963Sachim AAC_FIBSTATE_NORM | 535250963Sachim AAC_FIBSTATE_ASYNC | 536250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 537250963Sachim fib->Header.Command = ContainerCommand; 538263340Sachim rval = aacraid_wait_command(cm); 539263340Sachim if (rval == 0 && ccfg->Command == ST_OK && 540263340Sachim ccfg->CTCommand.param[0] == CT_OK && 541250963Sachim mir->MntTable[0].VolType != CT_PASSTHRU) 542250963Sachim *uid = ccfg->CTCommand.param[1]; 543250963Sachim aacraid_release_command(cm); 544250963Sachim } 545250963Sachim } 546250963Sachim 547250963Sachim return (0); 548250963Sachim} 549250963Sachim 550250963Sachim/* 551250963Sachim * Create a device to represent a new container 552250963Sachim */ 553250963Sachimstatic void 554250963Sachimaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f, 555250963Sachim u_int32_t uid) 556250963Sachim{ 557250963Sachim struct aac_container *co; 558250963Sachim 559250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 560250963Sachim 561250963Sachim /* 562250963Sachim * Check container volume type for validity. Note that many of 563250963Sachim * the possible types may never show up. 564250963Sachim */ 565250963Sachim if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 566250963Sachim co = (struct aac_container *)malloc(sizeof *co, M_AACRAIDBUF, 567250963Sachim M_NOWAIT | M_ZERO); 568250963Sachim if (co == NULL) { 569250963Sachim panic("Out of memory?!"); 570250963Sachim } 571250963Sachim 572250963Sachim co->co_found = f; 573250963Sachim bcopy(&mir->MntTable[0], &co->co_mntobj, 574250963Sachim sizeof(struct aac_mntobj)); 575250963Sachim co->co_uid = uid; 576250963Sachim TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 577250963Sachim } 578250963Sachim} 579250963Sachim 580250963Sachim/* 581250963Sachim * Allocate resources associated with (sc) 582250963Sachim */ 583250963Sachimstatic int 584250963Sachimaac_alloc(struct aac_softc *sc) 585250963Sachim{ 586250963Sachim bus_size_t maxsize; 587250963Sachim 588250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 589250963Sachim 590250963Sachim /* 591250963Sachim * Create DMA tag for mapping buffers into controller-addressable space. 592250963Sachim */ 593250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 594250963Sachim 1, 0, /* algnmnt, boundary */ 595250963Sachim (sc->flags & AAC_FLAGS_SG_64BIT) ? 596250963Sachim BUS_SPACE_MAXADDR : 597250963Sachim BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 598250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 599250963Sachim NULL, NULL, /* filter, filterarg */ 600250963Sachim MAXBSIZE, /* maxsize */ 601250963Sachim sc->aac_sg_tablesize, /* nsegments */ 602250963Sachim MAXBSIZE, /* maxsegsize */ 603250963Sachim BUS_DMA_ALLOCNOW, /* flags */ 604250963Sachim busdma_lock_mutex, /* lockfunc */ 605250963Sachim &sc->aac_io_lock, /* lockfuncarg */ 606250963Sachim &sc->aac_buffer_dmat)) { 607250963Sachim device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 608250963Sachim return (ENOMEM); 609250963Sachim } 610250963Sachim 611250963Sachim /* 612250963Sachim * Create DMA tag for mapping FIBs into controller-addressable space.. 613250963Sachim */ 614250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 615250963Sachim maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 616250963Sachim sizeof(struct aac_fib_xporthdr) + 31); 617250963Sachim else 618250963Sachim maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 31); 619250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 620250963Sachim 1, 0, /* algnmnt, boundary */ 621250963Sachim (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 622250963Sachim BUS_SPACE_MAXADDR_32BIT : 623250963Sachim 0x7fffffff, /* lowaddr */ 624250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 625250963Sachim NULL, NULL, /* filter, filterarg */ 626250963Sachim maxsize, /* maxsize */ 627250963Sachim 1, /* nsegments */ 628250963Sachim maxsize, /* maxsize */ 629250963Sachim 0, /* flags */ 630250963Sachim NULL, NULL, /* No locking needed */ 631250963Sachim &sc->aac_fib_dmat)) { 632250963Sachim device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 633250963Sachim return (ENOMEM); 634250963Sachim } 635250963Sachim 636250963Sachim /* 637250963Sachim * Create DMA tag for the common structure and allocate it. 638250963Sachim */ 639250963Sachim maxsize = sizeof(struct aac_common); 640250963Sachim maxsize += sc->aac_max_fibs * sizeof(u_int32_t); 641250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 642250963Sachim 1, 0, /* algnmnt, boundary */ 643250963Sachim (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 644250963Sachim BUS_SPACE_MAXADDR_32BIT : 645250963Sachim 0x7fffffff, /* lowaddr */ 646250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 647250963Sachim NULL, NULL, /* filter, filterarg */ 648250963Sachim maxsize, /* maxsize */ 649250963Sachim 1, /* nsegments */ 650250963Sachim maxsize, /* maxsegsize */ 651250963Sachim 0, /* flags */ 652250963Sachim NULL, NULL, /* No locking needed */ 653250963Sachim &sc->aac_common_dmat)) { 654250963Sachim device_printf(sc->aac_dev, 655250963Sachim "can't allocate common structure DMA tag\n"); 656250963Sachim return (ENOMEM); 657250963Sachim } 658250963Sachim if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 659250963Sachim BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 660250963Sachim device_printf(sc->aac_dev, "can't allocate common structure\n"); 661250963Sachim return (ENOMEM); 662250963Sachim } 663250963Sachim 664250963Sachim (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 665250963Sachim sc->aac_common, maxsize, 666250963Sachim aac_common_map, sc, 0); 667250963Sachim bzero(sc->aac_common, maxsize); 668250963Sachim 669250963Sachim /* Allocate some FIBs and associated command structs */ 670250963Sachim TAILQ_INIT(&sc->aac_fibmap_tqh); 671250963Sachim sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 672250963Sachim M_AACRAIDBUF, M_WAITOK|M_ZERO); 673250963Sachim mtx_lock(&sc->aac_io_lock); 674250963Sachim while (sc->total_fibs < sc->aac_max_fibs) { 675250963Sachim if (aac_alloc_commands(sc) != 0) 676250963Sachim break; 677250963Sachim } 678250963Sachim mtx_unlock(&sc->aac_io_lock); 679250963Sachim if (sc->total_fibs == 0) 680250963Sachim return (ENOMEM); 681250963Sachim 682250963Sachim return (0); 683250963Sachim} 684250963Sachim 685250963Sachim/* 686250963Sachim * Free all of the resources associated with (sc) 687250963Sachim * 688250963Sachim * Should not be called if the controller is active. 689250963Sachim */ 690250963Sachimvoid 691250963Sachimaacraid_free(struct aac_softc *sc) 692250963Sachim{ 693263340Sachim int i; 694263340Sachim 695250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 696250963Sachim 697250963Sachim /* remove the control device */ 698250963Sachim if (sc->aac_dev_t != NULL) 699250963Sachim destroy_dev(sc->aac_dev_t); 700250963Sachim 701250963Sachim /* throw away any FIB buffers, discard the FIB DMA tag */ 702250963Sachim aac_free_commands(sc); 703250963Sachim if (sc->aac_fib_dmat) 704250963Sachim bus_dma_tag_destroy(sc->aac_fib_dmat); 705250963Sachim 706250963Sachim free(sc->aac_commands, M_AACRAIDBUF); 707250963Sachim 708250963Sachim /* destroy the common area */ 709250963Sachim if (sc->aac_common) { 710250963Sachim bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 711250963Sachim bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 712250963Sachim sc->aac_common_dmamap); 713250963Sachim } 714250963Sachim if (sc->aac_common_dmat) 715250963Sachim bus_dma_tag_destroy(sc->aac_common_dmat); 716250963Sachim 717250963Sachim /* disconnect the interrupt handler */ 718263340Sachim for (i = 0; i < AAC_MAX_MSIX; ++i) { 719263340Sachim if (sc->aac_intr[i]) 720263340Sachim bus_teardown_intr(sc->aac_dev, 721263340Sachim sc->aac_irq[i], sc->aac_intr[i]); 722263340Sachim if (sc->aac_irq[i]) 723263340Sachim bus_release_resource(sc->aac_dev, SYS_RES_IRQ, 724263340Sachim sc->aac_irq_rid[i], sc->aac_irq[i]); 725263340Sachim else 726263340Sachim break; 727263340Sachim } 728263340Sachim if (sc->msi_enabled) 729263340Sachim pci_release_msi(sc->aac_dev); 730250963Sachim 731250963Sachim /* destroy data-transfer DMA tag */ 732250963Sachim if (sc->aac_buffer_dmat) 733250963Sachim bus_dma_tag_destroy(sc->aac_buffer_dmat); 734250963Sachim 735250963Sachim /* destroy the parent DMA tag */ 736250963Sachim if (sc->aac_parent_dmat) 737250963Sachim bus_dma_tag_destroy(sc->aac_parent_dmat); 738250963Sachim 739250963Sachim /* release the register window mapping */ 740250963Sachim if (sc->aac_regs_res0 != NULL) 741250963Sachim bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 742250963Sachim sc->aac_regs_rid0, sc->aac_regs_res0); 743250963Sachim if (sc->aac_regs_res1 != NULL) 744250963Sachim bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 745250963Sachim sc->aac_regs_rid1, sc->aac_regs_res1); 746250963Sachim} 747250963Sachim 748250963Sachim/* 749250963Sachim * Disconnect from the controller completely, in preparation for unload. 750250963Sachim */ 751250963Sachimint 752250963Sachimaacraid_detach(device_t dev) 753250963Sachim{ 754250963Sachim struct aac_softc *sc; 755250963Sachim struct aac_container *co; 756250963Sachim struct aac_sim *sim; 757250963Sachim int error; 758250963Sachim 759250963Sachim sc = device_get_softc(dev); 760250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 761250963Sachim 762250963Sachim#if __FreeBSD_version >= 800000 763250963Sachim callout_drain(&sc->aac_daemontime); 764250963Sachim#else 765250963Sachim untimeout(aac_daemon, (void *)sc, sc->timeout_id); 766250963Sachim#endif 767250963Sachim /* Remove the child containers */ 768250963Sachim while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 769250963Sachim TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 770250963Sachim free(co, M_AACRAIDBUF); 771250963Sachim } 772250963Sachim 773250963Sachim /* Remove the CAM SIMs */ 774250963Sachim while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 775250963Sachim TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 776250963Sachim error = device_delete_child(dev, sim->sim_dev); 777250963Sachim if (error) 778250963Sachim return (error); 779250963Sachim free(sim, M_AACRAIDBUF); 780250963Sachim } 781250963Sachim 782250963Sachim if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 783250963Sachim sc->aifflags |= AAC_AIFFLAGS_EXIT; 784250963Sachim wakeup(sc->aifthread); 785250963Sachim tsleep(sc->aac_dev, PUSER | PCATCH, "aac_dch", 30 * hz); 786250963Sachim } 787250963Sachim 788250963Sachim if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 789250963Sachim panic("Cannot shutdown AIF thread"); 790250963Sachim 791250963Sachim if ((error = aacraid_shutdown(dev))) 792250963Sachim return(error); 793250963Sachim 794250963Sachim EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 795250963Sachim 796250963Sachim aacraid_free(sc); 797250963Sachim 798250963Sachim mtx_destroy(&sc->aac_io_lock); 799250963Sachim 800250963Sachim return(0); 801250963Sachim} 802250963Sachim 803250963Sachim/* 804250963Sachim * Bring the controller down to a dormant state and detach all child devices. 805250963Sachim * 806250963Sachim * This function is called before detach or system shutdown. 807250963Sachim * 808250963Sachim * Note that we can assume that the bioq on the controller is empty, as we won't 809250963Sachim * allow shutdown if any device is open. 810250963Sachim */ 811250963Sachimint 812250963Sachimaacraid_shutdown(device_t dev) 813250963Sachim{ 814250963Sachim struct aac_softc *sc; 815250963Sachim struct aac_fib *fib; 816250963Sachim struct aac_close_command *cc; 817250963Sachim 818250963Sachim sc = device_get_softc(dev); 819250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 820250963Sachim 821250963Sachim sc->aac_state |= AAC_STATE_SUSPEND; 822250963Sachim 823250963Sachim /* 824250963Sachim * Send a Container shutdown followed by a HostShutdown FIB to the 825250963Sachim * controller to convince it that we don't want to talk to it anymore. 826250963Sachim * We've been closed and all I/O completed already 827250963Sachim */ 828250963Sachim device_printf(sc->aac_dev, "shutting down controller..."); 829250963Sachim 830250963Sachim mtx_lock(&sc->aac_io_lock); 831250963Sachim aac_alloc_sync_fib(sc, &fib); 832250963Sachim cc = (struct aac_close_command *)&fib->data[0]; 833250963Sachim 834250963Sachim bzero(cc, sizeof(struct aac_close_command)); 835250963Sachim cc->Command = VM_CloseAll; 836263340Sachim cc->ContainerId = 0xfffffffe; 837250963Sachim if (aac_sync_fib(sc, ContainerCommand, 0, fib, 838250963Sachim sizeof(struct aac_close_command))) 839250963Sachim printf("FAILED.\n"); 840250963Sachim else 841250963Sachim printf("done\n"); 842250963Sachim 843263340Sachim AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT); 844250963Sachim aac_release_sync_fib(sc); 845250963Sachim mtx_unlock(&sc->aac_io_lock); 846250963Sachim 847250963Sachim return(0); 848250963Sachim} 849250963Sachim 850250963Sachim/* 851250963Sachim * Bring the controller to a quiescent state, ready for system suspend. 852250963Sachim */ 853250963Sachimint 854250963Sachimaacraid_suspend(device_t dev) 855250963Sachim{ 856250963Sachim struct aac_softc *sc; 857250963Sachim 858250963Sachim sc = device_get_softc(dev); 859250963Sachim 860250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 861250963Sachim sc->aac_state |= AAC_STATE_SUSPEND; 862250963Sachim 863263340Sachim AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT); 864250963Sachim return(0); 865250963Sachim} 866250963Sachim 867250963Sachim/* 868250963Sachim * Bring the controller back to a state ready for operation. 869250963Sachim */ 870250963Sachimint 871250963Sachimaacraid_resume(device_t dev) 872250963Sachim{ 873250963Sachim struct aac_softc *sc; 874250963Sachim 875250963Sachim sc = device_get_softc(dev); 876250963Sachim 877250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 878250963Sachim sc->aac_state &= ~AAC_STATE_SUSPEND; 879263340Sachim AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT); 880250963Sachim return(0); 881250963Sachim} 882250963Sachim 883250963Sachim/* 884250963Sachim * Interrupt handler for NEW_COMM_TYPE1, NEW_COMM_TYPE2, NEW_COMM_TYPE34 interface. 885250963Sachim */ 886250963Sachimvoid 887250963Sachimaacraid_new_intr_type1(void *arg) 888250963Sachim{ 889263340Sachim struct aac_msix_ctx *ctx; 890250963Sachim struct aac_softc *sc; 891263340Sachim int vector_no; 892250963Sachim struct aac_command *cm; 893250963Sachim struct aac_fib *fib; 894250963Sachim u_int32_t bellbits, bellbits_shifted, index, handle; 895263340Sachim int isFastResponse, isAif, noMoreAif, mode; 896250963Sachim 897263340Sachim ctx = (struct aac_msix_ctx *)arg; 898263340Sachim sc = ctx->sc; 899263340Sachim vector_no = ctx->vector_no; 900250963Sachim 901250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 902250963Sachim mtx_lock(&sc->aac_io_lock); 903263340Sachim 904263340Sachim if (sc->msi_enabled) { 905263340Sachim mode = AAC_INT_MODE_MSI; 906263340Sachim if (vector_no == 0) { 907263340Sachim bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_MSI); 908263340Sachim if (bellbits & 0x40000) 909263340Sachim mode |= AAC_INT_MODE_AIF; 910263340Sachim else if (bellbits & 0x1000) 911263340Sachim mode |= AAC_INT_MODE_SYNC; 912263340Sachim } 913263340Sachim } else { 914263340Sachim mode = AAC_INT_MODE_INTX; 915263340Sachim bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); 916263340Sachim if (bellbits & AAC_DB_RESPONSE_SENT_NS) { 917263340Sachim bellbits = AAC_DB_RESPONSE_SENT_NS; 918263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 919263340Sachim } else { 920263340Sachim bellbits_shifted = (bellbits >> AAC_SRC_ODR_SHIFT); 921263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 922263340Sachim if (bellbits_shifted & AAC_DB_AIF_PENDING) 923263340Sachim mode |= AAC_INT_MODE_AIF; 924263340Sachim else if (bellbits_shifted & AAC_DB_SYNC_COMMAND) 925263340Sachim mode |= AAC_INT_MODE_SYNC; 926263340Sachim } 927263340Sachim /* ODR readback, Prep #238630 */ 928263340Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); 929263340Sachim } 930263340Sachim 931263340Sachim if (mode & AAC_INT_MODE_SYNC) { 932263340Sachim if (sc->aac_sync_cm) { 933263340Sachim cm = sc->aac_sync_cm; 934263340Sachim cm->cm_flags |= AAC_CMD_COMPLETED; 935263340Sachim /* is there a completion handler? */ 936263340Sachim if (cm->cm_complete != NULL) { 937263340Sachim cm->cm_complete(cm); 938263340Sachim } else { 939263340Sachim /* assume that someone is sleeping on this command */ 940263340Sachim wakeup(cm); 941263340Sachim } 942263340Sachim sc->flags &= ~AAC_QUEUE_FRZN; 943263340Sachim sc->aac_sync_cm = NULL; 944263340Sachim } 945263340Sachim mode = 0; 946263340Sachim } 947263340Sachim 948263340Sachim if (mode & AAC_INT_MODE_AIF) { 949263340Sachim if (mode & AAC_INT_MODE_INTX) { 950263340Sachim aac_request_aif(sc); 951263340Sachim mode = 0; 952263340Sachim } 953263340Sachim } 954263340Sachim 955263340Sachim if (mode) { 956250963Sachim /* handle async. status */ 957263340Sachim index = sc->aac_host_rrq_idx[vector_no]; 958250963Sachim for (;;) { 959250963Sachim isFastResponse = isAif = noMoreAif = 0; 960250963Sachim /* remove toggle bit (31) */ 961250963Sachim handle = (sc->aac_common->ac_host_rrq[index] & 0x7fffffff); 962250963Sachim /* check fast response bit (30) */ 963250963Sachim if (handle & 0x40000000) 964250963Sachim isFastResponse = 1; 965250963Sachim /* check AIF bit (23) */ 966250963Sachim else if (handle & 0x00800000) 967250963Sachim isAif = TRUE; 968250963Sachim handle &= 0x0000ffff; 969250963Sachim if (handle == 0) 970250963Sachim break; 971250963Sachim 972250963Sachim cm = sc->aac_commands + (handle - 1); 973250963Sachim fib = cm->cm_fib; 974263340Sachim sc->aac_rrq_outstanding[vector_no]--; 975250963Sachim if (isAif) { 976250963Sachim noMoreAif = (fib->Header.XferState & AAC_FIBSTATE_NOMOREAIF) ? 1:0; 977250963Sachim if (!noMoreAif) 978250963Sachim aac_handle_aif(sc, fib); 979250963Sachim aac_remove_busy(cm); 980250963Sachim aacraid_release_command(cm); 981250963Sachim } else { 982250963Sachim if (isFastResponse) { 983250963Sachim fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 984250963Sachim *((u_int32_t *)(fib->data)) = ST_OK; 985250963Sachim cm->cm_flags |= AAC_CMD_FASTRESP; 986250963Sachim } 987250963Sachim aac_remove_busy(cm); 988250963Sachim aac_unmap_command(cm); 989250963Sachim cm->cm_flags |= AAC_CMD_COMPLETED; 990250963Sachim 991250963Sachim /* is there a completion handler? */ 992250963Sachim if (cm->cm_complete != NULL) { 993250963Sachim cm->cm_complete(cm); 994250963Sachim } else { 995250963Sachim /* assume that someone is sleeping on this command */ 996250963Sachim wakeup(cm); 997250963Sachim } 998250963Sachim sc->flags &= ~AAC_QUEUE_FRZN; 999250963Sachim } 1000250963Sachim 1001250963Sachim sc->aac_common->ac_host_rrq[index++] = 0; 1002263340Sachim if (index == (vector_no + 1) * sc->aac_vector_cap) 1003263340Sachim index = vector_no * sc->aac_vector_cap; 1004263340Sachim sc->aac_host_rrq_idx[vector_no] = index; 1005250963Sachim 1006250963Sachim if ((isAif && !noMoreAif) || sc->aif_pending) 1007250963Sachim aac_request_aif(sc); 1008250963Sachim } 1009250963Sachim } 1010250963Sachim 1011263340Sachim if (mode & AAC_INT_MODE_AIF) { 1012263340Sachim aac_request_aif(sc); 1013263340Sachim AAC_ACCESS_DEVREG(sc, AAC_CLEAR_AIF_BIT); 1014263340Sachim mode = 0; 1015263340Sachim } 1016263340Sachim 1017250963Sachim /* see if we can start some more I/O */ 1018250963Sachim if ((sc->flags & AAC_QUEUE_FRZN) == 0) 1019250963Sachim aacraid_startio(sc); 1020250963Sachim mtx_unlock(&sc->aac_io_lock); 1021250963Sachim} 1022250963Sachim 1023250963Sachim/* 1024250963Sachim * Handle notification of one or more FIBs coming from the controller. 1025250963Sachim */ 1026250963Sachimstatic void 1027250963Sachimaac_command_thread(struct aac_softc *sc) 1028250963Sachim{ 1029250963Sachim int retval; 1030250963Sachim 1031250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1032250963Sachim 1033250963Sachim mtx_lock(&sc->aac_io_lock); 1034250963Sachim sc->aifflags = AAC_AIFFLAGS_RUNNING; 1035250963Sachim 1036250963Sachim while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1037250963Sachim 1038250963Sachim retval = 0; 1039250963Sachim if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1040250963Sachim retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1041250963Sachim "aacraid_aifthd", AAC_PERIODIC_INTERVAL * hz); 1042250963Sachim 1043250963Sachim /* 1044250963Sachim * First see if any FIBs need to be allocated. This needs 1045250963Sachim * to be called without the driver lock because contigmalloc 1046250963Sachim * will grab Giant, and would result in an LOR. 1047250963Sachim */ 1048250963Sachim if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1049250963Sachim aac_alloc_commands(sc); 1050250963Sachim sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1051250963Sachim aacraid_startio(sc); 1052250963Sachim } 1053250963Sachim 1054250963Sachim /* 1055250963Sachim * While we're here, check to see if any commands are stuck. 1056250963Sachim * This is pretty low-priority, so it's ok if it doesn't 1057250963Sachim * always fire. 1058250963Sachim */ 1059250963Sachim if (retval == EWOULDBLOCK) 1060250963Sachim aac_timeout(sc); 1061250963Sachim 1062250963Sachim /* Check the hardware printf message buffer */ 1063250963Sachim if (sc->aac_common->ac_printf[0] != 0) 1064250963Sachim aac_print_printf(sc); 1065250963Sachim } 1066250963Sachim sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1067250963Sachim mtx_unlock(&sc->aac_io_lock); 1068250963Sachim wakeup(sc->aac_dev); 1069250963Sachim 1070250963Sachim aac_kthread_exit(0); 1071250963Sachim} 1072250963Sachim 1073250963Sachim/* 1074250963Sachim * Submit a command to the controller, return when it completes. 1075250963Sachim * XXX This is very dangerous! If the card has gone out to lunch, we could 1076250963Sachim * be stuck here forever. At the same time, signals are not caught 1077250963Sachim * because there is a risk that a signal could wakeup the sleep before 1078250963Sachim * the card has a chance to complete the command. Since there is no way 1079250963Sachim * to cancel a command that is in progress, we can't protect against the 1080250963Sachim * card completing a command late and spamming the command and data 1081250963Sachim * memory. So, we are held hostage until the command completes. 1082250963Sachim */ 1083250963Sachimint 1084250963Sachimaacraid_wait_command(struct aac_command *cm) 1085250963Sachim{ 1086250963Sachim struct aac_softc *sc; 1087250963Sachim int error; 1088250963Sachim 1089250963Sachim sc = cm->cm_sc; 1090250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1091250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1092250963Sachim 1093250963Sachim /* Put the command on the ready queue and get things going */ 1094250963Sachim aac_enqueue_ready(cm); 1095250963Sachim aacraid_startio(sc); 1096250963Sachim error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacraid_wait", 0); 1097250963Sachim return(error); 1098250963Sachim} 1099250963Sachim 1100250963Sachim/* 1101250963Sachim *Command Buffer Management 1102250963Sachim */ 1103250963Sachim 1104250963Sachim/* 1105250963Sachim * Allocate a command. 1106250963Sachim */ 1107250963Sachimint 1108250963Sachimaacraid_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1109250963Sachim{ 1110250963Sachim struct aac_command *cm; 1111250963Sachim 1112250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1113250963Sachim 1114250963Sachim if ((cm = aac_dequeue_free(sc)) == NULL) { 1115250963Sachim if (sc->total_fibs < sc->aac_max_fibs) { 1116250963Sachim sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1117250963Sachim wakeup(sc->aifthread); 1118250963Sachim } 1119250963Sachim return (EBUSY); 1120250963Sachim } 1121250963Sachim 1122250963Sachim *cmp = cm; 1123250963Sachim return(0); 1124250963Sachim} 1125250963Sachim 1126250963Sachim/* 1127250963Sachim * Release a command back to the freelist. 1128250963Sachim */ 1129250963Sachimvoid 1130250963Sachimaacraid_release_command(struct aac_command *cm) 1131250963Sachim{ 1132250963Sachim struct aac_event *event; 1133250963Sachim struct aac_softc *sc; 1134250963Sachim 1135250963Sachim sc = cm->cm_sc; 1136250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1137250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1138250963Sachim 1139250963Sachim /* (re)initialize the command/FIB */ 1140250963Sachim cm->cm_sgtable = NULL; 1141250963Sachim cm->cm_flags = 0; 1142250963Sachim cm->cm_complete = NULL; 1143250963Sachim cm->cm_ccb = NULL; 1144250963Sachim cm->cm_passthr_dmat = 0; 1145250963Sachim cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1146250963Sachim cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1147250963Sachim cm->cm_fib->Header.Unused = 0; 1148250963Sachim cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 1149250963Sachim 1150250963Sachim /* 1151250963Sachim * These are duplicated in aac_start to cover the case where an 1152250963Sachim * intermediate stage may have destroyed them. They're left 1153250963Sachim * initialized here for debugging purposes only. 1154250963Sachim */ 1155250963Sachim cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1156250963Sachim cm->cm_fib->Header.Handle = 0; 1157250963Sachim 1158250963Sachim aac_enqueue_free(cm); 1159250963Sachim 1160250963Sachim /* 1161250963Sachim * Dequeue all events so that there's no risk of events getting 1162250963Sachim * stranded. 1163250963Sachim */ 1164250963Sachim while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 1165250963Sachim TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1166250963Sachim event->ev_callback(sc, event, event->ev_arg); 1167250963Sachim } 1168250963Sachim} 1169250963Sachim 1170250963Sachim/* 1171250963Sachim * Map helper for command/FIB allocation. 1172250963Sachim */ 1173250963Sachimstatic void 1174250963Sachimaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1175250963Sachim{ 1176250963Sachim uint64_t *fibphys; 1177250963Sachim 1178250963Sachim fibphys = (uint64_t *)arg; 1179250963Sachim 1180250963Sachim *fibphys = segs[0].ds_addr; 1181250963Sachim} 1182250963Sachim 1183250963Sachim/* 1184250963Sachim * Allocate and initialize commands/FIBs for this adapter. 1185250963Sachim */ 1186250963Sachimstatic int 1187250963Sachimaac_alloc_commands(struct aac_softc *sc) 1188250963Sachim{ 1189250963Sachim struct aac_command *cm; 1190250963Sachim struct aac_fibmap *fm; 1191250963Sachim uint64_t fibphys; 1192250963Sachim int i, error; 1193250963Sachim u_int32_t maxsize; 1194250963Sachim 1195250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1196250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1197250963Sachim 1198250963Sachim if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1199250963Sachim return (ENOMEM); 1200250963Sachim 1201250963Sachim fm = malloc(sizeof(struct aac_fibmap), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1202250963Sachim if (fm == NULL) 1203250963Sachim return (ENOMEM); 1204250963Sachim 1205250963Sachim mtx_unlock(&sc->aac_io_lock); 1206250963Sachim /* allocate the FIBs in DMAable memory and load them */ 1207250963Sachim if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1208250963Sachim BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1209250963Sachim device_printf(sc->aac_dev, 1210250963Sachim "Not enough contiguous memory available.\n"); 1211250963Sachim free(fm, M_AACRAIDBUF); 1212250963Sachim mtx_lock(&sc->aac_io_lock); 1213250963Sachim return (ENOMEM); 1214250963Sachim } 1215250963Sachim 1216250963Sachim maxsize = sc->aac_max_fib_size + 31; 1217250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1218250963Sachim maxsize += sizeof(struct aac_fib_xporthdr); 1219250963Sachim /* Ignore errors since this doesn't bounce */ 1220250963Sachim (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1221250963Sachim sc->aac_max_fibs_alloc * maxsize, 1222250963Sachim aac_map_command_helper, &fibphys, 0); 1223250963Sachim mtx_lock(&sc->aac_io_lock); 1224250963Sachim 1225250963Sachim /* initialize constant fields in the command structure */ 1226250963Sachim bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * maxsize); 1227250963Sachim for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1228250963Sachim cm = sc->aac_commands + sc->total_fibs; 1229250963Sachim fm->aac_commands = cm; 1230250963Sachim cm->cm_sc = sc; 1231250963Sachim cm->cm_fib = (struct aac_fib *) 1232250963Sachim ((u_int8_t *)fm->aac_fibs + i * maxsize); 1233250963Sachim cm->cm_fibphys = fibphys + i * maxsize; 1234250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1235250963Sachim u_int64_t fibphys_aligned; 1236250963Sachim fibphys_aligned = 1237250963Sachim (cm->cm_fibphys + sizeof(struct aac_fib_xporthdr) + 31) & ~31; 1238250963Sachim cm->cm_fib = (struct aac_fib *) 1239250963Sachim ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1240250963Sachim cm->cm_fibphys = fibphys_aligned; 1241250963Sachim } else { 1242250963Sachim u_int64_t fibphys_aligned; 1243250963Sachim fibphys_aligned = (cm->cm_fibphys + 31) & ~31; 1244250963Sachim cm->cm_fib = (struct aac_fib *) 1245250963Sachim ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1246250963Sachim cm->cm_fibphys = fibphys_aligned; 1247250963Sachim } 1248250963Sachim cm->cm_index = sc->total_fibs; 1249250963Sachim 1250250963Sachim if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1251250963Sachim &cm->cm_datamap)) != 0) 1252250963Sachim break; 1253250963Sachim if (sc->aac_max_fibs <= 1 || sc->aac_max_fibs - sc->total_fibs > 1) 1254250963Sachim aacraid_release_command(cm); 1255250963Sachim sc->total_fibs++; 1256250963Sachim } 1257250963Sachim 1258250963Sachim if (i > 0) { 1259250963Sachim TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1260250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1261250963Sachim return (0); 1262250963Sachim } 1263250963Sachim 1264250963Sachim bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1265250963Sachim bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1266250963Sachim free(fm, M_AACRAIDBUF); 1267250963Sachim return (ENOMEM); 1268250963Sachim} 1269250963Sachim 1270250963Sachim/* 1271250963Sachim * Free FIBs owned by this adapter. 1272250963Sachim */ 1273250963Sachimstatic void 1274250963Sachimaac_free_commands(struct aac_softc *sc) 1275250963Sachim{ 1276250963Sachim struct aac_fibmap *fm; 1277250963Sachim struct aac_command *cm; 1278250963Sachim int i; 1279250963Sachim 1280250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1281250963Sachim 1282250963Sachim while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1283250963Sachim 1284250963Sachim TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1285250963Sachim /* 1286250963Sachim * We check against total_fibs to handle partially 1287250963Sachim * allocated blocks. 1288250963Sachim */ 1289250963Sachim for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1290250963Sachim cm = fm->aac_commands + i; 1291250963Sachim bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1292250963Sachim } 1293250963Sachim bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1294250963Sachim bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1295250963Sachim free(fm, M_AACRAIDBUF); 1296250963Sachim } 1297250963Sachim} 1298250963Sachim 1299250963Sachim/* 1300250963Sachim * Command-mapping helper function - populate this command's s/g table. 1301250963Sachim */ 1302250963Sachimvoid 1303250963Sachimaacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1304250963Sachim{ 1305250963Sachim struct aac_softc *sc; 1306250963Sachim struct aac_command *cm; 1307250963Sachim struct aac_fib *fib; 1308250963Sachim int i; 1309250963Sachim 1310250963Sachim cm = (struct aac_command *)arg; 1311250963Sachim sc = cm->cm_sc; 1312250963Sachim fib = cm->cm_fib; 1313250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "nseg %d", nseg); 1314250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 1315250963Sachim 1316250963Sachim /* copy into the FIB */ 1317250963Sachim if (cm->cm_sgtable != NULL) { 1318250963Sachim if (fib->Header.Command == RawIo2) { 1319250963Sachim struct aac_raw_io2 *raw; 1320250963Sachim struct aac_sge_ieee1212 *sg; 1321250963Sachim u_int32_t min_size = PAGE_SIZE, cur_size; 1322250963Sachim int conformable = TRUE; 1323250963Sachim 1324250963Sachim raw = (struct aac_raw_io2 *)&fib->data[0]; 1325250963Sachim sg = (struct aac_sge_ieee1212 *)cm->cm_sgtable; 1326250963Sachim raw->sgeCnt = nseg; 1327250963Sachim 1328250963Sachim for (i = 0; i < nseg; i++) { 1329250963Sachim cur_size = segs[i].ds_len; 1330250963Sachim sg[i].addrHigh = 0; 1331250963Sachim *(bus_addr_t *)&sg[i].addrLow = segs[i].ds_addr; 1332250963Sachim sg[i].length = cur_size; 1333250963Sachim sg[i].flags = 0; 1334250963Sachim if (i == 0) { 1335250963Sachim raw->sgeFirstSize = cur_size; 1336250963Sachim } else if (i == 1) { 1337250963Sachim raw->sgeNominalSize = cur_size; 1338250963Sachim min_size = cur_size; 1339250963Sachim } else if ((i+1) < nseg && 1340250963Sachim cur_size != raw->sgeNominalSize) { 1341250963Sachim conformable = FALSE; 1342250963Sachim if (cur_size < min_size) 1343250963Sachim min_size = cur_size; 1344250963Sachim } 1345250963Sachim } 1346250963Sachim 1347250963Sachim /* not conformable: evaluate required sg elements */ 1348250963Sachim if (!conformable) { 1349250963Sachim int j, err_found, nseg_new = nseg; 1350250963Sachim for (i = min_size / PAGE_SIZE; i >= 1; --i) { 1351250963Sachim err_found = FALSE; 1352250963Sachim nseg_new = 2; 1353250963Sachim for (j = 1; j < nseg - 1; ++j) { 1354250963Sachim if (sg[j].length % (i*PAGE_SIZE)) { 1355250963Sachim err_found = TRUE; 1356250963Sachim break; 1357250963Sachim } 1358250963Sachim nseg_new += (sg[j].length / (i*PAGE_SIZE)); 1359250963Sachim } 1360250963Sachim if (!err_found) 1361250963Sachim break; 1362250963Sachim } 1363250963Sachim if (i>0 && nseg_new<=sc->aac_sg_tablesize && 1364250963Sachim !(sc->hint_flags & 4)) 1365250963Sachim nseg = aac_convert_sgraw2(sc, 1366250963Sachim raw, i, nseg, nseg_new); 1367250963Sachim } else { 1368250963Sachim raw->flags |= RIO2_SGL_CONFORMANT; 1369250963Sachim } 1370250963Sachim 1371250963Sachim /* update the FIB size for the s/g count */ 1372250963Sachim fib->Header.Size += nseg * 1373250963Sachim sizeof(struct aac_sge_ieee1212); 1374250963Sachim 1375250963Sachim } else if (fib->Header.Command == RawIo) { 1376250963Sachim struct aac_sg_tableraw *sg; 1377250963Sachim sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1378250963Sachim sg->SgCount = nseg; 1379250963Sachim for (i = 0; i < nseg; i++) { 1380250963Sachim sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1381250963Sachim sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1382250963Sachim sg->SgEntryRaw[i].Next = 0; 1383250963Sachim sg->SgEntryRaw[i].Prev = 0; 1384250963Sachim sg->SgEntryRaw[i].Flags = 0; 1385250963Sachim } 1386250963Sachim /* update the FIB size for the s/g count */ 1387250963Sachim fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1388250963Sachim } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1389250963Sachim struct aac_sg_table *sg; 1390250963Sachim sg = cm->cm_sgtable; 1391250963Sachim sg->SgCount = nseg; 1392250963Sachim for (i = 0; i < nseg; i++) { 1393250963Sachim sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1394250963Sachim sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1395250963Sachim } 1396250963Sachim /* update the FIB size for the s/g count */ 1397250963Sachim fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1398250963Sachim } else { 1399250963Sachim struct aac_sg_table64 *sg; 1400250963Sachim sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1401250963Sachim sg->SgCount = nseg; 1402250963Sachim for (i = 0; i < nseg; i++) { 1403250963Sachim sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1404250963Sachim sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1405250963Sachim } 1406250963Sachim /* update the FIB size for the s/g count */ 1407250963Sachim fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1408250963Sachim } 1409250963Sachim } 1410250963Sachim 1411250963Sachim /* Fix up the address values in the FIB. Use the command array index 1412250963Sachim * instead of a pointer since these fields are only 32 bits. Shift 1413250963Sachim * the SenderFibAddress over to make room for the fast response bit 1414250963Sachim * and for the AIF bit 1415250963Sachim */ 1416250963Sachim cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1417250963Sachim cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1418250963Sachim 1419250963Sachim /* save a pointer to the command for speedy reverse-lookup */ 1420250963Sachim cm->cm_fib->Header.Handle += cm->cm_index + 1; 1421250963Sachim 1422250963Sachim if (cm->cm_passthr_dmat == 0) { 1423250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 1424250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1425250963Sachim BUS_DMASYNC_PREREAD); 1426250963Sachim if (cm->cm_flags & AAC_CMD_DATAOUT) 1427250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1428250963Sachim BUS_DMASYNC_PREWRITE); 1429250963Sachim } 1430250963Sachim 1431250963Sachim cm->cm_flags |= AAC_CMD_MAPPED; 1432250963Sachim 1433250963Sachim if (sc->flags & AAC_FLAGS_SYNC_MODE) { 1434250963Sachim u_int32_t wait = 0; 1435250963Sachim aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, &wait, NULL); 1436250963Sachim } else if (cm->cm_flags & AAC_CMD_WAIT) { 1437250963Sachim aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, NULL, NULL); 1438250963Sachim } else { 1439250963Sachim int count = 10000000L; 1440250963Sachim while (AAC_SEND_COMMAND(sc, cm) != 0) { 1441250963Sachim if (--count == 0) { 1442250963Sachim aac_unmap_command(cm); 1443250963Sachim sc->flags |= AAC_QUEUE_FRZN; 1444250963Sachim aac_requeue_ready(cm); 1445250963Sachim } 1446250963Sachim DELAY(5); /* wait 5 usec. */ 1447250963Sachim } 1448250963Sachim } 1449250963Sachim} 1450250963Sachim 1451250963Sachim 1452250963Sachimstatic int 1453250963Sachimaac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 1454250963Sachim int pages, int nseg, int nseg_new) 1455250963Sachim{ 1456250963Sachim struct aac_sge_ieee1212 *sge; 1457250963Sachim int i, j, pos; 1458250963Sachim u_int32_t addr_low; 1459250963Sachim 1460250963Sachim sge = malloc(nseg_new * sizeof(struct aac_sge_ieee1212), 1461250963Sachim M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1462250963Sachim if (sge == NULL) 1463250963Sachim return nseg; 1464250963Sachim 1465250963Sachim for (i = 1, pos = 1; i < nseg - 1; ++i) { 1466250963Sachim for (j = 0; j < raw->sge[i].length / (pages*PAGE_SIZE); ++j) { 1467250963Sachim addr_low = raw->sge[i].addrLow + j * pages * PAGE_SIZE; 1468250963Sachim sge[pos].addrLow = addr_low; 1469250963Sachim sge[pos].addrHigh = raw->sge[i].addrHigh; 1470250963Sachim if (addr_low < raw->sge[i].addrLow) 1471250963Sachim sge[pos].addrHigh++; 1472250963Sachim sge[pos].length = pages * PAGE_SIZE; 1473250963Sachim sge[pos].flags = 0; 1474250963Sachim pos++; 1475250963Sachim } 1476250963Sachim } 1477250963Sachim sge[pos] = raw->sge[nseg-1]; 1478250963Sachim for (i = 1; i < nseg_new; ++i) 1479250963Sachim raw->sge[i] = sge[i]; 1480250963Sachim 1481250963Sachim free(sge, M_AACRAIDBUF); 1482250963Sachim raw->sgeCnt = nseg_new; 1483250963Sachim raw->flags |= RIO2_SGL_CONFORMANT; 1484250963Sachim raw->sgeNominalSize = pages * PAGE_SIZE; 1485250963Sachim return nseg_new; 1486250963Sachim} 1487250963Sachim 1488250963Sachim 1489250963Sachim/* 1490250963Sachim * Unmap a command from controller-visible space. 1491250963Sachim */ 1492250963Sachimstatic void 1493250963Sachimaac_unmap_command(struct aac_command *cm) 1494250963Sachim{ 1495250963Sachim struct aac_softc *sc; 1496250963Sachim 1497250963Sachim sc = cm->cm_sc; 1498250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1499250963Sachim 1500250963Sachim if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1501250963Sachim return; 1502250963Sachim 1503250963Sachim if (cm->cm_datalen != 0 && cm->cm_passthr_dmat == 0) { 1504250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 1505250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1506250963Sachim BUS_DMASYNC_POSTREAD); 1507250963Sachim if (cm->cm_flags & AAC_CMD_DATAOUT) 1508250963Sachim bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1509250963Sachim BUS_DMASYNC_POSTWRITE); 1510250963Sachim 1511250963Sachim bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1512250963Sachim } 1513250963Sachim cm->cm_flags &= ~AAC_CMD_MAPPED; 1514250963Sachim} 1515250963Sachim 1516250963Sachim/* 1517250963Sachim * Hardware Interface 1518250963Sachim */ 1519250963Sachim 1520250963Sachim/* 1521250963Sachim * Initialize the adapter. 1522250963Sachim */ 1523250963Sachimstatic void 1524250963Sachimaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1525250963Sachim{ 1526250963Sachim struct aac_softc *sc; 1527250963Sachim 1528250963Sachim sc = (struct aac_softc *)arg; 1529250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1530250963Sachim 1531250963Sachim sc->aac_common_busaddr = segs[0].ds_addr; 1532250963Sachim} 1533250963Sachim 1534250963Sachimstatic int 1535250963Sachimaac_check_firmware(struct aac_softc *sc) 1536250963Sachim{ 1537250963Sachim u_int32_t code, major, minor, maxsize; 1538263340Sachim u_int32_t options = 0, atu_size = 0, status, waitCount; 1539250963Sachim time_t then; 1540250963Sachim 1541250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1542263340Sachim 1543263340Sachim /* check if flash update is running */ 1544263340Sachim if (AAC_GET_FWSTATUS(sc) & AAC_FLASH_UPD_PENDING) { 1545263340Sachim then = time_uptime; 1546263340Sachim do { 1547263340Sachim code = AAC_GET_FWSTATUS(sc); 1548263340Sachim if (time_uptime > (then + AAC_FWUPD_TIMEOUT)) { 1549263340Sachim device_printf(sc->aac_dev, 1550263340Sachim "FATAL: controller not coming ready, " 1551263340Sachim "status %x\n", code); 1552263340Sachim return(ENXIO); 1553263340Sachim } 1554263340Sachim } while (!(code & AAC_FLASH_UPD_SUCCESS) && !(code & AAC_FLASH_UPD_FAILED)); 1555263340Sachim /* 1556263340Sachim * Delay 10 seconds. Because right now FW is doing a soft reset, 1557263340Sachim * do not read scratch pad register at this time 1558263340Sachim */ 1559263340Sachim waitCount = 10 * 10000; 1560263340Sachim while (waitCount) { 1561263340Sachim DELAY(100); /* delay 100 microseconds */ 1562263340Sachim waitCount--; 1563263340Sachim } 1564263340Sachim } 1565263340Sachim 1566250963Sachim /* 1567250963Sachim * Wait for the adapter to come ready. 1568250963Sachim */ 1569250963Sachim then = time_uptime; 1570250963Sachim do { 1571250963Sachim code = AAC_GET_FWSTATUS(sc); 1572250963Sachim if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1573250963Sachim device_printf(sc->aac_dev, 1574250963Sachim "FATAL: controller not coming ready, " 1575250963Sachim "status %x\n", code); 1576250963Sachim return(ENXIO); 1577250963Sachim } 1578263340Sachim } while (!(code & AAC_UP_AND_RUNNING) || code == 0xffffffff); 1579250963Sachim 1580250963Sachim /* 1581250963Sachim * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1582250963Sachim * firmware version 1.x are not compatible with this driver. 1583250963Sachim */ 1584250963Sachim if (sc->flags & AAC_FLAGS_PERC2QC) { 1585250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1586250963Sachim NULL, NULL)) { 1587250963Sachim device_printf(sc->aac_dev, 1588250963Sachim "Error reading firmware version\n"); 1589250963Sachim return (EIO); 1590250963Sachim } 1591250963Sachim 1592250963Sachim /* These numbers are stored as ASCII! */ 1593250963Sachim major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1594250963Sachim minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1595250963Sachim if (major == 1) { 1596250963Sachim device_printf(sc->aac_dev, 1597250963Sachim "Firmware version %d.%d is not supported.\n", 1598250963Sachim major, minor); 1599250963Sachim return (EINVAL); 1600250963Sachim } 1601250963Sachim } 1602250963Sachim /* 1603250963Sachim * Retrieve the capabilities/supported options word so we know what 1604250963Sachim * work-arounds to enable. Some firmware revs don't support this 1605250963Sachim * command. 1606250963Sachim */ 1607250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status, NULL)) { 1608250963Sachim if (status != AAC_SRB_STS_INVALID_REQUEST) { 1609250963Sachim device_printf(sc->aac_dev, 1610250963Sachim "RequestAdapterInfo failed\n"); 1611250963Sachim return (EIO); 1612250963Sachim } 1613250963Sachim } else { 1614250963Sachim options = AAC_GET_MAILBOX(sc, 1); 1615250963Sachim atu_size = AAC_GET_MAILBOX(sc, 2); 1616250963Sachim sc->supported_options = options; 1617250963Sachim 1618250963Sachim if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1619250963Sachim (sc->flags & AAC_FLAGS_NO4GB) == 0) 1620250963Sachim sc->flags |= AAC_FLAGS_4GB_WINDOW; 1621250963Sachim if (options & AAC_SUPPORTED_NONDASD) 1622250963Sachim sc->flags |= AAC_FLAGS_ENABLE_CAM; 1623250963Sachim if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1624250963Sachim && (sizeof(bus_addr_t) > 4) 1625250963Sachim && (sc->hint_flags & 0x1)) { 1626250963Sachim device_printf(sc->aac_dev, 1627250963Sachim "Enabling 64-bit address support\n"); 1628250963Sachim sc->flags |= AAC_FLAGS_SG_64BIT; 1629250963Sachim } 1630250963Sachim if (sc->aac_if.aif_send_command) { 1631250963Sachim if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) || 1632250963Sachim (options & AAC_SUPPORTED_NEW_COMM_TYPE4)) 1633250963Sachim sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34; 1634250963Sachim else if (options & AAC_SUPPORTED_NEW_COMM_TYPE1) 1635250963Sachim sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE1; 1636250963Sachim else if (options & AAC_SUPPORTED_NEW_COMM_TYPE2) 1637250963Sachim sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2; 1638250963Sachim } 1639250963Sachim if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1640250963Sachim sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1641250963Sachim } 1642250963Sachim 1643250963Sachim if (!(sc->flags & AAC_FLAGS_NEW_COMM)) { 1644250963Sachim device_printf(sc->aac_dev, "Communication interface not supported!\n"); 1645250963Sachim return (ENXIO); 1646250963Sachim } 1647250963Sachim 1648250963Sachim if (sc->hint_flags & 2) { 1649250963Sachim device_printf(sc->aac_dev, 1650250963Sachim "Sync. mode enforced by driver parameter. This will cause a significant performance decrease!\n"); 1651250963Sachim sc->flags |= AAC_FLAGS_SYNC_MODE; 1652250963Sachim } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE34) { 1653250963Sachim device_printf(sc->aac_dev, 1654250963Sachim "Async. mode not supported by current driver, sync. mode enforced.\nPlease update driver to get full performance.\n"); 1655250963Sachim sc->flags |= AAC_FLAGS_SYNC_MODE; 1656250963Sachim } 1657250963Sachim 1658250963Sachim /* Check for broken hardware that does a lower number of commands */ 1659250963Sachim sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1660250963Sachim 1661250963Sachim /* Remap mem. resource, if required */ 1662250963Sachim if (atu_size > rman_get_size(sc->aac_regs_res0)) { 1663250963Sachim bus_release_resource( 1664250963Sachim sc->aac_dev, SYS_RES_MEMORY, 1665250963Sachim sc->aac_regs_rid0, sc->aac_regs_res0); 1666250963Sachim sc->aac_regs_res0 = bus_alloc_resource( 1667250963Sachim sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid0, 1668250963Sachim 0ul, ~0ul, atu_size, RF_ACTIVE); 1669250963Sachim if (sc->aac_regs_res0 == NULL) { 1670250963Sachim sc->aac_regs_res0 = bus_alloc_resource_any( 1671250963Sachim sc->aac_dev, SYS_RES_MEMORY, 1672250963Sachim &sc->aac_regs_rid0, RF_ACTIVE); 1673250963Sachim if (sc->aac_regs_res0 == NULL) { 1674250963Sachim device_printf(sc->aac_dev, 1675250963Sachim "couldn't allocate register window\n"); 1676250963Sachim return (ENXIO); 1677250963Sachim } 1678250963Sachim } 1679250963Sachim sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); 1680250963Sachim sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); 1681250963Sachim } 1682250963Sachim 1683250963Sachim /* Read preferred settings */ 1684250963Sachim sc->aac_max_fib_size = sizeof(struct aac_fib); 1685250963Sachim sc->aac_max_sectors = 128; /* 64KB */ 1686250963Sachim sc->aac_max_aif = 1; 1687250963Sachim if (sc->flags & AAC_FLAGS_SG_64BIT) 1688250963Sachim sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1689250963Sachim - sizeof(struct aac_blockwrite64)) 1690250963Sachim / sizeof(struct aac_sg_entry64); 1691250963Sachim else 1692250963Sachim sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1693250963Sachim - sizeof(struct aac_blockwrite)) 1694250963Sachim / sizeof(struct aac_sg_entry); 1695250963Sachim 1696250963Sachim if (!aacraid_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL, NULL)) { 1697250963Sachim options = AAC_GET_MAILBOX(sc, 1); 1698250963Sachim sc->aac_max_fib_size = (options & 0xFFFF); 1699250963Sachim sc->aac_max_sectors = (options >> 16) << 1; 1700250963Sachim options = AAC_GET_MAILBOX(sc, 2); 1701250963Sachim sc->aac_sg_tablesize = (options >> 16); 1702250963Sachim options = AAC_GET_MAILBOX(sc, 3); 1703263340Sachim sc->aac_max_fibs = ((options >> 16) & 0xFFFF); 1704263340Sachim if (sc->aac_max_fibs == 0 || sc->aac_hwif != AAC_HWIF_SRCV) 1705263340Sachim sc->aac_max_fibs = (options & 0xFFFF); 1706250963Sachim options = AAC_GET_MAILBOX(sc, 4); 1707250963Sachim sc->aac_max_aif = (options & 0xFFFF); 1708263340Sachim options = AAC_GET_MAILBOX(sc, 5); 1709263340Sachim sc->aac_max_msix =(sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) ? options : 0; 1710250963Sachim } 1711250963Sachim 1712250963Sachim maxsize = sc->aac_max_fib_size + 31; 1713250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1714250963Sachim maxsize += sizeof(struct aac_fib_xporthdr); 1715250963Sachim if (maxsize > PAGE_SIZE) { 1716250963Sachim sc->aac_max_fib_size -= (maxsize - PAGE_SIZE); 1717250963Sachim maxsize = PAGE_SIZE; 1718250963Sachim } 1719250963Sachim sc->aac_max_fibs_alloc = PAGE_SIZE / maxsize; 1720250963Sachim 1721250963Sachim if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1722250963Sachim sc->flags |= AAC_FLAGS_RAW_IO; 1723250963Sachim device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1724250963Sachim } 1725250963Sachim if ((sc->flags & AAC_FLAGS_RAW_IO) && 1726250963Sachim (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1727250963Sachim sc->flags |= AAC_FLAGS_LBA_64BIT; 1728250963Sachim device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1729250963Sachim } 1730250963Sachim 1731263340Sachim#ifdef AACRAID_DEBUG 1732250963Sachim aacraid_get_fw_debug_buffer(sc); 1733263340Sachim#endif 1734250963Sachim return (0); 1735250963Sachim} 1736250963Sachim 1737250963Sachimstatic int 1738250963Sachimaac_init(struct aac_softc *sc) 1739250963Sachim{ 1740250963Sachim struct aac_adapter_init *ip; 1741263340Sachim int i, error; 1742250963Sachim 1743250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1744250963Sachim 1745250963Sachim /* reset rrq index */ 1746263340Sachim sc->aac_fibs_pushed_no = 0; 1747263340Sachim for (i = 0; i < sc->aac_max_msix; i++) 1748263340Sachim sc->aac_host_rrq_idx[i] = i * sc->aac_vector_cap; 1749250963Sachim 1750250963Sachim /* 1751250963Sachim * Fill in the init structure. This tells the adapter about the 1752250963Sachim * physical location of various important shared data structures. 1753250963Sachim */ 1754250963Sachim ip = &sc->aac_common->ac_init; 1755250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1756250963Sachim if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1757250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1758250963Sachim sc->flags |= AAC_FLAGS_RAW_IO; 1759250963Sachim } 1760263340Sachim ip->NoOfMSIXVectors = sc->aac_max_msix; 1761250963Sachim 1762250963Sachim ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1763250963Sachim offsetof(struct aac_common, ac_fibs); 1764250963Sachim ip->AdapterFibsVirtualAddress = 0; 1765250963Sachim ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1766250963Sachim ip->AdapterFibAlign = sizeof(struct aac_fib); 1767250963Sachim 1768250963Sachim ip->PrintfBufferAddress = sc->aac_common_busaddr + 1769250963Sachim offsetof(struct aac_common, ac_printf); 1770250963Sachim ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1771250963Sachim 1772250963Sachim /* 1773250963Sachim * The adapter assumes that pages are 4K in size, except on some 1774250963Sachim * broken firmware versions that do the page->byte conversion twice, 1775250963Sachim * therefore 'assuming' that this value is in 16MB units (2^24). 1776250963Sachim * Round up since the granularity is so high. 1777250963Sachim */ 1778250963Sachim ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1779250963Sachim if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1780250963Sachim ip->HostPhysMemPages = 1781250963Sachim (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1782250963Sachim } 1783250963Sachim ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 1784250963Sachim 1785250963Sachim ip->InitFlags = AAC_INITFLAGS_NEW_COMM_SUPPORTED; 1786250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1787250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_6; 1788250963Sachim ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | 1789250963Sachim AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1790250963Sachim device_printf(sc->aac_dev, "New comm. interface type1 enabled\n"); 1791250963Sachim } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 1792250963Sachim ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_7; 1793250963Sachim ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | 1794250963Sachim AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1795250963Sachim device_printf(sc->aac_dev, "New comm. interface type2 enabled\n"); 1796250963Sachim } 1797250963Sachim ip->MaxNumAif = sc->aac_max_aif; 1798250963Sachim ip->HostRRQ_AddrLow = 1799250963Sachim sc->aac_common_busaddr + offsetof(struct aac_common, ac_host_rrq); 1800250963Sachim /* always 32-bit address */ 1801250963Sachim ip->HostRRQ_AddrHigh = 0; 1802250963Sachim 1803250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) { 1804250963Sachim ip->InitFlags |= AAC_INITFLAGS_DRIVER_SUPPORTS_PM; 1805250963Sachim ip->InitFlags |= AAC_INITFLAGS_DRIVER_USES_UTC_TIME; 1806250963Sachim device_printf(sc->aac_dev, "Power Management enabled\n"); 1807250963Sachim } 1808250963Sachim 1809250963Sachim ip->MaxIoCommands = sc->aac_max_fibs; 1810250963Sachim ip->MaxIoSize = sc->aac_max_sectors << 9; 1811250963Sachim ip->MaxFibSize = sc->aac_max_fib_size; 1812250963Sachim 1813250963Sachim /* 1814250963Sachim * Do controller-type-specific initialisation 1815250963Sachim */ 1816250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, ~0); 1817250963Sachim 1818250963Sachim /* 1819250963Sachim * Give the init structure to the controller. 1820250963Sachim */ 1821250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_INITSTRUCT, 1822250963Sachim sc->aac_common_busaddr + 1823250963Sachim offsetof(struct aac_common, ac_init), 0, 0, 0, 1824250963Sachim NULL, NULL)) { 1825250963Sachim device_printf(sc->aac_dev, 1826250963Sachim "error establishing init structure\n"); 1827250963Sachim error = EIO; 1828250963Sachim goto out; 1829250963Sachim } 1830250963Sachim 1831263340Sachim /* 1832263340Sachim * Check configuration issues 1833263340Sachim */ 1834263340Sachim if ((error = aac_check_config(sc)) != 0) 1835263340Sachim goto out; 1836263340Sachim 1837250963Sachim error = 0; 1838250963Sachimout: 1839250963Sachim return(error); 1840250963Sachim} 1841250963Sachim 1842263340Sachimstatic void 1843263340Sachimaac_define_int_mode(struct aac_softc *sc) 1844263340Sachim{ 1845263340Sachim device_t dev; 1846263340Sachim int cap, msi_count, error = 0; 1847263340Sachim uint32_t val; 1848263340Sachim 1849263340Sachim dev = sc->aac_dev; 1850263340Sachim 1851263340Sachim /* max. vectors from AAC_MONKER_GETCOMMPREF */ 1852263340Sachim if (sc->aac_max_msix == 0) { 1853263340Sachim sc->aac_max_msix = 1; 1854263340Sachim sc->aac_vector_cap = sc->aac_max_fibs; 1855263340Sachim return; 1856263340Sachim } 1857263340Sachim 1858263340Sachim /* OS capability */ 1859263340Sachim msi_count = pci_msix_count(dev); 1860263340Sachim if (msi_count > AAC_MAX_MSIX) 1861263340Sachim msi_count = AAC_MAX_MSIX; 1862263340Sachim if (msi_count > sc->aac_max_msix) 1863263340Sachim msi_count = sc->aac_max_msix; 1864263340Sachim if (msi_count == 0 || (error = pci_alloc_msix(dev, &msi_count)) != 0) { 1865263340Sachim device_printf(dev, "alloc msix failed - msi_count=%d, err=%d; " 1866263340Sachim "will try MSI\n", msi_count, error); 1867263340Sachim pci_release_msi(dev); 1868263340Sachim } else { 1869263340Sachim sc->msi_enabled = TRUE; 1870263340Sachim device_printf(dev, "using MSI-X interrupts (%u vectors)\n", 1871263340Sachim msi_count); 1872263340Sachim } 1873263340Sachim 1874263340Sachim if (!sc->msi_enabled) { 1875263340Sachim msi_count = 1; 1876263340Sachim if ((error = pci_alloc_msi(dev, &msi_count)) != 0) { 1877263340Sachim device_printf(dev, "alloc msi failed - err=%d; " 1878263340Sachim "will use INTx\n", error); 1879263340Sachim pci_release_msi(dev); 1880263340Sachim } else { 1881263340Sachim sc->msi_enabled = TRUE; 1882263340Sachim device_printf(dev, "using MSI interrupts\n"); 1883263340Sachim } 1884263340Sachim } 1885263340Sachim 1886263340Sachim if (sc->msi_enabled) { 1887263340Sachim /* now read controller capability from PCI config. space */ 1888263340Sachim cap = aac_find_pci_capability(sc, PCIY_MSIX); 1889263340Sachim val = (cap != 0 ? pci_read_config(dev, cap + 2, 2) : 0); 1890263340Sachim if (!(val & AAC_PCI_MSI_ENABLE)) { 1891263340Sachim pci_release_msi(dev); 1892263340Sachim sc->msi_enabled = FALSE; 1893263340Sachim } 1894263340Sachim } 1895263340Sachim 1896263340Sachim if (!sc->msi_enabled) { 1897263340Sachim device_printf(dev, "using legacy interrupts\n"); 1898263340Sachim sc->aac_max_msix = 1; 1899263340Sachim } else { 1900263340Sachim AAC_ACCESS_DEVREG(sc, AAC_ENABLE_MSIX); 1901263340Sachim if (sc->aac_max_msix > msi_count) 1902263340Sachim sc->aac_max_msix = msi_count; 1903263340Sachim } 1904263340Sachim sc->aac_vector_cap = sc->aac_max_fibs / sc->aac_max_msix; 1905263340Sachim 1906263340Sachim fwprintf(sc, HBA_FLAGS_DBG_DEBUG_B, "msi_enabled %d vector_cap %d max_fibs %d max_msix %d", 1907263340Sachim sc->msi_enabled,sc->aac_vector_cap, sc->aac_max_fibs, sc->aac_max_msix); 1908263340Sachim} 1909263340Sachim 1910250963Sachimstatic int 1911263340Sachimaac_find_pci_capability(struct aac_softc *sc, int cap) 1912250963Sachim{ 1913263340Sachim device_t dev; 1914263340Sachim uint32_t status; 1915263340Sachim uint8_t ptr; 1916263340Sachim 1917263340Sachim dev = sc->aac_dev; 1918263340Sachim 1919263340Sachim status = pci_read_config(dev, PCIR_STATUS, 2); 1920263340Sachim if (!(status & PCIM_STATUS_CAPPRESENT)) 1921263340Sachim return (0); 1922263340Sachim 1923263340Sachim status = pci_read_config(dev, PCIR_HDRTYPE, 1); 1924263340Sachim switch (status & PCIM_HDRTYPE) { 1925263340Sachim case 0: 1926263340Sachim case 1: 1927263340Sachim ptr = PCIR_CAP_PTR; 1928263340Sachim break; 1929263340Sachim case 2: 1930263340Sachim ptr = PCIR_CAP_PTR_2; 1931263340Sachim break; 1932263340Sachim default: 1933263340Sachim return (0); 1934263340Sachim break; 1935250963Sachim } 1936263340Sachim ptr = pci_read_config(dev, ptr, 1); 1937263340Sachim 1938263340Sachim while (ptr != 0) { 1939263340Sachim int next, val; 1940263340Sachim next = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1941263340Sachim val = pci_read_config(dev, ptr + PCICAP_ID, 1); 1942263340Sachim if (val == cap) 1943263340Sachim return (ptr); 1944263340Sachim ptr = next; 1945250963Sachim } 1946263340Sachim 1947250963Sachim return (0); 1948250963Sachim} 1949250963Sachim 1950263340Sachimstatic int 1951263340Sachimaac_setup_intr(struct aac_softc *sc) 1952263340Sachim{ 1953263340Sachim int i, msi_count, rid; 1954263340Sachim struct resource *res; 1955263340Sachim void *tag; 1956263340Sachim 1957263340Sachim msi_count = sc->aac_max_msix; 1958263340Sachim rid = (sc->msi_enabled ? 1:0); 1959263340Sachim 1960263340Sachim for (i = 0; i < msi_count; i++, rid++) { 1961263340Sachim if ((res = bus_alloc_resource_any(sc->aac_dev,SYS_RES_IRQ, &rid, 1962263340Sachim RF_SHAREABLE | RF_ACTIVE)) == NULL) { 1963263340Sachim device_printf(sc->aac_dev,"can't allocate interrupt\n"); 1964263340Sachim return (EINVAL); 1965263340Sachim } 1966263340Sachim sc->aac_irq_rid[i] = rid; 1967263340Sachim sc->aac_irq[i] = res; 1968263340Sachim if (aac_bus_setup_intr(sc->aac_dev, res, 1969263340Sachim INTR_MPSAFE | INTR_TYPE_BIO, NULL, 1970263340Sachim aacraid_new_intr_type1, &sc->aac_msix[i], &tag)) { 1971263340Sachim device_printf(sc->aac_dev, "can't set up interrupt\n"); 1972263340Sachim return (EINVAL); 1973263340Sachim } 1974263340Sachim sc->aac_msix[i].vector_no = i; 1975263340Sachim sc->aac_msix[i].sc = sc; 1976263340Sachim sc->aac_intr[i] = tag; 1977263340Sachim } 1978263340Sachim 1979263340Sachim return (0); 1980263340Sachim} 1981263340Sachim 1982263340Sachimstatic int 1983263340Sachimaac_check_config(struct aac_softc *sc) 1984263340Sachim{ 1985263340Sachim struct aac_fib *fib; 1986263340Sachim struct aac_cnt_config *ccfg; 1987263340Sachim struct aac_cf_status_hdr *cf_shdr; 1988263340Sachim int rval; 1989263340Sachim 1990263340Sachim mtx_lock(&sc->aac_io_lock); 1991263340Sachim aac_alloc_sync_fib(sc, &fib); 1992263340Sachim 1993263340Sachim ccfg = (struct aac_cnt_config *)&fib->data[0]; 1994263340Sachim bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 1995263340Sachim ccfg->Command = VM_ContainerConfig; 1996263340Sachim ccfg->CTCommand.command = CT_GET_CONFIG_STATUS; 1997263340Sachim ccfg->CTCommand.param[CNT_SIZE] = sizeof(struct aac_cf_status_hdr); 1998263340Sachim 1999263340Sachim rval = aac_sync_fib(sc, ContainerCommand, 0, fib, 2000263340Sachim sizeof (struct aac_cnt_config)); 2001263340Sachim cf_shdr = (struct aac_cf_status_hdr *)ccfg->CTCommand.data; 2002263340Sachim if (rval == 0 && ccfg->Command == ST_OK && 2003263340Sachim ccfg->CTCommand.param[0] == CT_OK) { 2004263340Sachim if (cf_shdr->action <= CFACT_PAUSE) { 2005263340Sachim bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 2006263340Sachim ccfg->Command = VM_ContainerConfig; 2007263340Sachim ccfg->CTCommand.command = CT_COMMIT_CONFIG; 2008263340Sachim 2009263340Sachim rval = aac_sync_fib(sc, ContainerCommand, 0, fib, 2010263340Sachim sizeof (struct aac_cnt_config)); 2011263340Sachim if (rval == 0 && ccfg->Command == ST_OK && 2012263340Sachim ccfg->CTCommand.param[0] == CT_OK) { 2013263340Sachim /* successful completion */ 2014263340Sachim rval = 0; 2015263340Sachim } else { 2016263340Sachim /* auto commit aborted due to error(s) */ 2017263340Sachim rval = -2; 2018263340Sachim } 2019263340Sachim } else { 2020263340Sachim /* auto commit aborted due to adapter indicating 2021263340Sachim config. issues too dangerous to auto commit */ 2022263340Sachim rval = -3; 2023263340Sachim } 2024263340Sachim } else { 2025263340Sachim /* error */ 2026263340Sachim rval = -1; 2027263340Sachim } 2028263340Sachim 2029263340Sachim aac_release_sync_fib(sc); 2030263340Sachim mtx_unlock(&sc->aac_io_lock); 2031263340Sachim return(rval); 2032263340Sachim} 2033263340Sachim 2034250963Sachim/* 2035250963Sachim * Send a synchronous command to the controller and wait for a result. 2036250963Sachim * Indicate if the controller completed the command with an error status. 2037250963Sachim */ 2038250963Sachimint 2039250963Sachimaacraid_sync_command(struct aac_softc *sc, u_int32_t command, 2040250963Sachim u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 2041250963Sachim u_int32_t *sp, u_int32_t *r1) 2042250963Sachim{ 2043250963Sachim time_t then; 2044250963Sachim u_int32_t status; 2045250963Sachim 2046250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2047250963Sachim 2048250963Sachim /* populate the mailbox */ 2049250963Sachim AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 2050250963Sachim 2051250963Sachim /* ensure the sync command doorbell flag is cleared */ 2052263340Sachim if (!sc->msi_enabled) 2053263340Sachim AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 2054250963Sachim 2055250963Sachim /* then set it to signal the adapter */ 2056250963Sachim AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 2057250963Sachim 2058250963Sachim if ((command != AAC_MONKER_SYNCFIB) || (sp == NULL) || (*sp != 0)) { 2059250963Sachim /* spin waiting for the command to complete */ 2060250963Sachim then = time_uptime; 2061250963Sachim do { 2062263340Sachim if (time_uptime > (then + AAC_SYNC_TIMEOUT)) { 2063250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 2064250963Sachim return(EIO); 2065250963Sachim } 2066250963Sachim } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 2067250963Sachim 2068250963Sachim /* clear the completion flag */ 2069250963Sachim AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 2070250963Sachim 2071250963Sachim /* get the command status */ 2072250963Sachim status = AAC_GET_MAILBOX(sc, 0); 2073250963Sachim if (sp != NULL) 2074250963Sachim *sp = status; 2075250963Sachim 2076250963Sachim /* return parameter */ 2077250963Sachim if (r1 != NULL) 2078250963Sachim *r1 = AAC_GET_MAILBOX(sc, 1); 2079250963Sachim 2080250963Sachim if (status != AAC_SRB_STS_SUCCESS) 2081250963Sachim return (-1); 2082250963Sachim } 2083250963Sachim return(0); 2084250963Sachim} 2085250963Sachim 2086250963Sachimstatic int 2087250963Sachimaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2088250963Sachim struct aac_fib *fib, u_int16_t datasize) 2089250963Sachim{ 2090250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2091250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 2092250963Sachim 2093250963Sachim if (datasize > AAC_FIB_DATASIZE) 2094250963Sachim return(EINVAL); 2095250963Sachim 2096250963Sachim /* 2097250963Sachim * Set up the sync FIB 2098250963Sachim */ 2099250963Sachim fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2100250963Sachim AAC_FIBSTATE_INITIALISED | 2101250963Sachim AAC_FIBSTATE_EMPTY; 2102250963Sachim fib->Header.XferState |= xferstate; 2103250963Sachim fib->Header.Command = command; 2104250963Sachim fib->Header.StructType = AAC_FIBTYPE_TFIB; 2105250963Sachim fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 2106250963Sachim fib->Header.SenderSize = sizeof(struct aac_fib); 2107250963Sachim fib->Header.SenderFibAddress = 0; /* Not needed */ 2108250963Sachim fib->Header.u.ReceiverFibAddress = sc->aac_common_busaddr + 2109263340Sachim offsetof(struct aac_common, ac_sync_fib); 2110250963Sachim 2111250963Sachim /* 2112250963Sachim * Give the FIB to the controller, wait for a response. 2113250963Sachim */ 2114250963Sachim if (aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, 2115263340Sachim fib->Header.u.ReceiverFibAddress, 0, 0, 0, NULL, NULL)) { 2116250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 2117250963Sachim return(EIO); 2118250963Sachim } 2119250963Sachim 2120250963Sachim return (0); 2121250963Sachim} 2122250963Sachim 2123250963Sachim/* 2124250963Sachim * Check for commands that have been outstanding for a suspiciously long time, 2125250963Sachim * and complain about them. 2126250963Sachim */ 2127250963Sachimstatic void 2128250963Sachimaac_timeout(struct aac_softc *sc) 2129250963Sachim{ 2130250963Sachim struct aac_command *cm; 2131250963Sachim time_t deadline; 2132263340Sachim int timedout; 2133250963Sachim 2134250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2135250963Sachim /* 2136250963Sachim * Traverse the busy command list, bitch about late commands once 2137250963Sachim * only. 2138250963Sachim */ 2139250963Sachim timedout = 0; 2140250963Sachim deadline = time_uptime - AAC_CMD_TIMEOUT; 2141250963Sachim TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2142263340Sachim if (cm->cm_timestamp < deadline) { 2143250963Sachim device_printf(sc->aac_dev, 2144250963Sachim "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2145250963Sachim cm, (int)(time_uptime-cm->cm_timestamp)); 2146250963Sachim AAC_PRINT_FIB(sc, cm->cm_fib); 2147250963Sachim timedout++; 2148250963Sachim } 2149250963Sachim } 2150250963Sachim 2151263340Sachim if (timedout) 2152263340Sachim aac_reset_adapter(sc); 2153250963Sachim aacraid_print_queues(sc); 2154250963Sachim} 2155250963Sachim 2156250963Sachim/* 2157250963Sachim * Interface Function Vectors 2158250963Sachim */ 2159250963Sachim 2160250963Sachim/* 2161250963Sachim * Read the current firmware status word. 2162250963Sachim */ 2163250963Sachimstatic int 2164250963Sachimaac_src_get_fwstatus(struct aac_softc *sc) 2165250963Sachim{ 2166250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2167250963Sachim 2168250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRC_OMR)); 2169250963Sachim} 2170250963Sachim 2171250963Sachim/* 2172250963Sachim * Notify the controller of a change in a given queue 2173250963Sachim */ 2174250963Sachimstatic void 2175250963Sachimaac_src_qnotify(struct aac_softc *sc, int qbit) 2176250963Sachim{ 2177250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2178250963Sachim 2179250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, qbit << AAC_SRC_IDR_SHIFT); 2180250963Sachim} 2181250963Sachim 2182250963Sachim/* 2183250963Sachim * Get the interrupt reason bits 2184250963Sachim */ 2185250963Sachimstatic int 2186250963Sachimaac_src_get_istatus(struct aac_softc *sc) 2187250963Sachim{ 2188263340Sachim int val; 2189263340Sachim 2190250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2191250963Sachim 2192263340Sachim if (sc->msi_enabled) { 2193263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_MSI); 2194263340Sachim if (val & AAC_MSI_SYNC_STATUS) 2195263340Sachim val = AAC_DB_SYNC_COMMAND; 2196263340Sachim else 2197263340Sachim val = 0; 2198263340Sachim } else { 2199263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R) >> AAC_SRC_ODR_SHIFT; 2200263340Sachim } 2201263340Sachim return(val); 2202250963Sachim} 2203250963Sachim 2204250963Sachim/* 2205250963Sachim * Clear some interrupt reason bits 2206250963Sachim */ 2207250963Sachimstatic void 2208250963Sachimaac_src_clear_istatus(struct aac_softc *sc, int mask) 2209250963Sachim{ 2210250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2211250963Sachim 2212263340Sachim if (sc->msi_enabled) { 2213263340Sachim if (mask == AAC_DB_SYNC_COMMAND) 2214263340Sachim AAC_ACCESS_DEVREG(sc, AAC_CLEAR_SYNC_BIT); 2215263340Sachim } else { 2216263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, mask << AAC_SRC_ODR_SHIFT); 2217263340Sachim } 2218250963Sachim} 2219250963Sachim 2220250963Sachim/* 2221250963Sachim * Populate the mailbox and set the command word 2222250963Sachim */ 2223250963Sachimstatic void 2224250963Sachimaac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2225250963Sachim u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2226250963Sachim{ 2227250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2228250963Sachim 2229250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX, command); 2230250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 4, arg0); 2231250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 8, arg1); 2232250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 12, arg2); 2233250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 16, arg3); 2234250963Sachim} 2235250963Sachim 2236250963Sachimstatic void 2237250963Sachimaac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2238250963Sachim u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2239250963Sachim{ 2240250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2241250963Sachim 2242250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX, command); 2243250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 4, arg0); 2244250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 8, arg1); 2245250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 12, arg2); 2246250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 16, arg3); 2247250963Sachim} 2248250963Sachim 2249250963Sachim/* 2250250963Sachim * Fetch the immediate command status word 2251250963Sachim */ 2252250963Sachimstatic int 2253250963Sachimaac_src_get_mailbox(struct aac_softc *sc, int mb) 2254250963Sachim{ 2255250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2256250963Sachim 2257250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRC_MAILBOX + (mb * 4))); 2258250963Sachim} 2259250963Sachim 2260250963Sachimstatic int 2261250963Sachimaac_srcv_get_mailbox(struct aac_softc *sc, int mb) 2262250963Sachim{ 2263250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2264250963Sachim 2265250963Sachim return(AAC_MEM0_GETREG4(sc, AAC_SRCV_MAILBOX + (mb * 4))); 2266250963Sachim} 2267250963Sachim 2268250963Sachim/* 2269250963Sachim * Set/clear interrupt masks 2270250963Sachim */ 2271250963Sachimstatic void 2272263340Sachimaac_src_access_devreg(struct aac_softc *sc, int mode) 2273250963Sachim{ 2274263340Sachim u_int32_t val; 2275250963Sachim 2276263340Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2277263340Sachim 2278263340Sachim switch (mode) { 2279263340Sachim case AAC_ENABLE_INTERRUPT: 2280263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, 2281263340Sachim (sc->msi_enabled ? AAC_INT_ENABLE_TYPE1_MSIX : 2282263340Sachim AAC_INT_ENABLE_TYPE1_INTX)); 2283263340Sachim break; 2284263340Sachim 2285263340Sachim case AAC_DISABLE_INTERRUPT: 2286263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, AAC_INT_DISABLE_ALL); 2287263340Sachim break; 2288263340Sachim 2289263340Sachim case AAC_ENABLE_MSIX: 2290263340Sachim /* set bit 6 */ 2291263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2292263340Sachim val |= 0x40; 2293263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 2294263340Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2295263340Sachim /* unmask int. */ 2296263340Sachim val = PMC_ALL_INTERRUPT_BITS; 2297263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IOAR, val); 2298263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_OIMR); 2299263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, 2300263340Sachim val & (~(PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0))); 2301263340Sachim break; 2302263340Sachim 2303263340Sachim case AAC_DISABLE_MSIX: 2304263340Sachim /* reset bit 6 */ 2305263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2306263340Sachim val &= ~0x40; 2307263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 2308263340Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2309263340Sachim break; 2310263340Sachim 2311263340Sachim case AAC_CLEAR_AIF_BIT: 2312263340Sachim /* set bit 5 */ 2313263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2314263340Sachim val |= 0x20; 2315263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 2316263340Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2317263340Sachim break; 2318263340Sachim 2319263340Sachim case AAC_CLEAR_SYNC_BIT: 2320263340Sachim /* set bit 4 */ 2321263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2322263340Sachim val |= 0x10; 2323263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 2324263340Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2325263340Sachim break; 2326263340Sachim 2327263340Sachim case AAC_ENABLE_INTX: 2328263340Sachim /* set bit 7 */ 2329263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2330263340Sachim val |= 0x80; 2331263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 2332263340Sachim AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 2333263340Sachim /* unmask int. */ 2334263340Sachim val = PMC_ALL_INTERRUPT_BITS; 2335263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IOAR, val); 2336263340Sachim val = AAC_MEM0_GETREG4(sc, AAC_SRC_OIMR); 2337263340Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, 2338263340Sachim val & (~(PMC_GLOBAL_INT_BIT2))); 2339263340Sachim break; 2340263340Sachim 2341263340Sachim default: 2342263340Sachim break; 2343250963Sachim } 2344250963Sachim} 2345250963Sachim 2346250963Sachim/* 2347250963Sachim * New comm. interface: Send command functions 2348250963Sachim */ 2349250963Sachimstatic int 2350250963Sachimaac_src_send_command(struct aac_softc *sc, struct aac_command *cm) 2351250963Sachim{ 2352250963Sachim struct aac_fib_xporthdr *pFibX; 2353250963Sachim u_int32_t fibsize, high_addr; 2354250963Sachim u_int64_t address; 2355250963Sachim 2356250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm. type1)"); 2357250963Sachim 2358263340Sachim if (sc->msi_enabled && cm->cm_fib->Header.Command != AifRequest && 2359263340Sachim sc->aac_max_msix > 1) { 2360263340Sachim u_int16_t vector_no, first_choice = 0xffff; 2361263340Sachim 2362263340Sachim vector_no = sc->aac_fibs_pushed_no % sc->aac_max_msix; 2363263340Sachim do { 2364263340Sachim vector_no += 1; 2365263340Sachim if (vector_no == sc->aac_max_msix) 2366263340Sachim vector_no = 1; 2367263340Sachim if (sc->aac_rrq_outstanding[vector_no] < 2368263340Sachim sc->aac_vector_cap) 2369263340Sachim break; 2370263340Sachim if (0xffff == first_choice) 2371263340Sachim first_choice = vector_no; 2372263340Sachim else if (vector_no == first_choice) 2373263340Sachim break; 2374263340Sachim } while (1); 2375263340Sachim if (vector_no == first_choice) 2376263340Sachim vector_no = 0; 2377263340Sachim sc->aac_rrq_outstanding[vector_no]++; 2378263340Sachim if (sc->aac_fibs_pushed_no == 0xffffffff) 2379263340Sachim sc->aac_fibs_pushed_no = 0; 2380263340Sachim else 2381263340Sachim sc->aac_fibs_pushed_no++; 2382263340Sachim 2383263340Sachim cm->cm_fib->Header.Handle += (vector_no << 16); 2384263340Sachim } 2385263340Sachim 2386250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 2387250963Sachim /* Calculate the amount to the fibsize bits */ 2388250963Sachim fibsize = (cm->cm_fib->Header.Size + 127) / 128 - 1; 2389250963Sachim /* Fill new FIB header */ 2390250963Sachim address = cm->cm_fibphys; 2391250963Sachim high_addr = (u_int32_t)(address >> 32); 2392250963Sachim if (high_addr == 0L) { 2393250963Sachim cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2; 2394250963Sachim cm->cm_fib->Header.u.TimeStamp = 0L; 2395250963Sachim } else { 2396250963Sachim cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2_64; 2397250963Sachim cm->cm_fib->Header.u.SenderFibAddressHigh = high_addr; 2398250963Sachim } 2399250963Sachim cm->cm_fib->Header.SenderFibAddress = (u_int32_t)address; 2400250963Sachim } else { 2401250963Sachim /* Calculate the amount to the fibsize bits */ 2402250963Sachim fibsize = (sizeof(struct aac_fib_xporthdr) + 2403250963Sachim cm->cm_fib->Header.Size + 127) / 128 - 1; 2404250963Sachim /* Fill XPORT header */ 2405250963Sachim pFibX = (struct aac_fib_xporthdr *) 2406250963Sachim ((unsigned char *)cm->cm_fib - sizeof(struct aac_fib_xporthdr)); 2407250963Sachim pFibX->Handle = cm->cm_fib->Header.Handle; 2408250963Sachim pFibX->HostAddress = cm->cm_fibphys; 2409250963Sachim pFibX->Size = cm->cm_fib->Header.Size; 2410250963Sachim address = cm->cm_fibphys - sizeof(struct aac_fib_xporthdr); 2411250963Sachim high_addr = (u_int32_t)(address >> 32); 2412250963Sachim } 2413250963Sachim 2414250963Sachim if (fibsize > 31) 2415250963Sachim fibsize = 31; 2416250963Sachim aac_enqueue_busy(cm); 2417250963Sachim if (high_addr) { 2418250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_H, high_addr); 2419250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_L, (u_int32_t)address + fibsize); 2420250963Sachim } else { 2421250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE32, (u_int32_t)address + fibsize); 2422250963Sachim } 2423250963Sachim return 0; 2424250963Sachim} 2425250963Sachim 2426250963Sachim/* 2427250963Sachim * New comm. interface: get, set outbound queue index 2428250963Sachim */ 2429250963Sachimstatic int 2430250963Sachimaac_src_get_outb_queue(struct aac_softc *sc) 2431250963Sachim{ 2432250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2433250963Sachim 2434250963Sachim return(-1); 2435250963Sachim} 2436250963Sachim 2437250963Sachimstatic void 2438250963Sachimaac_src_set_outb_queue(struct aac_softc *sc, int index) 2439250963Sachim{ 2440250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2441250963Sachim} 2442250963Sachim 2443250963Sachim/* 2444250963Sachim * Debugging and Diagnostics 2445250963Sachim */ 2446250963Sachim 2447250963Sachim/* 2448250963Sachim * Print some information about the controller. 2449250963Sachim */ 2450250963Sachimstatic void 2451250963Sachimaac_describe_controller(struct aac_softc *sc) 2452250963Sachim{ 2453250963Sachim struct aac_fib *fib; 2454250963Sachim struct aac_adapter_info *info; 2455250963Sachim char *adapter_type = "Adaptec RAID controller"; 2456250963Sachim 2457250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2458250963Sachim 2459250963Sachim mtx_lock(&sc->aac_io_lock); 2460250963Sachim aac_alloc_sync_fib(sc, &fib); 2461250963Sachim 2462250963Sachim if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 2463250963Sachim fib->data[0] = 0; 2464250963Sachim if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 2465250963Sachim device_printf(sc->aac_dev, "RequestSupplementAdapterInfo failed\n"); 2466250963Sachim else { 2467250963Sachim struct aac_supplement_adapter_info *supp_info; 2468250963Sachim 2469250963Sachim supp_info = ((struct aac_supplement_adapter_info *)&fib->data[0]); 2470250963Sachim adapter_type = (char *)supp_info->AdapterTypeText; 2471250963Sachim sc->aac_feature_bits = supp_info->FeatureBits; 2472250963Sachim sc->aac_support_opt2 = supp_info->SupportedOptions2; 2473250963Sachim } 2474250963Sachim } 2475250963Sachim device_printf(sc->aac_dev, "%s, aacraid driver %d.%d.%d-%d\n", 2476250963Sachim adapter_type, 2477250963Sachim AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 2478250963Sachim AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 2479250963Sachim 2480250963Sachim fib->data[0] = 0; 2481250963Sachim if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 2482250963Sachim device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2483250963Sachim aac_release_sync_fib(sc); 2484250963Sachim mtx_unlock(&sc->aac_io_lock); 2485250963Sachim return; 2486250963Sachim } 2487250963Sachim 2488250963Sachim /* save the kernel revision structure for later use */ 2489250963Sachim info = (struct aac_adapter_info *)&fib->data[0]; 2490250963Sachim sc->aac_revision = info->KernelRevision; 2491250963Sachim 2492250963Sachim if (bootverbose) { 2493250963Sachim device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2494250963Sachim "(%dMB cache, %dMB execution), %s\n", 2495250963Sachim aac_describe_code(aac_cpu_variant, info->CpuVariant), 2496250963Sachim info->ClockSpeed, info->TotalMem / (1024 * 1024), 2497250963Sachim info->BufferMem / (1024 * 1024), 2498250963Sachim info->ExecutionMem / (1024 * 1024), 2499250963Sachim aac_describe_code(aac_battery_platform, 2500250963Sachim info->batteryPlatform)); 2501250963Sachim 2502250963Sachim device_printf(sc->aac_dev, 2503250963Sachim "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2504250963Sachim info->KernelRevision.external.comp.major, 2505250963Sachim info->KernelRevision.external.comp.minor, 2506250963Sachim info->KernelRevision.external.comp.dash, 2507250963Sachim info->KernelRevision.buildNumber, 2508250963Sachim (u_int32_t)(info->SerialNumber & 0xffffff)); 2509250963Sachim 2510250963Sachim device_printf(sc->aac_dev, "Supported Options=%b\n", 2511250963Sachim sc->supported_options, 2512250963Sachim "\20" 2513250963Sachim "\1SNAPSHOT" 2514250963Sachim "\2CLUSTERS" 2515250963Sachim "\3WCACHE" 2516250963Sachim "\4DATA64" 2517250963Sachim "\5HOSTTIME" 2518250963Sachim "\6RAID50" 2519250963Sachim "\7WINDOW4GB" 2520250963Sachim "\10SCSIUPGD" 2521250963Sachim "\11SOFTERR" 2522250963Sachim "\12NORECOND" 2523250963Sachim "\13SGMAP64" 2524250963Sachim "\14ALARM" 2525250963Sachim "\15NONDASD" 2526250963Sachim "\16SCSIMGT" 2527250963Sachim "\17RAIDSCSI" 2528250963Sachim "\21ADPTINFO" 2529250963Sachim "\22NEWCOMM" 2530250963Sachim "\23ARRAY64BIT" 2531250963Sachim "\24HEATSENSOR"); 2532250963Sachim } 2533250963Sachim 2534250963Sachim aac_release_sync_fib(sc); 2535250963Sachim mtx_unlock(&sc->aac_io_lock); 2536250963Sachim} 2537250963Sachim 2538250963Sachim/* 2539250963Sachim * Look up a text description of a numeric error code and return a pointer to 2540250963Sachim * same. 2541250963Sachim */ 2542250963Sachimstatic char * 2543250963Sachimaac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2544250963Sachim{ 2545250963Sachim int i; 2546250963Sachim 2547250963Sachim for (i = 0; table[i].string != NULL; i++) 2548250963Sachim if (table[i].code == code) 2549250963Sachim return(table[i].string); 2550250963Sachim return(table[i + 1].string); 2551250963Sachim} 2552250963Sachim 2553250963Sachim/* 2554250963Sachim * Management Interface 2555250963Sachim */ 2556250963Sachim 2557250963Sachimstatic int 2558250963Sachimaac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2559250963Sachim{ 2560250963Sachim struct aac_softc *sc; 2561250963Sachim 2562250963Sachim sc = dev->si_drv1; 2563250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2564250963Sachim#if __FreeBSD_version >= 702000 2565250963Sachim device_busy(sc->aac_dev); 2566250963Sachim devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 2567250963Sachim#endif 2568250963Sachim return 0; 2569250963Sachim} 2570250963Sachim 2571250963Sachimstatic int 2572250963Sachimaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2573250963Sachim{ 2574250963Sachim union aac_statrequest *as; 2575250963Sachim struct aac_softc *sc; 2576250963Sachim int error = 0; 2577250963Sachim 2578250963Sachim as = (union aac_statrequest *)arg; 2579250963Sachim sc = dev->si_drv1; 2580250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2581250963Sachim 2582250963Sachim switch (cmd) { 2583250963Sachim case AACIO_STATS: 2584250963Sachim switch (as->as_item) { 2585250963Sachim case AACQ_FREE: 2586250963Sachim case AACQ_READY: 2587250963Sachim case AACQ_BUSY: 2588250963Sachim bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2589250963Sachim sizeof(struct aac_qstat)); 2590250963Sachim break; 2591250963Sachim default: 2592250963Sachim error = ENOENT; 2593250963Sachim break; 2594250963Sachim } 2595250963Sachim break; 2596250963Sachim 2597250963Sachim case FSACTL_SENDFIB: 2598250963Sachim case FSACTL_SEND_LARGE_FIB: 2599250963Sachim arg = *(caddr_t*)arg; 2600250963Sachim case FSACTL_LNX_SENDFIB: 2601250963Sachim case FSACTL_LNX_SEND_LARGE_FIB: 2602250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 2603250963Sachim error = aac_ioctl_sendfib(sc, arg); 2604250963Sachim break; 2605250963Sachim case FSACTL_SEND_RAW_SRB: 2606250963Sachim arg = *(caddr_t*)arg; 2607250963Sachim case FSACTL_LNX_SEND_RAW_SRB: 2608250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2609250963Sachim error = aac_ioctl_send_raw_srb(sc, arg); 2610250963Sachim break; 2611250963Sachim case FSACTL_AIF_THREAD: 2612250963Sachim case FSACTL_LNX_AIF_THREAD: 2613250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 2614250963Sachim error = EINVAL; 2615250963Sachim break; 2616250963Sachim case FSACTL_OPEN_GET_ADAPTER_FIB: 2617250963Sachim arg = *(caddr_t*)arg; 2618250963Sachim case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2619250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2620250963Sachim error = aac_open_aif(sc, arg); 2621250963Sachim break; 2622250963Sachim case FSACTL_GET_NEXT_ADAPTER_FIB: 2623250963Sachim arg = *(caddr_t*)arg; 2624250963Sachim case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2625250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2626250963Sachim error = aac_getnext_aif(sc, arg); 2627250963Sachim break; 2628250963Sachim case FSACTL_CLOSE_GET_ADAPTER_FIB: 2629250963Sachim arg = *(caddr_t*)arg; 2630250963Sachim case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2631250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2632250963Sachim error = aac_close_aif(sc, arg); 2633250963Sachim break; 2634250963Sachim case FSACTL_MINIPORT_REV_CHECK: 2635250963Sachim arg = *(caddr_t*)arg; 2636250963Sachim case FSACTL_LNX_MINIPORT_REV_CHECK: 2637250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2638250963Sachim error = aac_rev_check(sc, arg); 2639250963Sachim break; 2640250963Sachim case FSACTL_QUERY_DISK: 2641250963Sachim arg = *(caddr_t*)arg; 2642250963Sachim case FSACTL_LNX_QUERY_DISK: 2643250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 2644250963Sachim error = aac_query_disk(sc, arg); 2645250963Sachim break; 2646250963Sachim case FSACTL_DELETE_DISK: 2647250963Sachim case FSACTL_LNX_DELETE_DISK: 2648250963Sachim /* 2649250963Sachim * We don't trust the underland to tell us when to delete a 2650250963Sachim * container, rather we rely on an AIF coming from the 2651250963Sachim * controller 2652250963Sachim */ 2653250963Sachim error = 0; 2654250963Sachim break; 2655250963Sachim case FSACTL_GET_PCI_INFO: 2656250963Sachim arg = *(caddr_t*)arg; 2657250963Sachim case FSACTL_LNX_GET_PCI_INFO: 2658250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 2659250963Sachim error = aac_get_pci_info(sc, arg); 2660250963Sachim break; 2661250963Sachim case FSACTL_GET_FEATURES: 2662250963Sachim arg = *(caddr_t*)arg; 2663250963Sachim case FSACTL_LNX_GET_FEATURES: 2664250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 2665250963Sachim error = aac_supported_features(sc, arg); 2666250963Sachim break; 2667250963Sachim default: 2668250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 2669250963Sachim error = EINVAL; 2670250963Sachim break; 2671250963Sachim } 2672250963Sachim return(error); 2673250963Sachim} 2674250963Sachim 2675250963Sachimstatic int 2676250963Sachimaac_poll(struct cdev *dev, int poll_events, struct thread *td) 2677250963Sachim{ 2678250963Sachim struct aac_softc *sc; 2679250963Sachim struct aac_fib_context *ctx; 2680250963Sachim int revents; 2681250963Sachim 2682250963Sachim sc = dev->si_drv1; 2683250963Sachim revents = 0; 2684250963Sachim 2685250963Sachim mtx_lock(&sc->aac_io_lock); 2686250963Sachim if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2687250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2688250963Sachim if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2689250963Sachim revents |= poll_events & (POLLIN | POLLRDNORM); 2690250963Sachim break; 2691250963Sachim } 2692250963Sachim } 2693250963Sachim } 2694250963Sachim mtx_unlock(&sc->aac_io_lock); 2695250963Sachim 2696250963Sachim if (revents == 0) { 2697250963Sachim if (poll_events & (POLLIN | POLLRDNORM)) 2698250963Sachim selrecord(td, &sc->rcv_select); 2699250963Sachim } 2700250963Sachim 2701250963Sachim return (revents); 2702250963Sachim} 2703250963Sachim 2704250963Sachimstatic void 2705250963Sachimaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2706250963Sachim{ 2707250963Sachim 2708250963Sachim switch (event->ev_type) { 2709250963Sachim case AAC_EVENT_CMFREE: 2710250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 2711250963Sachim if (aacraid_alloc_command(sc, (struct aac_command **)arg)) { 2712250963Sachim aacraid_add_event(sc, event); 2713250963Sachim return; 2714250963Sachim } 2715250963Sachim free(event, M_AACRAIDBUF); 2716250963Sachim wakeup(arg); 2717250963Sachim break; 2718250963Sachim default: 2719250963Sachim break; 2720250963Sachim } 2721250963Sachim} 2722250963Sachim 2723250963Sachim/* 2724250963Sachim * Send a FIB supplied from userspace 2725250963Sachim */ 2726250963Sachimstatic int 2727250963Sachimaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 2728250963Sachim{ 2729250963Sachim struct aac_command *cm; 2730250963Sachim int size, error; 2731250963Sachim 2732250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2733250963Sachim 2734250963Sachim cm = NULL; 2735250963Sachim 2736250963Sachim /* 2737250963Sachim * Get a command 2738250963Sachim */ 2739250963Sachim mtx_lock(&sc->aac_io_lock); 2740250963Sachim if (aacraid_alloc_command(sc, &cm)) { 2741250963Sachim struct aac_event *event; 2742250963Sachim 2743250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2744250963Sachim M_NOWAIT | M_ZERO); 2745250963Sachim if (event == NULL) { 2746250963Sachim error = EBUSY; 2747250963Sachim mtx_unlock(&sc->aac_io_lock); 2748250963Sachim goto out; 2749250963Sachim } 2750250963Sachim event->ev_type = AAC_EVENT_CMFREE; 2751250963Sachim event->ev_callback = aac_ioctl_event; 2752250963Sachim event->ev_arg = &cm; 2753250963Sachim aacraid_add_event(sc, event); 2754250963Sachim msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsfib", 0); 2755250963Sachim } 2756250963Sachim mtx_unlock(&sc->aac_io_lock); 2757250963Sachim 2758250963Sachim /* 2759250963Sachim * Fetch the FIB header, then re-copy to get data as well. 2760250963Sachim */ 2761250963Sachim if ((error = copyin(ufib, cm->cm_fib, 2762250963Sachim sizeof(struct aac_fib_header))) != 0) 2763250963Sachim goto out; 2764250963Sachim size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 2765250963Sachim if (size > sc->aac_max_fib_size) { 2766250963Sachim device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2767250963Sachim size, sc->aac_max_fib_size); 2768250963Sachim size = sc->aac_max_fib_size; 2769250963Sachim } 2770250963Sachim if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 2771250963Sachim goto out; 2772250963Sachim cm->cm_fib->Header.Size = size; 2773250963Sachim cm->cm_timestamp = time_uptime; 2774250963Sachim cm->cm_datalen = 0; 2775250963Sachim 2776250963Sachim /* 2777250963Sachim * Pass the FIB to the controller, wait for it to complete. 2778250963Sachim */ 2779250963Sachim mtx_lock(&sc->aac_io_lock); 2780250963Sachim error = aacraid_wait_command(cm); 2781250963Sachim mtx_unlock(&sc->aac_io_lock); 2782250963Sachim if (error != 0) { 2783250963Sachim device_printf(sc->aac_dev, 2784250963Sachim "aacraid_wait_command return %d\n", error); 2785250963Sachim goto out; 2786250963Sachim } 2787250963Sachim 2788250963Sachim /* 2789250963Sachim * Copy the FIB and data back out to the caller. 2790250963Sachim */ 2791250963Sachim size = cm->cm_fib->Header.Size; 2792250963Sachim if (size > sc->aac_max_fib_size) { 2793250963Sachim device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2794250963Sachim size, sc->aac_max_fib_size); 2795250963Sachim size = sc->aac_max_fib_size; 2796250963Sachim } 2797250963Sachim error = copyout(cm->cm_fib, ufib, size); 2798250963Sachim 2799250963Sachimout: 2800250963Sachim if (cm != NULL) { 2801250963Sachim mtx_lock(&sc->aac_io_lock); 2802250963Sachim aacraid_release_command(cm); 2803250963Sachim mtx_unlock(&sc->aac_io_lock); 2804250963Sachim } 2805250963Sachim return(error); 2806250963Sachim} 2807250963Sachim 2808250963Sachim/* 2809250963Sachim * Send a passthrough FIB supplied from userspace 2810250963Sachim */ 2811250963Sachimstatic int 2812250963Sachimaac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 2813250963Sachim{ 2814250963Sachim struct aac_command *cm; 2815250963Sachim struct aac_fib *fib; 2816250963Sachim struct aac_srb *srbcmd; 2817250963Sachim struct aac_srb *user_srb = (struct aac_srb *)arg; 2818250963Sachim void *user_reply; 2819250963Sachim int error, transfer_data = 0; 2820250963Sachim bus_dmamap_t orig_map = 0; 2821250963Sachim u_int32_t fibsize = 0; 2822250963Sachim u_int64_t srb_sg_address; 2823250963Sachim u_int32_t srb_sg_bytecount; 2824250963Sachim 2825250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2826250963Sachim 2827250963Sachim cm = NULL; 2828250963Sachim 2829250963Sachim mtx_lock(&sc->aac_io_lock); 2830250963Sachim if (aacraid_alloc_command(sc, &cm)) { 2831250963Sachim struct aac_event *event; 2832250963Sachim 2833250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2834250963Sachim M_NOWAIT | M_ZERO); 2835250963Sachim if (event == NULL) { 2836250963Sachim error = EBUSY; 2837250963Sachim mtx_unlock(&sc->aac_io_lock); 2838250963Sachim goto out; 2839250963Sachim } 2840250963Sachim event->ev_type = AAC_EVENT_CMFREE; 2841250963Sachim event->ev_callback = aac_ioctl_event; 2842250963Sachim event->ev_arg = &cm; 2843250963Sachim aacraid_add_event(sc, event); 2844250963Sachim msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsraw", 0); 2845250963Sachim } 2846250963Sachim mtx_unlock(&sc->aac_io_lock); 2847250963Sachim 2848250963Sachim cm->cm_data = NULL; 2849250963Sachim /* save original dma map */ 2850250963Sachim orig_map = cm->cm_datamap; 2851250963Sachim 2852250963Sachim fib = cm->cm_fib; 2853250963Sachim srbcmd = (struct aac_srb *)fib->data; 2854250963Sachim if ((error = copyin((void *)&user_srb->data_len, &fibsize, 2855250963Sachim sizeof (u_int32_t)) != 0)) 2856250963Sachim goto out; 2857250963Sachim if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) { 2858250963Sachim error = EINVAL; 2859250963Sachim goto out; 2860250963Sachim } 2861250963Sachim if ((error = copyin((void *)user_srb, srbcmd, fibsize) != 0)) 2862250963Sachim goto out; 2863250963Sachim 2864250963Sachim srbcmd->function = 0; /* SRBF_ExecuteScsi */ 2865250963Sachim srbcmd->retry_limit = 0; /* obsolete */ 2866250963Sachim 2867250963Sachim /* only one sg element from userspace supported */ 2868250963Sachim if (srbcmd->sg_map.SgCount > 1) { 2869250963Sachim error = EINVAL; 2870250963Sachim goto out; 2871250963Sachim } 2872250963Sachim /* check fibsize */ 2873250963Sachim if (fibsize == (sizeof(struct aac_srb) + 2874250963Sachim srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 2875250963Sachim struct aac_sg_entry *sgp = srbcmd->sg_map.SgEntry; 2876250963Sachim srb_sg_bytecount = sgp->SgByteCount; 2877250963Sachim srb_sg_address = (u_int64_t)sgp->SgAddress; 2878250963Sachim } else if (fibsize == (sizeof(struct aac_srb) + 2879250963Sachim srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 2880252778Sachim#ifdef __LP64__ 2881250963Sachim struct aac_sg_entry64 *sgp = 2882250963Sachim (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 2883250963Sachim srb_sg_bytecount = sgp->SgByteCount; 2884250963Sachim srb_sg_address = sgp->SgAddress; 2885250963Sachim if (srb_sg_address > 0xffffffffull && 2886250963Sachim !(sc->flags & AAC_FLAGS_SG_64BIT)) 2887250963Sachim#endif 2888250963Sachim { 2889250963Sachim error = EINVAL; 2890250963Sachim goto out; 2891250963Sachim } 2892250963Sachim } else { 2893250963Sachim error = EINVAL; 2894250963Sachim goto out; 2895250963Sachim } 2896250963Sachim user_reply = (char *)arg + fibsize; 2897250963Sachim srbcmd->data_len = srb_sg_bytecount; 2898250963Sachim if (srbcmd->sg_map.SgCount == 1) 2899250963Sachim transfer_data = 1; 2900250963Sachim 2901250963Sachim if (transfer_data) { 2902250963Sachim /* 2903250963Sachim * Create DMA tag for the passthr. data buffer and allocate it. 2904250963Sachim */ 2905250963Sachim if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 2906250963Sachim 1, 0, /* algnmnt, boundary */ 2907250963Sachim (sc->flags & AAC_FLAGS_SG_64BIT) ? 2908250963Sachim BUS_SPACE_MAXADDR_32BIT : 2909250963Sachim 0x7fffffff, /* lowaddr */ 2910250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 2911250963Sachim NULL, NULL, /* filter, filterarg */ 2912250963Sachim srb_sg_bytecount, /* size */ 2913250963Sachim sc->aac_sg_tablesize, /* nsegments */ 2914250963Sachim srb_sg_bytecount, /* maxsegsize */ 2915250963Sachim 0, /* flags */ 2916250963Sachim NULL, NULL, /* No locking needed */ 2917250963Sachim &cm->cm_passthr_dmat)) { 2918250963Sachim error = ENOMEM; 2919250963Sachim goto out; 2920250963Sachim } 2921250963Sachim if (bus_dmamem_alloc(cm->cm_passthr_dmat, (void **)&cm->cm_data, 2922250963Sachim BUS_DMA_NOWAIT, &cm->cm_datamap)) { 2923250963Sachim error = ENOMEM; 2924250963Sachim goto out; 2925250963Sachim } 2926250963Sachim /* fill some cm variables */ 2927250963Sachim cm->cm_datalen = srb_sg_bytecount; 2928250963Sachim if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 2929250963Sachim cm->cm_flags |= AAC_CMD_DATAIN; 2930250963Sachim if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) 2931250963Sachim cm->cm_flags |= AAC_CMD_DATAOUT; 2932250963Sachim 2933250963Sachim if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 2934252778Sachim if ((error = copyin((void *)(uintptr_t)srb_sg_address, 2935250963Sachim cm->cm_data, cm->cm_datalen)) != 0) 2936250963Sachim goto out; 2937250963Sachim /* sync required for bus_dmamem_alloc() alloc. mem.? */ 2938250963Sachim bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2939250963Sachim BUS_DMASYNC_PREWRITE); 2940250963Sachim } 2941250963Sachim } 2942250963Sachim 2943250963Sachim /* build the FIB */ 2944250963Sachim fib->Header.Size = sizeof(struct aac_fib_header) + 2945250963Sachim sizeof(struct aac_srb); 2946250963Sachim fib->Header.XferState = 2947250963Sachim AAC_FIBSTATE_HOSTOWNED | 2948250963Sachim AAC_FIBSTATE_INITIALISED | 2949250963Sachim AAC_FIBSTATE_EMPTY | 2950250963Sachim AAC_FIBSTATE_FROMHOST | 2951250963Sachim AAC_FIBSTATE_REXPECTED | 2952250963Sachim AAC_FIBSTATE_NORM | 2953250963Sachim AAC_FIBSTATE_ASYNC; 2954250963Sachim 2955250963Sachim fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? 2956250963Sachim ScsiPortCommandU64 : ScsiPortCommand; 2957250963Sachim cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 2958250963Sachim 2959250963Sachim /* send command */ 2960250963Sachim if (transfer_data) { 2961250963Sachim bus_dmamap_load(cm->cm_passthr_dmat, 2962250963Sachim cm->cm_datamap, cm->cm_data, 2963250963Sachim cm->cm_datalen, 2964250963Sachim aacraid_map_command_sg, cm, 0); 2965250963Sachim } else { 2966250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 2967250963Sachim } 2968250963Sachim 2969250963Sachim /* wait for completion */ 2970250963Sachim mtx_lock(&sc->aac_io_lock); 2971250963Sachim while (!(cm->cm_flags & AAC_CMD_COMPLETED)) 2972250963Sachim msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsrw2", 0); 2973250963Sachim mtx_unlock(&sc->aac_io_lock); 2974250963Sachim 2975250963Sachim /* copy data */ 2976250963Sachim if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)) { 2977252778Sachim if ((error = copyout(cm->cm_data, 2978252778Sachim (void *)(uintptr_t)srb_sg_address, 2979250963Sachim cm->cm_datalen)) != 0) 2980250963Sachim goto out; 2981250963Sachim /* sync required for bus_dmamem_alloc() allocated mem.? */ 2982250963Sachim bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2983250963Sachim BUS_DMASYNC_POSTREAD); 2984250963Sachim } 2985250963Sachim 2986250963Sachim /* status */ 2987250963Sachim error = copyout(fib->data, user_reply, sizeof(struct aac_srb_response)); 2988250963Sachim 2989250963Sachimout: 2990250963Sachim if (cm && cm->cm_data) { 2991250963Sachim if (transfer_data) 2992250963Sachim bus_dmamap_unload(cm->cm_passthr_dmat, cm->cm_datamap); 2993250963Sachim bus_dmamem_free(cm->cm_passthr_dmat, cm->cm_data, cm->cm_datamap); 2994250963Sachim cm->cm_datamap = orig_map; 2995250963Sachim } 2996250963Sachim if (cm && cm->cm_passthr_dmat) 2997250963Sachim bus_dma_tag_destroy(cm->cm_passthr_dmat); 2998250963Sachim if (cm) { 2999250963Sachim mtx_lock(&sc->aac_io_lock); 3000250963Sachim aacraid_release_command(cm); 3001250963Sachim mtx_unlock(&sc->aac_io_lock); 3002250963Sachim } 3003250963Sachim return(error); 3004250963Sachim} 3005250963Sachim 3006250963Sachim/* 3007250963Sachim * Request an AIF from the controller (new comm. type1) 3008250963Sachim */ 3009250963Sachimstatic void 3010250963Sachimaac_request_aif(struct aac_softc *sc) 3011250963Sachim{ 3012250963Sachim struct aac_command *cm; 3013250963Sachim struct aac_fib *fib; 3014250963Sachim 3015250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3016250963Sachim 3017250963Sachim if (aacraid_alloc_command(sc, &cm)) { 3018250963Sachim sc->aif_pending = 1; 3019250963Sachim return; 3020250963Sachim } 3021250963Sachim sc->aif_pending = 0; 3022250963Sachim 3023250963Sachim /* build the FIB */ 3024250963Sachim fib = cm->cm_fib; 3025250963Sachim fib->Header.Size = sizeof(struct aac_fib); 3026250963Sachim fib->Header.XferState = 3027250963Sachim AAC_FIBSTATE_HOSTOWNED | 3028250963Sachim AAC_FIBSTATE_INITIALISED | 3029250963Sachim AAC_FIBSTATE_EMPTY | 3030250963Sachim AAC_FIBSTATE_FROMHOST | 3031250963Sachim AAC_FIBSTATE_REXPECTED | 3032250963Sachim AAC_FIBSTATE_NORM | 3033250963Sachim AAC_FIBSTATE_ASYNC; 3034250963Sachim /* set AIF marker */ 3035250963Sachim fib->Header.Handle = 0x00800000; 3036250963Sachim fib->Header.Command = AifRequest; 3037250963Sachim ((struct aac_aif_command *)fib->data)->command = AifReqEvent; 3038250963Sachim 3039250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 3040250963Sachim} 3041250963Sachim 3042250963Sachim 3043250963Sachim#if __FreeBSD_version >= 702000 3044250963Sachim/* 3045250963Sachim * cdevpriv interface private destructor. 3046250963Sachim */ 3047250963Sachimstatic void 3048250963Sachimaac_cdevpriv_dtor(void *arg) 3049250963Sachim{ 3050250963Sachim struct aac_softc *sc; 3051250963Sachim 3052250963Sachim sc = arg; 3053250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3054250963Sachim mtx_lock(&Giant); 3055250963Sachim device_unbusy(sc->aac_dev); 3056250963Sachim mtx_unlock(&Giant); 3057250963Sachim} 3058250963Sachim#else 3059250963Sachimstatic int 3060250963Sachimaac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 3061250963Sachim{ 3062250963Sachim struct aac_softc *sc; 3063250963Sachim 3064250963Sachim sc = dev->si_drv1; 3065250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3066250963Sachim return 0; 3067250963Sachim} 3068250963Sachim#endif 3069250963Sachim 3070250963Sachim/* 3071250963Sachim * Handle an AIF sent to us by the controller; queue it for later reference. 3072250963Sachim * If the queue fills up, then drop the older entries. 3073250963Sachim */ 3074250963Sachimstatic void 3075250963Sachimaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 3076250963Sachim{ 3077250963Sachim struct aac_aif_command *aif; 3078250963Sachim struct aac_container *co, *co_next; 3079250963Sachim struct aac_fib_context *ctx; 3080250963Sachim struct aac_fib *sync_fib; 3081250963Sachim struct aac_mntinforesp mir; 3082250963Sachim int next, current, found; 3083250963Sachim int count = 0, changed = 0, i = 0; 3084250963Sachim u_int32_t channel, uid; 3085250963Sachim 3086250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3087250963Sachim 3088250963Sachim aif = (struct aac_aif_command*)&fib->data[0]; 3089250963Sachim aacraid_print_aif(sc, aif); 3090250963Sachim 3091250963Sachim /* Is it an event that we should care about? */ 3092250963Sachim switch (aif->command) { 3093250963Sachim case AifCmdEventNotify: 3094250963Sachim switch (aif->data.EN.type) { 3095250963Sachim case AifEnAddContainer: 3096250963Sachim case AifEnDeleteContainer: 3097250963Sachim /* 3098250963Sachim * A container was added or deleted, but the message 3099250963Sachim * doesn't tell us anything else! Re-enumerate the 3100250963Sachim * containers and sort things out. 3101250963Sachim */ 3102250963Sachim aac_alloc_sync_fib(sc, &sync_fib); 3103250963Sachim do { 3104250963Sachim /* 3105250963Sachim * Ask the controller for its containers one at 3106250963Sachim * a time. 3107250963Sachim * XXX What if the controller's list changes 3108250963Sachim * midway through this enumaration? 3109250963Sachim * XXX This should be done async. 3110250963Sachim */ 3111250963Sachim if (aac_get_container_info(sc, sync_fib, i, 3112250963Sachim &mir, &uid) != 0) 3113250963Sachim continue; 3114250963Sachim if (i == 0) 3115250963Sachim count = mir.MntRespCount; 3116250963Sachim /* 3117250963Sachim * Check the container against our list. 3118250963Sachim * co->co_found was already set to 0 in a 3119250963Sachim * previous run. 3120250963Sachim */ 3121250963Sachim if ((mir.Status == ST_OK) && 3122250963Sachim (mir.MntTable[0].VolType != CT_NONE)) { 3123250963Sachim found = 0; 3124250963Sachim TAILQ_FOREACH(co, 3125250963Sachim &sc->aac_container_tqh, 3126250963Sachim co_link) { 3127250963Sachim if (co->co_mntobj.ObjectId == 3128250963Sachim mir.MntTable[0].ObjectId) { 3129250963Sachim co->co_found = 1; 3130250963Sachim found = 1; 3131250963Sachim break; 3132250963Sachim } 3133250963Sachim } 3134250963Sachim /* 3135250963Sachim * If the container matched, continue 3136250963Sachim * in the list. 3137250963Sachim */ 3138250963Sachim if (found) { 3139250963Sachim i++; 3140250963Sachim continue; 3141250963Sachim } 3142250963Sachim 3143250963Sachim /* 3144250963Sachim * This is a new container. Do all the 3145250963Sachim * appropriate things to set it up. 3146250963Sachim */ 3147250963Sachim aac_add_container(sc, &mir, 1, uid); 3148250963Sachim changed = 1; 3149250963Sachim } 3150250963Sachim i++; 3151250963Sachim } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3152250963Sachim aac_release_sync_fib(sc); 3153250963Sachim 3154250963Sachim /* 3155250963Sachim * Go through our list of containers and see which ones 3156250963Sachim * were not marked 'found'. Since the controller didn't 3157250963Sachim * list them they must have been deleted. Do the 3158250963Sachim * appropriate steps to destroy the device. Also reset 3159250963Sachim * the co->co_found field. 3160250963Sachim */ 3161250963Sachim co = TAILQ_FIRST(&sc->aac_container_tqh); 3162250963Sachim while (co != NULL) { 3163250963Sachim if (co->co_found == 0) { 3164250963Sachim co_next = TAILQ_NEXT(co, co_link); 3165250963Sachim TAILQ_REMOVE(&sc->aac_container_tqh, co, 3166250963Sachim co_link); 3167250963Sachim free(co, M_AACRAIDBUF); 3168250963Sachim changed = 1; 3169250963Sachim co = co_next; 3170250963Sachim } else { 3171250963Sachim co->co_found = 0; 3172250963Sachim co = TAILQ_NEXT(co, co_link); 3173250963Sachim } 3174250963Sachim } 3175250963Sachim 3176250963Sachim /* Attach the newly created containers */ 3177250963Sachim if (changed) { 3178250963Sachim if (sc->cam_rescan_cb != NULL) 3179250963Sachim sc->cam_rescan_cb(sc, 0, 3180250963Sachim AAC_CAM_TARGET_WILDCARD); 3181250963Sachim } 3182250963Sachim 3183250963Sachim break; 3184250963Sachim 3185250963Sachim case AifEnEnclosureManagement: 3186250963Sachim switch (aif->data.EN.data.EEE.eventType) { 3187250963Sachim case AIF_EM_DRIVE_INSERTION: 3188250963Sachim case AIF_EM_DRIVE_REMOVAL: 3189250963Sachim channel = aif->data.EN.data.EEE.unitID; 3190250963Sachim if (sc->cam_rescan_cb != NULL) 3191250963Sachim sc->cam_rescan_cb(sc, 3192250963Sachim ((channel>>24) & 0xF) + 1, 3193250963Sachim (channel & 0xFFFF)); 3194250963Sachim break; 3195250963Sachim } 3196250963Sachim break; 3197250963Sachim 3198250963Sachim case AifEnAddJBOD: 3199250963Sachim case AifEnDeleteJBOD: 3200250963Sachim case AifRawDeviceRemove: 3201250963Sachim channel = aif->data.EN.data.ECE.container; 3202250963Sachim if (sc->cam_rescan_cb != NULL) 3203250963Sachim sc->cam_rescan_cb(sc, ((channel>>24) & 0xF) + 1, 3204250963Sachim AAC_CAM_TARGET_WILDCARD); 3205250963Sachim break; 3206250963Sachim 3207250963Sachim default: 3208250963Sachim break; 3209250963Sachim } 3210250963Sachim 3211250963Sachim default: 3212250963Sachim break; 3213250963Sachim } 3214250963Sachim 3215250963Sachim /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3216250963Sachim current = sc->aifq_idx; 3217250963Sachim next = (current + 1) % AAC_AIFQ_LENGTH; 3218250963Sachim if (next == 0) 3219250963Sachim sc->aifq_filled = 1; 3220250963Sachim bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3221250963Sachim /* modify AIF contexts */ 3222250963Sachim if (sc->aifq_filled) { 3223250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3224250963Sachim if (next == ctx->ctx_idx) 3225250963Sachim ctx->ctx_wrap = 1; 3226250963Sachim else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3227250963Sachim ctx->ctx_idx = next; 3228250963Sachim } 3229250963Sachim } 3230250963Sachim sc->aifq_idx = next; 3231250963Sachim /* On the off chance that someone is sleeping for an aif... */ 3232250963Sachim if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 3233250963Sachim wakeup(sc->aac_aifq); 3234250963Sachim /* Wakeup any poll()ers */ 3235250963Sachim selwakeuppri(&sc->rcv_select, PRIBIO); 3236250963Sachim 3237250963Sachim return; 3238250963Sachim} 3239250963Sachim 3240250963Sachim/* 3241250963Sachim * Return the Revision of the driver to userspace and check to see if the 3242250963Sachim * userspace app is possibly compatible. This is extremely bogus since 3243250963Sachim * our driver doesn't follow Adaptec's versioning system. Cheat by just 3244250963Sachim * returning what the card reported. 3245250963Sachim */ 3246250963Sachimstatic int 3247250963Sachimaac_rev_check(struct aac_softc *sc, caddr_t udata) 3248250963Sachim{ 3249250963Sachim struct aac_rev_check rev_check; 3250250963Sachim struct aac_rev_check_resp rev_check_resp; 3251250963Sachim int error = 0; 3252250963Sachim 3253250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3254250963Sachim 3255250963Sachim /* 3256250963Sachim * Copyin the revision struct from userspace 3257250963Sachim */ 3258250963Sachim if ((error = copyin(udata, (caddr_t)&rev_check, 3259250963Sachim sizeof(struct aac_rev_check))) != 0) { 3260250963Sachim return error; 3261250963Sachim } 3262250963Sachim 3263250963Sachim fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3264250963Sachim rev_check.callingRevision.buildNumber); 3265250963Sachim 3266250963Sachim /* 3267250963Sachim * Doctor up the response struct. 3268250963Sachim */ 3269250963Sachim rev_check_resp.possiblyCompatible = 1; 3270250963Sachim rev_check_resp.adapterSWRevision.external.comp.major = 3271250963Sachim AAC_DRIVER_MAJOR_VERSION; 3272250963Sachim rev_check_resp.adapterSWRevision.external.comp.minor = 3273250963Sachim AAC_DRIVER_MINOR_VERSION; 3274250963Sachim rev_check_resp.adapterSWRevision.external.comp.type = 3275250963Sachim AAC_DRIVER_TYPE; 3276250963Sachim rev_check_resp.adapterSWRevision.external.comp.dash = 3277250963Sachim AAC_DRIVER_BUGFIX_LEVEL; 3278250963Sachim rev_check_resp.adapterSWRevision.buildNumber = 3279250963Sachim AAC_DRIVER_BUILD; 3280250963Sachim 3281250963Sachim return(copyout((caddr_t)&rev_check_resp, udata, 3282250963Sachim sizeof(struct aac_rev_check_resp))); 3283250963Sachim} 3284250963Sachim 3285250963Sachim/* 3286250963Sachim * Pass the fib context to the caller 3287250963Sachim */ 3288250963Sachimstatic int 3289250963Sachimaac_open_aif(struct aac_softc *sc, caddr_t arg) 3290250963Sachim{ 3291250963Sachim struct aac_fib_context *fibctx, *ctx; 3292250963Sachim int error = 0; 3293250963Sachim 3294250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3295250963Sachim 3296250963Sachim fibctx = malloc(sizeof(struct aac_fib_context), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 3297250963Sachim if (fibctx == NULL) 3298250963Sachim return (ENOMEM); 3299250963Sachim 3300250963Sachim mtx_lock(&sc->aac_io_lock); 3301250963Sachim /* all elements are already 0, add to queue */ 3302250963Sachim if (sc->fibctx == NULL) 3303250963Sachim sc->fibctx = fibctx; 3304250963Sachim else { 3305250963Sachim for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3306250963Sachim ; 3307250963Sachim ctx->next = fibctx; 3308250963Sachim fibctx->prev = ctx; 3309250963Sachim } 3310250963Sachim 3311250963Sachim /* evaluate unique value */ 3312250963Sachim fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3313250963Sachim ctx = sc->fibctx; 3314250963Sachim while (ctx != fibctx) { 3315250963Sachim if (ctx->unique == fibctx->unique) { 3316250963Sachim fibctx->unique++; 3317250963Sachim ctx = sc->fibctx; 3318250963Sachim } else { 3319250963Sachim ctx = ctx->next; 3320250963Sachim } 3321250963Sachim } 3322250963Sachim 3323250963Sachim error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3324250963Sachim mtx_unlock(&sc->aac_io_lock); 3325250963Sachim if (error) 3326250963Sachim aac_close_aif(sc, (caddr_t)ctx); 3327250963Sachim return error; 3328250963Sachim} 3329250963Sachim 3330250963Sachim/* 3331250963Sachim * Close the caller's fib context 3332250963Sachim */ 3333250963Sachimstatic int 3334250963Sachimaac_close_aif(struct aac_softc *sc, caddr_t arg) 3335250963Sachim{ 3336250963Sachim struct aac_fib_context *ctx; 3337250963Sachim 3338250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3339250963Sachim 3340250963Sachim mtx_lock(&sc->aac_io_lock); 3341250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3342250963Sachim if (ctx->unique == *(uint32_t *)&arg) { 3343250963Sachim if (ctx == sc->fibctx) 3344250963Sachim sc->fibctx = NULL; 3345250963Sachim else { 3346250963Sachim ctx->prev->next = ctx->next; 3347250963Sachim if (ctx->next) 3348250963Sachim ctx->next->prev = ctx->prev; 3349250963Sachim } 3350250963Sachim break; 3351250963Sachim } 3352250963Sachim } 3353250963Sachim if (ctx) 3354250963Sachim free(ctx, M_AACRAIDBUF); 3355250963Sachim 3356250963Sachim mtx_unlock(&sc->aac_io_lock); 3357250963Sachim return 0; 3358250963Sachim} 3359250963Sachim 3360250963Sachim/* 3361250963Sachim * Pass the caller the next AIF in their queue 3362250963Sachim */ 3363250963Sachimstatic int 3364250963Sachimaac_getnext_aif(struct aac_softc *sc, caddr_t arg) 3365250963Sachim{ 3366250963Sachim struct get_adapter_fib_ioctl agf; 3367250963Sachim struct aac_fib_context *ctx; 3368250963Sachim int error; 3369250963Sachim 3370250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3371250963Sachim 3372250963Sachim mtx_lock(&sc->aac_io_lock); 3373250963Sachim if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3374250963Sachim for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3375250963Sachim if (agf.AdapterFibContext == ctx->unique) 3376250963Sachim break; 3377250963Sachim } 3378250963Sachim if (!ctx) { 3379250963Sachim mtx_unlock(&sc->aac_io_lock); 3380250963Sachim return (EFAULT); 3381250963Sachim } 3382250963Sachim 3383250963Sachim error = aac_return_aif(sc, ctx, agf.AifFib); 3384250963Sachim if (error == EAGAIN && agf.Wait) { 3385250963Sachim fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 3386250963Sachim sc->aac_state |= AAC_STATE_AIF_SLEEPER; 3387250963Sachim while (error == EAGAIN) { 3388250963Sachim mtx_unlock(&sc->aac_io_lock); 3389250963Sachim error = tsleep(sc->aac_aifq, PRIBIO | 3390250963Sachim PCATCH, "aacaif", 0); 3391250963Sachim mtx_lock(&sc->aac_io_lock); 3392250963Sachim if (error == 0) 3393250963Sachim error = aac_return_aif(sc, ctx, agf.AifFib); 3394250963Sachim } 3395250963Sachim sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 3396250963Sachim } 3397250963Sachim } 3398250963Sachim mtx_unlock(&sc->aac_io_lock); 3399250963Sachim return(error); 3400250963Sachim} 3401250963Sachim 3402250963Sachim/* 3403250963Sachim * Hand the next AIF off the top of the queue out to userspace. 3404250963Sachim */ 3405250963Sachimstatic int 3406250963Sachimaac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 3407250963Sachim{ 3408250963Sachim int current, error; 3409250963Sachim 3410250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3411250963Sachim 3412250963Sachim current = ctx->ctx_idx; 3413250963Sachim if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3414250963Sachim /* empty */ 3415250963Sachim return (EAGAIN); 3416250963Sachim } 3417250963Sachim error = 3418250963Sachim copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 3419250963Sachim if (error) 3420250963Sachim device_printf(sc->aac_dev, 3421250963Sachim "aac_return_aif: copyout returned %d\n", error); 3422250963Sachim else { 3423250963Sachim ctx->ctx_wrap = 0; 3424250963Sachim ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3425250963Sachim } 3426250963Sachim return(error); 3427250963Sachim} 3428250963Sachim 3429250963Sachimstatic int 3430250963Sachimaac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3431250963Sachim{ 3432250963Sachim struct aac_pci_info { 3433250963Sachim u_int32_t bus; 3434250963Sachim u_int32_t slot; 3435250963Sachim } pciinf; 3436250963Sachim int error; 3437250963Sachim 3438250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3439250963Sachim 3440250963Sachim pciinf.bus = pci_get_bus(sc->aac_dev); 3441250963Sachim pciinf.slot = pci_get_slot(sc->aac_dev); 3442250963Sachim 3443250963Sachim error = copyout((caddr_t)&pciinf, uptr, 3444250963Sachim sizeof(struct aac_pci_info)); 3445250963Sachim 3446250963Sachim return (error); 3447250963Sachim} 3448250963Sachim 3449250963Sachimstatic int 3450250963Sachimaac_supported_features(struct aac_softc *sc, caddr_t uptr) 3451250963Sachim{ 3452250963Sachim struct aac_features f; 3453250963Sachim int error; 3454250963Sachim 3455250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3456250963Sachim 3457250963Sachim if ((error = copyin(uptr, &f, sizeof (f))) != 0) 3458250963Sachim return (error); 3459250963Sachim 3460250963Sachim /* 3461250963Sachim * When the management driver receives FSACTL_GET_FEATURES ioctl with 3462250963Sachim * ALL zero in the featuresState, the driver will return the current 3463250963Sachim * state of all the supported features, the data field will not be 3464250963Sachim * valid. 3465250963Sachim * When the management driver receives FSACTL_GET_FEATURES ioctl with 3466250963Sachim * a specific bit set in the featuresState, the driver will return the 3467250963Sachim * current state of this specific feature and whatever data that are 3468250963Sachim * associated with the feature in the data field or perform whatever 3469250963Sachim * action needed indicates in the data field. 3470250963Sachim */ 3471250963Sachim if (f.feat.fValue == 0) { 3472250963Sachim f.feat.fBits.largeLBA = 3473250963Sachim (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3474250963Sachim f.feat.fBits.JBODSupport = 1; 3475250963Sachim /* TODO: In the future, add other features state here as well */ 3476250963Sachim } else { 3477250963Sachim if (f.feat.fBits.largeLBA) 3478250963Sachim f.feat.fBits.largeLBA = 3479250963Sachim (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3480250963Sachim /* TODO: Add other features state and data in the future */ 3481250963Sachim } 3482250963Sachim 3483250963Sachim error = copyout(&f, uptr, sizeof (f)); 3484250963Sachim return (error); 3485250963Sachim} 3486250963Sachim 3487250963Sachim/* 3488250963Sachim * Give the userland some information about the container. The AAC arch 3489250963Sachim * expects the driver to be a SCSI passthrough type driver, so it expects 3490250963Sachim * the containers to have b:t:l numbers. Fake it. 3491250963Sachim */ 3492250963Sachimstatic int 3493250963Sachimaac_query_disk(struct aac_softc *sc, caddr_t uptr) 3494250963Sachim{ 3495250963Sachim struct aac_query_disk query_disk; 3496250963Sachim struct aac_container *co; 3497250963Sachim int error, id; 3498250963Sachim 3499250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3500250963Sachim 3501250963Sachim mtx_lock(&sc->aac_io_lock); 3502250963Sachim error = copyin(uptr, (caddr_t)&query_disk, 3503250963Sachim sizeof(struct aac_query_disk)); 3504250963Sachim if (error) { 3505250963Sachim mtx_unlock(&sc->aac_io_lock); 3506250963Sachim return (error); 3507250963Sachim } 3508250963Sachim 3509250963Sachim id = query_disk.ContainerNumber; 3510250963Sachim if (id == -1) { 3511250963Sachim mtx_unlock(&sc->aac_io_lock); 3512250963Sachim return (EINVAL); 3513250963Sachim } 3514250963Sachim 3515250963Sachim TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 3516250963Sachim if (co->co_mntobj.ObjectId == id) 3517250963Sachim break; 3518250963Sachim } 3519250963Sachim 3520250963Sachim if (co == NULL) { 3521250963Sachim query_disk.Valid = 0; 3522250963Sachim query_disk.Locked = 0; 3523250963Sachim query_disk.Deleted = 1; /* XXX is this right? */ 3524250963Sachim } else { 3525250963Sachim query_disk.Valid = 1; 3526250963Sachim query_disk.Locked = 1; 3527250963Sachim query_disk.Deleted = 0; 3528250963Sachim query_disk.Bus = device_get_unit(sc->aac_dev); 3529250963Sachim query_disk.Target = 0; 3530250963Sachim query_disk.Lun = 0; 3531250963Sachim query_disk.UnMapped = 0; 3532250963Sachim } 3533250963Sachim 3534250963Sachim error = copyout((caddr_t)&query_disk, uptr, 3535250963Sachim sizeof(struct aac_query_disk)); 3536250963Sachim 3537250963Sachim mtx_unlock(&sc->aac_io_lock); 3538250963Sachim return (error); 3539250963Sachim} 3540250963Sachim 3541250963Sachimstatic void 3542250963Sachimaac_container_bus(struct aac_softc *sc) 3543250963Sachim{ 3544250963Sachim struct aac_sim *sim; 3545250963Sachim device_t child; 3546250963Sachim 3547250963Sachim sim =(struct aac_sim *)malloc(sizeof(struct aac_sim), 3548250963Sachim M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3549250963Sachim if (sim == NULL) { 3550250963Sachim device_printf(sc->aac_dev, 3551250963Sachim "No memory to add container bus\n"); 3552250963Sachim panic("Out of memory?!"); 3553250963Sachim }; 3554250963Sachim child = device_add_child(sc->aac_dev, "aacraidp", -1); 3555250963Sachim if (child == NULL) { 3556250963Sachim device_printf(sc->aac_dev, 3557250963Sachim "device_add_child failed for container bus\n"); 3558250963Sachim free(sim, M_AACRAIDBUF); 3559250963Sachim panic("Out of memory?!"); 3560250963Sachim } 3561250963Sachim 3562250963Sachim sim->TargetsPerBus = AAC_MAX_CONTAINERS; 3563250963Sachim sim->BusNumber = 0; 3564250963Sachim sim->BusType = CONTAINER_BUS; 3565250963Sachim sim->InitiatorBusId = -1; 3566250963Sachim sim->aac_sc = sc; 3567250963Sachim sim->sim_dev = child; 3568250963Sachim sim->aac_cam = NULL; 3569250963Sachim 3570250963Sachim device_set_ivars(child, sim); 3571250963Sachim device_set_desc(child, "Container Bus"); 3572250963Sachim TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, sim, sim_link); 3573250963Sachim /* 3574250963Sachim device_set_desc(child, aac_describe_code(aac_container_types, 3575250963Sachim mir->MntTable[0].VolType)); 3576250963Sachim */ 3577250963Sachim bus_generic_attach(sc->aac_dev); 3578250963Sachim} 3579250963Sachim 3580250963Sachimstatic void 3581250963Sachimaac_get_bus_info(struct aac_softc *sc) 3582250963Sachim{ 3583250963Sachim struct aac_fib *fib; 3584250963Sachim struct aac_ctcfg *c_cmd; 3585250963Sachim struct aac_ctcfg_resp *c_resp; 3586250963Sachim struct aac_vmioctl *vmi; 3587250963Sachim struct aac_vmi_businf_resp *vmi_resp; 3588250963Sachim struct aac_getbusinf businfo; 3589250963Sachim struct aac_sim *caminf; 3590250963Sachim device_t child; 3591250963Sachim int i, error; 3592250963Sachim 3593250963Sachim mtx_lock(&sc->aac_io_lock); 3594250963Sachim aac_alloc_sync_fib(sc, &fib); 3595250963Sachim c_cmd = (struct aac_ctcfg *)&fib->data[0]; 3596250963Sachim bzero(c_cmd, sizeof(struct aac_ctcfg)); 3597250963Sachim 3598250963Sachim c_cmd->Command = VM_ContainerConfig; 3599250963Sachim c_cmd->cmd = CT_GET_SCSI_METHOD; 3600250963Sachim c_cmd->param = 0; 3601250963Sachim 3602250963Sachim error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3603250963Sachim sizeof(struct aac_ctcfg)); 3604250963Sachim if (error) { 3605250963Sachim device_printf(sc->aac_dev, "Error %d sending " 3606250963Sachim "VM_ContainerConfig command\n", error); 3607250963Sachim aac_release_sync_fib(sc); 3608250963Sachim mtx_unlock(&sc->aac_io_lock); 3609250963Sachim return; 3610250963Sachim } 3611250963Sachim 3612250963Sachim c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3613250963Sachim if (c_resp->Status != ST_OK) { 3614250963Sachim device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3615250963Sachim c_resp->Status); 3616250963Sachim aac_release_sync_fib(sc); 3617250963Sachim mtx_unlock(&sc->aac_io_lock); 3618250963Sachim return; 3619250963Sachim } 3620250963Sachim 3621250963Sachim sc->scsi_method_id = c_resp->param; 3622250963Sachim 3623250963Sachim vmi = (struct aac_vmioctl *)&fib->data[0]; 3624250963Sachim bzero(vmi, sizeof(struct aac_vmioctl)); 3625250963Sachim 3626250963Sachim vmi->Command = VM_Ioctl; 3627250963Sachim vmi->ObjType = FT_DRIVE; 3628250963Sachim vmi->MethId = sc->scsi_method_id; 3629250963Sachim vmi->ObjId = 0; 3630250963Sachim vmi->IoctlCmd = GetBusInfo; 3631250963Sachim 3632250963Sachim error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3633250963Sachim sizeof(struct aac_vmi_businf_resp)); 3634250963Sachim if (error) { 3635250963Sachim device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3636250963Sachim error); 3637250963Sachim aac_release_sync_fib(sc); 3638250963Sachim mtx_unlock(&sc->aac_io_lock); 3639250963Sachim return; 3640250963Sachim } 3641250963Sachim 3642250963Sachim vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3643250963Sachim if (vmi_resp->Status != ST_OK) { 3644250963Sachim device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3645250963Sachim vmi_resp->Status); 3646250963Sachim aac_release_sync_fib(sc); 3647250963Sachim mtx_unlock(&sc->aac_io_lock); 3648250963Sachim return; 3649250963Sachim } 3650250963Sachim 3651250963Sachim bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3652250963Sachim aac_release_sync_fib(sc); 3653250963Sachim mtx_unlock(&sc->aac_io_lock); 3654250963Sachim 3655250963Sachim for (i = 0; i < businfo.BusCount; i++) { 3656250963Sachim if (businfo.BusValid[i] != AAC_BUS_VALID) 3657250963Sachim continue; 3658250963Sachim 3659250963Sachim caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3660250963Sachim M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3661250963Sachim if (caminf == NULL) { 3662250963Sachim device_printf(sc->aac_dev, 3663250963Sachim "No memory to add passthrough bus %d\n", i); 3664250963Sachim break; 3665250963Sachim }; 3666250963Sachim 3667250963Sachim child = device_add_child(sc->aac_dev, "aacraidp", -1); 3668250963Sachim if (child == NULL) { 3669250963Sachim device_printf(sc->aac_dev, 3670250963Sachim "device_add_child failed for passthrough bus %d\n", 3671250963Sachim i); 3672250963Sachim free(caminf, M_AACRAIDBUF); 3673250963Sachim break; 3674250963Sachim } 3675250963Sachim 3676250963Sachim caminf->TargetsPerBus = businfo.TargetsPerBus; 3677250963Sachim caminf->BusNumber = i+1; 3678250963Sachim caminf->BusType = PASSTHROUGH_BUS; 3679250963Sachim caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3680250963Sachim caminf->aac_sc = sc; 3681250963Sachim caminf->sim_dev = child; 3682250963Sachim caminf->aac_cam = NULL; 3683250963Sachim 3684250963Sachim device_set_ivars(child, caminf); 3685250963Sachim device_set_desc(child, "SCSI Passthrough Bus"); 3686250963Sachim TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3687250963Sachim } 3688250963Sachim} 3689250963Sachim 3690250963Sachim/* 3691250963Sachim * Check to see if the kernel is up and running. If we are in a 3692250963Sachim * BlinkLED state, return the BlinkLED code. 3693250963Sachim */ 3694250963Sachimstatic u_int32_t 3695250963Sachimaac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled) 3696250963Sachim{ 3697250963Sachim u_int32_t ret; 3698250963Sachim 3699250963Sachim ret = AAC_GET_FWSTATUS(sc); 3700250963Sachim 3701250963Sachim if (ret & AAC_UP_AND_RUNNING) 3702250963Sachim ret = 0; 3703250963Sachim else if (ret & AAC_KERNEL_PANIC && bled) 3704250963Sachim *bled = (ret >> 16) & 0xff; 3705250963Sachim 3706250963Sachim return (ret); 3707250963Sachim} 3708250963Sachim 3709250963Sachim/* 3710250963Sachim * Once do an IOP reset, basically have to re-initialize the card as 3711250963Sachim * if coming up from a cold boot, and the driver is responsible for 3712250963Sachim * any IO that was outstanding to the adapter at the time of the IOP 3713250963Sachim * RESET. And prepare the driver for IOP RESET by making the init code 3714250963Sachim * modular with the ability to call it from multiple places. 3715250963Sachim */ 3716250963Sachimstatic int 3717250963Sachimaac_reset_adapter(struct aac_softc *sc) 3718250963Sachim{ 3719250963Sachim struct aac_command *cm; 3720250963Sachim struct aac_fib *fib; 3721250963Sachim struct aac_pause_command *pc; 3722263340Sachim u_int32_t status, reset_mask, waitCount, max_msix_orig; 3723263340Sachim int msi_enabled_orig; 3724250963Sachim 3725250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3726263340Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 3727250963Sachim 3728250963Sachim if (sc->aac_state & AAC_STATE_RESET) { 3729250963Sachim device_printf(sc->aac_dev, "aac_reset_adapter() already in progress\n"); 3730250963Sachim return (EINVAL); 3731250963Sachim } 3732250963Sachim sc->aac_state |= AAC_STATE_RESET; 3733250963Sachim 3734250963Sachim /* disable interrupt */ 3735263340Sachim AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT); 3736250963Sachim 3737250963Sachim /* 3738250963Sachim * Abort all pending commands: 3739250963Sachim * a) on the controller 3740250963Sachim */ 3741250963Sachim while ((cm = aac_dequeue_busy(sc)) != NULL) { 3742250963Sachim cm->cm_flags |= AAC_CMD_RESET; 3743250963Sachim 3744250963Sachim /* is there a completion handler? */ 3745250963Sachim if (cm->cm_complete != NULL) { 3746250963Sachim cm->cm_complete(cm); 3747250963Sachim } else { 3748250963Sachim /* assume that someone is sleeping on this 3749250963Sachim * command 3750250963Sachim */ 3751250963Sachim wakeup(cm); 3752250963Sachim } 3753250963Sachim } 3754250963Sachim 3755250963Sachim /* b) in the waiting queues */ 3756250963Sachim while ((cm = aac_dequeue_ready(sc)) != NULL) { 3757250963Sachim cm->cm_flags |= AAC_CMD_RESET; 3758250963Sachim 3759250963Sachim /* is there a completion handler? */ 3760250963Sachim if (cm->cm_complete != NULL) { 3761250963Sachim cm->cm_complete(cm); 3762250963Sachim } else { 3763250963Sachim /* assume that someone is sleeping on this 3764250963Sachim * command 3765250963Sachim */ 3766250963Sachim wakeup(cm); 3767250963Sachim } 3768250963Sachim } 3769250963Sachim 3770250963Sachim /* flush drives */ 3771250963Sachim if (aac_check_adapter_health(sc, NULL) == 0) { 3772250963Sachim mtx_unlock(&sc->aac_io_lock); 3773250963Sachim (void) aacraid_shutdown(sc->aac_dev); 3774250963Sachim mtx_lock(&sc->aac_io_lock); 3775250963Sachim } 3776250963Sachim 3777250963Sachim /* execute IOP reset */ 3778250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_MU_RESET) { 3779250963Sachim AAC_MEM0_SETREG4(sc, AAC_IRCSR, AAC_IRCSR_CORES_RST); 3780250963Sachim 3781250963Sachim /* We need to wait for 5 seconds before accessing the MU again 3782250963Sachim * 10000 * 100us = 1000,000us = 1000ms = 1s 3783250963Sachim */ 3784250963Sachim waitCount = 5 * 10000; 3785250963Sachim while (waitCount) { 3786250963Sachim DELAY(100); /* delay 100 microseconds */ 3787250963Sachim waitCount--; 3788250963Sachim } 3789250963Sachim } else if ((aacraid_sync_command(sc, 3790250963Sachim AAC_IOP_RESET_ALWAYS, 0, 0, 0, 0, &status, &reset_mask)) != 0) { 3791250963Sachim /* call IOP_RESET for older firmware */ 3792250963Sachim if ((aacraid_sync_command(sc, 3793250963Sachim AAC_IOP_RESET, 0, 0, 0, 0, &status, NULL)) != 0) { 3794250963Sachim 3795250963Sachim if (status == AAC_SRB_STS_INVALID_REQUEST) 3796250963Sachim device_printf(sc->aac_dev, "IOP_RESET not supported\n"); 3797250963Sachim else 3798250963Sachim /* probably timeout */ 3799250963Sachim device_printf(sc->aac_dev, "IOP_RESET failed\n"); 3800250963Sachim 3801250963Sachim /* unwind aac_shutdown() */ 3802250963Sachim aac_alloc_sync_fib(sc, &fib); 3803250963Sachim pc = (struct aac_pause_command *)&fib->data[0]; 3804250963Sachim pc->Command = VM_ContainerConfig; 3805250963Sachim pc->Type = CT_PAUSE_IO; 3806250963Sachim pc->Timeout = 1; 3807250963Sachim pc->Min = 1; 3808250963Sachim pc->NoRescan = 1; 3809250963Sachim 3810250963Sachim (void) aac_sync_fib(sc, ContainerCommand, 0, fib, 3811250963Sachim sizeof (struct aac_pause_command)); 3812250963Sachim aac_release_sync_fib(sc); 3813250963Sachim 3814250963Sachim goto finish; 3815250963Sachim } 3816250963Sachim } else if (sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET) { 3817250963Sachim AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask); 3818263340Sachim /* 3819263340Sachim * We need to wait for 5 seconds before accessing the doorbell 3820263340Sachim * again, 10000 * 100us = 1000,000us = 1000ms = 1s 3821250963Sachim */ 3822250963Sachim waitCount = 5 * 10000; 3823250963Sachim while (waitCount) { 3824263340Sachim DELAY(100); /* delay 100 microseconds */ 3825250963Sachim waitCount--; 3826250963Sachim } 3827250963Sachim } 3828250963Sachim 3829250963Sachim /* 3830250963Sachim * Initialize the adapter. 3831250963Sachim */ 3832263340Sachim max_msix_orig = sc->aac_max_msix; 3833263340Sachim msi_enabled_orig = sc->msi_enabled; 3834263340Sachim sc->msi_enabled = FALSE; 3835250963Sachim if (aac_check_firmware(sc) != 0) 3836250963Sachim goto finish; 3837250963Sachim if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 3838263340Sachim sc->aac_max_msix = max_msix_orig; 3839263340Sachim if (msi_enabled_orig) { 3840263340Sachim sc->msi_enabled = msi_enabled_orig; 3841263340Sachim AAC_ACCESS_DEVREG(sc, AAC_ENABLE_MSIX); 3842263340Sachim } 3843263340Sachim mtx_unlock(&sc->aac_io_lock); 3844263340Sachim aac_init(sc); 3845263340Sachim mtx_lock(&sc->aac_io_lock); 3846250963Sachim } 3847250963Sachim 3848250963Sachimfinish: 3849250963Sachim sc->aac_state &= ~AAC_STATE_RESET; 3850263340Sachim AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT); 3851250963Sachim aacraid_startio(sc); 3852250963Sachim return (0); 3853250963Sachim} 3854