1*dce93cd0SAchim Leubner /*- 2*dce93cd0SAchim Leubner * Copyright (c) 2000 Michael Smith 3*dce93cd0SAchim Leubner * Copyright (c) 2001 Scott Long 4*dce93cd0SAchim Leubner * Copyright (c) 2000 BSDi 5*dce93cd0SAchim Leubner * Copyright (c) 2001-2010 Adaptec, Inc. 6*dce93cd0SAchim Leubner * Copyright (c) 2010-2012 PMC-Sierra, Inc. 7*dce93cd0SAchim Leubner * All rights reserved. 8*dce93cd0SAchim Leubner * 9*dce93cd0SAchim Leubner * Redistribution and use in source and binary forms, with or without 10*dce93cd0SAchim Leubner * modification, are permitted provided that the following conditions 11*dce93cd0SAchim Leubner * are met: 12*dce93cd0SAchim Leubner * 1. Redistributions of source code must retain the above copyright 13*dce93cd0SAchim Leubner * notice, this list of conditions and the following disclaimer. 14*dce93cd0SAchim Leubner * 2. Redistributions in binary form must reproduce the above copyright 15*dce93cd0SAchim Leubner * notice, this list of conditions and the following disclaimer in the 16*dce93cd0SAchim Leubner * documentation and/or other materials provided with the distribution. 17*dce93cd0SAchim Leubner * 18*dce93cd0SAchim Leubner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*dce93cd0SAchim Leubner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*dce93cd0SAchim Leubner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*dce93cd0SAchim Leubner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*dce93cd0SAchim Leubner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*dce93cd0SAchim Leubner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*dce93cd0SAchim Leubner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*dce93cd0SAchim Leubner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*dce93cd0SAchim Leubner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*dce93cd0SAchim Leubner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*dce93cd0SAchim Leubner * SUCH DAMAGE. 29*dce93cd0SAchim Leubner */ 30*dce93cd0SAchim Leubner 31*dce93cd0SAchim Leubner #include <sys/cdefs.h> 32*dce93cd0SAchim Leubner __FBSDID("$FreeBSD$"); 33*dce93cd0SAchim Leubner 34*dce93cd0SAchim Leubner /* 35*dce93cd0SAchim Leubner * Driver for the Adaptec by PMC Series 6,7,8,... families of RAID controllers 36*dce93cd0SAchim Leubner */ 37*dce93cd0SAchim Leubner #define AAC_DRIVERNAME "aacraid" 38*dce93cd0SAchim Leubner 39*dce93cd0SAchim Leubner #include "opt_aacraid.h" 40*dce93cd0SAchim Leubner 41*dce93cd0SAchim Leubner /* #include <stddef.h> */ 42*dce93cd0SAchim Leubner #include <sys/param.h> 43*dce93cd0SAchim Leubner #include <sys/systm.h> 44*dce93cd0SAchim Leubner #include <sys/malloc.h> 45*dce93cd0SAchim Leubner #include <sys/kernel.h> 46*dce93cd0SAchim Leubner #include <sys/kthread.h> 47*dce93cd0SAchim Leubner #include <sys/sysctl.h> 48*dce93cd0SAchim Leubner #include <sys/poll.h> 49*dce93cd0SAchim Leubner #include <sys/ioccom.h> 50*dce93cd0SAchim Leubner 51*dce93cd0SAchim Leubner #include <sys/bus.h> 52*dce93cd0SAchim Leubner #include <sys/conf.h> 53*dce93cd0SAchim Leubner #include <sys/signalvar.h> 54*dce93cd0SAchim Leubner #include <sys/time.h> 55*dce93cd0SAchim Leubner #include <sys/eventhandler.h> 56*dce93cd0SAchim Leubner #include <sys/rman.h> 57*dce93cd0SAchim Leubner 58*dce93cd0SAchim Leubner #include <machine/bus.h> 59*dce93cd0SAchim Leubner #include <sys/bus_dma.h> 60*dce93cd0SAchim Leubner #include <machine/resource.h> 61*dce93cd0SAchim Leubner 62*dce93cd0SAchim Leubner #include <dev/pci/pcireg.h> 63*dce93cd0SAchim Leubner #include <dev/pci/pcivar.h> 64*dce93cd0SAchim Leubner 65*dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_reg.h> 66*dce93cd0SAchim Leubner #include <sys/aac_ioctl.h> 67*dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_debug.h> 68*dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_var.h> 69*dce93cd0SAchim Leubner 70*dce93cd0SAchim Leubner #ifndef FILTER_HANDLED 71*dce93cd0SAchim Leubner #define FILTER_HANDLED 0x02 72*dce93cd0SAchim Leubner #endif 73*dce93cd0SAchim Leubner 74*dce93cd0SAchim Leubner static void aac_add_container(struct aac_softc *sc, 75*dce93cd0SAchim Leubner struct aac_mntinforesp *mir, int f, 76*dce93cd0SAchim Leubner u_int32_t uid); 77*dce93cd0SAchim Leubner static void aac_get_bus_info(struct aac_softc *sc); 78*dce93cd0SAchim Leubner static void aac_container_bus(struct aac_softc *sc); 79*dce93cd0SAchim Leubner static void aac_daemon(void *arg); 80*dce93cd0SAchim Leubner static int aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 81*dce93cd0SAchim Leubner int pages, int nseg, int nseg_new); 82*dce93cd0SAchim Leubner 83*dce93cd0SAchim Leubner /* Command Processing */ 84*dce93cd0SAchim Leubner static void aac_timeout(struct aac_softc *sc); 85*dce93cd0SAchim Leubner static void aac_command_thread(struct aac_softc *sc); 86*dce93cd0SAchim Leubner static int aac_sync_fib(struct aac_softc *sc, u_int32_t command, 87*dce93cd0SAchim Leubner u_int32_t xferstate, struct aac_fib *fib, 88*dce93cd0SAchim Leubner u_int16_t datasize); 89*dce93cd0SAchim Leubner /* Command Buffer Management */ 90*dce93cd0SAchim Leubner static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 91*dce93cd0SAchim Leubner int nseg, int error); 92*dce93cd0SAchim Leubner static int aac_alloc_commands(struct aac_softc *sc); 93*dce93cd0SAchim Leubner static void aac_free_commands(struct aac_softc *sc); 94*dce93cd0SAchim Leubner static void aac_unmap_command(struct aac_command *cm); 95*dce93cd0SAchim Leubner 96*dce93cd0SAchim Leubner /* Hardware Interface */ 97*dce93cd0SAchim Leubner static int aac_alloc(struct aac_softc *sc); 98*dce93cd0SAchim Leubner static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 99*dce93cd0SAchim Leubner int error); 100*dce93cd0SAchim Leubner static int aac_check_firmware(struct aac_softc *sc); 101*dce93cd0SAchim Leubner static int aac_init(struct aac_softc *sc); 102*dce93cd0SAchim Leubner static int aac_setup_intr(struct aac_softc *sc); 103*dce93cd0SAchim Leubner 104*dce93cd0SAchim Leubner /* PMC SRC interface */ 105*dce93cd0SAchim Leubner static int aac_src_get_fwstatus(struct aac_softc *sc); 106*dce93cd0SAchim Leubner static void aac_src_qnotify(struct aac_softc *sc, int qbit); 107*dce93cd0SAchim Leubner static int aac_src_get_istatus(struct aac_softc *sc); 108*dce93cd0SAchim Leubner static void aac_src_clear_istatus(struct aac_softc *sc, int mask); 109*dce93cd0SAchim Leubner static void aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, 110*dce93cd0SAchim Leubner u_int32_t arg0, u_int32_t arg1, 111*dce93cd0SAchim Leubner u_int32_t arg2, u_int32_t arg3); 112*dce93cd0SAchim Leubner static int aac_src_get_mailbox(struct aac_softc *sc, int mb); 113*dce93cd0SAchim Leubner static void aac_src_set_interrupts(struct aac_softc *sc, int enable); 114*dce93cd0SAchim Leubner static int aac_src_send_command(struct aac_softc *sc, struct aac_command *cm); 115*dce93cd0SAchim Leubner static int aac_src_get_outb_queue(struct aac_softc *sc); 116*dce93cd0SAchim Leubner static void aac_src_set_outb_queue(struct aac_softc *sc, int index); 117*dce93cd0SAchim Leubner 118*dce93cd0SAchim Leubner struct aac_interface aacraid_src_interface = { 119*dce93cd0SAchim Leubner aac_src_get_fwstatus, 120*dce93cd0SAchim Leubner aac_src_qnotify, 121*dce93cd0SAchim Leubner aac_src_get_istatus, 122*dce93cd0SAchim Leubner aac_src_clear_istatus, 123*dce93cd0SAchim Leubner aac_src_set_mailbox, 124*dce93cd0SAchim Leubner aac_src_get_mailbox, 125*dce93cd0SAchim Leubner aac_src_set_interrupts, 126*dce93cd0SAchim Leubner aac_src_send_command, 127*dce93cd0SAchim Leubner aac_src_get_outb_queue, 128*dce93cd0SAchim Leubner aac_src_set_outb_queue 129*dce93cd0SAchim Leubner }; 130*dce93cd0SAchim Leubner 131*dce93cd0SAchim Leubner /* PMC SRCv interface */ 132*dce93cd0SAchim Leubner static void aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, 133*dce93cd0SAchim Leubner u_int32_t arg0, u_int32_t arg1, 134*dce93cd0SAchim Leubner u_int32_t arg2, u_int32_t arg3); 135*dce93cd0SAchim Leubner static int aac_srcv_get_mailbox(struct aac_softc *sc, int mb); 136*dce93cd0SAchim Leubner 137*dce93cd0SAchim Leubner struct aac_interface aacraid_srcv_interface = { 138*dce93cd0SAchim Leubner aac_src_get_fwstatus, 139*dce93cd0SAchim Leubner aac_src_qnotify, 140*dce93cd0SAchim Leubner aac_src_get_istatus, 141*dce93cd0SAchim Leubner aac_src_clear_istatus, 142*dce93cd0SAchim Leubner aac_srcv_set_mailbox, 143*dce93cd0SAchim Leubner aac_srcv_get_mailbox, 144*dce93cd0SAchim Leubner aac_src_set_interrupts, 145*dce93cd0SAchim Leubner aac_src_send_command, 146*dce93cd0SAchim Leubner aac_src_get_outb_queue, 147*dce93cd0SAchim Leubner aac_src_set_outb_queue 148*dce93cd0SAchim Leubner }; 149*dce93cd0SAchim Leubner 150*dce93cd0SAchim Leubner /* Debugging and Diagnostics */ 151*dce93cd0SAchim Leubner static struct aac_code_lookup aac_cpu_variant[] = { 152*dce93cd0SAchim Leubner {"i960JX", CPUI960_JX}, 153*dce93cd0SAchim Leubner {"i960CX", CPUI960_CX}, 154*dce93cd0SAchim Leubner {"i960HX", CPUI960_HX}, 155*dce93cd0SAchim Leubner {"i960RX", CPUI960_RX}, 156*dce93cd0SAchim Leubner {"i960 80303", CPUI960_80303}, 157*dce93cd0SAchim Leubner {"StrongARM SA110", CPUARM_SA110}, 158*dce93cd0SAchim Leubner {"PPC603e", CPUPPC_603e}, 159*dce93cd0SAchim Leubner {"XScale 80321", CPU_XSCALE_80321}, 160*dce93cd0SAchim Leubner {"MIPS 4KC", CPU_MIPS_4KC}, 161*dce93cd0SAchim Leubner {"MIPS 5KC", CPU_MIPS_5KC}, 162*dce93cd0SAchim Leubner {"Unknown StrongARM", CPUARM_xxx}, 163*dce93cd0SAchim Leubner {"Unknown PowerPC", CPUPPC_xxx}, 164*dce93cd0SAchim Leubner {NULL, 0}, 165*dce93cd0SAchim Leubner {"Unknown processor", 0} 166*dce93cd0SAchim Leubner }; 167*dce93cd0SAchim Leubner 168*dce93cd0SAchim Leubner static struct aac_code_lookup aac_battery_platform[] = { 169*dce93cd0SAchim Leubner {"required battery present", PLATFORM_BAT_REQ_PRESENT}, 170*dce93cd0SAchim Leubner {"REQUIRED BATTERY NOT PRESENT", PLATFORM_BAT_REQ_NOTPRESENT}, 171*dce93cd0SAchim Leubner {"optional battery present", PLATFORM_BAT_OPT_PRESENT}, 172*dce93cd0SAchim Leubner {"optional battery not installed", PLATFORM_BAT_OPT_NOTPRESENT}, 173*dce93cd0SAchim Leubner {"no battery support", PLATFORM_BAT_NOT_SUPPORTED}, 174*dce93cd0SAchim Leubner {NULL, 0}, 175*dce93cd0SAchim Leubner {"unknown battery platform", 0} 176*dce93cd0SAchim Leubner }; 177*dce93cd0SAchim Leubner static void aac_describe_controller(struct aac_softc *sc); 178*dce93cd0SAchim Leubner static char *aac_describe_code(struct aac_code_lookup *table, 179*dce93cd0SAchim Leubner u_int32_t code); 180*dce93cd0SAchim Leubner 181*dce93cd0SAchim Leubner /* Management Interface */ 182*dce93cd0SAchim Leubner static d_open_t aac_open; 183*dce93cd0SAchim Leubner static d_ioctl_t aac_ioctl; 184*dce93cd0SAchim Leubner static d_poll_t aac_poll; 185*dce93cd0SAchim Leubner #if __FreeBSD_version >= 702000 186*dce93cd0SAchim Leubner static void aac_cdevpriv_dtor(void *arg); 187*dce93cd0SAchim Leubner #else 188*dce93cd0SAchim Leubner static d_close_t aac_close; 189*dce93cd0SAchim Leubner #endif 190*dce93cd0SAchim Leubner static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 191*dce93cd0SAchim Leubner static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 192*dce93cd0SAchim Leubner static void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); 193*dce93cd0SAchim Leubner static void aac_request_aif(struct aac_softc *sc); 194*dce93cd0SAchim Leubner static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 195*dce93cd0SAchim Leubner static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 196*dce93cd0SAchim Leubner static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 197*dce93cd0SAchim Leubner static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 198*dce93cd0SAchim Leubner static int aac_return_aif(struct aac_softc *sc, 199*dce93cd0SAchim Leubner struct aac_fib_context *ctx, caddr_t uptr); 200*dce93cd0SAchim Leubner static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 201*dce93cd0SAchim Leubner static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 202*dce93cd0SAchim Leubner static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 203*dce93cd0SAchim Leubner static void aac_ioctl_event(struct aac_softc *sc, 204*dce93cd0SAchim Leubner struct aac_event *event, void *arg); 205*dce93cd0SAchim Leubner static int aac_reset_adapter(struct aac_softc *sc); 206*dce93cd0SAchim Leubner static int aac_get_container_info(struct aac_softc *sc, 207*dce93cd0SAchim Leubner struct aac_fib *fib, int cid, 208*dce93cd0SAchim Leubner struct aac_mntinforesp *mir, 209*dce93cd0SAchim Leubner u_int32_t *uid); 210*dce93cd0SAchim Leubner static u_int32_t 211*dce93cd0SAchim Leubner aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled); 212*dce93cd0SAchim Leubner 213*dce93cd0SAchim Leubner static struct cdevsw aacraid_cdevsw = { 214*dce93cd0SAchim Leubner .d_version = D_VERSION, 215*dce93cd0SAchim Leubner .d_flags = D_NEEDGIANT, 216*dce93cd0SAchim Leubner .d_open = aac_open, 217*dce93cd0SAchim Leubner #if __FreeBSD_version < 702000 218*dce93cd0SAchim Leubner .d_close = aac_close, 219*dce93cd0SAchim Leubner #endif 220*dce93cd0SAchim Leubner .d_ioctl = aac_ioctl, 221*dce93cd0SAchim Leubner .d_poll = aac_poll, 222*dce93cd0SAchim Leubner .d_name = "aacraid", 223*dce93cd0SAchim Leubner }; 224*dce93cd0SAchim Leubner 225*dce93cd0SAchim Leubner MALLOC_DEFINE(M_AACRAIDBUF, "aacraid_buf", "Buffers for the AACRAID driver"); 226*dce93cd0SAchim Leubner 227*dce93cd0SAchim Leubner /* sysctl node */ 228*dce93cd0SAchim Leubner SYSCTL_NODE(_hw, OID_AUTO, aacraid, CTLFLAG_RD, 0, "AACRAID driver parameters"); 229*dce93cd0SAchim Leubner 230*dce93cd0SAchim Leubner /* 231*dce93cd0SAchim Leubner * Device Interface 232*dce93cd0SAchim Leubner */ 233*dce93cd0SAchim Leubner 234*dce93cd0SAchim Leubner /* 235*dce93cd0SAchim Leubner * Initialize the controller and softc 236*dce93cd0SAchim Leubner */ 237*dce93cd0SAchim Leubner int 238*dce93cd0SAchim Leubner aacraid_attach(struct aac_softc *sc) 239*dce93cd0SAchim Leubner { 240*dce93cd0SAchim Leubner int error, unit; 241*dce93cd0SAchim Leubner struct aac_fib *fib; 242*dce93cd0SAchim Leubner struct aac_mntinforesp mir; 243*dce93cd0SAchim Leubner int count = 0, i = 0; 244*dce93cd0SAchim Leubner u_int32_t uid; 245*dce93cd0SAchim Leubner 246*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 247*dce93cd0SAchim Leubner sc->hint_flags = device_get_flags(sc->aac_dev); 248*dce93cd0SAchim Leubner /* 249*dce93cd0SAchim Leubner * Initialize per-controller queues. 250*dce93cd0SAchim Leubner */ 251*dce93cd0SAchim Leubner aac_initq_free(sc); 252*dce93cd0SAchim Leubner aac_initq_ready(sc); 253*dce93cd0SAchim Leubner aac_initq_busy(sc); 254*dce93cd0SAchim Leubner 255*dce93cd0SAchim Leubner /* mark controller as suspended until we get ourselves organised */ 256*dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_SUSPEND; 257*dce93cd0SAchim Leubner 258*dce93cd0SAchim Leubner /* 259*dce93cd0SAchim Leubner * Check that the firmware on the card is supported. 260*dce93cd0SAchim Leubner */ 261*dce93cd0SAchim Leubner if ((error = aac_check_firmware(sc)) != 0) 262*dce93cd0SAchim Leubner return(error); 263*dce93cd0SAchim Leubner 264*dce93cd0SAchim Leubner /* 265*dce93cd0SAchim Leubner * Initialize locks 266*dce93cd0SAchim Leubner */ 267*dce93cd0SAchim Leubner mtx_init(&sc->aac_io_lock, "AACRAID I/O lock", NULL, MTX_DEF); 268*dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_container_tqh); 269*dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_ev_cmfree); 270*dce93cd0SAchim Leubner 271*dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 272*dce93cd0SAchim Leubner /* Initialize the clock daemon callout. */ 273*dce93cd0SAchim Leubner callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 274*dce93cd0SAchim Leubner #endif 275*dce93cd0SAchim Leubner /* 276*dce93cd0SAchim Leubner * Initialize the adapter. 277*dce93cd0SAchim Leubner */ 278*dce93cd0SAchim Leubner if ((error = aac_alloc(sc)) != 0) 279*dce93cd0SAchim Leubner return(error); 280*dce93cd0SAchim Leubner if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 281*dce93cd0SAchim Leubner if ((error = aac_init(sc)) != 0) 282*dce93cd0SAchim Leubner return(error); 283*dce93cd0SAchim Leubner } 284*dce93cd0SAchim Leubner 285*dce93cd0SAchim Leubner /* 286*dce93cd0SAchim Leubner * Allocate and connect our interrupt. 287*dce93cd0SAchim Leubner */ 288*dce93cd0SAchim Leubner if ((error = aac_setup_intr(sc)) != 0) 289*dce93cd0SAchim Leubner return(error); 290*dce93cd0SAchim Leubner 291*dce93cd0SAchim Leubner /* 292*dce93cd0SAchim Leubner * Print a little information about the controller. 293*dce93cd0SAchim Leubner */ 294*dce93cd0SAchim Leubner aac_describe_controller(sc); 295*dce93cd0SAchim Leubner 296*dce93cd0SAchim Leubner /* 297*dce93cd0SAchim Leubner * Make the control device. 298*dce93cd0SAchim Leubner */ 299*dce93cd0SAchim Leubner unit = device_get_unit(sc->aac_dev); 300*dce93cd0SAchim Leubner sc->aac_dev_t = make_dev(&aacraid_cdevsw, unit, UID_ROOT, GID_OPERATOR, 301*dce93cd0SAchim Leubner 0640, "aacraid%d", unit); 302*dce93cd0SAchim Leubner sc->aac_dev_t->si_drv1 = sc; 303*dce93cd0SAchim Leubner 304*dce93cd0SAchim Leubner /* Create the AIF thread */ 305*dce93cd0SAchim Leubner if (aac_kthread_create((void(*)(void *))aac_command_thread, sc, 306*dce93cd0SAchim Leubner &sc->aifthread, 0, 0, "aacraid%daif", unit)) 307*dce93cd0SAchim Leubner panic("Could not create AIF thread"); 308*dce93cd0SAchim Leubner 309*dce93cd0SAchim Leubner /* Register the shutdown method to only be called post-dump */ 310*dce93cd0SAchim Leubner if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aacraid_shutdown, 311*dce93cd0SAchim Leubner sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 312*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 313*dce93cd0SAchim Leubner "shutdown event registration failed\n"); 314*dce93cd0SAchim Leubner 315*dce93cd0SAchim Leubner /* Find containers */ 316*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 317*dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 318*dce93cd0SAchim Leubner /* loop over possible containers */ 319*dce93cd0SAchim Leubner do { 320*dce93cd0SAchim Leubner if ((aac_get_container_info(sc, fib, i, &mir, &uid)) != 0) 321*dce93cd0SAchim Leubner continue; 322*dce93cd0SAchim Leubner if (i == 0) 323*dce93cd0SAchim Leubner count = mir.MntRespCount; 324*dce93cd0SAchim Leubner aac_add_container(sc, &mir, 0, uid); 325*dce93cd0SAchim Leubner i++; 326*dce93cd0SAchim Leubner } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 327*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 328*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 329*dce93cd0SAchim Leubner 330*dce93cd0SAchim Leubner /* Register with CAM for the containers */ 331*dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_sim_tqh); 332*dce93cd0SAchim Leubner aac_container_bus(sc); 333*dce93cd0SAchim Leubner /* Register with CAM for the non-DASD devices */ 334*dce93cd0SAchim Leubner if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) 335*dce93cd0SAchim Leubner aac_get_bus_info(sc); 336*dce93cd0SAchim Leubner 337*dce93cd0SAchim Leubner /* poke the bus to actually attach the child devices */ 338*dce93cd0SAchim Leubner bus_generic_attach(sc->aac_dev); 339*dce93cd0SAchim Leubner 340*dce93cd0SAchim Leubner /* mark the controller up */ 341*dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_SUSPEND; 342*dce93cd0SAchim Leubner 343*dce93cd0SAchim Leubner /* enable interrupts now */ 344*dce93cd0SAchim Leubner AAC_UNMASK_INTERRUPTS(sc); 345*dce93cd0SAchim Leubner 346*dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 347*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 348*dce93cd0SAchim Leubner callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 349*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 350*dce93cd0SAchim Leubner #else 351*dce93cd0SAchim Leubner { 352*dce93cd0SAchim Leubner struct timeval tv; 353*dce93cd0SAchim Leubner tv.tv_sec = 60; 354*dce93cd0SAchim Leubner tv.tv_usec = 0; 355*dce93cd0SAchim Leubner sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 356*dce93cd0SAchim Leubner } 357*dce93cd0SAchim Leubner #endif 358*dce93cd0SAchim Leubner 359*dce93cd0SAchim Leubner return(0); 360*dce93cd0SAchim Leubner } 361*dce93cd0SAchim Leubner 362*dce93cd0SAchim Leubner static void 363*dce93cd0SAchim Leubner aac_daemon(void *arg) 364*dce93cd0SAchim Leubner { 365*dce93cd0SAchim Leubner struct aac_softc *sc; 366*dce93cd0SAchim Leubner struct timeval tv; 367*dce93cd0SAchim Leubner struct aac_command *cm; 368*dce93cd0SAchim Leubner struct aac_fib *fib; 369*dce93cd0SAchim Leubner 370*dce93cd0SAchim Leubner sc = arg; 371*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 372*dce93cd0SAchim Leubner 373*dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 374*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 375*dce93cd0SAchim Leubner if (callout_pending(&sc->aac_daemontime) || 376*dce93cd0SAchim Leubner callout_active(&sc->aac_daemontime) == 0) 377*dce93cd0SAchim Leubner return; 378*dce93cd0SAchim Leubner #else 379*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 380*dce93cd0SAchim Leubner #endif 381*dce93cd0SAchim Leubner getmicrotime(&tv); 382*dce93cd0SAchim Leubner 383*dce93cd0SAchim Leubner if (!aacraid_alloc_command(sc, &cm)) { 384*dce93cd0SAchim Leubner fib = cm->cm_fib; 385*dce93cd0SAchim Leubner cm->cm_timestamp = time_uptime; 386*dce93cd0SAchim Leubner cm->cm_datalen = 0; 387*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_WAIT; 388*dce93cd0SAchim Leubner 389*dce93cd0SAchim Leubner fib->Header.Size = 390*dce93cd0SAchim Leubner sizeof(struct aac_fib_header) + sizeof(u_int32_t); 391*dce93cd0SAchim Leubner fib->Header.XferState = 392*dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 393*dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 394*dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 395*dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 396*dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 397*dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 398*dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC | 399*dce93cd0SAchim Leubner AAC_FIBSTATE_FAST_RESPONSE; 400*dce93cd0SAchim Leubner fib->Header.Command = SendHostTime; 401*dce93cd0SAchim Leubner *(uint32_t *)fib->data = tv.tv_sec; 402*dce93cd0SAchim Leubner 403*dce93cd0SAchim Leubner aacraid_map_command_sg(cm, NULL, 0, 0); 404*dce93cd0SAchim Leubner aacraid_release_command(cm); 405*dce93cd0SAchim Leubner } 406*dce93cd0SAchim Leubner 407*dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 408*dce93cd0SAchim Leubner callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 409*dce93cd0SAchim Leubner #else 410*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 411*dce93cd0SAchim Leubner tv.tv_sec = 30 * 60; 412*dce93cd0SAchim Leubner tv.tv_usec = 0; 413*dce93cd0SAchim Leubner sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 414*dce93cd0SAchim Leubner #endif 415*dce93cd0SAchim Leubner } 416*dce93cd0SAchim Leubner 417*dce93cd0SAchim Leubner void 418*dce93cd0SAchim Leubner aacraid_add_event(struct aac_softc *sc, struct aac_event *event) 419*dce93cd0SAchim Leubner { 420*dce93cd0SAchim Leubner 421*dce93cd0SAchim Leubner switch (event->ev_type & AAC_EVENT_MASK) { 422*dce93cd0SAchim Leubner case AAC_EVENT_CMFREE: 423*dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 424*dce93cd0SAchim Leubner break; 425*dce93cd0SAchim Leubner default: 426*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 427*dce93cd0SAchim Leubner event->ev_type); 428*dce93cd0SAchim Leubner break; 429*dce93cd0SAchim Leubner } 430*dce93cd0SAchim Leubner 431*dce93cd0SAchim Leubner return; 432*dce93cd0SAchim Leubner } 433*dce93cd0SAchim Leubner 434*dce93cd0SAchim Leubner /* 435*dce93cd0SAchim Leubner * Request information of container #cid 436*dce93cd0SAchim Leubner */ 437*dce93cd0SAchim Leubner static int 438*dce93cd0SAchim Leubner aac_get_container_info(struct aac_softc *sc, struct aac_fib *sync_fib, int cid, 439*dce93cd0SAchim Leubner struct aac_mntinforesp *mir, u_int32_t *uid) 440*dce93cd0SAchim Leubner { 441*dce93cd0SAchim Leubner struct aac_command *cm; 442*dce93cd0SAchim Leubner struct aac_fib *fib; 443*dce93cd0SAchim Leubner struct aac_mntinfo *mi; 444*dce93cd0SAchim Leubner struct aac_cnt_config *ccfg; 445*dce93cd0SAchim Leubner 446*dce93cd0SAchim Leubner if (sync_fib == NULL) { 447*dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 448*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 449*dce93cd0SAchim Leubner "Warning, no free command available\n"); 450*dce93cd0SAchim Leubner return (-1); 451*dce93cd0SAchim Leubner } 452*dce93cd0SAchim Leubner fib = cm->cm_fib; 453*dce93cd0SAchim Leubner } else { 454*dce93cd0SAchim Leubner fib = sync_fib; 455*dce93cd0SAchim Leubner } 456*dce93cd0SAchim Leubner 457*dce93cd0SAchim Leubner mi = (struct aac_mntinfo *)&fib->data[0]; 458*dce93cd0SAchim Leubner /* 4KB support?, 64-bit LBA? */ 459*dce93cd0SAchim Leubner if (sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE) 460*dce93cd0SAchim Leubner mi->Command = VM_NameServeAllBlk; 461*dce93cd0SAchim Leubner else if (sc->flags & AAC_FLAGS_LBA_64BIT) 462*dce93cd0SAchim Leubner mi->Command = VM_NameServe64; 463*dce93cd0SAchim Leubner else 464*dce93cd0SAchim Leubner mi->Command = VM_NameServe; 465*dce93cd0SAchim Leubner mi->MntType = FT_FILESYS; 466*dce93cd0SAchim Leubner mi->MntCount = cid; 467*dce93cd0SAchim Leubner 468*dce93cd0SAchim Leubner if (sync_fib) { 469*dce93cd0SAchim Leubner if (aac_sync_fib(sc, ContainerCommand, 0, fib, 470*dce93cd0SAchim Leubner sizeof(struct aac_mntinfo))) { 471*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error probing container %d\n", cid); 472*dce93cd0SAchim Leubner return (-1); 473*dce93cd0SAchim Leubner } 474*dce93cd0SAchim Leubner } else { 475*dce93cd0SAchim Leubner cm->cm_timestamp = time_uptime; 476*dce93cd0SAchim Leubner cm->cm_datalen = 0; 477*dce93cd0SAchim Leubner 478*dce93cd0SAchim Leubner fib->Header.Size = 479*dce93cd0SAchim Leubner sizeof(struct aac_fib_header) + sizeof(struct aac_mntinfo); 480*dce93cd0SAchim Leubner fib->Header.XferState = 481*dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 482*dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 483*dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 484*dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 485*dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 486*dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 487*dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC | 488*dce93cd0SAchim Leubner AAC_FIBSTATE_FAST_RESPONSE; 489*dce93cd0SAchim Leubner fib->Header.Command = ContainerCommand; 490*dce93cd0SAchim Leubner if (aacraid_wait_command(cm) != 0) { 491*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error probing container %d\n", cid); 492*dce93cd0SAchim Leubner aacraid_release_command(cm); 493*dce93cd0SAchim Leubner return (-1); 494*dce93cd0SAchim Leubner } 495*dce93cd0SAchim Leubner } 496*dce93cd0SAchim Leubner bcopy(&fib->data[0], mir, sizeof(struct aac_mntinforesp)); 497*dce93cd0SAchim Leubner 498*dce93cd0SAchim Leubner /* UID */ 499*dce93cd0SAchim Leubner *uid = cid; 500*dce93cd0SAchim Leubner if (mir->MntTable[0].VolType != CT_NONE && 501*dce93cd0SAchim Leubner !(mir->MntTable[0].ContentState & AAC_FSCS_HIDDEN)) { 502*dce93cd0SAchim Leubner if (!(sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)) 503*dce93cd0SAchim Leubner mir->MntTable[0].ObjExtension.BlockSize = 0x200; 504*dce93cd0SAchim Leubner 505*dce93cd0SAchim Leubner ccfg = (struct aac_cnt_config *)&fib->data[0]; 506*dce93cd0SAchim Leubner bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 507*dce93cd0SAchim Leubner ccfg->Command = VM_ContainerConfig; 508*dce93cd0SAchim Leubner ccfg->CTCommand.command = CT_CID_TO_32BITS_UID; 509*dce93cd0SAchim Leubner ccfg->CTCommand.param[0] = cid; 510*dce93cd0SAchim Leubner 511*dce93cd0SAchim Leubner if (sync_fib) { 512*dce93cd0SAchim Leubner if (aac_sync_fib(sc, ContainerCommand, 0, fib, 513*dce93cd0SAchim Leubner sizeof(struct aac_cnt_config) == 0) && 514*dce93cd0SAchim Leubner ccfg->CTCommand.param[0] == ST_OK && 515*dce93cd0SAchim Leubner mir->MntTable[0].VolType != CT_PASSTHRU) 516*dce93cd0SAchim Leubner *uid = ccfg->CTCommand.param[1]; 517*dce93cd0SAchim Leubner } else { 518*dce93cd0SAchim Leubner fib->Header.Size = 519*dce93cd0SAchim Leubner sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config); 520*dce93cd0SAchim Leubner fib->Header.XferState = 521*dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 522*dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 523*dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 524*dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 525*dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 526*dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 527*dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC | 528*dce93cd0SAchim Leubner AAC_FIBSTATE_FAST_RESPONSE; 529*dce93cd0SAchim Leubner fib->Header.Command = ContainerCommand; 530*dce93cd0SAchim Leubner if (aacraid_wait_command(cm) == 0 && 531*dce93cd0SAchim Leubner ccfg->CTCommand.param[0] == ST_OK && 532*dce93cd0SAchim Leubner mir->MntTable[0].VolType != CT_PASSTHRU) 533*dce93cd0SAchim Leubner *uid = ccfg->CTCommand.param[1]; 534*dce93cd0SAchim Leubner aacraid_release_command(cm); 535*dce93cd0SAchim Leubner } 536*dce93cd0SAchim Leubner } 537*dce93cd0SAchim Leubner 538*dce93cd0SAchim Leubner return (0); 539*dce93cd0SAchim Leubner } 540*dce93cd0SAchim Leubner 541*dce93cd0SAchim Leubner /* 542*dce93cd0SAchim Leubner * Create a device to represent a new container 543*dce93cd0SAchim Leubner */ 544*dce93cd0SAchim Leubner static void 545*dce93cd0SAchim Leubner aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f, 546*dce93cd0SAchim Leubner u_int32_t uid) 547*dce93cd0SAchim Leubner { 548*dce93cd0SAchim Leubner struct aac_container *co; 549*dce93cd0SAchim Leubner 550*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 551*dce93cd0SAchim Leubner 552*dce93cd0SAchim Leubner /* 553*dce93cd0SAchim Leubner * Check container volume type for validity. Note that many of 554*dce93cd0SAchim Leubner * the possible types may never show up. 555*dce93cd0SAchim Leubner */ 556*dce93cd0SAchim Leubner if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 557*dce93cd0SAchim Leubner co = (struct aac_container *)malloc(sizeof *co, M_AACRAIDBUF, 558*dce93cd0SAchim Leubner M_NOWAIT | M_ZERO); 559*dce93cd0SAchim Leubner if (co == NULL) { 560*dce93cd0SAchim Leubner panic("Out of memory?!"); 561*dce93cd0SAchim Leubner } 562*dce93cd0SAchim Leubner 563*dce93cd0SAchim Leubner co->co_found = f; 564*dce93cd0SAchim Leubner bcopy(&mir->MntTable[0], &co->co_mntobj, 565*dce93cd0SAchim Leubner sizeof(struct aac_mntobj)); 566*dce93cd0SAchim Leubner co->co_uid = uid; 567*dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 568*dce93cd0SAchim Leubner } 569*dce93cd0SAchim Leubner } 570*dce93cd0SAchim Leubner 571*dce93cd0SAchim Leubner /* 572*dce93cd0SAchim Leubner * Allocate resources associated with (sc) 573*dce93cd0SAchim Leubner */ 574*dce93cd0SAchim Leubner static int 575*dce93cd0SAchim Leubner aac_alloc(struct aac_softc *sc) 576*dce93cd0SAchim Leubner { 577*dce93cd0SAchim Leubner bus_size_t maxsize; 578*dce93cd0SAchim Leubner 579*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 580*dce93cd0SAchim Leubner 581*dce93cd0SAchim Leubner /* 582*dce93cd0SAchim Leubner * Create DMA tag for mapping buffers into controller-addressable space. 583*dce93cd0SAchim Leubner */ 584*dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 585*dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 586*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_SG_64BIT) ? 587*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR : 588*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 589*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 590*dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 591*dce93cd0SAchim Leubner MAXBSIZE, /* maxsize */ 592*dce93cd0SAchim Leubner sc->aac_sg_tablesize, /* nsegments */ 593*dce93cd0SAchim Leubner MAXBSIZE, /* maxsegsize */ 594*dce93cd0SAchim Leubner BUS_DMA_ALLOCNOW, /* flags */ 595*dce93cd0SAchim Leubner busdma_lock_mutex, /* lockfunc */ 596*dce93cd0SAchim Leubner &sc->aac_io_lock, /* lockfuncarg */ 597*dce93cd0SAchim Leubner &sc->aac_buffer_dmat)) { 598*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 599*dce93cd0SAchim Leubner return (ENOMEM); 600*dce93cd0SAchim Leubner } 601*dce93cd0SAchim Leubner 602*dce93cd0SAchim Leubner /* 603*dce93cd0SAchim Leubner * Create DMA tag for mapping FIBs into controller-addressable space.. 604*dce93cd0SAchim Leubner */ 605*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 606*dce93cd0SAchim Leubner maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 607*dce93cd0SAchim Leubner sizeof(struct aac_fib_xporthdr) + 31); 608*dce93cd0SAchim Leubner else 609*dce93cd0SAchim Leubner maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 31); 610*dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 611*dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 612*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 613*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT : 614*dce93cd0SAchim Leubner 0x7fffffff, /* lowaddr */ 615*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 616*dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 617*dce93cd0SAchim Leubner maxsize, /* maxsize */ 618*dce93cd0SAchim Leubner 1, /* nsegments */ 619*dce93cd0SAchim Leubner maxsize, /* maxsize */ 620*dce93cd0SAchim Leubner 0, /* flags */ 621*dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 622*dce93cd0SAchim Leubner &sc->aac_fib_dmat)) { 623*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 624*dce93cd0SAchim Leubner return (ENOMEM); 625*dce93cd0SAchim Leubner } 626*dce93cd0SAchim Leubner 627*dce93cd0SAchim Leubner /* 628*dce93cd0SAchim Leubner * Create DMA tag for the common structure and allocate it. 629*dce93cd0SAchim Leubner */ 630*dce93cd0SAchim Leubner maxsize = sizeof(struct aac_common); 631*dce93cd0SAchim Leubner maxsize += sc->aac_max_fibs * sizeof(u_int32_t); 632*dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 633*dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 634*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 635*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT : 636*dce93cd0SAchim Leubner 0x7fffffff, /* lowaddr */ 637*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 638*dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 639*dce93cd0SAchim Leubner maxsize, /* maxsize */ 640*dce93cd0SAchim Leubner 1, /* nsegments */ 641*dce93cd0SAchim Leubner maxsize, /* maxsegsize */ 642*dce93cd0SAchim Leubner 0, /* flags */ 643*dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 644*dce93cd0SAchim Leubner &sc->aac_common_dmat)) { 645*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 646*dce93cd0SAchim Leubner "can't allocate common structure DMA tag\n"); 647*dce93cd0SAchim Leubner return (ENOMEM); 648*dce93cd0SAchim Leubner } 649*dce93cd0SAchim Leubner if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 650*dce93cd0SAchim Leubner BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 651*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate common structure\n"); 652*dce93cd0SAchim Leubner return (ENOMEM); 653*dce93cd0SAchim Leubner } 654*dce93cd0SAchim Leubner 655*dce93cd0SAchim Leubner (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 656*dce93cd0SAchim Leubner sc->aac_common, maxsize, 657*dce93cd0SAchim Leubner aac_common_map, sc, 0); 658*dce93cd0SAchim Leubner bzero(sc->aac_common, maxsize); 659*dce93cd0SAchim Leubner 660*dce93cd0SAchim Leubner /* Allocate some FIBs and associated command structs */ 661*dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_fibmap_tqh); 662*dce93cd0SAchim Leubner sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 663*dce93cd0SAchim Leubner M_AACRAIDBUF, M_WAITOK|M_ZERO); 664*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 665*dce93cd0SAchim Leubner while (sc->total_fibs < sc->aac_max_fibs) { 666*dce93cd0SAchim Leubner if (aac_alloc_commands(sc) != 0) 667*dce93cd0SAchim Leubner break; 668*dce93cd0SAchim Leubner } 669*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 670*dce93cd0SAchim Leubner if (sc->total_fibs == 0) 671*dce93cd0SAchim Leubner return (ENOMEM); 672*dce93cd0SAchim Leubner 673*dce93cd0SAchim Leubner return (0); 674*dce93cd0SAchim Leubner } 675*dce93cd0SAchim Leubner 676*dce93cd0SAchim Leubner /* 677*dce93cd0SAchim Leubner * Free all of the resources associated with (sc) 678*dce93cd0SAchim Leubner * 679*dce93cd0SAchim Leubner * Should not be called if the controller is active. 680*dce93cd0SAchim Leubner */ 681*dce93cd0SAchim Leubner void 682*dce93cd0SAchim Leubner aacraid_free(struct aac_softc *sc) 683*dce93cd0SAchim Leubner { 684*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 685*dce93cd0SAchim Leubner 686*dce93cd0SAchim Leubner /* remove the control device */ 687*dce93cd0SAchim Leubner if (sc->aac_dev_t != NULL) 688*dce93cd0SAchim Leubner destroy_dev(sc->aac_dev_t); 689*dce93cd0SAchim Leubner 690*dce93cd0SAchim Leubner /* throw away any FIB buffers, discard the FIB DMA tag */ 691*dce93cd0SAchim Leubner aac_free_commands(sc); 692*dce93cd0SAchim Leubner if (sc->aac_fib_dmat) 693*dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_fib_dmat); 694*dce93cd0SAchim Leubner 695*dce93cd0SAchim Leubner free(sc->aac_commands, M_AACRAIDBUF); 696*dce93cd0SAchim Leubner 697*dce93cd0SAchim Leubner /* destroy the common area */ 698*dce93cd0SAchim Leubner if (sc->aac_common) { 699*dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 700*dce93cd0SAchim Leubner bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 701*dce93cd0SAchim Leubner sc->aac_common_dmamap); 702*dce93cd0SAchim Leubner } 703*dce93cd0SAchim Leubner if (sc->aac_common_dmat) 704*dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_common_dmat); 705*dce93cd0SAchim Leubner 706*dce93cd0SAchim Leubner /* disconnect the interrupt handler */ 707*dce93cd0SAchim Leubner if (sc->aac_intr) 708*dce93cd0SAchim Leubner bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 709*dce93cd0SAchim Leubner if (sc->aac_irq != NULL) 710*dce93cd0SAchim Leubner bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 711*dce93cd0SAchim Leubner sc->aac_irq); 712*dce93cd0SAchim Leubner 713*dce93cd0SAchim Leubner /* destroy data-transfer DMA tag */ 714*dce93cd0SAchim Leubner if (sc->aac_buffer_dmat) 715*dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_buffer_dmat); 716*dce93cd0SAchim Leubner 717*dce93cd0SAchim Leubner /* destroy the parent DMA tag */ 718*dce93cd0SAchim Leubner if (sc->aac_parent_dmat) 719*dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_parent_dmat); 720*dce93cd0SAchim Leubner 721*dce93cd0SAchim Leubner /* release the register window mapping */ 722*dce93cd0SAchim Leubner if (sc->aac_regs_res0 != NULL) 723*dce93cd0SAchim Leubner bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 724*dce93cd0SAchim Leubner sc->aac_regs_rid0, sc->aac_regs_res0); 725*dce93cd0SAchim Leubner if (sc->aac_regs_res1 != NULL) 726*dce93cd0SAchim Leubner bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 727*dce93cd0SAchim Leubner sc->aac_regs_rid1, sc->aac_regs_res1); 728*dce93cd0SAchim Leubner } 729*dce93cd0SAchim Leubner 730*dce93cd0SAchim Leubner /* 731*dce93cd0SAchim Leubner * Disconnect from the controller completely, in preparation for unload. 732*dce93cd0SAchim Leubner */ 733*dce93cd0SAchim Leubner int 734*dce93cd0SAchim Leubner aacraid_detach(device_t dev) 735*dce93cd0SAchim Leubner { 736*dce93cd0SAchim Leubner struct aac_softc *sc; 737*dce93cd0SAchim Leubner struct aac_container *co; 738*dce93cd0SAchim Leubner struct aac_sim *sim; 739*dce93cd0SAchim Leubner int error; 740*dce93cd0SAchim Leubner 741*dce93cd0SAchim Leubner sc = device_get_softc(dev); 742*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 743*dce93cd0SAchim Leubner 744*dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 745*dce93cd0SAchim Leubner callout_drain(&sc->aac_daemontime); 746*dce93cd0SAchim Leubner #else 747*dce93cd0SAchim Leubner untimeout(aac_daemon, (void *)sc, sc->timeout_id); 748*dce93cd0SAchim Leubner #endif 749*dce93cd0SAchim Leubner /* Remove the child containers */ 750*dce93cd0SAchim Leubner while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 751*dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 752*dce93cd0SAchim Leubner free(co, M_AACRAIDBUF); 753*dce93cd0SAchim Leubner } 754*dce93cd0SAchim Leubner 755*dce93cd0SAchim Leubner /* Remove the CAM SIMs */ 756*dce93cd0SAchim Leubner while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 757*dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 758*dce93cd0SAchim Leubner error = device_delete_child(dev, sim->sim_dev); 759*dce93cd0SAchim Leubner if (error) 760*dce93cd0SAchim Leubner return (error); 761*dce93cd0SAchim Leubner free(sim, M_AACRAIDBUF); 762*dce93cd0SAchim Leubner } 763*dce93cd0SAchim Leubner 764*dce93cd0SAchim Leubner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 765*dce93cd0SAchim Leubner sc->aifflags |= AAC_AIFFLAGS_EXIT; 766*dce93cd0SAchim Leubner wakeup(sc->aifthread); 767*dce93cd0SAchim Leubner tsleep(sc->aac_dev, PUSER | PCATCH, "aac_dch", 30 * hz); 768*dce93cd0SAchim Leubner } 769*dce93cd0SAchim Leubner 770*dce93cd0SAchim Leubner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 771*dce93cd0SAchim Leubner panic("Cannot shutdown AIF thread"); 772*dce93cd0SAchim Leubner 773*dce93cd0SAchim Leubner if ((error = aacraid_shutdown(dev))) 774*dce93cd0SAchim Leubner return(error); 775*dce93cd0SAchim Leubner 776*dce93cd0SAchim Leubner EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 777*dce93cd0SAchim Leubner 778*dce93cd0SAchim Leubner aacraid_free(sc); 779*dce93cd0SAchim Leubner 780*dce93cd0SAchim Leubner mtx_destroy(&sc->aac_io_lock); 781*dce93cd0SAchim Leubner 782*dce93cd0SAchim Leubner return(0); 783*dce93cd0SAchim Leubner } 784*dce93cd0SAchim Leubner 785*dce93cd0SAchim Leubner /* 786*dce93cd0SAchim Leubner * Bring the controller down to a dormant state and detach all child devices. 787*dce93cd0SAchim Leubner * 788*dce93cd0SAchim Leubner * This function is called before detach or system shutdown. 789*dce93cd0SAchim Leubner * 790*dce93cd0SAchim Leubner * Note that we can assume that the bioq on the controller is empty, as we won't 791*dce93cd0SAchim Leubner * allow shutdown if any device is open. 792*dce93cd0SAchim Leubner */ 793*dce93cd0SAchim Leubner int 794*dce93cd0SAchim Leubner aacraid_shutdown(device_t dev) 795*dce93cd0SAchim Leubner { 796*dce93cd0SAchim Leubner struct aac_softc *sc; 797*dce93cd0SAchim Leubner struct aac_fib *fib; 798*dce93cd0SAchim Leubner struct aac_close_command *cc; 799*dce93cd0SAchim Leubner 800*dce93cd0SAchim Leubner sc = device_get_softc(dev); 801*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 802*dce93cd0SAchim Leubner 803*dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_SUSPEND; 804*dce93cd0SAchim Leubner 805*dce93cd0SAchim Leubner /* 806*dce93cd0SAchim Leubner * Send a Container shutdown followed by a HostShutdown FIB to the 807*dce93cd0SAchim Leubner * controller to convince it that we don't want to talk to it anymore. 808*dce93cd0SAchim Leubner * We've been closed and all I/O completed already 809*dce93cd0SAchim Leubner */ 810*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "shutting down controller..."); 811*dce93cd0SAchim Leubner 812*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 813*dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 814*dce93cd0SAchim Leubner cc = (struct aac_close_command *)&fib->data[0]; 815*dce93cd0SAchim Leubner 816*dce93cd0SAchim Leubner bzero(cc, sizeof(struct aac_close_command)); 817*dce93cd0SAchim Leubner cc->Command = VM_CloseAll; 818*dce93cd0SAchim Leubner cc->ContainerId = 0xffffffff; 819*dce93cd0SAchim Leubner if (aac_sync_fib(sc, ContainerCommand, 0, fib, 820*dce93cd0SAchim Leubner sizeof(struct aac_close_command))) 821*dce93cd0SAchim Leubner printf("FAILED.\n"); 822*dce93cd0SAchim Leubner else 823*dce93cd0SAchim Leubner printf("done\n"); 824*dce93cd0SAchim Leubner 825*dce93cd0SAchim Leubner AAC_MASK_INTERRUPTS(sc); 826*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 827*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 828*dce93cd0SAchim Leubner 829*dce93cd0SAchim Leubner return(0); 830*dce93cd0SAchim Leubner } 831*dce93cd0SAchim Leubner 832*dce93cd0SAchim Leubner /* 833*dce93cd0SAchim Leubner * Bring the controller to a quiescent state, ready for system suspend. 834*dce93cd0SAchim Leubner */ 835*dce93cd0SAchim Leubner int 836*dce93cd0SAchim Leubner aacraid_suspend(device_t dev) 837*dce93cd0SAchim Leubner { 838*dce93cd0SAchim Leubner struct aac_softc *sc; 839*dce93cd0SAchim Leubner 840*dce93cd0SAchim Leubner sc = device_get_softc(dev); 841*dce93cd0SAchim Leubner 842*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 843*dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_SUSPEND; 844*dce93cd0SAchim Leubner 845*dce93cd0SAchim Leubner AAC_MASK_INTERRUPTS(sc); 846*dce93cd0SAchim Leubner return(0); 847*dce93cd0SAchim Leubner } 848*dce93cd0SAchim Leubner 849*dce93cd0SAchim Leubner /* 850*dce93cd0SAchim Leubner * Bring the controller back to a state ready for operation. 851*dce93cd0SAchim Leubner */ 852*dce93cd0SAchim Leubner int 853*dce93cd0SAchim Leubner aacraid_resume(device_t dev) 854*dce93cd0SAchim Leubner { 855*dce93cd0SAchim Leubner struct aac_softc *sc; 856*dce93cd0SAchim Leubner 857*dce93cd0SAchim Leubner sc = device_get_softc(dev); 858*dce93cd0SAchim Leubner 859*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 860*dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_SUSPEND; 861*dce93cd0SAchim Leubner AAC_UNMASK_INTERRUPTS(sc); 862*dce93cd0SAchim Leubner return(0); 863*dce93cd0SAchim Leubner } 864*dce93cd0SAchim Leubner 865*dce93cd0SAchim Leubner /* 866*dce93cd0SAchim Leubner * Interrupt handler for NEW_COMM_TYPE1, NEW_COMM_TYPE2, NEW_COMM_TYPE34 interface. 867*dce93cd0SAchim Leubner */ 868*dce93cd0SAchim Leubner void 869*dce93cd0SAchim Leubner aacraid_new_intr_type1(void *arg) 870*dce93cd0SAchim Leubner { 871*dce93cd0SAchim Leubner struct aac_softc *sc; 872*dce93cd0SAchim Leubner struct aac_command *cm; 873*dce93cd0SAchim Leubner struct aac_fib *fib; 874*dce93cd0SAchim Leubner u_int32_t bellbits, bellbits_shifted, index, handle; 875*dce93cd0SAchim Leubner int isFastResponse, isAif, noMoreAif; 876*dce93cd0SAchim Leubner 877*dce93cd0SAchim Leubner sc = (struct aac_softc *)arg; 878*dce93cd0SAchim Leubner 879*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 880*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 881*dce93cd0SAchim Leubner bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); 882*dce93cd0SAchim Leubner if (bellbits & AAC_DB_RESPONSE_SENT_NS) { 883*dce93cd0SAchim Leubner bellbits = AAC_DB_RESPONSE_SENT_NS; 884*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 885*dce93cd0SAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); /* ODR readback,Prep #238630 */ 886*dce93cd0SAchim Leubner /* handle async. status */ 887*dce93cd0SAchim Leubner index = sc->aac_host_rrq_idx; 888*dce93cd0SAchim Leubner for (;;) { 889*dce93cd0SAchim Leubner isFastResponse = isAif = noMoreAif = 0; 890*dce93cd0SAchim Leubner /* remove toggle bit (31) */ 891*dce93cd0SAchim Leubner handle = (sc->aac_common->ac_host_rrq[index] & 0x7fffffff); 892*dce93cd0SAchim Leubner /* check fast response bit (30) */ 893*dce93cd0SAchim Leubner if (handle & 0x40000000) 894*dce93cd0SAchim Leubner isFastResponse = 1; 895*dce93cd0SAchim Leubner /* check AIF bit (23) */ 896*dce93cd0SAchim Leubner else if (handle & 0x00800000) 897*dce93cd0SAchim Leubner isAif = TRUE; 898*dce93cd0SAchim Leubner handle &= 0x0000ffff; 899*dce93cd0SAchim Leubner if (handle == 0) 900*dce93cd0SAchim Leubner break; 901*dce93cd0SAchim Leubner 902*dce93cd0SAchim Leubner cm = sc->aac_commands + (handle - 1); 903*dce93cd0SAchim Leubner fib = cm->cm_fib; 904*dce93cd0SAchim Leubner if (isAif) { 905*dce93cd0SAchim Leubner noMoreAif = (fib->Header.XferState & AAC_FIBSTATE_NOMOREAIF) ? 1:0; 906*dce93cd0SAchim Leubner if (!noMoreAif) 907*dce93cd0SAchim Leubner aac_handle_aif(sc, fib); 908*dce93cd0SAchim Leubner aac_remove_busy(cm); 909*dce93cd0SAchim Leubner aacraid_release_command(cm); 910*dce93cd0SAchim Leubner } else { 911*dce93cd0SAchim Leubner if (isFastResponse) { 912*dce93cd0SAchim Leubner fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 913*dce93cd0SAchim Leubner *((u_int32_t *)(fib->data)) = ST_OK; 914*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_FASTRESP; 915*dce93cd0SAchim Leubner } 916*dce93cd0SAchim Leubner aac_remove_busy(cm); 917*dce93cd0SAchim Leubner aac_unmap_command(cm); 918*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_COMPLETED; 919*dce93cd0SAchim Leubner 920*dce93cd0SAchim Leubner /* is there a completion handler? */ 921*dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 922*dce93cd0SAchim Leubner cm->cm_complete(cm); 923*dce93cd0SAchim Leubner } else { 924*dce93cd0SAchim Leubner /* assume that someone is sleeping on this command */ 925*dce93cd0SAchim Leubner wakeup(cm); 926*dce93cd0SAchim Leubner } 927*dce93cd0SAchim Leubner sc->flags &= ~AAC_QUEUE_FRZN; 928*dce93cd0SAchim Leubner } 929*dce93cd0SAchim Leubner 930*dce93cd0SAchim Leubner sc->aac_common->ac_host_rrq[index++] = 0; 931*dce93cd0SAchim Leubner if (index == sc->aac_max_fibs) 932*dce93cd0SAchim Leubner index = 0; 933*dce93cd0SAchim Leubner sc->aac_host_rrq_idx = index; 934*dce93cd0SAchim Leubner 935*dce93cd0SAchim Leubner if ((isAif && !noMoreAif) || sc->aif_pending) 936*dce93cd0SAchim Leubner aac_request_aif(sc); 937*dce93cd0SAchim Leubner } 938*dce93cd0SAchim Leubner } else { 939*dce93cd0SAchim Leubner bellbits_shifted = (bellbits >> AAC_SRC_ODR_SHIFT); 940*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 941*dce93cd0SAchim Leubner if (bellbits_shifted & AAC_DB_AIF_PENDING) { 942*dce93cd0SAchim Leubner /* handle AIF */ 943*dce93cd0SAchim Leubner aac_request_aif(sc); 944*dce93cd0SAchim Leubner } else if (bellbits_shifted & AAC_DB_SYNC_COMMAND) { 945*dce93cd0SAchim Leubner if (sc->aac_sync_cm) { 946*dce93cd0SAchim Leubner cm = sc->aac_sync_cm; 947*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_COMPLETED; 948*dce93cd0SAchim Leubner /* is there a completion handler? */ 949*dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 950*dce93cd0SAchim Leubner cm->cm_complete(cm); 951*dce93cd0SAchim Leubner } else { 952*dce93cd0SAchim Leubner /* assume that someone is sleeping on this command */ 953*dce93cd0SAchim Leubner wakeup(cm); 954*dce93cd0SAchim Leubner } 955*dce93cd0SAchim Leubner sc->flags &= ~AAC_QUEUE_FRZN; 956*dce93cd0SAchim Leubner sc->aac_sync_cm = NULL; 957*dce93cd0SAchim Leubner } 958*dce93cd0SAchim Leubner } 959*dce93cd0SAchim Leubner } 960*dce93cd0SAchim Leubner 961*dce93cd0SAchim Leubner /* see if we can start some more I/O */ 962*dce93cd0SAchim Leubner if ((sc->flags & AAC_QUEUE_FRZN) == 0) 963*dce93cd0SAchim Leubner aacraid_startio(sc); 964*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 965*dce93cd0SAchim Leubner } 966*dce93cd0SAchim Leubner 967*dce93cd0SAchim Leubner /* 968*dce93cd0SAchim Leubner * Handle notification of one or more FIBs coming from the controller. 969*dce93cd0SAchim Leubner */ 970*dce93cd0SAchim Leubner static void 971*dce93cd0SAchim Leubner aac_command_thread(struct aac_softc *sc) 972*dce93cd0SAchim Leubner { 973*dce93cd0SAchim Leubner int retval; 974*dce93cd0SAchim Leubner 975*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 976*dce93cd0SAchim Leubner 977*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 978*dce93cd0SAchim Leubner sc->aifflags = AAC_AIFFLAGS_RUNNING; 979*dce93cd0SAchim Leubner 980*dce93cd0SAchim Leubner while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 981*dce93cd0SAchim Leubner 982*dce93cd0SAchim Leubner retval = 0; 983*dce93cd0SAchim Leubner if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 984*dce93cd0SAchim Leubner retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 985*dce93cd0SAchim Leubner "aacraid_aifthd", AAC_PERIODIC_INTERVAL * hz); 986*dce93cd0SAchim Leubner 987*dce93cd0SAchim Leubner /* 988*dce93cd0SAchim Leubner * First see if any FIBs need to be allocated. This needs 989*dce93cd0SAchim Leubner * to be called without the driver lock because contigmalloc 990*dce93cd0SAchim Leubner * will grab Giant, and would result in an LOR. 991*dce93cd0SAchim Leubner */ 992*dce93cd0SAchim Leubner if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 993*dce93cd0SAchim Leubner aac_alloc_commands(sc); 994*dce93cd0SAchim Leubner sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 995*dce93cd0SAchim Leubner aacraid_startio(sc); 996*dce93cd0SAchim Leubner } 997*dce93cd0SAchim Leubner 998*dce93cd0SAchim Leubner /* 999*dce93cd0SAchim Leubner * While we're here, check to see if any commands are stuck. 1000*dce93cd0SAchim Leubner * This is pretty low-priority, so it's ok if it doesn't 1001*dce93cd0SAchim Leubner * always fire. 1002*dce93cd0SAchim Leubner */ 1003*dce93cd0SAchim Leubner if (retval == EWOULDBLOCK) 1004*dce93cd0SAchim Leubner aac_timeout(sc); 1005*dce93cd0SAchim Leubner 1006*dce93cd0SAchim Leubner /* Check the hardware printf message buffer */ 1007*dce93cd0SAchim Leubner if (sc->aac_common->ac_printf[0] != 0) 1008*dce93cd0SAchim Leubner aac_print_printf(sc); 1009*dce93cd0SAchim Leubner } 1010*dce93cd0SAchim Leubner sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1011*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 1012*dce93cd0SAchim Leubner wakeup(sc->aac_dev); 1013*dce93cd0SAchim Leubner 1014*dce93cd0SAchim Leubner aac_kthread_exit(0); 1015*dce93cd0SAchim Leubner } 1016*dce93cd0SAchim Leubner 1017*dce93cd0SAchim Leubner /* 1018*dce93cd0SAchim Leubner * Submit a command to the controller, return when it completes. 1019*dce93cd0SAchim Leubner * XXX This is very dangerous! If the card has gone out to lunch, we could 1020*dce93cd0SAchim Leubner * be stuck here forever. At the same time, signals are not caught 1021*dce93cd0SAchim Leubner * because there is a risk that a signal could wakeup the sleep before 1022*dce93cd0SAchim Leubner * the card has a chance to complete the command. Since there is no way 1023*dce93cd0SAchim Leubner * to cancel a command that is in progress, we can't protect against the 1024*dce93cd0SAchim Leubner * card completing a command late and spamming the command and data 1025*dce93cd0SAchim Leubner * memory. So, we are held hostage until the command completes. 1026*dce93cd0SAchim Leubner */ 1027*dce93cd0SAchim Leubner int 1028*dce93cd0SAchim Leubner aacraid_wait_command(struct aac_command *cm) 1029*dce93cd0SAchim Leubner { 1030*dce93cd0SAchim Leubner struct aac_softc *sc; 1031*dce93cd0SAchim Leubner int error; 1032*dce93cd0SAchim Leubner 1033*dce93cd0SAchim Leubner sc = cm->cm_sc; 1034*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1035*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1036*dce93cd0SAchim Leubner 1037*dce93cd0SAchim Leubner /* Put the command on the ready queue and get things going */ 1038*dce93cd0SAchim Leubner aac_enqueue_ready(cm); 1039*dce93cd0SAchim Leubner aacraid_startio(sc); 1040*dce93cd0SAchim Leubner error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacraid_wait", 0); 1041*dce93cd0SAchim Leubner return(error); 1042*dce93cd0SAchim Leubner } 1043*dce93cd0SAchim Leubner 1044*dce93cd0SAchim Leubner /* 1045*dce93cd0SAchim Leubner *Command Buffer Management 1046*dce93cd0SAchim Leubner */ 1047*dce93cd0SAchim Leubner 1048*dce93cd0SAchim Leubner /* 1049*dce93cd0SAchim Leubner * Allocate a command. 1050*dce93cd0SAchim Leubner */ 1051*dce93cd0SAchim Leubner int 1052*dce93cd0SAchim Leubner aacraid_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1053*dce93cd0SAchim Leubner { 1054*dce93cd0SAchim Leubner struct aac_command *cm; 1055*dce93cd0SAchim Leubner 1056*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1057*dce93cd0SAchim Leubner 1058*dce93cd0SAchim Leubner if ((cm = aac_dequeue_free(sc)) == NULL) { 1059*dce93cd0SAchim Leubner if (sc->total_fibs < sc->aac_max_fibs) { 1060*dce93cd0SAchim Leubner sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1061*dce93cd0SAchim Leubner wakeup(sc->aifthread); 1062*dce93cd0SAchim Leubner } 1063*dce93cd0SAchim Leubner return (EBUSY); 1064*dce93cd0SAchim Leubner } 1065*dce93cd0SAchim Leubner 1066*dce93cd0SAchim Leubner *cmp = cm; 1067*dce93cd0SAchim Leubner return(0); 1068*dce93cd0SAchim Leubner } 1069*dce93cd0SAchim Leubner 1070*dce93cd0SAchim Leubner /* 1071*dce93cd0SAchim Leubner * Release a command back to the freelist. 1072*dce93cd0SAchim Leubner */ 1073*dce93cd0SAchim Leubner void 1074*dce93cd0SAchim Leubner aacraid_release_command(struct aac_command *cm) 1075*dce93cd0SAchim Leubner { 1076*dce93cd0SAchim Leubner struct aac_event *event; 1077*dce93cd0SAchim Leubner struct aac_softc *sc; 1078*dce93cd0SAchim Leubner 1079*dce93cd0SAchim Leubner sc = cm->cm_sc; 1080*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1081*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1082*dce93cd0SAchim Leubner 1083*dce93cd0SAchim Leubner /* (re)initialize the command/FIB */ 1084*dce93cd0SAchim Leubner cm->cm_sgtable = NULL; 1085*dce93cd0SAchim Leubner cm->cm_flags = 0; 1086*dce93cd0SAchim Leubner cm->cm_complete = NULL; 1087*dce93cd0SAchim Leubner cm->cm_ccb = NULL; 1088*dce93cd0SAchim Leubner cm->cm_passthr_dmat = 0; 1089*dce93cd0SAchim Leubner cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1090*dce93cd0SAchim Leubner cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1091*dce93cd0SAchim Leubner cm->cm_fib->Header.Unused = 0; 1092*dce93cd0SAchim Leubner cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 1093*dce93cd0SAchim Leubner 1094*dce93cd0SAchim Leubner /* 1095*dce93cd0SAchim Leubner * These are duplicated in aac_start to cover the case where an 1096*dce93cd0SAchim Leubner * intermediate stage may have destroyed them. They're left 1097*dce93cd0SAchim Leubner * initialized here for debugging purposes only. 1098*dce93cd0SAchim Leubner */ 1099*dce93cd0SAchim Leubner cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1100*dce93cd0SAchim Leubner cm->cm_fib->Header.Handle = 0; 1101*dce93cd0SAchim Leubner 1102*dce93cd0SAchim Leubner aac_enqueue_free(cm); 1103*dce93cd0SAchim Leubner 1104*dce93cd0SAchim Leubner /* 1105*dce93cd0SAchim Leubner * Dequeue all events so that there's no risk of events getting 1106*dce93cd0SAchim Leubner * stranded. 1107*dce93cd0SAchim Leubner */ 1108*dce93cd0SAchim Leubner while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 1109*dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1110*dce93cd0SAchim Leubner event->ev_callback(sc, event, event->ev_arg); 1111*dce93cd0SAchim Leubner } 1112*dce93cd0SAchim Leubner } 1113*dce93cd0SAchim Leubner 1114*dce93cd0SAchim Leubner /* 1115*dce93cd0SAchim Leubner * Map helper for command/FIB allocation. 1116*dce93cd0SAchim Leubner */ 1117*dce93cd0SAchim Leubner static void 1118*dce93cd0SAchim Leubner aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1119*dce93cd0SAchim Leubner { 1120*dce93cd0SAchim Leubner uint64_t *fibphys; 1121*dce93cd0SAchim Leubner 1122*dce93cd0SAchim Leubner fibphys = (uint64_t *)arg; 1123*dce93cd0SAchim Leubner 1124*dce93cd0SAchim Leubner *fibphys = segs[0].ds_addr; 1125*dce93cd0SAchim Leubner } 1126*dce93cd0SAchim Leubner 1127*dce93cd0SAchim Leubner /* 1128*dce93cd0SAchim Leubner * Allocate and initialize commands/FIBs for this adapter. 1129*dce93cd0SAchim Leubner */ 1130*dce93cd0SAchim Leubner static int 1131*dce93cd0SAchim Leubner aac_alloc_commands(struct aac_softc *sc) 1132*dce93cd0SAchim Leubner { 1133*dce93cd0SAchim Leubner struct aac_command *cm; 1134*dce93cd0SAchim Leubner struct aac_fibmap *fm; 1135*dce93cd0SAchim Leubner uint64_t fibphys; 1136*dce93cd0SAchim Leubner int i, error; 1137*dce93cd0SAchim Leubner u_int32_t maxsize; 1138*dce93cd0SAchim Leubner 1139*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1140*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1141*dce93cd0SAchim Leubner 1142*dce93cd0SAchim Leubner if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1143*dce93cd0SAchim Leubner return (ENOMEM); 1144*dce93cd0SAchim Leubner 1145*dce93cd0SAchim Leubner fm = malloc(sizeof(struct aac_fibmap), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1146*dce93cd0SAchim Leubner if (fm == NULL) 1147*dce93cd0SAchim Leubner return (ENOMEM); 1148*dce93cd0SAchim Leubner 1149*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 1150*dce93cd0SAchim Leubner /* allocate the FIBs in DMAable memory and load them */ 1151*dce93cd0SAchim Leubner if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1152*dce93cd0SAchim Leubner BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1153*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1154*dce93cd0SAchim Leubner "Not enough contiguous memory available.\n"); 1155*dce93cd0SAchim Leubner free(fm, M_AACRAIDBUF); 1156*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 1157*dce93cd0SAchim Leubner return (ENOMEM); 1158*dce93cd0SAchim Leubner } 1159*dce93cd0SAchim Leubner 1160*dce93cd0SAchim Leubner maxsize = sc->aac_max_fib_size + 31; 1161*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1162*dce93cd0SAchim Leubner maxsize += sizeof(struct aac_fib_xporthdr); 1163*dce93cd0SAchim Leubner /* Ignore errors since this doesn't bounce */ 1164*dce93cd0SAchim Leubner (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1165*dce93cd0SAchim Leubner sc->aac_max_fibs_alloc * maxsize, 1166*dce93cd0SAchim Leubner aac_map_command_helper, &fibphys, 0); 1167*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 1168*dce93cd0SAchim Leubner 1169*dce93cd0SAchim Leubner /* initialize constant fields in the command structure */ 1170*dce93cd0SAchim Leubner bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * maxsize); 1171*dce93cd0SAchim Leubner for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1172*dce93cd0SAchim Leubner cm = sc->aac_commands + sc->total_fibs; 1173*dce93cd0SAchim Leubner fm->aac_commands = cm; 1174*dce93cd0SAchim Leubner cm->cm_sc = sc; 1175*dce93cd0SAchim Leubner cm->cm_fib = (struct aac_fib *) 1176*dce93cd0SAchim Leubner ((u_int8_t *)fm->aac_fibs + i * maxsize); 1177*dce93cd0SAchim Leubner cm->cm_fibphys = fibphys + i * maxsize; 1178*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1179*dce93cd0SAchim Leubner u_int64_t fibphys_aligned; 1180*dce93cd0SAchim Leubner fibphys_aligned = 1181*dce93cd0SAchim Leubner (cm->cm_fibphys + sizeof(struct aac_fib_xporthdr) + 31) & ~31; 1182*dce93cd0SAchim Leubner cm->cm_fib = (struct aac_fib *) 1183*dce93cd0SAchim Leubner ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1184*dce93cd0SAchim Leubner cm->cm_fibphys = fibphys_aligned; 1185*dce93cd0SAchim Leubner } else { 1186*dce93cd0SAchim Leubner u_int64_t fibphys_aligned; 1187*dce93cd0SAchim Leubner fibphys_aligned = (cm->cm_fibphys + 31) & ~31; 1188*dce93cd0SAchim Leubner cm->cm_fib = (struct aac_fib *) 1189*dce93cd0SAchim Leubner ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1190*dce93cd0SAchim Leubner cm->cm_fibphys = fibphys_aligned; 1191*dce93cd0SAchim Leubner } 1192*dce93cd0SAchim Leubner cm->cm_index = sc->total_fibs; 1193*dce93cd0SAchim Leubner 1194*dce93cd0SAchim Leubner if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1195*dce93cd0SAchim Leubner &cm->cm_datamap)) != 0) 1196*dce93cd0SAchim Leubner break; 1197*dce93cd0SAchim Leubner if (sc->aac_max_fibs <= 1 || sc->aac_max_fibs - sc->total_fibs > 1) 1198*dce93cd0SAchim Leubner aacraid_release_command(cm); 1199*dce93cd0SAchim Leubner sc->total_fibs++; 1200*dce93cd0SAchim Leubner } 1201*dce93cd0SAchim Leubner 1202*dce93cd0SAchim Leubner if (i > 0) { 1203*dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1204*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1205*dce93cd0SAchim Leubner return (0); 1206*dce93cd0SAchim Leubner } 1207*dce93cd0SAchim Leubner 1208*dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1209*dce93cd0SAchim Leubner bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1210*dce93cd0SAchim Leubner free(fm, M_AACRAIDBUF); 1211*dce93cd0SAchim Leubner return (ENOMEM); 1212*dce93cd0SAchim Leubner } 1213*dce93cd0SAchim Leubner 1214*dce93cd0SAchim Leubner /* 1215*dce93cd0SAchim Leubner * Free FIBs owned by this adapter. 1216*dce93cd0SAchim Leubner */ 1217*dce93cd0SAchim Leubner static void 1218*dce93cd0SAchim Leubner aac_free_commands(struct aac_softc *sc) 1219*dce93cd0SAchim Leubner { 1220*dce93cd0SAchim Leubner struct aac_fibmap *fm; 1221*dce93cd0SAchim Leubner struct aac_command *cm; 1222*dce93cd0SAchim Leubner int i; 1223*dce93cd0SAchim Leubner 1224*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1225*dce93cd0SAchim Leubner 1226*dce93cd0SAchim Leubner while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1227*dce93cd0SAchim Leubner 1228*dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1229*dce93cd0SAchim Leubner /* 1230*dce93cd0SAchim Leubner * We check against total_fibs to handle partially 1231*dce93cd0SAchim Leubner * allocated blocks. 1232*dce93cd0SAchim Leubner */ 1233*dce93cd0SAchim Leubner for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1234*dce93cd0SAchim Leubner cm = fm->aac_commands + i; 1235*dce93cd0SAchim Leubner bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1236*dce93cd0SAchim Leubner } 1237*dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1238*dce93cd0SAchim Leubner bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1239*dce93cd0SAchim Leubner free(fm, M_AACRAIDBUF); 1240*dce93cd0SAchim Leubner } 1241*dce93cd0SAchim Leubner } 1242*dce93cd0SAchim Leubner 1243*dce93cd0SAchim Leubner /* 1244*dce93cd0SAchim Leubner * Command-mapping helper function - populate this command's s/g table. 1245*dce93cd0SAchim Leubner */ 1246*dce93cd0SAchim Leubner void 1247*dce93cd0SAchim Leubner aacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1248*dce93cd0SAchim Leubner { 1249*dce93cd0SAchim Leubner struct aac_softc *sc; 1250*dce93cd0SAchim Leubner struct aac_command *cm; 1251*dce93cd0SAchim Leubner struct aac_fib *fib; 1252*dce93cd0SAchim Leubner int i; 1253*dce93cd0SAchim Leubner 1254*dce93cd0SAchim Leubner cm = (struct aac_command *)arg; 1255*dce93cd0SAchim Leubner sc = cm->cm_sc; 1256*dce93cd0SAchim Leubner fib = cm->cm_fib; 1257*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "nseg %d", nseg); 1258*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1259*dce93cd0SAchim Leubner 1260*dce93cd0SAchim Leubner /* copy into the FIB */ 1261*dce93cd0SAchim Leubner if (cm->cm_sgtable != NULL) { 1262*dce93cd0SAchim Leubner if (fib->Header.Command == RawIo2) { 1263*dce93cd0SAchim Leubner struct aac_raw_io2 *raw; 1264*dce93cd0SAchim Leubner struct aac_sge_ieee1212 *sg; 1265*dce93cd0SAchim Leubner u_int32_t min_size = PAGE_SIZE, cur_size; 1266*dce93cd0SAchim Leubner int conformable = TRUE; 1267*dce93cd0SAchim Leubner 1268*dce93cd0SAchim Leubner raw = (struct aac_raw_io2 *)&fib->data[0]; 1269*dce93cd0SAchim Leubner sg = (struct aac_sge_ieee1212 *)cm->cm_sgtable; 1270*dce93cd0SAchim Leubner raw->sgeCnt = nseg; 1271*dce93cd0SAchim Leubner 1272*dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1273*dce93cd0SAchim Leubner cur_size = segs[i].ds_len; 1274*dce93cd0SAchim Leubner sg[i].addrHigh = 0; 1275*dce93cd0SAchim Leubner *(bus_addr_t *)&sg[i].addrLow = segs[i].ds_addr; 1276*dce93cd0SAchim Leubner sg[i].length = cur_size; 1277*dce93cd0SAchim Leubner sg[i].flags = 0; 1278*dce93cd0SAchim Leubner if (i == 0) { 1279*dce93cd0SAchim Leubner raw->sgeFirstSize = cur_size; 1280*dce93cd0SAchim Leubner } else if (i == 1) { 1281*dce93cd0SAchim Leubner raw->sgeNominalSize = cur_size; 1282*dce93cd0SAchim Leubner min_size = cur_size; 1283*dce93cd0SAchim Leubner } else if ((i+1) < nseg && 1284*dce93cd0SAchim Leubner cur_size != raw->sgeNominalSize) { 1285*dce93cd0SAchim Leubner conformable = FALSE; 1286*dce93cd0SAchim Leubner if (cur_size < min_size) 1287*dce93cd0SAchim Leubner min_size = cur_size; 1288*dce93cd0SAchim Leubner } 1289*dce93cd0SAchim Leubner } 1290*dce93cd0SAchim Leubner 1291*dce93cd0SAchim Leubner /* not conformable: evaluate required sg elements */ 1292*dce93cd0SAchim Leubner if (!conformable) { 1293*dce93cd0SAchim Leubner int j, err_found, nseg_new = nseg; 1294*dce93cd0SAchim Leubner for (i = min_size / PAGE_SIZE; i >= 1; --i) { 1295*dce93cd0SAchim Leubner err_found = FALSE; 1296*dce93cd0SAchim Leubner nseg_new = 2; 1297*dce93cd0SAchim Leubner for (j = 1; j < nseg - 1; ++j) { 1298*dce93cd0SAchim Leubner if (sg[j].length % (i*PAGE_SIZE)) { 1299*dce93cd0SAchim Leubner err_found = TRUE; 1300*dce93cd0SAchim Leubner break; 1301*dce93cd0SAchim Leubner } 1302*dce93cd0SAchim Leubner nseg_new += (sg[j].length / (i*PAGE_SIZE)); 1303*dce93cd0SAchim Leubner } 1304*dce93cd0SAchim Leubner if (!err_found) 1305*dce93cd0SAchim Leubner break; 1306*dce93cd0SAchim Leubner } 1307*dce93cd0SAchim Leubner if (i>0 && nseg_new<=sc->aac_sg_tablesize && 1308*dce93cd0SAchim Leubner !(sc->hint_flags & 4)) 1309*dce93cd0SAchim Leubner nseg = aac_convert_sgraw2(sc, 1310*dce93cd0SAchim Leubner raw, i, nseg, nseg_new); 1311*dce93cd0SAchim Leubner } else { 1312*dce93cd0SAchim Leubner raw->flags |= RIO2_SGL_CONFORMANT; 1313*dce93cd0SAchim Leubner } 1314*dce93cd0SAchim Leubner 1315*dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1316*dce93cd0SAchim Leubner fib->Header.Size += nseg * 1317*dce93cd0SAchim Leubner sizeof(struct aac_sge_ieee1212); 1318*dce93cd0SAchim Leubner 1319*dce93cd0SAchim Leubner } else if (fib->Header.Command == RawIo) { 1320*dce93cd0SAchim Leubner struct aac_sg_tableraw *sg; 1321*dce93cd0SAchim Leubner sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1322*dce93cd0SAchim Leubner sg->SgCount = nseg; 1323*dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1324*dce93cd0SAchim Leubner sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1325*dce93cd0SAchim Leubner sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1326*dce93cd0SAchim Leubner sg->SgEntryRaw[i].Next = 0; 1327*dce93cd0SAchim Leubner sg->SgEntryRaw[i].Prev = 0; 1328*dce93cd0SAchim Leubner sg->SgEntryRaw[i].Flags = 0; 1329*dce93cd0SAchim Leubner } 1330*dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1331*dce93cd0SAchim Leubner fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1332*dce93cd0SAchim Leubner } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1333*dce93cd0SAchim Leubner struct aac_sg_table *sg; 1334*dce93cd0SAchim Leubner sg = cm->cm_sgtable; 1335*dce93cd0SAchim Leubner sg->SgCount = nseg; 1336*dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1337*dce93cd0SAchim Leubner sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1338*dce93cd0SAchim Leubner sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1339*dce93cd0SAchim Leubner } 1340*dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1341*dce93cd0SAchim Leubner fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1342*dce93cd0SAchim Leubner } else { 1343*dce93cd0SAchim Leubner struct aac_sg_table64 *sg; 1344*dce93cd0SAchim Leubner sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1345*dce93cd0SAchim Leubner sg->SgCount = nseg; 1346*dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1347*dce93cd0SAchim Leubner sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1348*dce93cd0SAchim Leubner sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1349*dce93cd0SAchim Leubner } 1350*dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1351*dce93cd0SAchim Leubner fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1352*dce93cd0SAchim Leubner } 1353*dce93cd0SAchim Leubner } 1354*dce93cd0SAchim Leubner 1355*dce93cd0SAchim Leubner /* Fix up the address values in the FIB. Use the command array index 1356*dce93cd0SAchim Leubner * instead of a pointer since these fields are only 32 bits. Shift 1357*dce93cd0SAchim Leubner * the SenderFibAddress over to make room for the fast response bit 1358*dce93cd0SAchim Leubner * and for the AIF bit 1359*dce93cd0SAchim Leubner */ 1360*dce93cd0SAchim Leubner cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1361*dce93cd0SAchim Leubner cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1362*dce93cd0SAchim Leubner 1363*dce93cd0SAchim Leubner /* save a pointer to the command for speedy reverse-lookup */ 1364*dce93cd0SAchim Leubner cm->cm_fib->Header.Handle += cm->cm_index + 1; 1365*dce93cd0SAchim Leubner 1366*dce93cd0SAchim Leubner if (cm->cm_passthr_dmat == 0) { 1367*dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAIN) 1368*dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1369*dce93cd0SAchim Leubner BUS_DMASYNC_PREREAD); 1370*dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAOUT) 1371*dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1372*dce93cd0SAchim Leubner BUS_DMASYNC_PREWRITE); 1373*dce93cd0SAchim Leubner } 1374*dce93cd0SAchim Leubner 1375*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_MAPPED; 1376*dce93cd0SAchim Leubner 1377*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_SYNC_MODE) { 1378*dce93cd0SAchim Leubner u_int32_t wait = 0; 1379*dce93cd0SAchim Leubner aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, &wait, NULL); 1380*dce93cd0SAchim Leubner } else if (cm->cm_flags & AAC_CMD_WAIT) { 1381*dce93cd0SAchim Leubner aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, NULL, NULL); 1382*dce93cd0SAchim Leubner } else { 1383*dce93cd0SAchim Leubner int count = 10000000L; 1384*dce93cd0SAchim Leubner while (AAC_SEND_COMMAND(sc, cm) != 0) { 1385*dce93cd0SAchim Leubner if (--count == 0) { 1386*dce93cd0SAchim Leubner aac_unmap_command(cm); 1387*dce93cd0SAchim Leubner sc->flags |= AAC_QUEUE_FRZN; 1388*dce93cd0SAchim Leubner aac_requeue_ready(cm); 1389*dce93cd0SAchim Leubner } 1390*dce93cd0SAchim Leubner DELAY(5); /* wait 5 usec. */ 1391*dce93cd0SAchim Leubner } 1392*dce93cd0SAchim Leubner } 1393*dce93cd0SAchim Leubner } 1394*dce93cd0SAchim Leubner 1395*dce93cd0SAchim Leubner 1396*dce93cd0SAchim Leubner static int 1397*dce93cd0SAchim Leubner aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 1398*dce93cd0SAchim Leubner int pages, int nseg, int nseg_new) 1399*dce93cd0SAchim Leubner { 1400*dce93cd0SAchim Leubner struct aac_sge_ieee1212 *sge; 1401*dce93cd0SAchim Leubner int i, j, pos; 1402*dce93cd0SAchim Leubner u_int32_t addr_low; 1403*dce93cd0SAchim Leubner 1404*dce93cd0SAchim Leubner sge = malloc(nseg_new * sizeof(struct aac_sge_ieee1212), 1405*dce93cd0SAchim Leubner M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1406*dce93cd0SAchim Leubner if (sge == NULL) 1407*dce93cd0SAchim Leubner return nseg; 1408*dce93cd0SAchim Leubner 1409*dce93cd0SAchim Leubner for (i = 1, pos = 1; i < nseg - 1; ++i) { 1410*dce93cd0SAchim Leubner for (j = 0; j < raw->sge[i].length / (pages*PAGE_SIZE); ++j) { 1411*dce93cd0SAchim Leubner addr_low = raw->sge[i].addrLow + j * pages * PAGE_SIZE; 1412*dce93cd0SAchim Leubner sge[pos].addrLow = addr_low; 1413*dce93cd0SAchim Leubner sge[pos].addrHigh = raw->sge[i].addrHigh; 1414*dce93cd0SAchim Leubner if (addr_low < raw->sge[i].addrLow) 1415*dce93cd0SAchim Leubner sge[pos].addrHigh++; 1416*dce93cd0SAchim Leubner sge[pos].length = pages * PAGE_SIZE; 1417*dce93cd0SAchim Leubner sge[pos].flags = 0; 1418*dce93cd0SAchim Leubner pos++; 1419*dce93cd0SAchim Leubner } 1420*dce93cd0SAchim Leubner } 1421*dce93cd0SAchim Leubner sge[pos] = raw->sge[nseg-1]; 1422*dce93cd0SAchim Leubner for (i = 1; i < nseg_new; ++i) 1423*dce93cd0SAchim Leubner raw->sge[i] = sge[i]; 1424*dce93cd0SAchim Leubner 1425*dce93cd0SAchim Leubner free(sge, M_AACRAIDBUF); 1426*dce93cd0SAchim Leubner raw->sgeCnt = nseg_new; 1427*dce93cd0SAchim Leubner raw->flags |= RIO2_SGL_CONFORMANT; 1428*dce93cd0SAchim Leubner raw->sgeNominalSize = pages * PAGE_SIZE; 1429*dce93cd0SAchim Leubner return nseg_new; 1430*dce93cd0SAchim Leubner } 1431*dce93cd0SAchim Leubner 1432*dce93cd0SAchim Leubner 1433*dce93cd0SAchim Leubner /* 1434*dce93cd0SAchim Leubner * Unmap a command from controller-visible space. 1435*dce93cd0SAchim Leubner */ 1436*dce93cd0SAchim Leubner static void 1437*dce93cd0SAchim Leubner aac_unmap_command(struct aac_command *cm) 1438*dce93cd0SAchim Leubner { 1439*dce93cd0SAchim Leubner struct aac_softc *sc; 1440*dce93cd0SAchim Leubner 1441*dce93cd0SAchim Leubner sc = cm->cm_sc; 1442*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1443*dce93cd0SAchim Leubner 1444*dce93cd0SAchim Leubner if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1445*dce93cd0SAchim Leubner return; 1446*dce93cd0SAchim Leubner 1447*dce93cd0SAchim Leubner if (cm->cm_datalen != 0 && cm->cm_passthr_dmat == 0) { 1448*dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAIN) 1449*dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1450*dce93cd0SAchim Leubner BUS_DMASYNC_POSTREAD); 1451*dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAOUT) 1452*dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1453*dce93cd0SAchim Leubner BUS_DMASYNC_POSTWRITE); 1454*dce93cd0SAchim Leubner 1455*dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1456*dce93cd0SAchim Leubner } 1457*dce93cd0SAchim Leubner cm->cm_flags &= ~AAC_CMD_MAPPED; 1458*dce93cd0SAchim Leubner } 1459*dce93cd0SAchim Leubner 1460*dce93cd0SAchim Leubner /* 1461*dce93cd0SAchim Leubner * Hardware Interface 1462*dce93cd0SAchim Leubner */ 1463*dce93cd0SAchim Leubner 1464*dce93cd0SAchim Leubner /* 1465*dce93cd0SAchim Leubner * Initialize the adapter. 1466*dce93cd0SAchim Leubner */ 1467*dce93cd0SAchim Leubner static void 1468*dce93cd0SAchim Leubner aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1469*dce93cd0SAchim Leubner { 1470*dce93cd0SAchim Leubner struct aac_softc *sc; 1471*dce93cd0SAchim Leubner 1472*dce93cd0SAchim Leubner sc = (struct aac_softc *)arg; 1473*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1474*dce93cd0SAchim Leubner 1475*dce93cd0SAchim Leubner sc->aac_common_busaddr = segs[0].ds_addr; 1476*dce93cd0SAchim Leubner } 1477*dce93cd0SAchim Leubner 1478*dce93cd0SAchim Leubner static int 1479*dce93cd0SAchim Leubner aac_check_firmware(struct aac_softc *sc) 1480*dce93cd0SAchim Leubner { 1481*dce93cd0SAchim Leubner u_int32_t code, major, minor, maxsize; 1482*dce93cd0SAchim Leubner u_int32_t options = 0, atu_size = 0, status; 1483*dce93cd0SAchim Leubner time_t then; 1484*dce93cd0SAchim Leubner 1485*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1486*dce93cd0SAchim Leubner /* 1487*dce93cd0SAchim Leubner * Wait for the adapter to come ready. 1488*dce93cd0SAchim Leubner */ 1489*dce93cd0SAchim Leubner then = time_uptime; 1490*dce93cd0SAchim Leubner do { 1491*dce93cd0SAchim Leubner code = AAC_GET_FWSTATUS(sc); 1492*dce93cd0SAchim Leubner if (code & AAC_SELF_TEST_FAILED) { 1493*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 1494*dce93cd0SAchim Leubner return(ENXIO); 1495*dce93cd0SAchim Leubner } 1496*dce93cd0SAchim Leubner if (code & AAC_KERNEL_PANIC) { 1497*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1498*dce93cd0SAchim Leubner "FATAL: controller kernel panic"); 1499*dce93cd0SAchim Leubner return(ENXIO); 1500*dce93cd0SAchim Leubner } 1501*dce93cd0SAchim Leubner if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1502*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1503*dce93cd0SAchim Leubner "FATAL: controller not coming ready, " 1504*dce93cd0SAchim Leubner "status %x\n", code); 1505*dce93cd0SAchim Leubner return(ENXIO); 1506*dce93cd0SAchim Leubner } 1507*dce93cd0SAchim Leubner } while (!(code & AAC_UP_AND_RUNNING)); 1508*dce93cd0SAchim Leubner 1509*dce93cd0SAchim Leubner /* 1510*dce93cd0SAchim Leubner * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1511*dce93cd0SAchim Leubner * firmware version 1.x are not compatible with this driver. 1512*dce93cd0SAchim Leubner */ 1513*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_PERC2QC) { 1514*dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1515*dce93cd0SAchim Leubner NULL, NULL)) { 1516*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1517*dce93cd0SAchim Leubner "Error reading firmware version\n"); 1518*dce93cd0SAchim Leubner return (EIO); 1519*dce93cd0SAchim Leubner } 1520*dce93cd0SAchim Leubner 1521*dce93cd0SAchim Leubner /* These numbers are stored as ASCII! */ 1522*dce93cd0SAchim Leubner major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1523*dce93cd0SAchim Leubner minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1524*dce93cd0SAchim Leubner if (major == 1) { 1525*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1526*dce93cd0SAchim Leubner "Firmware version %d.%d is not supported.\n", 1527*dce93cd0SAchim Leubner major, minor); 1528*dce93cd0SAchim Leubner return (EINVAL); 1529*dce93cd0SAchim Leubner } 1530*dce93cd0SAchim Leubner } 1531*dce93cd0SAchim Leubner /* 1532*dce93cd0SAchim Leubner * Retrieve the capabilities/supported options word so we know what 1533*dce93cd0SAchim Leubner * work-arounds to enable. Some firmware revs don't support this 1534*dce93cd0SAchim Leubner * command. 1535*dce93cd0SAchim Leubner */ 1536*dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status, NULL)) { 1537*dce93cd0SAchim Leubner if (status != AAC_SRB_STS_INVALID_REQUEST) { 1538*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1539*dce93cd0SAchim Leubner "RequestAdapterInfo failed\n"); 1540*dce93cd0SAchim Leubner return (EIO); 1541*dce93cd0SAchim Leubner } 1542*dce93cd0SAchim Leubner } else { 1543*dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 1); 1544*dce93cd0SAchim Leubner atu_size = AAC_GET_MAILBOX(sc, 2); 1545*dce93cd0SAchim Leubner sc->supported_options = options; 1546*dce93cd0SAchim Leubner 1547*dce93cd0SAchim Leubner if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1548*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_NO4GB) == 0) 1549*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_4GB_WINDOW; 1550*dce93cd0SAchim Leubner if (options & AAC_SUPPORTED_NONDASD) 1551*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_ENABLE_CAM; 1552*dce93cd0SAchim Leubner if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1553*dce93cd0SAchim Leubner && (sizeof(bus_addr_t) > 4) 1554*dce93cd0SAchim Leubner && (sc->hint_flags & 0x1)) { 1555*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1556*dce93cd0SAchim Leubner "Enabling 64-bit address support\n"); 1557*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_SG_64BIT; 1558*dce93cd0SAchim Leubner } 1559*dce93cd0SAchim Leubner if (sc->aac_if.aif_send_command) { 1560*dce93cd0SAchim Leubner if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) || 1561*dce93cd0SAchim Leubner (options & AAC_SUPPORTED_NEW_COMM_TYPE4)) 1562*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34; 1563*dce93cd0SAchim Leubner else if (options & AAC_SUPPORTED_NEW_COMM_TYPE1) 1564*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE1; 1565*dce93cd0SAchim Leubner else if (options & AAC_SUPPORTED_NEW_COMM_TYPE2) 1566*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2; 1567*dce93cd0SAchim Leubner } 1568*dce93cd0SAchim Leubner if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1569*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1570*dce93cd0SAchim Leubner } 1571*dce93cd0SAchim Leubner 1572*dce93cd0SAchim Leubner if (!(sc->flags & AAC_FLAGS_NEW_COMM)) { 1573*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Communication interface not supported!\n"); 1574*dce93cd0SAchim Leubner return (ENXIO); 1575*dce93cd0SAchim Leubner } 1576*dce93cd0SAchim Leubner 1577*dce93cd0SAchim Leubner if (sc->hint_flags & 2) { 1578*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1579*dce93cd0SAchim Leubner "Sync. mode enforced by driver parameter. This will cause a significant performance decrease!\n"); 1580*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_SYNC_MODE; 1581*dce93cd0SAchim Leubner } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE34) { 1582*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1583*dce93cd0SAchim Leubner "Async. mode not supported by current driver, sync. mode enforced.\nPlease update driver to get full performance.\n"); 1584*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_SYNC_MODE; 1585*dce93cd0SAchim Leubner } 1586*dce93cd0SAchim Leubner 1587*dce93cd0SAchim Leubner /* Check for broken hardware that does a lower number of commands */ 1588*dce93cd0SAchim Leubner sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1589*dce93cd0SAchim Leubner 1590*dce93cd0SAchim Leubner /* Remap mem. resource, if required */ 1591*dce93cd0SAchim Leubner if (atu_size > rman_get_size(sc->aac_regs_res0)) { 1592*dce93cd0SAchim Leubner bus_release_resource( 1593*dce93cd0SAchim Leubner sc->aac_dev, SYS_RES_MEMORY, 1594*dce93cd0SAchim Leubner sc->aac_regs_rid0, sc->aac_regs_res0); 1595*dce93cd0SAchim Leubner sc->aac_regs_res0 = bus_alloc_resource( 1596*dce93cd0SAchim Leubner sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid0, 1597*dce93cd0SAchim Leubner 0ul, ~0ul, atu_size, RF_ACTIVE); 1598*dce93cd0SAchim Leubner if (sc->aac_regs_res0 == NULL) { 1599*dce93cd0SAchim Leubner sc->aac_regs_res0 = bus_alloc_resource_any( 1600*dce93cd0SAchim Leubner sc->aac_dev, SYS_RES_MEMORY, 1601*dce93cd0SAchim Leubner &sc->aac_regs_rid0, RF_ACTIVE); 1602*dce93cd0SAchim Leubner if (sc->aac_regs_res0 == NULL) { 1603*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1604*dce93cd0SAchim Leubner "couldn't allocate register window\n"); 1605*dce93cd0SAchim Leubner return (ENXIO); 1606*dce93cd0SAchim Leubner } 1607*dce93cd0SAchim Leubner } 1608*dce93cd0SAchim Leubner sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); 1609*dce93cd0SAchim Leubner sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); 1610*dce93cd0SAchim Leubner } 1611*dce93cd0SAchim Leubner 1612*dce93cd0SAchim Leubner /* Read preferred settings */ 1613*dce93cd0SAchim Leubner sc->aac_max_fib_size = sizeof(struct aac_fib); 1614*dce93cd0SAchim Leubner sc->aac_max_sectors = 128; /* 64KB */ 1615*dce93cd0SAchim Leubner sc->aac_max_aif = 1; 1616*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_SG_64BIT) 1617*dce93cd0SAchim Leubner sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1618*dce93cd0SAchim Leubner - sizeof(struct aac_blockwrite64)) 1619*dce93cd0SAchim Leubner / sizeof(struct aac_sg_entry64); 1620*dce93cd0SAchim Leubner else 1621*dce93cd0SAchim Leubner sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1622*dce93cd0SAchim Leubner - sizeof(struct aac_blockwrite)) 1623*dce93cd0SAchim Leubner / sizeof(struct aac_sg_entry); 1624*dce93cd0SAchim Leubner 1625*dce93cd0SAchim Leubner if (!aacraid_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL, NULL)) { 1626*dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 1); 1627*dce93cd0SAchim Leubner sc->aac_max_fib_size = (options & 0xFFFF); 1628*dce93cd0SAchim Leubner sc->aac_max_sectors = (options >> 16) << 1; 1629*dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 2); 1630*dce93cd0SAchim Leubner sc->aac_sg_tablesize = (options >> 16); 1631*dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 3); 1632*dce93cd0SAchim Leubner sc->aac_max_fibs = (options & 0xFFFF); 1633*dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 4); 1634*dce93cd0SAchim Leubner sc->aac_max_aif = (options & 0xFFFF); 1635*dce93cd0SAchim Leubner } 1636*dce93cd0SAchim Leubner 1637*dce93cd0SAchim Leubner maxsize = sc->aac_max_fib_size + 31; 1638*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1639*dce93cd0SAchim Leubner maxsize += sizeof(struct aac_fib_xporthdr); 1640*dce93cd0SAchim Leubner if (maxsize > PAGE_SIZE) { 1641*dce93cd0SAchim Leubner sc->aac_max_fib_size -= (maxsize - PAGE_SIZE); 1642*dce93cd0SAchim Leubner maxsize = PAGE_SIZE; 1643*dce93cd0SAchim Leubner } 1644*dce93cd0SAchim Leubner sc->aac_max_fibs_alloc = PAGE_SIZE / maxsize; 1645*dce93cd0SAchim Leubner 1646*dce93cd0SAchim Leubner if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1647*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_RAW_IO; 1648*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1649*dce93cd0SAchim Leubner } 1650*dce93cd0SAchim Leubner if ((sc->flags & AAC_FLAGS_RAW_IO) && 1651*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1652*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_LBA_64BIT; 1653*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1654*dce93cd0SAchim Leubner } 1655*dce93cd0SAchim Leubner 1656*dce93cd0SAchim Leubner aacraid_get_fw_debug_buffer(sc); 1657*dce93cd0SAchim Leubner return (0); 1658*dce93cd0SAchim Leubner } 1659*dce93cd0SAchim Leubner 1660*dce93cd0SAchim Leubner static int 1661*dce93cd0SAchim Leubner aac_init(struct aac_softc *sc) 1662*dce93cd0SAchim Leubner { 1663*dce93cd0SAchim Leubner struct aac_adapter_init *ip; 1664*dce93cd0SAchim Leubner int error; 1665*dce93cd0SAchim Leubner 1666*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1667*dce93cd0SAchim Leubner 1668*dce93cd0SAchim Leubner /* reset rrq index */ 1669*dce93cd0SAchim Leubner sc->aac_host_rrq_idx = 0; 1670*dce93cd0SAchim Leubner 1671*dce93cd0SAchim Leubner /* 1672*dce93cd0SAchim Leubner * Fill in the init structure. This tells the adapter about the 1673*dce93cd0SAchim Leubner * physical location of various important shared data structures. 1674*dce93cd0SAchim Leubner */ 1675*dce93cd0SAchim Leubner ip = &sc->aac_common->ac_init; 1676*dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1677*dce93cd0SAchim Leubner if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1678*dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1679*dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_RAW_IO; 1680*dce93cd0SAchim Leubner } 1681*dce93cd0SAchim Leubner ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 1682*dce93cd0SAchim Leubner 1683*dce93cd0SAchim Leubner ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1684*dce93cd0SAchim Leubner offsetof(struct aac_common, ac_fibs); 1685*dce93cd0SAchim Leubner ip->AdapterFibsVirtualAddress = 0; 1686*dce93cd0SAchim Leubner ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1687*dce93cd0SAchim Leubner ip->AdapterFibAlign = sizeof(struct aac_fib); 1688*dce93cd0SAchim Leubner 1689*dce93cd0SAchim Leubner ip->PrintfBufferAddress = sc->aac_common_busaddr + 1690*dce93cd0SAchim Leubner offsetof(struct aac_common, ac_printf); 1691*dce93cd0SAchim Leubner ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1692*dce93cd0SAchim Leubner 1693*dce93cd0SAchim Leubner /* 1694*dce93cd0SAchim Leubner * The adapter assumes that pages are 4K in size, except on some 1695*dce93cd0SAchim Leubner * broken firmware versions that do the page->byte conversion twice, 1696*dce93cd0SAchim Leubner * therefore 'assuming' that this value is in 16MB units (2^24). 1697*dce93cd0SAchim Leubner * Round up since the granularity is so high. 1698*dce93cd0SAchim Leubner */ 1699*dce93cd0SAchim Leubner ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1700*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1701*dce93cd0SAchim Leubner ip->HostPhysMemPages = 1702*dce93cd0SAchim Leubner (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1703*dce93cd0SAchim Leubner } 1704*dce93cd0SAchim Leubner ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 1705*dce93cd0SAchim Leubner 1706*dce93cd0SAchim Leubner ip->InitFlags = AAC_INITFLAGS_NEW_COMM_SUPPORTED; 1707*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1708*dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_6; 1709*dce93cd0SAchim Leubner ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | 1710*dce93cd0SAchim Leubner AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1711*dce93cd0SAchim Leubner ip->MiniPortRevision = 0L; 1712*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "New comm. interface type1 enabled\n"); 1713*dce93cd0SAchim Leubner } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 1714*dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_7; 1715*dce93cd0SAchim Leubner ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | 1716*dce93cd0SAchim Leubner AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1717*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "New comm. interface type2 enabled\n"); 1718*dce93cd0SAchim Leubner } 1719*dce93cd0SAchim Leubner ip->MaxNumAif = sc->aac_max_aif; 1720*dce93cd0SAchim Leubner ip->HostRRQ_AddrLow = 1721*dce93cd0SAchim Leubner sc->aac_common_busaddr + offsetof(struct aac_common, ac_host_rrq); 1722*dce93cd0SAchim Leubner /* always 32-bit address */ 1723*dce93cd0SAchim Leubner ip->HostRRQ_AddrHigh = 0; 1724*dce93cd0SAchim Leubner 1725*dce93cd0SAchim Leubner if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) { 1726*dce93cd0SAchim Leubner ip->InitFlags |= AAC_INITFLAGS_DRIVER_SUPPORTS_PM; 1727*dce93cd0SAchim Leubner ip->InitFlags |= AAC_INITFLAGS_DRIVER_USES_UTC_TIME; 1728*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Power Management enabled\n"); 1729*dce93cd0SAchim Leubner } 1730*dce93cd0SAchim Leubner 1731*dce93cd0SAchim Leubner ip->MaxIoCommands = sc->aac_max_fibs; 1732*dce93cd0SAchim Leubner ip->MaxIoSize = sc->aac_max_sectors << 9; 1733*dce93cd0SAchim Leubner ip->MaxFibSize = sc->aac_max_fib_size; 1734*dce93cd0SAchim Leubner 1735*dce93cd0SAchim Leubner /* 1736*dce93cd0SAchim Leubner * Do controller-type-specific initialisation 1737*dce93cd0SAchim Leubner */ 1738*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, ~0); 1739*dce93cd0SAchim Leubner 1740*dce93cd0SAchim Leubner /* 1741*dce93cd0SAchim Leubner * Give the init structure to the controller. 1742*dce93cd0SAchim Leubner */ 1743*dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_INITSTRUCT, 1744*dce93cd0SAchim Leubner sc->aac_common_busaddr + 1745*dce93cd0SAchim Leubner offsetof(struct aac_common, ac_init), 0, 0, 0, 1746*dce93cd0SAchim Leubner NULL, NULL)) { 1747*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1748*dce93cd0SAchim Leubner "error establishing init structure\n"); 1749*dce93cd0SAchim Leubner error = EIO; 1750*dce93cd0SAchim Leubner goto out; 1751*dce93cd0SAchim Leubner } 1752*dce93cd0SAchim Leubner 1753*dce93cd0SAchim Leubner error = 0; 1754*dce93cd0SAchim Leubner out: 1755*dce93cd0SAchim Leubner return(error); 1756*dce93cd0SAchim Leubner } 1757*dce93cd0SAchim Leubner 1758*dce93cd0SAchim Leubner static int 1759*dce93cd0SAchim Leubner aac_setup_intr(struct aac_softc *sc) 1760*dce93cd0SAchim Leubner { 1761*dce93cd0SAchim Leubner sc->aac_irq_rid = 0; 1762*dce93cd0SAchim Leubner if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 1763*dce93cd0SAchim Leubner &sc->aac_irq_rid, 1764*dce93cd0SAchim Leubner RF_SHAREABLE | 1765*dce93cd0SAchim Leubner RF_ACTIVE)) == NULL) { 1766*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate interrupt\n"); 1767*dce93cd0SAchim Leubner return (EINVAL); 1768*dce93cd0SAchim Leubner } 1769*dce93cd0SAchim Leubner if (aac_bus_setup_intr(sc->aac_dev, sc->aac_irq, 1770*dce93cd0SAchim Leubner INTR_MPSAFE|INTR_TYPE_BIO, NULL, 1771*dce93cd0SAchim Leubner aacraid_new_intr_type1, sc, &sc->aac_intr)) { 1772*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't set up interrupt\n"); 1773*dce93cd0SAchim Leubner return (EINVAL); 1774*dce93cd0SAchim Leubner } 1775*dce93cd0SAchim Leubner return (0); 1776*dce93cd0SAchim Leubner } 1777*dce93cd0SAchim Leubner 1778*dce93cd0SAchim Leubner /* 1779*dce93cd0SAchim Leubner * Send a synchronous command to the controller and wait for a result. 1780*dce93cd0SAchim Leubner * Indicate if the controller completed the command with an error status. 1781*dce93cd0SAchim Leubner */ 1782*dce93cd0SAchim Leubner int 1783*dce93cd0SAchim Leubner aacraid_sync_command(struct aac_softc *sc, u_int32_t command, 1784*dce93cd0SAchim Leubner u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 1785*dce93cd0SAchim Leubner u_int32_t *sp, u_int32_t *r1) 1786*dce93cd0SAchim Leubner { 1787*dce93cd0SAchim Leubner time_t then; 1788*dce93cd0SAchim Leubner u_int32_t status; 1789*dce93cd0SAchim Leubner 1790*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1791*dce93cd0SAchim Leubner 1792*dce93cd0SAchim Leubner /* populate the mailbox */ 1793*dce93cd0SAchim Leubner AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 1794*dce93cd0SAchim Leubner 1795*dce93cd0SAchim Leubner /* ensure the sync command doorbell flag is cleared */ 1796*dce93cd0SAchim Leubner AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1797*dce93cd0SAchim Leubner 1798*dce93cd0SAchim Leubner /* then set it to signal the adapter */ 1799*dce93cd0SAchim Leubner AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 1800*dce93cd0SAchim Leubner 1801*dce93cd0SAchim Leubner if ((command != AAC_MONKER_SYNCFIB) || (sp == NULL) || (*sp != 0)) { 1802*dce93cd0SAchim Leubner /* spin waiting for the command to complete */ 1803*dce93cd0SAchim Leubner then = time_uptime; 1804*dce93cd0SAchim Leubner do { 1805*dce93cd0SAchim Leubner if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 1806*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 1807*dce93cd0SAchim Leubner return(EIO); 1808*dce93cd0SAchim Leubner } 1809*dce93cd0SAchim Leubner } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 1810*dce93cd0SAchim Leubner 1811*dce93cd0SAchim Leubner /* clear the completion flag */ 1812*dce93cd0SAchim Leubner AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 1813*dce93cd0SAchim Leubner 1814*dce93cd0SAchim Leubner /* get the command status */ 1815*dce93cd0SAchim Leubner status = AAC_GET_MAILBOX(sc, 0); 1816*dce93cd0SAchim Leubner if (sp != NULL) 1817*dce93cd0SAchim Leubner *sp = status; 1818*dce93cd0SAchim Leubner 1819*dce93cd0SAchim Leubner /* return parameter */ 1820*dce93cd0SAchim Leubner if (r1 != NULL) 1821*dce93cd0SAchim Leubner *r1 = AAC_GET_MAILBOX(sc, 1); 1822*dce93cd0SAchim Leubner 1823*dce93cd0SAchim Leubner if (status != AAC_SRB_STS_SUCCESS) 1824*dce93cd0SAchim Leubner return (-1); 1825*dce93cd0SAchim Leubner } 1826*dce93cd0SAchim Leubner return(0); 1827*dce93cd0SAchim Leubner } 1828*dce93cd0SAchim Leubner 1829*dce93cd0SAchim Leubner static int 1830*dce93cd0SAchim Leubner aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 1831*dce93cd0SAchim Leubner struct aac_fib *fib, u_int16_t datasize) 1832*dce93cd0SAchim Leubner { 1833*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1834*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1835*dce93cd0SAchim Leubner 1836*dce93cd0SAchim Leubner if (datasize > AAC_FIB_DATASIZE) 1837*dce93cd0SAchim Leubner return(EINVAL); 1838*dce93cd0SAchim Leubner 1839*dce93cd0SAchim Leubner /* 1840*dce93cd0SAchim Leubner * Set up the sync FIB 1841*dce93cd0SAchim Leubner */ 1842*dce93cd0SAchim Leubner fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 1843*dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 1844*dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY; 1845*dce93cd0SAchim Leubner fib->Header.XferState |= xferstate; 1846*dce93cd0SAchim Leubner fib->Header.Command = command; 1847*dce93cd0SAchim Leubner fib->Header.StructType = AAC_FIBTYPE_TFIB; 1848*dce93cd0SAchim Leubner fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 1849*dce93cd0SAchim Leubner fib->Header.SenderSize = sizeof(struct aac_fib); 1850*dce93cd0SAchim Leubner fib->Header.SenderFibAddress = 0; /* Not needed */ 1851*dce93cd0SAchim Leubner fib->Header.u.ReceiverFibAddress = sc->aac_common_busaddr + 1852*dce93cd0SAchim Leubner offsetof(struct aac_common, 1853*dce93cd0SAchim Leubner ac_sync_fib); 1854*dce93cd0SAchim Leubner 1855*dce93cd0SAchim Leubner /* 1856*dce93cd0SAchim Leubner * Give the FIB to the controller, wait for a response. 1857*dce93cd0SAchim Leubner */ 1858*dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, 1859*dce93cd0SAchim Leubner fib->Header.u.ReceiverFibAddress, 0, 0, 0, NULL, NULL)) { 1860*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 1861*dce93cd0SAchim Leubner return(EIO); 1862*dce93cd0SAchim Leubner } 1863*dce93cd0SAchim Leubner 1864*dce93cd0SAchim Leubner return (0); 1865*dce93cd0SAchim Leubner } 1866*dce93cd0SAchim Leubner 1867*dce93cd0SAchim Leubner /* 1868*dce93cd0SAchim Leubner * Check for commands that have been outstanding for a suspiciously long time, 1869*dce93cd0SAchim Leubner * and complain about them. 1870*dce93cd0SAchim Leubner */ 1871*dce93cd0SAchim Leubner static void 1872*dce93cd0SAchim Leubner aac_timeout(struct aac_softc *sc) 1873*dce93cd0SAchim Leubner { 1874*dce93cd0SAchim Leubner struct aac_command *cm; 1875*dce93cd0SAchim Leubner time_t deadline; 1876*dce93cd0SAchim Leubner int timedout, code; 1877*dce93cd0SAchim Leubner 1878*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1879*dce93cd0SAchim Leubner /* 1880*dce93cd0SAchim Leubner * Traverse the busy command list, bitch about late commands once 1881*dce93cd0SAchim Leubner * only. 1882*dce93cd0SAchim Leubner */ 1883*dce93cd0SAchim Leubner timedout = 0; 1884*dce93cd0SAchim Leubner deadline = time_uptime - AAC_CMD_TIMEOUT; 1885*dce93cd0SAchim Leubner TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 1886*dce93cd0SAchim Leubner if ((cm->cm_timestamp < deadline) 1887*dce93cd0SAchim Leubner /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 1888*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_TIMEDOUT; 1889*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1890*dce93cd0SAchim Leubner "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 1891*dce93cd0SAchim Leubner cm, (int)(time_uptime-cm->cm_timestamp)); 1892*dce93cd0SAchim Leubner AAC_PRINT_FIB(sc, cm->cm_fib); 1893*dce93cd0SAchim Leubner timedout++; 1894*dce93cd0SAchim Leubner } 1895*dce93cd0SAchim Leubner } 1896*dce93cd0SAchim Leubner 1897*dce93cd0SAchim Leubner if (timedout) { 1898*dce93cd0SAchim Leubner code = AAC_GET_FWSTATUS(sc); 1899*dce93cd0SAchim Leubner if (code != AAC_UP_AND_RUNNING) { 1900*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "WARNING! Controller is no " 1901*dce93cd0SAchim Leubner "longer running! code= 0x%x\n", code); 1902*dce93cd0SAchim Leubner aac_reset_adapter(sc); 1903*dce93cd0SAchim Leubner } 1904*dce93cd0SAchim Leubner } 1905*dce93cd0SAchim Leubner aacraid_print_queues(sc); 1906*dce93cd0SAchim Leubner } 1907*dce93cd0SAchim Leubner 1908*dce93cd0SAchim Leubner /* 1909*dce93cd0SAchim Leubner * Interface Function Vectors 1910*dce93cd0SAchim Leubner */ 1911*dce93cd0SAchim Leubner 1912*dce93cd0SAchim Leubner /* 1913*dce93cd0SAchim Leubner * Read the current firmware status word. 1914*dce93cd0SAchim Leubner */ 1915*dce93cd0SAchim Leubner static int 1916*dce93cd0SAchim Leubner aac_src_get_fwstatus(struct aac_softc *sc) 1917*dce93cd0SAchim Leubner { 1918*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1919*dce93cd0SAchim Leubner 1920*dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRC_OMR)); 1921*dce93cd0SAchim Leubner } 1922*dce93cd0SAchim Leubner 1923*dce93cd0SAchim Leubner /* 1924*dce93cd0SAchim Leubner * Notify the controller of a change in a given queue 1925*dce93cd0SAchim Leubner */ 1926*dce93cd0SAchim Leubner static void 1927*dce93cd0SAchim Leubner aac_src_qnotify(struct aac_softc *sc, int qbit) 1928*dce93cd0SAchim Leubner { 1929*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1930*dce93cd0SAchim Leubner 1931*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, qbit << AAC_SRC_IDR_SHIFT); 1932*dce93cd0SAchim Leubner } 1933*dce93cd0SAchim Leubner 1934*dce93cd0SAchim Leubner /* 1935*dce93cd0SAchim Leubner * Get the interrupt reason bits 1936*dce93cd0SAchim Leubner */ 1937*dce93cd0SAchim Leubner static int 1938*dce93cd0SAchim Leubner aac_src_get_istatus(struct aac_softc *sc) 1939*dce93cd0SAchim Leubner { 1940*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1941*dce93cd0SAchim Leubner 1942*dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R) >> AAC_SRC_ODR_SHIFT); 1943*dce93cd0SAchim Leubner } 1944*dce93cd0SAchim Leubner 1945*dce93cd0SAchim Leubner /* 1946*dce93cd0SAchim Leubner * Clear some interrupt reason bits 1947*dce93cd0SAchim Leubner */ 1948*dce93cd0SAchim Leubner static void 1949*dce93cd0SAchim Leubner aac_src_clear_istatus(struct aac_softc *sc, int mask) 1950*dce93cd0SAchim Leubner { 1951*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1952*dce93cd0SAchim Leubner 1953*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, mask << AAC_SRC_ODR_SHIFT); 1954*dce93cd0SAchim Leubner } 1955*dce93cd0SAchim Leubner 1956*dce93cd0SAchim Leubner /* 1957*dce93cd0SAchim Leubner * Populate the mailbox and set the command word 1958*dce93cd0SAchim Leubner */ 1959*dce93cd0SAchim Leubner static void 1960*dce93cd0SAchim Leubner aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 1961*dce93cd0SAchim Leubner u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1962*dce93cd0SAchim Leubner { 1963*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1964*dce93cd0SAchim Leubner 1965*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX, command); 1966*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 4, arg0); 1967*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 8, arg1); 1968*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 12, arg2); 1969*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 16, arg3); 1970*dce93cd0SAchim Leubner } 1971*dce93cd0SAchim Leubner 1972*dce93cd0SAchim Leubner static void 1973*dce93cd0SAchim Leubner aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 1974*dce93cd0SAchim Leubner u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 1975*dce93cd0SAchim Leubner { 1976*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1977*dce93cd0SAchim Leubner 1978*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX, command); 1979*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 4, arg0); 1980*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 8, arg1); 1981*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 12, arg2); 1982*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 16, arg3); 1983*dce93cd0SAchim Leubner } 1984*dce93cd0SAchim Leubner 1985*dce93cd0SAchim Leubner /* 1986*dce93cd0SAchim Leubner * Fetch the immediate command status word 1987*dce93cd0SAchim Leubner */ 1988*dce93cd0SAchim Leubner static int 1989*dce93cd0SAchim Leubner aac_src_get_mailbox(struct aac_softc *sc, int mb) 1990*dce93cd0SAchim Leubner { 1991*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1992*dce93cd0SAchim Leubner 1993*dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRC_MAILBOX + (mb * 4))); 1994*dce93cd0SAchim Leubner } 1995*dce93cd0SAchim Leubner 1996*dce93cd0SAchim Leubner static int 1997*dce93cd0SAchim Leubner aac_srcv_get_mailbox(struct aac_softc *sc, int mb) 1998*dce93cd0SAchim Leubner { 1999*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2000*dce93cd0SAchim Leubner 2001*dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRCV_MAILBOX + (mb * 4))); 2002*dce93cd0SAchim Leubner } 2003*dce93cd0SAchim Leubner 2004*dce93cd0SAchim Leubner /* 2005*dce93cd0SAchim Leubner * Set/clear interrupt masks 2006*dce93cd0SAchim Leubner */ 2007*dce93cd0SAchim Leubner static void 2008*dce93cd0SAchim Leubner aac_src_set_interrupts(struct aac_softc *sc, int enable) 2009*dce93cd0SAchim Leubner { 2010*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2011*dce93cd0SAchim Leubner 2012*dce93cd0SAchim Leubner if (enable) { 2013*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, ~AAC_DB_INT_NEW_COMM_TYPE1); 2014*dce93cd0SAchim Leubner } else { 2015*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, ~0); 2016*dce93cd0SAchim Leubner } 2017*dce93cd0SAchim Leubner } 2018*dce93cd0SAchim Leubner 2019*dce93cd0SAchim Leubner /* 2020*dce93cd0SAchim Leubner * New comm. interface: Send command functions 2021*dce93cd0SAchim Leubner */ 2022*dce93cd0SAchim Leubner static int 2023*dce93cd0SAchim Leubner aac_src_send_command(struct aac_softc *sc, struct aac_command *cm) 2024*dce93cd0SAchim Leubner { 2025*dce93cd0SAchim Leubner struct aac_fib_xporthdr *pFibX; 2026*dce93cd0SAchim Leubner u_int32_t fibsize, high_addr; 2027*dce93cd0SAchim Leubner u_int64_t address; 2028*dce93cd0SAchim Leubner 2029*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm. type1)"); 2030*dce93cd0SAchim Leubner 2031*dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 2032*dce93cd0SAchim Leubner /* Calculate the amount to the fibsize bits */ 2033*dce93cd0SAchim Leubner fibsize = (cm->cm_fib->Header.Size + 127) / 128 - 1; 2034*dce93cd0SAchim Leubner /* Fill new FIB header */ 2035*dce93cd0SAchim Leubner address = cm->cm_fibphys; 2036*dce93cd0SAchim Leubner high_addr = (u_int32_t)(address >> 32); 2037*dce93cd0SAchim Leubner if (high_addr == 0L) { 2038*dce93cd0SAchim Leubner cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2; 2039*dce93cd0SAchim Leubner cm->cm_fib->Header.u.TimeStamp = 0L; 2040*dce93cd0SAchim Leubner } else { 2041*dce93cd0SAchim Leubner cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2_64; 2042*dce93cd0SAchim Leubner cm->cm_fib->Header.u.SenderFibAddressHigh = high_addr; 2043*dce93cd0SAchim Leubner } 2044*dce93cd0SAchim Leubner cm->cm_fib->Header.SenderFibAddress = (u_int32_t)address; 2045*dce93cd0SAchim Leubner } else { 2046*dce93cd0SAchim Leubner /* Calculate the amount to the fibsize bits */ 2047*dce93cd0SAchim Leubner fibsize = (sizeof(struct aac_fib_xporthdr) + 2048*dce93cd0SAchim Leubner cm->cm_fib->Header.Size + 127) / 128 - 1; 2049*dce93cd0SAchim Leubner /* Fill XPORT header */ 2050*dce93cd0SAchim Leubner pFibX = (struct aac_fib_xporthdr *) 2051*dce93cd0SAchim Leubner ((unsigned char *)cm->cm_fib - sizeof(struct aac_fib_xporthdr)); 2052*dce93cd0SAchim Leubner pFibX->Handle = cm->cm_fib->Header.Handle; 2053*dce93cd0SAchim Leubner pFibX->HostAddress = cm->cm_fibphys; 2054*dce93cd0SAchim Leubner pFibX->Size = cm->cm_fib->Header.Size; 2055*dce93cd0SAchim Leubner address = cm->cm_fibphys - sizeof(struct aac_fib_xporthdr); 2056*dce93cd0SAchim Leubner high_addr = (u_int32_t)(address >> 32); 2057*dce93cd0SAchim Leubner } 2058*dce93cd0SAchim Leubner 2059*dce93cd0SAchim Leubner if (fibsize > 31) 2060*dce93cd0SAchim Leubner fibsize = 31; 2061*dce93cd0SAchim Leubner aac_enqueue_busy(cm); 2062*dce93cd0SAchim Leubner if (high_addr) { 2063*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_H, high_addr); 2064*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_L, (u_int32_t)address + fibsize); 2065*dce93cd0SAchim Leubner } else { 2066*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE32, (u_int32_t)address + fibsize); 2067*dce93cd0SAchim Leubner } 2068*dce93cd0SAchim Leubner return 0; 2069*dce93cd0SAchim Leubner } 2070*dce93cd0SAchim Leubner 2071*dce93cd0SAchim Leubner /* 2072*dce93cd0SAchim Leubner * New comm. interface: get, set outbound queue index 2073*dce93cd0SAchim Leubner */ 2074*dce93cd0SAchim Leubner static int 2075*dce93cd0SAchim Leubner aac_src_get_outb_queue(struct aac_softc *sc) 2076*dce93cd0SAchim Leubner { 2077*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2078*dce93cd0SAchim Leubner 2079*dce93cd0SAchim Leubner return(-1); 2080*dce93cd0SAchim Leubner } 2081*dce93cd0SAchim Leubner 2082*dce93cd0SAchim Leubner static void 2083*dce93cd0SAchim Leubner aac_src_set_outb_queue(struct aac_softc *sc, int index) 2084*dce93cd0SAchim Leubner { 2085*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2086*dce93cd0SAchim Leubner } 2087*dce93cd0SAchim Leubner 2088*dce93cd0SAchim Leubner /* 2089*dce93cd0SAchim Leubner * Debugging and Diagnostics 2090*dce93cd0SAchim Leubner */ 2091*dce93cd0SAchim Leubner 2092*dce93cd0SAchim Leubner /* 2093*dce93cd0SAchim Leubner * Print some information about the controller. 2094*dce93cd0SAchim Leubner */ 2095*dce93cd0SAchim Leubner static void 2096*dce93cd0SAchim Leubner aac_describe_controller(struct aac_softc *sc) 2097*dce93cd0SAchim Leubner { 2098*dce93cd0SAchim Leubner struct aac_fib *fib; 2099*dce93cd0SAchim Leubner struct aac_adapter_info *info; 2100*dce93cd0SAchim Leubner char *adapter_type = "Adaptec RAID controller"; 2101*dce93cd0SAchim Leubner 2102*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2103*dce93cd0SAchim Leubner 2104*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2105*dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 2106*dce93cd0SAchim Leubner 2107*dce93cd0SAchim Leubner if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 2108*dce93cd0SAchim Leubner fib->data[0] = 0; 2109*dce93cd0SAchim Leubner if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 2110*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "RequestSupplementAdapterInfo failed\n"); 2111*dce93cd0SAchim Leubner else { 2112*dce93cd0SAchim Leubner struct aac_supplement_adapter_info *supp_info; 2113*dce93cd0SAchim Leubner 2114*dce93cd0SAchim Leubner supp_info = ((struct aac_supplement_adapter_info *)&fib->data[0]); 2115*dce93cd0SAchim Leubner adapter_type = (char *)supp_info->AdapterTypeText; 2116*dce93cd0SAchim Leubner sc->aac_feature_bits = supp_info->FeatureBits; 2117*dce93cd0SAchim Leubner sc->aac_support_opt2 = supp_info->SupportedOptions2; 2118*dce93cd0SAchim Leubner } 2119*dce93cd0SAchim Leubner } 2120*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "%s, aacraid driver %d.%d.%d-%d\n", 2121*dce93cd0SAchim Leubner adapter_type, 2122*dce93cd0SAchim Leubner AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 2123*dce93cd0SAchim Leubner AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 2124*dce93cd0SAchim Leubner 2125*dce93cd0SAchim Leubner fib->data[0] = 0; 2126*dce93cd0SAchim Leubner if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 2127*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2128*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 2129*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2130*dce93cd0SAchim Leubner return; 2131*dce93cd0SAchim Leubner } 2132*dce93cd0SAchim Leubner 2133*dce93cd0SAchim Leubner /* save the kernel revision structure for later use */ 2134*dce93cd0SAchim Leubner info = (struct aac_adapter_info *)&fib->data[0]; 2135*dce93cd0SAchim Leubner sc->aac_revision = info->KernelRevision; 2136*dce93cd0SAchim Leubner 2137*dce93cd0SAchim Leubner if (bootverbose) { 2138*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2139*dce93cd0SAchim Leubner "(%dMB cache, %dMB execution), %s\n", 2140*dce93cd0SAchim Leubner aac_describe_code(aac_cpu_variant, info->CpuVariant), 2141*dce93cd0SAchim Leubner info->ClockSpeed, info->TotalMem / (1024 * 1024), 2142*dce93cd0SAchim Leubner info->BufferMem / (1024 * 1024), 2143*dce93cd0SAchim Leubner info->ExecutionMem / (1024 * 1024), 2144*dce93cd0SAchim Leubner aac_describe_code(aac_battery_platform, 2145*dce93cd0SAchim Leubner info->batteryPlatform)); 2146*dce93cd0SAchim Leubner 2147*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 2148*dce93cd0SAchim Leubner "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2149*dce93cd0SAchim Leubner info->KernelRevision.external.comp.major, 2150*dce93cd0SAchim Leubner info->KernelRevision.external.comp.minor, 2151*dce93cd0SAchim Leubner info->KernelRevision.external.comp.dash, 2152*dce93cd0SAchim Leubner info->KernelRevision.buildNumber, 2153*dce93cd0SAchim Leubner (u_int32_t)(info->SerialNumber & 0xffffff)); 2154*dce93cd0SAchim Leubner 2155*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Supported Options=%b\n", 2156*dce93cd0SAchim Leubner sc->supported_options, 2157*dce93cd0SAchim Leubner "\20" 2158*dce93cd0SAchim Leubner "\1SNAPSHOT" 2159*dce93cd0SAchim Leubner "\2CLUSTERS" 2160*dce93cd0SAchim Leubner "\3WCACHE" 2161*dce93cd0SAchim Leubner "\4DATA64" 2162*dce93cd0SAchim Leubner "\5HOSTTIME" 2163*dce93cd0SAchim Leubner "\6RAID50" 2164*dce93cd0SAchim Leubner "\7WINDOW4GB" 2165*dce93cd0SAchim Leubner "\10SCSIUPGD" 2166*dce93cd0SAchim Leubner "\11SOFTERR" 2167*dce93cd0SAchim Leubner "\12NORECOND" 2168*dce93cd0SAchim Leubner "\13SGMAP64" 2169*dce93cd0SAchim Leubner "\14ALARM" 2170*dce93cd0SAchim Leubner "\15NONDASD" 2171*dce93cd0SAchim Leubner "\16SCSIMGT" 2172*dce93cd0SAchim Leubner "\17RAIDSCSI" 2173*dce93cd0SAchim Leubner "\21ADPTINFO" 2174*dce93cd0SAchim Leubner "\22NEWCOMM" 2175*dce93cd0SAchim Leubner "\23ARRAY64BIT" 2176*dce93cd0SAchim Leubner "\24HEATSENSOR"); 2177*dce93cd0SAchim Leubner } 2178*dce93cd0SAchim Leubner 2179*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 2180*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2181*dce93cd0SAchim Leubner } 2182*dce93cd0SAchim Leubner 2183*dce93cd0SAchim Leubner /* 2184*dce93cd0SAchim Leubner * Look up a text description of a numeric error code and return a pointer to 2185*dce93cd0SAchim Leubner * same. 2186*dce93cd0SAchim Leubner */ 2187*dce93cd0SAchim Leubner static char * 2188*dce93cd0SAchim Leubner aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2189*dce93cd0SAchim Leubner { 2190*dce93cd0SAchim Leubner int i; 2191*dce93cd0SAchim Leubner 2192*dce93cd0SAchim Leubner for (i = 0; table[i].string != NULL; i++) 2193*dce93cd0SAchim Leubner if (table[i].code == code) 2194*dce93cd0SAchim Leubner return(table[i].string); 2195*dce93cd0SAchim Leubner return(table[i + 1].string); 2196*dce93cd0SAchim Leubner } 2197*dce93cd0SAchim Leubner 2198*dce93cd0SAchim Leubner /* 2199*dce93cd0SAchim Leubner * Management Interface 2200*dce93cd0SAchim Leubner */ 2201*dce93cd0SAchim Leubner 2202*dce93cd0SAchim Leubner static int 2203*dce93cd0SAchim Leubner aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2204*dce93cd0SAchim Leubner { 2205*dce93cd0SAchim Leubner struct aac_softc *sc; 2206*dce93cd0SAchim Leubner 2207*dce93cd0SAchim Leubner sc = dev->si_drv1; 2208*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2209*dce93cd0SAchim Leubner #if __FreeBSD_version >= 702000 2210*dce93cd0SAchim Leubner device_busy(sc->aac_dev); 2211*dce93cd0SAchim Leubner devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 2212*dce93cd0SAchim Leubner #endif 2213*dce93cd0SAchim Leubner return 0; 2214*dce93cd0SAchim Leubner } 2215*dce93cd0SAchim Leubner 2216*dce93cd0SAchim Leubner static int 2217*dce93cd0SAchim Leubner aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2218*dce93cd0SAchim Leubner { 2219*dce93cd0SAchim Leubner union aac_statrequest *as; 2220*dce93cd0SAchim Leubner struct aac_softc *sc; 2221*dce93cd0SAchim Leubner int error = 0; 2222*dce93cd0SAchim Leubner 2223*dce93cd0SAchim Leubner as = (union aac_statrequest *)arg; 2224*dce93cd0SAchim Leubner sc = dev->si_drv1; 2225*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2226*dce93cd0SAchim Leubner 2227*dce93cd0SAchim Leubner switch (cmd) { 2228*dce93cd0SAchim Leubner case AACIO_STATS: 2229*dce93cd0SAchim Leubner switch (as->as_item) { 2230*dce93cd0SAchim Leubner case AACQ_FREE: 2231*dce93cd0SAchim Leubner case AACQ_READY: 2232*dce93cd0SAchim Leubner case AACQ_BUSY: 2233*dce93cd0SAchim Leubner bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2234*dce93cd0SAchim Leubner sizeof(struct aac_qstat)); 2235*dce93cd0SAchim Leubner break; 2236*dce93cd0SAchim Leubner default: 2237*dce93cd0SAchim Leubner error = ENOENT; 2238*dce93cd0SAchim Leubner break; 2239*dce93cd0SAchim Leubner } 2240*dce93cd0SAchim Leubner break; 2241*dce93cd0SAchim Leubner 2242*dce93cd0SAchim Leubner case FSACTL_SENDFIB: 2243*dce93cd0SAchim Leubner case FSACTL_SEND_LARGE_FIB: 2244*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2245*dce93cd0SAchim Leubner case FSACTL_LNX_SENDFIB: 2246*dce93cd0SAchim Leubner case FSACTL_LNX_SEND_LARGE_FIB: 2247*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 2248*dce93cd0SAchim Leubner error = aac_ioctl_sendfib(sc, arg); 2249*dce93cd0SAchim Leubner break; 2250*dce93cd0SAchim Leubner case FSACTL_SEND_RAW_SRB: 2251*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2252*dce93cd0SAchim Leubner case FSACTL_LNX_SEND_RAW_SRB: 2253*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2254*dce93cd0SAchim Leubner error = aac_ioctl_send_raw_srb(sc, arg); 2255*dce93cd0SAchim Leubner break; 2256*dce93cd0SAchim Leubner case FSACTL_AIF_THREAD: 2257*dce93cd0SAchim Leubner case FSACTL_LNX_AIF_THREAD: 2258*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 2259*dce93cd0SAchim Leubner error = EINVAL; 2260*dce93cd0SAchim Leubner break; 2261*dce93cd0SAchim Leubner case FSACTL_OPEN_GET_ADAPTER_FIB: 2262*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2263*dce93cd0SAchim Leubner case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2264*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2265*dce93cd0SAchim Leubner error = aac_open_aif(sc, arg); 2266*dce93cd0SAchim Leubner break; 2267*dce93cd0SAchim Leubner case FSACTL_GET_NEXT_ADAPTER_FIB: 2268*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2269*dce93cd0SAchim Leubner case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2270*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2271*dce93cd0SAchim Leubner error = aac_getnext_aif(sc, arg); 2272*dce93cd0SAchim Leubner break; 2273*dce93cd0SAchim Leubner case FSACTL_CLOSE_GET_ADAPTER_FIB: 2274*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2275*dce93cd0SAchim Leubner case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2276*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2277*dce93cd0SAchim Leubner error = aac_close_aif(sc, arg); 2278*dce93cd0SAchim Leubner break; 2279*dce93cd0SAchim Leubner case FSACTL_MINIPORT_REV_CHECK: 2280*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2281*dce93cd0SAchim Leubner case FSACTL_LNX_MINIPORT_REV_CHECK: 2282*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2283*dce93cd0SAchim Leubner error = aac_rev_check(sc, arg); 2284*dce93cd0SAchim Leubner break; 2285*dce93cd0SAchim Leubner case FSACTL_QUERY_DISK: 2286*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2287*dce93cd0SAchim Leubner case FSACTL_LNX_QUERY_DISK: 2288*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 2289*dce93cd0SAchim Leubner error = aac_query_disk(sc, arg); 2290*dce93cd0SAchim Leubner break; 2291*dce93cd0SAchim Leubner case FSACTL_DELETE_DISK: 2292*dce93cd0SAchim Leubner case FSACTL_LNX_DELETE_DISK: 2293*dce93cd0SAchim Leubner /* 2294*dce93cd0SAchim Leubner * We don't trust the underland to tell us when to delete a 2295*dce93cd0SAchim Leubner * container, rather we rely on an AIF coming from the 2296*dce93cd0SAchim Leubner * controller 2297*dce93cd0SAchim Leubner */ 2298*dce93cd0SAchim Leubner error = 0; 2299*dce93cd0SAchim Leubner break; 2300*dce93cd0SAchim Leubner case FSACTL_GET_PCI_INFO: 2301*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2302*dce93cd0SAchim Leubner case FSACTL_LNX_GET_PCI_INFO: 2303*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 2304*dce93cd0SAchim Leubner error = aac_get_pci_info(sc, arg); 2305*dce93cd0SAchim Leubner break; 2306*dce93cd0SAchim Leubner case FSACTL_GET_FEATURES: 2307*dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2308*dce93cd0SAchim Leubner case FSACTL_LNX_GET_FEATURES: 2309*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 2310*dce93cd0SAchim Leubner error = aac_supported_features(sc, arg); 2311*dce93cd0SAchim Leubner break; 2312*dce93cd0SAchim Leubner default: 2313*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 2314*dce93cd0SAchim Leubner error = EINVAL; 2315*dce93cd0SAchim Leubner break; 2316*dce93cd0SAchim Leubner } 2317*dce93cd0SAchim Leubner return(error); 2318*dce93cd0SAchim Leubner } 2319*dce93cd0SAchim Leubner 2320*dce93cd0SAchim Leubner static int 2321*dce93cd0SAchim Leubner aac_poll(struct cdev *dev, int poll_events, struct thread *td) 2322*dce93cd0SAchim Leubner { 2323*dce93cd0SAchim Leubner struct aac_softc *sc; 2324*dce93cd0SAchim Leubner struct aac_fib_context *ctx; 2325*dce93cd0SAchim Leubner int revents; 2326*dce93cd0SAchim Leubner 2327*dce93cd0SAchim Leubner sc = dev->si_drv1; 2328*dce93cd0SAchim Leubner revents = 0; 2329*dce93cd0SAchim Leubner 2330*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2331*dce93cd0SAchim Leubner if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2332*dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2333*dce93cd0SAchim Leubner if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2334*dce93cd0SAchim Leubner revents |= poll_events & (POLLIN | POLLRDNORM); 2335*dce93cd0SAchim Leubner break; 2336*dce93cd0SAchim Leubner } 2337*dce93cd0SAchim Leubner } 2338*dce93cd0SAchim Leubner } 2339*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2340*dce93cd0SAchim Leubner 2341*dce93cd0SAchim Leubner if (revents == 0) { 2342*dce93cd0SAchim Leubner if (poll_events & (POLLIN | POLLRDNORM)) 2343*dce93cd0SAchim Leubner selrecord(td, &sc->rcv_select); 2344*dce93cd0SAchim Leubner } 2345*dce93cd0SAchim Leubner 2346*dce93cd0SAchim Leubner return (revents); 2347*dce93cd0SAchim Leubner } 2348*dce93cd0SAchim Leubner 2349*dce93cd0SAchim Leubner static void 2350*dce93cd0SAchim Leubner aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2351*dce93cd0SAchim Leubner { 2352*dce93cd0SAchim Leubner 2353*dce93cd0SAchim Leubner switch (event->ev_type) { 2354*dce93cd0SAchim Leubner case AAC_EVENT_CMFREE: 2355*dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 2356*dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, (struct aac_command **)arg)) { 2357*dce93cd0SAchim Leubner aacraid_add_event(sc, event); 2358*dce93cd0SAchim Leubner return; 2359*dce93cd0SAchim Leubner } 2360*dce93cd0SAchim Leubner free(event, M_AACRAIDBUF); 2361*dce93cd0SAchim Leubner wakeup(arg); 2362*dce93cd0SAchim Leubner break; 2363*dce93cd0SAchim Leubner default: 2364*dce93cd0SAchim Leubner break; 2365*dce93cd0SAchim Leubner } 2366*dce93cd0SAchim Leubner } 2367*dce93cd0SAchim Leubner 2368*dce93cd0SAchim Leubner /* 2369*dce93cd0SAchim Leubner * Send a FIB supplied from userspace 2370*dce93cd0SAchim Leubner */ 2371*dce93cd0SAchim Leubner static int 2372*dce93cd0SAchim Leubner aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 2373*dce93cd0SAchim Leubner { 2374*dce93cd0SAchim Leubner struct aac_command *cm; 2375*dce93cd0SAchim Leubner int size, error; 2376*dce93cd0SAchim Leubner 2377*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2378*dce93cd0SAchim Leubner 2379*dce93cd0SAchim Leubner cm = NULL; 2380*dce93cd0SAchim Leubner 2381*dce93cd0SAchim Leubner /* 2382*dce93cd0SAchim Leubner * Get a command 2383*dce93cd0SAchim Leubner */ 2384*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2385*dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 2386*dce93cd0SAchim Leubner struct aac_event *event; 2387*dce93cd0SAchim Leubner 2388*dce93cd0SAchim Leubner event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2389*dce93cd0SAchim Leubner M_NOWAIT | M_ZERO); 2390*dce93cd0SAchim Leubner if (event == NULL) { 2391*dce93cd0SAchim Leubner error = EBUSY; 2392*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2393*dce93cd0SAchim Leubner goto out; 2394*dce93cd0SAchim Leubner } 2395*dce93cd0SAchim Leubner event->ev_type = AAC_EVENT_CMFREE; 2396*dce93cd0SAchim Leubner event->ev_callback = aac_ioctl_event; 2397*dce93cd0SAchim Leubner event->ev_arg = &cm; 2398*dce93cd0SAchim Leubner aacraid_add_event(sc, event); 2399*dce93cd0SAchim Leubner msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsfib", 0); 2400*dce93cd0SAchim Leubner } 2401*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2402*dce93cd0SAchim Leubner 2403*dce93cd0SAchim Leubner /* 2404*dce93cd0SAchim Leubner * Fetch the FIB header, then re-copy to get data as well. 2405*dce93cd0SAchim Leubner */ 2406*dce93cd0SAchim Leubner if ((error = copyin(ufib, cm->cm_fib, 2407*dce93cd0SAchim Leubner sizeof(struct aac_fib_header))) != 0) 2408*dce93cd0SAchim Leubner goto out; 2409*dce93cd0SAchim Leubner size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 2410*dce93cd0SAchim Leubner if (size > sc->aac_max_fib_size) { 2411*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2412*dce93cd0SAchim Leubner size, sc->aac_max_fib_size); 2413*dce93cd0SAchim Leubner size = sc->aac_max_fib_size; 2414*dce93cd0SAchim Leubner } 2415*dce93cd0SAchim Leubner if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 2416*dce93cd0SAchim Leubner goto out; 2417*dce93cd0SAchim Leubner cm->cm_fib->Header.Size = size; 2418*dce93cd0SAchim Leubner cm->cm_timestamp = time_uptime; 2419*dce93cd0SAchim Leubner cm->cm_datalen = 0; 2420*dce93cd0SAchim Leubner 2421*dce93cd0SAchim Leubner /* 2422*dce93cd0SAchim Leubner * Pass the FIB to the controller, wait for it to complete. 2423*dce93cd0SAchim Leubner */ 2424*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2425*dce93cd0SAchim Leubner error = aacraid_wait_command(cm); 2426*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2427*dce93cd0SAchim Leubner if (error != 0) { 2428*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 2429*dce93cd0SAchim Leubner "aacraid_wait_command return %d\n", error); 2430*dce93cd0SAchim Leubner goto out; 2431*dce93cd0SAchim Leubner } 2432*dce93cd0SAchim Leubner 2433*dce93cd0SAchim Leubner /* 2434*dce93cd0SAchim Leubner * Copy the FIB and data back out to the caller. 2435*dce93cd0SAchim Leubner */ 2436*dce93cd0SAchim Leubner size = cm->cm_fib->Header.Size; 2437*dce93cd0SAchim Leubner if (size > sc->aac_max_fib_size) { 2438*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2439*dce93cd0SAchim Leubner size, sc->aac_max_fib_size); 2440*dce93cd0SAchim Leubner size = sc->aac_max_fib_size; 2441*dce93cd0SAchim Leubner } 2442*dce93cd0SAchim Leubner error = copyout(cm->cm_fib, ufib, size); 2443*dce93cd0SAchim Leubner 2444*dce93cd0SAchim Leubner out: 2445*dce93cd0SAchim Leubner if (cm != NULL) { 2446*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2447*dce93cd0SAchim Leubner aacraid_release_command(cm); 2448*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2449*dce93cd0SAchim Leubner } 2450*dce93cd0SAchim Leubner return(error); 2451*dce93cd0SAchim Leubner } 2452*dce93cd0SAchim Leubner 2453*dce93cd0SAchim Leubner /* 2454*dce93cd0SAchim Leubner * Send a passthrough FIB supplied from userspace 2455*dce93cd0SAchim Leubner */ 2456*dce93cd0SAchim Leubner static int 2457*dce93cd0SAchim Leubner aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 2458*dce93cd0SAchim Leubner { 2459*dce93cd0SAchim Leubner struct aac_command *cm; 2460*dce93cd0SAchim Leubner struct aac_fib *fib; 2461*dce93cd0SAchim Leubner struct aac_srb *srbcmd; 2462*dce93cd0SAchim Leubner struct aac_srb *user_srb = (struct aac_srb *)arg; 2463*dce93cd0SAchim Leubner void *user_reply; 2464*dce93cd0SAchim Leubner int error, transfer_data = 0; 2465*dce93cd0SAchim Leubner bus_dmamap_t orig_map = 0; 2466*dce93cd0SAchim Leubner u_int32_t fibsize = 0; 2467*dce93cd0SAchim Leubner u_int64_t srb_sg_address; 2468*dce93cd0SAchim Leubner u_int32_t srb_sg_bytecount; 2469*dce93cd0SAchim Leubner 2470*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2471*dce93cd0SAchim Leubner 2472*dce93cd0SAchim Leubner cm = NULL; 2473*dce93cd0SAchim Leubner 2474*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2475*dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 2476*dce93cd0SAchim Leubner struct aac_event *event; 2477*dce93cd0SAchim Leubner 2478*dce93cd0SAchim Leubner event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2479*dce93cd0SAchim Leubner M_NOWAIT | M_ZERO); 2480*dce93cd0SAchim Leubner if (event == NULL) { 2481*dce93cd0SAchim Leubner error = EBUSY; 2482*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2483*dce93cd0SAchim Leubner goto out; 2484*dce93cd0SAchim Leubner } 2485*dce93cd0SAchim Leubner event->ev_type = AAC_EVENT_CMFREE; 2486*dce93cd0SAchim Leubner event->ev_callback = aac_ioctl_event; 2487*dce93cd0SAchim Leubner event->ev_arg = &cm; 2488*dce93cd0SAchim Leubner aacraid_add_event(sc, event); 2489*dce93cd0SAchim Leubner msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsraw", 0); 2490*dce93cd0SAchim Leubner } 2491*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2492*dce93cd0SAchim Leubner 2493*dce93cd0SAchim Leubner cm->cm_data = NULL; 2494*dce93cd0SAchim Leubner /* save original dma map */ 2495*dce93cd0SAchim Leubner orig_map = cm->cm_datamap; 2496*dce93cd0SAchim Leubner 2497*dce93cd0SAchim Leubner fib = cm->cm_fib; 2498*dce93cd0SAchim Leubner srbcmd = (struct aac_srb *)fib->data; 2499*dce93cd0SAchim Leubner if ((error = copyin((void *)&user_srb->data_len, &fibsize, 2500*dce93cd0SAchim Leubner sizeof (u_int32_t)) != 0)) 2501*dce93cd0SAchim Leubner goto out; 2502*dce93cd0SAchim Leubner if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) { 2503*dce93cd0SAchim Leubner error = EINVAL; 2504*dce93cd0SAchim Leubner goto out; 2505*dce93cd0SAchim Leubner } 2506*dce93cd0SAchim Leubner if ((error = copyin((void *)user_srb, srbcmd, fibsize) != 0)) 2507*dce93cd0SAchim Leubner goto out; 2508*dce93cd0SAchim Leubner 2509*dce93cd0SAchim Leubner srbcmd->function = 0; /* SRBF_ExecuteScsi */ 2510*dce93cd0SAchim Leubner srbcmd->retry_limit = 0; /* obsolete */ 2511*dce93cd0SAchim Leubner 2512*dce93cd0SAchim Leubner /* only one sg element from userspace supported */ 2513*dce93cd0SAchim Leubner if (srbcmd->sg_map.SgCount > 1) { 2514*dce93cd0SAchim Leubner error = EINVAL; 2515*dce93cd0SAchim Leubner goto out; 2516*dce93cd0SAchim Leubner } 2517*dce93cd0SAchim Leubner /* check fibsize */ 2518*dce93cd0SAchim Leubner if (fibsize == (sizeof(struct aac_srb) + 2519*dce93cd0SAchim Leubner srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 2520*dce93cd0SAchim Leubner struct aac_sg_entry *sgp = srbcmd->sg_map.SgEntry; 2521*dce93cd0SAchim Leubner srb_sg_bytecount = sgp->SgByteCount; 2522*dce93cd0SAchim Leubner srb_sg_address = (u_int64_t)sgp->SgAddress; 2523*dce93cd0SAchim Leubner } else if (fibsize == (sizeof(struct aac_srb) + 2524*dce93cd0SAchim Leubner srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 2525*dce93cd0SAchim Leubner #ifdef __amd64__ 2526*dce93cd0SAchim Leubner struct aac_sg_entry64 *sgp = 2527*dce93cd0SAchim Leubner (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 2528*dce93cd0SAchim Leubner srb_sg_bytecount = sgp->SgByteCount; 2529*dce93cd0SAchim Leubner srb_sg_address = sgp->SgAddress; 2530*dce93cd0SAchim Leubner if (srb_sg_address > 0xffffffffull && 2531*dce93cd0SAchim Leubner !(sc->flags & AAC_FLAGS_SG_64BIT)) 2532*dce93cd0SAchim Leubner #endif 2533*dce93cd0SAchim Leubner { 2534*dce93cd0SAchim Leubner error = EINVAL; 2535*dce93cd0SAchim Leubner goto out; 2536*dce93cd0SAchim Leubner } 2537*dce93cd0SAchim Leubner } else { 2538*dce93cd0SAchim Leubner error = EINVAL; 2539*dce93cd0SAchim Leubner goto out; 2540*dce93cd0SAchim Leubner } 2541*dce93cd0SAchim Leubner user_reply = (char *)arg + fibsize; 2542*dce93cd0SAchim Leubner srbcmd->data_len = srb_sg_bytecount; 2543*dce93cd0SAchim Leubner if (srbcmd->sg_map.SgCount == 1) 2544*dce93cd0SAchim Leubner transfer_data = 1; 2545*dce93cd0SAchim Leubner 2546*dce93cd0SAchim Leubner if (transfer_data) { 2547*dce93cd0SAchim Leubner /* 2548*dce93cd0SAchim Leubner * Create DMA tag for the passthr. data buffer and allocate it. 2549*dce93cd0SAchim Leubner */ 2550*dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 2551*dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 2552*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_SG_64BIT) ? 2553*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT : 2554*dce93cd0SAchim Leubner 0x7fffffff, /* lowaddr */ 2555*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 2556*dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 2557*dce93cd0SAchim Leubner srb_sg_bytecount, /* size */ 2558*dce93cd0SAchim Leubner sc->aac_sg_tablesize, /* nsegments */ 2559*dce93cd0SAchim Leubner srb_sg_bytecount, /* maxsegsize */ 2560*dce93cd0SAchim Leubner 0, /* flags */ 2561*dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 2562*dce93cd0SAchim Leubner &cm->cm_passthr_dmat)) { 2563*dce93cd0SAchim Leubner error = ENOMEM; 2564*dce93cd0SAchim Leubner goto out; 2565*dce93cd0SAchim Leubner } 2566*dce93cd0SAchim Leubner if (bus_dmamem_alloc(cm->cm_passthr_dmat, (void **)&cm->cm_data, 2567*dce93cd0SAchim Leubner BUS_DMA_NOWAIT, &cm->cm_datamap)) { 2568*dce93cd0SAchim Leubner error = ENOMEM; 2569*dce93cd0SAchim Leubner goto out; 2570*dce93cd0SAchim Leubner } 2571*dce93cd0SAchim Leubner /* fill some cm variables */ 2572*dce93cd0SAchim Leubner cm->cm_datalen = srb_sg_bytecount; 2573*dce93cd0SAchim Leubner if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 2574*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_DATAIN; 2575*dce93cd0SAchim Leubner if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) 2576*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_DATAOUT; 2577*dce93cd0SAchim Leubner 2578*dce93cd0SAchim Leubner if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 2579*dce93cd0SAchim Leubner if ((error = copyin( 2580*dce93cd0SAchim Leubner #ifdef __amd64__ 2581*dce93cd0SAchim Leubner (void *)srb_sg_address, 2582*dce93cd0SAchim Leubner #else 2583*dce93cd0SAchim Leubner (void *)(u_int32_t)srb_sg_address, 2584*dce93cd0SAchim Leubner #endif 2585*dce93cd0SAchim Leubner cm->cm_data, cm->cm_datalen)) != 0) 2586*dce93cd0SAchim Leubner goto out; 2587*dce93cd0SAchim Leubner /* sync required for bus_dmamem_alloc() alloc. mem.? */ 2588*dce93cd0SAchim Leubner bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2589*dce93cd0SAchim Leubner BUS_DMASYNC_PREWRITE); 2590*dce93cd0SAchim Leubner } 2591*dce93cd0SAchim Leubner } 2592*dce93cd0SAchim Leubner 2593*dce93cd0SAchim Leubner /* build the FIB */ 2594*dce93cd0SAchim Leubner fib->Header.Size = sizeof(struct aac_fib_header) + 2595*dce93cd0SAchim Leubner sizeof(struct aac_srb); 2596*dce93cd0SAchim Leubner fib->Header.XferState = 2597*dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 2598*dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 2599*dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 2600*dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 2601*dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 2602*dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 2603*dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC; 2604*dce93cd0SAchim Leubner 2605*dce93cd0SAchim Leubner fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? 2606*dce93cd0SAchim Leubner ScsiPortCommandU64 : ScsiPortCommand; 2607*dce93cd0SAchim Leubner cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 2608*dce93cd0SAchim Leubner 2609*dce93cd0SAchim Leubner /* send command */ 2610*dce93cd0SAchim Leubner if (transfer_data) { 2611*dce93cd0SAchim Leubner bus_dmamap_load(cm->cm_passthr_dmat, 2612*dce93cd0SAchim Leubner cm->cm_datamap, cm->cm_data, 2613*dce93cd0SAchim Leubner cm->cm_datalen, 2614*dce93cd0SAchim Leubner aacraid_map_command_sg, cm, 0); 2615*dce93cd0SAchim Leubner } else { 2616*dce93cd0SAchim Leubner aacraid_map_command_sg(cm, NULL, 0, 0); 2617*dce93cd0SAchim Leubner } 2618*dce93cd0SAchim Leubner 2619*dce93cd0SAchim Leubner /* wait for completion */ 2620*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2621*dce93cd0SAchim Leubner while (!(cm->cm_flags & AAC_CMD_COMPLETED)) 2622*dce93cd0SAchim Leubner msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsrw2", 0); 2623*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2624*dce93cd0SAchim Leubner 2625*dce93cd0SAchim Leubner /* copy data */ 2626*dce93cd0SAchim Leubner if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)) { 2627*dce93cd0SAchim Leubner if ((error = copyout(cm->cm_data, 2628*dce93cd0SAchim Leubner #ifdef __amd64__ 2629*dce93cd0SAchim Leubner (void *)srb_sg_address, 2630*dce93cd0SAchim Leubner #else 2631*dce93cd0SAchim Leubner (void *)(u_int32_t)srb_sg_address, 2632*dce93cd0SAchim Leubner #endif 2633*dce93cd0SAchim Leubner cm->cm_datalen)) != 0) 2634*dce93cd0SAchim Leubner goto out; 2635*dce93cd0SAchim Leubner /* sync required for bus_dmamem_alloc() allocated mem.? */ 2636*dce93cd0SAchim Leubner bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2637*dce93cd0SAchim Leubner BUS_DMASYNC_POSTREAD); 2638*dce93cd0SAchim Leubner } 2639*dce93cd0SAchim Leubner 2640*dce93cd0SAchim Leubner /* status */ 2641*dce93cd0SAchim Leubner error = copyout(fib->data, user_reply, sizeof(struct aac_srb_response)); 2642*dce93cd0SAchim Leubner 2643*dce93cd0SAchim Leubner out: 2644*dce93cd0SAchim Leubner if (cm && cm->cm_data) { 2645*dce93cd0SAchim Leubner if (transfer_data) 2646*dce93cd0SAchim Leubner bus_dmamap_unload(cm->cm_passthr_dmat, cm->cm_datamap); 2647*dce93cd0SAchim Leubner bus_dmamem_free(cm->cm_passthr_dmat, cm->cm_data, cm->cm_datamap); 2648*dce93cd0SAchim Leubner cm->cm_datamap = orig_map; 2649*dce93cd0SAchim Leubner } 2650*dce93cd0SAchim Leubner if (cm && cm->cm_passthr_dmat) 2651*dce93cd0SAchim Leubner bus_dma_tag_destroy(cm->cm_passthr_dmat); 2652*dce93cd0SAchim Leubner if (cm) { 2653*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2654*dce93cd0SAchim Leubner aacraid_release_command(cm); 2655*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2656*dce93cd0SAchim Leubner } 2657*dce93cd0SAchim Leubner return(error); 2658*dce93cd0SAchim Leubner } 2659*dce93cd0SAchim Leubner 2660*dce93cd0SAchim Leubner /* 2661*dce93cd0SAchim Leubner * Request an AIF from the controller (new comm. type1) 2662*dce93cd0SAchim Leubner */ 2663*dce93cd0SAchim Leubner static void 2664*dce93cd0SAchim Leubner aac_request_aif(struct aac_softc *sc) 2665*dce93cd0SAchim Leubner { 2666*dce93cd0SAchim Leubner struct aac_command *cm; 2667*dce93cd0SAchim Leubner struct aac_fib *fib; 2668*dce93cd0SAchim Leubner 2669*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2670*dce93cd0SAchim Leubner 2671*dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 2672*dce93cd0SAchim Leubner sc->aif_pending = 1; 2673*dce93cd0SAchim Leubner return; 2674*dce93cd0SAchim Leubner } 2675*dce93cd0SAchim Leubner sc->aif_pending = 0; 2676*dce93cd0SAchim Leubner 2677*dce93cd0SAchim Leubner /* build the FIB */ 2678*dce93cd0SAchim Leubner fib = cm->cm_fib; 2679*dce93cd0SAchim Leubner fib->Header.Size = sizeof(struct aac_fib); 2680*dce93cd0SAchim Leubner fib->Header.XferState = 2681*dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 2682*dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 2683*dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 2684*dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 2685*dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 2686*dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 2687*dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC; 2688*dce93cd0SAchim Leubner /* set AIF marker */ 2689*dce93cd0SAchim Leubner fib->Header.Handle = 0x00800000; 2690*dce93cd0SAchim Leubner fib->Header.Command = AifRequest; 2691*dce93cd0SAchim Leubner ((struct aac_aif_command *)fib->data)->command = AifReqEvent; 2692*dce93cd0SAchim Leubner 2693*dce93cd0SAchim Leubner aacraid_map_command_sg(cm, NULL, 0, 0); 2694*dce93cd0SAchim Leubner } 2695*dce93cd0SAchim Leubner 2696*dce93cd0SAchim Leubner 2697*dce93cd0SAchim Leubner #if __FreeBSD_version >= 702000 2698*dce93cd0SAchim Leubner /* 2699*dce93cd0SAchim Leubner * cdevpriv interface private destructor. 2700*dce93cd0SAchim Leubner */ 2701*dce93cd0SAchim Leubner static void 2702*dce93cd0SAchim Leubner aac_cdevpriv_dtor(void *arg) 2703*dce93cd0SAchim Leubner { 2704*dce93cd0SAchim Leubner struct aac_softc *sc; 2705*dce93cd0SAchim Leubner 2706*dce93cd0SAchim Leubner sc = arg; 2707*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2708*dce93cd0SAchim Leubner mtx_lock(&Giant); 2709*dce93cd0SAchim Leubner device_unbusy(sc->aac_dev); 2710*dce93cd0SAchim Leubner mtx_unlock(&Giant); 2711*dce93cd0SAchim Leubner } 2712*dce93cd0SAchim Leubner #else 2713*dce93cd0SAchim Leubner static int 2714*dce93cd0SAchim Leubner aac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2715*dce93cd0SAchim Leubner { 2716*dce93cd0SAchim Leubner struct aac_softc *sc; 2717*dce93cd0SAchim Leubner 2718*dce93cd0SAchim Leubner sc = dev->si_drv1; 2719*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2720*dce93cd0SAchim Leubner return 0; 2721*dce93cd0SAchim Leubner } 2722*dce93cd0SAchim Leubner #endif 2723*dce93cd0SAchim Leubner 2724*dce93cd0SAchim Leubner /* 2725*dce93cd0SAchim Leubner * Handle an AIF sent to us by the controller; queue it for later reference. 2726*dce93cd0SAchim Leubner * If the queue fills up, then drop the older entries. 2727*dce93cd0SAchim Leubner */ 2728*dce93cd0SAchim Leubner static void 2729*dce93cd0SAchim Leubner aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 2730*dce93cd0SAchim Leubner { 2731*dce93cd0SAchim Leubner struct aac_aif_command *aif; 2732*dce93cd0SAchim Leubner struct aac_container *co, *co_next; 2733*dce93cd0SAchim Leubner struct aac_fib_context *ctx; 2734*dce93cd0SAchim Leubner struct aac_fib *sync_fib; 2735*dce93cd0SAchim Leubner struct aac_mntinforesp mir; 2736*dce93cd0SAchim Leubner int next, current, found; 2737*dce93cd0SAchim Leubner int count = 0, changed = 0, i = 0; 2738*dce93cd0SAchim Leubner u_int32_t channel, uid; 2739*dce93cd0SAchim Leubner 2740*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2741*dce93cd0SAchim Leubner 2742*dce93cd0SAchim Leubner aif = (struct aac_aif_command*)&fib->data[0]; 2743*dce93cd0SAchim Leubner aacraid_print_aif(sc, aif); 2744*dce93cd0SAchim Leubner 2745*dce93cd0SAchim Leubner /* Is it an event that we should care about? */ 2746*dce93cd0SAchim Leubner switch (aif->command) { 2747*dce93cd0SAchim Leubner case AifCmdEventNotify: 2748*dce93cd0SAchim Leubner switch (aif->data.EN.type) { 2749*dce93cd0SAchim Leubner case AifEnAddContainer: 2750*dce93cd0SAchim Leubner case AifEnDeleteContainer: 2751*dce93cd0SAchim Leubner /* 2752*dce93cd0SAchim Leubner * A container was added or deleted, but the message 2753*dce93cd0SAchim Leubner * doesn't tell us anything else! Re-enumerate the 2754*dce93cd0SAchim Leubner * containers and sort things out. 2755*dce93cd0SAchim Leubner */ 2756*dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &sync_fib); 2757*dce93cd0SAchim Leubner do { 2758*dce93cd0SAchim Leubner /* 2759*dce93cd0SAchim Leubner * Ask the controller for its containers one at 2760*dce93cd0SAchim Leubner * a time. 2761*dce93cd0SAchim Leubner * XXX What if the controller's list changes 2762*dce93cd0SAchim Leubner * midway through this enumaration? 2763*dce93cd0SAchim Leubner * XXX This should be done async. 2764*dce93cd0SAchim Leubner */ 2765*dce93cd0SAchim Leubner if (aac_get_container_info(sc, sync_fib, i, 2766*dce93cd0SAchim Leubner &mir, &uid) != 0) 2767*dce93cd0SAchim Leubner continue; 2768*dce93cd0SAchim Leubner if (i == 0) 2769*dce93cd0SAchim Leubner count = mir.MntRespCount; 2770*dce93cd0SAchim Leubner /* 2771*dce93cd0SAchim Leubner * Check the container against our list. 2772*dce93cd0SAchim Leubner * co->co_found was already set to 0 in a 2773*dce93cd0SAchim Leubner * previous run. 2774*dce93cd0SAchim Leubner */ 2775*dce93cd0SAchim Leubner if ((mir.Status == ST_OK) && 2776*dce93cd0SAchim Leubner (mir.MntTable[0].VolType != CT_NONE)) { 2777*dce93cd0SAchim Leubner found = 0; 2778*dce93cd0SAchim Leubner TAILQ_FOREACH(co, 2779*dce93cd0SAchim Leubner &sc->aac_container_tqh, 2780*dce93cd0SAchim Leubner co_link) { 2781*dce93cd0SAchim Leubner if (co->co_mntobj.ObjectId == 2782*dce93cd0SAchim Leubner mir.MntTable[0].ObjectId) { 2783*dce93cd0SAchim Leubner co->co_found = 1; 2784*dce93cd0SAchim Leubner found = 1; 2785*dce93cd0SAchim Leubner break; 2786*dce93cd0SAchim Leubner } 2787*dce93cd0SAchim Leubner } 2788*dce93cd0SAchim Leubner /* 2789*dce93cd0SAchim Leubner * If the container matched, continue 2790*dce93cd0SAchim Leubner * in the list. 2791*dce93cd0SAchim Leubner */ 2792*dce93cd0SAchim Leubner if (found) { 2793*dce93cd0SAchim Leubner i++; 2794*dce93cd0SAchim Leubner continue; 2795*dce93cd0SAchim Leubner } 2796*dce93cd0SAchim Leubner 2797*dce93cd0SAchim Leubner /* 2798*dce93cd0SAchim Leubner * This is a new container. Do all the 2799*dce93cd0SAchim Leubner * appropriate things to set it up. 2800*dce93cd0SAchim Leubner */ 2801*dce93cd0SAchim Leubner aac_add_container(sc, &mir, 1, uid); 2802*dce93cd0SAchim Leubner changed = 1; 2803*dce93cd0SAchim Leubner } 2804*dce93cd0SAchim Leubner i++; 2805*dce93cd0SAchim Leubner } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 2806*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 2807*dce93cd0SAchim Leubner 2808*dce93cd0SAchim Leubner /* 2809*dce93cd0SAchim Leubner * Go through our list of containers and see which ones 2810*dce93cd0SAchim Leubner * were not marked 'found'. Since the controller didn't 2811*dce93cd0SAchim Leubner * list them they must have been deleted. Do the 2812*dce93cd0SAchim Leubner * appropriate steps to destroy the device. Also reset 2813*dce93cd0SAchim Leubner * the co->co_found field. 2814*dce93cd0SAchim Leubner */ 2815*dce93cd0SAchim Leubner co = TAILQ_FIRST(&sc->aac_container_tqh); 2816*dce93cd0SAchim Leubner while (co != NULL) { 2817*dce93cd0SAchim Leubner if (co->co_found == 0) { 2818*dce93cd0SAchim Leubner co_next = TAILQ_NEXT(co, co_link); 2819*dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_container_tqh, co, 2820*dce93cd0SAchim Leubner co_link); 2821*dce93cd0SAchim Leubner free(co, M_AACRAIDBUF); 2822*dce93cd0SAchim Leubner changed = 1; 2823*dce93cd0SAchim Leubner co = co_next; 2824*dce93cd0SAchim Leubner } else { 2825*dce93cd0SAchim Leubner co->co_found = 0; 2826*dce93cd0SAchim Leubner co = TAILQ_NEXT(co, co_link); 2827*dce93cd0SAchim Leubner } 2828*dce93cd0SAchim Leubner } 2829*dce93cd0SAchim Leubner 2830*dce93cd0SAchim Leubner /* Attach the newly created containers */ 2831*dce93cd0SAchim Leubner if (changed) { 2832*dce93cd0SAchim Leubner if (sc->cam_rescan_cb != NULL) 2833*dce93cd0SAchim Leubner sc->cam_rescan_cb(sc, 0, 2834*dce93cd0SAchim Leubner AAC_CAM_TARGET_WILDCARD); 2835*dce93cd0SAchim Leubner } 2836*dce93cd0SAchim Leubner 2837*dce93cd0SAchim Leubner break; 2838*dce93cd0SAchim Leubner 2839*dce93cd0SAchim Leubner case AifEnEnclosureManagement: 2840*dce93cd0SAchim Leubner switch (aif->data.EN.data.EEE.eventType) { 2841*dce93cd0SAchim Leubner case AIF_EM_DRIVE_INSERTION: 2842*dce93cd0SAchim Leubner case AIF_EM_DRIVE_REMOVAL: 2843*dce93cd0SAchim Leubner channel = aif->data.EN.data.EEE.unitID; 2844*dce93cd0SAchim Leubner if (sc->cam_rescan_cb != NULL) 2845*dce93cd0SAchim Leubner sc->cam_rescan_cb(sc, 2846*dce93cd0SAchim Leubner ((channel>>24) & 0xF) + 1, 2847*dce93cd0SAchim Leubner (channel & 0xFFFF)); 2848*dce93cd0SAchim Leubner break; 2849*dce93cd0SAchim Leubner } 2850*dce93cd0SAchim Leubner break; 2851*dce93cd0SAchim Leubner 2852*dce93cd0SAchim Leubner case AifEnAddJBOD: 2853*dce93cd0SAchim Leubner case AifEnDeleteJBOD: 2854*dce93cd0SAchim Leubner case AifRawDeviceRemove: 2855*dce93cd0SAchim Leubner channel = aif->data.EN.data.ECE.container; 2856*dce93cd0SAchim Leubner if (sc->cam_rescan_cb != NULL) 2857*dce93cd0SAchim Leubner sc->cam_rescan_cb(sc, ((channel>>24) & 0xF) + 1, 2858*dce93cd0SAchim Leubner AAC_CAM_TARGET_WILDCARD); 2859*dce93cd0SAchim Leubner break; 2860*dce93cd0SAchim Leubner 2861*dce93cd0SAchim Leubner default: 2862*dce93cd0SAchim Leubner break; 2863*dce93cd0SAchim Leubner } 2864*dce93cd0SAchim Leubner 2865*dce93cd0SAchim Leubner default: 2866*dce93cd0SAchim Leubner break; 2867*dce93cd0SAchim Leubner } 2868*dce93cd0SAchim Leubner 2869*dce93cd0SAchim Leubner /* Copy the AIF data to the AIF queue for ioctl retrieval */ 2870*dce93cd0SAchim Leubner current = sc->aifq_idx; 2871*dce93cd0SAchim Leubner next = (current + 1) % AAC_AIFQ_LENGTH; 2872*dce93cd0SAchim Leubner if (next == 0) 2873*dce93cd0SAchim Leubner sc->aifq_filled = 1; 2874*dce93cd0SAchim Leubner bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 2875*dce93cd0SAchim Leubner /* modify AIF contexts */ 2876*dce93cd0SAchim Leubner if (sc->aifq_filled) { 2877*dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2878*dce93cd0SAchim Leubner if (next == ctx->ctx_idx) 2879*dce93cd0SAchim Leubner ctx->ctx_wrap = 1; 2880*dce93cd0SAchim Leubner else if (current == ctx->ctx_idx && ctx->ctx_wrap) 2881*dce93cd0SAchim Leubner ctx->ctx_idx = next; 2882*dce93cd0SAchim Leubner } 2883*dce93cd0SAchim Leubner } 2884*dce93cd0SAchim Leubner sc->aifq_idx = next; 2885*dce93cd0SAchim Leubner /* On the off chance that someone is sleeping for an aif... */ 2886*dce93cd0SAchim Leubner if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 2887*dce93cd0SAchim Leubner wakeup(sc->aac_aifq); 2888*dce93cd0SAchim Leubner /* Wakeup any poll()ers */ 2889*dce93cd0SAchim Leubner selwakeuppri(&sc->rcv_select, PRIBIO); 2890*dce93cd0SAchim Leubner 2891*dce93cd0SAchim Leubner return; 2892*dce93cd0SAchim Leubner } 2893*dce93cd0SAchim Leubner 2894*dce93cd0SAchim Leubner /* 2895*dce93cd0SAchim Leubner * Return the Revision of the driver to userspace and check to see if the 2896*dce93cd0SAchim Leubner * userspace app is possibly compatible. This is extremely bogus since 2897*dce93cd0SAchim Leubner * our driver doesn't follow Adaptec's versioning system. Cheat by just 2898*dce93cd0SAchim Leubner * returning what the card reported. 2899*dce93cd0SAchim Leubner */ 2900*dce93cd0SAchim Leubner static int 2901*dce93cd0SAchim Leubner aac_rev_check(struct aac_softc *sc, caddr_t udata) 2902*dce93cd0SAchim Leubner { 2903*dce93cd0SAchim Leubner struct aac_rev_check rev_check; 2904*dce93cd0SAchim Leubner struct aac_rev_check_resp rev_check_resp; 2905*dce93cd0SAchim Leubner int error = 0; 2906*dce93cd0SAchim Leubner 2907*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2908*dce93cd0SAchim Leubner 2909*dce93cd0SAchim Leubner /* 2910*dce93cd0SAchim Leubner * Copyin the revision struct from userspace 2911*dce93cd0SAchim Leubner */ 2912*dce93cd0SAchim Leubner if ((error = copyin(udata, (caddr_t)&rev_check, 2913*dce93cd0SAchim Leubner sizeof(struct aac_rev_check))) != 0) { 2914*dce93cd0SAchim Leubner return error; 2915*dce93cd0SAchim Leubner } 2916*dce93cd0SAchim Leubner 2917*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 2918*dce93cd0SAchim Leubner rev_check.callingRevision.buildNumber); 2919*dce93cd0SAchim Leubner 2920*dce93cd0SAchim Leubner /* 2921*dce93cd0SAchim Leubner * Doctor up the response struct. 2922*dce93cd0SAchim Leubner */ 2923*dce93cd0SAchim Leubner rev_check_resp.possiblyCompatible = 1; 2924*dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.major = 2925*dce93cd0SAchim Leubner AAC_DRIVER_MAJOR_VERSION; 2926*dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.minor = 2927*dce93cd0SAchim Leubner AAC_DRIVER_MINOR_VERSION; 2928*dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.type = 2929*dce93cd0SAchim Leubner AAC_DRIVER_TYPE; 2930*dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.dash = 2931*dce93cd0SAchim Leubner AAC_DRIVER_BUGFIX_LEVEL; 2932*dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.buildNumber = 2933*dce93cd0SAchim Leubner AAC_DRIVER_BUILD; 2934*dce93cd0SAchim Leubner 2935*dce93cd0SAchim Leubner return(copyout((caddr_t)&rev_check_resp, udata, 2936*dce93cd0SAchim Leubner sizeof(struct aac_rev_check_resp))); 2937*dce93cd0SAchim Leubner } 2938*dce93cd0SAchim Leubner 2939*dce93cd0SAchim Leubner /* 2940*dce93cd0SAchim Leubner * Pass the fib context to the caller 2941*dce93cd0SAchim Leubner */ 2942*dce93cd0SAchim Leubner static int 2943*dce93cd0SAchim Leubner aac_open_aif(struct aac_softc *sc, caddr_t arg) 2944*dce93cd0SAchim Leubner { 2945*dce93cd0SAchim Leubner struct aac_fib_context *fibctx, *ctx; 2946*dce93cd0SAchim Leubner int error = 0; 2947*dce93cd0SAchim Leubner 2948*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2949*dce93cd0SAchim Leubner 2950*dce93cd0SAchim Leubner fibctx = malloc(sizeof(struct aac_fib_context), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 2951*dce93cd0SAchim Leubner if (fibctx == NULL) 2952*dce93cd0SAchim Leubner return (ENOMEM); 2953*dce93cd0SAchim Leubner 2954*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2955*dce93cd0SAchim Leubner /* all elements are already 0, add to queue */ 2956*dce93cd0SAchim Leubner if (sc->fibctx == NULL) 2957*dce93cd0SAchim Leubner sc->fibctx = fibctx; 2958*dce93cd0SAchim Leubner else { 2959*dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 2960*dce93cd0SAchim Leubner ; 2961*dce93cd0SAchim Leubner ctx->next = fibctx; 2962*dce93cd0SAchim Leubner fibctx->prev = ctx; 2963*dce93cd0SAchim Leubner } 2964*dce93cd0SAchim Leubner 2965*dce93cd0SAchim Leubner /* evaluate unique value */ 2966*dce93cd0SAchim Leubner fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 2967*dce93cd0SAchim Leubner ctx = sc->fibctx; 2968*dce93cd0SAchim Leubner while (ctx != fibctx) { 2969*dce93cd0SAchim Leubner if (ctx->unique == fibctx->unique) { 2970*dce93cd0SAchim Leubner fibctx->unique++; 2971*dce93cd0SAchim Leubner ctx = sc->fibctx; 2972*dce93cd0SAchim Leubner } else { 2973*dce93cd0SAchim Leubner ctx = ctx->next; 2974*dce93cd0SAchim Leubner } 2975*dce93cd0SAchim Leubner } 2976*dce93cd0SAchim Leubner 2977*dce93cd0SAchim Leubner error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 2978*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2979*dce93cd0SAchim Leubner if (error) 2980*dce93cd0SAchim Leubner aac_close_aif(sc, (caddr_t)ctx); 2981*dce93cd0SAchim Leubner return error; 2982*dce93cd0SAchim Leubner } 2983*dce93cd0SAchim Leubner 2984*dce93cd0SAchim Leubner /* 2985*dce93cd0SAchim Leubner * Close the caller's fib context 2986*dce93cd0SAchim Leubner */ 2987*dce93cd0SAchim Leubner static int 2988*dce93cd0SAchim Leubner aac_close_aif(struct aac_softc *sc, caddr_t arg) 2989*dce93cd0SAchim Leubner { 2990*dce93cd0SAchim Leubner struct aac_fib_context *ctx; 2991*dce93cd0SAchim Leubner 2992*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2993*dce93cd0SAchim Leubner 2994*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2995*dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2996*dce93cd0SAchim Leubner if (ctx->unique == *(uint32_t *)&arg) { 2997*dce93cd0SAchim Leubner if (ctx == sc->fibctx) 2998*dce93cd0SAchim Leubner sc->fibctx = NULL; 2999*dce93cd0SAchim Leubner else { 3000*dce93cd0SAchim Leubner ctx->prev->next = ctx->next; 3001*dce93cd0SAchim Leubner if (ctx->next) 3002*dce93cd0SAchim Leubner ctx->next->prev = ctx->prev; 3003*dce93cd0SAchim Leubner } 3004*dce93cd0SAchim Leubner break; 3005*dce93cd0SAchim Leubner } 3006*dce93cd0SAchim Leubner } 3007*dce93cd0SAchim Leubner if (ctx) 3008*dce93cd0SAchim Leubner free(ctx, M_AACRAIDBUF); 3009*dce93cd0SAchim Leubner 3010*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3011*dce93cd0SAchim Leubner return 0; 3012*dce93cd0SAchim Leubner } 3013*dce93cd0SAchim Leubner 3014*dce93cd0SAchim Leubner /* 3015*dce93cd0SAchim Leubner * Pass the caller the next AIF in their queue 3016*dce93cd0SAchim Leubner */ 3017*dce93cd0SAchim Leubner static int 3018*dce93cd0SAchim Leubner aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 3019*dce93cd0SAchim Leubner { 3020*dce93cd0SAchim Leubner struct get_adapter_fib_ioctl agf; 3021*dce93cd0SAchim Leubner struct aac_fib_context *ctx; 3022*dce93cd0SAchim Leubner int error; 3023*dce93cd0SAchim Leubner 3024*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3025*dce93cd0SAchim Leubner 3026*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3027*dce93cd0SAchim Leubner if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3028*dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3029*dce93cd0SAchim Leubner if (agf.AdapterFibContext == ctx->unique) 3030*dce93cd0SAchim Leubner break; 3031*dce93cd0SAchim Leubner } 3032*dce93cd0SAchim Leubner if (!ctx) { 3033*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3034*dce93cd0SAchim Leubner return (EFAULT); 3035*dce93cd0SAchim Leubner } 3036*dce93cd0SAchim Leubner 3037*dce93cd0SAchim Leubner error = aac_return_aif(sc, ctx, agf.AifFib); 3038*dce93cd0SAchim Leubner if (error == EAGAIN && agf.Wait) { 3039*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 3040*dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_AIF_SLEEPER; 3041*dce93cd0SAchim Leubner while (error == EAGAIN) { 3042*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3043*dce93cd0SAchim Leubner error = tsleep(sc->aac_aifq, PRIBIO | 3044*dce93cd0SAchim Leubner PCATCH, "aacaif", 0); 3045*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3046*dce93cd0SAchim Leubner if (error == 0) 3047*dce93cd0SAchim Leubner error = aac_return_aif(sc, ctx, agf.AifFib); 3048*dce93cd0SAchim Leubner } 3049*dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 3050*dce93cd0SAchim Leubner } 3051*dce93cd0SAchim Leubner } 3052*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3053*dce93cd0SAchim Leubner return(error); 3054*dce93cd0SAchim Leubner } 3055*dce93cd0SAchim Leubner 3056*dce93cd0SAchim Leubner /* 3057*dce93cd0SAchim Leubner * Hand the next AIF off the top of the queue out to userspace. 3058*dce93cd0SAchim Leubner */ 3059*dce93cd0SAchim Leubner static int 3060*dce93cd0SAchim Leubner aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 3061*dce93cd0SAchim Leubner { 3062*dce93cd0SAchim Leubner int current, error; 3063*dce93cd0SAchim Leubner 3064*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3065*dce93cd0SAchim Leubner 3066*dce93cd0SAchim Leubner current = ctx->ctx_idx; 3067*dce93cd0SAchim Leubner if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3068*dce93cd0SAchim Leubner /* empty */ 3069*dce93cd0SAchim Leubner return (EAGAIN); 3070*dce93cd0SAchim Leubner } 3071*dce93cd0SAchim Leubner error = 3072*dce93cd0SAchim Leubner copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 3073*dce93cd0SAchim Leubner if (error) 3074*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3075*dce93cd0SAchim Leubner "aac_return_aif: copyout returned %d\n", error); 3076*dce93cd0SAchim Leubner else { 3077*dce93cd0SAchim Leubner ctx->ctx_wrap = 0; 3078*dce93cd0SAchim Leubner ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3079*dce93cd0SAchim Leubner } 3080*dce93cd0SAchim Leubner return(error); 3081*dce93cd0SAchim Leubner } 3082*dce93cd0SAchim Leubner 3083*dce93cd0SAchim Leubner static int 3084*dce93cd0SAchim Leubner aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3085*dce93cd0SAchim Leubner { 3086*dce93cd0SAchim Leubner struct aac_pci_info { 3087*dce93cd0SAchim Leubner u_int32_t bus; 3088*dce93cd0SAchim Leubner u_int32_t slot; 3089*dce93cd0SAchim Leubner } pciinf; 3090*dce93cd0SAchim Leubner int error; 3091*dce93cd0SAchim Leubner 3092*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3093*dce93cd0SAchim Leubner 3094*dce93cd0SAchim Leubner pciinf.bus = pci_get_bus(sc->aac_dev); 3095*dce93cd0SAchim Leubner pciinf.slot = pci_get_slot(sc->aac_dev); 3096*dce93cd0SAchim Leubner 3097*dce93cd0SAchim Leubner error = copyout((caddr_t)&pciinf, uptr, 3098*dce93cd0SAchim Leubner sizeof(struct aac_pci_info)); 3099*dce93cd0SAchim Leubner 3100*dce93cd0SAchim Leubner return (error); 3101*dce93cd0SAchim Leubner } 3102*dce93cd0SAchim Leubner 3103*dce93cd0SAchim Leubner static int 3104*dce93cd0SAchim Leubner aac_supported_features(struct aac_softc *sc, caddr_t uptr) 3105*dce93cd0SAchim Leubner { 3106*dce93cd0SAchim Leubner struct aac_features f; 3107*dce93cd0SAchim Leubner int error; 3108*dce93cd0SAchim Leubner 3109*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3110*dce93cd0SAchim Leubner 3111*dce93cd0SAchim Leubner if ((error = copyin(uptr, &f, sizeof (f))) != 0) 3112*dce93cd0SAchim Leubner return (error); 3113*dce93cd0SAchim Leubner 3114*dce93cd0SAchim Leubner /* 3115*dce93cd0SAchim Leubner * When the management driver receives FSACTL_GET_FEATURES ioctl with 3116*dce93cd0SAchim Leubner * ALL zero in the featuresState, the driver will return the current 3117*dce93cd0SAchim Leubner * state of all the supported features, the data field will not be 3118*dce93cd0SAchim Leubner * valid. 3119*dce93cd0SAchim Leubner * When the management driver receives FSACTL_GET_FEATURES ioctl with 3120*dce93cd0SAchim Leubner * a specific bit set in the featuresState, the driver will return the 3121*dce93cd0SAchim Leubner * current state of this specific feature and whatever data that are 3122*dce93cd0SAchim Leubner * associated with the feature in the data field or perform whatever 3123*dce93cd0SAchim Leubner * action needed indicates in the data field. 3124*dce93cd0SAchim Leubner */ 3125*dce93cd0SAchim Leubner if (f.feat.fValue == 0) { 3126*dce93cd0SAchim Leubner f.feat.fBits.largeLBA = 3127*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3128*dce93cd0SAchim Leubner f.feat.fBits.JBODSupport = 1; 3129*dce93cd0SAchim Leubner /* TODO: In the future, add other features state here as well */ 3130*dce93cd0SAchim Leubner } else { 3131*dce93cd0SAchim Leubner if (f.feat.fBits.largeLBA) 3132*dce93cd0SAchim Leubner f.feat.fBits.largeLBA = 3133*dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3134*dce93cd0SAchim Leubner /* TODO: Add other features state and data in the future */ 3135*dce93cd0SAchim Leubner } 3136*dce93cd0SAchim Leubner 3137*dce93cd0SAchim Leubner error = copyout(&f, uptr, sizeof (f)); 3138*dce93cd0SAchim Leubner return (error); 3139*dce93cd0SAchim Leubner } 3140*dce93cd0SAchim Leubner 3141*dce93cd0SAchim Leubner /* 3142*dce93cd0SAchim Leubner * Give the userland some information about the container. The AAC arch 3143*dce93cd0SAchim Leubner * expects the driver to be a SCSI passthrough type driver, so it expects 3144*dce93cd0SAchim Leubner * the containers to have b:t:l numbers. Fake it. 3145*dce93cd0SAchim Leubner */ 3146*dce93cd0SAchim Leubner static int 3147*dce93cd0SAchim Leubner aac_query_disk(struct aac_softc *sc, caddr_t uptr) 3148*dce93cd0SAchim Leubner { 3149*dce93cd0SAchim Leubner struct aac_query_disk query_disk; 3150*dce93cd0SAchim Leubner struct aac_container *co; 3151*dce93cd0SAchim Leubner int error, id; 3152*dce93cd0SAchim Leubner 3153*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3154*dce93cd0SAchim Leubner 3155*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3156*dce93cd0SAchim Leubner error = copyin(uptr, (caddr_t)&query_disk, 3157*dce93cd0SAchim Leubner sizeof(struct aac_query_disk)); 3158*dce93cd0SAchim Leubner if (error) { 3159*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3160*dce93cd0SAchim Leubner return (error); 3161*dce93cd0SAchim Leubner } 3162*dce93cd0SAchim Leubner 3163*dce93cd0SAchim Leubner id = query_disk.ContainerNumber; 3164*dce93cd0SAchim Leubner if (id == -1) { 3165*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3166*dce93cd0SAchim Leubner return (EINVAL); 3167*dce93cd0SAchim Leubner } 3168*dce93cd0SAchim Leubner 3169*dce93cd0SAchim Leubner TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 3170*dce93cd0SAchim Leubner if (co->co_mntobj.ObjectId == id) 3171*dce93cd0SAchim Leubner break; 3172*dce93cd0SAchim Leubner } 3173*dce93cd0SAchim Leubner 3174*dce93cd0SAchim Leubner if (co == NULL) { 3175*dce93cd0SAchim Leubner query_disk.Valid = 0; 3176*dce93cd0SAchim Leubner query_disk.Locked = 0; 3177*dce93cd0SAchim Leubner query_disk.Deleted = 1; /* XXX is this right? */ 3178*dce93cd0SAchim Leubner } else { 3179*dce93cd0SAchim Leubner query_disk.Valid = 1; 3180*dce93cd0SAchim Leubner query_disk.Locked = 1; 3181*dce93cd0SAchim Leubner query_disk.Deleted = 0; 3182*dce93cd0SAchim Leubner query_disk.Bus = device_get_unit(sc->aac_dev); 3183*dce93cd0SAchim Leubner query_disk.Target = 0; 3184*dce93cd0SAchim Leubner query_disk.Lun = 0; 3185*dce93cd0SAchim Leubner query_disk.UnMapped = 0; 3186*dce93cd0SAchim Leubner } 3187*dce93cd0SAchim Leubner 3188*dce93cd0SAchim Leubner error = copyout((caddr_t)&query_disk, uptr, 3189*dce93cd0SAchim Leubner sizeof(struct aac_query_disk)); 3190*dce93cd0SAchim Leubner 3191*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3192*dce93cd0SAchim Leubner return (error); 3193*dce93cd0SAchim Leubner } 3194*dce93cd0SAchim Leubner 3195*dce93cd0SAchim Leubner static void 3196*dce93cd0SAchim Leubner aac_container_bus(struct aac_softc *sc) 3197*dce93cd0SAchim Leubner { 3198*dce93cd0SAchim Leubner struct aac_sim *sim; 3199*dce93cd0SAchim Leubner device_t child; 3200*dce93cd0SAchim Leubner 3201*dce93cd0SAchim Leubner sim =(struct aac_sim *)malloc(sizeof(struct aac_sim), 3202*dce93cd0SAchim Leubner M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3203*dce93cd0SAchim Leubner if (sim == NULL) { 3204*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3205*dce93cd0SAchim Leubner "No memory to add container bus\n"); 3206*dce93cd0SAchim Leubner panic("Out of memory?!"); 3207*dce93cd0SAchim Leubner }; 3208*dce93cd0SAchim Leubner child = device_add_child(sc->aac_dev, "aacraidp", -1); 3209*dce93cd0SAchim Leubner if (child == NULL) { 3210*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3211*dce93cd0SAchim Leubner "device_add_child failed for container bus\n"); 3212*dce93cd0SAchim Leubner free(sim, M_AACRAIDBUF); 3213*dce93cd0SAchim Leubner panic("Out of memory?!"); 3214*dce93cd0SAchim Leubner } 3215*dce93cd0SAchim Leubner 3216*dce93cd0SAchim Leubner sim->TargetsPerBus = AAC_MAX_CONTAINERS; 3217*dce93cd0SAchim Leubner sim->BusNumber = 0; 3218*dce93cd0SAchim Leubner sim->BusType = CONTAINER_BUS; 3219*dce93cd0SAchim Leubner sim->InitiatorBusId = -1; 3220*dce93cd0SAchim Leubner sim->aac_sc = sc; 3221*dce93cd0SAchim Leubner sim->sim_dev = child; 3222*dce93cd0SAchim Leubner sim->aac_cam = NULL; 3223*dce93cd0SAchim Leubner 3224*dce93cd0SAchim Leubner device_set_ivars(child, sim); 3225*dce93cd0SAchim Leubner device_set_desc(child, "Container Bus"); 3226*dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, sim, sim_link); 3227*dce93cd0SAchim Leubner /* 3228*dce93cd0SAchim Leubner device_set_desc(child, aac_describe_code(aac_container_types, 3229*dce93cd0SAchim Leubner mir->MntTable[0].VolType)); 3230*dce93cd0SAchim Leubner */ 3231*dce93cd0SAchim Leubner bus_generic_attach(sc->aac_dev); 3232*dce93cd0SAchim Leubner } 3233*dce93cd0SAchim Leubner 3234*dce93cd0SAchim Leubner static void 3235*dce93cd0SAchim Leubner aac_get_bus_info(struct aac_softc *sc) 3236*dce93cd0SAchim Leubner { 3237*dce93cd0SAchim Leubner struct aac_fib *fib; 3238*dce93cd0SAchim Leubner struct aac_ctcfg *c_cmd; 3239*dce93cd0SAchim Leubner struct aac_ctcfg_resp *c_resp; 3240*dce93cd0SAchim Leubner struct aac_vmioctl *vmi; 3241*dce93cd0SAchim Leubner struct aac_vmi_businf_resp *vmi_resp; 3242*dce93cd0SAchim Leubner struct aac_getbusinf businfo; 3243*dce93cd0SAchim Leubner struct aac_sim *caminf; 3244*dce93cd0SAchim Leubner device_t child; 3245*dce93cd0SAchim Leubner int i, error; 3246*dce93cd0SAchim Leubner 3247*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3248*dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 3249*dce93cd0SAchim Leubner c_cmd = (struct aac_ctcfg *)&fib->data[0]; 3250*dce93cd0SAchim Leubner bzero(c_cmd, sizeof(struct aac_ctcfg)); 3251*dce93cd0SAchim Leubner 3252*dce93cd0SAchim Leubner c_cmd->Command = VM_ContainerConfig; 3253*dce93cd0SAchim Leubner c_cmd->cmd = CT_GET_SCSI_METHOD; 3254*dce93cd0SAchim Leubner c_cmd->param = 0; 3255*dce93cd0SAchim Leubner 3256*dce93cd0SAchim Leubner error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3257*dce93cd0SAchim Leubner sizeof(struct aac_ctcfg)); 3258*dce93cd0SAchim Leubner if (error) { 3259*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error %d sending " 3260*dce93cd0SAchim Leubner "VM_ContainerConfig command\n", error); 3261*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3262*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3263*dce93cd0SAchim Leubner return; 3264*dce93cd0SAchim Leubner } 3265*dce93cd0SAchim Leubner 3266*dce93cd0SAchim Leubner c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3267*dce93cd0SAchim Leubner if (c_resp->Status != ST_OK) { 3268*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3269*dce93cd0SAchim Leubner c_resp->Status); 3270*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3271*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3272*dce93cd0SAchim Leubner return; 3273*dce93cd0SAchim Leubner } 3274*dce93cd0SAchim Leubner 3275*dce93cd0SAchim Leubner sc->scsi_method_id = c_resp->param; 3276*dce93cd0SAchim Leubner 3277*dce93cd0SAchim Leubner vmi = (struct aac_vmioctl *)&fib->data[0]; 3278*dce93cd0SAchim Leubner bzero(vmi, sizeof(struct aac_vmioctl)); 3279*dce93cd0SAchim Leubner 3280*dce93cd0SAchim Leubner vmi->Command = VM_Ioctl; 3281*dce93cd0SAchim Leubner vmi->ObjType = FT_DRIVE; 3282*dce93cd0SAchim Leubner vmi->MethId = sc->scsi_method_id; 3283*dce93cd0SAchim Leubner vmi->ObjId = 0; 3284*dce93cd0SAchim Leubner vmi->IoctlCmd = GetBusInfo; 3285*dce93cd0SAchim Leubner 3286*dce93cd0SAchim Leubner error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3287*dce93cd0SAchim Leubner sizeof(struct aac_vmi_businf_resp)); 3288*dce93cd0SAchim Leubner if (error) { 3289*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3290*dce93cd0SAchim Leubner error); 3291*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3292*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3293*dce93cd0SAchim Leubner return; 3294*dce93cd0SAchim Leubner } 3295*dce93cd0SAchim Leubner 3296*dce93cd0SAchim Leubner vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3297*dce93cd0SAchim Leubner if (vmi_resp->Status != ST_OK) { 3298*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3299*dce93cd0SAchim Leubner vmi_resp->Status); 3300*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3301*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3302*dce93cd0SAchim Leubner return; 3303*dce93cd0SAchim Leubner } 3304*dce93cd0SAchim Leubner 3305*dce93cd0SAchim Leubner bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3306*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3307*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3308*dce93cd0SAchim Leubner 3309*dce93cd0SAchim Leubner for (i = 0; i < businfo.BusCount; i++) { 3310*dce93cd0SAchim Leubner if (businfo.BusValid[i] != AAC_BUS_VALID) 3311*dce93cd0SAchim Leubner continue; 3312*dce93cd0SAchim Leubner 3313*dce93cd0SAchim Leubner caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3314*dce93cd0SAchim Leubner M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3315*dce93cd0SAchim Leubner if (caminf == NULL) { 3316*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3317*dce93cd0SAchim Leubner "No memory to add passthrough bus %d\n", i); 3318*dce93cd0SAchim Leubner break; 3319*dce93cd0SAchim Leubner }; 3320*dce93cd0SAchim Leubner 3321*dce93cd0SAchim Leubner child = device_add_child(sc->aac_dev, "aacraidp", -1); 3322*dce93cd0SAchim Leubner if (child == NULL) { 3323*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3324*dce93cd0SAchim Leubner "device_add_child failed for passthrough bus %d\n", 3325*dce93cd0SAchim Leubner i); 3326*dce93cd0SAchim Leubner free(caminf, M_AACRAIDBUF); 3327*dce93cd0SAchim Leubner break; 3328*dce93cd0SAchim Leubner } 3329*dce93cd0SAchim Leubner 3330*dce93cd0SAchim Leubner caminf->TargetsPerBus = businfo.TargetsPerBus; 3331*dce93cd0SAchim Leubner caminf->BusNumber = i+1; 3332*dce93cd0SAchim Leubner caminf->BusType = PASSTHROUGH_BUS; 3333*dce93cd0SAchim Leubner caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3334*dce93cd0SAchim Leubner caminf->aac_sc = sc; 3335*dce93cd0SAchim Leubner caminf->sim_dev = child; 3336*dce93cd0SAchim Leubner caminf->aac_cam = NULL; 3337*dce93cd0SAchim Leubner 3338*dce93cd0SAchim Leubner device_set_ivars(child, caminf); 3339*dce93cd0SAchim Leubner device_set_desc(child, "SCSI Passthrough Bus"); 3340*dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3341*dce93cd0SAchim Leubner } 3342*dce93cd0SAchim Leubner } 3343*dce93cd0SAchim Leubner 3344*dce93cd0SAchim Leubner /* 3345*dce93cd0SAchim Leubner * Check to see if the kernel is up and running. If we are in a 3346*dce93cd0SAchim Leubner * BlinkLED state, return the BlinkLED code. 3347*dce93cd0SAchim Leubner */ 3348*dce93cd0SAchim Leubner static u_int32_t 3349*dce93cd0SAchim Leubner aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled) 3350*dce93cd0SAchim Leubner { 3351*dce93cd0SAchim Leubner u_int32_t ret; 3352*dce93cd0SAchim Leubner 3353*dce93cd0SAchim Leubner ret = AAC_GET_FWSTATUS(sc); 3354*dce93cd0SAchim Leubner 3355*dce93cd0SAchim Leubner if (ret & AAC_UP_AND_RUNNING) 3356*dce93cd0SAchim Leubner ret = 0; 3357*dce93cd0SAchim Leubner else if (ret & AAC_KERNEL_PANIC && bled) 3358*dce93cd0SAchim Leubner *bled = (ret >> 16) & 0xff; 3359*dce93cd0SAchim Leubner 3360*dce93cd0SAchim Leubner return (ret); 3361*dce93cd0SAchim Leubner } 3362*dce93cd0SAchim Leubner 3363*dce93cd0SAchim Leubner /* 3364*dce93cd0SAchim Leubner * Once do an IOP reset, basically have to re-initialize the card as 3365*dce93cd0SAchim Leubner * if coming up from a cold boot, and the driver is responsible for 3366*dce93cd0SAchim Leubner * any IO that was outstanding to the adapter at the time of the IOP 3367*dce93cd0SAchim Leubner * RESET. And prepare the driver for IOP RESET by making the init code 3368*dce93cd0SAchim Leubner * modular with the ability to call it from multiple places. 3369*dce93cd0SAchim Leubner */ 3370*dce93cd0SAchim Leubner static int 3371*dce93cd0SAchim Leubner aac_reset_adapter(struct aac_softc *sc) 3372*dce93cd0SAchim Leubner { 3373*dce93cd0SAchim Leubner struct aac_command *cm; 3374*dce93cd0SAchim Leubner struct aac_fib *fib; 3375*dce93cd0SAchim Leubner struct aac_pause_command *pc; 3376*dce93cd0SAchim Leubner u_int32_t status, old_flags, reset_mask, waitCount; 3377*dce93cd0SAchim Leubner 3378*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3379*dce93cd0SAchim Leubner 3380*dce93cd0SAchim Leubner if (sc->aac_state & AAC_STATE_RESET) { 3381*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "aac_reset_adapter() already in progress\n"); 3382*dce93cd0SAchim Leubner return (EINVAL); 3383*dce93cd0SAchim Leubner } 3384*dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_RESET; 3385*dce93cd0SAchim Leubner 3386*dce93cd0SAchim Leubner /* disable interrupt */ 3387*dce93cd0SAchim Leubner AAC_MASK_INTERRUPTS(sc); 3388*dce93cd0SAchim Leubner 3389*dce93cd0SAchim Leubner /* 3390*dce93cd0SAchim Leubner * Abort all pending commands: 3391*dce93cd0SAchim Leubner * a) on the controller 3392*dce93cd0SAchim Leubner */ 3393*dce93cd0SAchim Leubner while ((cm = aac_dequeue_busy(sc)) != NULL) { 3394*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_RESET; 3395*dce93cd0SAchim Leubner 3396*dce93cd0SAchim Leubner /* is there a completion handler? */ 3397*dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 3398*dce93cd0SAchim Leubner cm->cm_complete(cm); 3399*dce93cd0SAchim Leubner } else { 3400*dce93cd0SAchim Leubner /* assume that someone is sleeping on this 3401*dce93cd0SAchim Leubner * command 3402*dce93cd0SAchim Leubner */ 3403*dce93cd0SAchim Leubner wakeup(cm); 3404*dce93cd0SAchim Leubner } 3405*dce93cd0SAchim Leubner } 3406*dce93cd0SAchim Leubner 3407*dce93cd0SAchim Leubner /* b) in the waiting queues */ 3408*dce93cd0SAchim Leubner while ((cm = aac_dequeue_ready(sc)) != NULL) { 3409*dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_RESET; 3410*dce93cd0SAchim Leubner 3411*dce93cd0SAchim Leubner /* is there a completion handler? */ 3412*dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 3413*dce93cd0SAchim Leubner cm->cm_complete(cm); 3414*dce93cd0SAchim Leubner } else { 3415*dce93cd0SAchim Leubner /* assume that someone is sleeping on this 3416*dce93cd0SAchim Leubner * command 3417*dce93cd0SAchim Leubner */ 3418*dce93cd0SAchim Leubner wakeup(cm); 3419*dce93cd0SAchim Leubner } 3420*dce93cd0SAchim Leubner } 3421*dce93cd0SAchim Leubner 3422*dce93cd0SAchim Leubner /* flush drives */ 3423*dce93cd0SAchim Leubner if (aac_check_adapter_health(sc, NULL) == 0) { 3424*dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3425*dce93cd0SAchim Leubner (void) aacraid_shutdown(sc->aac_dev); 3426*dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3427*dce93cd0SAchim Leubner } 3428*dce93cd0SAchim Leubner 3429*dce93cd0SAchim Leubner /* execute IOP reset */ 3430*dce93cd0SAchim Leubner if (sc->aac_support_opt2 & AAC_SUPPORTED_MU_RESET) { 3431*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_IRCSR, AAC_IRCSR_CORES_RST); 3432*dce93cd0SAchim Leubner 3433*dce93cd0SAchim Leubner /* We need to wait for 5 seconds before accessing the MU again 3434*dce93cd0SAchim Leubner * 10000 * 100us = 1000,000us = 1000ms = 1s 3435*dce93cd0SAchim Leubner */ 3436*dce93cd0SAchim Leubner waitCount = 5 * 10000; 3437*dce93cd0SAchim Leubner while (waitCount) { 3438*dce93cd0SAchim Leubner DELAY(100); /* delay 100 microseconds */ 3439*dce93cd0SAchim Leubner waitCount--; 3440*dce93cd0SAchim Leubner } 3441*dce93cd0SAchim Leubner } else if ((aacraid_sync_command(sc, 3442*dce93cd0SAchim Leubner AAC_IOP_RESET_ALWAYS, 0, 0, 0, 0, &status, &reset_mask)) != 0) { 3443*dce93cd0SAchim Leubner /* call IOP_RESET for older firmware */ 3444*dce93cd0SAchim Leubner if ((aacraid_sync_command(sc, 3445*dce93cd0SAchim Leubner AAC_IOP_RESET, 0, 0, 0, 0, &status, NULL)) != 0) { 3446*dce93cd0SAchim Leubner 3447*dce93cd0SAchim Leubner if (status == AAC_SRB_STS_INVALID_REQUEST) 3448*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "IOP_RESET not supported\n"); 3449*dce93cd0SAchim Leubner else 3450*dce93cd0SAchim Leubner /* probably timeout */ 3451*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "IOP_RESET failed\n"); 3452*dce93cd0SAchim Leubner 3453*dce93cd0SAchim Leubner /* unwind aac_shutdown() */ 3454*dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 3455*dce93cd0SAchim Leubner pc = (struct aac_pause_command *)&fib->data[0]; 3456*dce93cd0SAchim Leubner pc->Command = VM_ContainerConfig; 3457*dce93cd0SAchim Leubner pc->Type = CT_PAUSE_IO; 3458*dce93cd0SAchim Leubner pc->Timeout = 1; 3459*dce93cd0SAchim Leubner pc->Min = 1; 3460*dce93cd0SAchim Leubner pc->NoRescan = 1; 3461*dce93cd0SAchim Leubner 3462*dce93cd0SAchim Leubner (void) aac_sync_fib(sc, ContainerCommand, 0, fib, 3463*dce93cd0SAchim Leubner sizeof (struct aac_pause_command)); 3464*dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3465*dce93cd0SAchim Leubner 3466*dce93cd0SAchim Leubner goto finish; 3467*dce93cd0SAchim Leubner } 3468*dce93cd0SAchim Leubner } else if (sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET) { 3469*dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask); 3470*dce93cd0SAchim Leubner /* We need to wait for 5 seconds before accessing the doorbell again 3471*dce93cd0SAchim Leubner * 10000 * 100us = 1000,000us = 1000ms = 1s 3472*dce93cd0SAchim Leubner */ 3473*dce93cd0SAchim Leubner waitCount = 5 * 10000; 3474*dce93cd0SAchim Leubner while (waitCount) { 3475*dce93cd0SAchim Leubner DELAY(100); /* delay 100 microseconds */ 3476*dce93cd0SAchim Leubner waitCount--; 3477*dce93cd0SAchim Leubner } 3478*dce93cd0SAchim Leubner } 3479*dce93cd0SAchim Leubner 3480*dce93cd0SAchim Leubner /* 3481*dce93cd0SAchim Leubner * Re-read and renegotiate the FIB parameters, as one of the actions 3482*dce93cd0SAchim Leubner * that can result from an IOP reset is the running of a new firmware 3483*dce93cd0SAchim Leubner * image. 3484*dce93cd0SAchim Leubner */ 3485*dce93cd0SAchim Leubner old_flags = sc->flags; 3486*dce93cd0SAchim Leubner /* 3487*dce93cd0SAchim Leubner * Initialize the adapter. 3488*dce93cd0SAchim Leubner */ 3489*dce93cd0SAchim Leubner if (aac_check_firmware(sc) != 0) 3490*dce93cd0SAchim Leubner goto finish; 3491*dce93cd0SAchim Leubner if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 3492*dce93cd0SAchim Leubner if (aac_init(sc) != 0) 3493*dce93cd0SAchim Leubner goto finish; 3494*dce93cd0SAchim Leubner } 3495*dce93cd0SAchim Leubner 3496*dce93cd0SAchim Leubner finish: 3497*dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_RESET; 3498*dce93cd0SAchim Leubner AAC_UNMASK_INTERRUPTS(sc); 3499*dce93cd0SAchim Leubner aacraid_startio(sc); 3500*dce93cd0SAchim Leubner return (0); 3501*dce93cd0SAchim Leubner } 3502