1dce93cd0SAchim Leubner /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*718cf2ccSPedro F. Giffuni * 4dce93cd0SAchim Leubner * Copyright (c) 2000 Michael Smith 5dce93cd0SAchim Leubner * Copyright (c) 2001 Scott Long 6dce93cd0SAchim Leubner * Copyright (c) 2000 BSDi 7dce93cd0SAchim Leubner * Copyright (c) 2001-2010 Adaptec, Inc. 8dce93cd0SAchim Leubner * Copyright (c) 2010-2012 PMC-Sierra, Inc. 9dce93cd0SAchim Leubner * All rights reserved. 10dce93cd0SAchim Leubner * 11dce93cd0SAchim Leubner * Redistribution and use in source and binary forms, with or without 12dce93cd0SAchim Leubner * modification, are permitted provided that the following conditions 13dce93cd0SAchim Leubner * are met: 14dce93cd0SAchim Leubner * 1. Redistributions of source code must retain the above copyright 15dce93cd0SAchim Leubner * notice, this list of conditions and the following disclaimer. 16dce93cd0SAchim Leubner * 2. Redistributions in binary form must reproduce the above copyright 17dce93cd0SAchim Leubner * notice, this list of conditions and the following disclaimer in the 18dce93cd0SAchim Leubner * documentation and/or other materials provided with the distribution. 19dce93cd0SAchim Leubner * 20dce93cd0SAchim Leubner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21dce93cd0SAchim Leubner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22dce93cd0SAchim Leubner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23dce93cd0SAchim Leubner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24dce93cd0SAchim Leubner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25dce93cd0SAchim Leubner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26dce93cd0SAchim Leubner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27dce93cd0SAchim Leubner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28dce93cd0SAchim Leubner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29dce93cd0SAchim Leubner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30dce93cd0SAchim Leubner * SUCH DAMAGE. 31dce93cd0SAchim Leubner */ 32dce93cd0SAchim Leubner 33dce93cd0SAchim Leubner #include <sys/cdefs.h> 34dce93cd0SAchim Leubner __FBSDID("$FreeBSD$"); 35dce93cd0SAchim Leubner 36dce93cd0SAchim Leubner /* 37dce93cd0SAchim Leubner * Driver for the Adaptec by PMC Series 6,7,8,... families of RAID controllers 38dce93cd0SAchim Leubner */ 39dce93cd0SAchim Leubner #define AAC_DRIVERNAME "aacraid" 40dce93cd0SAchim Leubner 41dce93cd0SAchim Leubner #include "opt_aacraid.h" 42dce93cd0SAchim Leubner 43dce93cd0SAchim Leubner /* #include <stddef.h> */ 44dce93cd0SAchim Leubner #include <sys/param.h> 45dce93cd0SAchim Leubner #include <sys/systm.h> 46dce93cd0SAchim Leubner #include <sys/malloc.h> 47dce93cd0SAchim Leubner #include <sys/kernel.h> 48dce93cd0SAchim Leubner #include <sys/kthread.h> 49dce93cd0SAchim Leubner #include <sys/sysctl.h> 50dce93cd0SAchim Leubner #include <sys/poll.h> 51dce93cd0SAchim Leubner #include <sys/ioccom.h> 52dce93cd0SAchim Leubner 53dce93cd0SAchim Leubner #include <sys/bus.h> 54dce93cd0SAchim Leubner #include <sys/conf.h> 55dce93cd0SAchim Leubner #include <sys/signalvar.h> 56dce93cd0SAchim Leubner #include <sys/time.h> 57dce93cd0SAchim Leubner #include <sys/eventhandler.h> 58dce93cd0SAchim Leubner #include <sys/rman.h> 59dce93cd0SAchim Leubner 60dce93cd0SAchim Leubner #include <machine/bus.h> 61dce93cd0SAchim Leubner #include <machine/resource.h> 62dce93cd0SAchim Leubner 63dce93cd0SAchim Leubner #include <dev/pci/pcireg.h> 64dce93cd0SAchim Leubner #include <dev/pci/pcivar.h> 65dce93cd0SAchim Leubner 66dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_reg.h> 67dce93cd0SAchim Leubner #include <sys/aac_ioctl.h> 68dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_debug.h> 69dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_var.h> 70dce93cd0SAchim Leubner 71dce93cd0SAchim Leubner #ifndef FILTER_HANDLED 72dce93cd0SAchim Leubner #define FILTER_HANDLED 0x02 73dce93cd0SAchim Leubner #endif 74dce93cd0SAchim Leubner 75dce93cd0SAchim Leubner static void aac_add_container(struct aac_softc *sc, 76dce93cd0SAchim Leubner struct aac_mntinforesp *mir, int f, 77dce93cd0SAchim Leubner u_int32_t uid); 78dce93cd0SAchim Leubner static void aac_get_bus_info(struct aac_softc *sc); 79dce93cd0SAchim Leubner static void aac_container_bus(struct aac_softc *sc); 80dce93cd0SAchim Leubner static void aac_daemon(void *arg); 81dce93cd0SAchim Leubner static int aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 82dce93cd0SAchim Leubner int pages, int nseg, int nseg_new); 83dce93cd0SAchim Leubner 84dce93cd0SAchim Leubner /* Command Processing */ 85dce93cd0SAchim Leubner static void aac_timeout(struct aac_softc *sc); 86dce93cd0SAchim Leubner static void aac_command_thread(struct aac_softc *sc); 87dce93cd0SAchim Leubner static int aac_sync_fib(struct aac_softc *sc, u_int32_t command, 88dce93cd0SAchim Leubner u_int32_t xferstate, struct aac_fib *fib, 89dce93cd0SAchim Leubner u_int16_t datasize); 90dce93cd0SAchim Leubner /* Command Buffer Management */ 91dce93cd0SAchim Leubner static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 92dce93cd0SAchim Leubner int nseg, int error); 93dce93cd0SAchim Leubner static int aac_alloc_commands(struct aac_softc *sc); 94dce93cd0SAchim Leubner static void aac_free_commands(struct aac_softc *sc); 95dce93cd0SAchim Leubner static void aac_unmap_command(struct aac_command *cm); 96dce93cd0SAchim Leubner 97dce93cd0SAchim Leubner /* Hardware Interface */ 98dce93cd0SAchim Leubner static int aac_alloc(struct aac_softc *sc); 99dce93cd0SAchim Leubner static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 100dce93cd0SAchim Leubner int error); 101dce93cd0SAchim Leubner static int aac_check_firmware(struct aac_softc *sc); 1023fea9c0dSAchim Leubner static void aac_define_int_mode(struct aac_softc *sc); 103dce93cd0SAchim Leubner static int aac_init(struct aac_softc *sc); 1043fea9c0dSAchim Leubner static int aac_find_pci_capability(struct aac_softc *sc, int cap); 105dce93cd0SAchim Leubner static int aac_setup_intr(struct aac_softc *sc); 1063fea9c0dSAchim Leubner static int aac_check_config(struct aac_softc *sc); 107dce93cd0SAchim Leubner 108dce93cd0SAchim Leubner /* PMC SRC interface */ 109dce93cd0SAchim Leubner static int aac_src_get_fwstatus(struct aac_softc *sc); 110dce93cd0SAchim Leubner static void aac_src_qnotify(struct aac_softc *sc, int qbit); 111dce93cd0SAchim Leubner static int aac_src_get_istatus(struct aac_softc *sc); 112dce93cd0SAchim Leubner static void aac_src_clear_istatus(struct aac_softc *sc, int mask); 113dce93cd0SAchim Leubner static void aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, 114dce93cd0SAchim Leubner u_int32_t arg0, u_int32_t arg1, 115dce93cd0SAchim Leubner u_int32_t arg2, u_int32_t arg3); 116dce93cd0SAchim Leubner static int aac_src_get_mailbox(struct aac_softc *sc, int mb); 1173fea9c0dSAchim Leubner static void aac_src_access_devreg(struct aac_softc *sc, int mode); 118dce93cd0SAchim Leubner static int aac_src_send_command(struct aac_softc *sc, struct aac_command *cm); 119dce93cd0SAchim Leubner static int aac_src_get_outb_queue(struct aac_softc *sc); 120dce93cd0SAchim Leubner static void aac_src_set_outb_queue(struct aac_softc *sc, int index); 121dce93cd0SAchim Leubner 122dce93cd0SAchim Leubner struct aac_interface aacraid_src_interface = { 123dce93cd0SAchim Leubner aac_src_get_fwstatus, 124dce93cd0SAchim Leubner aac_src_qnotify, 125dce93cd0SAchim Leubner aac_src_get_istatus, 126dce93cd0SAchim Leubner aac_src_clear_istatus, 127dce93cd0SAchim Leubner aac_src_set_mailbox, 128dce93cd0SAchim Leubner aac_src_get_mailbox, 1293fea9c0dSAchim Leubner aac_src_access_devreg, 130dce93cd0SAchim Leubner aac_src_send_command, 131dce93cd0SAchim Leubner aac_src_get_outb_queue, 132dce93cd0SAchim Leubner aac_src_set_outb_queue 133dce93cd0SAchim Leubner }; 134dce93cd0SAchim Leubner 135dce93cd0SAchim Leubner /* PMC SRCv interface */ 136dce93cd0SAchim Leubner static void aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, 137dce93cd0SAchim Leubner u_int32_t arg0, u_int32_t arg1, 138dce93cd0SAchim Leubner u_int32_t arg2, u_int32_t arg3); 139dce93cd0SAchim Leubner static int aac_srcv_get_mailbox(struct aac_softc *sc, int mb); 140dce93cd0SAchim Leubner 141dce93cd0SAchim Leubner struct aac_interface aacraid_srcv_interface = { 142dce93cd0SAchim Leubner aac_src_get_fwstatus, 143dce93cd0SAchim Leubner aac_src_qnotify, 144dce93cd0SAchim Leubner aac_src_get_istatus, 145dce93cd0SAchim Leubner aac_src_clear_istatus, 146dce93cd0SAchim Leubner aac_srcv_set_mailbox, 147dce93cd0SAchim Leubner aac_srcv_get_mailbox, 1483fea9c0dSAchim Leubner aac_src_access_devreg, 149dce93cd0SAchim Leubner aac_src_send_command, 150dce93cd0SAchim Leubner aac_src_get_outb_queue, 151dce93cd0SAchim Leubner aac_src_set_outb_queue 152dce93cd0SAchim Leubner }; 153dce93cd0SAchim Leubner 154dce93cd0SAchim Leubner /* Debugging and Diagnostics */ 155dce93cd0SAchim Leubner static struct aac_code_lookup aac_cpu_variant[] = { 156dce93cd0SAchim Leubner {"i960JX", CPUI960_JX}, 157dce93cd0SAchim Leubner {"i960CX", CPUI960_CX}, 158dce93cd0SAchim Leubner {"i960HX", CPUI960_HX}, 159dce93cd0SAchim Leubner {"i960RX", CPUI960_RX}, 160dce93cd0SAchim Leubner {"i960 80303", CPUI960_80303}, 161dce93cd0SAchim Leubner {"StrongARM SA110", CPUARM_SA110}, 162dce93cd0SAchim Leubner {"PPC603e", CPUPPC_603e}, 163dce93cd0SAchim Leubner {"XScale 80321", CPU_XSCALE_80321}, 164dce93cd0SAchim Leubner {"MIPS 4KC", CPU_MIPS_4KC}, 165dce93cd0SAchim Leubner {"MIPS 5KC", CPU_MIPS_5KC}, 166dce93cd0SAchim Leubner {"Unknown StrongARM", CPUARM_xxx}, 167dce93cd0SAchim Leubner {"Unknown PowerPC", CPUPPC_xxx}, 168dce93cd0SAchim Leubner {NULL, 0}, 169dce93cd0SAchim Leubner {"Unknown processor", 0} 170dce93cd0SAchim Leubner }; 171dce93cd0SAchim Leubner 172dce93cd0SAchim Leubner static struct aac_code_lookup aac_battery_platform[] = { 173dce93cd0SAchim Leubner {"required battery present", PLATFORM_BAT_REQ_PRESENT}, 174dce93cd0SAchim Leubner {"REQUIRED BATTERY NOT PRESENT", PLATFORM_BAT_REQ_NOTPRESENT}, 175dce93cd0SAchim Leubner {"optional battery present", PLATFORM_BAT_OPT_PRESENT}, 176dce93cd0SAchim Leubner {"optional battery not installed", PLATFORM_BAT_OPT_NOTPRESENT}, 177dce93cd0SAchim Leubner {"no battery support", PLATFORM_BAT_NOT_SUPPORTED}, 178dce93cd0SAchim Leubner {NULL, 0}, 179dce93cd0SAchim Leubner {"unknown battery platform", 0} 180dce93cd0SAchim Leubner }; 181dce93cd0SAchim Leubner static void aac_describe_controller(struct aac_softc *sc); 182dce93cd0SAchim Leubner static char *aac_describe_code(struct aac_code_lookup *table, 183dce93cd0SAchim Leubner u_int32_t code); 184dce93cd0SAchim Leubner 185dce93cd0SAchim Leubner /* Management Interface */ 186dce93cd0SAchim Leubner static d_open_t aac_open; 187dce93cd0SAchim Leubner static d_ioctl_t aac_ioctl; 188dce93cd0SAchim Leubner static d_poll_t aac_poll; 189dce93cd0SAchim Leubner #if __FreeBSD_version >= 702000 190dce93cd0SAchim Leubner static void aac_cdevpriv_dtor(void *arg); 191dce93cd0SAchim Leubner #else 192dce93cd0SAchim Leubner static d_close_t aac_close; 193dce93cd0SAchim Leubner #endif 194dce93cd0SAchim Leubner static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 195dce93cd0SAchim Leubner static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 196dce93cd0SAchim Leubner static void aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib); 197dce93cd0SAchim Leubner static void aac_request_aif(struct aac_softc *sc); 198dce93cd0SAchim Leubner static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 199dce93cd0SAchim Leubner static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 200dce93cd0SAchim Leubner static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 201dce93cd0SAchim Leubner static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 202dce93cd0SAchim Leubner static int aac_return_aif(struct aac_softc *sc, 203dce93cd0SAchim Leubner struct aac_fib_context *ctx, caddr_t uptr); 204dce93cd0SAchim Leubner static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 205dce93cd0SAchim Leubner static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 206dce93cd0SAchim Leubner static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 207dce93cd0SAchim Leubner static void aac_ioctl_event(struct aac_softc *sc, 208dce93cd0SAchim Leubner struct aac_event *event, void *arg); 209dce93cd0SAchim Leubner static int aac_reset_adapter(struct aac_softc *sc); 210dce93cd0SAchim Leubner static int aac_get_container_info(struct aac_softc *sc, 211dce93cd0SAchim Leubner struct aac_fib *fib, int cid, 212dce93cd0SAchim Leubner struct aac_mntinforesp *mir, 213dce93cd0SAchim Leubner u_int32_t *uid); 214dce93cd0SAchim Leubner static u_int32_t 215dce93cd0SAchim Leubner aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled); 216dce93cd0SAchim Leubner 217dce93cd0SAchim Leubner static struct cdevsw aacraid_cdevsw = { 218dce93cd0SAchim Leubner .d_version = D_VERSION, 219dce93cd0SAchim Leubner .d_flags = D_NEEDGIANT, 220dce93cd0SAchim Leubner .d_open = aac_open, 221dce93cd0SAchim Leubner #if __FreeBSD_version < 702000 222dce93cd0SAchim Leubner .d_close = aac_close, 223dce93cd0SAchim Leubner #endif 224dce93cd0SAchim Leubner .d_ioctl = aac_ioctl, 225dce93cd0SAchim Leubner .d_poll = aac_poll, 226dce93cd0SAchim Leubner .d_name = "aacraid", 227dce93cd0SAchim Leubner }; 228dce93cd0SAchim Leubner 229dce93cd0SAchim Leubner MALLOC_DEFINE(M_AACRAIDBUF, "aacraid_buf", "Buffers for the AACRAID driver"); 230dce93cd0SAchim Leubner 231dce93cd0SAchim Leubner /* sysctl node */ 232dce93cd0SAchim Leubner SYSCTL_NODE(_hw, OID_AUTO, aacraid, CTLFLAG_RD, 0, "AACRAID driver parameters"); 233dce93cd0SAchim Leubner 234dce93cd0SAchim Leubner /* 235dce93cd0SAchim Leubner * Device Interface 236dce93cd0SAchim Leubner */ 237dce93cd0SAchim Leubner 238dce93cd0SAchim Leubner /* 239dce93cd0SAchim Leubner * Initialize the controller and softc 240dce93cd0SAchim Leubner */ 241dce93cd0SAchim Leubner int 242dce93cd0SAchim Leubner aacraid_attach(struct aac_softc *sc) 243dce93cd0SAchim Leubner { 244dce93cd0SAchim Leubner int error, unit; 245dce93cd0SAchim Leubner struct aac_fib *fib; 246dce93cd0SAchim Leubner struct aac_mntinforesp mir; 247dce93cd0SAchim Leubner int count = 0, i = 0; 248dce93cd0SAchim Leubner u_int32_t uid; 249dce93cd0SAchim Leubner 250dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 251dce93cd0SAchim Leubner sc->hint_flags = device_get_flags(sc->aac_dev); 252dce93cd0SAchim Leubner /* 253dce93cd0SAchim Leubner * Initialize per-controller queues. 254dce93cd0SAchim Leubner */ 255dce93cd0SAchim Leubner aac_initq_free(sc); 256dce93cd0SAchim Leubner aac_initq_ready(sc); 257dce93cd0SAchim Leubner aac_initq_busy(sc); 258dce93cd0SAchim Leubner 259dce93cd0SAchim Leubner /* mark controller as suspended until we get ourselves organised */ 260dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_SUSPEND; 261dce93cd0SAchim Leubner 262dce93cd0SAchim Leubner /* 263dce93cd0SAchim Leubner * Check that the firmware on the card is supported. 264dce93cd0SAchim Leubner */ 2653fea9c0dSAchim Leubner sc->msi_enabled = FALSE; 266dce93cd0SAchim Leubner if ((error = aac_check_firmware(sc)) != 0) 267dce93cd0SAchim Leubner return(error); 268dce93cd0SAchim Leubner 269dce93cd0SAchim Leubner /* 270dce93cd0SAchim Leubner * Initialize locks 271dce93cd0SAchim Leubner */ 272dce93cd0SAchim Leubner mtx_init(&sc->aac_io_lock, "AACRAID I/O lock", NULL, MTX_DEF); 273dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_container_tqh); 274dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_ev_cmfree); 275dce93cd0SAchim Leubner 276dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 277dce93cd0SAchim Leubner /* Initialize the clock daemon callout. */ 278dce93cd0SAchim Leubner callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 279dce93cd0SAchim Leubner #endif 280dce93cd0SAchim Leubner /* 281dce93cd0SAchim Leubner * Initialize the adapter. 282dce93cd0SAchim Leubner */ 283dce93cd0SAchim Leubner if ((error = aac_alloc(sc)) != 0) 284dce93cd0SAchim Leubner return(error); 285dce93cd0SAchim Leubner if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 2863fea9c0dSAchim Leubner aac_define_int_mode(sc); 287dce93cd0SAchim Leubner if ((error = aac_init(sc)) != 0) 288dce93cd0SAchim Leubner return(error); 289dce93cd0SAchim Leubner } 290dce93cd0SAchim Leubner 291dce93cd0SAchim Leubner /* 292dce93cd0SAchim Leubner * Allocate and connect our interrupt. 293dce93cd0SAchim Leubner */ 294dce93cd0SAchim Leubner if ((error = aac_setup_intr(sc)) != 0) 295dce93cd0SAchim Leubner return(error); 296dce93cd0SAchim Leubner 297dce93cd0SAchim Leubner /* 298dce93cd0SAchim Leubner * Print a little information about the controller. 299dce93cd0SAchim Leubner */ 300dce93cd0SAchim Leubner aac_describe_controller(sc); 301dce93cd0SAchim Leubner 302dce93cd0SAchim Leubner /* 303dce93cd0SAchim Leubner * Make the control device. 304dce93cd0SAchim Leubner */ 305dce93cd0SAchim Leubner unit = device_get_unit(sc->aac_dev); 306dce93cd0SAchim Leubner sc->aac_dev_t = make_dev(&aacraid_cdevsw, unit, UID_ROOT, GID_OPERATOR, 307dce93cd0SAchim Leubner 0640, "aacraid%d", unit); 308dce93cd0SAchim Leubner sc->aac_dev_t->si_drv1 = sc; 309dce93cd0SAchim Leubner 310dce93cd0SAchim Leubner /* Create the AIF thread */ 311dce93cd0SAchim Leubner if (aac_kthread_create((void(*)(void *))aac_command_thread, sc, 312dce93cd0SAchim Leubner &sc->aifthread, 0, 0, "aacraid%daif", unit)) 313dce93cd0SAchim Leubner panic("Could not create AIF thread"); 314dce93cd0SAchim Leubner 315dce93cd0SAchim Leubner /* Register the shutdown method to only be called post-dump */ 316dce93cd0SAchim Leubner if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aacraid_shutdown, 317dce93cd0SAchim Leubner sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 318dce93cd0SAchim Leubner device_printf(sc->aac_dev, 319dce93cd0SAchim Leubner "shutdown event registration failed\n"); 320dce93cd0SAchim Leubner 321dce93cd0SAchim Leubner /* Find containers */ 322dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 323dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 324dce93cd0SAchim Leubner /* loop over possible containers */ 325dce93cd0SAchim Leubner do { 326dce93cd0SAchim Leubner if ((aac_get_container_info(sc, fib, i, &mir, &uid)) != 0) 327dce93cd0SAchim Leubner continue; 328dce93cd0SAchim Leubner if (i == 0) 329dce93cd0SAchim Leubner count = mir.MntRespCount; 330dce93cd0SAchim Leubner aac_add_container(sc, &mir, 0, uid); 331dce93cd0SAchim Leubner i++; 332dce93cd0SAchim Leubner } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 333dce93cd0SAchim Leubner aac_release_sync_fib(sc); 334dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 335dce93cd0SAchim Leubner 336dce93cd0SAchim Leubner /* Register with CAM for the containers */ 337dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_sim_tqh); 338dce93cd0SAchim Leubner aac_container_bus(sc); 339dce93cd0SAchim Leubner /* Register with CAM for the non-DASD devices */ 340dce93cd0SAchim Leubner if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) 341dce93cd0SAchim Leubner aac_get_bus_info(sc); 342dce93cd0SAchim Leubner 343dce93cd0SAchim Leubner /* poke the bus to actually attach the child devices */ 344dce93cd0SAchim Leubner bus_generic_attach(sc->aac_dev); 345dce93cd0SAchim Leubner 346dce93cd0SAchim Leubner /* mark the controller up */ 347dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_SUSPEND; 348dce93cd0SAchim Leubner 349dce93cd0SAchim Leubner /* enable interrupts now */ 3503fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT); 351dce93cd0SAchim Leubner 352dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 353dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 354dce93cd0SAchim Leubner callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 355dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 356dce93cd0SAchim Leubner #else 357dce93cd0SAchim Leubner { 358dce93cd0SAchim Leubner struct timeval tv; 359dce93cd0SAchim Leubner tv.tv_sec = 60; 360dce93cd0SAchim Leubner tv.tv_usec = 0; 361dce93cd0SAchim Leubner sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 362dce93cd0SAchim Leubner } 363dce93cd0SAchim Leubner #endif 364dce93cd0SAchim Leubner 365dce93cd0SAchim Leubner return(0); 366dce93cd0SAchim Leubner } 367dce93cd0SAchim Leubner 368dce93cd0SAchim Leubner static void 369dce93cd0SAchim Leubner aac_daemon(void *arg) 370dce93cd0SAchim Leubner { 371dce93cd0SAchim Leubner struct aac_softc *sc; 372dce93cd0SAchim Leubner struct timeval tv; 373dce93cd0SAchim Leubner struct aac_command *cm; 374dce93cd0SAchim Leubner struct aac_fib *fib; 375dce93cd0SAchim Leubner 376dce93cd0SAchim Leubner sc = arg; 377dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 378dce93cd0SAchim Leubner 379dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 380dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 381dce93cd0SAchim Leubner if (callout_pending(&sc->aac_daemontime) || 382dce93cd0SAchim Leubner callout_active(&sc->aac_daemontime) == 0) 383dce93cd0SAchim Leubner return; 384dce93cd0SAchim Leubner #else 385dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 386dce93cd0SAchim Leubner #endif 387dce93cd0SAchim Leubner getmicrotime(&tv); 388dce93cd0SAchim Leubner 389dce93cd0SAchim Leubner if (!aacraid_alloc_command(sc, &cm)) { 390dce93cd0SAchim Leubner fib = cm->cm_fib; 391dce93cd0SAchim Leubner cm->cm_timestamp = time_uptime; 392dce93cd0SAchim Leubner cm->cm_datalen = 0; 393dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_WAIT; 394dce93cd0SAchim Leubner 395dce93cd0SAchim Leubner fib->Header.Size = 396dce93cd0SAchim Leubner sizeof(struct aac_fib_header) + sizeof(u_int32_t); 397dce93cd0SAchim Leubner fib->Header.XferState = 398dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 399dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 400dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 401dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 402dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 403dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 404dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC | 405dce93cd0SAchim Leubner AAC_FIBSTATE_FAST_RESPONSE; 406dce93cd0SAchim Leubner fib->Header.Command = SendHostTime; 407dce93cd0SAchim Leubner *(uint32_t *)fib->data = tv.tv_sec; 408dce93cd0SAchim Leubner 409dce93cd0SAchim Leubner aacraid_map_command_sg(cm, NULL, 0, 0); 410dce93cd0SAchim Leubner aacraid_release_command(cm); 411dce93cd0SAchim Leubner } 412dce93cd0SAchim Leubner 413dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 414dce93cd0SAchim Leubner callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 415dce93cd0SAchim Leubner #else 416dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 417dce93cd0SAchim Leubner tv.tv_sec = 30 * 60; 418dce93cd0SAchim Leubner tv.tv_usec = 0; 419dce93cd0SAchim Leubner sc->timeout_id = timeout(aac_daemon, (void *)sc, tvtohz(&tv)); 420dce93cd0SAchim Leubner #endif 421dce93cd0SAchim Leubner } 422dce93cd0SAchim Leubner 423dce93cd0SAchim Leubner void 424dce93cd0SAchim Leubner aacraid_add_event(struct aac_softc *sc, struct aac_event *event) 425dce93cd0SAchim Leubner { 426dce93cd0SAchim Leubner 427dce93cd0SAchim Leubner switch (event->ev_type & AAC_EVENT_MASK) { 428dce93cd0SAchim Leubner case AAC_EVENT_CMFREE: 429dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 430dce93cd0SAchim Leubner break; 431dce93cd0SAchim Leubner default: 432dce93cd0SAchim Leubner device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 433dce93cd0SAchim Leubner event->ev_type); 434dce93cd0SAchim Leubner break; 435dce93cd0SAchim Leubner } 436dce93cd0SAchim Leubner 437dce93cd0SAchim Leubner return; 438dce93cd0SAchim Leubner } 439dce93cd0SAchim Leubner 440dce93cd0SAchim Leubner /* 441dce93cd0SAchim Leubner * Request information of container #cid 442dce93cd0SAchim Leubner */ 443dce93cd0SAchim Leubner static int 444dce93cd0SAchim Leubner aac_get_container_info(struct aac_softc *sc, struct aac_fib *sync_fib, int cid, 445dce93cd0SAchim Leubner struct aac_mntinforesp *mir, u_int32_t *uid) 446dce93cd0SAchim Leubner { 447dce93cd0SAchim Leubner struct aac_command *cm; 448dce93cd0SAchim Leubner struct aac_fib *fib; 449dce93cd0SAchim Leubner struct aac_mntinfo *mi; 450dce93cd0SAchim Leubner struct aac_cnt_config *ccfg; 4513fea9c0dSAchim Leubner int rval; 452dce93cd0SAchim Leubner 453dce93cd0SAchim Leubner if (sync_fib == NULL) { 454dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 455dce93cd0SAchim Leubner device_printf(sc->aac_dev, 456dce93cd0SAchim Leubner "Warning, no free command available\n"); 457dce93cd0SAchim Leubner return (-1); 458dce93cd0SAchim Leubner } 459dce93cd0SAchim Leubner fib = cm->cm_fib; 460dce93cd0SAchim Leubner } else { 461dce93cd0SAchim Leubner fib = sync_fib; 462dce93cd0SAchim Leubner } 463dce93cd0SAchim Leubner 464dce93cd0SAchim Leubner mi = (struct aac_mntinfo *)&fib->data[0]; 465dce93cd0SAchim Leubner /* 4KB support?, 64-bit LBA? */ 466dce93cd0SAchim Leubner if (sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE) 467dce93cd0SAchim Leubner mi->Command = VM_NameServeAllBlk; 468dce93cd0SAchim Leubner else if (sc->flags & AAC_FLAGS_LBA_64BIT) 469dce93cd0SAchim Leubner mi->Command = VM_NameServe64; 470dce93cd0SAchim Leubner else 471dce93cd0SAchim Leubner mi->Command = VM_NameServe; 472dce93cd0SAchim Leubner mi->MntType = FT_FILESYS; 473dce93cd0SAchim Leubner mi->MntCount = cid; 474dce93cd0SAchim Leubner 475dce93cd0SAchim Leubner if (sync_fib) { 476dce93cd0SAchim Leubner if (aac_sync_fib(sc, ContainerCommand, 0, fib, 477dce93cd0SAchim Leubner sizeof(struct aac_mntinfo))) { 478dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error probing container %d\n", cid); 479dce93cd0SAchim Leubner return (-1); 480dce93cd0SAchim Leubner } 481dce93cd0SAchim Leubner } else { 482dce93cd0SAchim Leubner cm->cm_timestamp = time_uptime; 483dce93cd0SAchim Leubner cm->cm_datalen = 0; 484dce93cd0SAchim Leubner 485dce93cd0SAchim Leubner fib->Header.Size = 486dce93cd0SAchim Leubner sizeof(struct aac_fib_header) + sizeof(struct aac_mntinfo); 487dce93cd0SAchim Leubner fib->Header.XferState = 488dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 489dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 490dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 491dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 492dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 493dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 494dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC | 495dce93cd0SAchim Leubner AAC_FIBSTATE_FAST_RESPONSE; 496dce93cd0SAchim Leubner fib->Header.Command = ContainerCommand; 497dce93cd0SAchim Leubner if (aacraid_wait_command(cm) != 0) { 498dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error probing container %d\n", cid); 499dce93cd0SAchim Leubner aacraid_release_command(cm); 500dce93cd0SAchim Leubner return (-1); 501dce93cd0SAchim Leubner } 502dce93cd0SAchim Leubner } 503dce93cd0SAchim Leubner bcopy(&fib->data[0], mir, sizeof(struct aac_mntinforesp)); 504dce93cd0SAchim Leubner 505dce93cd0SAchim Leubner /* UID */ 506dce93cd0SAchim Leubner *uid = cid; 507dce93cd0SAchim Leubner if (mir->MntTable[0].VolType != CT_NONE && 508dce93cd0SAchim Leubner !(mir->MntTable[0].ContentState & AAC_FSCS_HIDDEN)) { 5093fea9c0dSAchim Leubner if (!(sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)) { 5103fea9c0dSAchim Leubner mir->MntTable[0].ObjExtension.BlockDevice.BlockSize = 0x200; 5113fea9c0dSAchim Leubner mir->MntTable[0].ObjExtension.BlockDevice.bdLgclPhysMap = 0; 5123fea9c0dSAchim Leubner } 513dce93cd0SAchim Leubner ccfg = (struct aac_cnt_config *)&fib->data[0]; 514dce93cd0SAchim Leubner bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 515dce93cd0SAchim Leubner ccfg->Command = VM_ContainerConfig; 516dce93cd0SAchim Leubner ccfg->CTCommand.command = CT_CID_TO_32BITS_UID; 517dce93cd0SAchim Leubner ccfg->CTCommand.param[0] = cid; 518dce93cd0SAchim Leubner 519dce93cd0SAchim Leubner if (sync_fib) { 5203fea9c0dSAchim Leubner rval = aac_sync_fib(sc, ContainerCommand, 0, fib, 5213fea9c0dSAchim Leubner sizeof(struct aac_cnt_config)); 5223fea9c0dSAchim Leubner if (rval == 0 && ccfg->Command == ST_OK && 5233fea9c0dSAchim Leubner ccfg->CTCommand.param[0] == CT_OK && 524dce93cd0SAchim Leubner mir->MntTable[0].VolType != CT_PASSTHRU) 525dce93cd0SAchim Leubner *uid = ccfg->CTCommand.param[1]; 526dce93cd0SAchim Leubner } else { 527dce93cd0SAchim Leubner fib->Header.Size = 528dce93cd0SAchim Leubner sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config); 529dce93cd0SAchim Leubner fib->Header.XferState = 530dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 531dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 532dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 533dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 534dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 535dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 536dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC | 537dce93cd0SAchim Leubner AAC_FIBSTATE_FAST_RESPONSE; 538dce93cd0SAchim Leubner fib->Header.Command = ContainerCommand; 5393fea9c0dSAchim Leubner rval = aacraid_wait_command(cm); 5403fea9c0dSAchim Leubner if (rval == 0 && ccfg->Command == ST_OK && 5413fea9c0dSAchim Leubner ccfg->CTCommand.param[0] == CT_OK && 542dce93cd0SAchim Leubner mir->MntTable[0].VolType != CT_PASSTHRU) 543dce93cd0SAchim Leubner *uid = ccfg->CTCommand.param[1]; 544dce93cd0SAchim Leubner aacraid_release_command(cm); 545dce93cd0SAchim Leubner } 546dce93cd0SAchim Leubner } 547dce93cd0SAchim Leubner 548dce93cd0SAchim Leubner return (0); 549dce93cd0SAchim Leubner } 550dce93cd0SAchim Leubner 551dce93cd0SAchim Leubner /* 552dce93cd0SAchim Leubner * Create a device to represent a new container 553dce93cd0SAchim Leubner */ 554dce93cd0SAchim Leubner static void 555dce93cd0SAchim Leubner aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f, 556dce93cd0SAchim Leubner u_int32_t uid) 557dce93cd0SAchim Leubner { 558dce93cd0SAchim Leubner struct aac_container *co; 559dce93cd0SAchim Leubner 560dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 561dce93cd0SAchim Leubner 562dce93cd0SAchim Leubner /* 563dce93cd0SAchim Leubner * Check container volume type for validity. Note that many of 564dce93cd0SAchim Leubner * the possible types may never show up. 565dce93cd0SAchim Leubner */ 566dce93cd0SAchim Leubner if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 567dce93cd0SAchim Leubner co = (struct aac_container *)malloc(sizeof *co, M_AACRAIDBUF, 568dce93cd0SAchim Leubner M_NOWAIT | M_ZERO); 569dce93cd0SAchim Leubner if (co == NULL) { 570dce93cd0SAchim Leubner panic("Out of memory?!"); 571dce93cd0SAchim Leubner } 572dce93cd0SAchim Leubner 573dce93cd0SAchim Leubner co->co_found = f; 574dce93cd0SAchim Leubner bcopy(&mir->MntTable[0], &co->co_mntobj, 575dce93cd0SAchim Leubner sizeof(struct aac_mntobj)); 576dce93cd0SAchim Leubner co->co_uid = uid; 577dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 578dce93cd0SAchim Leubner } 579dce93cd0SAchim Leubner } 580dce93cd0SAchim Leubner 581dce93cd0SAchim Leubner /* 582dce93cd0SAchim Leubner * Allocate resources associated with (sc) 583dce93cd0SAchim Leubner */ 584dce93cd0SAchim Leubner static int 585dce93cd0SAchim Leubner aac_alloc(struct aac_softc *sc) 586dce93cd0SAchim Leubner { 587dce93cd0SAchim Leubner bus_size_t maxsize; 588dce93cd0SAchim Leubner 589dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 590dce93cd0SAchim Leubner 591dce93cd0SAchim Leubner /* 592dce93cd0SAchim Leubner * Create DMA tag for mapping buffers into controller-addressable space. 593dce93cd0SAchim Leubner */ 594dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 595dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 596dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_SG_64BIT) ? 597dce93cd0SAchim Leubner BUS_SPACE_MAXADDR : 598dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 599dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 600dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 6016f954fb3SAlexander Motin sc->aac_max_sectors << 9, /* maxsize */ 602dce93cd0SAchim Leubner sc->aac_sg_tablesize, /* nsegments */ 6036f954fb3SAlexander Motin BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 604dce93cd0SAchim Leubner BUS_DMA_ALLOCNOW, /* flags */ 605dce93cd0SAchim Leubner busdma_lock_mutex, /* lockfunc */ 606dce93cd0SAchim Leubner &sc->aac_io_lock, /* lockfuncarg */ 607dce93cd0SAchim Leubner &sc->aac_buffer_dmat)) { 608dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 609dce93cd0SAchim Leubner return (ENOMEM); 610dce93cd0SAchim Leubner } 611dce93cd0SAchim Leubner 612dce93cd0SAchim Leubner /* 613dce93cd0SAchim Leubner * Create DMA tag for mapping FIBs into controller-addressable space.. 614dce93cd0SAchim Leubner */ 615dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 616dce93cd0SAchim Leubner maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 617dce93cd0SAchim Leubner sizeof(struct aac_fib_xporthdr) + 31); 618dce93cd0SAchim Leubner else 619dce93cd0SAchim Leubner maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 31); 620dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 621dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 622dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 623dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT : 624dce93cd0SAchim Leubner 0x7fffffff, /* lowaddr */ 625dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 626dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 627dce93cd0SAchim Leubner maxsize, /* maxsize */ 628dce93cd0SAchim Leubner 1, /* nsegments */ 629dce93cd0SAchim Leubner maxsize, /* maxsize */ 630dce93cd0SAchim Leubner 0, /* flags */ 631dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 632dce93cd0SAchim Leubner &sc->aac_fib_dmat)) { 633dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 634dce93cd0SAchim Leubner return (ENOMEM); 635dce93cd0SAchim Leubner } 636dce93cd0SAchim Leubner 637dce93cd0SAchim Leubner /* 638dce93cd0SAchim Leubner * Create DMA tag for the common structure and allocate it. 639dce93cd0SAchim Leubner */ 640dce93cd0SAchim Leubner maxsize = sizeof(struct aac_common); 641dce93cd0SAchim Leubner maxsize += sc->aac_max_fibs * sizeof(u_int32_t); 642dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 643dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 644dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 645dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT : 646dce93cd0SAchim Leubner 0x7fffffff, /* lowaddr */ 647dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 648dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 649dce93cd0SAchim Leubner maxsize, /* maxsize */ 650dce93cd0SAchim Leubner 1, /* nsegments */ 651dce93cd0SAchim Leubner maxsize, /* maxsegsize */ 652dce93cd0SAchim Leubner 0, /* flags */ 653dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 654dce93cd0SAchim Leubner &sc->aac_common_dmat)) { 655dce93cd0SAchim Leubner device_printf(sc->aac_dev, 656dce93cd0SAchim Leubner "can't allocate common structure DMA tag\n"); 657dce93cd0SAchim Leubner return (ENOMEM); 658dce93cd0SAchim Leubner } 659dce93cd0SAchim Leubner if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 660dce93cd0SAchim Leubner BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 661dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate common structure\n"); 662dce93cd0SAchim Leubner return (ENOMEM); 663dce93cd0SAchim Leubner } 664dce93cd0SAchim Leubner 665dce93cd0SAchim Leubner (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 666dce93cd0SAchim Leubner sc->aac_common, maxsize, 667dce93cd0SAchim Leubner aac_common_map, sc, 0); 668dce93cd0SAchim Leubner bzero(sc->aac_common, maxsize); 669dce93cd0SAchim Leubner 670dce93cd0SAchim Leubner /* Allocate some FIBs and associated command structs */ 671dce93cd0SAchim Leubner TAILQ_INIT(&sc->aac_fibmap_tqh); 672dce93cd0SAchim Leubner sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 673dce93cd0SAchim Leubner M_AACRAIDBUF, M_WAITOK|M_ZERO); 67461722264SAndriy Gapon mtx_lock(&sc->aac_io_lock); 675dce93cd0SAchim Leubner while (sc->total_fibs < sc->aac_max_fibs) { 676dce93cd0SAchim Leubner if (aac_alloc_commands(sc) != 0) 677dce93cd0SAchim Leubner break; 678dce93cd0SAchim Leubner } 67961722264SAndriy Gapon mtx_unlock(&sc->aac_io_lock); 680dce93cd0SAchim Leubner if (sc->total_fibs == 0) 681dce93cd0SAchim Leubner return (ENOMEM); 682dce93cd0SAchim Leubner 683dce93cd0SAchim Leubner return (0); 684dce93cd0SAchim Leubner } 685dce93cd0SAchim Leubner 686dce93cd0SAchim Leubner /* 687dce93cd0SAchim Leubner * Free all of the resources associated with (sc) 688dce93cd0SAchim Leubner * 689dce93cd0SAchim Leubner * Should not be called if the controller is active. 690dce93cd0SAchim Leubner */ 691dce93cd0SAchim Leubner void 692dce93cd0SAchim Leubner aacraid_free(struct aac_softc *sc) 693dce93cd0SAchim Leubner { 6943fea9c0dSAchim Leubner int i; 6953fea9c0dSAchim Leubner 696dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 697dce93cd0SAchim Leubner 698dce93cd0SAchim Leubner /* remove the control device */ 699dce93cd0SAchim Leubner if (sc->aac_dev_t != NULL) 700dce93cd0SAchim Leubner destroy_dev(sc->aac_dev_t); 701dce93cd0SAchim Leubner 702dce93cd0SAchim Leubner /* throw away any FIB buffers, discard the FIB DMA tag */ 703dce93cd0SAchim Leubner aac_free_commands(sc); 704dce93cd0SAchim Leubner if (sc->aac_fib_dmat) 705dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_fib_dmat); 706dce93cd0SAchim Leubner 707dce93cd0SAchim Leubner free(sc->aac_commands, M_AACRAIDBUF); 708dce93cd0SAchim Leubner 709dce93cd0SAchim Leubner /* destroy the common area */ 710dce93cd0SAchim Leubner if (sc->aac_common) { 711dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 712dce93cd0SAchim Leubner bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 713dce93cd0SAchim Leubner sc->aac_common_dmamap); 714dce93cd0SAchim Leubner } 715dce93cd0SAchim Leubner if (sc->aac_common_dmat) 716dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_common_dmat); 717dce93cd0SAchim Leubner 718dce93cd0SAchim Leubner /* disconnect the interrupt handler */ 7193fea9c0dSAchim Leubner for (i = 0; i < AAC_MAX_MSIX; ++i) { 7203fea9c0dSAchim Leubner if (sc->aac_intr[i]) 7213fea9c0dSAchim Leubner bus_teardown_intr(sc->aac_dev, 7223fea9c0dSAchim Leubner sc->aac_irq[i], sc->aac_intr[i]); 7233fea9c0dSAchim Leubner if (sc->aac_irq[i]) 7243fea9c0dSAchim Leubner bus_release_resource(sc->aac_dev, SYS_RES_IRQ, 7253fea9c0dSAchim Leubner sc->aac_irq_rid[i], sc->aac_irq[i]); 7263fea9c0dSAchim Leubner else 7273fea9c0dSAchim Leubner break; 7283fea9c0dSAchim Leubner } 7293fea9c0dSAchim Leubner if (sc->msi_enabled) 7303fea9c0dSAchim Leubner pci_release_msi(sc->aac_dev); 731dce93cd0SAchim Leubner 732dce93cd0SAchim Leubner /* destroy data-transfer DMA tag */ 733dce93cd0SAchim Leubner if (sc->aac_buffer_dmat) 734dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_buffer_dmat); 735dce93cd0SAchim Leubner 736dce93cd0SAchim Leubner /* destroy the parent DMA tag */ 737dce93cd0SAchim Leubner if (sc->aac_parent_dmat) 738dce93cd0SAchim Leubner bus_dma_tag_destroy(sc->aac_parent_dmat); 739dce93cd0SAchim Leubner 740dce93cd0SAchim Leubner /* release the register window mapping */ 741dce93cd0SAchim Leubner if (sc->aac_regs_res0 != NULL) 742dce93cd0SAchim Leubner bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 743dce93cd0SAchim Leubner sc->aac_regs_rid0, sc->aac_regs_res0); 744dce93cd0SAchim Leubner if (sc->aac_regs_res1 != NULL) 745dce93cd0SAchim Leubner bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 746dce93cd0SAchim Leubner sc->aac_regs_rid1, sc->aac_regs_res1); 747dce93cd0SAchim Leubner } 748dce93cd0SAchim Leubner 749dce93cd0SAchim Leubner /* 750dce93cd0SAchim Leubner * Disconnect from the controller completely, in preparation for unload. 751dce93cd0SAchim Leubner */ 752dce93cd0SAchim Leubner int 753dce93cd0SAchim Leubner aacraid_detach(device_t dev) 754dce93cd0SAchim Leubner { 755dce93cd0SAchim Leubner struct aac_softc *sc; 756dce93cd0SAchim Leubner struct aac_container *co; 757dce93cd0SAchim Leubner struct aac_sim *sim; 758dce93cd0SAchim Leubner int error; 759dce93cd0SAchim Leubner 760dce93cd0SAchim Leubner sc = device_get_softc(dev); 761dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 762dce93cd0SAchim Leubner 763dce93cd0SAchim Leubner #if __FreeBSD_version >= 800000 764dce93cd0SAchim Leubner callout_drain(&sc->aac_daemontime); 765dce93cd0SAchim Leubner #else 766dce93cd0SAchim Leubner untimeout(aac_daemon, (void *)sc, sc->timeout_id); 767dce93cd0SAchim Leubner #endif 768dce93cd0SAchim Leubner /* Remove the child containers */ 769dce93cd0SAchim Leubner while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 770dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 771dce93cd0SAchim Leubner free(co, M_AACRAIDBUF); 772dce93cd0SAchim Leubner } 773dce93cd0SAchim Leubner 774dce93cd0SAchim Leubner /* Remove the CAM SIMs */ 775dce93cd0SAchim Leubner while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 776dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 777dce93cd0SAchim Leubner error = device_delete_child(dev, sim->sim_dev); 778dce93cd0SAchim Leubner if (error) 779dce93cd0SAchim Leubner return (error); 780dce93cd0SAchim Leubner free(sim, M_AACRAIDBUF); 781dce93cd0SAchim Leubner } 782dce93cd0SAchim Leubner 783dce93cd0SAchim Leubner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 784dce93cd0SAchim Leubner sc->aifflags |= AAC_AIFFLAGS_EXIT; 785dce93cd0SAchim Leubner wakeup(sc->aifthread); 786dce93cd0SAchim Leubner tsleep(sc->aac_dev, PUSER | PCATCH, "aac_dch", 30 * hz); 787dce93cd0SAchim Leubner } 788dce93cd0SAchim Leubner 789dce93cd0SAchim Leubner if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 790dce93cd0SAchim Leubner panic("Cannot shutdown AIF thread"); 791dce93cd0SAchim Leubner 792dce93cd0SAchim Leubner if ((error = aacraid_shutdown(dev))) 793dce93cd0SAchim Leubner return(error); 794dce93cd0SAchim Leubner 795dce93cd0SAchim Leubner EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 796dce93cd0SAchim Leubner 797dce93cd0SAchim Leubner aacraid_free(sc); 798dce93cd0SAchim Leubner 799dce93cd0SAchim Leubner mtx_destroy(&sc->aac_io_lock); 800dce93cd0SAchim Leubner 801dce93cd0SAchim Leubner return(0); 802dce93cd0SAchim Leubner } 803dce93cd0SAchim Leubner 804dce93cd0SAchim Leubner /* 805dce93cd0SAchim Leubner * Bring the controller down to a dormant state and detach all child devices. 806dce93cd0SAchim Leubner * 807dce93cd0SAchim Leubner * This function is called before detach or system shutdown. 808dce93cd0SAchim Leubner * 809dce93cd0SAchim Leubner * Note that we can assume that the bioq on the controller is empty, as we won't 810dce93cd0SAchim Leubner * allow shutdown if any device is open. 811dce93cd0SAchim Leubner */ 812dce93cd0SAchim Leubner int 813dce93cd0SAchim Leubner aacraid_shutdown(device_t dev) 814dce93cd0SAchim Leubner { 815dce93cd0SAchim Leubner struct aac_softc *sc; 816dce93cd0SAchim Leubner struct aac_fib *fib; 817dce93cd0SAchim Leubner struct aac_close_command *cc; 818dce93cd0SAchim Leubner 819dce93cd0SAchim Leubner sc = device_get_softc(dev); 820dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 821dce93cd0SAchim Leubner 822dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_SUSPEND; 823dce93cd0SAchim Leubner 824dce93cd0SAchim Leubner /* 825dce93cd0SAchim Leubner * Send a Container shutdown followed by a HostShutdown FIB to the 826dce93cd0SAchim Leubner * controller to convince it that we don't want to talk to it anymore. 827dce93cd0SAchim Leubner * We've been closed and all I/O completed already 828dce93cd0SAchim Leubner */ 829dce93cd0SAchim Leubner device_printf(sc->aac_dev, "shutting down controller..."); 830dce93cd0SAchim Leubner 831dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 832dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 833dce93cd0SAchim Leubner cc = (struct aac_close_command *)&fib->data[0]; 834dce93cd0SAchim Leubner 835dce93cd0SAchim Leubner bzero(cc, sizeof(struct aac_close_command)); 836dce93cd0SAchim Leubner cc->Command = VM_CloseAll; 8373fea9c0dSAchim Leubner cc->ContainerId = 0xfffffffe; 838dce93cd0SAchim Leubner if (aac_sync_fib(sc, ContainerCommand, 0, fib, 839dce93cd0SAchim Leubner sizeof(struct aac_close_command))) 840dce93cd0SAchim Leubner printf("FAILED.\n"); 841dce93cd0SAchim Leubner else 842dce93cd0SAchim Leubner printf("done\n"); 843dce93cd0SAchim Leubner 8443fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT); 845dce93cd0SAchim Leubner aac_release_sync_fib(sc); 846dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 847dce93cd0SAchim Leubner 848dce93cd0SAchim Leubner return(0); 849dce93cd0SAchim Leubner } 850dce93cd0SAchim Leubner 851dce93cd0SAchim Leubner /* 852dce93cd0SAchim Leubner * Bring the controller to a quiescent state, ready for system suspend. 853dce93cd0SAchim Leubner */ 854dce93cd0SAchim Leubner int 855dce93cd0SAchim Leubner aacraid_suspend(device_t dev) 856dce93cd0SAchim Leubner { 857dce93cd0SAchim Leubner struct aac_softc *sc; 858dce93cd0SAchim Leubner 859dce93cd0SAchim Leubner sc = device_get_softc(dev); 860dce93cd0SAchim Leubner 861dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 862dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_SUSPEND; 863dce93cd0SAchim Leubner 8643fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT); 865dce93cd0SAchim Leubner return(0); 866dce93cd0SAchim Leubner } 867dce93cd0SAchim Leubner 868dce93cd0SAchim Leubner /* 869dce93cd0SAchim Leubner * Bring the controller back to a state ready for operation. 870dce93cd0SAchim Leubner */ 871dce93cd0SAchim Leubner int 872dce93cd0SAchim Leubner aacraid_resume(device_t dev) 873dce93cd0SAchim Leubner { 874dce93cd0SAchim Leubner struct aac_softc *sc; 875dce93cd0SAchim Leubner 876dce93cd0SAchim Leubner sc = device_get_softc(dev); 877dce93cd0SAchim Leubner 878dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 879dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_SUSPEND; 8803fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT); 881dce93cd0SAchim Leubner return(0); 882dce93cd0SAchim Leubner } 883dce93cd0SAchim Leubner 884dce93cd0SAchim Leubner /* 885dce93cd0SAchim Leubner * Interrupt handler for NEW_COMM_TYPE1, NEW_COMM_TYPE2, NEW_COMM_TYPE34 interface. 886dce93cd0SAchim Leubner */ 887dce93cd0SAchim Leubner void 888dce93cd0SAchim Leubner aacraid_new_intr_type1(void *arg) 889dce93cd0SAchim Leubner { 8903fea9c0dSAchim Leubner struct aac_msix_ctx *ctx; 891dce93cd0SAchim Leubner struct aac_softc *sc; 8923fea9c0dSAchim Leubner int vector_no; 893dce93cd0SAchim Leubner struct aac_command *cm; 894dce93cd0SAchim Leubner struct aac_fib *fib; 895dce93cd0SAchim Leubner u_int32_t bellbits, bellbits_shifted, index, handle; 8963fea9c0dSAchim Leubner int isFastResponse, isAif, noMoreAif, mode; 897dce93cd0SAchim Leubner 8983fea9c0dSAchim Leubner ctx = (struct aac_msix_ctx *)arg; 8993fea9c0dSAchim Leubner sc = ctx->sc; 9003fea9c0dSAchim Leubner vector_no = ctx->vector_no; 901dce93cd0SAchim Leubner 902dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 903dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 9043fea9c0dSAchim Leubner 9053fea9c0dSAchim Leubner if (sc->msi_enabled) { 9063fea9c0dSAchim Leubner mode = AAC_INT_MODE_MSI; 9073fea9c0dSAchim Leubner if (vector_no == 0) { 9083fea9c0dSAchim Leubner bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_MSI); 9093fea9c0dSAchim Leubner if (bellbits & 0x40000) 9103fea9c0dSAchim Leubner mode |= AAC_INT_MODE_AIF; 9113fea9c0dSAchim Leubner else if (bellbits & 0x1000) 9123fea9c0dSAchim Leubner mode |= AAC_INT_MODE_SYNC; 9133fea9c0dSAchim Leubner } 9143fea9c0dSAchim Leubner } else { 9153fea9c0dSAchim Leubner mode = AAC_INT_MODE_INTX; 916dce93cd0SAchim Leubner bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); 917dce93cd0SAchim Leubner if (bellbits & AAC_DB_RESPONSE_SENT_NS) { 918dce93cd0SAchim Leubner bellbits = AAC_DB_RESPONSE_SENT_NS; 919dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 9203fea9c0dSAchim Leubner } else { 9213fea9c0dSAchim Leubner bellbits_shifted = (bellbits >> AAC_SRC_ODR_SHIFT); 9223fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits); 9233fea9c0dSAchim Leubner if (bellbits_shifted & AAC_DB_AIF_PENDING) 9243fea9c0dSAchim Leubner mode |= AAC_INT_MODE_AIF; 9253fea9c0dSAchim Leubner else if (bellbits_shifted & AAC_DB_SYNC_COMMAND) 9263fea9c0dSAchim Leubner mode |= AAC_INT_MODE_SYNC; 9273fea9c0dSAchim Leubner } 9283fea9c0dSAchim Leubner /* ODR readback, Prep #238630 */ 9293fea9c0dSAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R); 9303fea9c0dSAchim Leubner } 9313fea9c0dSAchim Leubner 9323fea9c0dSAchim Leubner if (mode & AAC_INT_MODE_SYNC) { 9333fea9c0dSAchim Leubner if (sc->aac_sync_cm) { 9343fea9c0dSAchim Leubner cm = sc->aac_sync_cm; 9353fea9c0dSAchim Leubner cm->cm_flags |= AAC_CMD_COMPLETED; 9363fea9c0dSAchim Leubner /* is there a completion handler? */ 9373fea9c0dSAchim Leubner if (cm->cm_complete != NULL) { 9383fea9c0dSAchim Leubner cm->cm_complete(cm); 9393fea9c0dSAchim Leubner } else { 9403fea9c0dSAchim Leubner /* assume that someone is sleeping on this command */ 9413fea9c0dSAchim Leubner wakeup(cm); 9423fea9c0dSAchim Leubner } 9433fea9c0dSAchim Leubner sc->flags &= ~AAC_QUEUE_FRZN; 9443fea9c0dSAchim Leubner sc->aac_sync_cm = NULL; 9453fea9c0dSAchim Leubner } 9463fea9c0dSAchim Leubner mode = 0; 9473fea9c0dSAchim Leubner } 9483fea9c0dSAchim Leubner 9493fea9c0dSAchim Leubner if (mode & AAC_INT_MODE_AIF) { 9503fea9c0dSAchim Leubner if (mode & AAC_INT_MODE_INTX) { 9513fea9c0dSAchim Leubner aac_request_aif(sc); 9523fea9c0dSAchim Leubner mode = 0; 9533fea9c0dSAchim Leubner } 9543fea9c0dSAchim Leubner } 9553fea9c0dSAchim Leubner 9563fea9c0dSAchim Leubner if (mode) { 957dce93cd0SAchim Leubner /* handle async. status */ 9583fea9c0dSAchim Leubner index = sc->aac_host_rrq_idx[vector_no]; 959dce93cd0SAchim Leubner for (;;) { 960dce93cd0SAchim Leubner isFastResponse = isAif = noMoreAif = 0; 961dce93cd0SAchim Leubner /* remove toggle bit (31) */ 962dce93cd0SAchim Leubner handle = (sc->aac_common->ac_host_rrq[index] & 0x7fffffff); 963dce93cd0SAchim Leubner /* check fast response bit (30) */ 964dce93cd0SAchim Leubner if (handle & 0x40000000) 965dce93cd0SAchim Leubner isFastResponse = 1; 966dce93cd0SAchim Leubner /* check AIF bit (23) */ 967dce93cd0SAchim Leubner else if (handle & 0x00800000) 968dce93cd0SAchim Leubner isAif = TRUE; 969dce93cd0SAchim Leubner handle &= 0x0000ffff; 970dce93cd0SAchim Leubner if (handle == 0) 971dce93cd0SAchim Leubner break; 972dce93cd0SAchim Leubner 973dce93cd0SAchim Leubner cm = sc->aac_commands + (handle - 1); 974dce93cd0SAchim Leubner fib = cm->cm_fib; 9753fea9c0dSAchim Leubner sc->aac_rrq_outstanding[vector_no]--; 976dce93cd0SAchim Leubner if (isAif) { 977dce93cd0SAchim Leubner noMoreAif = (fib->Header.XferState & AAC_FIBSTATE_NOMOREAIF) ? 1:0; 978dce93cd0SAchim Leubner if (!noMoreAif) 979dce93cd0SAchim Leubner aac_handle_aif(sc, fib); 980dce93cd0SAchim Leubner aac_remove_busy(cm); 981dce93cd0SAchim Leubner aacraid_release_command(cm); 982dce93cd0SAchim Leubner } else { 983dce93cd0SAchim Leubner if (isFastResponse) { 984dce93cd0SAchim Leubner fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 985dce93cd0SAchim Leubner *((u_int32_t *)(fib->data)) = ST_OK; 986dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_FASTRESP; 987dce93cd0SAchim Leubner } 988dce93cd0SAchim Leubner aac_remove_busy(cm); 989dce93cd0SAchim Leubner aac_unmap_command(cm); 990dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_COMPLETED; 991dce93cd0SAchim Leubner 992dce93cd0SAchim Leubner /* is there a completion handler? */ 993dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 994dce93cd0SAchim Leubner cm->cm_complete(cm); 995dce93cd0SAchim Leubner } else { 996dce93cd0SAchim Leubner /* assume that someone is sleeping on this command */ 997dce93cd0SAchim Leubner wakeup(cm); 998dce93cd0SAchim Leubner } 999dce93cd0SAchim Leubner sc->flags &= ~AAC_QUEUE_FRZN; 1000dce93cd0SAchim Leubner } 1001dce93cd0SAchim Leubner 1002dce93cd0SAchim Leubner sc->aac_common->ac_host_rrq[index++] = 0; 10033fea9c0dSAchim Leubner if (index == (vector_no + 1) * sc->aac_vector_cap) 10043fea9c0dSAchim Leubner index = vector_no * sc->aac_vector_cap; 10053fea9c0dSAchim Leubner sc->aac_host_rrq_idx[vector_no] = index; 1006dce93cd0SAchim Leubner 1007dce93cd0SAchim Leubner if ((isAif && !noMoreAif) || sc->aif_pending) 1008dce93cd0SAchim Leubner aac_request_aif(sc); 1009dce93cd0SAchim Leubner } 10103fea9c0dSAchim Leubner } 10113fea9c0dSAchim Leubner 10123fea9c0dSAchim Leubner if (mode & AAC_INT_MODE_AIF) { 1013dce93cd0SAchim Leubner aac_request_aif(sc); 10143fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_CLEAR_AIF_BIT); 10153fea9c0dSAchim Leubner mode = 0; 1016dce93cd0SAchim Leubner } 1017dce93cd0SAchim Leubner 1018dce93cd0SAchim Leubner /* see if we can start some more I/O */ 1019dce93cd0SAchim Leubner if ((sc->flags & AAC_QUEUE_FRZN) == 0) 1020dce93cd0SAchim Leubner aacraid_startio(sc); 1021dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 1022dce93cd0SAchim Leubner } 1023dce93cd0SAchim Leubner 1024dce93cd0SAchim Leubner /* 1025dce93cd0SAchim Leubner * Handle notification of one or more FIBs coming from the controller. 1026dce93cd0SAchim Leubner */ 1027dce93cd0SAchim Leubner static void 1028dce93cd0SAchim Leubner aac_command_thread(struct aac_softc *sc) 1029dce93cd0SAchim Leubner { 1030dce93cd0SAchim Leubner int retval; 1031dce93cd0SAchim Leubner 1032dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1033dce93cd0SAchim Leubner 1034dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 1035dce93cd0SAchim Leubner sc->aifflags = AAC_AIFFLAGS_RUNNING; 1036dce93cd0SAchim Leubner 1037dce93cd0SAchim Leubner while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1038dce93cd0SAchim Leubner 1039dce93cd0SAchim Leubner retval = 0; 1040dce93cd0SAchim Leubner if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1041dce93cd0SAchim Leubner retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1042dce93cd0SAchim Leubner "aacraid_aifthd", AAC_PERIODIC_INTERVAL * hz); 1043dce93cd0SAchim Leubner 1044dce93cd0SAchim Leubner /* 1045dce93cd0SAchim Leubner * First see if any FIBs need to be allocated. This needs 1046dce93cd0SAchim Leubner * to be called without the driver lock because contigmalloc 1047dce93cd0SAchim Leubner * will grab Giant, and would result in an LOR. 1048dce93cd0SAchim Leubner */ 1049dce93cd0SAchim Leubner if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1050dce93cd0SAchim Leubner aac_alloc_commands(sc); 1051dce93cd0SAchim Leubner sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1052dce93cd0SAchim Leubner aacraid_startio(sc); 1053dce93cd0SAchim Leubner } 1054dce93cd0SAchim Leubner 1055dce93cd0SAchim Leubner /* 1056dce93cd0SAchim Leubner * While we're here, check to see if any commands are stuck. 1057dce93cd0SAchim Leubner * This is pretty low-priority, so it's ok if it doesn't 1058dce93cd0SAchim Leubner * always fire. 1059dce93cd0SAchim Leubner */ 1060dce93cd0SAchim Leubner if (retval == EWOULDBLOCK) 1061dce93cd0SAchim Leubner aac_timeout(sc); 1062dce93cd0SAchim Leubner 1063dce93cd0SAchim Leubner /* Check the hardware printf message buffer */ 1064dce93cd0SAchim Leubner if (sc->aac_common->ac_printf[0] != 0) 1065dce93cd0SAchim Leubner aac_print_printf(sc); 1066dce93cd0SAchim Leubner } 1067dce93cd0SAchim Leubner sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1068dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 1069dce93cd0SAchim Leubner wakeup(sc->aac_dev); 1070dce93cd0SAchim Leubner 1071dce93cd0SAchim Leubner aac_kthread_exit(0); 1072dce93cd0SAchim Leubner } 1073dce93cd0SAchim Leubner 1074dce93cd0SAchim Leubner /* 1075dce93cd0SAchim Leubner * Submit a command to the controller, return when it completes. 1076dce93cd0SAchim Leubner * XXX This is very dangerous! If the card has gone out to lunch, we could 1077dce93cd0SAchim Leubner * be stuck here forever. At the same time, signals are not caught 1078dce93cd0SAchim Leubner * because there is a risk that a signal could wakeup the sleep before 1079dce93cd0SAchim Leubner * the card has a chance to complete the command. Since there is no way 1080dce93cd0SAchim Leubner * to cancel a command that is in progress, we can't protect against the 1081dce93cd0SAchim Leubner * card completing a command late and spamming the command and data 1082dce93cd0SAchim Leubner * memory. So, we are held hostage until the command completes. 1083dce93cd0SAchim Leubner */ 1084dce93cd0SAchim Leubner int 1085dce93cd0SAchim Leubner aacraid_wait_command(struct aac_command *cm) 1086dce93cd0SAchim Leubner { 1087dce93cd0SAchim Leubner struct aac_softc *sc; 1088dce93cd0SAchim Leubner int error; 1089dce93cd0SAchim Leubner 1090dce93cd0SAchim Leubner sc = cm->cm_sc; 1091dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1092dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1093dce93cd0SAchim Leubner 1094dce93cd0SAchim Leubner /* Put the command on the ready queue and get things going */ 1095dce93cd0SAchim Leubner aac_enqueue_ready(cm); 1096dce93cd0SAchim Leubner aacraid_startio(sc); 1097dce93cd0SAchim Leubner error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacraid_wait", 0); 1098dce93cd0SAchim Leubner return(error); 1099dce93cd0SAchim Leubner } 1100dce93cd0SAchim Leubner 1101dce93cd0SAchim Leubner /* 1102dce93cd0SAchim Leubner *Command Buffer Management 1103dce93cd0SAchim Leubner */ 1104dce93cd0SAchim Leubner 1105dce93cd0SAchim Leubner /* 1106dce93cd0SAchim Leubner * Allocate a command. 1107dce93cd0SAchim Leubner */ 1108dce93cd0SAchim Leubner int 1109dce93cd0SAchim Leubner aacraid_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 1110dce93cd0SAchim Leubner { 1111dce93cd0SAchim Leubner struct aac_command *cm; 1112dce93cd0SAchim Leubner 1113dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1114dce93cd0SAchim Leubner 1115dce93cd0SAchim Leubner if ((cm = aac_dequeue_free(sc)) == NULL) { 1116dce93cd0SAchim Leubner if (sc->total_fibs < sc->aac_max_fibs) { 1117dce93cd0SAchim Leubner sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1118dce93cd0SAchim Leubner wakeup(sc->aifthread); 1119dce93cd0SAchim Leubner } 1120dce93cd0SAchim Leubner return (EBUSY); 1121dce93cd0SAchim Leubner } 1122dce93cd0SAchim Leubner 1123dce93cd0SAchim Leubner *cmp = cm; 1124dce93cd0SAchim Leubner return(0); 1125dce93cd0SAchim Leubner } 1126dce93cd0SAchim Leubner 1127dce93cd0SAchim Leubner /* 1128dce93cd0SAchim Leubner * Release a command back to the freelist. 1129dce93cd0SAchim Leubner */ 1130dce93cd0SAchim Leubner void 1131dce93cd0SAchim Leubner aacraid_release_command(struct aac_command *cm) 1132dce93cd0SAchim Leubner { 1133dce93cd0SAchim Leubner struct aac_event *event; 1134dce93cd0SAchim Leubner struct aac_softc *sc; 1135dce93cd0SAchim Leubner 1136dce93cd0SAchim Leubner sc = cm->cm_sc; 1137dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1138dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1139dce93cd0SAchim Leubner 1140dce93cd0SAchim Leubner /* (re)initialize the command/FIB */ 1141dce93cd0SAchim Leubner cm->cm_sgtable = NULL; 1142dce93cd0SAchim Leubner cm->cm_flags = 0; 1143dce93cd0SAchim Leubner cm->cm_complete = NULL; 1144dce93cd0SAchim Leubner cm->cm_ccb = NULL; 1145dce93cd0SAchim Leubner cm->cm_passthr_dmat = 0; 1146dce93cd0SAchim Leubner cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 1147dce93cd0SAchim Leubner cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 1148dce93cd0SAchim Leubner cm->cm_fib->Header.Unused = 0; 1149dce93cd0SAchim Leubner cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 1150dce93cd0SAchim Leubner 1151dce93cd0SAchim Leubner /* 1152dce93cd0SAchim Leubner * These are duplicated in aac_start to cover the case where an 1153dce93cd0SAchim Leubner * intermediate stage may have destroyed them. They're left 1154dce93cd0SAchim Leubner * initialized here for debugging purposes only. 1155dce93cd0SAchim Leubner */ 1156dce93cd0SAchim Leubner cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1157dce93cd0SAchim Leubner cm->cm_fib->Header.Handle = 0; 1158dce93cd0SAchim Leubner 1159dce93cd0SAchim Leubner aac_enqueue_free(cm); 1160dce93cd0SAchim Leubner 1161dce93cd0SAchim Leubner /* 1162dce93cd0SAchim Leubner * Dequeue all events so that there's no risk of events getting 1163dce93cd0SAchim Leubner * stranded. 1164dce93cd0SAchim Leubner */ 1165dce93cd0SAchim Leubner while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 1166dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 1167dce93cd0SAchim Leubner event->ev_callback(sc, event, event->ev_arg); 1168dce93cd0SAchim Leubner } 1169dce93cd0SAchim Leubner } 1170dce93cd0SAchim Leubner 1171dce93cd0SAchim Leubner /* 1172dce93cd0SAchim Leubner * Map helper for command/FIB allocation. 1173dce93cd0SAchim Leubner */ 1174dce93cd0SAchim Leubner static void 1175dce93cd0SAchim Leubner aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1176dce93cd0SAchim Leubner { 1177dce93cd0SAchim Leubner uint64_t *fibphys; 1178dce93cd0SAchim Leubner 1179dce93cd0SAchim Leubner fibphys = (uint64_t *)arg; 1180dce93cd0SAchim Leubner 1181dce93cd0SAchim Leubner *fibphys = segs[0].ds_addr; 1182dce93cd0SAchim Leubner } 1183dce93cd0SAchim Leubner 1184dce93cd0SAchim Leubner /* 1185dce93cd0SAchim Leubner * Allocate and initialize commands/FIBs for this adapter. 1186dce93cd0SAchim Leubner */ 1187dce93cd0SAchim Leubner static int 1188dce93cd0SAchim Leubner aac_alloc_commands(struct aac_softc *sc) 1189dce93cd0SAchim Leubner { 1190dce93cd0SAchim Leubner struct aac_command *cm; 1191dce93cd0SAchim Leubner struct aac_fibmap *fm; 1192dce93cd0SAchim Leubner uint64_t fibphys; 1193dce93cd0SAchim Leubner int i, error; 1194dce93cd0SAchim Leubner u_int32_t maxsize; 1195dce93cd0SAchim Leubner 1196dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 119761722264SAndriy Gapon mtx_assert(&sc->aac_io_lock, MA_OWNED); 1198dce93cd0SAchim Leubner 1199dce93cd0SAchim Leubner if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1200dce93cd0SAchim Leubner return (ENOMEM); 1201dce93cd0SAchim Leubner 1202dce93cd0SAchim Leubner fm = malloc(sizeof(struct aac_fibmap), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1203dce93cd0SAchim Leubner if (fm == NULL) 1204dce93cd0SAchim Leubner return (ENOMEM); 1205dce93cd0SAchim Leubner 120661722264SAndriy Gapon mtx_unlock(&sc->aac_io_lock); 1207dce93cd0SAchim Leubner /* allocate the FIBs in DMAable memory and load them */ 1208dce93cd0SAchim Leubner if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1209dce93cd0SAchim Leubner BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 1210dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1211dce93cd0SAchim Leubner "Not enough contiguous memory available.\n"); 1212dce93cd0SAchim Leubner free(fm, M_AACRAIDBUF); 1213dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 1214dce93cd0SAchim Leubner return (ENOMEM); 1215dce93cd0SAchim Leubner } 1216dce93cd0SAchim Leubner 1217dce93cd0SAchim Leubner maxsize = sc->aac_max_fib_size + 31; 1218dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1219dce93cd0SAchim Leubner maxsize += sizeof(struct aac_fib_xporthdr); 1220dce93cd0SAchim Leubner /* Ignore errors since this doesn't bounce */ 1221dce93cd0SAchim Leubner (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 1222dce93cd0SAchim Leubner sc->aac_max_fibs_alloc * maxsize, 1223dce93cd0SAchim Leubner aac_map_command_helper, &fibphys, 0); 122461722264SAndriy Gapon mtx_lock(&sc->aac_io_lock); 1225dce93cd0SAchim Leubner 1226dce93cd0SAchim Leubner /* initialize constant fields in the command structure */ 1227dce93cd0SAchim Leubner bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * maxsize); 1228dce93cd0SAchim Leubner for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 1229dce93cd0SAchim Leubner cm = sc->aac_commands + sc->total_fibs; 1230dce93cd0SAchim Leubner fm->aac_commands = cm; 1231dce93cd0SAchim Leubner cm->cm_sc = sc; 1232dce93cd0SAchim Leubner cm->cm_fib = (struct aac_fib *) 1233dce93cd0SAchim Leubner ((u_int8_t *)fm->aac_fibs + i * maxsize); 1234dce93cd0SAchim Leubner cm->cm_fibphys = fibphys + i * maxsize; 1235dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1236dce93cd0SAchim Leubner u_int64_t fibphys_aligned; 1237dce93cd0SAchim Leubner fibphys_aligned = 1238dce93cd0SAchim Leubner (cm->cm_fibphys + sizeof(struct aac_fib_xporthdr) + 31) & ~31; 1239dce93cd0SAchim Leubner cm->cm_fib = (struct aac_fib *) 1240dce93cd0SAchim Leubner ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1241dce93cd0SAchim Leubner cm->cm_fibphys = fibphys_aligned; 1242dce93cd0SAchim Leubner } else { 1243dce93cd0SAchim Leubner u_int64_t fibphys_aligned; 1244dce93cd0SAchim Leubner fibphys_aligned = (cm->cm_fibphys + 31) & ~31; 1245dce93cd0SAchim Leubner cm->cm_fib = (struct aac_fib *) 1246dce93cd0SAchim Leubner ((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys)); 1247dce93cd0SAchim Leubner cm->cm_fibphys = fibphys_aligned; 1248dce93cd0SAchim Leubner } 1249dce93cd0SAchim Leubner cm->cm_index = sc->total_fibs; 1250dce93cd0SAchim Leubner 1251dce93cd0SAchim Leubner if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1252dce93cd0SAchim Leubner &cm->cm_datamap)) != 0) 1253dce93cd0SAchim Leubner break; 125461722264SAndriy Gapon if (sc->aac_max_fibs <= 1 || sc->aac_max_fibs - sc->total_fibs > 1) 1255dce93cd0SAchim Leubner aacraid_release_command(cm); 1256dce93cd0SAchim Leubner sc->total_fibs++; 1257dce93cd0SAchim Leubner } 1258dce93cd0SAchim Leubner 1259dce93cd0SAchim Leubner if (i > 0) { 1260dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1261dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1262dce93cd0SAchim Leubner return (0); 1263dce93cd0SAchim Leubner } 1264dce93cd0SAchim Leubner 1265dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1266dce93cd0SAchim Leubner bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1267dce93cd0SAchim Leubner free(fm, M_AACRAIDBUF); 1268dce93cd0SAchim Leubner return (ENOMEM); 1269dce93cd0SAchim Leubner } 1270dce93cd0SAchim Leubner 1271dce93cd0SAchim Leubner /* 1272dce93cd0SAchim Leubner * Free FIBs owned by this adapter. 1273dce93cd0SAchim Leubner */ 1274dce93cd0SAchim Leubner static void 1275dce93cd0SAchim Leubner aac_free_commands(struct aac_softc *sc) 1276dce93cd0SAchim Leubner { 1277dce93cd0SAchim Leubner struct aac_fibmap *fm; 1278dce93cd0SAchim Leubner struct aac_command *cm; 1279dce93cd0SAchim Leubner int i; 1280dce93cd0SAchim Leubner 1281dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1282dce93cd0SAchim Leubner 1283dce93cd0SAchim Leubner while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 1284dce93cd0SAchim Leubner 1285dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 1286dce93cd0SAchim Leubner /* 1287dce93cd0SAchim Leubner * We check against total_fibs to handle partially 1288dce93cd0SAchim Leubner * allocated blocks. 1289dce93cd0SAchim Leubner */ 1290dce93cd0SAchim Leubner for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1291dce93cd0SAchim Leubner cm = fm->aac_commands + i; 1292dce93cd0SAchim Leubner bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1293dce93cd0SAchim Leubner } 1294dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1295dce93cd0SAchim Leubner bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 1296dce93cd0SAchim Leubner free(fm, M_AACRAIDBUF); 1297dce93cd0SAchim Leubner } 1298dce93cd0SAchim Leubner } 1299dce93cd0SAchim Leubner 1300dce93cd0SAchim Leubner /* 1301dce93cd0SAchim Leubner * Command-mapping helper function - populate this command's s/g table. 1302dce93cd0SAchim Leubner */ 1303dce93cd0SAchim Leubner void 1304dce93cd0SAchim Leubner aacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1305dce93cd0SAchim Leubner { 1306dce93cd0SAchim Leubner struct aac_softc *sc; 1307dce93cd0SAchim Leubner struct aac_command *cm; 1308dce93cd0SAchim Leubner struct aac_fib *fib; 1309dce93cd0SAchim Leubner int i; 1310dce93cd0SAchim Leubner 1311dce93cd0SAchim Leubner cm = (struct aac_command *)arg; 1312dce93cd0SAchim Leubner sc = cm->cm_sc; 1313dce93cd0SAchim Leubner fib = cm->cm_fib; 1314dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "nseg %d", nseg); 1315dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 1316dce93cd0SAchim Leubner 1317dce93cd0SAchim Leubner /* copy into the FIB */ 1318dce93cd0SAchim Leubner if (cm->cm_sgtable != NULL) { 1319dce93cd0SAchim Leubner if (fib->Header.Command == RawIo2) { 1320dce93cd0SAchim Leubner struct aac_raw_io2 *raw; 1321dce93cd0SAchim Leubner struct aac_sge_ieee1212 *sg; 1322dce93cd0SAchim Leubner u_int32_t min_size = PAGE_SIZE, cur_size; 1323dce93cd0SAchim Leubner int conformable = TRUE; 1324dce93cd0SAchim Leubner 1325dce93cd0SAchim Leubner raw = (struct aac_raw_io2 *)&fib->data[0]; 1326dce93cd0SAchim Leubner sg = (struct aac_sge_ieee1212 *)cm->cm_sgtable; 1327dce93cd0SAchim Leubner raw->sgeCnt = nseg; 1328dce93cd0SAchim Leubner 1329dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1330dce93cd0SAchim Leubner cur_size = segs[i].ds_len; 1331dce93cd0SAchim Leubner sg[i].addrHigh = 0; 1332dce93cd0SAchim Leubner *(bus_addr_t *)&sg[i].addrLow = segs[i].ds_addr; 1333dce93cd0SAchim Leubner sg[i].length = cur_size; 1334dce93cd0SAchim Leubner sg[i].flags = 0; 1335dce93cd0SAchim Leubner if (i == 0) { 1336dce93cd0SAchim Leubner raw->sgeFirstSize = cur_size; 1337dce93cd0SAchim Leubner } else if (i == 1) { 1338dce93cd0SAchim Leubner raw->sgeNominalSize = cur_size; 1339dce93cd0SAchim Leubner min_size = cur_size; 1340dce93cd0SAchim Leubner } else if ((i+1) < nseg && 1341dce93cd0SAchim Leubner cur_size != raw->sgeNominalSize) { 1342dce93cd0SAchim Leubner conformable = FALSE; 1343dce93cd0SAchim Leubner if (cur_size < min_size) 1344dce93cd0SAchim Leubner min_size = cur_size; 1345dce93cd0SAchim Leubner } 1346dce93cd0SAchim Leubner } 1347dce93cd0SAchim Leubner 1348dce93cd0SAchim Leubner /* not conformable: evaluate required sg elements */ 1349dce93cd0SAchim Leubner if (!conformable) { 1350dce93cd0SAchim Leubner int j, err_found, nseg_new = nseg; 1351dce93cd0SAchim Leubner for (i = min_size / PAGE_SIZE; i >= 1; --i) { 1352dce93cd0SAchim Leubner err_found = FALSE; 1353dce93cd0SAchim Leubner nseg_new = 2; 1354dce93cd0SAchim Leubner for (j = 1; j < nseg - 1; ++j) { 1355dce93cd0SAchim Leubner if (sg[j].length % (i*PAGE_SIZE)) { 1356dce93cd0SAchim Leubner err_found = TRUE; 1357dce93cd0SAchim Leubner break; 1358dce93cd0SAchim Leubner } 1359dce93cd0SAchim Leubner nseg_new += (sg[j].length / (i*PAGE_SIZE)); 1360dce93cd0SAchim Leubner } 1361dce93cd0SAchim Leubner if (!err_found) 1362dce93cd0SAchim Leubner break; 1363dce93cd0SAchim Leubner } 1364dce93cd0SAchim Leubner if (i>0 && nseg_new<=sc->aac_sg_tablesize && 1365dce93cd0SAchim Leubner !(sc->hint_flags & 4)) 1366dce93cd0SAchim Leubner nseg = aac_convert_sgraw2(sc, 1367dce93cd0SAchim Leubner raw, i, nseg, nseg_new); 1368dce93cd0SAchim Leubner } else { 1369dce93cd0SAchim Leubner raw->flags |= RIO2_SGL_CONFORMANT; 1370dce93cd0SAchim Leubner } 1371dce93cd0SAchim Leubner 1372dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1373dce93cd0SAchim Leubner fib->Header.Size += nseg * 1374dce93cd0SAchim Leubner sizeof(struct aac_sge_ieee1212); 1375dce93cd0SAchim Leubner 1376dce93cd0SAchim Leubner } else if (fib->Header.Command == RawIo) { 1377dce93cd0SAchim Leubner struct aac_sg_tableraw *sg; 1378dce93cd0SAchim Leubner sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 1379dce93cd0SAchim Leubner sg->SgCount = nseg; 1380dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1381dce93cd0SAchim Leubner sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 1382dce93cd0SAchim Leubner sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 1383dce93cd0SAchim Leubner sg->SgEntryRaw[i].Next = 0; 1384dce93cd0SAchim Leubner sg->SgEntryRaw[i].Prev = 0; 1385dce93cd0SAchim Leubner sg->SgEntryRaw[i].Flags = 0; 1386dce93cd0SAchim Leubner } 1387dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1388dce93cd0SAchim Leubner fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 1389dce93cd0SAchim Leubner } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1390dce93cd0SAchim Leubner struct aac_sg_table *sg; 1391dce93cd0SAchim Leubner sg = cm->cm_sgtable; 1392dce93cd0SAchim Leubner sg->SgCount = nseg; 1393dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1394dce93cd0SAchim Leubner sg->SgEntry[i].SgAddress = segs[i].ds_addr; 1395dce93cd0SAchim Leubner sg->SgEntry[i].SgByteCount = segs[i].ds_len; 1396dce93cd0SAchim Leubner } 1397dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1398dce93cd0SAchim Leubner fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1399dce93cd0SAchim Leubner } else { 1400dce93cd0SAchim Leubner struct aac_sg_table64 *sg; 1401dce93cd0SAchim Leubner sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1402dce93cd0SAchim Leubner sg->SgCount = nseg; 1403dce93cd0SAchim Leubner for (i = 0; i < nseg; i++) { 1404dce93cd0SAchim Leubner sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1405dce93cd0SAchim Leubner sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 1406dce93cd0SAchim Leubner } 1407dce93cd0SAchim Leubner /* update the FIB size for the s/g count */ 1408dce93cd0SAchim Leubner fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1409dce93cd0SAchim Leubner } 1410dce93cd0SAchim Leubner } 1411dce93cd0SAchim Leubner 1412dce93cd0SAchim Leubner /* Fix up the address values in the FIB. Use the command array index 1413dce93cd0SAchim Leubner * instead of a pointer since these fields are only 32 bits. Shift 1414dce93cd0SAchim Leubner * the SenderFibAddress over to make room for the fast response bit 1415dce93cd0SAchim Leubner * and for the AIF bit 1416dce93cd0SAchim Leubner */ 1417dce93cd0SAchim Leubner cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 1418dce93cd0SAchim Leubner cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1419dce93cd0SAchim Leubner 1420dce93cd0SAchim Leubner /* save a pointer to the command for speedy reverse-lookup */ 1421dce93cd0SAchim Leubner cm->cm_fib->Header.Handle += cm->cm_index + 1; 1422dce93cd0SAchim Leubner 1423dce93cd0SAchim Leubner if (cm->cm_passthr_dmat == 0) { 1424dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAIN) 1425dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1426dce93cd0SAchim Leubner BUS_DMASYNC_PREREAD); 1427dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAOUT) 1428dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1429dce93cd0SAchim Leubner BUS_DMASYNC_PREWRITE); 1430dce93cd0SAchim Leubner } 1431dce93cd0SAchim Leubner 1432dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_MAPPED; 1433dce93cd0SAchim Leubner 1434dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_SYNC_MODE) { 1435dce93cd0SAchim Leubner u_int32_t wait = 0; 1436dce93cd0SAchim Leubner aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, &wait, NULL); 1437dce93cd0SAchim Leubner } else if (cm->cm_flags & AAC_CMD_WAIT) { 1438dce93cd0SAchim Leubner aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, NULL, NULL); 1439dce93cd0SAchim Leubner } else { 1440dce93cd0SAchim Leubner int count = 10000000L; 1441dce93cd0SAchim Leubner while (AAC_SEND_COMMAND(sc, cm) != 0) { 1442dce93cd0SAchim Leubner if (--count == 0) { 1443dce93cd0SAchim Leubner aac_unmap_command(cm); 1444dce93cd0SAchim Leubner sc->flags |= AAC_QUEUE_FRZN; 1445dce93cd0SAchim Leubner aac_requeue_ready(cm); 1446dce93cd0SAchim Leubner } 1447dce93cd0SAchim Leubner DELAY(5); /* wait 5 usec. */ 1448dce93cd0SAchim Leubner } 1449dce93cd0SAchim Leubner } 1450dce93cd0SAchim Leubner } 1451dce93cd0SAchim Leubner 1452dce93cd0SAchim Leubner 1453dce93cd0SAchim Leubner static int 1454dce93cd0SAchim Leubner aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw, 1455dce93cd0SAchim Leubner int pages, int nseg, int nseg_new) 1456dce93cd0SAchim Leubner { 1457dce93cd0SAchim Leubner struct aac_sge_ieee1212 *sge; 1458dce93cd0SAchim Leubner int i, j, pos; 1459dce93cd0SAchim Leubner u_int32_t addr_low; 1460dce93cd0SAchim Leubner 1461dce93cd0SAchim Leubner sge = malloc(nseg_new * sizeof(struct aac_sge_ieee1212), 1462dce93cd0SAchim Leubner M_AACRAIDBUF, M_NOWAIT|M_ZERO); 1463dce93cd0SAchim Leubner if (sge == NULL) 1464dce93cd0SAchim Leubner return nseg; 1465dce93cd0SAchim Leubner 1466dce93cd0SAchim Leubner for (i = 1, pos = 1; i < nseg - 1; ++i) { 1467dce93cd0SAchim Leubner for (j = 0; j < raw->sge[i].length / (pages*PAGE_SIZE); ++j) { 1468dce93cd0SAchim Leubner addr_low = raw->sge[i].addrLow + j * pages * PAGE_SIZE; 1469dce93cd0SAchim Leubner sge[pos].addrLow = addr_low; 1470dce93cd0SAchim Leubner sge[pos].addrHigh = raw->sge[i].addrHigh; 1471dce93cd0SAchim Leubner if (addr_low < raw->sge[i].addrLow) 1472dce93cd0SAchim Leubner sge[pos].addrHigh++; 1473dce93cd0SAchim Leubner sge[pos].length = pages * PAGE_SIZE; 1474dce93cd0SAchim Leubner sge[pos].flags = 0; 1475dce93cd0SAchim Leubner pos++; 1476dce93cd0SAchim Leubner } 1477dce93cd0SAchim Leubner } 1478dce93cd0SAchim Leubner sge[pos] = raw->sge[nseg-1]; 1479dce93cd0SAchim Leubner for (i = 1; i < nseg_new; ++i) 1480dce93cd0SAchim Leubner raw->sge[i] = sge[i]; 1481dce93cd0SAchim Leubner 1482dce93cd0SAchim Leubner free(sge, M_AACRAIDBUF); 1483dce93cd0SAchim Leubner raw->sgeCnt = nseg_new; 1484dce93cd0SAchim Leubner raw->flags |= RIO2_SGL_CONFORMANT; 1485dce93cd0SAchim Leubner raw->sgeNominalSize = pages * PAGE_SIZE; 1486dce93cd0SAchim Leubner return nseg_new; 1487dce93cd0SAchim Leubner } 1488dce93cd0SAchim Leubner 1489dce93cd0SAchim Leubner 1490dce93cd0SAchim Leubner /* 1491dce93cd0SAchim Leubner * Unmap a command from controller-visible space. 1492dce93cd0SAchim Leubner */ 1493dce93cd0SAchim Leubner static void 1494dce93cd0SAchim Leubner aac_unmap_command(struct aac_command *cm) 1495dce93cd0SAchim Leubner { 1496dce93cd0SAchim Leubner struct aac_softc *sc; 1497dce93cd0SAchim Leubner 1498dce93cd0SAchim Leubner sc = cm->cm_sc; 1499dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1500dce93cd0SAchim Leubner 1501dce93cd0SAchim Leubner if (!(cm->cm_flags & AAC_CMD_MAPPED)) 1502dce93cd0SAchim Leubner return; 1503dce93cd0SAchim Leubner 1504dce93cd0SAchim Leubner if (cm->cm_datalen != 0 && cm->cm_passthr_dmat == 0) { 1505dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAIN) 1506dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1507dce93cd0SAchim Leubner BUS_DMASYNC_POSTREAD); 1508dce93cd0SAchim Leubner if (cm->cm_flags & AAC_CMD_DATAOUT) 1509dce93cd0SAchim Leubner bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1510dce93cd0SAchim Leubner BUS_DMASYNC_POSTWRITE); 1511dce93cd0SAchim Leubner 1512dce93cd0SAchim Leubner bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 1513dce93cd0SAchim Leubner } 1514dce93cd0SAchim Leubner cm->cm_flags &= ~AAC_CMD_MAPPED; 1515dce93cd0SAchim Leubner } 1516dce93cd0SAchim Leubner 1517dce93cd0SAchim Leubner /* 1518dce93cd0SAchim Leubner * Hardware Interface 1519dce93cd0SAchim Leubner */ 1520dce93cd0SAchim Leubner 1521dce93cd0SAchim Leubner /* 1522dce93cd0SAchim Leubner * Initialize the adapter. 1523dce93cd0SAchim Leubner */ 1524dce93cd0SAchim Leubner static void 1525dce93cd0SAchim Leubner aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1526dce93cd0SAchim Leubner { 1527dce93cd0SAchim Leubner struct aac_softc *sc; 1528dce93cd0SAchim Leubner 1529dce93cd0SAchim Leubner sc = (struct aac_softc *)arg; 1530dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1531dce93cd0SAchim Leubner 1532dce93cd0SAchim Leubner sc->aac_common_busaddr = segs[0].ds_addr; 1533dce93cd0SAchim Leubner } 1534dce93cd0SAchim Leubner 1535dce93cd0SAchim Leubner static int 1536dce93cd0SAchim Leubner aac_check_firmware(struct aac_softc *sc) 1537dce93cd0SAchim Leubner { 1538dce93cd0SAchim Leubner u_int32_t code, major, minor, maxsize; 15393fea9c0dSAchim Leubner u_int32_t options = 0, atu_size = 0, status, waitCount; 1540dce93cd0SAchim Leubner time_t then; 1541dce93cd0SAchim Leubner 1542dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 15433fea9c0dSAchim Leubner 15443fea9c0dSAchim Leubner /* check if flash update is running */ 15453fea9c0dSAchim Leubner if (AAC_GET_FWSTATUS(sc) & AAC_FLASH_UPD_PENDING) { 15463fea9c0dSAchim Leubner then = time_uptime; 15473fea9c0dSAchim Leubner do { 15483fea9c0dSAchim Leubner code = AAC_GET_FWSTATUS(sc); 15493fea9c0dSAchim Leubner if (time_uptime > (then + AAC_FWUPD_TIMEOUT)) { 15503fea9c0dSAchim Leubner device_printf(sc->aac_dev, 15513fea9c0dSAchim Leubner "FATAL: controller not coming ready, " 15523fea9c0dSAchim Leubner "status %x\n", code); 15533fea9c0dSAchim Leubner return(ENXIO); 15543fea9c0dSAchim Leubner } 15553fea9c0dSAchim Leubner } while (!(code & AAC_FLASH_UPD_SUCCESS) && !(code & AAC_FLASH_UPD_FAILED)); 15563fea9c0dSAchim Leubner /* 15573fea9c0dSAchim Leubner * Delay 10 seconds. Because right now FW is doing a soft reset, 15583fea9c0dSAchim Leubner * do not read scratch pad register at this time 15593fea9c0dSAchim Leubner */ 15603fea9c0dSAchim Leubner waitCount = 10 * 10000; 15613fea9c0dSAchim Leubner while (waitCount) { 15623fea9c0dSAchim Leubner DELAY(100); /* delay 100 microseconds */ 15633fea9c0dSAchim Leubner waitCount--; 15643fea9c0dSAchim Leubner } 15653fea9c0dSAchim Leubner } 15663fea9c0dSAchim Leubner 1567dce93cd0SAchim Leubner /* 1568dce93cd0SAchim Leubner * Wait for the adapter to come ready. 1569dce93cd0SAchim Leubner */ 1570dce93cd0SAchim Leubner then = time_uptime; 1571dce93cd0SAchim Leubner do { 1572dce93cd0SAchim Leubner code = AAC_GET_FWSTATUS(sc); 1573dce93cd0SAchim Leubner if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1574dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1575dce93cd0SAchim Leubner "FATAL: controller not coming ready, " 1576dce93cd0SAchim Leubner "status %x\n", code); 1577dce93cd0SAchim Leubner return(ENXIO); 1578dce93cd0SAchim Leubner } 15793fea9c0dSAchim Leubner } while (!(code & AAC_UP_AND_RUNNING) || code == 0xffffffff); 1580dce93cd0SAchim Leubner 1581dce93cd0SAchim Leubner /* 1582dce93cd0SAchim Leubner * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1583dce93cd0SAchim Leubner * firmware version 1.x are not compatible with this driver. 1584dce93cd0SAchim Leubner */ 1585dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_PERC2QC) { 1586dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1587dce93cd0SAchim Leubner NULL, NULL)) { 1588dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1589dce93cd0SAchim Leubner "Error reading firmware version\n"); 1590dce93cd0SAchim Leubner return (EIO); 1591dce93cd0SAchim Leubner } 1592dce93cd0SAchim Leubner 1593dce93cd0SAchim Leubner /* These numbers are stored as ASCII! */ 1594dce93cd0SAchim Leubner major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1595dce93cd0SAchim Leubner minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1596dce93cd0SAchim Leubner if (major == 1) { 1597dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1598dce93cd0SAchim Leubner "Firmware version %d.%d is not supported.\n", 1599dce93cd0SAchim Leubner major, minor); 1600dce93cd0SAchim Leubner return (EINVAL); 1601dce93cd0SAchim Leubner } 1602dce93cd0SAchim Leubner } 1603dce93cd0SAchim Leubner /* 1604dce93cd0SAchim Leubner * Retrieve the capabilities/supported options word so we know what 1605dce93cd0SAchim Leubner * work-arounds to enable. Some firmware revs don't support this 1606dce93cd0SAchim Leubner * command. 1607dce93cd0SAchim Leubner */ 1608dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status, NULL)) { 1609dce93cd0SAchim Leubner if (status != AAC_SRB_STS_INVALID_REQUEST) { 1610dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1611dce93cd0SAchim Leubner "RequestAdapterInfo failed\n"); 1612dce93cd0SAchim Leubner return (EIO); 1613dce93cd0SAchim Leubner } 1614dce93cd0SAchim Leubner } else { 1615dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 1); 1616dce93cd0SAchim Leubner atu_size = AAC_GET_MAILBOX(sc, 2); 1617dce93cd0SAchim Leubner sc->supported_options = options; 1618dce93cd0SAchim Leubner 1619dce93cd0SAchim Leubner if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1620dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_NO4GB) == 0) 1621dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_4GB_WINDOW; 1622dce93cd0SAchim Leubner if (options & AAC_SUPPORTED_NONDASD) 1623dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_ENABLE_CAM; 1624dce93cd0SAchim Leubner if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1625dce93cd0SAchim Leubner && (sizeof(bus_addr_t) > 4) 1626dce93cd0SAchim Leubner && (sc->hint_flags & 0x1)) { 1627dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1628dce93cd0SAchim Leubner "Enabling 64-bit address support\n"); 1629dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_SG_64BIT; 1630dce93cd0SAchim Leubner } 1631dce93cd0SAchim Leubner if (sc->aac_if.aif_send_command) { 1632dce93cd0SAchim Leubner if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) || 1633dce93cd0SAchim Leubner (options & AAC_SUPPORTED_NEW_COMM_TYPE4)) 1634dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34; 1635dce93cd0SAchim Leubner else if (options & AAC_SUPPORTED_NEW_COMM_TYPE1) 1636dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE1; 1637dce93cd0SAchim Leubner else if (options & AAC_SUPPORTED_NEW_COMM_TYPE2) 1638dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2; 1639dce93cd0SAchim Leubner } 1640dce93cd0SAchim Leubner if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 1641dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1642dce93cd0SAchim Leubner } 1643dce93cd0SAchim Leubner 1644dce93cd0SAchim Leubner if (!(sc->flags & AAC_FLAGS_NEW_COMM)) { 1645dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Communication interface not supported!\n"); 1646dce93cd0SAchim Leubner return (ENXIO); 1647dce93cd0SAchim Leubner } 1648dce93cd0SAchim Leubner 1649dce93cd0SAchim Leubner if (sc->hint_flags & 2) { 1650dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1651dce93cd0SAchim Leubner "Sync. mode enforced by driver parameter. This will cause a significant performance decrease!\n"); 1652dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_SYNC_MODE; 1653dce93cd0SAchim Leubner } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE34) { 1654dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1655dce93cd0SAchim Leubner "Async. mode not supported by current driver, sync. mode enforced.\nPlease update driver to get full performance.\n"); 1656dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_SYNC_MODE; 1657dce93cd0SAchim Leubner } 1658dce93cd0SAchim Leubner 1659dce93cd0SAchim Leubner /* Check for broken hardware that does a lower number of commands */ 1660dce93cd0SAchim Leubner sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 1661dce93cd0SAchim Leubner 1662dce93cd0SAchim Leubner /* Remap mem. resource, if required */ 1663dce93cd0SAchim Leubner if (atu_size > rman_get_size(sc->aac_regs_res0)) { 1664dce93cd0SAchim Leubner bus_release_resource( 1665dce93cd0SAchim Leubner sc->aac_dev, SYS_RES_MEMORY, 1666dce93cd0SAchim Leubner sc->aac_regs_rid0, sc->aac_regs_res0); 1667c47476d7SJustin Hibbits sc->aac_regs_res0 = bus_alloc_resource_anywhere( 1668dce93cd0SAchim Leubner sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid0, 1669c47476d7SJustin Hibbits atu_size, RF_ACTIVE); 1670dce93cd0SAchim Leubner if (sc->aac_regs_res0 == NULL) { 1671dce93cd0SAchim Leubner sc->aac_regs_res0 = bus_alloc_resource_any( 1672dce93cd0SAchim Leubner sc->aac_dev, SYS_RES_MEMORY, 1673dce93cd0SAchim Leubner &sc->aac_regs_rid0, RF_ACTIVE); 1674dce93cd0SAchim Leubner if (sc->aac_regs_res0 == NULL) { 1675dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1676dce93cd0SAchim Leubner "couldn't allocate register window\n"); 1677dce93cd0SAchim Leubner return (ENXIO); 1678dce93cd0SAchim Leubner } 1679dce93cd0SAchim Leubner } 1680dce93cd0SAchim Leubner sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); 1681dce93cd0SAchim Leubner sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); 1682dce93cd0SAchim Leubner } 1683dce93cd0SAchim Leubner 1684dce93cd0SAchim Leubner /* Read preferred settings */ 1685dce93cd0SAchim Leubner sc->aac_max_fib_size = sizeof(struct aac_fib); 1686dce93cd0SAchim Leubner sc->aac_max_sectors = 128; /* 64KB */ 1687dce93cd0SAchim Leubner sc->aac_max_aif = 1; 1688dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_SG_64BIT) 1689dce93cd0SAchim Leubner sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1690dce93cd0SAchim Leubner - sizeof(struct aac_blockwrite64)) 1691dce93cd0SAchim Leubner / sizeof(struct aac_sg_entry64); 1692dce93cd0SAchim Leubner else 1693dce93cd0SAchim Leubner sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1694dce93cd0SAchim Leubner - sizeof(struct aac_blockwrite)) 1695dce93cd0SAchim Leubner / sizeof(struct aac_sg_entry); 1696dce93cd0SAchim Leubner 1697dce93cd0SAchim Leubner if (!aacraid_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL, NULL)) { 1698dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 1); 1699dce93cd0SAchim Leubner sc->aac_max_fib_size = (options & 0xFFFF); 1700dce93cd0SAchim Leubner sc->aac_max_sectors = (options >> 16) << 1; 1701dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 2); 1702dce93cd0SAchim Leubner sc->aac_sg_tablesize = (options >> 16); 1703dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 3); 17043fea9c0dSAchim Leubner sc->aac_max_fibs = ((options >> 16) & 0xFFFF); 17053fea9c0dSAchim Leubner if (sc->aac_max_fibs == 0 || sc->aac_hwif != AAC_HWIF_SRCV) 1706dce93cd0SAchim Leubner sc->aac_max_fibs = (options & 0xFFFF); 1707dce93cd0SAchim Leubner options = AAC_GET_MAILBOX(sc, 4); 1708dce93cd0SAchim Leubner sc->aac_max_aif = (options & 0xFFFF); 17093fea9c0dSAchim Leubner options = AAC_GET_MAILBOX(sc, 5); 17103fea9c0dSAchim Leubner sc->aac_max_msix =(sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) ? options : 0; 1711dce93cd0SAchim Leubner } 1712dce93cd0SAchim Leubner 1713dce93cd0SAchim Leubner maxsize = sc->aac_max_fib_size + 31; 1714dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) 1715dce93cd0SAchim Leubner maxsize += sizeof(struct aac_fib_xporthdr); 1716dce93cd0SAchim Leubner if (maxsize > PAGE_SIZE) { 1717dce93cd0SAchim Leubner sc->aac_max_fib_size -= (maxsize - PAGE_SIZE); 1718dce93cd0SAchim Leubner maxsize = PAGE_SIZE; 1719dce93cd0SAchim Leubner } 1720dce93cd0SAchim Leubner sc->aac_max_fibs_alloc = PAGE_SIZE / maxsize; 1721dce93cd0SAchim Leubner 1722dce93cd0SAchim Leubner if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1723dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_RAW_IO; 1724dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1725dce93cd0SAchim Leubner } 1726dce93cd0SAchim Leubner if ((sc->flags & AAC_FLAGS_RAW_IO) && 1727dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1728dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_LBA_64BIT; 1729dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1730dce93cd0SAchim Leubner } 1731dce93cd0SAchim Leubner 1732457b3426SSean Bruno #ifdef AACRAID_DEBUG 1733dce93cd0SAchim Leubner aacraid_get_fw_debug_buffer(sc); 1734457b3426SSean Bruno #endif 1735dce93cd0SAchim Leubner return (0); 1736dce93cd0SAchim Leubner } 1737dce93cd0SAchim Leubner 1738dce93cd0SAchim Leubner static int 1739dce93cd0SAchim Leubner aac_init(struct aac_softc *sc) 1740dce93cd0SAchim Leubner { 1741dce93cd0SAchim Leubner struct aac_adapter_init *ip; 17423fea9c0dSAchim Leubner int i, error; 1743dce93cd0SAchim Leubner 1744dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1745dce93cd0SAchim Leubner 1746dce93cd0SAchim Leubner /* reset rrq index */ 17473fea9c0dSAchim Leubner sc->aac_fibs_pushed_no = 0; 17483fea9c0dSAchim Leubner for (i = 0; i < sc->aac_max_msix; i++) 17493fea9c0dSAchim Leubner sc->aac_host_rrq_idx[i] = i * sc->aac_vector_cap; 1750dce93cd0SAchim Leubner 1751dce93cd0SAchim Leubner /* 1752dce93cd0SAchim Leubner * Fill in the init structure. This tells the adapter about the 1753dce93cd0SAchim Leubner * physical location of various important shared data structures. 1754dce93cd0SAchim Leubner */ 1755dce93cd0SAchim Leubner ip = &sc->aac_common->ac_init; 1756dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 1757dce93cd0SAchim Leubner if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1758dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 1759dce93cd0SAchim Leubner sc->flags |= AAC_FLAGS_RAW_IO; 1760dce93cd0SAchim Leubner } 17613fea9c0dSAchim Leubner ip->NoOfMSIXVectors = sc->aac_max_msix; 1762dce93cd0SAchim Leubner 1763dce93cd0SAchim Leubner ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1764dce93cd0SAchim Leubner offsetof(struct aac_common, ac_fibs); 1765dce93cd0SAchim Leubner ip->AdapterFibsVirtualAddress = 0; 1766dce93cd0SAchim Leubner ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 1767dce93cd0SAchim Leubner ip->AdapterFibAlign = sizeof(struct aac_fib); 1768dce93cd0SAchim Leubner 1769dce93cd0SAchim Leubner ip->PrintfBufferAddress = sc->aac_common_busaddr + 1770dce93cd0SAchim Leubner offsetof(struct aac_common, ac_printf); 1771dce93cd0SAchim Leubner ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 1772dce93cd0SAchim Leubner 1773dce93cd0SAchim Leubner /* 1774dce93cd0SAchim Leubner * The adapter assumes that pages are 4K in size, except on some 1775dce93cd0SAchim Leubner * broken firmware versions that do the page->byte conversion twice, 1776dce93cd0SAchim Leubner * therefore 'assuming' that this value is in 16MB units (2^24). 1777dce93cd0SAchim Leubner * Round up since the granularity is so high. 1778dce93cd0SAchim Leubner */ 1779dce93cd0SAchim Leubner ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 1780dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 1781dce93cd0SAchim Leubner ip->HostPhysMemPages = 1782dce93cd0SAchim Leubner (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1783dce93cd0SAchim Leubner } 1784dce93cd0SAchim Leubner ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 1785dce93cd0SAchim Leubner 1786dce93cd0SAchim Leubner ip->InitFlags = AAC_INITFLAGS_NEW_COMM_SUPPORTED; 1787dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) { 1788dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_6; 1789dce93cd0SAchim Leubner ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | 1790dce93cd0SAchim Leubner AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1791dce93cd0SAchim Leubner device_printf(sc->aac_dev, "New comm. interface type1 enabled\n"); 1792dce93cd0SAchim Leubner } else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 1793dce93cd0SAchim Leubner ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_7; 1794dce93cd0SAchim Leubner ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | 1795dce93cd0SAchim Leubner AAC_INITFLAGS_FAST_JBOD_SUPPORTED); 1796dce93cd0SAchim Leubner device_printf(sc->aac_dev, "New comm. interface type2 enabled\n"); 1797dce93cd0SAchim Leubner } 1798dce93cd0SAchim Leubner ip->MaxNumAif = sc->aac_max_aif; 1799dce93cd0SAchim Leubner ip->HostRRQ_AddrLow = 1800dce93cd0SAchim Leubner sc->aac_common_busaddr + offsetof(struct aac_common, ac_host_rrq); 1801dce93cd0SAchim Leubner /* always 32-bit address */ 1802dce93cd0SAchim Leubner ip->HostRRQ_AddrHigh = 0; 1803dce93cd0SAchim Leubner 1804dce93cd0SAchim Leubner if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) { 1805dce93cd0SAchim Leubner ip->InitFlags |= AAC_INITFLAGS_DRIVER_SUPPORTS_PM; 1806dce93cd0SAchim Leubner ip->InitFlags |= AAC_INITFLAGS_DRIVER_USES_UTC_TIME; 1807dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Power Management enabled\n"); 1808dce93cd0SAchim Leubner } 1809dce93cd0SAchim Leubner 1810dce93cd0SAchim Leubner ip->MaxIoCommands = sc->aac_max_fibs; 1811dce93cd0SAchim Leubner ip->MaxIoSize = sc->aac_max_sectors << 9; 1812dce93cd0SAchim Leubner ip->MaxFibSize = sc->aac_max_fib_size; 1813dce93cd0SAchim Leubner 1814dce93cd0SAchim Leubner /* 1815dce93cd0SAchim Leubner * Do controller-type-specific initialisation 1816dce93cd0SAchim Leubner */ 1817dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, ~0); 1818dce93cd0SAchim Leubner 1819dce93cd0SAchim Leubner /* 1820dce93cd0SAchim Leubner * Give the init structure to the controller. 1821dce93cd0SAchim Leubner */ 1822dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_INITSTRUCT, 1823dce93cd0SAchim Leubner sc->aac_common_busaddr + 1824dce93cd0SAchim Leubner offsetof(struct aac_common, ac_init), 0, 0, 0, 1825dce93cd0SAchim Leubner NULL, NULL)) { 1826dce93cd0SAchim Leubner device_printf(sc->aac_dev, 1827dce93cd0SAchim Leubner "error establishing init structure\n"); 1828dce93cd0SAchim Leubner error = EIO; 1829dce93cd0SAchim Leubner goto out; 1830dce93cd0SAchim Leubner } 1831dce93cd0SAchim Leubner 18323fea9c0dSAchim Leubner /* 18333fea9c0dSAchim Leubner * Check configuration issues 18343fea9c0dSAchim Leubner */ 18353fea9c0dSAchim Leubner if ((error = aac_check_config(sc)) != 0) 18363fea9c0dSAchim Leubner goto out; 18373fea9c0dSAchim Leubner 1838dce93cd0SAchim Leubner error = 0; 1839dce93cd0SAchim Leubner out: 1840dce93cd0SAchim Leubner return(error); 1841dce93cd0SAchim Leubner } 1842dce93cd0SAchim Leubner 18433fea9c0dSAchim Leubner static void 18443fea9c0dSAchim Leubner aac_define_int_mode(struct aac_softc *sc) 18453fea9c0dSAchim Leubner { 18463fea9c0dSAchim Leubner device_t dev; 18473fea9c0dSAchim Leubner int cap, msi_count, error = 0; 18483fea9c0dSAchim Leubner uint32_t val; 18493fea9c0dSAchim Leubner 18503fea9c0dSAchim Leubner dev = sc->aac_dev; 18513fea9c0dSAchim Leubner 18523fea9c0dSAchim Leubner /* max. vectors from AAC_MONKER_GETCOMMPREF */ 18533fea9c0dSAchim Leubner if (sc->aac_max_msix == 0) { 18543fea9c0dSAchim Leubner sc->aac_max_msix = 1; 18553fea9c0dSAchim Leubner sc->aac_vector_cap = sc->aac_max_fibs; 18563fea9c0dSAchim Leubner return; 18573fea9c0dSAchim Leubner } 18583fea9c0dSAchim Leubner 18593fea9c0dSAchim Leubner /* OS capability */ 18603fea9c0dSAchim Leubner msi_count = pci_msix_count(dev); 18613fea9c0dSAchim Leubner if (msi_count > AAC_MAX_MSIX) 18623fea9c0dSAchim Leubner msi_count = AAC_MAX_MSIX; 18633fea9c0dSAchim Leubner if (msi_count > sc->aac_max_msix) 18643fea9c0dSAchim Leubner msi_count = sc->aac_max_msix; 18653fea9c0dSAchim Leubner if (msi_count == 0 || (error = pci_alloc_msix(dev, &msi_count)) != 0) { 18663fea9c0dSAchim Leubner device_printf(dev, "alloc msix failed - msi_count=%d, err=%d; " 18673fea9c0dSAchim Leubner "will try MSI\n", msi_count, error); 18683fea9c0dSAchim Leubner pci_release_msi(dev); 18693fea9c0dSAchim Leubner } else { 18703fea9c0dSAchim Leubner sc->msi_enabled = TRUE; 18713fea9c0dSAchim Leubner device_printf(dev, "using MSI-X interrupts (%u vectors)\n", 18723fea9c0dSAchim Leubner msi_count); 18733fea9c0dSAchim Leubner } 18743fea9c0dSAchim Leubner 18753fea9c0dSAchim Leubner if (!sc->msi_enabled) { 18763fea9c0dSAchim Leubner msi_count = 1; 18773fea9c0dSAchim Leubner if ((error = pci_alloc_msi(dev, &msi_count)) != 0) { 18783fea9c0dSAchim Leubner device_printf(dev, "alloc msi failed - err=%d; " 18793fea9c0dSAchim Leubner "will use INTx\n", error); 18803fea9c0dSAchim Leubner pci_release_msi(dev); 18813fea9c0dSAchim Leubner } else { 18823fea9c0dSAchim Leubner sc->msi_enabled = TRUE; 18833fea9c0dSAchim Leubner device_printf(dev, "using MSI interrupts\n"); 18843fea9c0dSAchim Leubner } 18853fea9c0dSAchim Leubner } 18863fea9c0dSAchim Leubner 18873fea9c0dSAchim Leubner if (sc->msi_enabled) { 18883fea9c0dSAchim Leubner /* now read controller capability from PCI config. space */ 18893fea9c0dSAchim Leubner cap = aac_find_pci_capability(sc, PCIY_MSIX); 18903fea9c0dSAchim Leubner val = (cap != 0 ? pci_read_config(dev, cap + 2, 2) : 0); 18913fea9c0dSAchim Leubner if (!(val & AAC_PCI_MSI_ENABLE)) { 18923fea9c0dSAchim Leubner pci_release_msi(dev); 18933fea9c0dSAchim Leubner sc->msi_enabled = FALSE; 18943fea9c0dSAchim Leubner } 18953fea9c0dSAchim Leubner } 18963fea9c0dSAchim Leubner 18973fea9c0dSAchim Leubner if (!sc->msi_enabled) { 18983fea9c0dSAchim Leubner device_printf(dev, "using legacy interrupts\n"); 18993fea9c0dSAchim Leubner sc->aac_max_msix = 1; 19003fea9c0dSAchim Leubner } else { 19013fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_ENABLE_MSIX); 19023fea9c0dSAchim Leubner if (sc->aac_max_msix > msi_count) 19033fea9c0dSAchim Leubner sc->aac_max_msix = msi_count; 19043fea9c0dSAchim Leubner } 19053fea9c0dSAchim Leubner sc->aac_vector_cap = sc->aac_max_fibs / sc->aac_max_msix; 19063fea9c0dSAchim Leubner 19073fea9c0dSAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_DEBUG_B, "msi_enabled %d vector_cap %d max_fibs %d max_msix %d", 19083fea9c0dSAchim Leubner sc->msi_enabled,sc->aac_vector_cap, sc->aac_max_fibs, sc->aac_max_msix); 19093fea9c0dSAchim Leubner } 19103fea9c0dSAchim Leubner 19113fea9c0dSAchim Leubner static int 19123fea9c0dSAchim Leubner aac_find_pci_capability(struct aac_softc *sc, int cap) 19133fea9c0dSAchim Leubner { 19143fea9c0dSAchim Leubner device_t dev; 19153fea9c0dSAchim Leubner uint32_t status; 19163fea9c0dSAchim Leubner uint8_t ptr; 19173fea9c0dSAchim Leubner 19183fea9c0dSAchim Leubner dev = sc->aac_dev; 19193fea9c0dSAchim Leubner 19203fea9c0dSAchim Leubner status = pci_read_config(dev, PCIR_STATUS, 2); 19213fea9c0dSAchim Leubner if (!(status & PCIM_STATUS_CAPPRESENT)) 19223fea9c0dSAchim Leubner return (0); 19233fea9c0dSAchim Leubner 19243fea9c0dSAchim Leubner status = pci_read_config(dev, PCIR_HDRTYPE, 1); 19253fea9c0dSAchim Leubner switch (status & PCIM_HDRTYPE) { 19263fea9c0dSAchim Leubner case 0: 19273fea9c0dSAchim Leubner case 1: 19283fea9c0dSAchim Leubner ptr = PCIR_CAP_PTR; 19293fea9c0dSAchim Leubner break; 19303fea9c0dSAchim Leubner case 2: 19313fea9c0dSAchim Leubner ptr = PCIR_CAP_PTR_2; 19323fea9c0dSAchim Leubner break; 19333fea9c0dSAchim Leubner default: 19343fea9c0dSAchim Leubner return (0); 19353fea9c0dSAchim Leubner break; 19363fea9c0dSAchim Leubner } 19373fea9c0dSAchim Leubner ptr = pci_read_config(dev, ptr, 1); 19383fea9c0dSAchim Leubner 19393fea9c0dSAchim Leubner while (ptr != 0) { 19403fea9c0dSAchim Leubner int next, val; 19413fea9c0dSAchim Leubner next = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 19423fea9c0dSAchim Leubner val = pci_read_config(dev, ptr + PCICAP_ID, 1); 19433fea9c0dSAchim Leubner if (val == cap) 19443fea9c0dSAchim Leubner return (ptr); 19453fea9c0dSAchim Leubner ptr = next; 19463fea9c0dSAchim Leubner } 19473fea9c0dSAchim Leubner 19483fea9c0dSAchim Leubner return (0); 19493fea9c0dSAchim Leubner } 19503fea9c0dSAchim Leubner 1951dce93cd0SAchim Leubner static int 1952dce93cd0SAchim Leubner aac_setup_intr(struct aac_softc *sc) 1953dce93cd0SAchim Leubner { 19543fea9c0dSAchim Leubner int i, msi_count, rid; 19553fea9c0dSAchim Leubner struct resource *res; 19563fea9c0dSAchim Leubner void *tag; 19573fea9c0dSAchim Leubner 19583fea9c0dSAchim Leubner msi_count = sc->aac_max_msix; 19593fea9c0dSAchim Leubner rid = (sc->msi_enabled ? 1:0); 19603fea9c0dSAchim Leubner 19613fea9c0dSAchim Leubner for (i = 0; i < msi_count; i++, rid++) { 19623fea9c0dSAchim Leubner if ((res = bus_alloc_resource_any(sc->aac_dev,SYS_RES_IRQ, &rid, 19633fea9c0dSAchim Leubner RF_SHAREABLE | RF_ACTIVE)) == NULL) { 1964dce93cd0SAchim Leubner device_printf(sc->aac_dev,"can't allocate interrupt\n"); 1965dce93cd0SAchim Leubner return (EINVAL); 1966dce93cd0SAchim Leubner } 19673fea9c0dSAchim Leubner sc->aac_irq_rid[i] = rid; 19683fea9c0dSAchim Leubner sc->aac_irq[i] = res; 19693fea9c0dSAchim Leubner if (aac_bus_setup_intr(sc->aac_dev, res, 1970dce93cd0SAchim Leubner INTR_MPSAFE | INTR_TYPE_BIO, NULL, 19713fea9c0dSAchim Leubner aacraid_new_intr_type1, &sc->aac_msix[i], &tag)) { 1972dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't set up interrupt\n"); 1973dce93cd0SAchim Leubner return (EINVAL); 1974dce93cd0SAchim Leubner } 19753fea9c0dSAchim Leubner sc->aac_msix[i].vector_no = i; 19763fea9c0dSAchim Leubner sc->aac_msix[i].sc = sc; 19773fea9c0dSAchim Leubner sc->aac_intr[i] = tag; 19783fea9c0dSAchim Leubner } 19793fea9c0dSAchim Leubner 1980dce93cd0SAchim Leubner return (0); 1981dce93cd0SAchim Leubner } 1982dce93cd0SAchim Leubner 19833fea9c0dSAchim Leubner static int 19843fea9c0dSAchim Leubner aac_check_config(struct aac_softc *sc) 19853fea9c0dSAchim Leubner { 19863fea9c0dSAchim Leubner struct aac_fib *fib; 19873fea9c0dSAchim Leubner struct aac_cnt_config *ccfg; 19883fea9c0dSAchim Leubner struct aac_cf_status_hdr *cf_shdr; 19893fea9c0dSAchim Leubner int rval; 19903fea9c0dSAchim Leubner 19913fea9c0dSAchim Leubner mtx_lock(&sc->aac_io_lock); 19923fea9c0dSAchim Leubner aac_alloc_sync_fib(sc, &fib); 19933fea9c0dSAchim Leubner 19943fea9c0dSAchim Leubner ccfg = (struct aac_cnt_config *)&fib->data[0]; 19953fea9c0dSAchim Leubner bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 19963fea9c0dSAchim Leubner ccfg->Command = VM_ContainerConfig; 19973fea9c0dSAchim Leubner ccfg->CTCommand.command = CT_GET_CONFIG_STATUS; 19983fea9c0dSAchim Leubner ccfg->CTCommand.param[CNT_SIZE] = sizeof(struct aac_cf_status_hdr); 19993fea9c0dSAchim Leubner 20003fea9c0dSAchim Leubner rval = aac_sync_fib(sc, ContainerCommand, 0, fib, 20013fea9c0dSAchim Leubner sizeof (struct aac_cnt_config)); 20023fea9c0dSAchim Leubner cf_shdr = (struct aac_cf_status_hdr *)ccfg->CTCommand.data; 20033fea9c0dSAchim Leubner if (rval == 0 && ccfg->Command == ST_OK && 20043fea9c0dSAchim Leubner ccfg->CTCommand.param[0] == CT_OK) { 20053fea9c0dSAchim Leubner if (cf_shdr->action <= CFACT_PAUSE) { 20063fea9c0dSAchim Leubner bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 20073fea9c0dSAchim Leubner ccfg->Command = VM_ContainerConfig; 20083fea9c0dSAchim Leubner ccfg->CTCommand.command = CT_COMMIT_CONFIG; 20093fea9c0dSAchim Leubner 20103fea9c0dSAchim Leubner rval = aac_sync_fib(sc, ContainerCommand, 0, fib, 20113fea9c0dSAchim Leubner sizeof (struct aac_cnt_config)); 20123fea9c0dSAchim Leubner if (rval == 0 && ccfg->Command == ST_OK && 20133fea9c0dSAchim Leubner ccfg->CTCommand.param[0] == CT_OK) { 20143fea9c0dSAchim Leubner /* successful completion */ 20153fea9c0dSAchim Leubner rval = 0; 20163fea9c0dSAchim Leubner } else { 20173fea9c0dSAchim Leubner /* auto commit aborted due to error(s) */ 20183fea9c0dSAchim Leubner rval = -2; 20193fea9c0dSAchim Leubner } 20203fea9c0dSAchim Leubner } else { 20213fea9c0dSAchim Leubner /* auto commit aborted due to adapter indicating 20223fea9c0dSAchim Leubner config. issues too dangerous to auto commit */ 20233fea9c0dSAchim Leubner rval = -3; 20243fea9c0dSAchim Leubner } 20253fea9c0dSAchim Leubner } else { 20263fea9c0dSAchim Leubner /* error */ 20273fea9c0dSAchim Leubner rval = -1; 20283fea9c0dSAchim Leubner } 20293fea9c0dSAchim Leubner 20303fea9c0dSAchim Leubner aac_release_sync_fib(sc); 20313fea9c0dSAchim Leubner mtx_unlock(&sc->aac_io_lock); 20323fea9c0dSAchim Leubner return(rval); 20333fea9c0dSAchim Leubner } 20343fea9c0dSAchim Leubner 2035dce93cd0SAchim Leubner /* 2036dce93cd0SAchim Leubner * Send a synchronous command to the controller and wait for a result. 2037dce93cd0SAchim Leubner * Indicate if the controller completed the command with an error status. 2038dce93cd0SAchim Leubner */ 2039dce93cd0SAchim Leubner int 2040dce93cd0SAchim Leubner aacraid_sync_command(struct aac_softc *sc, u_int32_t command, 2041dce93cd0SAchim Leubner u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 2042dce93cd0SAchim Leubner u_int32_t *sp, u_int32_t *r1) 2043dce93cd0SAchim Leubner { 2044dce93cd0SAchim Leubner time_t then; 2045dce93cd0SAchim Leubner u_int32_t status; 2046dce93cd0SAchim Leubner 2047dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2048dce93cd0SAchim Leubner 2049dce93cd0SAchim Leubner /* populate the mailbox */ 2050dce93cd0SAchim Leubner AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 2051dce93cd0SAchim Leubner 2052dce93cd0SAchim Leubner /* ensure the sync command doorbell flag is cleared */ 20533fea9c0dSAchim Leubner if (!sc->msi_enabled) 2054dce93cd0SAchim Leubner AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 2055dce93cd0SAchim Leubner 2056dce93cd0SAchim Leubner /* then set it to signal the adapter */ 2057dce93cd0SAchim Leubner AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 2058dce93cd0SAchim Leubner 2059dce93cd0SAchim Leubner if ((command != AAC_MONKER_SYNCFIB) || (sp == NULL) || (*sp != 0)) { 2060dce93cd0SAchim Leubner /* spin waiting for the command to complete */ 2061dce93cd0SAchim Leubner then = time_uptime; 2062dce93cd0SAchim Leubner do { 20633fea9c0dSAchim Leubner if (time_uptime > (then + AAC_SYNC_TIMEOUT)) { 2064dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 2065dce93cd0SAchim Leubner return(EIO); 2066dce93cd0SAchim Leubner } 2067dce93cd0SAchim Leubner } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 2068dce93cd0SAchim Leubner 2069dce93cd0SAchim Leubner /* clear the completion flag */ 2070dce93cd0SAchim Leubner AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 2071dce93cd0SAchim Leubner 2072dce93cd0SAchim Leubner /* get the command status */ 2073dce93cd0SAchim Leubner status = AAC_GET_MAILBOX(sc, 0); 2074dce93cd0SAchim Leubner if (sp != NULL) 2075dce93cd0SAchim Leubner *sp = status; 2076dce93cd0SAchim Leubner 2077dce93cd0SAchim Leubner /* return parameter */ 2078dce93cd0SAchim Leubner if (r1 != NULL) 2079dce93cd0SAchim Leubner *r1 = AAC_GET_MAILBOX(sc, 1); 2080dce93cd0SAchim Leubner 2081dce93cd0SAchim Leubner if (status != AAC_SRB_STS_SUCCESS) 2082dce93cd0SAchim Leubner return (-1); 2083dce93cd0SAchim Leubner } 2084dce93cd0SAchim Leubner return(0); 2085dce93cd0SAchim Leubner } 2086dce93cd0SAchim Leubner 2087dce93cd0SAchim Leubner static int 2088dce93cd0SAchim Leubner aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2089dce93cd0SAchim Leubner struct aac_fib *fib, u_int16_t datasize) 2090dce93cd0SAchim Leubner { 2091dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2092dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 2093dce93cd0SAchim Leubner 2094dce93cd0SAchim Leubner if (datasize > AAC_FIB_DATASIZE) 2095dce93cd0SAchim Leubner return(EINVAL); 2096dce93cd0SAchim Leubner 2097dce93cd0SAchim Leubner /* 2098dce93cd0SAchim Leubner * Set up the sync FIB 2099dce93cd0SAchim Leubner */ 2100dce93cd0SAchim Leubner fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2101dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 2102dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY; 2103dce93cd0SAchim Leubner fib->Header.XferState |= xferstate; 2104dce93cd0SAchim Leubner fib->Header.Command = command; 2105dce93cd0SAchim Leubner fib->Header.StructType = AAC_FIBTYPE_TFIB; 2106dce93cd0SAchim Leubner fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 2107dce93cd0SAchim Leubner fib->Header.SenderSize = sizeof(struct aac_fib); 2108dce93cd0SAchim Leubner fib->Header.SenderFibAddress = 0; /* Not needed */ 2109dce93cd0SAchim Leubner fib->Header.u.ReceiverFibAddress = sc->aac_common_busaddr + 21103fea9c0dSAchim Leubner offsetof(struct aac_common, ac_sync_fib); 2111dce93cd0SAchim Leubner 2112dce93cd0SAchim Leubner /* 2113dce93cd0SAchim Leubner * Give the FIB to the controller, wait for a response. 2114dce93cd0SAchim Leubner */ 2115dce93cd0SAchim Leubner if (aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, 2116dce93cd0SAchim Leubner fib->Header.u.ReceiverFibAddress, 0, 0, 0, NULL, NULL)) { 2117dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 2118dce93cd0SAchim Leubner return(EIO); 2119dce93cd0SAchim Leubner } 2120dce93cd0SAchim Leubner 2121dce93cd0SAchim Leubner return (0); 2122dce93cd0SAchim Leubner } 2123dce93cd0SAchim Leubner 2124dce93cd0SAchim Leubner /* 2125dce93cd0SAchim Leubner * Check for commands that have been outstanding for a suspiciously long time, 2126dce93cd0SAchim Leubner * and complain about them. 2127dce93cd0SAchim Leubner */ 2128dce93cd0SAchim Leubner static void 2129dce93cd0SAchim Leubner aac_timeout(struct aac_softc *sc) 2130dce93cd0SAchim Leubner { 2131dce93cd0SAchim Leubner struct aac_command *cm; 2132dce93cd0SAchim Leubner time_t deadline; 21333fea9c0dSAchim Leubner int timedout; 2134dce93cd0SAchim Leubner 2135dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2136dce93cd0SAchim Leubner /* 2137dce93cd0SAchim Leubner * Traverse the busy command list, bitch about late commands once 2138dce93cd0SAchim Leubner * only. 2139dce93cd0SAchim Leubner */ 2140dce93cd0SAchim Leubner timedout = 0; 2141dce93cd0SAchim Leubner deadline = time_uptime - AAC_CMD_TIMEOUT; 2142dce93cd0SAchim Leubner TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 21433fea9c0dSAchim Leubner if (cm->cm_timestamp < deadline) { 2144dce93cd0SAchim Leubner device_printf(sc->aac_dev, 2145dce93cd0SAchim Leubner "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 2146dce93cd0SAchim Leubner cm, (int)(time_uptime-cm->cm_timestamp)); 2147dce93cd0SAchim Leubner AAC_PRINT_FIB(sc, cm->cm_fib); 2148dce93cd0SAchim Leubner timedout++; 2149dce93cd0SAchim Leubner } 2150dce93cd0SAchim Leubner } 2151dce93cd0SAchim Leubner 21523fea9c0dSAchim Leubner if (timedout) 2153dce93cd0SAchim Leubner aac_reset_adapter(sc); 2154dce93cd0SAchim Leubner aacraid_print_queues(sc); 2155dce93cd0SAchim Leubner } 2156dce93cd0SAchim Leubner 2157dce93cd0SAchim Leubner /* 2158dce93cd0SAchim Leubner * Interface Function Vectors 2159dce93cd0SAchim Leubner */ 2160dce93cd0SAchim Leubner 2161dce93cd0SAchim Leubner /* 2162dce93cd0SAchim Leubner * Read the current firmware status word. 2163dce93cd0SAchim Leubner */ 2164dce93cd0SAchim Leubner static int 2165dce93cd0SAchim Leubner aac_src_get_fwstatus(struct aac_softc *sc) 2166dce93cd0SAchim Leubner { 2167dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2168dce93cd0SAchim Leubner 2169dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRC_OMR)); 2170dce93cd0SAchim Leubner } 2171dce93cd0SAchim Leubner 2172dce93cd0SAchim Leubner /* 2173dce93cd0SAchim Leubner * Notify the controller of a change in a given queue 2174dce93cd0SAchim Leubner */ 2175dce93cd0SAchim Leubner static void 2176dce93cd0SAchim Leubner aac_src_qnotify(struct aac_softc *sc, int qbit) 2177dce93cd0SAchim Leubner { 2178dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2179dce93cd0SAchim Leubner 2180dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, qbit << AAC_SRC_IDR_SHIFT); 2181dce93cd0SAchim Leubner } 2182dce93cd0SAchim Leubner 2183dce93cd0SAchim Leubner /* 2184dce93cd0SAchim Leubner * Get the interrupt reason bits 2185dce93cd0SAchim Leubner */ 2186dce93cd0SAchim Leubner static int 2187dce93cd0SAchim Leubner aac_src_get_istatus(struct aac_softc *sc) 2188dce93cd0SAchim Leubner { 21893fea9c0dSAchim Leubner int val; 21903fea9c0dSAchim Leubner 2191dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2192dce93cd0SAchim Leubner 21933fea9c0dSAchim Leubner if (sc->msi_enabled) { 21943fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_MSI); 21953fea9c0dSAchim Leubner if (val & AAC_MSI_SYNC_STATUS) 21963fea9c0dSAchim Leubner val = AAC_DB_SYNC_COMMAND; 21973fea9c0dSAchim Leubner else 21983fea9c0dSAchim Leubner val = 0; 21993fea9c0dSAchim Leubner } else { 22003fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R) >> AAC_SRC_ODR_SHIFT; 22013fea9c0dSAchim Leubner } 22023fea9c0dSAchim Leubner return(val); 2203dce93cd0SAchim Leubner } 2204dce93cd0SAchim Leubner 2205dce93cd0SAchim Leubner /* 2206dce93cd0SAchim Leubner * Clear some interrupt reason bits 2207dce93cd0SAchim Leubner */ 2208dce93cd0SAchim Leubner static void 2209dce93cd0SAchim Leubner aac_src_clear_istatus(struct aac_softc *sc, int mask) 2210dce93cd0SAchim Leubner { 2211dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2212dce93cd0SAchim Leubner 22133fea9c0dSAchim Leubner if (sc->msi_enabled) { 22143fea9c0dSAchim Leubner if (mask == AAC_DB_SYNC_COMMAND) 22153fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_CLEAR_SYNC_BIT); 22163fea9c0dSAchim Leubner } else { 2217dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, mask << AAC_SRC_ODR_SHIFT); 2218dce93cd0SAchim Leubner } 22193fea9c0dSAchim Leubner } 2220dce93cd0SAchim Leubner 2221dce93cd0SAchim Leubner /* 2222dce93cd0SAchim Leubner * Populate the mailbox and set the command word 2223dce93cd0SAchim Leubner */ 2224dce93cd0SAchim Leubner static void 2225dce93cd0SAchim Leubner aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2226dce93cd0SAchim Leubner u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2227dce93cd0SAchim Leubner { 2228dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2229dce93cd0SAchim Leubner 2230dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX, command); 2231dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 4, arg0); 2232dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 8, arg1); 2233dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 12, arg2); 2234dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 16, arg3); 2235dce93cd0SAchim Leubner } 2236dce93cd0SAchim Leubner 2237dce93cd0SAchim Leubner static void 2238dce93cd0SAchim Leubner aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 2239dce93cd0SAchim Leubner u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2240dce93cd0SAchim Leubner { 2241dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2242dce93cd0SAchim Leubner 2243dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX, command); 2244dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 4, arg0); 2245dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 8, arg1); 2246dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 12, arg2); 2247dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 16, arg3); 2248dce93cd0SAchim Leubner } 2249dce93cd0SAchim Leubner 2250dce93cd0SAchim Leubner /* 2251dce93cd0SAchim Leubner * Fetch the immediate command status word 2252dce93cd0SAchim Leubner */ 2253dce93cd0SAchim Leubner static int 2254dce93cd0SAchim Leubner aac_src_get_mailbox(struct aac_softc *sc, int mb) 2255dce93cd0SAchim Leubner { 2256dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2257dce93cd0SAchim Leubner 2258dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRC_MAILBOX + (mb * 4))); 2259dce93cd0SAchim Leubner } 2260dce93cd0SAchim Leubner 2261dce93cd0SAchim Leubner static int 2262dce93cd0SAchim Leubner aac_srcv_get_mailbox(struct aac_softc *sc, int mb) 2263dce93cd0SAchim Leubner { 2264dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2265dce93cd0SAchim Leubner 2266dce93cd0SAchim Leubner return(AAC_MEM0_GETREG4(sc, AAC_SRCV_MAILBOX + (mb * 4))); 2267dce93cd0SAchim Leubner } 2268dce93cd0SAchim Leubner 2269dce93cd0SAchim Leubner /* 2270dce93cd0SAchim Leubner * Set/clear interrupt masks 2271dce93cd0SAchim Leubner */ 2272dce93cd0SAchim Leubner static void 22733fea9c0dSAchim Leubner aac_src_access_devreg(struct aac_softc *sc, int mode) 2274dce93cd0SAchim Leubner { 22753fea9c0dSAchim Leubner u_int32_t val; 2276dce93cd0SAchim Leubner 22773fea9c0dSAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 22783fea9c0dSAchim Leubner 22793fea9c0dSAchim Leubner switch (mode) { 22803fea9c0dSAchim Leubner case AAC_ENABLE_INTERRUPT: 22813fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, 22823fea9c0dSAchim Leubner (sc->msi_enabled ? AAC_INT_ENABLE_TYPE1_MSIX : 22833fea9c0dSAchim Leubner AAC_INT_ENABLE_TYPE1_INTX)); 22843fea9c0dSAchim Leubner break; 22853fea9c0dSAchim Leubner 22863fea9c0dSAchim Leubner case AAC_DISABLE_INTERRUPT: 22873fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, AAC_INT_DISABLE_ALL); 22883fea9c0dSAchim Leubner break; 22893fea9c0dSAchim Leubner 22903fea9c0dSAchim Leubner case AAC_ENABLE_MSIX: 22913fea9c0dSAchim Leubner /* set bit 6 */ 22923fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 22933fea9c0dSAchim Leubner val |= 0x40; 22943fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 22953fea9c0dSAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 22963fea9c0dSAchim Leubner /* unmask int. */ 22973fea9c0dSAchim Leubner val = PMC_ALL_INTERRUPT_BITS; 22983fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IOAR, val); 22993fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_OIMR); 23003fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, 23013fea9c0dSAchim Leubner val & (~(PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0))); 23023fea9c0dSAchim Leubner break; 23033fea9c0dSAchim Leubner 23043fea9c0dSAchim Leubner case AAC_DISABLE_MSIX: 23053fea9c0dSAchim Leubner /* reset bit 6 */ 23063fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23073fea9c0dSAchim Leubner val &= ~0x40; 23083fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 23093fea9c0dSAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23103fea9c0dSAchim Leubner break; 23113fea9c0dSAchim Leubner 23123fea9c0dSAchim Leubner case AAC_CLEAR_AIF_BIT: 23133fea9c0dSAchim Leubner /* set bit 5 */ 23143fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23153fea9c0dSAchim Leubner val |= 0x20; 23163fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 23173fea9c0dSAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23183fea9c0dSAchim Leubner break; 23193fea9c0dSAchim Leubner 23203fea9c0dSAchim Leubner case AAC_CLEAR_SYNC_BIT: 23213fea9c0dSAchim Leubner /* set bit 4 */ 23223fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23233fea9c0dSAchim Leubner val |= 0x10; 23243fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 23253fea9c0dSAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23263fea9c0dSAchim Leubner break; 23273fea9c0dSAchim Leubner 23283fea9c0dSAchim Leubner case AAC_ENABLE_INTX: 23293fea9c0dSAchim Leubner /* set bit 7 */ 23303fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23313fea9c0dSAchim Leubner val |= 0x80; 23323fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val); 23333fea9c0dSAchim Leubner AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR); 23343fea9c0dSAchim Leubner /* unmask int. */ 23353fea9c0dSAchim Leubner val = PMC_ALL_INTERRUPT_BITS; 23363fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IOAR, val); 23373fea9c0dSAchim Leubner val = AAC_MEM0_GETREG4(sc, AAC_SRC_OIMR); 23383fea9c0dSAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, 23393fea9c0dSAchim Leubner val & (~(PMC_GLOBAL_INT_BIT2))); 23403fea9c0dSAchim Leubner break; 23413fea9c0dSAchim Leubner 23423fea9c0dSAchim Leubner default: 23433fea9c0dSAchim Leubner break; 2344dce93cd0SAchim Leubner } 2345dce93cd0SAchim Leubner } 2346dce93cd0SAchim Leubner 2347dce93cd0SAchim Leubner /* 2348dce93cd0SAchim Leubner * New comm. interface: Send command functions 2349dce93cd0SAchim Leubner */ 2350dce93cd0SAchim Leubner static int 2351dce93cd0SAchim Leubner aac_src_send_command(struct aac_softc *sc, struct aac_command *cm) 2352dce93cd0SAchim Leubner { 2353dce93cd0SAchim Leubner struct aac_fib_xporthdr *pFibX; 2354dce93cd0SAchim Leubner u_int32_t fibsize, high_addr; 2355dce93cd0SAchim Leubner u_int64_t address; 2356dce93cd0SAchim Leubner 2357dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm. type1)"); 2358dce93cd0SAchim Leubner 23593fea9c0dSAchim Leubner if (sc->msi_enabled && cm->cm_fib->Header.Command != AifRequest && 23603fea9c0dSAchim Leubner sc->aac_max_msix > 1) { 23613fea9c0dSAchim Leubner u_int16_t vector_no, first_choice = 0xffff; 23623fea9c0dSAchim Leubner 23633fea9c0dSAchim Leubner vector_no = sc->aac_fibs_pushed_no % sc->aac_max_msix; 23643fea9c0dSAchim Leubner do { 23653fea9c0dSAchim Leubner vector_no += 1; 23663fea9c0dSAchim Leubner if (vector_no == sc->aac_max_msix) 23673fea9c0dSAchim Leubner vector_no = 1; 23683fea9c0dSAchim Leubner if (sc->aac_rrq_outstanding[vector_no] < 23693fea9c0dSAchim Leubner sc->aac_vector_cap) 23703fea9c0dSAchim Leubner break; 23713fea9c0dSAchim Leubner if (0xffff == first_choice) 23723fea9c0dSAchim Leubner first_choice = vector_no; 23733fea9c0dSAchim Leubner else if (vector_no == first_choice) 23743fea9c0dSAchim Leubner break; 23753fea9c0dSAchim Leubner } while (1); 23763fea9c0dSAchim Leubner if (vector_no == first_choice) 23773fea9c0dSAchim Leubner vector_no = 0; 23783fea9c0dSAchim Leubner sc->aac_rrq_outstanding[vector_no]++; 23793fea9c0dSAchim Leubner if (sc->aac_fibs_pushed_no == 0xffffffff) 23803fea9c0dSAchim Leubner sc->aac_fibs_pushed_no = 0; 23813fea9c0dSAchim Leubner else 23823fea9c0dSAchim Leubner sc->aac_fibs_pushed_no++; 23833fea9c0dSAchim Leubner 23843fea9c0dSAchim Leubner cm->cm_fib->Header.Handle += (vector_no << 16); 23853fea9c0dSAchim Leubner } 23863fea9c0dSAchim Leubner 2387dce93cd0SAchim Leubner if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 2388dce93cd0SAchim Leubner /* Calculate the amount to the fibsize bits */ 2389dce93cd0SAchim Leubner fibsize = (cm->cm_fib->Header.Size + 127) / 128 - 1; 2390dce93cd0SAchim Leubner /* Fill new FIB header */ 2391dce93cd0SAchim Leubner address = cm->cm_fibphys; 2392dce93cd0SAchim Leubner high_addr = (u_int32_t)(address >> 32); 2393dce93cd0SAchim Leubner if (high_addr == 0L) { 2394dce93cd0SAchim Leubner cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2; 2395dce93cd0SAchim Leubner cm->cm_fib->Header.u.TimeStamp = 0L; 2396dce93cd0SAchim Leubner } else { 2397dce93cd0SAchim Leubner cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2_64; 2398dce93cd0SAchim Leubner cm->cm_fib->Header.u.SenderFibAddressHigh = high_addr; 2399dce93cd0SAchim Leubner } 2400dce93cd0SAchim Leubner cm->cm_fib->Header.SenderFibAddress = (u_int32_t)address; 2401dce93cd0SAchim Leubner } else { 2402dce93cd0SAchim Leubner /* Calculate the amount to the fibsize bits */ 2403dce93cd0SAchim Leubner fibsize = (sizeof(struct aac_fib_xporthdr) + 2404dce93cd0SAchim Leubner cm->cm_fib->Header.Size + 127) / 128 - 1; 2405dce93cd0SAchim Leubner /* Fill XPORT header */ 2406dce93cd0SAchim Leubner pFibX = (struct aac_fib_xporthdr *) 2407dce93cd0SAchim Leubner ((unsigned char *)cm->cm_fib - sizeof(struct aac_fib_xporthdr)); 2408dce93cd0SAchim Leubner pFibX->Handle = cm->cm_fib->Header.Handle; 2409dce93cd0SAchim Leubner pFibX->HostAddress = cm->cm_fibphys; 2410dce93cd0SAchim Leubner pFibX->Size = cm->cm_fib->Header.Size; 2411dce93cd0SAchim Leubner address = cm->cm_fibphys - sizeof(struct aac_fib_xporthdr); 2412dce93cd0SAchim Leubner high_addr = (u_int32_t)(address >> 32); 2413dce93cd0SAchim Leubner } 2414dce93cd0SAchim Leubner 2415dce93cd0SAchim Leubner if (fibsize > 31) 2416dce93cd0SAchim Leubner fibsize = 31; 2417dce93cd0SAchim Leubner aac_enqueue_busy(cm); 2418dce93cd0SAchim Leubner if (high_addr) { 2419dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_H, high_addr); 2420dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_L, (u_int32_t)address + fibsize); 2421dce93cd0SAchim Leubner } else { 2422dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE32, (u_int32_t)address + fibsize); 2423dce93cd0SAchim Leubner } 2424dce93cd0SAchim Leubner return 0; 2425dce93cd0SAchim Leubner } 2426dce93cd0SAchim Leubner 2427dce93cd0SAchim Leubner /* 2428dce93cd0SAchim Leubner * New comm. interface: get, set outbound queue index 2429dce93cd0SAchim Leubner */ 2430dce93cd0SAchim Leubner static int 2431dce93cd0SAchim Leubner aac_src_get_outb_queue(struct aac_softc *sc) 2432dce93cd0SAchim Leubner { 2433dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2434dce93cd0SAchim Leubner 2435dce93cd0SAchim Leubner return(-1); 2436dce93cd0SAchim Leubner } 2437dce93cd0SAchim Leubner 2438dce93cd0SAchim Leubner static void 2439dce93cd0SAchim Leubner aac_src_set_outb_queue(struct aac_softc *sc, int index) 2440dce93cd0SAchim Leubner { 2441dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2442dce93cd0SAchim Leubner } 2443dce93cd0SAchim Leubner 2444dce93cd0SAchim Leubner /* 2445dce93cd0SAchim Leubner * Debugging and Diagnostics 2446dce93cd0SAchim Leubner */ 2447dce93cd0SAchim Leubner 2448dce93cd0SAchim Leubner /* 2449dce93cd0SAchim Leubner * Print some information about the controller. 2450dce93cd0SAchim Leubner */ 2451dce93cd0SAchim Leubner static void 2452dce93cd0SAchim Leubner aac_describe_controller(struct aac_softc *sc) 2453dce93cd0SAchim Leubner { 2454dce93cd0SAchim Leubner struct aac_fib *fib; 2455dce93cd0SAchim Leubner struct aac_adapter_info *info; 2456dce93cd0SAchim Leubner char *adapter_type = "Adaptec RAID controller"; 2457dce93cd0SAchim Leubner 2458dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2459dce93cd0SAchim Leubner 2460dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2461dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 2462dce93cd0SAchim Leubner 2463dce93cd0SAchim Leubner if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 2464dce93cd0SAchim Leubner fib->data[0] = 0; 2465dce93cd0SAchim Leubner if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 2466dce93cd0SAchim Leubner device_printf(sc->aac_dev, "RequestSupplementAdapterInfo failed\n"); 2467dce93cd0SAchim Leubner else { 2468dce93cd0SAchim Leubner struct aac_supplement_adapter_info *supp_info; 2469dce93cd0SAchim Leubner 2470dce93cd0SAchim Leubner supp_info = ((struct aac_supplement_adapter_info *)&fib->data[0]); 2471dce93cd0SAchim Leubner adapter_type = (char *)supp_info->AdapterTypeText; 2472dce93cd0SAchim Leubner sc->aac_feature_bits = supp_info->FeatureBits; 2473dce93cd0SAchim Leubner sc->aac_support_opt2 = supp_info->SupportedOptions2; 2474dce93cd0SAchim Leubner } 2475dce93cd0SAchim Leubner } 2476dce93cd0SAchim Leubner device_printf(sc->aac_dev, "%s, aacraid driver %d.%d.%d-%d\n", 2477dce93cd0SAchim Leubner adapter_type, 2478dce93cd0SAchim Leubner AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 2479dce93cd0SAchim Leubner AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 2480dce93cd0SAchim Leubner 2481dce93cd0SAchim Leubner fib->data[0] = 0; 2482dce93cd0SAchim Leubner if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 2483dce93cd0SAchim Leubner device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2484dce93cd0SAchim Leubner aac_release_sync_fib(sc); 2485dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2486dce93cd0SAchim Leubner return; 2487dce93cd0SAchim Leubner } 2488dce93cd0SAchim Leubner 2489dce93cd0SAchim Leubner /* save the kernel revision structure for later use */ 2490dce93cd0SAchim Leubner info = (struct aac_adapter_info *)&fib->data[0]; 2491dce93cd0SAchim Leubner sc->aac_revision = info->KernelRevision; 2492dce93cd0SAchim Leubner 2493dce93cd0SAchim Leubner if (bootverbose) { 2494dce93cd0SAchim Leubner device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2495dce93cd0SAchim Leubner "(%dMB cache, %dMB execution), %s\n", 2496dce93cd0SAchim Leubner aac_describe_code(aac_cpu_variant, info->CpuVariant), 2497dce93cd0SAchim Leubner info->ClockSpeed, info->TotalMem / (1024 * 1024), 2498dce93cd0SAchim Leubner info->BufferMem / (1024 * 1024), 2499dce93cd0SAchim Leubner info->ExecutionMem / (1024 * 1024), 2500dce93cd0SAchim Leubner aac_describe_code(aac_battery_platform, 2501dce93cd0SAchim Leubner info->batteryPlatform)); 2502dce93cd0SAchim Leubner 2503dce93cd0SAchim Leubner device_printf(sc->aac_dev, 2504dce93cd0SAchim Leubner "Kernel %d.%d-%d, Build %d, S/N %6X\n", 2505dce93cd0SAchim Leubner info->KernelRevision.external.comp.major, 2506dce93cd0SAchim Leubner info->KernelRevision.external.comp.minor, 2507dce93cd0SAchim Leubner info->KernelRevision.external.comp.dash, 2508dce93cd0SAchim Leubner info->KernelRevision.buildNumber, 2509dce93cd0SAchim Leubner (u_int32_t)(info->SerialNumber & 0xffffff)); 2510dce93cd0SAchim Leubner 2511dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Supported Options=%b\n", 2512dce93cd0SAchim Leubner sc->supported_options, 2513dce93cd0SAchim Leubner "\20" 2514dce93cd0SAchim Leubner "\1SNAPSHOT" 2515dce93cd0SAchim Leubner "\2CLUSTERS" 2516dce93cd0SAchim Leubner "\3WCACHE" 2517dce93cd0SAchim Leubner "\4DATA64" 2518dce93cd0SAchim Leubner "\5HOSTTIME" 2519dce93cd0SAchim Leubner "\6RAID50" 2520dce93cd0SAchim Leubner "\7WINDOW4GB" 2521dce93cd0SAchim Leubner "\10SCSIUPGD" 2522dce93cd0SAchim Leubner "\11SOFTERR" 2523dce93cd0SAchim Leubner "\12NORECOND" 2524dce93cd0SAchim Leubner "\13SGMAP64" 2525dce93cd0SAchim Leubner "\14ALARM" 2526dce93cd0SAchim Leubner "\15NONDASD" 2527dce93cd0SAchim Leubner "\16SCSIMGT" 2528dce93cd0SAchim Leubner "\17RAIDSCSI" 2529dce93cd0SAchim Leubner "\21ADPTINFO" 2530dce93cd0SAchim Leubner "\22NEWCOMM" 2531dce93cd0SAchim Leubner "\23ARRAY64BIT" 2532dce93cd0SAchim Leubner "\24HEATSENSOR"); 2533dce93cd0SAchim Leubner } 2534dce93cd0SAchim Leubner 2535dce93cd0SAchim Leubner aac_release_sync_fib(sc); 2536dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2537dce93cd0SAchim Leubner } 2538dce93cd0SAchim Leubner 2539dce93cd0SAchim Leubner /* 2540dce93cd0SAchim Leubner * Look up a text description of a numeric error code and return a pointer to 2541dce93cd0SAchim Leubner * same. 2542dce93cd0SAchim Leubner */ 2543dce93cd0SAchim Leubner static char * 2544dce93cd0SAchim Leubner aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 2545dce93cd0SAchim Leubner { 2546dce93cd0SAchim Leubner int i; 2547dce93cd0SAchim Leubner 2548dce93cd0SAchim Leubner for (i = 0; table[i].string != NULL; i++) 2549dce93cd0SAchim Leubner if (table[i].code == code) 2550dce93cd0SAchim Leubner return(table[i].string); 2551dce93cd0SAchim Leubner return(table[i + 1].string); 2552dce93cd0SAchim Leubner } 2553dce93cd0SAchim Leubner 2554dce93cd0SAchim Leubner /* 2555dce93cd0SAchim Leubner * Management Interface 2556dce93cd0SAchim Leubner */ 2557dce93cd0SAchim Leubner 2558dce93cd0SAchim Leubner static int 2559dce93cd0SAchim Leubner aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2560dce93cd0SAchim Leubner { 2561dce93cd0SAchim Leubner struct aac_softc *sc; 2562dce93cd0SAchim Leubner 2563dce93cd0SAchim Leubner sc = dev->si_drv1; 2564dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2565dce93cd0SAchim Leubner #if __FreeBSD_version >= 702000 2566dce93cd0SAchim Leubner device_busy(sc->aac_dev); 2567dce93cd0SAchim Leubner devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 2568dce93cd0SAchim Leubner #endif 2569dce93cd0SAchim Leubner return 0; 2570dce93cd0SAchim Leubner } 2571dce93cd0SAchim Leubner 2572dce93cd0SAchim Leubner static int 2573dce93cd0SAchim Leubner aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2574dce93cd0SAchim Leubner { 2575dce93cd0SAchim Leubner union aac_statrequest *as; 2576dce93cd0SAchim Leubner struct aac_softc *sc; 2577dce93cd0SAchim Leubner int error = 0; 2578dce93cd0SAchim Leubner 2579dce93cd0SAchim Leubner as = (union aac_statrequest *)arg; 2580dce93cd0SAchim Leubner sc = dev->si_drv1; 2581dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2582dce93cd0SAchim Leubner 2583dce93cd0SAchim Leubner switch (cmd) { 2584dce93cd0SAchim Leubner case AACIO_STATS: 2585dce93cd0SAchim Leubner switch (as->as_item) { 2586dce93cd0SAchim Leubner case AACQ_FREE: 2587dce93cd0SAchim Leubner case AACQ_READY: 2588dce93cd0SAchim Leubner case AACQ_BUSY: 2589dce93cd0SAchim Leubner bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2590dce93cd0SAchim Leubner sizeof(struct aac_qstat)); 2591dce93cd0SAchim Leubner break; 2592dce93cd0SAchim Leubner default: 2593dce93cd0SAchim Leubner error = ENOENT; 2594dce93cd0SAchim Leubner break; 2595dce93cd0SAchim Leubner } 2596dce93cd0SAchim Leubner break; 2597dce93cd0SAchim Leubner 2598dce93cd0SAchim Leubner case FSACTL_SENDFIB: 2599dce93cd0SAchim Leubner case FSACTL_SEND_LARGE_FIB: 2600dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2601dce93cd0SAchim Leubner case FSACTL_LNX_SENDFIB: 2602dce93cd0SAchim Leubner case FSACTL_LNX_SEND_LARGE_FIB: 2603dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 2604dce93cd0SAchim Leubner error = aac_ioctl_sendfib(sc, arg); 2605dce93cd0SAchim Leubner break; 2606dce93cd0SAchim Leubner case FSACTL_SEND_RAW_SRB: 2607dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2608dce93cd0SAchim Leubner case FSACTL_LNX_SEND_RAW_SRB: 2609dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2610dce93cd0SAchim Leubner error = aac_ioctl_send_raw_srb(sc, arg); 2611dce93cd0SAchim Leubner break; 2612dce93cd0SAchim Leubner case FSACTL_AIF_THREAD: 2613dce93cd0SAchim Leubner case FSACTL_LNX_AIF_THREAD: 2614dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 2615dce93cd0SAchim Leubner error = EINVAL; 2616dce93cd0SAchim Leubner break; 2617dce93cd0SAchim Leubner case FSACTL_OPEN_GET_ADAPTER_FIB: 2618dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2619dce93cd0SAchim Leubner case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 2620dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2621dce93cd0SAchim Leubner error = aac_open_aif(sc, arg); 2622dce93cd0SAchim Leubner break; 2623dce93cd0SAchim Leubner case FSACTL_GET_NEXT_ADAPTER_FIB: 2624dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2625dce93cd0SAchim Leubner case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 2626dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2627dce93cd0SAchim Leubner error = aac_getnext_aif(sc, arg); 2628dce93cd0SAchim Leubner break; 2629dce93cd0SAchim Leubner case FSACTL_CLOSE_GET_ADAPTER_FIB: 2630dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2631dce93cd0SAchim Leubner case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 2632dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2633dce93cd0SAchim Leubner error = aac_close_aif(sc, arg); 2634dce93cd0SAchim Leubner break; 2635dce93cd0SAchim Leubner case FSACTL_MINIPORT_REV_CHECK: 2636dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2637dce93cd0SAchim Leubner case FSACTL_LNX_MINIPORT_REV_CHECK: 2638dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2639dce93cd0SAchim Leubner error = aac_rev_check(sc, arg); 2640dce93cd0SAchim Leubner break; 2641dce93cd0SAchim Leubner case FSACTL_QUERY_DISK: 2642dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2643dce93cd0SAchim Leubner case FSACTL_LNX_QUERY_DISK: 2644dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 2645dce93cd0SAchim Leubner error = aac_query_disk(sc, arg); 2646dce93cd0SAchim Leubner break; 2647dce93cd0SAchim Leubner case FSACTL_DELETE_DISK: 2648dce93cd0SAchim Leubner case FSACTL_LNX_DELETE_DISK: 2649dce93cd0SAchim Leubner /* 2650dce93cd0SAchim Leubner * We don't trust the underland to tell us when to delete a 2651dce93cd0SAchim Leubner * container, rather we rely on an AIF coming from the 2652dce93cd0SAchim Leubner * controller 2653dce93cd0SAchim Leubner */ 2654dce93cd0SAchim Leubner error = 0; 2655dce93cd0SAchim Leubner break; 2656dce93cd0SAchim Leubner case FSACTL_GET_PCI_INFO: 2657dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2658dce93cd0SAchim Leubner case FSACTL_LNX_GET_PCI_INFO: 2659dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 2660dce93cd0SAchim Leubner error = aac_get_pci_info(sc, arg); 2661dce93cd0SAchim Leubner break; 2662dce93cd0SAchim Leubner case FSACTL_GET_FEATURES: 2663dce93cd0SAchim Leubner arg = *(caddr_t*)arg; 2664dce93cd0SAchim Leubner case FSACTL_LNX_GET_FEATURES: 2665dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 2666dce93cd0SAchim Leubner error = aac_supported_features(sc, arg); 2667dce93cd0SAchim Leubner break; 2668dce93cd0SAchim Leubner default: 2669dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 2670dce93cd0SAchim Leubner error = EINVAL; 2671dce93cd0SAchim Leubner break; 2672dce93cd0SAchim Leubner } 2673dce93cd0SAchim Leubner return(error); 2674dce93cd0SAchim Leubner } 2675dce93cd0SAchim Leubner 2676dce93cd0SAchim Leubner static int 2677dce93cd0SAchim Leubner aac_poll(struct cdev *dev, int poll_events, struct thread *td) 2678dce93cd0SAchim Leubner { 2679dce93cd0SAchim Leubner struct aac_softc *sc; 2680dce93cd0SAchim Leubner struct aac_fib_context *ctx; 2681dce93cd0SAchim Leubner int revents; 2682dce93cd0SAchim Leubner 2683dce93cd0SAchim Leubner sc = dev->si_drv1; 2684dce93cd0SAchim Leubner revents = 0; 2685dce93cd0SAchim Leubner 2686dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2687dce93cd0SAchim Leubner if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2688dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2689dce93cd0SAchim Leubner if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2690dce93cd0SAchim Leubner revents |= poll_events & (POLLIN | POLLRDNORM); 2691dce93cd0SAchim Leubner break; 2692dce93cd0SAchim Leubner } 2693dce93cd0SAchim Leubner } 2694dce93cd0SAchim Leubner } 2695dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2696dce93cd0SAchim Leubner 2697dce93cd0SAchim Leubner if (revents == 0) { 2698dce93cd0SAchim Leubner if (poll_events & (POLLIN | POLLRDNORM)) 2699dce93cd0SAchim Leubner selrecord(td, &sc->rcv_select); 2700dce93cd0SAchim Leubner } 2701dce93cd0SAchim Leubner 2702dce93cd0SAchim Leubner return (revents); 2703dce93cd0SAchim Leubner } 2704dce93cd0SAchim Leubner 2705dce93cd0SAchim Leubner static void 2706dce93cd0SAchim Leubner aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 2707dce93cd0SAchim Leubner { 2708dce93cd0SAchim Leubner 2709dce93cd0SAchim Leubner switch (event->ev_type) { 2710dce93cd0SAchim Leubner case AAC_EVENT_CMFREE: 2711dce93cd0SAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 2712dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, (struct aac_command **)arg)) { 2713dce93cd0SAchim Leubner aacraid_add_event(sc, event); 2714dce93cd0SAchim Leubner return; 2715dce93cd0SAchim Leubner } 2716dce93cd0SAchim Leubner free(event, M_AACRAIDBUF); 2717dce93cd0SAchim Leubner wakeup(arg); 2718dce93cd0SAchim Leubner break; 2719dce93cd0SAchim Leubner default: 2720dce93cd0SAchim Leubner break; 2721dce93cd0SAchim Leubner } 2722dce93cd0SAchim Leubner } 2723dce93cd0SAchim Leubner 2724dce93cd0SAchim Leubner /* 2725dce93cd0SAchim Leubner * Send a FIB supplied from userspace 2726dce93cd0SAchim Leubner */ 2727dce93cd0SAchim Leubner static int 2728dce93cd0SAchim Leubner aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 2729dce93cd0SAchim Leubner { 2730dce93cd0SAchim Leubner struct aac_command *cm; 2731dce93cd0SAchim Leubner int size, error; 2732dce93cd0SAchim Leubner 2733dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2734dce93cd0SAchim Leubner 2735dce93cd0SAchim Leubner cm = NULL; 2736dce93cd0SAchim Leubner 2737dce93cd0SAchim Leubner /* 2738dce93cd0SAchim Leubner * Get a command 2739dce93cd0SAchim Leubner */ 2740dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2741dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 2742dce93cd0SAchim Leubner struct aac_event *event; 2743dce93cd0SAchim Leubner 2744dce93cd0SAchim Leubner event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2745dce93cd0SAchim Leubner M_NOWAIT | M_ZERO); 2746dce93cd0SAchim Leubner if (event == NULL) { 2747dce93cd0SAchim Leubner error = EBUSY; 2748dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2749dce93cd0SAchim Leubner goto out; 2750dce93cd0SAchim Leubner } 2751dce93cd0SAchim Leubner event->ev_type = AAC_EVENT_CMFREE; 2752dce93cd0SAchim Leubner event->ev_callback = aac_ioctl_event; 2753dce93cd0SAchim Leubner event->ev_arg = &cm; 2754dce93cd0SAchim Leubner aacraid_add_event(sc, event); 2755dce93cd0SAchim Leubner msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsfib", 0); 2756dce93cd0SAchim Leubner } 2757dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2758dce93cd0SAchim Leubner 2759dce93cd0SAchim Leubner /* 2760dce93cd0SAchim Leubner * Fetch the FIB header, then re-copy to get data as well. 2761dce93cd0SAchim Leubner */ 2762dce93cd0SAchim Leubner if ((error = copyin(ufib, cm->cm_fib, 2763dce93cd0SAchim Leubner sizeof(struct aac_fib_header))) != 0) 2764dce93cd0SAchim Leubner goto out; 2765dce93cd0SAchim Leubner size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 2766dce93cd0SAchim Leubner if (size > sc->aac_max_fib_size) { 2767dce93cd0SAchim Leubner device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 2768dce93cd0SAchim Leubner size, sc->aac_max_fib_size); 2769dce93cd0SAchim Leubner size = sc->aac_max_fib_size; 2770dce93cd0SAchim Leubner } 2771dce93cd0SAchim Leubner if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 2772dce93cd0SAchim Leubner goto out; 2773dce93cd0SAchim Leubner cm->cm_fib->Header.Size = size; 2774dce93cd0SAchim Leubner cm->cm_timestamp = time_uptime; 2775dce93cd0SAchim Leubner cm->cm_datalen = 0; 2776dce93cd0SAchim Leubner 2777dce93cd0SAchim Leubner /* 2778dce93cd0SAchim Leubner * Pass the FIB to the controller, wait for it to complete. 2779dce93cd0SAchim Leubner */ 2780dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2781dce93cd0SAchim Leubner error = aacraid_wait_command(cm); 2782dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2783dce93cd0SAchim Leubner if (error != 0) { 2784dce93cd0SAchim Leubner device_printf(sc->aac_dev, 2785dce93cd0SAchim Leubner "aacraid_wait_command return %d\n", error); 2786dce93cd0SAchim Leubner goto out; 2787dce93cd0SAchim Leubner } 2788dce93cd0SAchim Leubner 2789dce93cd0SAchim Leubner /* 2790dce93cd0SAchim Leubner * Copy the FIB and data back out to the caller. 2791dce93cd0SAchim Leubner */ 2792dce93cd0SAchim Leubner size = cm->cm_fib->Header.Size; 2793dce93cd0SAchim Leubner if (size > sc->aac_max_fib_size) { 2794dce93cd0SAchim Leubner device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 2795dce93cd0SAchim Leubner size, sc->aac_max_fib_size); 2796dce93cd0SAchim Leubner size = sc->aac_max_fib_size; 2797dce93cd0SAchim Leubner } 2798dce93cd0SAchim Leubner error = copyout(cm->cm_fib, ufib, size); 2799dce93cd0SAchim Leubner 2800dce93cd0SAchim Leubner out: 2801dce93cd0SAchim Leubner if (cm != NULL) { 2802dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2803dce93cd0SAchim Leubner aacraid_release_command(cm); 2804dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2805dce93cd0SAchim Leubner } 2806dce93cd0SAchim Leubner return(error); 2807dce93cd0SAchim Leubner } 2808dce93cd0SAchim Leubner 2809dce93cd0SAchim Leubner /* 2810dce93cd0SAchim Leubner * Send a passthrough FIB supplied from userspace 2811dce93cd0SAchim Leubner */ 2812dce93cd0SAchim Leubner static int 2813dce93cd0SAchim Leubner aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 2814dce93cd0SAchim Leubner { 2815dce93cd0SAchim Leubner struct aac_command *cm; 2816dce93cd0SAchim Leubner struct aac_fib *fib; 2817dce93cd0SAchim Leubner struct aac_srb *srbcmd; 2818dce93cd0SAchim Leubner struct aac_srb *user_srb = (struct aac_srb *)arg; 2819dce93cd0SAchim Leubner void *user_reply; 2820dce93cd0SAchim Leubner int error, transfer_data = 0; 2821dce93cd0SAchim Leubner bus_dmamap_t orig_map = 0; 2822dce93cd0SAchim Leubner u_int32_t fibsize = 0; 2823dce93cd0SAchim Leubner u_int64_t srb_sg_address; 2824dce93cd0SAchim Leubner u_int32_t srb_sg_bytecount; 2825dce93cd0SAchim Leubner 2826dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2827dce93cd0SAchim Leubner 2828dce93cd0SAchim Leubner cm = NULL; 2829dce93cd0SAchim Leubner 2830dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2831dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 2832dce93cd0SAchim Leubner struct aac_event *event; 2833dce93cd0SAchim Leubner 2834dce93cd0SAchim Leubner event = malloc(sizeof(struct aac_event), M_AACRAIDBUF, 2835dce93cd0SAchim Leubner M_NOWAIT | M_ZERO); 2836dce93cd0SAchim Leubner if (event == NULL) { 2837dce93cd0SAchim Leubner error = EBUSY; 2838dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2839dce93cd0SAchim Leubner goto out; 2840dce93cd0SAchim Leubner } 2841dce93cd0SAchim Leubner event->ev_type = AAC_EVENT_CMFREE; 2842dce93cd0SAchim Leubner event->ev_callback = aac_ioctl_event; 2843dce93cd0SAchim Leubner event->ev_arg = &cm; 2844dce93cd0SAchim Leubner aacraid_add_event(sc, event); 2845dce93cd0SAchim Leubner msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsraw", 0); 2846dce93cd0SAchim Leubner } 2847dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2848dce93cd0SAchim Leubner 2849dce93cd0SAchim Leubner cm->cm_data = NULL; 2850dce93cd0SAchim Leubner /* save original dma map */ 2851dce93cd0SAchim Leubner orig_map = cm->cm_datamap; 2852dce93cd0SAchim Leubner 2853dce93cd0SAchim Leubner fib = cm->cm_fib; 2854dce93cd0SAchim Leubner srbcmd = (struct aac_srb *)fib->data; 2855dce93cd0SAchim Leubner if ((error = copyin((void *)&user_srb->data_len, &fibsize, 2856dce93cd0SAchim Leubner sizeof (u_int32_t)) != 0)) 2857dce93cd0SAchim Leubner goto out; 2858dce93cd0SAchim Leubner if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) { 2859dce93cd0SAchim Leubner error = EINVAL; 2860dce93cd0SAchim Leubner goto out; 2861dce93cd0SAchim Leubner } 2862dce93cd0SAchim Leubner if ((error = copyin((void *)user_srb, srbcmd, fibsize) != 0)) 2863dce93cd0SAchim Leubner goto out; 2864dce93cd0SAchim Leubner 2865dce93cd0SAchim Leubner srbcmd->function = 0; /* SRBF_ExecuteScsi */ 2866dce93cd0SAchim Leubner srbcmd->retry_limit = 0; /* obsolete */ 2867dce93cd0SAchim Leubner 2868dce93cd0SAchim Leubner /* only one sg element from userspace supported */ 2869dce93cd0SAchim Leubner if (srbcmd->sg_map.SgCount > 1) { 2870dce93cd0SAchim Leubner error = EINVAL; 2871dce93cd0SAchim Leubner goto out; 2872dce93cd0SAchim Leubner } 2873dce93cd0SAchim Leubner /* check fibsize */ 2874dce93cd0SAchim Leubner if (fibsize == (sizeof(struct aac_srb) + 2875dce93cd0SAchim Leubner srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 2876dce93cd0SAchim Leubner struct aac_sg_entry *sgp = srbcmd->sg_map.SgEntry; 2877f4a18258SSean Bruno struct aac_sg_entry sg; 2878f4a18258SSean Bruno 2879f4a18258SSean Bruno if ((error = copyin(sgp, &sg, sizeof(sg))) != 0) 2880f4a18258SSean Bruno goto out; 2881f4a18258SSean Bruno 2882f4a18258SSean Bruno srb_sg_bytecount = sg.SgByteCount; 2883f4a18258SSean Bruno srb_sg_address = (u_int64_t)sg.SgAddress; 2884dce93cd0SAchim Leubner } else if (fibsize == (sizeof(struct aac_srb) + 2885dce93cd0SAchim Leubner srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 2886dceba9b5SMarcel Moolenaar #ifdef __LP64__ 2887dce93cd0SAchim Leubner struct aac_sg_entry64 *sgp = 2888dce93cd0SAchim Leubner (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 2889f4a18258SSean Bruno struct aac_sg_entry64 sg; 2890f4a18258SSean Bruno 2891f4a18258SSean Bruno if ((error = copyin(sgp, &sg, sizeof(sg))) != 0) 2892f4a18258SSean Bruno goto out; 2893f4a18258SSean Bruno 2894f4a18258SSean Bruno srb_sg_bytecount = sg.SgByteCount; 2895f4a18258SSean Bruno srb_sg_address = sg.SgAddress; 2896dce93cd0SAchim Leubner if (srb_sg_address > 0xffffffffull && 2897dce93cd0SAchim Leubner !(sc->flags & AAC_FLAGS_SG_64BIT)) 2898dce93cd0SAchim Leubner #endif 2899dce93cd0SAchim Leubner { 2900dce93cd0SAchim Leubner error = EINVAL; 2901dce93cd0SAchim Leubner goto out; 2902dce93cd0SAchim Leubner } 2903dce93cd0SAchim Leubner } else { 2904dce93cd0SAchim Leubner error = EINVAL; 2905dce93cd0SAchim Leubner goto out; 2906dce93cd0SAchim Leubner } 2907dce93cd0SAchim Leubner user_reply = (char *)arg + fibsize; 2908dce93cd0SAchim Leubner srbcmd->data_len = srb_sg_bytecount; 2909dce93cd0SAchim Leubner if (srbcmd->sg_map.SgCount == 1) 2910dce93cd0SAchim Leubner transfer_data = 1; 2911dce93cd0SAchim Leubner 2912dce93cd0SAchim Leubner if (transfer_data) { 2913dce93cd0SAchim Leubner /* 2914dce93cd0SAchim Leubner * Create DMA tag for the passthr. data buffer and allocate it. 2915dce93cd0SAchim Leubner */ 2916dce93cd0SAchim Leubner if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 2917dce93cd0SAchim Leubner 1, 0, /* algnmnt, boundary */ 2918dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_SG_64BIT) ? 2919dce93cd0SAchim Leubner BUS_SPACE_MAXADDR_32BIT : 2920dce93cd0SAchim Leubner 0x7fffffff, /* lowaddr */ 2921dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 2922dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 2923dce93cd0SAchim Leubner srb_sg_bytecount, /* size */ 2924dce93cd0SAchim Leubner sc->aac_sg_tablesize, /* nsegments */ 2925dce93cd0SAchim Leubner srb_sg_bytecount, /* maxsegsize */ 2926dce93cd0SAchim Leubner 0, /* flags */ 2927dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 2928dce93cd0SAchim Leubner &cm->cm_passthr_dmat)) { 2929dce93cd0SAchim Leubner error = ENOMEM; 2930dce93cd0SAchim Leubner goto out; 2931dce93cd0SAchim Leubner } 2932dce93cd0SAchim Leubner if (bus_dmamem_alloc(cm->cm_passthr_dmat, (void **)&cm->cm_data, 2933dce93cd0SAchim Leubner BUS_DMA_NOWAIT, &cm->cm_datamap)) { 2934dce93cd0SAchim Leubner error = ENOMEM; 2935dce93cd0SAchim Leubner goto out; 2936dce93cd0SAchim Leubner } 2937dce93cd0SAchim Leubner /* fill some cm variables */ 2938dce93cd0SAchim Leubner cm->cm_datalen = srb_sg_bytecount; 2939dce93cd0SAchim Leubner if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 2940dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_DATAIN; 2941dce93cd0SAchim Leubner if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) 2942dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_DATAOUT; 2943dce93cd0SAchim Leubner 2944dce93cd0SAchim Leubner if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 2945dceba9b5SMarcel Moolenaar if ((error = copyin((void *)(uintptr_t)srb_sg_address, 2946dce93cd0SAchim Leubner cm->cm_data, cm->cm_datalen)) != 0) 2947dce93cd0SAchim Leubner goto out; 2948dce93cd0SAchim Leubner /* sync required for bus_dmamem_alloc() alloc. mem.? */ 2949dce93cd0SAchim Leubner bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2950dce93cd0SAchim Leubner BUS_DMASYNC_PREWRITE); 2951dce93cd0SAchim Leubner } 2952dce93cd0SAchim Leubner } 2953dce93cd0SAchim Leubner 2954dce93cd0SAchim Leubner /* build the FIB */ 2955dce93cd0SAchim Leubner fib->Header.Size = sizeof(struct aac_fib_header) + 2956dce93cd0SAchim Leubner sizeof(struct aac_srb); 2957dce93cd0SAchim Leubner fib->Header.XferState = 2958dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 2959dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 2960dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 2961dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 2962dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 2963dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 2964dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC; 2965dce93cd0SAchim Leubner 2966dce93cd0SAchim Leubner fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? 2967dce93cd0SAchim Leubner ScsiPortCommandU64 : ScsiPortCommand; 2968dce93cd0SAchim Leubner cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 2969dce93cd0SAchim Leubner 2970dce93cd0SAchim Leubner /* send command */ 2971dce93cd0SAchim Leubner if (transfer_data) { 2972dce93cd0SAchim Leubner bus_dmamap_load(cm->cm_passthr_dmat, 2973dce93cd0SAchim Leubner cm->cm_datamap, cm->cm_data, 2974dce93cd0SAchim Leubner cm->cm_datalen, 2975dce93cd0SAchim Leubner aacraid_map_command_sg, cm, 0); 2976dce93cd0SAchim Leubner } else { 2977dce93cd0SAchim Leubner aacraid_map_command_sg(cm, NULL, 0, 0); 2978dce93cd0SAchim Leubner } 2979dce93cd0SAchim Leubner 2980dce93cd0SAchim Leubner /* wait for completion */ 2981dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 2982dce93cd0SAchim Leubner while (!(cm->cm_flags & AAC_CMD_COMPLETED)) 2983dce93cd0SAchim Leubner msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsrw2", 0); 2984dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 2985dce93cd0SAchim Leubner 2986dce93cd0SAchim Leubner /* copy data */ 2987dce93cd0SAchim Leubner if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)) { 2988dce93cd0SAchim Leubner if ((error = copyout(cm->cm_data, 2989dceba9b5SMarcel Moolenaar (void *)(uintptr_t)srb_sg_address, 2990dce93cd0SAchim Leubner cm->cm_datalen)) != 0) 2991dce93cd0SAchim Leubner goto out; 2992dce93cd0SAchim Leubner /* sync required for bus_dmamem_alloc() allocated mem.? */ 2993dce93cd0SAchim Leubner bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap, 2994dce93cd0SAchim Leubner BUS_DMASYNC_POSTREAD); 2995dce93cd0SAchim Leubner } 2996dce93cd0SAchim Leubner 2997dce93cd0SAchim Leubner /* status */ 2998dce93cd0SAchim Leubner error = copyout(fib->data, user_reply, sizeof(struct aac_srb_response)); 2999dce93cd0SAchim Leubner 3000dce93cd0SAchim Leubner out: 3001dce93cd0SAchim Leubner if (cm && cm->cm_data) { 3002dce93cd0SAchim Leubner if (transfer_data) 3003dce93cd0SAchim Leubner bus_dmamap_unload(cm->cm_passthr_dmat, cm->cm_datamap); 3004dce93cd0SAchim Leubner bus_dmamem_free(cm->cm_passthr_dmat, cm->cm_data, cm->cm_datamap); 3005dce93cd0SAchim Leubner cm->cm_datamap = orig_map; 3006dce93cd0SAchim Leubner } 3007dce93cd0SAchim Leubner if (cm && cm->cm_passthr_dmat) 3008dce93cd0SAchim Leubner bus_dma_tag_destroy(cm->cm_passthr_dmat); 3009dce93cd0SAchim Leubner if (cm) { 3010dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3011dce93cd0SAchim Leubner aacraid_release_command(cm); 3012dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3013dce93cd0SAchim Leubner } 3014dce93cd0SAchim Leubner return(error); 3015dce93cd0SAchim Leubner } 3016dce93cd0SAchim Leubner 3017dce93cd0SAchim Leubner /* 3018dce93cd0SAchim Leubner * Request an AIF from the controller (new comm. type1) 3019dce93cd0SAchim Leubner */ 3020dce93cd0SAchim Leubner static void 3021dce93cd0SAchim Leubner aac_request_aif(struct aac_softc *sc) 3022dce93cd0SAchim Leubner { 3023dce93cd0SAchim Leubner struct aac_command *cm; 3024dce93cd0SAchim Leubner struct aac_fib *fib; 3025dce93cd0SAchim Leubner 3026dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3027dce93cd0SAchim Leubner 3028dce93cd0SAchim Leubner if (aacraid_alloc_command(sc, &cm)) { 3029dce93cd0SAchim Leubner sc->aif_pending = 1; 3030dce93cd0SAchim Leubner return; 3031dce93cd0SAchim Leubner } 3032dce93cd0SAchim Leubner sc->aif_pending = 0; 3033dce93cd0SAchim Leubner 3034dce93cd0SAchim Leubner /* build the FIB */ 3035dce93cd0SAchim Leubner fib = cm->cm_fib; 3036dce93cd0SAchim Leubner fib->Header.Size = sizeof(struct aac_fib); 3037dce93cd0SAchim Leubner fib->Header.XferState = 3038dce93cd0SAchim Leubner AAC_FIBSTATE_HOSTOWNED | 3039dce93cd0SAchim Leubner AAC_FIBSTATE_INITIALISED | 3040dce93cd0SAchim Leubner AAC_FIBSTATE_EMPTY | 3041dce93cd0SAchim Leubner AAC_FIBSTATE_FROMHOST | 3042dce93cd0SAchim Leubner AAC_FIBSTATE_REXPECTED | 3043dce93cd0SAchim Leubner AAC_FIBSTATE_NORM | 3044dce93cd0SAchim Leubner AAC_FIBSTATE_ASYNC; 3045dce93cd0SAchim Leubner /* set AIF marker */ 3046dce93cd0SAchim Leubner fib->Header.Handle = 0x00800000; 3047dce93cd0SAchim Leubner fib->Header.Command = AifRequest; 3048dce93cd0SAchim Leubner ((struct aac_aif_command *)fib->data)->command = AifReqEvent; 3049dce93cd0SAchim Leubner 3050dce93cd0SAchim Leubner aacraid_map_command_sg(cm, NULL, 0, 0); 3051dce93cd0SAchim Leubner } 3052dce93cd0SAchim Leubner 3053dce93cd0SAchim Leubner 3054dce93cd0SAchim Leubner #if __FreeBSD_version >= 702000 3055dce93cd0SAchim Leubner /* 3056dce93cd0SAchim Leubner * cdevpriv interface private destructor. 3057dce93cd0SAchim Leubner */ 3058dce93cd0SAchim Leubner static void 3059dce93cd0SAchim Leubner aac_cdevpriv_dtor(void *arg) 3060dce93cd0SAchim Leubner { 3061dce93cd0SAchim Leubner struct aac_softc *sc; 3062dce93cd0SAchim Leubner 3063dce93cd0SAchim Leubner sc = arg; 3064dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3065dce93cd0SAchim Leubner mtx_lock(&Giant); 3066dce93cd0SAchim Leubner device_unbusy(sc->aac_dev); 3067dce93cd0SAchim Leubner mtx_unlock(&Giant); 3068dce93cd0SAchim Leubner } 3069dce93cd0SAchim Leubner #else 3070dce93cd0SAchim Leubner static int 3071dce93cd0SAchim Leubner aac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 3072dce93cd0SAchim Leubner { 3073dce93cd0SAchim Leubner struct aac_softc *sc; 3074dce93cd0SAchim Leubner 3075dce93cd0SAchim Leubner sc = dev->si_drv1; 3076dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3077dce93cd0SAchim Leubner return 0; 3078dce93cd0SAchim Leubner } 3079dce93cd0SAchim Leubner #endif 3080dce93cd0SAchim Leubner 3081dce93cd0SAchim Leubner /* 3082dce93cd0SAchim Leubner * Handle an AIF sent to us by the controller; queue it for later reference. 3083dce93cd0SAchim Leubner * If the queue fills up, then drop the older entries. 3084dce93cd0SAchim Leubner */ 3085dce93cd0SAchim Leubner static void 3086dce93cd0SAchim Leubner aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 3087dce93cd0SAchim Leubner { 3088dce93cd0SAchim Leubner struct aac_aif_command *aif; 3089dce93cd0SAchim Leubner struct aac_container *co, *co_next; 3090dce93cd0SAchim Leubner struct aac_fib_context *ctx; 3091dce93cd0SAchim Leubner struct aac_fib *sync_fib; 3092dce93cd0SAchim Leubner struct aac_mntinforesp mir; 3093dce93cd0SAchim Leubner int next, current, found; 3094dce93cd0SAchim Leubner int count = 0, changed = 0, i = 0; 3095dce93cd0SAchim Leubner u_int32_t channel, uid; 3096dce93cd0SAchim Leubner 3097dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3098dce93cd0SAchim Leubner 3099dce93cd0SAchim Leubner aif = (struct aac_aif_command*)&fib->data[0]; 3100dce93cd0SAchim Leubner aacraid_print_aif(sc, aif); 3101dce93cd0SAchim Leubner 3102dce93cd0SAchim Leubner /* Is it an event that we should care about? */ 3103dce93cd0SAchim Leubner switch (aif->command) { 3104dce93cd0SAchim Leubner case AifCmdEventNotify: 3105dce93cd0SAchim Leubner switch (aif->data.EN.type) { 3106dce93cd0SAchim Leubner case AifEnAddContainer: 3107dce93cd0SAchim Leubner case AifEnDeleteContainer: 3108dce93cd0SAchim Leubner /* 3109dce93cd0SAchim Leubner * A container was added or deleted, but the message 3110dce93cd0SAchim Leubner * doesn't tell us anything else! Re-enumerate the 3111dce93cd0SAchim Leubner * containers and sort things out. 3112dce93cd0SAchim Leubner */ 3113dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &sync_fib); 3114dce93cd0SAchim Leubner do { 3115dce93cd0SAchim Leubner /* 3116dce93cd0SAchim Leubner * Ask the controller for its containers one at 3117dce93cd0SAchim Leubner * a time. 3118dce93cd0SAchim Leubner * XXX What if the controller's list changes 3119dce93cd0SAchim Leubner * midway through this enumaration? 3120dce93cd0SAchim Leubner * XXX This should be done async. 3121dce93cd0SAchim Leubner */ 3122dce93cd0SAchim Leubner if (aac_get_container_info(sc, sync_fib, i, 3123dce93cd0SAchim Leubner &mir, &uid) != 0) 3124dce93cd0SAchim Leubner continue; 3125dce93cd0SAchim Leubner if (i == 0) 3126dce93cd0SAchim Leubner count = mir.MntRespCount; 3127dce93cd0SAchim Leubner /* 3128dce93cd0SAchim Leubner * Check the container against our list. 3129dce93cd0SAchim Leubner * co->co_found was already set to 0 in a 3130dce93cd0SAchim Leubner * previous run. 3131dce93cd0SAchim Leubner */ 3132dce93cd0SAchim Leubner if ((mir.Status == ST_OK) && 3133dce93cd0SAchim Leubner (mir.MntTable[0].VolType != CT_NONE)) { 3134dce93cd0SAchim Leubner found = 0; 3135dce93cd0SAchim Leubner TAILQ_FOREACH(co, 3136dce93cd0SAchim Leubner &sc->aac_container_tqh, 3137dce93cd0SAchim Leubner co_link) { 3138dce93cd0SAchim Leubner if (co->co_mntobj.ObjectId == 3139dce93cd0SAchim Leubner mir.MntTable[0].ObjectId) { 3140dce93cd0SAchim Leubner co->co_found = 1; 3141dce93cd0SAchim Leubner found = 1; 3142dce93cd0SAchim Leubner break; 3143dce93cd0SAchim Leubner } 3144dce93cd0SAchim Leubner } 3145dce93cd0SAchim Leubner /* 3146dce93cd0SAchim Leubner * If the container matched, continue 3147dce93cd0SAchim Leubner * in the list. 3148dce93cd0SAchim Leubner */ 3149dce93cd0SAchim Leubner if (found) { 3150dce93cd0SAchim Leubner i++; 3151dce93cd0SAchim Leubner continue; 3152dce93cd0SAchim Leubner } 3153dce93cd0SAchim Leubner 3154dce93cd0SAchim Leubner /* 3155dce93cd0SAchim Leubner * This is a new container. Do all the 3156dce93cd0SAchim Leubner * appropriate things to set it up. 3157dce93cd0SAchim Leubner */ 3158dce93cd0SAchim Leubner aac_add_container(sc, &mir, 1, uid); 3159dce93cd0SAchim Leubner changed = 1; 3160dce93cd0SAchim Leubner } 3161dce93cd0SAchim Leubner i++; 3162dce93cd0SAchim Leubner } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3163dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3164dce93cd0SAchim Leubner 3165dce93cd0SAchim Leubner /* 3166dce93cd0SAchim Leubner * Go through our list of containers and see which ones 3167dce93cd0SAchim Leubner * were not marked 'found'. Since the controller didn't 3168dce93cd0SAchim Leubner * list them they must have been deleted. Do the 3169dce93cd0SAchim Leubner * appropriate steps to destroy the device. Also reset 3170dce93cd0SAchim Leubner * the co->co_found field. 3171dce93cd0SAchim Leubner */ 3172dce93cd0SAchim Leubner co = TAILQ_FIRST(&sc->aac_container_tqh); 3173dce93cd0SAchim Leubner while (co != NULL) { 3174dce93cd0SAchim Leubner if (co->co_found == 0) { 3175dce93cd0SAchim Leubner co_next = TAILQ_NEXT(co, co_link); 3176dce93cd0SAchim Leubner TAILQ_REMOVE(&sc->aac_container_tqh, co, 3177dce93cd0SAchim Leubner co_link); 3178dce93cd0SAchim Leubner free(co, M_AACRAIDBUF); 3179dce93cd0SAchim Leubner changed = 1; 3180dce93cd0SAchim Leubner co = co_next; 3181dce93cd0SAchim Leubner } else { 3182dce93cd0SAchim Leubner co->co_found = 0; 3183dce93cd0SAchim Leubner co = TAILQ_NEXT(co, co_link); 3184dce93cd0SAchim Leubner } 3185dce93cd0SAchim Leubner } 3186dce93cd0SAchim Leubner 3187dce93cd0SAchim Leubner /* Attach the newly created containers */ 3188dce93cd0SAchim Leubner if (changed) { 3189dce93cd0SAchim Leubner if (sc->cam_rescan_cb != NULL) 3190dce93cd0SAchim Leubner sc->cam_rescan_cb(sc, 0, 3191dce93cd0SAchim Leubner AAC_CAM_TARGET_WILDCARD); 3192dce93cd0SAchim Leubner } 3193dce93cd0SAchim Leubner 3194dce93cd0SAchim Leubner break; 3195dce93cd0SAchim Leubner 3196dce93cd0SAchim Leubner case AifEnEnclosureManagement: 3197dce93cd0SAchim Leubner switch (aif->data.EN.data.EEE.eventType) { 3198dce93cd0SAchim Leubner case AIF_EM_DRIVE_INSERTION: 3199dce93cd0SAchim Leubner case AIF_EM_DRIVE_REMOVAL: 3200dce93cd0SAchim Leubner channel = aif->data.EN.data.EEE.unitID; 3201dce93cd0SAchim Leubner if (sc->cam_rescan_cb != NULL) 3202dce93cd0SAchim Leubner sc->cam_rescan_cb(sc, 3203dce93cd0SAchim Leubner ((channel>>24) & 0xF) + 1, 3204dce93cd0SAchim Leubner (channel & 0xFFFF)); 3205dce93cd0SAchim Leubner break; 3206dce93cd0SAchim Leubner } 3207dce93cd0SAchim Leubner break; 3208dce93cd0SAchim Leubner 3209dce93cd0SAchim Leubner case AifEnAddJBOD: 3210dce93cd0SAchim Leubner case AifEnDeleteJBOD: 3211dce93cd0SAchim Leubner case AifRawDeviceRemove: 3212dce93cd0SAchim Leubner channel = aif->data.EN.data.ECE.container; 3213dce93cd0SAchim Leubner if (sc->cam_rescan_cb != NULL) 3214dce93cd0SAchim Leubner sc->cam_rescan_cb(sc, ((channel>>24) & 0xF) + 1, 3215dce93cd0SAchim Leubner AAC_CAM_TARGET_WILDCARD); 3216dce93cd0SAchim Leubner break; 3217dce93cd0SAchim Leubner 3218dce93cd0SAchim Leubner default: 3219dce93cd0SAchim Leubner break; 3220dce93cd0SAchim Leubner } 3221dce93cd0SAchim Leubner 3222dce93cd0SAchim Leubner default: 3223dce93cd0SAchim Leubner break; 3224dce93cd0SAchim Leubner } 3225dce93cd0SAchim Leubner 3226dce93cd0SAchim Leubner /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3227dce93cd0SAchim Leubner current = sc->aifq_idx; 3228dce93cd0SAchim Leubner next = (current + 1) % AAC_AIFQ_LENGTH; 3229dce93cd0SAchim Leubner if (next == 0) 3230dce93cd0SAchim Leubner sc->aifq_filled = 1; 3231dce93cd0SAchim Leubner bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3232dce93cd0SAchim Leubner /* modify AIF contexts */ 3233dce93cd0SAchim Leubner if (sc->aifq_filled) { 3234dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3235dce93cd0SAchim Leubner if (next == ctx->ctx_idx) 3236dce93cd0SAchim Leubner ctx->ctx_wrap = 1; 3237dce93cd0SAchim Leubner else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3238dce93cd0SAchim Leubner ctx->ctx_idx = next; 3239dce93cd0SAchim Leubner } 3240dce93cd0SAchim Leubner } 3241dce93cd0SAchim Leubner sc->aifq_idx = next; 3242dce93cd0SAchim Leubner /* On the off chance that someone is sleeping for an aif... */ 3243dce93cd0SAchim Leubner if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 3244dce93cd0SAchim Leubner wakeup(sc->aac_aifq); 3245dce93cd0SAchim Leubner /* Wakeup any poll()ers */ 3246dce93cd0SAchim Leubner selwakeuppri(&sc->rcv_select, PRIBIO); 3247dce93cd0SAchim Leubner 3248dce93cd0SAchim Leubner return; 3249dce93cd0SAchim Leubner } 3250dce93cd0SAchim Leubner 3251dce93cd0SAchim Leubner /* 3252dce93cd0SAchim Leubner * Return the Revision of the driver to userspace and check to see if the 3253dce93cd0SAchim Leubner * userspace app is possibly compatible. This is extremely bogus since 3254dce93cd0SAchim Leubner * our driver doesn't follow Adaptec's versioning system. Cheat by just 3255dce93cd0SAchim Leubner * returning what the card reported. 3256dce93cd0SAchim Leubner */ 3257dce93cd0SAchim Leubner static int 3258dce93cd0SAchim Leubner aac_rev_check(struct aac_softc *sc, caddr_t udata) 3259dce93cd0SAchim Leubner { 3260dce93cd0SAchim Leubner struct aac_rev_check rev_check; 3261dce93cd0SAchim Leubner struct aac_rev_check_resp rev_check_resp; 3262dce93cd0SAchim Leubner int error = 0; 3263dce93cd0SAchim Leubner 3264dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3265dce93cd0SAchim Leubner 3266dce93cd0SAchim Leubner /* 3267dce93cd0SAchim Leubner * Copyin the revision struct from userspace 3268dce93cd0SAchim Leubner */ 3269dce93cd0SAchim Leubner if ((error = copyin(udata, (caddr_t)&rev_check, 3270dce93cd0SAchim Leubner sizeof(struct aac_rev_check))) != 0) { 3271dce93cd0SAchim Leubner return error; 3272dce93cd0SAchim Leubner } 3273dce93cd0SAchim Leubner 3274dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3275dce93cd0SAchim Leubner rev_check.callingRevision.buildNumber); 3276dce93cd0SAchim Leubner 3277dce93cd0SAchim Leubner /* 3278dce93cd0SAchim Leubner * Doctor up the response struct. 3279dce93cd0SAchim Leubner */ 3280dce93cd0SAchim Leubner rev_check_resp.possiblyCompatible = 1; 3281dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.major = 3282dce93cd0SAchim Leubner AAC_DRIVER_MAJOR_VERSION; 3283dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.minor = 3284dce93cd0SAchim Leubner AAC_DRIVER_MINOR_VERSION; 3285dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.type = 3286dce93cd0SAchim Leubner AAC_DRIVER_TYPE; 3287dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.external.comp.dash = 3288dce93cd0SAchim Leubner AAC_DRIVER_BUGFIX_LEVEL; 3289dce93cd0SAchim Leubner rev_check_resp.adapterSWRevision.buildNumber = 3290dce93cd0SAchim Leubner AAC_DRIVER_BUILD; 3291dce93cd0SAchim Leubner 3292dce93cd0SAchim Leubner return(copyout((caddr_t)&rev_check_resp, udata, 3293dce93cd0SAchim Leubner sizeof(struct aac_rev_check_resp))); 3294dce93cd0SAchim Leubner } 3295dce93cd0SAchim Leubner 3296dce93cd0SAchim Leubner /* 3297dce93cd0SAchim Leubner * Pass the fib context to the caller 3298dce93cd0SAchim Leubner */ 3299dce93cd0SAchim Leubner static int 3300dce93cd0SAchim Leubner aac_open_aif(struct aac_softc *sc, caddr_t arg) 3301dce93cd0SAchim Leubner { 3302dce93cd0SAchim Leubner struct aac_fib_context *fibctx, *ctx; 3303dce93cd0SAchim Leubner int error = 0; 3304dce93cd0SAchim Leubner 3305dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3306dce93cd0SAchim Leubner 3307dce93cd0SAchim Leubner fibctx = malloc(sizeof(struct aac_fib_context), M_AACRAIDBUF, M_NOWAIT|M_ZERO); 3308dce93cd0SAchim Leubner if (fibctx == NULL) 3309dce93cd0SAchim Leubner return (ENOMEM); 3310dce93cd0SAchim Leubner 3311dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3312dce93cd0SAchim Leubner /* all elements are already 0, add to queue */ 3313dce93cd0SAchim Leubner if (sc->fibctx == NULL) 3314dce93cd0SAchim Leubner sc->fibctx = fibctx; 3315dce93cd0SAchim Leubner else { 3316dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3317dce93cd0SAchim Leubner ; 3318dce93cd0SAchim Leubner ctx->next = fibctx; 3319dce93cd0SAchim Leubner fibctx->prev = ctx; 3320dce93cd0SAchim Leubner } 3321dce93cd0SAchim Leubner 3322dce93cd0SAchim Leubner /* evaluate unique value */ 3323dce93cd0SAchim Leubner fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3324dce93cd0SAchim Leubner ctx = sc->fibctx; 3325dce93cd0SAchim Leubner while (ctx != fibctx) { 3326dce93cd0SAchim Leubner if (ctx->unique == fibctx->unique) { 3327dce93cd0SAchim Leubner fibctx->unique++; 3328dce93cd0SAchim Leubner ctx = sc->fibctx; 3329dce93cd0SAchim Leubner } else { 3330dce93cd0SAchim Leubner ctx = ctx->next; 3331dce93cd0SAchim Leubner } 3332dce93cd0SAchim Leubner } 3333dce93cd0SAchim Leubner 3334dce93cd0SAchim Leubner error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3335dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3336dce93cd0SAchim Leubner if (error) 3337dce93cd0SAchim Leubner aac_close_aif(sc, (caddr_t)ctx); 3338dce93cd0SAchim Leubner return error; 3339dce93cd0SAchim Leubner } 3340dce93cd0SAchim Leubner 3341dce93cd0SAchim Leubner /* 3342dce93cd0SAchim Leubner * Close the caller's fib context 3343dce93cd0SAchim Leubner */ 3344dce93cd0SAchim Leubner static int 3345dce93cd0SAchim Leubner aac_close_aif(struct aac_softc *sc, caddr_t arg) 3346dce93cd0SAchim Leubner { 3347dce93cd0SAchim Leubner struct aac_fib_context *ctx; 3348dce93cd0SAchim Leubner 3349dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3350dce93cd0SAchim Leubner 3351dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3352dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3353dce93cd0SAchim Leubner if (ctx->unique == *(uint32_t *)&arg) { 3354dce93cd0SAchim Leubner if (ctx == sc->fibctx) 3355dce93cd0SAchim Leubner sc->fibctx = NULL; 3356dce93cd0SAchim Leubner else { 3357dce93cd0SAchim Leubner ctx->prev->next = ctx->next; 3358dce93cd0SAchim Leubner if (ctx->next) 3359dce93cd0SAchim Leubner ctx->next->prev = ctx->prev; 3360dce93cd0SAchim Leubner } 3361dce93cd0SAchim Leubner break; 3362dce93cd0SAchim Leubner } 3363dce93cd0SAchim Leubner } 3364dce93cd0SAchim Leubner if (ctx) 3365dce93cd0SAchim Leubner free(ctx, M_AACRAIDBUF); 3366dce93cd0SAchim Leubner 3367dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3368dce93cd0SAchim Leubner return 0; 3369dce93cd0SAchim Leubner } 3370dce93cd0SAchim Leubner 3371dce93cd0SAchim Leubner /* 3372dce93cd0SAchim Leubner * Pass the caller the next AIF in their queue 3373dce93cd0SAchim Leubner */ 3374dce93cd0SAchim Leubner static int 3375dce93cd0SAchim Leubner aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 3376dce93cd0SAchim Leubner { 3377dce93cd0SAchim Leubner struct get_adapter_fib_ioctl agf; 3378dce93cd0SAchim Leubner struct aac_fib_context *ctx; 3379dce93cd0SAchim Leubner int error; 3380dce93cd0SAchim Leubner 3381dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3382dce93cd0SAchim Leubner 3383dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3384dce93cd0SAchim Leubner if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3385dce93cd0SAchim Leubner for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3386dce93cd0SAchim Leubner if (agf.AdapterFibContext == ctx->unique) 3387dce93cd0SAchim Leubner break; 3388dce93cd0SAchim Leubner } 3389dce93cd0SAchim Leubner if (!ctx) { 3390dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3391dce93cd0SAchim Leubner return (EFAULT); 3392dce93cd0SAchim Leubner } 3393dce93cd0SAchim Leubner 3394dce93cd0SAchim Leubner error = aac_return_aif(sc, ctx, agf.AifFib); 3395dce93cd0SAchim Leubner if (error == EAGAIN && agf.Wait) { 3396dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 3397dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_AIF_SLEEPER; 3398dce93cd0SAchim Leubner while (error == EAGAIN) { 3399dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3400dce93cd0SAchim Leubner error = tsleep(sc->aac_aifq, PRIBIO | 3401dce93cd0SAchim Leubner PCATCH, "aacaif", 0); 3402dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3403dce93cd0SAchim Leubner if (error == 0) 3404dce93cd0SAchim Leubner error = aac_return_aif(sc, ctx, agf.AifFib); 3405dce93cd0SAchim Leubner } 3406dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 3407dce93cd0SAchim Leubner } 3408dce93cd0SAchim Leubner } 3409dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3410dce93cd0SAchim Leubner return(error); 3411dce93cd0SAchim Leubner } 3412dce93cd0SAchim Leubner 3413dce93cd0SAchim Leubner /* 3414dce93cd0SAchim Leubner * Hand the next AIF off the top of the queue out to userspace. 3415dce93cd0SAchim Leubner */ 3416dce93cd0SAchim Leubner static int 3417dce93cd0SAchim Leubner aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 3418dce93cd0SAchim Leubner { 3419dce93cd0SAchim Leubner int current, error; 3420dce93cd0SAchim Leubner 3421dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3422dce93cd0SAchim Leubner 3423dce93cd0SAchim Leubner current = ctx->ctx_idx; 3424dce93cd0SAchim Leubner if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3425dce93cd0SAchim Leubner /* empty */ 3426dce93cd0SAchim Leubner return (EAGAIN); 3427dce93cd0SAchim Leubner } 3428dce93cd0SAchim Leubner error = 3429dce93cd0SAchim Leubner copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 3430dce93cd0SAchim Leubner if (error) 3431dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3432dce93cd0SAchim Leubner "aac_return_aif: copyout returned %d\n", error); 3433dce93cd0SAchim Leubner else { 3434dce93cd0SAchim Leubner ctx->ctx_wrap = 0; 3435dce93cd0SAchim Leubner ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3436dce93cd0SAchim Leubner } 3437dce93cd0SAchim Leubner return(error); 3438dce93cd0SAchim Leubner } 3439dce93cd0SAchim Leubner 3440dce93cd0SAchim Leubner static int 3441dce93cd0SAchim Leubner aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 3442dce93cd0SAchim Leubner { 3443dce93cd0SAchim Leubner struct aac_pci_info { 3444dce93cd0SAchim Leubner u_int32_t bus; 3445dce93cd0SAchim Leubner u_int32_t slot; 3446dce93cd0SAchim Leubner } pciinf; 3447dce93cd0SAchim Leubner int error; 3448dce93cd0SAchim Leubner 3449dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3450dce93cd0SAchim Leubner 3451dce93cd0SAchim Leubner pciinf.bus = pci_get_bus(sc->aac_dev); 3452dce93cd0SAchim Leubner pciinf.slot = pci_get_slot(sc->aac_dev); 3453dce93cd0SAchim Leubner 3454dce93cd0SAchim Leubner error = copyout((caddr_t)&pciinf, uptr, 3455dce93cd0SAchim Leubner sizeof(struct aac_pci_info)); 3456dce93cd0SAchim Leubner 3457dce93cd0SAchim Leubner return (error); 3458dce93cd0SAchim Leubner } 3459dce93cd0SAchim Leubner 3460dce93cd0SAchim Leubner static int 3461dce93cd0SAchim Leubner aac_supported_features(struct aac_softc *sc, caddr_t uptr) 3462dce93cd0SAchim Leubner { 3463dce93cd0SAchim Leubner struct aac_features f; 3464dce93cd0SAchim Leubner int error; 3465dce93cd0SAchim Leubner 3466dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3467dce93cd0SAchim Leubner 3468dce93cd0SAchim Leubner if ((error = copyin(uptr, &f, sizeof (f))) != 0) 3469dce93cd0SAchim Leubner return (error); 3470dce93cd0SAchim Leubner 3471dce93cd0SAchim Leubner /* 3472dce93cd0SAchim Leubner * When the management driver receives FSACTL_GET_FEATURES ioctl with 3473dce93cd0SAchim Leubner * ALL zero in the featuresState, the driver will return the current 3474dce93cd0SAchim Leubner * state of all the supported features, the data field will not be 3475dce93cd0SAchim Leubner * valid. 3476dce93cd0SAchim Leubner * When the management driver receives FSACTL_GET_FEATURES ioctl with 3477dce93cd0SAchim Leubner * a specific bit set in the featuresState, the driver will return the 3478dce93cd0SAchim Leubner * current state of this specific feature and whatever data that are 3479dce93cd0SAchim Leubner * associated with the feature in the data field or perform whatever 3480dce93cd0SAchim Leubner * action needed indicates in the data field. 3481dce93cd0SAchim Leubner */ 3482dce93cd0SAchim Leubner if (f.feat.fValue == 0) { 3483dce93cd0SAchim Leubner f.feat.fBits.largeLBA = 3484dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3485dce93cd0SAchim Leubner f.feat.fBits.JBODSupport = 1; 3486dce93cd0SAchim Leubner /* TODO: In the future, add other features state here as well */ 3487dce93cd0SAchim Leubner } else { 3488dce93cd0SAchim Leubner if (f.feat.fBits.largeLBA) 3489dce93cd0SAchim Leubner f.feat.fBits.largeLBA = 3490dce93cd0SAchim Leubner (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 3491dce93cd0SAchim Leubner /* TODO: Add other features state and data in the future */ 3492dce93cd0SAchim Leubner } 3493dce93cd0SAchim Leubner 3494dce93cd0SAchim Leubner error = copyout(&f, uptr, sizeof (f)); 3495dce93cd0SAchim Leubner return (error); 3496dce93cd0SAchim Leubner } 3497dce93cd0SAchim Leubner 3498dce93cd0SAchim Leubner /* 3499dce93cd0SAchim Leubner * Give the userland some information about the container. The AAC arch 3500dce93cd0SAchim Leubner * expects the driver to be a SCSI passthrough type driver, so it expects 3501dce93cd0SAchim Leubner * the containers to have b:t:l numbers. Fake it. 3502dce93cd0SAchim Leubner */ 3503dce93cd0SAchim Leubner static int 3504dce93cd0SAchim Leubner aac_query_disk(struct aac_softc *sc, caddr_t uptr) 3505dce93cd0SAchim Leubner { 3506dce93cd0SAchim Leubner struct aac_query_disk query_disk; 3507dce93cd0SAchim Leubner struct aac_container *co; 3508dce93cd0SAchim Leubner int error, id; 3509dce93cd0SAchim Leubner 3510dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3511dce93cd0SAchim Leubner 3512dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3513dce93cd0SAchim Leubner error = copyin(uptr, (caddr_t)&query_disk, 3514dce93cd0SAchim Leubner sizeof(struct aac_query_disk)); 3515dce93cd0SAchim Leubner if (error) { 3516dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3517dce93cd0SAchim Leubner return (error); 3518dce93cd0SAchim Leubner } 3519dce93cd0SAchim Leubner 3520dce93cd0SAchim Leubner id = query_disk.ContainerNumber; 3521dce93cd0SAchim Leubner if (id == -1) { 3522dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3523dce93cd0SAchim Leubner return (EINVAL); 3524dce93cd0SAchim Leubner } 3525dce93cd0SAchim Leubner 3526dce93cd0SAchim Leubner TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 3527dce93cd0SAchim Leubner if (co->co_mntobj.ObjectId == id) 3528dce93cd0SAchim Leubner break; 3529dce93cd0SAchim Leubner } 3530dce93cd0SAchim Leubner 3531dce93cd0SAchim Leubner if (co == NULL) { 3532dce93cd0SAchim Leubner query_disk.Valid = 0; 3533dce93cd0SAchim Leubner query_disk.Locked = 0; 3534dce93cd0SAchim Leubner query_disk.Deleted = 1; /* XXX is this right? */ 3535dce93cd0SAchim Leubner } else { 3536dce93cd0SAchim Leubner query_disk.Valid = 1; 3537dce93cd0SAchim Leubner query_disk.Locked = 1; 3538dce93cd0SAchim Leubner query_disk.Deleted = 0; 3539dce93cd0SAchim Leubner query_disk.Bus = device_get_unit(sc->aac_dev); 3540dce93cd0SAchim Leubner query_disk.Target = 0; 3541dce93cd0SAchim Leubner query_disk.Lun = 0; 3542dce93cd0SAchim Leubner query_disk.UnMapped = 0; 3543dce93cd0SAchim Leubner } 3544dce93cd0SAchim Leubner 3545dce93cd0SAchim Leubner error = copyout((caddr_t)&query_disk, uptr, 3546dce93cd0SAchim Leubner sizeof(struct aac_query_disk)); 3547dce93cd0SAchim Leubner 3548dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3549dce93cd0SAchim Leubner return (error); 3550dce93cd0SAchim Leubner } 3551dce93cd0SAchim Leubner 3552dce93cd0SAchim Leubner static void 3553dce93cd0SAchim Leubner aac_container_bus(struct aac_softc *sc) 3554dce93cd0SAchim Leubner { 3555dce93cd0SAchim Leubner struct aac_sim *sim; 3556dce93cd0SAchim Leubner device_t child; 3557dce93cd0SAchim Leubner 3558dce93cd0SAchim Leubner sim =(struct aac_sim *)malloc(sizeof(struct aac_sim), 3559dce93cd0SAchim Leubner M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3560dce93cd0SAchim Leubner if (sim == NULL) { 3561dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3562dce93cd0SAchim Leubner "No memory to add container bus\n"); 3563dce93cd0SAchim Leubner panic("Out of memory?!"); 356474b8d63dSPedro F. Giffuni } 3565dce93cd0SAchim Leubner child = device_add_child(sc->aac_dev, "aacraidp", -1); 3566dce93cd0SAchim Leubner if (child == NULL) { 3567dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3568dce93cd0SAchim Leubner "device_add_child failed for container bus\n"); 3569dce93cd0SAchim Leubner free(sim, M_AACRAIDBUF); 3570dce93cd0SAchim Leubner panic("Out of memory?!"); 3571dce93cd0SAchim Leubner } 3572dce93cd0SAchim Leubner 3573dce93cd0SAchim Leubner sim->TargetsPerBus = AAC_MAX_CONTAINERS; 3574dce93cd0SAchim Leubner sim->BusNumber = 0; 3575dce93cd0SAchim Leubner sim->BusType = CONTAINER_BUS; 3576dce93cd0SAchim Leubner sim->InitiatorBusId = -1; 3577dce93cd0SAchim Leubner sim->aac_sc = sc; 3578dce93cd0SAchim Leubner sim->sim_dev = child; 3579dce93cd0SAchim Leubner sim->aac_cam = NULL; 3580dce93cd0SAchim Leubner 3581dce93cd0SAchim Leubner device_set_ivars(child, sim); 3582dce93cd0SAchim Leubner device_set_desc(child, "Container Bus"); 3583dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, sim, sim_link); 3584dce93cd0SAchim Leubner /* 3585dce93cd0SAchim Leubner device_set_desc(child, aac_describe_code(aac_container_types, 3586dce93cd0SAchim Leubner mir->MntTable[0].VolType)); 3587dce93cd0SAchim Leubner */ 3588dce93cd0SAchim Leubner bus_generic_attach(sc->aac_dev); 3589dce93cd0SAchim Leubner } 3590dce93cd0SAchim Leubner 3591dce93cd0SAchim Leubner static void 3592dce93cd0SAchim Leubner aac_get_bus_info(struct aac_softc *sc) 3593dce93cd0SAchim Leubner { 3594dce93cd0SAchim Leubner struct aac_fib *fib; 3595dce93cd0SAchim Leubner struct aac_ctcfg *c_cmd; 3596dce93cd0SAchim Leubner struct aac_ctcfg_resp *c_resp; 3597dce93cd0SAchim Leubner struct aac_vmioctl *vmi; 3598dce93cd0SAchim Leubner struct aac_vmi_businf_resp *vmi_resp; 3599dce93cd0SAchim Leubner struct aac_getbusinf businfo; 3600dce93cd0SAchim Leubner struct aac_sim *caminf; 3601dce93cd0SAchim Leubner device_t child; 3602dce93cd0SAchim Leubner int i, error; 3603dce93cd0SAchim Leubner 3604dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3605dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 3606dce93cd0SAchim Leubner c_cmd = (struct aac_ctcfg *)&fib->data[0]; 3607dce93cd0SAchim Leubner bzero(c_cmd, sizeof(struct aac_ctcfg)); 3608dce93cd0SAchim Leubner 3609dce93cd0SAchim Leubner c_cmd->Command = VM_ContainerConfig; 3610dce93cd0SAchim Leubner c_cmd->cmd = CT_GET_SCSI_METHOD; 3611dce93cd0SAchim Leubner c_cmd->param = 0; 3612dce93cd0SAchim Leubner 3613dce93cd0SAchim Leubner error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3614dce93cd0SAchim Leubner sizeof(struct aac_ctcfg)); 3615dce93cd0SAchim Leubner if (error) { 3616dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error %d sending " 3617dce93cd0SAchim Leubner "VM_ContainerConfig command\n", error); 3618dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3619dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3620dce93cd0SAchim Leubner return; 3621dce93cd0SAchim Leubner } 3622dce93cd0SAchim Leubner 3623dce93cd0SAchim Leubner c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3624dce93cd0SAchim Leubner if (c_resp->Status != ST_OK) { 3625dce93cd0SAchim Leubner device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3626dce93cd0SAchim Leubner c_resp->Status); 3627dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3628dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3629dce93cd0SAchim Leubner return; 3630dce93cd0SAchim Leubner } 3631dce93cd0SAchim Leubner 3632dce93cd0SAchim Leubner sc->scsi_method_id = c_resp->param; 3633dce93cd0SAchim Leubner 3634dce93cd0SAchim Leubner vmi = (struct aac_vmioctl *)&fib->data[0]; 3635dce93cd0SAchim Leubner bzero(vmi, sizeof(struct aac_vmioctl)); 3636dce93cd0SAchim Leubner 3637dce93cd0SAchim Leubner vmi->Command = VM_Ioctl; 3638dce93cd0SAchim Leubner vmi->ObjType = FT_DRIVE; 3639dce93cd0SAchim Leubner vmi->MethId = sc->scsi_method_id; 3640dce93cd0SAchim Leubner vmi->ObjId = 0; 3641dce93cd0SAchim Leubner vmi->IoctlCmd = GetBusInfo; 3642dce93cd0SAchim Leubner 3643dce93cd0SAchim Leubner error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3644dce93cd0SAchim Leubner sizeof(struct aac_vmi_businf_resp)); 3645dce93cd0SAchim Leubner if (error) { 3646dce93cd0SAchim Leubner device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3647dce93cd0SAchim Leubner error); 3648dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3649dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3650dce93cd0SAchim Leubner return; 3651dce93cd0SAchim Leubner } 3652dce93cd0SAchim Leubner 3653dce93cd0SAchim Leubner vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3654dce93cd0SAchim Leubner if (vmi_resp->Status != ST_OK) { 3655dce93cd0SAchim Leubner device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3656dce93cd0SAchim Leubner vmi_resp->Status); 3657dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3658dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3659dce93cd0SAchim Leubner return; 3660dce93cd0SAchim Leubner } 3661dce93cd0SAchim Leubner 3662dce93cd0SAchim Leubner bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3663dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3664dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3665dce93cd0SAchim Leubner 3666dce93cd0SAchim Leubner for (i = 0; i < businfo.BusCount; i++) { 3667dce93cd0SAchim Leubner if (businfo.BusValid[i] != AAC_BUS_VALID) 3668dce93cd0SAchim Leubner continue; 3669dce93cd0SAchim Leubner 3670dce93cd0SAchim Leubner caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3671dce93cd0SAchim Leubner M_AACRAIDBUF, M_NOWAIT | M_ZERO); 3672dce93cd0SAchim Leubner if (caminf == NULL) { 3673dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3674dce93cd0SAchim Leubner "No memory to add passthrough bus %d\n", i); 3675dce93cd0SAchim Leubner break; 367674b8d63dSPedro F. Giffuni } 3677dce93cd0SAchim Leubner 3678dce93cd0SAchim Leubner child = device_add_child(sc->aac_dev, "aacraidp", -1); 3679dce93cd0SAchim Leubner if (child == NULL) { 3680dce93cd0SAchim Leubner device_printf(sc->aac_dev, 3681dce93cd0SAchim Leubner "device_add_child failed for passthrough bus %d\n", 3682dce93cd0SAchim Leubner i); 3683dce93cd0SAchim Leubner free(caminf, M_AACRAIDBUF); 3684dce93cd0SAchim Leubner break; 3685dce93cd0SAchim Leubner } 3686dce93cd0SAchim Leubner 3687dce93cd0SAchim Leubner caminf->TargetsPerBus = businfo.TargetsPerBus; 3688dce93cd0SAchim Leubner caminf->BusNumber = i+1; 3689dce93cd0SAchim Leubner caminf->BusType = PASSTHROUGH_BUS; 3690dce93cd0SAchim Leubner caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3691dce93cd0SAchim Leubner caminf->aac_sc = sc; 3692dce93cd0SAchim Leubner caminf->sim_dev = child; 3693dce93cd0SAchim Leubner caminf->aac_cam = NULL; 3694dce93cd0SAchim Leubner 3695dce93cd0SAchim Leubner device_set_ivars(child, caminf); 3696dce93cd0SAchim Leubner device_set_desc(child, "SCSI Passthrough Bus"); 3697dce93cd0SAchim Leubner TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3698dce93cd0SAchim Leubner } 3699dce93cd0SAchim Leubner } 3700dce93cd0SAchim Leubner 3701dce93cd0SAchim Leubner /* 3702dce93cd0SAchim Leubner * Check to see if the kernel is up and running. If we are in a 3703dce93cd0SAchim Leubner * BlinkLED state, return the BlinkLED code. 3704dce93cd0SAchim Leubner */ 3705dce93cd0SAchim Leubner static u_int32_t 3706dce93cd0SAchim Leubner aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled) 3707dce93cd0SAchim Leubner { 3708dce93cd0SAchim Leubner u_int32_t ret; 3709dce93cd0SAchim Leubner 3710dce93cd0SAchim Leubner ret = AAC_GET_FWSTATUS(sc); 3711dce93cd0SAchim Leubner 3712dce93cd0SAchim Leubner if (ret & AAC_UP_AND_RUNNING) 3713dce93cd0SAchim Leubner ret = 0; 3714dce93cd0SAchim Leubner else if (ret & AAC_KERNEL_PANIC && bled) 3715dce93cd0SAchim Leubner *bled = (ret >> 16) & 0xff; 3716dce93cd0SAchim Leubner 3717dce93cd0SAchim Leubner return (ret); 3718dce93cd0SAchim Leubner } 3719dce93cd0SAchim Leubner 3720dce93cd0SAchim Leubner /* 3721dce93cd0SAchim Leubner * Once do an IOP reset, basically have to re-initialize the card as 3722dce93cd0SAchim Leubner * if coming up from a cold boot, and the driver is responsible for 3723dce93cd0SAchim Leubner * any IO that was outstanding to the adapter at the time of the IOP 3724dce93cd0SAchim Leubner * RESET. And prepare the driver for IOP RESET by making the init code 3725dce93cd0SAchim Leubner * modular with the ability to call it from multiple places. 3726dce93cd0SAchim Leubner */ 3727dce93cd0SAchim Leubner static int 3728dce93cd0SAchim Leubner aac_reset_adapter(struct aac_softc *sc) 3729dce93cd0SAchim Leubner { 3730dce93cd0SAchim Leubner struct aac_command *cm; 3731dce93cd0SAchim Leubner struct aac_fib *fib; 3732dce93cd0SAchim Leubner struct aac_pause_command *pc; 37333fea9c0dSAchim Leubner u_int32_t status, reset_mask, waitCount, max_msix_orig; 37343fea9c0dSAchim Leubner int msi_enabled_orig; 3735dce93cd0SAchim Leubner 3736dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 37373fea9c0dSAchim Leubner mtx_assert(&sc->aac_io_lock, MA_OWNED); 3738dce93cd0SAchim Leubner 3739dce93cd0SAchim Leubner if (sc->aac_state & AAC_STATE_RESET) { 3740dce93cd0SAchim Leubner device_printf(sc->aac_dev, "aac_reset_adapter() already in progress\n"); 3741dce93cd0SAchim Leubner return (EINVAL); 3742dce93cd0SAchim Leubner } 3743dce93cd0SAchim Leubner sc->aac_state |= AAC_STATE_RESET; 3744dce93cd0SAchim Leubner 3745dce93cd0SAchim Leubner /* disable interrupt */ 37463fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT); 3747dce93cd0SAchim Leubner 3748dce93cd0SAchim Leubner /* 3749dce93cd0SAchim Leubner * Abort all pending commands: 3750dce93cd0SAchim Leubner * a) on the controller 3751dce93cd0SAchim Leubner */ 3752dce93cd0SAchim Leubner while ((cm = aac_dequeue_busy(sc)) != NULL) { 3753dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_RESET; 3754dce93cd0SAchim Leubner 3755dce93cd0SAchim Leubner /* is there a completion handler? */ 3756dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 3757dce93cd0SAchim Leubner cm->cm_complete(cm); 3758dce93cd0SAchim Leubner } else { 3759dce93cd0SAchim Leubner /* assume that someone is sleeping on this 3760dce93cd0SAchim Leubner * command 3761dce93cd0SAchim Leubner */ 3762dce93cd0SAchim Leubner wakeup(cm); 3763dce93cd0SAchim Leubner } 3764dce93cd0SAchim Leubner } 3765dce93cd0SAchim Leubner 3766dce93cd0SAchim Leubner /* b) in the waiting queues */ 3767dce93cd0SAchim Leubner while ((cm = aac_dequeue_ready(sc)) != NULL) { 3768dce93cd0SAchim Leubner cm->cm_flags |= AAC_CMD_RESET; 3769dce93cd0SAchim Leubner 3770dce93cd0SAchim Leubner /* is there a completion handler? */ 3771dce93cd0SAchim Leubner if (cm->cm_complete != NULL) { 3772dce93cd0SAchim Leubner cm->cm_complete(cm); 3773dce93cd0SAchim Leubner } else { 3774dce93cd0SAchim Leubner /* assume that someone is sleeping on this 3775dce93cd0SAchim Leubner * command 3776dce93cd0SAchim Leubner */ 3777dce93cd0SAchim Leubner wakeup(cm); 3778dce93cd0SAchim Leubner } 3779dce93cd0SAchim Leubner } 3780dce93cd0SAchim Leubner 3781dce93cd0SAchim Leubner /* flush drives */ 3782dce93cd0SAchim Leubner if (aac_check_adapter_health(sc, NULL) == 0) { 3783dce93cd0SAchim Leubner mtx_unlock(&sc->aac_io_lock); 3784dce93cd0SAchim Leubner (void) aacraid_shutdown(sc->aac_dev); 3785dce93cd0SAchim Leubner mtx_lock(&sc->aac_io_lock); 3786dce93cd0SAchim Leubner } 3787dce93cd0SAchim Leubner 3788dce93cd0SAchim Leubner /* execute IOP reset */ 3789dce93cd0SAchim Leubner if (sc->aac_support_opt2 & AAC_SUPPORTED_MU_RESET) { 3790dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_IRCSR, AAC_IRCSR_CORES_RST); 3791dce93cd0SAchim Leubner 3792dce93cd0SAchim Leubner /* We need to wait for 5 seconds before accessing the MU again 3793dce93cd0SAchim Leubner * 10000 * 100us = 1000,000us = 1000ms = 1s 3794dce93cd0SAchim Leubner */ 3795dce93cd0SAchim Leubner waitCount = 5 * 10000; 3796dce93cd0SAchim Leubner while (waitCount) { 3797dce93cd0SAchim Leubner DELAY(100); /* delay 100 microseconds */ 3798dce93cd0SAchim Leubner waitCount--; 3799dce93cd0SAchim Leubner } 3800dce93cd0SAchim Leubner } else if ((aacraid_sync_command(sc, 3801dce93cd0SAchim Leubner AAC_IOP_RESET_ALWAYS, 0, 0, 0, 0, &status, &reset_mask)) != 0) { 3802dce93cd0SAchim Leubner /* call IOP_RESET for older firmware */ 3803dce93cd0SAchim Leubner if ((aacraid_sync_command(sc, 3804dce93cd0SAchim Leubner AAC_IOP_RESET, 0, 0, 0, 0, &status, NULL)) != 0) { 3805dce93cd0SAchim Leubner 3806dce93cd0SAchim Leubner if (status == AAC_SRB_STS_INVALID_REQUEST) 3807dce93cd0SAchim Leubner device_printf(sc->aac_dev, "IOP_RESET not supported\n"); 3808dce93cd0SAchim Leubner else 3809dce93cd0SAchim Leubner /* probably timeout */ 3810dce93cd0SAchim Leubner device_printf(sc->aac_dev, "IOP_RESET failed\n"); 3811dce93cd0SAchim Leubner 3812dce93cd0SAchim Leubner /* unwind aac_shutdown() */ 3813dce93cd0SAchim Leubner aac_alloc_sync_fib(sc, &fib); 3814dce93cd0SAchim Leubner pc = (struct aac_pause_command *)&fib->data[0]; 3815dce93cd0SAchim Leubner pc->Command = VM_ContainerConfig; 3816dce93cd0SAchim Leubner pc->Type = CT_PAUSE_IO; 3817dce93cd0SAchim Leubner pc->Timeout = 1; 3818dce93cd0SAchim Leubner pc->Min = 1; 3819dce93cd0SAchim Leubner pc->NoRescan = 1; 3820dce93cd0SAchim Leubner 3821dce93cd0SAchim Leubner (void) aac_sync_fib(sc, ContainerCommand, 0, fib, 3822dce93cd0SAchim Leubner sizeof (struct aac_pause_command)); 3823dce93cd0SAchim Leubner aac_release_sync_fib(sc); 3824dce93cd0SAchim Leubner 3825dce93cd0SAchim Leubner goto finish; 3826dce93cd0SAchim Leubner } 3827dce93cd0SAchim Leubner } else if (sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET) { 3828dce93cd0SAchim Leubner AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask); 38293fea9c0dSAchim Leubner /* 38303fea9c0dSAchim Leubner * We need to wait for 5 seconds before accessing the doorbell 38313fea9c0dSAchim Leubner * again, 10000 * 100us = 1000,000us = 1000ms = 1s 3832dce93cd0SAchim Leubner */ 3833dce93cd0SAchim Leubner waitCount = 5 * 10000; 3834dce93cd0SAchim Leubner while (waitCount) { 3835dce93cd0SAchim Leubner DELAY(100); /* delay 100 microseconds */ 3836dce93cd0SAchim Leubner waitCount--; 3837dce93cd0SAchim Leubner } 3838dce93cd0SAchim Leubner } 3839dce93cd0SAchim Leubner 3840dce93cd0SAchim Leubner /* 3841dce93cd0SAchim Leubner * Initialize the adapter. 3842dce93cd0SAchim Leubner */ 38433fea9c0dSAchim Leubner max_msix_orig = sc->aac_max_msix; 38443fea9c0dSAchim Leubner msi_enabled_orig = sc->msi_enabled; 38453fea9c0dSAchim Leubner sc->msi_enabled = FALSE; 3846dce93cd0SAchim Leubner if (aac_check_firmware(sc) != 0) 3847dce93cd0SAchim Leubner goto finish; 3848dce93cd0SAchim Leubner if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) { 38493fea9c0dSAchim Leubner sc->aac_max_msix = max_msix_orig; 38503fea9c0dSAchim Leubner if (msi_enabled_orig) { 38513fea9c0dSAchim Leubner sc->msi_enabled = msi_enabled_orig; 38523fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_ENABLE_MSIX); 38533fea9c0dSAchim Leubner } 38543fea9c0dSAchim Leubner mtx_unlock(&sc->aac_io_lock); 38553fea9c0dSAchim Leubner aac_init(sc); 38563fea9c0dSAchim Leubner mtx_lock(&sc->aac_io_lock); 3857dce93cd0SAchim Leubner } 3858dce93cd0SAchim Leubner 3859dce93cd0SAchim Leubner finish: 3860dce93cd0SAchim Leubner sc->aac_state &= ~AAC_STATE_RESET; 38613fea9c0dSAchim Leubner AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT); 3862dce93cd0SAchim Leubner aacraid_startio(sc); 3863dce93cd0SAchim Leubner return (0); 3864dce93cd0SAchim Leubner } 3865