135863739SMike Smith /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 435863739SMike Smith * Copyright (c) 2000 Michael Smith 5c6eafcf2SScott Long * Copyright (c) 2001 Scott Long 635863739SMike Smith * Copyright (c) 2000 BSDi 7c6eafcf2SScott Long * Copyright (c) 2001 Adaptec, Inc. 835863739SMike Smith * All rights reserved. 935863739SMike Smith * 1035863739SMike Smith * Redistribution and use in source and binary forms, with or without 1135863739SMike Smith * modification, are permitted provided that the following conditions 1235863739SMike Smith * are met: 1335863739SMike Smith * 1. Redistributions of source code must retain the above copyright 1435863739SMike Smith * notice, this list of conditions and the following disclaimer. 1535863739SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1635863739SMike Smith * notice, this list of conditions and the following disclaimer in the 1735863739SMike Smith * documentation and/or other materials provided with the distribution. 1835863739SMike Smith * 1935863739SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2035863739SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2135863739SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2235863739SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2335863739SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2435863739SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2535863739SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2635863739SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2735863739SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2835863739SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2935863739SMike Smith * SUCH DAMAGE. 3035863739SMike Smith */ 3135863739SMike Smith 32aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 33aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 34aad970f1SDavid E. O'Brien 3535863739SMike Smith /* 3635863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3735863739SMike Smith */ 387cb209f5SScott Long #define AAC_DRIVERNAME "aac" 3935863739SMike Smith 40f6c4dd3fSScott Long #include "opt_aac.h" 41f6c4dd3fSScott Long 4236e0bf6eSScott Long /* #include <stddef.h> */ 4335863739SMike Smith #include <sys/param.h> 4435863739SMike Smith #include <sys/systm.h> 4535863739SMike Smith #include <sys/malloc.h> 4635863739SMike Smith #include <sys/kernel.h> 4736e0bf6eSScott Long #include <sys/kthread.h> 48f287c3e4SBrooks Davis #include <sys/proc.h> 493d04a9d7SScott Long #include <sys/sysctl.h> 50f287c3e4SBrooks Davis #include <sys/sysent.h> 51b3457b51SScott Long #include <sys/poll.h> 52891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 5335863739SMike Smith 5435863739SMike Smith #include <sys/bus.h> 5535863739SMike Smith #include <sys/conf.h> 5635863739SMike Smith #include <sys/signalvar.h> 570b94a66eSMike Smith #include <sys/time.h> 5836e0bf6eSScott Long #include <sys/eventhandler.h> 597cb209f5SScott Long #include <sys/rman.h> 6035863739SMike Smith 6135863739SMike Smith #include <machine/bus.h> 6235863739SMike Smith #include <machine/resource.h> 6335863739SMike Smith 647cb209f5SScott Long #include <dev/pci/pcireg.h> 657cb209f5SScott Long #include <dev/pci/pcivar.h> 667cb209f5SScott Long 6735863739SMike Smith #include <dev/aac/aacreg.h> 680b0594cdSScott Long #include <sys/aac_ioctl.h> 6935863739SMike Smith #include <dev/aac/aacvar.h> 7035863739SMike Smith #include <dev/aac/aac_tables.h> 7135863739SMike Smith 7235863739SMike Smith static void aac_startup(void *arg); 73914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 74cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 75fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 76ff0991c4SAttilio Rao static void aac_daemon(void *arg); 7735863739SMike Smith 7835863739SMike Smith /* Command Processing */ 790b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 8035863739SMike Smith static void aac_complete(void *context, int pending); 8135863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8235863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 83d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 8470545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8535863739SMike Smith 8635863739SMike Smith /* Command Buffer Management */ 87cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 88cd481291SScott Long int nseg, int error); 89c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 90c6eafcf2SScott Long int nseg, int error); 910b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 928480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9335863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9435863739SMike Smith 9535863739SMike Smith /* Hardware Interface */ 9604f4d586SEd Maste static int aac_alloc(struct aac_softc *sc); 97c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 98c6eafcf2SScott Long int error); 99fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 10035863739SMike Smith static int aac_init(struct aac_softc *sc); 10135863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 102c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 103c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 10404f4d586SEd Maste static int aac_setup_intr(struct aac_softc *sc); 105c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 106f6c4dd3fSScott Long struct aac_command *cm); 107c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 108914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10936e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 11036e0bf6eSScott Long struct aac_fib *fib); 11135863739SMike Smith 11235863739SMike Smith /* StrongARM interface */ 11335863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 11435863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 11535863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 11635863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 11735863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 118c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 119c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 120a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 12135863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 12235863739SMike Smith 123da4882c2SMarius Strobl const struct aac_interface aac_sa_interface = { 12435863739SMike Smith aac_sa_get_fwstatus, 12535863739SMike Smith aac_sa_qnotify, 12635863739SMike Smith aac_sa_get_istatus, 12735863739SMike Smith aac_sa_clear_istatus, 12835863739SMike Smith aac_sa_set_mailbox, 129a6d35632SScott Long aac_sa_get_mailbox, 1307cb209f5SScott Long aac_sa_set_interrupts, 1317cb209f5SScott Long NULL, NULL, NULL 13235863739SMike Smith }; 13335863739SMike Smith 13435863739SMike Smith /* i960Rx interface */ 13535863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 13635863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 13735863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 13835863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 13935863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 140c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 141c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 142a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 14335863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1447cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1457cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1467cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 14735863739SMike Smith 148da4882c2SMarius Strobl const struct aac_interface aac_rx_interface = { 14935863739SMike Smith aac_rx_get_fwstatus, 15035863739SMike Smith aac_rx_qnotify, 15135863739SMike Smith aac_rx_get_istatus, 15235863739SMike Smith aac_rx_clear_istatus, 15335863739SMike Smith aac_rx_set_mailbox, 154a6d35632SScott Long aac_rx_get_mailbox, 1557cb209f5SScott Long aac_rx_set_interrupts, 1567cb209f5SScott Long aac_rx_send_command, 1577cb209f5SScott Long aac_rx_get_outb_queue, 1587cb209f5SScott Long aac_rx_set_outb_queue 15935863739SMike Smith }; 16035863739SMike Smith 1614afedc31SScott Long /* Rocket/MIPS interface */ 1624afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1634afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1644afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1654afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1664afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1674afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1684afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1694afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1704afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1717cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1727cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1737cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1744afedc31SScott Long 175da4882c2SMarius Strobl const struct aac_interface aac_rkt_interface = { 1764afedc31SScott Long aac_rkt_get_fwstatus, 1774afedc31SScott Long aac_rkt_qnotify, 1784afedc31SScott Long aac_rkt_get_istatus, 1794afedc31SScott Long aac_rkt_clear_istatus, 1804afedc31SScott Long aac_rkt_set_mailbox, 1814afedc31SScott Long aac_rkt_get_mailbox, 1827cb209f5SScott Long aac_rkt_set_interrupts, 1837cb209f5SScott Long aac_rkt_send_command, 1847cb209f5SScott Long aac_rkt_get_outb_queue, 1857cb209f5SScott Long aac_rkt_set_outb_queue 1864afedc31SScott Long }; 1874afedc31SScott Long 18835863739SMike Smith /* Debugging and Diagnostics */ 18935863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 190da4882c2SMarius Strobl static const char *aac_describe_code(const struct aac_code_lookup *table, 191c6eafcf2SScott Long u_int32_t code); 19235863739SMike Smith 19335863739SMike Smith /* Management Interface */ 19435863739SMike Smith static d_open_t aac_open; 19535863739SMike Smith static d_ioctl_t aac_ioctl; 196b3457b51SScott Long static d_poll_t aac_poll; 197dfe2c294SAttilio Rao static void aac_cdevpriv_dtor(void *arg); 198c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 199f355c0e0SEd Maste static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 200c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 20136e0bf6eSScott Long struct aac_fib *fib); 202fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 203a723a548SEd Maste static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 204a723a548SEd Maste static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 205fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 206a723a548SEd Maste static int aac_return_aif(struct aac_softc *sc, 207a723a548SEd Maste struct aac_fib_context *ctx, caddr_t uptr); 20836e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2097cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2106d307336SEd Maste static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 2117cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2127cb209f5SScott Long struct aac_event *event, void *arg); 21304f4d586SEd Maste static struct aac_mntinforesp * 21404f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); 21535863739SMike Smith 21635863739SMike Smith static struct cdevsw aac_cdevsw = { 217dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 218dfdbb320SWarner Losh .d_flags = 0, 2197ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2207ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2217ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2227ac40f5fSPoul-Henning Kamp .d_name = "aac", 22335863739SMike Smith }; 22435863739SMike Smith 225d745c852SEd Schouten static MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 22636e0bf6eSScott Long 2273d04a9d7SScott Long /* sysctl node */ 2287029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 2297029da5cSPawel Biernacki "AAC driver parameters"); 2303d04a9d7SScott Long 231914da7d0SScott Long /* 232914da7d0SScott Long * Device Interface 233914da7d0SScott Long */ 23435863739SMike Smith 235914da7d0SScott Long /* 2364109ba51SEd Maste * Initialize the controller and softc 23735863739SMike Smith */ 23835863739SMike Smith int 23935863739SMike Smith aac_attach(struct aac_softc *sc) 24035863739SMike Smith { 24135863739SMike Smith int error, unit; 24235863739SMike Smith 24331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24435863739SMike Smith 24535863739SMike Smith /* 2464109ba51SEd Maste * Initialize per-controller queues. 24735863739SMike Smith */ 2480b94a66eSMike Smith aac_initq_free(sc); 2490b94a66eSMike Smith aac_initq_ready(sc); 2500b94a66eSMike Smith aac_initq_busy(sc); 2510b94a66eSMike Smith aac_initq_bio(sc); 25235863739SMike Smith 25335863739SMike Smith /* 2544109ba51SEd Maste * Initialize command-completion task. 25535863739SMike Smith */ 25635863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 25735863739SMike Smith 25835863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 26035863739SMike Smith 26135863739SMike Smith /* 262fe94b852SScott Long * Check that the firmware on the card is supported. 263fe94b852SScott Long */ 264fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 265fe94b852SScott Long return(error); 266fe94b852SScott Long 267f6b1c44dSScott Long /* 268f6b1c44dSScott Long * Initialize locks 269f6b1c44dSScott Long */ 270bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 271bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 272bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 273f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 274065dd78cSScott Long TAILQ_INIT(&sc->aac_ev_cmfree); 275f6b1c44dSScott Long 276ff0991c4SAttilio Rao /* Initialize the clock daemon callout. */ 277ff0991c4SAttilio Rao callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 278ff0991c4SAttilio Rao 2790b94a66eSMike Smith /* 2804109ba51SEd Maste * Initialize the adapter. 28135863739SMike Smith */ 28204f4d586SEd Maste if ((error = aac_alloc(sc)) != 0) 28304f4d586SEd Maste return(error); 2840b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 28535863739SMike Smith return(error); 28635863739SMike Smith 28735863739SMike Smith /* 2887cb209f5SScott Long * Allocate and connect our interrupt. 2897cb209f5SScott Long */ 29004f4d586SEd Maste if ((error = aac_setup_intr(sc)) != 0) 29104f4d586SEd Maste return(error); 2927cb209f5SScott Long 2937cb209f5SScott Long /* 29435863739SMike Smith * Print a little information about the controller. 29535863739SMike Smith */ 29635863739SMike Smith aac_describe_controller(sc); 29735863739SMike Smith 29835863739SMike Smith /* 2991423dcd6SEd Maste * Add sysctls. 3001423dcd6SEd Maste */ 3011423dcd6SEd Maste SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->aac_dev), 3021423dcd6SEd Maste SYSCTL_CHILDREN(device_get_sysctl_tree(sc->aac_dev)), 3031423dcd6SEd Maste OID_AUTO, "firmware_build", CTLFLAG_RD, 3041423dcd6SEd Maste &sc->aac_revision.buildNumber, 0, 3051423dcd6SEd Maste "firmware build number"); 3061423dcd6SEd Maste 3071423dcd6SEd Maste /* 308ae543596SScott Long * Register to probe our containers later. 309ae543596SScott Long */ 31035863739SMike Smith sc->aac_ich.ich_func = aac_startup; 31135863739SMike Smith sc->aac_ich.ich_arg = sc; 31235863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 313914da7d0SScott Long device_printf(sc->aac_dev, 314914da7d0SScott Long "can't establish configuration hook\n"); 31535863739SMike Smith return(ENXIO); 31635863739SMike Smith } 31735863739SMike Smith 31835863739SMike Smith /* 31935863739SMike Smith * Make the control device. 32035863739SMike Smith */ 32135863739SMike Smith unit = device_get_unit(sc->aac_dev); 3229e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3239e9466baSRobert Watson 0640, "aac%d", unit); 324157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3254aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 32635863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 32735863739SMike Smith 32836e0bf6eSScott Long /* Create the AIF thread */ 3293745c395SJulian Elischer if (kproc_create((void(*)(void *))aac_command_thread, sc, 330316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 331a620bad0SEd Maste panic("Could not create AIF thread"); 33236e0bf6eSScott Long 33336e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3345f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3355f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3365f54d522SScott Long device_printf(sc->aac_dev, 3375f54d522SScott Long "shutdown event registration failed\n"); 33836e0bf6eSScott Long 339fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 340a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 34170545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 342fe3cb0e1SScott Long aac_get_bus_info(sc); 34370545d1aSScott Long } 344fe3cb0e1SScott Long 345ff0991c4SAttilio Rao mtx_lock(&sc->aac_io_lock); 346867b1d34SEd Maste callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 347ff0991c4SAttilio Rao mtx_unlock(&sc->aac_io_lock); 348ff0991c4SAttilio Rao 34935863739SMike Smith return(0); 35035863739SMike Smith } 35135863739SMike Smith 352ff0991c4SAttilio Rao static void 353ff0991c4SAttilio Rao aac_daemon(void *arg) 354ff0991c4SAttilio Rao { 355ff0991c4SAttilio Rao struct timeval tv; 356ff0991c4SAttilio Rao struct aac_softc *sc; 357ff0991c4SAttilio Rao struct aac_fib *fib; 358ff0991c4SAttilio Rao 359ff0991c4SAttilio Rao sc = arg; 360ff0991c4SAttilio Rao mtx_assert(&sc->aac_io_lock, MA_OWNED); 361ff0991c4SAttilio Rao 362ff0991c4SAttilio Rao if (callout_pending(&sc->aac_daemontime) || 363ff0991c4SAttilio Rao callout_active(&sc->aac_daemontime) == 0) 364ff0991c4SAttilio Rao return; 365ff0991c4SAttilio Rao getmicrotime(&tv); 366ff0991c4SAttilio Rao aac_alloc_sync_fib(sc, &fib); 367ff0991c4SAttilio Rao *(uint32_t *)fib->data = tv.tv_sec; 368ff0991c4SAttilio Rao aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); 369ff0991c4SAttilio Rao aac_release_sync_fib(sc); 370ff0991c4SAttilio Rao callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 371ff0991c4SAttilio Rao } 372ff0991c4SAttilio Rao 3737cb209f5SScott Long void 3747cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event) 3757cb209f5SScott Long { 3767cb209f5SScott Long 3777cb209f5SScott Long switch (event->ev_type & AAC_EVENT_MASK) { 3787cb209f5SScott Long case AAC_EVENT_CMFREE: 3797cb209f5SScott Long TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 3807cb209f5SScott Long break; 3817cb209f5SScott Long default: 3827cb209f5SScott Long device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 3837cb209f5SScott Long event->ev_type); 3847cb209f5SScott Long break; 3857cb209f5SScott Long } 3867cb209f5SScott Long } 3877cb209f5SScott Long 388914da7d0SScott Long /* 38904f4d586SEd Maste * Request information of container #cid 39004f4d586SEd Maste */ 39104f4d586SEd Maste static struct aac_mntinforesp * 39204f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) 39304f4d586SEd Maste { 39404f4d586SEd Maste struct aac_mntinfo *mi; 39504f4d586SEd Maste 39604f4d586SEd Maste mi = (struct aac_mntinfo *)&fib->data[0]; 397523da39bSEd Maste /* use 64-bit LBA if enabled */ 398523da39bSEd Maste mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? 399523da39bSEd Maste VM_NameServe64 : VM_NameServe; 40004f4d586SEd Maste mi->MntType = FT_FILESYS; 40104f4d586SEd Maste mi->MntCount = cid; 40204f4d586SEd Maste 40304f4d586SEd Maste if (aac_sync_fib(sc, ContainerCommand, 0, fib, 40404f4d586SEd Maste sizeof(struct aac_mntinfo))) { 405dbb34a64SEd Maste device_printf(sc->aac_dev, "Error probing container %d\n", cid); 40604f4d586SEd Maste return (NULL); 40704f4d586SEd Maste } 40804f4d586SEd Maste 40904f4d586SEd Maste return ((struct aac_mntinforesp *)&fib->data[0]); 41004f4d586SEd Maste } 41104f4d586SEd Maste 41204f4d586SEd Maste /* 41335863739SMike Smith * Probe for containers, create disks. 41435863739SMike Smith */ 41535863739SMike Smith static void 41635863739SMike Smith aac_startup(void *arg) 41735863739SMike Smith { 418914da7d0SScott Long struct aac_softc *sc; 419cbfd045bSScott Long struct aac_fib *fib; 42004f4d586SEd Maste struct aac_mntinforesp *mir; 421795d7dc0SScott Long int count = 0, i = 0; 42235863739SMike Smith 423914da7d0SScott Long sc = (struct aac_softc *)arg; 42431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 425914da7d0SScott Long 4267cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 42703b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 428cbfd045bSScott Long 42935863739SMike Smith /* loop over possible containers */ 43036e0bf6eSScott Long do { 43104f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 43235863739SMike Smith continue; 43304f4d586SEd Maste if (i == 0) 434795d7dc0SScott Long count = mir->MntRespCount; 435cbfd045bSScott Long aac_add_container(sc, mir, 0); 43636e0bf6eSScott Long i++; 437795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 438cbfd045bSScott Long 439cbfd045bSScott Long aac_release_sync_fib(sc); 4407cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 44135863739SMike Smith 442cc336c78SScott Long /* mark the controller up */ 443cc336c78SScott Long sc->aac_state &= ~AAC_STATE_SUSPEND; 444cc336c78SScott Long 44535863739SMike Smith /* poke the bus to actually attach the child devices */ 44635863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 44735863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 44835863739SMike Smith 449cc336c78SScott Long /* disconnect ourselves from the intrhook chain */ 450cc336c78SScott Long config_intrhook_disestablish(&sc->aac_ich); 45135863739SMike Smith 45235863739SMike Smith /* enable interrupts now */ 45335863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 45435863739SMike Smith } 45535863739SMike Smith 456914da7d0SScott Long /* 4574109ba51SEd Maste * Create a device to represent a new container 458914da7d0SScott Long */ 459914da7d0SScott Long static void 460cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 461914da7d0SScott Long { 462914da7d0SScott Long struct aac_container *co; 463914da7d0SScott Long device_t child; 464914da7d0SScott Long 465914da7d0SScott Long /* 466914da7d0SScott Long * Check container volume type for validity. Note that many of 467914da7d0SScott Long * the possible types may never show up. 468914da7d0SScott Long */ 469914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 470a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 471a761a1caSScott Long M_NOWAIT | M_ZERO); 472914da7d0SScott Long if (co == NULL) 473a620bad0SEd Maste panic("Out of memory?!"); 47431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", 475914da7d0SScott Long mir->MntTable[0].ObjectId, 476914da7d0SScott Long mir->MntTable[0].FileSystemName, 477914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 478914da7d0SScott Long 479fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 480914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 481914da7d0SScott Long else 482914da7d0SScott Long device_set_ivars(child, co); 483914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 484914da7d0SScott Long mir->MntTable[0].VolType)); 485914da7d0SScott Long co->co_disk = child; 486914da7d0SScott Long co->co_found = f; 487914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 488914da7d0SScott Long sizeof(struct aac_mntobj)); 489bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 490914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 491bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 492914da7d0SScott Long } 493914da7d0SScott Long } 494914da7d0SScott Long 495914da7d0SScott Long /* 49604f4d586SEd Maste * Allocate resources associated with (sc) 49704f4d586SEd Maste */ 49804f4d586SEd Maste static int 49904f4d586SEd Maste aac_alloc(struct aac_softc *sc) 50004f4d586SEd Maste { 50131a0399eSEd Maste 50231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 50331a0399eSEd Maste 50404f4d586SEd Maste /* 50504f4d586SEd Maste * Create DMA tag for mapping buffers into controller-addressable space. 50604f4d586SEd Maste */ 50704f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 50804f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 50904f4d586SEd Maste (sc->flags & AAC_FLAGS_SG_64BIT) ? 51004f4d586SEd Maste BUS_SPACE_MAXADDR : 51104f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 51204f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 51304f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 5146f954fb3SAlexander Motin sc->aac_max_sectors << 9, /* maxsize */ 51504f4d586SEd Maste sc->aac_sg_tablesize, /* nsegments */ 5166f954fb3SAlexander Motin BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 51704f4d586SEd Maste BUS_DMA_ALLOCNOW, /* flags */ 51804f4d586SEd Maste busdma_lock_mutex, /* lockfunc */ 51904f4d586SEd Maste &sc->aac_io_lock, /* lockfuncarg */ 52004f4d586SEd Maste &sc->aac_buffer_dmat)) { 52104f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 52204f4d586SEd Maste return (ENOMEM); 52304f4d586SEd Maste } 52404f4d586SEd Maste 52504f4d586SEd Maste /* 52604f4d586SEd Maste * Create DMA tag for mapping FIBs into controller-addressable space.. 52704f4d586SEd Maste */ 52804f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 52904f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 53004f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 53104f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 53204f4d586SEd Maste 0x7fffffff, /* lowaddr */ 53304f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 53404f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 53504f4d586SEd Maste sc->aac_max_fibs_alloc * 53604f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 53704f4d586SEd Maste 1, /* nsegments */ 53804f4d586SEd Maste sc->aac_max_fibs_alloc * 53904f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 54004f4d586SEd Maste 0, /* flags */ 54104f4d586SEd Maste NULL, NULL, /* No locking needed */ 54204f4d586SEd Maste &sc->aac_fib_dmat)) { 543c2ede4b3SMartin Blapp device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 54404f4d586SEd Maste return (ENOMEM); 54504f4d586SEd Maste } 54604f4d586SEd Maste 54704f4d586SEd Maste /* 54804f4d586SEd Maste * Create DMA tag for the common structure and allocate it. 54904f4d586SEd Maste */ 55004f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 55104f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 55204f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 55304f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 55404f4d586SEd Maste 0x7fffffff, /* lowaddr */ 55504f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 55604f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 55704f4d586SEd Maste 8192 + sizeof(struct aac_common), /* maxsize */ 55804f4d586SEd Maste 1, /* nsegments */ 55904f4d586SEd Maste BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 56004f4d586SEd Maste 0, /* flags */ 56104f4d586SEd Maste NULL, NULL, /* No locking needed */ 56204f4d586SEd Maste &sc->aac_common_dmat)) { 56304f4d586SEd Maste device_printf(sc->aac_dev, 56404f4d586SEd Maste "can't allocate common structure DMA tag\n"); 56504f4d586SEd Maste return (ENOMEM); 56604f4d586SEd Maste } 56704f4d586SEd Maste if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 56804f4d586SEd Maste BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 56904f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate common structure\n"); 57004f4d586SEd Maste return (ENOMEM); 57104f4d586SEd Maste } 57204f4d586SEd Maste 57304f4d586SEd Maste /* 57404f4d586SEd Maste * Work around a bug in the 2120 and 2200 that cannot DMA commands 57504f4d586SEd Maste * below address 8192 in physical memory. 57604f4d586SEd Maste * XXX If the padding is not needed, can it be put to use instead 57704f4d586SEd Maste * of ignored? 57804f4d586SEd Maste */ 57904f4d586SEd Maste (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 58004f4d586SEd Maste sc->aac_common, 8192 + sizeof(*sc->aac_common), 58104f4d586SEd Maste aac_common_map, sc, 0); 58204f4d586SEd Maste 58304f4d586SEd Maste if (sc->aac_common_busaddr < 8192) { 58404f4d586SEd Maste sc->aac_common = (struct aac_common *) 58504f4d586SEd Maste ((uint8_t *)sc->aac_common + 8192); 58604f4d586SEd Maste sc->aac_common_busaddr += 8192; 58704f4d586SEd Maste } 58804f4d586SEd Maste bzero(sc->aac_common, sizeof(*sc->aac_common)); 58904f4d586SEd Maste 59004f4d586SEd Maste /* Allocate some FIBs and associated command structs */ 59104f4d586SEd Maste TAILQ_INIT(&sc->aac_fibmap_tqh); 59204f4d586SEd Maste sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 59304f4d586SEd Maste M_AACBUF, M_WAITOK|M_ZERO); 59423e876b1SJung-uk Kim while (sc->total_fibs < sc->aac_max_fibs) { 59504f4d586SEd Maste if (aac_alloc_commands(sc) != 0) 59604f4d586SEd Maste break; 59704f4d586SEd Maste } 59804f4d586SEd Maste if (sc->total_fibs == 0) 59904f4d586SEd Maste return (ENOMEM); 60004f4d586SEd Maste 60104f4d586SEd Maste return (0); 60204f4d586SEd Maste } 60304f4d586SEd Maste 60404f4d586SEd Maste /* 60535863739SMike Smith * Free all of the resources associated with (sc) 60635863739SMike Smith * 60735863739SMike Smith * Should not be called if the controller is active. 60835863739SMike Smith */ 60935863739SMike Smith void 61035863739SMike Smith aac_free(struct aac_softc *sc) 61135863739SMike Smith { 612ffb37f33SScott Long 61331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 61435863739SMike Smith 61535863739SMike Smith /* remove the control device */ 61635863739SMike Smith if (sc->aac_dev_t != NULL) 61735863739SMike Smith destroy_dev(sc->aac_dev_t); 61835863739SMike Smith 6190b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 6208480cc63SScott Long aac_free_commands(sc); 6210b94a66eSMike Smith if (sc->aac_fib_dmat) 6220b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 62335863739SMike Smith 624ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 625ffb37f33SScott Long 62635863739SMike Smith /* destroy the common area */ 62735863739SMike Smith if (sc->aac_common) { 62835863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 629c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 630c6eafcf2SScott Long sc->aac_common_dmamap); 63135863739SMike Smith } 6320b94a66eSMike Smith if (sc->aac_common_dmat) 6330b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 63435863739SMike Smith 63535863739SMike Smith /* disconnect the interrupt handler */ 63635863739SMike Smith if (sc->aac_intr) 63735863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 638bbc03f1bSMarius Strobl if (sc->aac_irq != NULL) { 639da4882c2SMarius Strobl bus_release_resource(sc->aac_dev, SYS_RES_IRQ, 640da4882c2SMarius Strobl rman_get_rid(sc->aac_irq), sc->aac_irq); 641bbc03f1bSMarius Strobl pci_release_msi(sc->aac_dev); 642bbc03f1bSMarius Strobl } 64335863739SMike Smith 64435863739SMike Smith /* destroy data-transfer DMA tag */ 64535863739SMike Smith if (sc->aac_buffer_dmat) 64635863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 64735863739SMike Smith 64835863739SMike Smith /* destroy the parent DMA tag */ 64935863739SMike Smith if (sc->aac_parent_dmat) 65035863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 65135863739SMike Smith 65235863739SMike Smith /* release the register window mapping */ 653ff0991c4SAttilio Rao if (sc->aac_regs_res0 != NULL) 654914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 655da4882c2SMarius Strobl rman_get_rid(sc->aac_regs_res0), sc->aac_regs_res0); 656ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) 657ff0991c4SAttilio Rao bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 658da4882c2SMarius Strobl rman_get_rid(sc->aac_regs_res1), sc->aac_regs_res1); 65935863739SMike Smith } 66035863739SMike Smith 661914da7d0SScott Long /* 66235863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 66335863739SMike Smith */ 66435863739SMike Smith int 66535863739SMike Smith aac_detach(device_t dev) 66635863739SMike Smith { 667914da7d0SScott Long struct aac_softc *sc; 66870545d1aSScott Long struct aac_container *co; 66970545d1aSScott Long struct aac_sim *sim; 67035863739SMike Smith int error; 67135863739SMike Smith 672914da7d0SScott Long sc = device_get_softc(dev); 67331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 674914da7d0SScott Long 675ff0991c4SAttilio Rao callout_drain(&sc->aac_daemontime); 676ff0991c4SAttilio Rao 6771bd320ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 6781bd320ecSAttilio Rao while (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 6791bd320ecSAttilio Rao sc->aifflags |= AAC_AIFFLAGS_EXIT; 6801bd320ecSAttilio Rao wakeup(sc->aifthread); 6811bd320ecSAttilio Rao msleep(sc->aac_dev, &sc->aac_io_lock, PUSER, "aacdch", 0); 6821bd320ecSAttilio Rao } 6831bd320ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 6841bd320ecSAttilio Rao KASSERT((sc->aifflags & AAC_AIFFLAGS_RUNNING) == 0, 6851bd320ecSAttilio Rao ("%s: invalid detach state", __func__)); 6861bd320ecSAttilio Rao 68770545d1aSScott Long /* Remove the child containers */ 688a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 68970545d1aSScott Long error = device_delete_child(dev, co->co_disk); 69070545d1aSScott Long if (error) 69170545d1aSScott Long return (error); 69265ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 693a761a1caSScott Long free(co, M_AACBUF); 69470545d1aSScott Long } 69570545d1aSScott Long 69670545d1aSScott Long /* Remove the CAM SIMs */ 697a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 698a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 69970545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 70070545d1aSScott Long if (error) 70170545d1aSScott Long return (error); 702a761a1caSScott Long free(sim, M_AACBUF); 70370545d1aSScott Long } 70470545d1aSScott Long 70535863739SMike Smith if ((error = aac_shutdown(dev))) 70635863739SMike Smith return(error); 70735863739SMike Smith 7085f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 7095f54d522SScott Long 71035863739SMike Smith aac_free(sc); 71135863739SMike Smith 712dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 713dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 714dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 715dc9efde5SScott Long 71635863739SMike Smith return(0); 71735863739SMike Smith } 71835863739SMike Smith 719914da7d0SScott Long /* 72035863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 72135863739SMike Smith * 72235863739SMike Smith * This function is called before detach or system shutdown. 72335863739SMike Smith * 7240b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 72535863739SMike Smith * allow shutdown if any device is open. 72635863739SMike Smith */ 72735863739SMike Smith int 72835863739SMike Smith aac_shutdown(device_t dev) 72935863739SMike Smith { 730914da7d0SScott Long struct aac_softc *sc; 731cbfd045bSScott Long struct aac_fib *fib; 732cbfd045bSScott Long struct aac_close_command *cc; 73335863739SMike Smith 734914da7d0SScott Long sc = device_get_softc(dev); 73531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 736914da7d0SScott Long 73735863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 73835863739SMike Smith 73935863739SMike Smith /* 74035863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 74135863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 74235863739SMike Smith * We've been closed and all I/O completed already 74335863739SMike Smith */ 74435863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 74535863739SMike Smith 7467cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 74703b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 748cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 749cbfd045bSScott Long 75039ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 751cbfd045bSScott Long cc->Command = VM_CloseAll; 752cbfd045bSScott Long cc->ContainerId = 0xffffffff; 753cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 754cbfd045bSScott Long sizeof(struct aac_close_command))) 75535863739SMike Smith printf("FAILED.\n"); 75670545d1aSScott Long else 75770545d1aSScott Long printf("done\n"); 75870545d1aSScott Long #if 0 759914da7d0SScott Long else { 760cbfd045bSScott Long fib->data[0] = 0; 76136e0bf6eSScott Long /* 762914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 76336e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 76436e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 76536e0bf6eSScott Long * driver module with the intent to reload it later. 76636e0bf6eSScott Long */ 767cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 768cbfd045bSScott Long fib, 1)) { 76935863739SMike Smith printf("FAILED.\n"); 77035863739SMike Smith } else { 77135863739SMike Smith printf("done.\n"); 77235863739SMike Smith } 77335863739SMike Smith } 77470545d1aSScott Long #endif 77535863739SMike Smith 77635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 7773576af8fSScott Long aac_release_sync_fib(sc); 7787cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 77935863739SMike Smith 78035863739SMike Smith return(0); 78135863739SMike Smith } 78235863739SMike Smith 783914da7d0SScott Long /* 78435863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 78535863739SMike Smith */ 78635863739SMike Smith int 78735863739SMike Smith aac_suspend(device_t dev) 78835863739SMike Smith { 789914da7d0SScott Long struct aac_softc *sc; 79035863739SMike Smith 791914da7d0SScott Long sc = device_get_softc(dev); 792914da7d0SScott Long 79331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 79435863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 79535863739SMike Smith 79635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 79735863739SMike Smith return(0); 79835863739SMike Smith } 79935863739SMike Smith 800914da7d0SScott Long /* 80135863739SMike Smith * Bring the controller back to a state ready for operation. 80235863739SMike Smith */ 80335863739SMike Smith int 80435863739SMike Smith aac_resume(device_t dev) 80535863739SMike Smith { 806914da7d0SScott Long struct aac_softc *sc; 80735863739SMike Smith 808914da7d0SScott Long sc = device_get_softc(dev); 809914da7d0SScott Long 81031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 81135863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 81235863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 81335863739SMike Smith return(0); 81435863739SMike Smith } 81535863739SMike Smith 816914da7d0SScott Long /* 8177cb209f5SScott Long * Interrupt handler for NEW_COMM interface. 81835863739SMike Smith */ 81935863739SMike Smith void 8207cb209f5SScott Long aac_new_intr(void *arg) 8217cb209f5SScott Long { 8227cb209f5SScott Long struct aac_softc *sc; 8237cb209f5SScott Long u_int32_t index, fast; 8247cb209f5SScott Long struct aac_command *cm; 8257cb209f5SScott Long struct aac_fib *fib; 8267cb209f5SScott Long int i; 8277cb209f5SScott Long 8287cb209f5SScott Long sc = (struct aac_softc *)arg; 8297cb209f5SScott Long 83031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 8317cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 8327cb209f5SScott Long while (1) { 8337cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8347cb209f5SScott Long if (index == 0xffffffff) 8357cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8367cb209f5SScott Long if (index == 0xffffffff) 8377cb209f5SScott Long break; 8387cb209f5SScott Long if (index & 2) { 8397cb209f5SScott Long if (index == 0xfffffffe) { 8407cb209f5SScott Long /* XXX This means that the controller wants 8417cb209f5SScott Long * more work. Ignore it for now. 8427cb209f5SScott Long */ 8437cb209f5SScott Long continue; 8447cb209f5SScott Long } 8457cb209f5SScott Long /* AIF */ 8467cb209f5SScott Long fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 8477cb209f5SScott Long M_NOWAIT | M_ZERO); 8487cb209f5SScott Long if (fib == NULL) { 8497cb209f5SScott Long /* If we're really this short on memory, 8507cb209f5SScott Long * hopefully breaking out of the handler will 8517cb209f5SScott Long * allow something to get freed. This 8527cb209f5SScott Long * actually sucks a whole lot. 8537cb209f5SScott Long */ 8547cb209f5SScott Long break; 8557cb209f5SScott Long } 8567cb209f5SScott Long index &= ~2; 8577cb209f5SScott Long for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 858ff0991c4SAttilio Rao ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); 8597cb209f5SScott Long aac_handle_aif(sc, fib); 8607cb209f5SScott Long free(fib, M_AACBUF); 8617cb209f5SScott Long 8627cb209f5SScott Long /* 8637cb209f5SScott Long * AIF memory is owned by the adapter, so let it 8647cb209f5SScott Long * know that we are done with it. 8657cb209f5SScott Long */ 8667cb209f5SScott Long AAC_SET_OUTB_QUEUE(sc, index); 8677cb209f5SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 8687cb209f5SScott Long } else { 8697cb209f5SScott Long fast = index & 1; 8707cb209f5SScott Long cm = sc->aac_commands + (index >> 2); 8717cb209f5SScott Long fib = cm->cm_fib; 8727cb209f5SScott Long if (fast) { 8737cb209f5SScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 8747cb209f5SScott Long *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 8757cb209f5SScott Long } 8767cb209f5SScott Long aac_remove_busy(cm); 8777cb209f5SScott Long aac_unmap_command(cm); 8787cb209f5SScott Long cm->cm_flags |= AAC_CMD_COMPLETED; 8797cb209f5SScott Long 8807cb209f5SScott Long /* is there a completion handler? */ 8817cb209f5SScott Long if (cm->cm_complete != NULL) { 8827cb209f5SScott Long cm->cm_complete(cm); 8837cb209f5SScott Long } else { 8847cb209f5SScott Long /* assume that someone is sleeping on this 8857cb209f5SScott Long * command 8867cb209f5SScott Long */ 8877cb209f5SScott Long wakeup(cm); 8887cb209f5SScott Long } 8897cb209f5SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 8907cb209f5SScott Long } 8917cb209f5SScott Long } 8927cb209f5SScott Long /* see if we can start some more I/O */ 8937cb209f5SScott Long if ((sc->flags & AAC_QUEUE_FRZN) == 0) 8947cb209f5SScott Long aac_startio(sc); 8957cb209f5SScott Long 8967cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 8977cb209f5SScott Long } 8987cb209f5SScott Long 899e46b9eeaSEd Maste /* 900e46b9eeaSEd Maste * Interrupt filter for !NEW_COMM interface. 901e46b9eeaSEd Maste */ 902ef544f63SPaolo Pisati int 903e46b9eeaSEd Maste aac_filter(void *arg) 90435863739SMike Smith { 905914da7d0SScott Long struct aac_softc *sc; 90670545d1aSScott Long u_int16_t reason; 90735863739SMike Smith 908914da7d0SScott Long sc = (struct aac_softc *)arg; 909914da7d0SScott Long 91031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 911f30ac74cSScott Long /* 9129148fa21SScott Long * Read the status register directly. This is faster than taking the 9139148fa21SScott Long * driver lock and reading the queues directly. It also saves having 9149148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 9159148fa21SScott Long * ugly. 916f30ac74cSScott Long */ 91735863739SMike Smith reason = AAC_GET_ISTATUS(sc); 918f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 919f30ac74cSScott Long 9209c3a7fceSScott Long /* handle completion processing */ 9219148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 922cbc4d2dbSJohn Baldwin taskqueue_enqueue(taskqueue_fast, &sc->aac_task_complete); 92335863739SMike Smith 9249148fa21SScott Long /* controller wants to talk to us */ 9259148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 92670545d1aSScott Long /* 9279148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 9289148fa21SScott Long * that start with a NULL. 92970545d1aSScott Long */ 9309148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 9319148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 9329148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 93370545d1aSScott Long 9349148fa21SScott Long /* 9359148fa21SScott Long * This might miss doing the actual wakeup. However, the 936a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 9379148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 9389148fa21SScott Long * priority that they can handle hanging out for a few seconds 9399148fa21SScott Long * if needed. 9409148fa21SScott Long */ 94136e0bf6eSScott Long wakeup(sc->aifthread); 94236e0bf6eSScott Long } 943ef544f63SPaolo Pisati return (FILTER_HANDLED); 9449148fa21SScott Long } 94535863739SMike Smith 946c6eafcf2SScott Long /* 947914da7d0SScott Long * Command Processing 948914da7d0SScott Long */ 94935863739SMike Smith 950914da7d0SScott Long /* 95135863739SMike Smith * Start as much queued I/O as possible on the controller 95235863739SMike Smith */ 953fe3cb0e1SScott Long void 95435863739SMike Smith aac_startio(struct aac_softc *sc) 95535863739SMike Smith { 95635863739SMike Smith struct aac_command *cm; 957397fa34fSScott Long int error; 95835863739SMike Smith 95931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 96035863739SMike Smith 96135863739SMike Smith for (;;) { 962914da7d0SScott Long /* 963397fa34fSScott Long * This flag might be set if the card is out of resources. 964397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 965397fa34fSScott Long */ 966397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 967397fa34fSScott Long break; 968397fa34fSScott Long 969397fa34fSScott Long /* 970914da7d0SScott Long * Try to get a command that's been put off for lack of 971914da7d0SScott Long * resources 972914da7d0SScott Long */ 97335863739SMike Smith cm = aac_dequeue_ready(sc); 97435863739SMike Smith 975914da7d0SScott Long /* 976914da7d0SScott Long * Try to build a command off the bio queue (ignore error 977914da7d0SScott Long * return) 978914da7d0SScott Long */ 9790b94a66eSMike Smith if (cm == NULL) 98035863739SMike Smith aac_bio_command(sc, &cm); 98135863739SMike Smith 98235863739SMike Smith /* nothing to do? */ 98335863739SMike Smith if (cm == NULL) 98435863739SMike Smith break; 98535863739SMike Smith 986cd481291SScott Long /* don't map more than once */ 987cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 9884102d44bSScott Long panic("aac: command %p already mapped", cm); 98935863739SMike Smith 990397fa34fSScott Long /* 991397fa34fSScott Long * Set up the command to go to the controller. If there are no 992397fa34fSScott Long * data buffers associated with the command then it can bypass 993397fa34fSScott Long * busdma. 994397fa34fSScott Long */ 995cd481291SScott Long if (cm->cm_datalen != 0) { 9968fce673cSMarius Strobl if (cm->cm_flags & AAC_REQ_BIO) 9978fce673cSMarius Strobl error = bus_dmamap_load_bio( 9988fce673cSMarius Strobl sc->aac_buffer_dmat, cm->cm_datamap, 9998fce673cSMarius Strobl (struct bio *)cm->cm_private, 10008fce673cSMarius Strobl aac_map_command_sg, cm, 0); 10018fce673cSMarius Strobl else 1002397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 1003397fa34fSScott Long cm->cm_datamap, cm->cm_data, 10048fce673cSMarius Strobl cm->cm_datalen, aac_map_command_sg, cm, 0); 1005cd481291SScott Long if (error == EINPROGRESS) { 100631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); 1007cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 1008614c22b2SScott Long } else if (error != 0) 1009397fa34fSScott Long panic("aac_startio: unexpected error %d from " 1010a620bad0SEd Maste "busdma", error); 1011397fa34fSScott Long } else 10128778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 1013cd481291SScott Long } 101435863739SMike Smith } 101535863739SMike Smith 1016914da7d0SScott Long /* 101735863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 101835863739SMike Smith */ 101935863739SMike Smith static void 102070545d1aSScott Long aac_command_thread(struct aac_softc *sc) 102135863739SMike Smith { 102235863739SMike Smith struct aac_fib *fib; 102335863739SMike Smith u_int32_t fib_size; 10249148fa21SScott Long int size, retval; 102535863739SMike Smith 102631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 102735863739SMike Smith 1028bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1029a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 103036e0bf6eSScott Long 1031a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1032a32a982dSScott Long retval = 0; 1033a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1034a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1035a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 103636e0bf6eSScott Long 10379148fa21SScott Long /* 10389148fa21SScott Long * First see if any FIBs need to be allocated. This needs 10399148fa21SScott Long * to be called without the driver lock because contigmalloc 10401bd320ecSAttilio Rao * can sleep. 10419148fa21SScott Long */ 10429148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1043bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 1044a32a982dSScott Long aac_alloc_commands(sc); 1045bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 10464102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1047a32a982dSScott Long aac_startio(sc); 1048a32a982dSScott Long } 10499148fa21SScott Long 10509148fa21SScott Long /* 10519148fa21SScott Long * While we're here, check to see if any commands are stuck. 10529148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 10539148fa21SScott Long * always fire. 10549148fa21SScott Long */ 10559148fa21SScott Long if (retval == EWOULDBLOCK) 105670545d1aSScott Long aac_timeout(sc); 105770545d1aSScott Long 105870545d1aSScott Long /* Check the hardware printf message buffer */ 10599148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 106070545d1aSScott Long aac_print_printf(sc); 106170545d1aSScott Long 10629148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 10637cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 10647cb209f5SScott Long continue; 10657cb209f5SScott Long for (;;) { 10667cb209f5SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 10677cb209f5SScott Long &fib_size, &fib)) 10687cb209f5SScott Long break; 106935863739SMike Smith 107036e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 107136e0bf6eSScott Long 107235863739SMike Smith switch (fib->Header.Command) { 107335863739SMike Smith case AifRequest: 107436e0bf6eSScott Long aac_handle_aif(sc, fib); 107535863739SMike Smith break; 107635863739SMike Smith default: 1077914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 1078914da7d0SScott Long "from controller\n"); 107935863739SMike Smith break; 108035863739SMike Smith } 108135863739SMike Smith 108236e0bf6eSScott Long if ((fib->Header.XferState == 0) || 10837cb209f5SScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 108436e0bf6eSScott Long break; 10857cb209f5SScott Long } 108636e0bf6eSScott Long 108770545d1aSScott Long /* Return the AIF to the controller. */ 108836e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 108936e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 109036e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 109136e0bf6eSScott Long 109236e0bf6eSScott Long /* XXX Compute the Size field? */ 109336e0bf6eSScott Long size = fib->Header.Size; 109436e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 109536e0bf6eSScott Long size = sizeof(struct aac_fib); 109636e0bf6eSScott Long fib->Header.Size = size; 109736e0bf6eSScott Long } 109836e0bf6eSScott Long /* 1099914da7d0SScott Long * Since we did not generate this command, it 1100914da7d0SScott Long * cannot go through the normal 1101914da7d0SScott Long * enqueue->startio chain. 110236e0bf6eSScott Long */ 1103914da7d0SScott Long aac_enqueue_response(sc, 1104914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 1105914da7d0SScott Long fib); 110636e0bf6eSScott Long } 110736e0bf6eSScott Long } 110836e0bf6eSScott Long } 110936e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1110bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 111136e0bf6eSScott Long wakeup(sc->aac_dev); 111236e0bf6eSScott Long 11133745c395SJulian Elischer kproc_exit(0); 111435863739SMike Smith } 111535863739SMike Smith 1116914da7d0SScott Long /* 11179c3a7fceSScott Long * Process completed commands. 111835863739SMike Smith */ 111935863739SMike Smith static void 11209c3a7fceSScott Long aac_complete(void *context, int pending) 112135863739SMike Smith { 11229c3a7fceSScott Long struct aac_softc *sc; 112335863739SMike Smith struct aac_command *cm; 112435863739SMike Smith struct aac_fib *fib; 112535863739SMike Smith u_int32_t fib_size; 112635863739SMike Smith 11279c3a7fceSScott Long sc = (struct aac_softc *)context; 112831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 11299c3a7fceSScott Long 1130bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1131ae543596SScott Long 11329c3a7fceSScott Long /* pull completed commands off the queue */ 113335863739SMike Smith for (;;) { 113435863739SMike Smith /* look for completed FIBs on our queue */ 1135914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1136914da7d0SScott Long &fib)) 113735863739SMike Smith break; /* nothing to do */ 113835863739SMike Smith 1139ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 1140cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 114135863739SMike Smith if (cm == NULL) { 114235863739SMike Smith AAC_PRINT_FIB(sc, fib); 11439c3a7fceSScott Long break; 11449c3a7fceSScott Long } 11453e507710SEd Maste if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0) 11463e507710SEd Maste device_printf(sc->aac_dev, 11473e507710SEd Maste "COMMAND %p COMPLETED AFTER %d SECONDS\n", 11483e507710SEd Maste cm, (int)(time_uptime-cm->cm_timestamp)); 11493e507710SEd Maste 11500b94a66eSMike Smith aac_remove_busy(cm); 11517cb209f5SScott Long 1152ecd1c51fSScott Long aac_unmap_command(cm); 115335863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 115435863739SMike Smith 115535863739SMike Smith /* is there a completion handler? */ 115635863739SMike Smith if (cm->cm_complete != NULL) { 115735863739SMike Smith cm->cm_complete(cm); 115835863739SMike Smith } else { 115935863739SMike Smith /* assume that someone is sleeping on this command */ 116035863739SMike Smith wakeup(cm); 116135863739SMike Smith } 116235863739SMike Smith } 11630b94a66eSMike Smith 11640b94a66eSMike Smith /* see if we can start some more I/O */ 1165cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 11660b94a66eSMike Smith aac_startio(sc); 1167ae543596SScott Long 1168bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 116935863739SMike Smith } 117035863739SMike Smith 1171914da7d0SScott Long /* 117235863739SMike Smith * Handle a bio submitted from a disk device. 117335863739SMike Smith */ 117435863739SMike Smith void 117535863739SMike Smith aac_submit_bio(struct bio *bp) 117635863739SMike Smith { 1177914da7d0SScott Long struct aac_disk *ad; 1178914da7d0SScott Long struct aac_softc *sc; 117935863739SMike Smith 11807540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1181914da7d0SScott Long sc = ad->ad_controller; 118231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1183914da7d0SScott Long 118435863739SMike Smith /* queue the BIO and try to get some work done */ 11850b94a66eSMike Smith aac_enqueue_bio(sc, bp); 118635863739SMike Smith aac_startio(sc); 118735863739SMike Smith } 118835863739SMike Smith 1189914da7d0SScott Long /* 119035863739SMike Smith * Get a bio and build a command to go with it. 119135863739SMike Smith */ 119235863739SMike Smith static int 119335863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 119435863739SMike Smith { 119535863739SMike Smith struct aac_command *cm; 119635863739SMike Smith struct aac_fib *fib; 119735863739SMike Smith struct aac_disk *ad; 119835863739SMike Smith struct bio *bp; 119935863739SMike Smith 120031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 120135863739SMike Smith 120235863739SMike Smith /* get the resources we will need */ 120335863739SMike Smith cm = NULL; 1204a32a982dSScott Long bp = NULL; 120535863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 120635863739SMike Smith goto fail; 1207a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 1208a32a982dSScott Long goto fail; 120935863739SMike Smith 121035863739SMike Smith /* fill out the command */ 12110b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 12120b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 12138fce673cSMarius Strobl cm->cm_flags = AAC_REQ_BIO; 121435863739SMike Smith cm->cm_private = bp; 12152b3b0f17SScott Long cm->cm_timestamp = time_uptime; 121635863739SMike Smith 121735863739SMike Smith /* build the FIB */ 121835863739SMike Smith fib = cm->cm_fib; 1219b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 122035863739SMike Smith fib->Header.XferState = 122135863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 122235863739SMike Smith AAC_FIBSTATE_INITIALISED | 1223f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 122435863739SMike Smith AAC_FIBSTATE_FROMHOST | 122535863739SMike Smith AAC_FIBSTATE_REXPECTED | 1226f30ac74cSScott Long AAC_FIBSTATE_NORM | 1227f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 1228f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 122935863739SMike Smith 123035863739SMike Smith /* build the read/write request */ 12317540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1232b85f5808SScott Long 12337cb209f5SScott Long if (sc->flags & AAC_FLAGS_RAW_IO) { 12347cb209f5SScott Long struct aac_raw_io *raw; 12357cb209f5SScott Long raw = (struct aac_raw_io *)&fib->data[0]; 12367cb209f5SScott Long fib->Header.Command = RawIo; 12377cb209f5SScott Long raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 12387cb209f5SScott Long raw->ByteCount = bp->bio_bcount; 12397cb209f5SScott Long raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 12407cb209f5SScott Long raw->BpTotal = 0; 12417cb209f5SScott Long raw->BpComplete = 0; 12427cb209f5SScott Long fib->Header.Size += sizeof(struct aac_raw_io); 12437cb209f5SScott Long cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 12447cb209f5SScott Long if (bp->bio_cmd == BIO_READ) { 12457cb209f5SScott Long raw->Flags = 1; 12467cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 12477cb209f5SScott Long } else { 12487cb209f5SScott Long raw->Flags = 0; 12497cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 12507cb209f5SScott Long } 12517cb209f5SScott Long } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1252b85f5808SScott Long fib->Header.Command = ContainerCommand; 12539e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 1254b85f5808SScott Long struct aac_blockread *br; 125535863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 125635863739SMike Smith br->Command = VM_CtBlockRead; 125735863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 125835863739SMike Smith br->BlockNumber = bp->bio_pblkno; 125935863739SMike Smith br->ByteCount = bp->bio_bcount; 126035863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 126135863739SMike Smith cm->cm_sgtable = &br->SgMap; 126235863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 126335863739SMike Smith } else { 1264b85f5808SScott Long struct aac_blockwrite *bw; 126535863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 126635863739SMike Smith bw->Command = VM_CtBlockWrite; 126735863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 126835863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 126935863739SMike Smith bw->ByteCount = bp->bio_bcount; 1270b85f5808SScott Long bw->Stable = CUNSTABLE; 127135863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 127235863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 127335863739SMike Smith cm->cm_sgtable = &bw->SgMap; 127435863739SMike Smith } 1275b85f5808SScott Long } else { 1276b85f5808SScott Long fib->Header.Command = ContainerCommand64; 1277b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 1278b85f5808SScott Long struct aac_blockread64 *br; 1279b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 1280b85f5808SScott Long br->Command = VM_CtHostRead64; 1281b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1282b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1283b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 1284b85f5808SScott Long br->Pad = 0; 1285b85f5808SScott Long br->Flags = 0; 1286b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 128754e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAIN; 1288eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1289b85f5808SScott Long } else { 1290b85f5808SScott Long struct aac_blockwrite64 *bw; 1291b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 1292b85f5808SScott Long bw->Command = VM_CtHostWrite64; 1293b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1294b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1295b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 1296b85f5808SScott Long bw->Pad = 0; 1297b85f5808SScott Long bw->Flags = 0; 1298b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 129954e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAOUT; 1300eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1301b85f5808SScott Long } 1302b85f5808SScott Long } 130335863739SMike Smith 130435863739SMike Smith *cmp = cm; 130535863739SMike Smith return(0); 130635863739SMike Smith 130735863739SMike Smith fail: 13087cb209f5SScott Long if (bp != NULL) 13097cb209f5SScott Long aac_enqueue_bio(sc, bp); 131035863739SMike Smith if (cm != NULL) 131135863739SMike Smith aac_release_command(cm); 131235863739SMike Smith return(ENOMEM); 131335863739SMike Smith } 131435863739SMike Smith 1315914da7d0SScott Long /* 131635863739SMike Smith * Handle a bio-instigated command that has been completed. 131735863739SMike Smith */ 131835863739SMike Smith static void 131935863739SMike Smith aac_bio_complete(struct aac_command *cm) 132035863739SMike Smith { 132135863739SMike Smith struct aac_blockread_response *brr; 132235863739SMike Smith struct aac_blockwrite_response *bwr; 132335863739SMike Smith struct bio *bp; 132435863739SMike Smith AAC_FSAStatus status; 132535863739SMike Smith 132635863739SMike Smith /* fetch relevant status and then release the command */ 132735863739SMike Smith bp = (struct bio *)cm->cm_private; 13289e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 132935863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 133035863739SMike Smith status = brr->Status; 133135863739SMike Smith } else { 133235863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 133335863739SMike Smith status = bwr->Status; 133435863739SMike Smith } 133535863739SMike Smith aac_release_command(cm); 133635863739SMike Smith 133735863739SMike Smith /* fix up the bio based on status */ 133835863739SMike Smith if (status == ST_OK) { 133935863739SMike Smith bp->bio_resid = 0; 134035863739SMike Smith } else { 134135863739SMike Smith bp->bio_error = EIO; 134235863739SMike Smith bp->bio_flags |= BIO_ERROR; 134335863739SMike Smith } 13440b94a66eSMike Smith aac_biodone(bp); 134535863739SMike Smith } 134635863739SMike Smith 1347914da7d0SScott Long /* 134835863739SMike Smith * Submit a command to the controller, return when it completes. 1349b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1350b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1351d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1352d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1353d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1354d8a0a473SScott Long * card completing a command late and spamming the command and data 1355d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 135635863739SMike Smith */ 135735863739SMike Smith static int 1358d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 135935863739SMike Smith { 1360ae543596SScott Long struct aac_softc *sc; 1361d8a0a473SScott Long int error; 136235863739SMike Smith 1363ae543596SScott Long sc = cm->cm_sc; 136431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1365ae543596SScott Long 136635863739SMike Smith /* Put the command on the ready queue and get things going */ 136735863739SMike Smith aac_enqueue_ready(cm); 1368ae543596SScott Long aac_startio(sc); 1369ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 137035863739SMike Smith return(error); 137135863739SMike Smith } 137235863739SMike Smith 1373914da7d0SScott Long /* 1374914da7d0SScott Long *Command Buffer Management 1375914da7d0SScott Long */ 137635863739SMike Smith 1377914da7d0SScott Long /* 137835863739SMike Smith * Allocate a command. 137935863739SMike Smith */ 1380fe3cb0e1SScott Long int 138135863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 138235863739SMike Smith { 138335863739SMike Smith struct aac_command *cm; 138435863739SMike Smith 138531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 138635863739SMike Smith 1387ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1388b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 13891bd320ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 1390ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 13911bd320ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 1392ae543596SScott Long wakeup(sc->aifthread); 1393b85f5808SScott Long } 1394ae543596SScott Long return (EBUSY); 1395ffb37f33SScott Long } 139635863739SMike Smith 13970b94a66eSMike Smith *cmp = cm; 13980b94a66eSMike Smith return(0); 13990b94a66eSMike Smith } 14000b94a66eSMike Smith 1401914da7d0SScott Long /* 14020b94a66eSMike Smith * Release a command back to the freelist. 14030b94a66eSMike Smith */ 1404fe3cb0e1SScott Long void 14050b94a66eSMike Smith aac_release_command(struct aac_command *cm) 14060b94a66eSMike Smith { 14077cb209f5SScott Long struct aac_event *event; 14087cb209f5SScott Long struct aac_softc *sc; 14097cb209f5SScott Long 141031a0399eSEd Maste sc = cm->cm_sc; 141131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 14120b94a66eSMike Smith 14134109ba51SEd Maste /* (re)initialize the command/FIB */ 1414b2b39b04SJohn Baldwin cm->cm_datalen = 0; 141535863739SMike Smith cm->cm_sgtable = NULL; 141635863739SMike Smith cm->cm_flags = 0; 141735863739SMike Smith cm->cm_complete = NULL; 141835863739SMike Smith cm->cm_private = NULL; 1419dbfc5960SEd Maste cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 142035863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 142135863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 142235863739SMike Smith cm->cm_fib->Header.Flags = 0; 14237cb209f5SScott Long cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 142435863739SMike Smith 142535863739SMike Smith /* 142635863739SMike Smith * These are duplicated in aac_start to cover the case where an 142735863739SMike Smith * intermediate stage may have destroyed them. They're left 14284109ba51SEd Maste * initialized here for debugging purposes only. 142935863739SMike Smith */ 1430f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1431f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 143235863739SMike Smith 143335863739SMike Smith aac_enqueue_free(cm); 14347cb209f5SScott Long 14352ad1c92dSEd Maste if ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 14367cb209f5SScott Long TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 14377cb209f5SScott Long event->ev_callback(sc, event, event->ev_arg); 14387cb209f5SScott Long } 143935863739SMike Smith } 144035863739SMike Smith 1441914da7d0SScott Long /* 14420b94a66eSMike Smith * Map helper for command/FIB allocation. 144335863739SMike Smith */ 144435863739SMike Smith static void 14450b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 144635863739SMike Smith { 14477cb209f5SScott Long uint64_t *fibphys; 1448914da7d0SScott Long 14497cb209f5SScott Long fibphys = (uint64_t *)arg; 145035863739SMike Smith 1451ffb37f33SScott Long *fibphys = segs[0].ds_addr; 145235863739SMike Smith } 145335863739SMike Smith 1454914da7d0SScott Long /* 14554109ba51SEd Maste * Allocate and initialize commands/FIBs for this adapter. 145635863739SMike Smith */ 14570b94a66eSMike Smith static int 14580b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 145935863739SMike Smith { 146035863739SMike Smith struct aac_command *cm; 1461ffb37f33SScott Long struct aac_fibmap *fm; 14627cb209f5SScott Long uint64_t fibphys; 1463ffb37f33SScott Long int i, error; 146435863739SMike Smith 146531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 146635863739SMike Smith 14677cb209f5SScott Long if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1468ffb37f33SScott Long return (ENOMEM); 1469ffb37f33SScott Long 14708480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1471a6d35632SScott Long if (fm == NULL) 1472a6d35632SScott Long return (ENOMEM); 1473ffb37f33SScott Long 14740b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1475ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1476ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 147770545d1aSScott Long device_printf(sc->aac_dev, 147870545d1aSScott Long "Not enough contiguous memory available.\n"); 14798480cc63SScott Long free(fm, M_AACBUF); 14800b94a66eSMike Smith return (ENOMEM); 148135863739SMike Smith } 1482128aa5a0SScott Long 1483cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1484cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 14857cb209f5SScott Long sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1486ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1487128aa5a0SScott Long 14884109ba51SEd Maste /* initialize constant fields in the command structure */ 14897cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 14907cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 14918480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1492ffb37f33SScott Long fm->aac_commands = cm; 149335863739SMike Smith cm->cm_sc = sc; 14947cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 14957cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 14967cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1497cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 149835863739SMike Smith 1499ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 150093cfca22SScott Long &cm->cm_datamap)) != 0) 15018480cc63SScott Long break; 150293cfca22SScott Long mtx_lock(&sc->aac_io_lock); 150393cfca22SScott Long aac_release_command(cm); 15048480cc63SScott Long sc->total_fibs++; 150593cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 150635863739SMike Smith } 1507ffb37f33SScott Long 15088480cc63SScott Long if (i > 0) { 150993cfca22SScott Long mtx_lock(&sc->aac_io_lock); 1510ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 151131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1512bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 15130b94a66eSMike Smith return (0); 151435863739SMike Smith } 151535863739SMike Smith 15168480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 15178480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15188480cc63SScott Long free(fm, M_AACBUF); 15198480cc63SScott Long return (ENOMEM); 15208480cc63SScott Long } 15218480cc63SScott Long 1522914da7d0SScott Long /* 15230b94a66eSMike Smith * Free FIBs owned by this adapter. 152435863739SMike Smith */ 152535863739SMike Smith static void 15268480cc63SScott Long aac_free_commands(struct aac_softc *sc) 152735863739SMike Smith { 15288480cc63SScott Long struct aac_fibmap *fm; 1529ffb37f33SScott Long struct aac_command *cm; 153035863739SMike Smith int i; 153135863739SMike Smith 153231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 153335863739SMike Smith 15348480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 15358480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 15368480cc63SScott Long /* 15378480cc63SScott Long * We check against total_fibs to handle partially 15388480cc63SScott Long * allocated blocks. 15398480cc63SScott Long */ 15407cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1541ffb37f33SScott Long cm = fm->aac_commands + i; 1542ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1543ffb37f33SScott Long } 1544ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1545ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15468480cc63SScott Long free(fm, M_AACBUF); 15478480cc63SScott Long } 154835863739SMike Smith } 154935863739SMike Smith 1550914da7d0SScott Long /* 155135863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 155235863739SMike Smith */ 155335863739SMike Smith static void 155435863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 155535863739SMike Smith { 1556cd481291SScott Long struct aac_softc *sc; 1557914da7d0SScott Long struct aac_command *cm; 1558914da7d0SScott Long struct aac_fib *fib; 155935863739SMike Smith int i; 156035863739SMike Smith 1561914da7d0SScott Long cm = (struct aac_command *)arg; 1562cd481291SScott Long sc = cm->cm_sc; 1563914da7d0SScott Long fib = cm->cm_fib; 156431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1565914da7d0SScott Long 156635863739SMike Smith /* copy into the FIB */ 1567b85f5808SScott Long if (cm->cm_sgtable != NULL) { 15687cb209f5SScott Long if (fib->Header.Command == RawIo) { 15697cb209f5SScott Long struct aac_sg_tableraw *sg; 15707cb209f5SScott Long sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 15717cb209f5SScott Long sg->SgCount = nseg; 15727cb209f5SScott Long for (i = 0; i < nseg; i++) { 15737cb209f5SScott Long sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 15747cb209f5SScott Long sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 15757cb209f5SScott Long sg->SgEntryRaw[i].Next = 0; 15767cb209f5SScott Long sg->SgEntryRaw[i].Prev = 0; 15777cb209f5SScott Long sg->SgEntryRaw[i].Flags = 0; 15787cb209f5SScott Long } 15797cb209f5SScott Long /* update the FIB size for the s/g count */ 15807cb209f5SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 15817cb209f5SScott Long } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1582b85f5808SScott Long struct aac_sg_table *sg; 1583b85f5808SScott Long sg = cm->cm_sgtable; 158435863739SMike Smith sg->SgCount = nseg; 158535863739SMike Smith for (i = 0; i < nseg; i++) { 158635863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 158735863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 158835863739SMike Smith } 158935863739SMike Smith /* update the FIB size for the s/g count */ 159035863739SMike Smith fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1591b85f5808SScott Long } else { 1592b85f5808SScott Long struct aac_sg_table64 *sg; 1593b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1594b85f5808SScott Long sg->SgCount = nseg; 1595b85f5808SScott Long for (i = 0; i < nseg; i++) { 1596b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1597b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 159835863739SMike Smith } 1599b85f5808SScott Long /* update the FIB size for the s/g count */ 1600b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1601b85f5808SScott Long } 1602b85f5808SScott Long } 160335863739SMike Smith 1604cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1605cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 16067cb209f5SScott Long * the SenderFibAddress over to make room for the fast response bit 16077cb209f5SScott Long * and for the AIF bit 160835863739SMike Smith */ 16097cb209f5SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 16107cb209f5SScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 161135863739SMike Smith 1612cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1613cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 161435863739SMike Smith 161535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1616c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1617c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 161835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1619c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1620c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 162135863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1622cd481291SScott Long 16237cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 16247cb209f5SScott Long int count = 10000000L; 16257cb209f5SScott Long while (AAC_SEND_COMMAND(sc, cm) != 0) { 16267cb209f5SScott Long if (--count == 0) { 16277cb209f5SScott Long aac_unmap_command(cm); 16287cb209f5SScott Long sc->flags |= AAC_QUEUE_FRZN; 16297cb209f5SScott Long aac_requeue_ready(cm); 16307cb209f5SScott Long } 16317cb209f5SScott Long DELAY(5); /* wait 5 usec. */ 16327cb209f5SScott Long } 16337cb209f5SScott Long } else { 1634397fa34fSScott Long /* Put the FIB on the outbound queue */ 16354102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 16364102d44bSScott Long aac_unmap_command(cm); 1637397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1638cd481291SScott Long aac_requeue_ready(cm); 16394102d44bSScott Long } 16407cb209f5SScott Long } 164135863739SMike Smith } 164235863739SMike Smith 1643914da7d0SScott Long /* 164435863739SMike Smith * Unmap a command from controller-visible space. 164535863739SMike Smith */ 164635863739SMike Smith static void 164735863739SMike Smith aac_unmap_command(struct aac_command *cm) 164835863739SMike Smith { 1649914da7d0SScott Long struct aac_softc *sc; 165035863739SMike Smith 1651914da7d0SScott Long sc = cm->cm_sc; 165231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1653914da7d0SScott Long 165435863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 165535863739SMike Smith return; 165635863739SMike Smith 165735863739SMike Smith if (cm->cm_datalen != 0) { 165835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1659c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1660c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 166135863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1662c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1663c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 166435863739SMike Smith 166535863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 166635863739SMike Smith } 166735863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 166835863739SMike Smith } 166935863739SMike Smith 1670914da7d0SScott Long /* 1671914da7d0SScott Long * Hardware Interface 1672914da7d0SScott Long */ 167335863739SMike Smith 1674914da7d0SScott Long /* 16754109ba51SEd Maste * Initialize the adapter. 167635863739SMike Smith */ 167735863739SMike Smith static void 167835863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 167935863739SMike Smith { 1680914da7d0SScott Long struct aac_softc *sc; 168135863739SMike Smith 1682914da7d0SScott Long sc = (struct aac_softc *)arg; 168331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1684914da7d0SScott Long 168535863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 168635863739SMike Smith } 168735863739SMike Smith 1688a6d35632SScott Long static int 1689a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1690a6d35632SScott Long { 169104f4d586SEd Maste u_int32_t code, major, minor, options = 0, atu_size = 0; 1692da4882c2SMarius Strobl int rid, status; 169304f4d586SEd Maste time_t then; 1694a6d35632SScott Long 169531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 169604f4d586SEd Maste /* 169704f4d586SEd Maste * Wait for the adapter to come ready. 169804f4d586SEd Maste */ 169904f4d586SEd Maste then = time_uptime; 170004f4d586SEd Maste do { 170104f4d586SEd Maste code = AAC_GET_FWSTATUS(sc); 170204f4d586SEd Maste if (code & AAC_SELF_TEST_FAILED) { 170304f4d586SEd Maste device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 170404f4d586SEd Maste return(ENXIO); 170504f4d586SEd Maste } 170604f4d586SEd Maste if (code & AAC_KERNEL_PANIC) { 170704f4d586SEd Maste device_printf(sc->aac_dev, 1708a620bad0SEd Maste "FATAL: controller kernel panic"); 170904f4d586SEd Maste return(ENXIO); 171004f4d586SEd Maste } 171104f4d586SEd Maste if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 171204f4d586SEd Maste device_printf(sc->aac_dev, 171304f4d586SEd Maste "FATAL: controller not coming ready, " 171404f4d586SEd Maste "status %x\n", code); 171504f4d586SEd Maste return(ENXIO); 171604f4d586SEd Maste } 171704f4d586SEd Maste } while (!(code & AAC_UP_AND_RUNNING)); 1718a6d35632SScott Long 1719fe94b852SScott Long /* 1720fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1721fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1722fe94b852SScott Long */ 1723a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1724fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1725fe94b852SScott Long NULL)) { 1726fe94b852SScott Long device_printf(sc->aac_dev, 1727fe94b852SScott Long "Error reading firmware version\n"); 1728fe94b852SScott Long return (EIO); 1729fe94b852SScott Long } 1730fe94b852SScott Long 1731fe94b852SScott Long /* These numbers are stored as ASCII! */ 1732a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1733a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1734fe94b852SScott Long if (major == 1) { 1735fe94b852SScott Long device_printf(sc->aac_dev, 1736fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1737fe94b852SScott Long major, minor); 1738fe94b852SScott Long return (EINVAL); 1739fe94b852SScott Long } 1740fe94b852SScott Long } 1741fe94b852SScott Long 1742a6d35632SScott Long /* 1743a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1744a441b3fcSScott Long * work-arounds to enable. Some firmware revs don't support this 1745a441b3fcSScott Long * command. 1746a6d35632SScott Long */ 1747a441b3fcSScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1748a441b3fcSScott Long if (status != AAC_SRB_STS_INVALID_REQUEST) { 1749a441b3fcSScott Long device_printf(sc->aac_dev, 1750a441b3fcSScott Long "RequestAdapterInfo failed\n"); 1751a6d35632SScott Long return (EIO); 1752a6d35632SScott Long } 1753a441b3fcSScott Long } else { 1754a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 17557cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1756a6d35632SScott Long sc->supported_options = options; 1757a6d35632SScott Long 1758a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1759a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1760a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1761a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1762a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1763cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1764cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1765a441b3fcSScott Long device_printf(sc->aac_dev, 1766a441b3fcSScott Long "Enabling 64-bit address support\n"); 1767a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1768a6d35632SScott Long } 1769a441b3fcSScott Long if ((options & AAC_SUPPORTED_NEW_COMM) 1770da4882c2SMarius Strobl && sc->aac_if->aif_send_command) 17717cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 17727cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 17737cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1774a441b3fcSScott Long } 1775a6d35632SScott Long 1776a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 17777cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 17787cb209f5SScott Long 17797cb209f5SScott Long /* Remap mem. resource, if required */ 17807cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1781ff0991c4SAttilio Rao atu_size > rman_get_size(sc->aac_regs_res1)) { 1782da4882c2SMarius Strobl rid = rman_get_rid(sc->aac_regs_res1); 1783da4882c2SMarius Strobl bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, rid, 1784da4882c2SMarius Strobl sc->aac_regs_res1); 1785c47476d7SJustin Hibbits sc->aac_regs_res1 = bus_alloc_resource_anywhere(sc->aac_dev, 1786c47476d7SJustin Hibbits SYS_RES_MEMORY, &rid, atu_size, RF_ACTIVE); 1787ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 1788ff0991c4SAttilio Rao sc->aac_regs_res1 = bus_alloc_resource_any( 1789da4882c2SMarius Strobl sc->aac_dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 1790ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 17917cb209f5SScott Long device_printf(sc->aac_dev, 17927cb209f5SScott Long "couldn't allocate register window\n"); 17937cb209f5SScott Long return (ENXIO); 17947cb209f5SScott Long } 17957cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 17967cb209f5SScott Long } 1797ff0991c4SAttilio Rao sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 1798ff0991c4SAttilio Rao sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 1799ff0991c4SAttilio Rao 1800ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK) { 1801ff0991c4SAttilio Rao sc->aac_regs_res0 = sc->aac_regs_res1; 1802ff0991c4SAttilio Rao sc->aac_btag0 = sc->aac_btag1; 1803ff0991c4SAttilio Rao sc->aac_bhandle0 = sc->aac_bhandle1; 1804ff0991c4SAttilio Rao } 18057cb209f5SScott Long } 18067cb209f5SScott Long 18077cb209f5SScott Long /* Read preferred settings */ 18087cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 18097cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 18107cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 1811a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18127e7a458eSEd Maste - sizeof(struct aac_blockwrite64)) 18137e7a458eSEd Maste / sizeof(struct aac_sg_entry64); 1814a6d35632SScott Long else 1815a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18167e7a458eSEd Maste - sizeof(struct aac_blockwrite)) 18177e7a458eSEd Maste / sizeof(struct aac_sg_entry); 1818a441b3fcSScott Long 18197cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 18207cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 18217cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 18227cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 18237cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 18247cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 18257cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 18267cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 18277cb209f5SScott Long } 18287cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 18297cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 18307cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1831a6d35632SScott Long 1832f355c0e0SEd Maste if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1833f355c0e0SEd Maste sc->flags |= AAC_FLAGS_RAW_IO; 1834f355c0e0SEd Maste device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1835f355c0e0SEd Maste } 1836523da39bSEd Maste if ((sc->flags & AAC_FLAGS_RAW_IO) && 1837523da39bSEd Maste (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1838523da39bSEd Maste sc->flags |= AAC_FLAGS_LBA_64BIT; 1839523da39bSEd Maste device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1840523da39bSEd Maste } 1841f355c0e0SEd Maste 1842fe94b852SScott Long return (0); 1843fe94b852SScott Long } 1844fe94b852SScott Long 184535863739SMike Smith static int 184635863739SMike Smith aac_init(struct aac_softc *sc) 184735863739SMike Smith { 184835863739SMike Smith struct aac_adapter_init *ip; 184904f4d586SEd Maste u_int32_t qoffset; 1850a6d35632SScott Long int error; 185135863739SMike Smith 185231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1853ffb37f33SScott Long 185435863739SMike Smith /* 1855914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1856914da7d0SScott Long * physical location of various important shared data structures. 185735863739SMike Smith */ 185835863739SMike Smith ip = &sc->aac_common->ac_init; 185935863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18607cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18617cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18627cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18637cb209f5SScott Long } 1864f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 186535863739SMike Smith 1866c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1867c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1868149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 186935863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 187035863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 187135863739SMike Smith 1872c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1873c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 187435863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 187535863739SMike Smith 18764b00f859SScott Long /* 18774b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18784b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18794b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18804b00f859SScott Long * Round up since the granularity is so high. 18814b00f859SScott Long */ 1882f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18834b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 18844b00f859SScott Long ip->HostPhysMemPages = 18854b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1886204c0befSScott Long } 18872b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 188835863739SMike Smith 18897cb209f5SScott Long ip->InitFlags = 0; 18907cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 1891e71d3b9cSEd Maste ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED; 18927cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 18937cb209f5SScott Long } 18947cb209f5SScott Long 18957cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 18967cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 18977cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 18987cb209f5SScott Long 189935863739SMike Smith /* 19004109ba51SEd Maste * Initialize FIB queues. Note that it appears that the layout of the 1901c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1902c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 190335863739SMike Smith * 190435863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1905914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1906914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1907914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1908914da7d0SScott Long * does. 190935863739SMike Smith * 1910914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1911914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1912914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1913914da7d0SScott Long * virtue of a table. 191435863739SMike Smith */ 1915b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 19160bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 19170bcbebd6SScott Long sc->aac_queues = 19180bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1919b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 192035863739SMike Smith 1921c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1922c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1923c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1924c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1925c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1926c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1927c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1928c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1929c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1930c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1931c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1932c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1933c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1934c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1935c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1936c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1937c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1938c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1939c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1940c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1941c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1942c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1943c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1944c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1945c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1946c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1947c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1948c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1949c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1950c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1951c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1952c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1953c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1954c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1955c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1956c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1957c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1958c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1959c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1960c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1961c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1962c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1963c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1964c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1965c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1966c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1967c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1968c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 196935863739SMike Smith 197035863739SMike Smith /* 197135863739SMike Smith * Do controller-type-specific initialisation 197235863739SMike Smith */ 197335863739SMike Smith switch (sc->aac_hwif) { 197435863739SMike Smith case AAC_HWIF_I960RX: 1975ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); 197635863739SMike Smith break; 19774afedc31SScott Long case AAC_HWIF_RKT: 1978ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); 19794afedc31SScott Long break; 19804afedc31SScott Long default: 19814afedc31SScott Long break; 198235863739SMike Smith } 198335863739SMike Smith 198435863739SMike Smith /* 198535863739SMike Smith * Give the init structure to the controller. 198635863739SMike Smith */ 198735863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1988914da7d0SScott Long sc->aac_common_busaddr + 1989914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1990914da7d0SScott Long NULL)) { 1991914da7d0SScott Long device_printf(sc->aac_dev, 1992914da7d0SScott Long "error establishing init structure\n"); 1993a6d35632SScott Long error = EIO; 1994a6d35632SScott Long goto out; 199535863739SMike Smith } 199635863739SMike Smith 1997a6d35632SScott Long error = 0; 1998a6d35632SScott Long out: 1999a6d35632SScott Long return(error); 200035863739SMike Smith } 200135863739SMike Smith 200204f4d586SEd Maste static int 200304f4d586SEd Maste aac_setup_intr(struct aac_softc *sc) 200404f4d586SEd Maste { 2005da4882c2SMarius Strobl 200604f4d586SEd Maste if (sc->flags & AAC_FLAGS_NEW_COMM) { 200704f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 200804f4d586SEd Maste INTR_MPSAFE|INTR_TYPE_BIO, NULL, 200904f4d586SEd Maste aac_new_intr, sc, &sc->aac_intr)) { 201004f4d586SEd Maste device_printf(sc->aac_dev, "can't set up interrupt\n"); 201104f4d586SEd Maste return (EINVAL); 201204f4d586SEd Maste } 201304f4d586SEd Maste } else { 201404f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2015e46b9eeaSEd Maste INTR_TYPE_BIO, aac_filter, NULL, 201604f4d586SEd Maste sc, &sc->aac_intr)) { 201704f4d586SEd Maste device_printf(sc->aac_dev, 2018e46b9eeaSEd Maste "can't set up interrupt filter\n"); 201904f4d586SEd Maste return (EINVAL); 202004f4d586SEd Maste } 202104f4d586SEd Maste } 202204f4d586SEd Maste return (0); 202304f4d586SEd Maste } 202404f4d586SEd Maste 2025914da7d0SScott Long /* 202635863739SMike Smith * Send a synchronous command to the controller and wait for a result. 20277cb209f5SScott Long * Indicate if the controller completed the command with an error status. 202835863739SMike Smith */ 202935863739SMike Smith static int 203035863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 203135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 203235863739SMike Smith u_int32_t *sp) 203335863739SMike Smith { 203435863739SMike Smith time_t then; 203535863739SMike Smith u_int32_t status; 203635863739SMike Smith 203731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 203835863739SMike Smith 203935863739SMike Smith /* populate the mailbox */ 204035863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 204135863739SMike Smith 204235863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 204335863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 204435863739SMike Smith 204535863739SMike Smith /* then set it to signal the adapter */ 204635863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 204735863739SMike Smith 204835863739SMike Smith /* spin waiting for the command to complete */ 20492b3b0f17SScott Long then = time_uptime; 205035863739SMike Smith do { 20512b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 205231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 205335863739SMike Smith return(EIO); 205435863739SMike Smith } 205535863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 205635863739SMike Smith 205735863739SMike Smith /* clear the completion flag */ 205835863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 205935863739SMike Smith 206035863739SMike Smith /* get the command status */ 2061a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 206235863739SMike Smith if (sp != NULL) 206335863739SMike Smith *sp = status; 20647cb209f5SScott Long 2065a441b3fcSScott Long if (status != AAC_SRB_STS_SUCCESS) 20667cb209f5SScott Long return (-1); 20670b94a66eSMike Smith return(0); 206835863739SMike Smith } 206935863739SMike Smith 2070cbfd045bSScott Long int 207135863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2072cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 207335863739SMike Smith { 207431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 20757cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 207635863739SMike Smith 207735863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 207835863739SMike Smith return(EINVAL); 207935863739SMike Smith 208035863739SMike Smith /* 208135863739SMike Smith * Set up the sync FIB 208235863739SMike Smith */ 2083914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2084914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2085c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 208635863739SMike Smith fib->Header.XferState |= xferstate; 208735863739SMike Smith fib->Header.Command = command; 208835863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 208942ef13a2SEd Maste fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 209035863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2091b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2092c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2093914da7d0SScott Long offsetof(struct aac_common, 2094914da7d0SScott Long ac_sync_fib); 209535863739SMike Smith 209635863739SMike Smith /* 209735863739SMike Smith * Give the FIB to the controller, wait for a response. 209835863739SMike Smith */ 2099914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2100914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 210131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 210235863739SMike Smith return(EIO); 210335863739SMike Smith } 210435863739SMike Smith 210535863739SMike Smith return (0); 210635863739SMike Smith } 210735863739SMike Smith 2108914da7d0SScott Long /* 210935863739SMike Smith * Adapter-space FIB queue manipulation 211035863739SMike Smith * 211135863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 211235863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 211335863739SMike Smith */ 2114da4882c2SMarius Strobl static const struct { 211535863739SMike Smith int size; 211635863739SMike Smith int notify; 211735863739SMike Smith } aac_qinfo[] = { 211835863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 211935863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 212035863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 212135863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 212235863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 212335863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 212435863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 212535863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 212635863739SMike Smith }; 212735863739SMike Smith 212835863739SMike Smith /* 2129c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2130c6eafcf2SScott Long * EBUSY if the queue is full. 213135863739SMike Smith * 21320b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2133914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2134914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2135c6eafcf2SScott Long * separate queue/notify interface). 213635863739SMike Smith */ 213735863739SMike Smith static int 2138f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 213935863739SMike Smith { 214035863739SMike Smith u_int32_t pi, ci; 21419e2e96d8SScott Long int error; 2142f6c4dd3fSScott Long u_int32_t fib_size; 2143f6c4dd3fSScott Long u_int32_t fib_addr; 2144f6c4dd3fSScott Long 214531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 214636e0bf6eSScott Long 2147f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2148f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 214935863739SMike Smith 215035863739SMike Smith /* get the producer/consumer indices */ 215135863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215235863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215335863739SMike Smith 215435863739SMike Smith /* wrap the queue? */ 215535863739SMike Smith if (pi >= aac_qinfo[queue].size) 215635863739SMike Smith pi = 0; 215735863739SMike Smith 215835863739SMike Smith /* check for queue full */ 215935863739SMike Smith if ((pi + 1) == ci) { 216035863739SMike Smith error = EBUSY; 216135863739SMike Smith goto out; 216235863739SMike Smith } 216335863739SMike Smith 2164614c22b2SScott Long /* 2165614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2166614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2167614c22b2SScott Long */ 2168614c22b2SScott Long aac_enqueue_busy(cm); 2169614c22b2SScott Long 217035863739SMike Smith /* populate queue entry */ 217135863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 217235863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 217335863739SMike Smith 217435863739SMike Smith /* update producer index */ 217535863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 217635863739SMike Smith 217735863739SMike Smith /* notify the adapter if we know how */ 217835863739SMike Smith if (aac_qinfo[queue].notify != 0) 217935863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 218035863739SMike Smith 218135863739SMike Smith error = 0; 218235863739SMike Smith 218335863739SMike Smith out: 218435863739SMike Smith return(error); 218535863739SMike Smith } 218635863739SMike Smith 218735863739SMike Smith /* 218836e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 218936e0bf6eSScott Long * success or ENOENT if the queue is empty. 219035863739SMike Smith */ 219135863739SMike Smith static int 2192c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2193c6eafcf2SScott Long struct aac_fib **fib_addr) 219435863739SMike Smith { 219535863739SMike Smith u_int32_t pi, ci; 2196149af931SScott Long u_int32_t fib_index; 21979e2e96d8SScott Long int error; 2198f6c4dd3fSScott Long int notify; 219935863739SMike Smith 220031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 220135863739SMike Smith 220235863739SMike Smith /* get the producer/consumer indices */ 220335863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 220435863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 220535863739SMike Smith 220635863739SMike Smith /* check for queue empty */ 220735863739SMike Smith if (ci == pi) { 220835863739SMike Smith error = ENOENT; 220935863739SMike Smith goto out; 221035863739SMike Smith } 221135863739SMike Smith 22127753acd2SScott Long /* wrap the pi so the following test works */ 22137753acd2SScott Long if (pi >= aac_qinfo[queue].size) 22147753acd2SScott Long pi = 0; 22157753acd2SScott Long 2216f6c4dd3fSScott Long notify = 0; 2217f6c4dd3fSScott Long if (ci == pi + 1) 2218f6c4dd3fSScott Long notify++; 2219f6c4dd3fSScott Long 222035863739SMike Smith /* wrap the queue? */ 222135863739SMike Smith if (ci >= aac_qinfo[queue].size) 222235863739SMike Smith ci = 0; 222335863739SMike Smith 222435863739SMike Smith /* fetch the entry */ 222535863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2226149af931SScott Long 2227149af931SScott Long switch (queue) { 2228149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2229149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2230149af931SScott Long /* 2231149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2232149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2233149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2234149af931SScott Long * Therefore, we have to convert it to an index. 2235149af931SScott Long */ 2236149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2237149af931SScott Long sizeof(struct aac_fib); 2238149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2239149af931SScott Long break; 2240149af931SScott Long 2241149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2242149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2243149af931SScott Long { 2244149af931SScott Long struct aac_command *cm; 2245149af931SScott Long 2246149af931SScott Long /* 2247149af931SScott Long * As above, an index is used instead of an actual address. 2248149af931SScott Long * Gotta shift the index to account for the fast response 2249149af931SScott Long * bit. No other correction is needed since this value was 2250149af931SScott Long * originally provided by the driver via the SenderFibAddress 2251149af931SScott Long * field. 2252149af931SScott Long */ 2253149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 22547cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2255149af931SScott Long *fib_addr = cm->cm_fib; 225635863739SMike Smith 2257f30ac74cSScott Long /* 2258f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2259149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2260f30ac74cSScott Long */ 2261149af931SScott Long if (fib_index & 0x01) { 2262f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2263f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2264f30ac74cSScott Long } 2265149af931SScott Long break; 2266149af931SScott Long } 2267149af931SScott Long default: 2268149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2269149af931SScott Long break; 2270149af931SScott Long } 2271149af931SScott Long 227235863739SMike Smith /* update consumer index */ 227335863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 227435863739SMike Smith 227535863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2276f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 227735863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227835863739SMike Smith error = 0; 227935863739SMike Smith 228035863739SMike Smith out: 228135863739SMike Smith return(error); 228235863739SMike Smith } 228335863739SMike Smith 2284914da7d0SScott Long /* 228536e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 228636e0bf6eSScott Long */ 228736e0bf6eSScott Long static int 228836e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 228936e0bf6eSScott Long { 229036e0bf6eSScott Long u_int32_t pi, ci; 22919e2e96d8SScott Long int error; 229236e0bf6eSScott Long u_int32_t fib_size; 229336e0bf6eSScott Long u_int32_t fib_addr; 229436e0bf6eSScott Long 229531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 229636e0bf6eSScott Long 229736e0bf6eSScott Long /* Tell the adapter where the FIB is */ 229836e0bf6eSScott Long fib_size = fib->Header.Size; 229936e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 230036e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 230136e0bf6eSScott Long 230236e0bf6eSScott Long /* get the producer/consumer indices */ 230336e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 230436e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 230536e0bf6eSScott Long 230636e0bf6eSScott Long /* wrap the queue? */ 230736e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 230836e0bf6eSScott Long pi = 0; 230936e0bf6eSScott Long 231036e0bf6eSScott Long /* check for queue full */ 231136e0bf6eSScott Long if ((pi + 1) == ci) { 231236e0bf6eSScott Long error = EBUSY; 231336e0bf6eSScott Long goto out; 231436e0bf6eSScott Long } 231536e0bf6eSScott Long 231636e0bf6eSScott Long /* populate queue entry */ 231736e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 231836e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 231936e0bf6eSScott Long 232036e0bf6eSScott Long /* update producer index */ 232136e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 232236e0bf6eSScott Long 232336e0bf6eSScott Long /* notify the adapter if we know how */ 232436e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 232536e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 232636e0bf6eSScott Long 232736e0bf6eSScott Long error = 0; 232836e0bf6eSScott Long 232936e0bf6eSScott Long out: 233036e0bf6eSScott Long return(error); 233136e0bf6eSScott Long } 233236e0bf6eSScott Long 2333914da7d0SScott Long /* 23340b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 23350b94a66eSMike Smith * and complain about them. 23360b94a66eSMike Smith */ 23370b94a66eSMike Smith static void 23380b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 23390b94a66eSMike Smith { 23400b94a66eSMike Smith struct aac_command *cm; 23410b94a66eSMike Smith time_t deadline; 234215c37be0SScott Long int timedout, code; 23430b94a66eSMike Smith 2344f6c4dd3fSScott Long /* 234570545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2346914da7d0SScott Long * only. 2347914da7d0SScott Long */ 234815c37be0SScott Long timedout = 0; 23492b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 23500b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2351f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 23523e507710SEd Maste && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { 23530b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2354914da7d0SScott Long device_printf(sc->aac_dev, 23555aa4bb5bSEd Maste "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n", 23565aa4bb5bSEd Maste cm, cm->cm_fib->Header.Command, 23575aa4bb5bSEd Maste (int)(time_uptime-cm->cm_timestamp)); 23580b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 235915c37be0SScott Long timedout++; 23600b94a66eSMike Smith } 23610b94a66eSMike Smith } 23620b94a66eSMike Smith 236315c37be0SScott Long if (timedout) { 236415c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 236515c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 236615c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 236715c37be0SScott Long "longer running! code= 0x%x\n", code); 236815c37be0SScott Long } 236915c37be0SScott Long } 23700b94a66eSMike Smith } 23710b94a66eSMike Smith 2372914da7d0SScott Long /* 2373914da7d0SScott Long * Interface Function Vectors 2374914da7d0SScott Long */ 237535863739SMike Smith 2376914da7d0SScott Long /* 237735863739SMike Smith * Read the current firmware status word. 237835863739SMike Smith */ 237935863739SMike Smith static int 238035863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 238135863739SMike Smith { 238231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 238335863739SMike Smith 2384ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); 238535863739SMike Smith } 238635863739SMike Smith 238735863739SMike Smith static int 238835863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 238935863739SMike Smith { 239031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 239135863739SMike Smith 23924824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 23934824be88SEd Maste AAC_RX_OMR0 : AAC_RX_FWSTATUS)); 239435863739SMike Smith } 239535863739SMike Smith 2396b3457b51SScott Long static int 23974afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 23984afedc31SScott Long { 239931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24004afedc31SScott Long 24014824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 24024824be88SEd Maste AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); 24034afedc31SScott Long } 24044afedc31SScott Long 2405914da7d0SScott Long /* 240635863739SMike Smith * Notify the controller of a change in a given queue 240735863739SMike Smith */ 240835863739SMike Smith 240935863739SMike Smith static void 241035863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 241135863739SMike Smith { 241231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241335863739SMike Smith 2414ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 241535863739SMike Smith } 241635863739SMike Smith 241735863739SMike Smith static void 241835863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 241935863739SMike Smith { 242031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 242135863739SMike Smith 2422ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); 242335863739SMike Smith } 242435863739SMike Smith 2425b3457b51SScott Long static void 24264afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 24274afedc31SScott Long { 242831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24294afedc31SScott Long 2430ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); 24314afedc31SScott Long } 24324afedc31SScott Long 2433914da7d0SScott Long /* 243435863739SMike Smith * Get the interrupt reason bits 243535863739SMike Smith */ 243635863739SMike Smith static int 243735863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 243835863739SMike Smith { 243931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244035863739SMike Smith 2441ff0991c4SAttilio Rao return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); 244235863739SMike Smith } 244335863739SMike Smith 244435863739SMike Smith static int 244535863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 244635863739SMike Smith { 244731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244835863739SMike Smith 2449ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); 245035863739SMike Smith } 245135863739SMike Smith 2452b3457b51SScott Long static int 24534afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 24544afedc31SScott Long { 245531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24564afedc31SScott Long 2457ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); 24584afedc31SScott Long } 24594afedc31SScott Long 2460914da7d0SScott Long /* 246135863739SMike Smith * Clear some interrupt reason bits 246235863739SMike Smith */ 246335863739SMike Smith static void 246435863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 246535863739SMike Smith { 246631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 246735863739SMike Smith 2468ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 246935863739SMike Smith } 247035863739SMike Smith 247135863739SMike Smith static void 247235863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 247335863739SMike Smith { 247431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 247535863739SMike Smith 2476ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); 247735863739SMike Smith } 247835863739SMike Smith 2479b3457b51SScott Long static void 24804afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 24814afedc31SScott Long { 248231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24834afedc31SScott Long 2484ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); 24854afedc31SScott Long } 24864afedc31SScott Long 2487914da7d0SScott Long /* 248835863739SMike Smith * Populate the mailbox and set the command word 248935863739SMike Smith */ 249035863739SMike Smith static void 249135863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 249235863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249335863739SMike Smith { 249431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 249535863739SMike Smith 2496ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); 2497ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2498ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2499ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2500ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 250135863739SMike Smith } 250235863739SMike Smith 250335863739SMike Smith static void 250435863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 250535863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 250635863739SMike Smith { 250731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 250835863739SMike Smith 2509ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); 2510ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2511ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2512ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2513ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 251435863739SMike Smith } 251535863739SMike Smith 2516b3457b51SScott Long static void 25174afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25184afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 25194afedc31SScott Long { 252031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25214afedc31SScott Long 2522ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); 2523ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2524ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2525ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2526ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 25274afedc31SScott Long } 25284afedc31SScott Long 2529914da7d0SScott Long /* 253035863739SMike Smith * Fetch the immediate command status word 253135863739SMike Smith */ 253235863739SMike Smith static int 2533a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 253435863739SMike Smith { 253531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 253635863739SMike Smith 2537ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 253835863739SMike Smith } 253935863739SMike Smith 254035863739SMike Smith static int 2541a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 254235863739SMike Smith { 254331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 254435863739SMike Smith 2545ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 254635863739SMike Smith } 254735863739SMike Smith 2548b3457b51SScott Long static int 25494afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 25504afedc31SScott Long { 255131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25524afedc31SScott Long 2553ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 25544afedc31SScott Long } 25554afedc31SScott Long 2556914da7d0SScott Long /* 255735863739SMike Smith * Set/clear interrupt masks 255835863739SMike Smith */ 255935863739SMike Smith static void 256035863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 256135863739SMike Smith { 256231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 256335863739SMike Smith 256435863739SMike Smith if (enable) { 2565ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 256635863739SMike Smith } else { 2567ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 256835863739SMike Smith } 256935863739SMike Smith } 257035863739SMike Smith 257135863739SMike Smith static void 257235863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 257335863739SMike Smith { 257431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 257535863739SMike Smith 257635863739SMike Smith if (enable) { 25777cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2578ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 25797cb209f5SScott Long else 2580ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 258135863739SMike Smith } else { 2582ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); 258335863739SMike Smith } 258435863739SMike Smith } 258535863739SMike Smith 2586b3457b51SScott Long static void 25874afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 25884afedc31SScott Long { 258931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 25904afedc31SScott Long 25914afedc31SScott Long if (enable) { 25927cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2593ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 25947cb209f5SScott Long else 2595ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 25964afedc31SScott Long } else { 2597ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); 25984afedc31SScott Long } 25994afedc31SScott Long } 26004afedc31SScott Long 2601914da7d0SScott Long /* 26027cb209f5SScott Long * New comm. interface: Send command functions 26037cb209f5SScott Long */ 26047cb209f5SScott Long static int 26057cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 26067cb209f5SScott Long { 26077cb209f5SScott Long u_int32_t index, device; 26087cb209f5SScott Long 260931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 26107cb209f5SScott Long 2611ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 26127cb209f5SScott Long if (index == 0xffffffffL) 2613ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 26147cb209f5SScott Long if (index == 0xffffffffL) 26157cb209f5SScott Long return index; 26167cb209f5SScott Long aac_enqueue_busy(cm); 26177cb209f5SScott Long device = index; 2618ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26197cb209f5SScott Long device += 4; 2620ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26217cb209f5SScott Long device += 4; 2622ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2623ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); 26247cb209f5SScott Long return 0; 26257cb209f5SScott Long } 26267cb209f5SScott Long 26277cb209f5SScott Long static int 26287cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 26297cb209f5SScott Long { 26307cb209f5SScott Long u_int32_t index, device; 26317cb209f5SScott Long 263231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 26337cb209f5SScott Long 2634ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 26357cb209f5SScott Long if (index == 0xffffffffL) 2636ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 26377cb209f5SScott Long if (index == 0xffffffffL) 26387cb209f5SScott Long return index; 26397cb209f5SScott Long aac_enqueue_busy(cm); 26407cb209f5SScott Long device = index; 2641ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26427cb209f5SScott Long device += 4; 2643ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26447cb209f5SScott Long device += 4; 2645ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2646ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); 26477cb209f5SScott Long return 0; 26487cb209f5SScott Long } 26497cb209f5SScott Long 26507cb209f5SScott Long /* 26517cb209f5SScott Long * New comm. interface: get, set outbound queue index 26527cb209f5SScott Long */ 26537cb209f5SScott Long static int 26547cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 26557cb209f5SScott Long { 265631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26577cb209f5SScott Long 2658ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); 26597cb209f5SScott Long } 26607cb209f5SScott Long 26617cb209f5SScott Long static int 26627cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 26637cb209f5SScott Long { 266431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26657cb209f5SScott Long 2666ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); 26677cb209f5SScott Long } 26687cb209f5SScott Long 26697cb209f5SScott Long static void 26707cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 26717cb209f5SScott Long { 267231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26737cb209f5SScott Long 2674ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); 26757cb209f5SScott Long } 26767cb209f5SScott Long 26777cb209f5SScott Long static void 26787cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 26797cb209f5SScott Long { 268031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26817cb209f5SScott Long 2682ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); 26837cb209f5SScott Long } 26847cb209f5SScott Long 26857cb209f5SScott Long /* 2686914da7d0SScott Long * Debugging and Diagnostics 2687914da7d0SScott Long */ 268835863739SMike Smith 2689914da7d0SScott Long /* 269035863739SMike Smith * Print some information about the controller. 269135863739SMike Smith */ 269235863739SMike Smith static void 269335863739SMike Smith aac_describe_controller(struct aac_softc *sc) 269435863739SMike Smith { 2695cbfd045bSScott Long struct aac_fib *fib; 269635863739SMike Smith struct aac_adapter_info *info; 26977ea2d558SEd Maste char *adapter_type = "Adaptec RAID controller"; 269835863739SMike Smith 269931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 270035863739SMike Smith 270181b3da08SScott Long mtx_lock(&sc->aac_io_lock); 270203b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2703cbfd045bSScott Long 2704cbfd045bSScott Long fib->data[0] = 0; 2705cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 270635863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2707fe3cb0e1SScott Long aac_release_sync_fib(sc); 270881b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 270935863739SMike Smith return; 271035863739SMike Smith } 271135863739SMike Smith 2712bd971c49SScott Long /* save the kernel revision structure for later use */ 2713bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2714bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2715bd971c49SScott Long 2716bd971c49SScott Long if (bootverbose) { 2717b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2718b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2719c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2720b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2721b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2722b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2723914da7d0SScott Long aac_describe_code(aac_battery_platform, 2724914da7d0SScott Long info->batteryPlatform)); 272535863739SMike Smith 2726bd971c49SScott Long device_printf(sc->aac_dev, 2727bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 272835863739SMike Smith info->KernelRevision.external.comp.major, 272935863739SMike Smith info->KernelRevision.external.comp.minor, 273035863739SMike Smith info->KernelRevision.external.comp.dash, 273136e0bf6eSScott Long info->KernelRevision.buildNumber, 273236e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2733fe3cb0e1SScott Long 2734a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2735a6d35632SScott Long sc->supported_options, 2736a6d35632SScott Long "\20" 2737a6d35632SScott Long "\1SNAPSHOT" 2738a6d35632SScott Long "\2CLUSTERS" 2739a6d35632SScott Long "\3WCACHE" 2740a6d35632SScott Long "\4DATA64" 2741a6d35632SScott Long "\5HOSTTIME" 2742a6d35632SScott Long "\6RAID50" 2743a6d35632SScott Long "\7WINDOW4GB" 2744a6d35632SScott Long "\10SCSIUPGD" 2745a6d35632SScott Long "\11SOFTERR" 2746a6d35632SScott Long "\12NORECOND" 2747a6d35632SScott Long "\13SGMAP64" 2748a6d35632SScott Long "\14ALARM" 27497cb209f5SScott Long "\15NONDASD" 27507cb209f5SScott Long "\16SCSIMGT" 27517cb209f5SScott Long "\17RAIDSCSI" 27527cb209f5SScott Long "\21ADPTINFO" 27537cb209f5SScott Long "\22NEWCOMM" 27547cb209f5SScott Long "\23ARRAY64BIT" 27557cb209f5SScott Long "\24HEATSENSOR"); 2756a6d35632SScott Long } 275755aa1136SEd Maste 275855aa1136SEd Maste if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 275955aa1136SEd Maste fib->data[0] = 0; 276055aa1136SEd Maste if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 276155aa1136SEd Maste device_printf(sc->aac_dev, 276255aa1136SEd Maste "RequestSupplementAdapterInfo failed\n"); 276355aa1136SEd Maste else 276455aa1136SEd Maste adapter_type = ((struct aac_supplement_adapter_info *) 276555aa1136SEd Maste &fib->data[0])->AdapterTypeText; 276655aa1136SEd Maste } 276755aa1136SEd Maste device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 276855aa1136SEd Maste adapter_type, 27698e7e6335SEd Maste AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 27708e7e6335SEd Maste AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 277155aa1136SEd Maste 2772bd971c49SScott Long aac_release_sync_fib(sc); 277381b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 277435863739SMike Smith } 277535863739SMike Smith 2776914da7d0SScott Long /* 277735863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 277835863739SMike Smith * same. 277935863739SMike Smith */ 2780da4882c2SMarius Strobl static const char * 2781da4882c2SMarius Strobl aac_describe_code(const struct aac_code_lookup *table, u_int32_t code) 278235863739SMike Smith { 278335863739SMike Smith int i; 278435863739SMike Smith 278535863739SMike Smith for (i = 0; table[i].string != NULL; i++) 278635863739SMike Smith if (table[i].code == code) 278735863739SMike Smith return(table[i].string); 278835863739SMike Smith return(table[i + 1].string); 278935863739SMike Smith } 279035863739SMike Smith 2791914da7d0SScott Long /* 2792914da7d0SScott Long * Management Interface 2793914da7d0SScott Long */ 279435863739SMike Smith 279535863739SMike Smith static int 279600b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 279735863739SMike Smith { 2798914da7d0SScott Long struct aac_softc *sc; 279935863739SMike Smith 2800914da7d0SScott Long sc = dev->si_drv1; 280131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 280204f798ecSAttilio Rao device_busy(sc->aac_dev); 2803dfe2c294SAttilio Rao devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 280435863739SMike Smith 280535863739SMike Smith return 0; 280635863739SMike Smith } 280735863739SMike Smith 280835863739SMike Smith static int 280900b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 281035863739SMike Smith { 2811914da7d0SScott Long union aac_statrequest *as; 2812914da7d0SScott Long struct aac_softc *sc; 28130b94a66eSMike Smith int error = 0; 281435863739SMike Smith 2815914da7d0SScott Long as = (union aac_statrequest *)arg; 2816914da7d0SScott Long sc = dev->si_drv1; 281731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2818914da7d0SScott Long 281935863739SMike Smith switch (cmd) { 28200b94a66eSMike Smith case AACIO_STATS: 28210b94a66eSMike Smith switch (as->as_item) { 28220b94a66eSMike Smith case AACQ_FREE: 28230b94a66eSMike Smith case AACQ_BIO: 28240b94a66eSMike Smith case AACQ_READY: 28250b94a66eSMike Smith case AACQ_BUSY: 2826c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2827c6eafcf2SScott Long sizeof(struct aac_qstat)); 28280b94a66eSMike Smith break; 28290b94a66eSMike Smith default: 28300b94a66eSMike Smith error = ENOENT; 28310b94a66eSMike Smith break; 28320b94a66eSMike Smith } 28330b94a66eSMike Smith break; 28340b94a66eSMike Smith 283535863739SMike Smith case FSACTL_SENDFIB: 2836f355c0e0SEd Maste case FSACTL_SEND_LARGE_FIB: 2837fb0c27d7SScott Long arg = *(caddr_t*)arg; 2838fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 2839f355c0e0SEd Maste case FSACTL_LNX_SEND_LARGE_FIB: 284031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 284135863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 284235863739SMike Smith break; 2843f355c0e0SEd Maste case FSACTL_SEND_RAW_SRB: 2844f355c0e0SEd Maste arg = *(caddr_t*)arg; 2845f355c0e0SEd Maste case FSACTL_LNX_SEND_RAW_SRB: 284631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2847f355c0e0SEd Maste error = aac_ioctl_send_raw_srb(sc, arg); 2848f355c0e0SEd Maste break; 284935863739SMike Smith case FSACTL_AIF_THREAD: 2850fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 285131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 285235863739SMike Smith error = EINVAL; 285335863739SMike Smith break; 285435863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2855fb0c27d7SScott Long arg = *(caddr_t*)arg; 2856fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 285731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2858a723a548SEd Maste error = aac_open_aif(sc, arg); 285935863739SMike Smith break; 286035863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2861fb0c27d7SScott Long arg = *(caddr_t*)arg; 2862fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 286331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2864fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 286535863739SMike Smith break; 286635863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2867a723a548SEd Maste arg = *(caddr_t*)arg; 2868fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 286931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2870a723a548SEd Maste error = aac_close_aif(sc, arg); 287135863739SMike Smith break; 287235863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2873fb0c27d7SScott Long arg = *(caddr_t*)arg; 2874fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 287531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2876fb0c27d7SScott Long error = aac_rev_check(sc, arg); 287735863739SMike Smith break; 287836e0bf6eSScott Long case FSACTL_QUERY_DISK: 287936e0bf6eSScott Long arg = *(caddr_t*)arg; 288036e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 288131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 288236e0bf6eSScott Long error = aac_query_disk(sc, arg); 288336e0bf6eSScott Long break; 288436e0bf6eSScott Long case FSACTL_DELETE_DISK: 288536e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2886914da7d0SScott Long /* 2887914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2888914da7d0SScott Long * container, rather we rely on an AIF coming from the 2889914da7d0SScott Long * controller 2890914da7d0SScott Long */ 289136e0bf6eSScott Long error = 0; 289236e0bf6eSScott Long break; 28937cb209f5SScott Long case FSACTL_GET_PCI_INFO: 28947cb209f5SScott Long arg = *(caddr_t*)arg; 28957cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 289631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 28977cb209f5SScott Long error = aac_get_pci_info(sc, arg); 28987cb209f5SScott Long break; 28996d307336SEd Maste case FSACTL_GET_FEATURES: 29006d307336SEd Maste arg = *(caddr_t*)arg; 29016d307336SEd Maste case FSACTL_LNX_GET_FEATURES: 29026d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 29036d307336SEd Maste error = aac_supported_features(sc, arg); 29046d307336SEd Maste break; 290535863739SMike Smith default: 290631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 290735863739SMike Smith error = EINVAL; 290835863739SMike Smith break; 290935863739SMike Smith } 291035863739SMike Smith return(error); 291135863739SMike Smith } 291235863739SMike Smith 2913b3457b51SScott Long static int 291400b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td) 2915b3457b51SScott Long { 2916b3457b51SScott Long struct aac_softc *sc; 2917ef0b687cSEd Maste struct aac_fib_context *ctx; 2918b3457b51SScott Long int revents; 2919b3457b51SScott Long 2920b3457b51SScott Long sc = dev->si_drv1; 2921b3457b51SScott Long revents = 0; 2922b3457b51SScott Long 2923bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2924b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2925ef0b687cSEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2926ef0b687cSEd Maste if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2927b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2928ef0b687cSEd Maste break; 2929ef0b687cSEd Maste } 2930ef0b687cSEd Maste } 2931b3457b51SScott Long } 2932bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2933b3457b51SScott Long 2934b3457b51SScott Long if (revents == 0) { 2935b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2936b3457b51SScott Long selrecord(td, &sc->rcv_select); 2937b3457b51SScott Long } 2938b3457b51SScott Long 2939b3457b51SScott Long return (revents); 2940b3457b51SScott Long } 2941b3457b51SScott Long 29427cb209f5SScott Long static void 29437cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 29447cb209f5SScott Long { 29457cb209f5SScott Long 29467cb209f5SScott Long switch (event->ev_type) { 29477cb209f5SScott Long case AAC_EVENT_CMFREE: 29480c40d5beSEd Maste mtx_assert(&sc->aac_io_lock, MA_OWNED); 29491a681311SLuoqi Chen if (aac_alloc_command(sc, (struct aac_command **)arg)) { 29507cb209f5SScott Long aac_add_event(sc, event); 29517cb209f5SScott Long return; 29527cb209f5SScott Long } 29537cb209f5SScott Long free(event, M_AACBUF); 29548eeb2ca6SScott Long wakeup(arg); 29557cb209f5SScott Long break; 29567cb209f5SScott Long default: 29577cb209f5SScott Long break; 29587cb209f5SScott Long } 29597cb209f5SScott Long } 29607cb209f5SScott Long 2961914da7d0SScott Long /* 296235863739SMike Smith * Send a FIB supplied from userspace 296335863739SMike Smith */ 296435863739SMike Smith static int 296535863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 296635863739SMike Smith { 296735863739SMike Smith struct aac_command *cm; 296835863739SMike Smith int size, error; 296935863739SMike Smith 297031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 297135863739SMike Smith 297235863739SMike Smith cm = NULL; 297335863739SMike Smith 297435863739SMike Smith /* 297535863739SMike Smith * Get a command 297635863739SMike Smith */ 2977bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 297835863739SMike Smith if (aac_alloc_command(sc, &cm)) { 29797cb209f5SScott Long struct aac_event *event; 29807cb209f5SScott Long 29817cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 29827cb209f5SScott Long M_NOWAIT | M_ZERO); 29837cb209f5SScott Long if (event == NULL) { 298435863739SMike Smith error = EBUSY; 2985f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 298635863739SMike Smith goto out; 298735863739SMike Smith } 29887cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 29897cb209f5SScott Long event->ev_callback = aac_ioctl_event; 29907cb209f5SScott Long event->ev_arg = &cm; 29917cb209f5SScott Long aac_add_event(sc, event); 29928eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 29937cb209f5SScott Long } 299493cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 299535863739SMike Smith 299635863739SMike Smith /* 299735863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 299835863739SMike Smith */ 2999914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 3000914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 300135863739SMike Smith goto out; 300235863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 3003f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3004f355c0e0SEd Maste device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 3005f355c0e0SEd Maste size, sc->aac_max_fib_size); 3006f355c0e0SEd Maste size = sc->aac_max_fib_size; 300735863739SMike Smith } 300835863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 300935863739SMike Smith goto out; 301035863739SMike Smith cm->cm_fib->Header.Size = size; 30112b3b0f17SScott Long cm->cm_timestamp = time_uptime; 301235863739SMike Smith 301335863739SMike Smith /* 301435863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 301535863739SMike Smith */ 301693cfca22SScott Long mtx_lock(&sc->aac_io_lock); 3017f16627aaSEd Maste error = aac_wait_command(cm); 3018f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 3019f16627aaSEd Maste if (error != 0) { 302070545d1aSScott Long device_printf(sc->aac_dev, 302170545d1aSScott Long "aac_wait_command return %d\n", error); 302235863739SMike Smith goto out; 3023b3457b51SScott Long } 302435863739SMike Smith 302535863739SMike Smith /* 302635863739SMike Smith * Copy the FIB and data back out to the caller. 302735863739SMike Smith */ 302835863739SMike Smith size = cm->cm_fib->Header.Size; 3029f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3030f355c0e0SEd Maste device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 3031f355c0e0SEd Maste size, sc->aac_max_fib_size); 3032f355c0e0SEd Maste size = sc->aac_max_fib_size; 303335863739SMike Smith } 303435863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 303535863739SMike Smith 303635863739SMike Smith out: 3037f6c4dd3fSScott Long if (cm != NULL) { 3038f16627aaSEd Maste mtx_lock(&sc->aac_io_lock); 303935863739SMike Smith aac_release_command(cm); 3040bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 3041f16627aaSEd Maste } 304235863739SMike Smith return(error); 304335863739SMike Smith } 304435863739SMike Smith 3045914da7d0SScott Long /* 3046f355c0e0SEd Maste * Send a passthrough FIB supplied from userspace 3047f355c0e0SEd Maste */ 3048f355c0e0SEd Maste static int 3049f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 3050f355c0e0SEd Maste { 30517b90e5ecSAttilio Rao struct aac_command *cm; 30527b90e5ecSAttilio Rao struct aac_event *event; 30537b90e5ecSAttilio Rao struct aac_fib *fib; 30547b90e5ecSAttilio Rao struct aac_srb *srbcmd, *user_srb; 30557b90e5ecSAttilio Rao struct aac_sg_entry *sge; 30567b90e5ecSAttilio Rao void *srb_sg_address, *ureply; 30577b90e5ecSAttilio Rao uint32_t fibsize, srb_sg_bytecount; 30587b90e5ecSAttilio Rao int error, transfer_data; 30597b90e5ecSAttilio Rao 30607b90e5ecSAttilio Rao fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 30617b90e5ecSAttilio Rao 30627b90e5ecSAttilio Rao cm = NULL; 30637b90e5ecSAttilio Rao transfer_data = 0; 30647b90e5ecSAttilio Rao fibsize = 0; 30657b90e5ecSAttilio Rao user_srb = (struct aac_srb *)arg; 30667b90e5ecSAttilio Rao 30677b90e5ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 30687b90e5ecSAttilio Rao if (aac_alloc_command(sc, &cm)) { 30697b90e5ecSAttilio Rao event = malloc(sizeof(struct aac_event), M_AACBUF, 30707b90e5ecSAttilio Rao M_NOWAIT | M_ZERO); 30717b90e5ecSAttilio Rao if (event == NULL) { 30727b90e5ecSAttilio Rao error = EBUSY; 30737b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 30747b90e5ecSAttilio Rao goto out; 30757b90e5ecSAttilio Rao } 30767b90e5ecSAttilio Rao event->ev_type = AAC_EVENT_CMFREE; 30777b90e5ecSAttilio Rao event->ev_callback = aac_ioctl_event; 30787b90e5ecSAttilio Rao event->ev_arg = &cm; 30797b90e5ecSAttilio Rao aac_add_event(sc, event); 30807b90e5ecSAttilio Rao msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0); 30817b90e5ecSAttilio Rao } 30827b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 30837b90e5ecSAttilio Rao 30847b90e5ecSAttilio Rao cm->cm_data = NULL; 30857b90e5ecSAttilio Rao fib = cm->cm_fib; 30867b90e5ecSAttilio Rao srbcmd = (struct aac_srb *)fib->data; 30877b90e5ecSAttilio Rao error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t)); 30887b90e5ecSAttilio Rao if (error != 0) 30897b90e5ecSAttilio Rao goto out; 30907b90e5ecSAttilio Rao if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) { 30917b90e5ecSAttilio Rao error = EINVAL; 30927b90e5ecSAttilio Rao goto out; 30937b90e5ecSAttilio Rao } 30947b90e5ecSAttilio Rao error = copyin(user_srb, srbcmd, fibsize); 30957b90e5ecSAttilio Rao if (error != 0) 30967b90e5ecSAttilio Rao goto out; 30977b90e5ecSAttilio Rao srbcmd->function = 0; 30987b90e5ecSAttilio Rao srbcmd->retry_limit = 0; 30997b90e5ecSAttilio Rao if (srbcmd->sg_map.SgCount > 1) { 31007b90e5ecSAttilio Rao error = EINVAL; 31017b90e5ecSAttilio Rao goto out; 31027b90e5ecSAttilio Rao } 31037b90e5ecSAttilio Rao 31047b90e5ecSAttilio Rao /* Retrieve correct SG entries. */ 31057b90e5ecSAttilio Rao if (fibsize == (sizeof(struct aac_srb) + 31067b90e5ecSAttilio Rao srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 3107f4a18258SSean Bruno struct aac_sg_entry sg; 3108f4a18258SSean Bruno 31097b90e5ecSAttilio Rao sge = srbcmd->sg_map.SgEntry; 3110f4a18258SSean Bruno 3111f4a18258SSean Bruno if ((error = copyin(sge, &sg, sizeof(sg))) != 0) 3112f4a18258SSean Bruno goto out; 3113f4a18258SSean Bruno 3114f4a18258SSean Bruno srb_sg_bytecount = sg.SgByteCount; 3115f4a18258SSean Bruno srb_sg_address = (void *)(uintptr_t)sg.SgAddress; 31167b90e5ecSAttilio Rao } 31177b90e5ecSAttilio Rao #ifdef __amd64__ 31187b90e5ecSAttilio Rao else if (fibsize == (sizeof(struct aac_srb) + 31197b90e5ecSAttilio Rao srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 3120*5cd9d254SJohn Baldwin struct aac_sg_entry64 *sge64; 3121f4a18258SSean Bruno struct aac_sg_entry64 sg; 3122f4a18258SSean Bruno 31237b90e5ecSAttilio Rao sge = NULL; 31247b90e5ecSAttilio Rao sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 3125f4a18258SSean Bruno 3126f4a18258SSean Bruno if ((error = copyin(sge64, &sg, sizeof(sg))) != 0) 3127f4a18258SSean Bruno goto out; 3128f4a18258SSean Bruno 3129f4a18258SSean Bruno srb_sg_bytecount = sg.SgByteCount; 3130f4a18258SSean Bruno srb_sg_address = (void *)sg.SgAddress; 31317b90e5ecSAttilio Rao if (sge64->SgAddress > 0xffffffffull && 31327b90e5ecSAttilio Rao (sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 31337b90e5ecSAttilio Rao error = EINVAL; 31347b90e5ecSAttilio Rao goto out; 31357b90e5ecSAttilio Rao } 31367b90e5ecSAttilio Rao } 31377b90e5ecSAttilio Rao #endif 31387b90e5ecSAttilio Rao else { 31397b90e5ecSAttilio Rao error = EINVAL; 31407b90e5ecSAttilio Rao goto out; 31417b90e5ecSAttilio Rao } 31427b90e5ecSAttilio Rao ureply = (char *)arg + fibsize; 31437b90e5ecSAttilio Rao srbcmd->data_len = srb_sg_bytecount; 31447b90e5ecSAttilio Rao if (srbcmd->sg_map.SgCount == 1) 31457b90e5ecSAttilio Rao transfer_data = 1; 31467b90e5ecSAttilio Rao 31477b90e5ecSAttilio Rao cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 31487b90e5ecSAttilio Rao if (transfer_data) { 31497b90e5ecSAttilio Rao cm->cm_datalen = srb_sg_bytecount; 31507b90e5ecSAttilio Rao cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT); 31517b90e5ecSAttilio Rao if (cm->cm_data == NULL) { 31527b90e5ecSAttilio Rao error = ENOMEM; 31537b90e5ecSAttilio Rao goto out; 31547b90e5ecSAttilio Rao } 31557b90e5ecSAttilio Rao if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 31567b90e5ecSAttilio Rao cm->cm_flags |= AAC_CMD_DATAIN; 31577b90e5ecSAttilio Rao if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 31587b90e5ecSAttilio Rao cm->cm_flags |= AAC_CMD_DATAOUT; 31597b90e5ecSAttilio Rao error = copyin(srb_sg_address, cm->cm_data, 31607b90e5ecSAttilio Rao cm->cm_datalen); 31617b90e5ecSAttilio Rao if (error != 0) 31627b90e5ecSAttilio Rao goto out; 31637b90e5ecSAttilio Rao } 31647b90e5ecSAttilio Rao } 31657b90e5ecSAttilio Rao 31667b90e5ecSAttilio Rao fib->Header.Size = sizeof(struct aac_fib_header) + 31677b90e5ecSAttilio Rao sizeof(struct aac_srb); 31687b90e5ecSAttilio Rao fib->Header.XferState = 31697b90e5ecSAttilio Rao AAC_FIBSTATE_HOSTOWNED | 31707b90e5ecSAttilio Rao AAC_FIBSTATE_INITIALISED | 31717b90e5ecSAttilio Rao AAC_FIBSTATE_EMPTY | 31727b90e5ecSAttilio Rao AAC_FIBSTATE_FROMHOST | 31737b90e5ecSAttilio Rao AAC_FIBSTATE_REXPECTED | 31747b90e5ecSAttilio Rao AAC_FIBSTATE_NORM | 31757b90e5ecSAttilio Rao AAC_FIBSTATE_ASYNC | 31767b90e5ecSAttilio Rao AAC_FIBSTATE_FAST_RESPONSE; 31777b90e5ecSAttilio Rao fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ? 31787b90e5ecSAttilio Rao ScsiPortCommandU64 : ScsiPortCommand; 31797b90e5ecSAttilio Rao 31807b90e5ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 31817b90e5ecSAttilio Rao aac_wait_command(cm); 31827b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 31837b90e5ecSAttilio Rao 31847b90e5ecSAttilio Rao if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) { 31857b90e5ecSAttilio Rao error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen); 31867b90e5ecSAttilio Rao if (error != 0) 31877b90e5ecSAttilio Rao goto out; 31887b90e5ecSAttilio Rao } 31897b90e5ecSAttilio Rao error = copyout(fib->data, ureply, sizeof(struct aac_srb_response)); 31907b90e5ecSAttilio Rao out: 31917b90e5ecSAttilio Rao if (cm != NULL) { 31927b90e5ecSAttilio Rao if (cm->cm_data != NULL) 31937b90e5ecSAttilio Rao free(cm->cm_data, M_AACBUF); 31947b90e5ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 31957b90e5ecSAttilio Rao aac_release_command(cm); 31967b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 31977b90e5ecSAttilio Rao } 31987b90e5ecSAttilio Rao return(error); 3199f355c0e0SEd Maste } 3200f355c0e0SEd Maste 3201f355c0e0SEd Maste /* 3202dfe2c294SAttilio Rao * cdevpriv interface private destructor. 3203dfe2c294SAttilio Rao */ 3204dfe2c294SAttilio Rao static void 3205dfe2c294SAttilio Rao aac_cdevpriv_dtor(void *arg) 3206dfe2c294SAttilio Rao { 3207dfe2c294SAttilio Rao struct aac_softc *sc; 3208dfe2c294SAttilio Rao 3209dfe2c294SAttilio Rao sc = arg; 3210dfe2c294SAttilio Rao fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3211dfe2c294SAttilio Rao device_unbusy(sc->aac_dev); 3212dfe2c294SAttilio Rao } 3213dfe2c294SAttilio Rao 3214dfe2c294SAttilio Rao /* 321535863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 321636e0bf6eSScott Long * If the queue fills up, then drop the older entries. 321735863739SMike Smith */ 321835863739SMike Smith static void 321936e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 322035863739SMike Smith { 322136e0bf6eSScott Long struct aac_aif_command *aif; 322236e0bf6eSScott Long struct aac_container *co, *co_next; 3223a723a548SEd Maste struct aac_fib_context *ctx; 322404f4d586SEd Maste struct aac_mntinforesp *mir; 3225a723a548SEd Maste int next, current, found; 3226795d7dc0SScott Long int count = 0, added = 0, i = 0; 3227851f59d7SEd Maste uint32_t channel; 322835863739SMike Smith 322931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 323035863739SMike Smith 323136e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 323236e0bf6eSScott Long aac_print_aif(sc, aif); 323336e0bf6eSScott Long 323436e0bf6eSScott Long /* Is it an event that we should care about? */ 323536e0bf6eSScott Long switch (aif->command) { 323636e0bf6eSScott Long case AifCmdEventNotify: 323736e0bf6eSScott Long switch (aif->data.EN.type) { 323836e0bf6eSScott Long case AifEnAddContainer: 323936e0bf6eSScott Long case AifEnDeleteContainer: 324036e0bf6eSScott Long /* 3241914da7d0SScott Long * A container was added or deleted, but the message 3242914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3243914da7d0SScott Long * containers and sort things out. 324436e0bf6eSScott Long */ 324503b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 324636e0bf6eSScott Long do { 324736e0bf6eSScott Long /* 3248914da7d0SScott Long * Ask the controller for its containers one at 3249914da7d0SScott Long * a time. 3250914da7d0SScott Long * XXX What if the controller's list changes 3251914da7d0SScott Long * midway through this enumaration? 325236e0bf6eSScott Long * XXX This should be done async. 325336e0bf6eSScott Long */ 325404f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 325536e0bf6eSScott Long continue; 325604f4d586SEd Maste if (i == 0) 3257795d7dc0SScott Long count = mir->MntRespCount; 325836e0bf6eSScott Long /* 3259914da7d0SScott Long * Check the container against our list. 3260914da7d0SScott Long * co->co_found was already set to 0 in a 3261914da7d0SScott Long * previous run. 326236e0bf6eSScott Long */ 3263cbfd045bSScott Long if ((mir->Status == ST_OK) && 3264cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 326536e0bf6eSScott Long found = 0; 3266914da7d0SScott Long TAILQ_FOREACH(co, 3267914da7d0SScott Long &sc->aac_container_tqh, 3268914da7d0SScott Long co_link) { 326936e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3270cbfd045bSScott Long mir->MntTable[0].ObjectId) { 327136e0bf6eSScott Long co->co_found = 1; 327236e0bf6eSScott Long found = 1; 327336e0bf6eSScott Long break; 327436e0bf6eSScott Long } 327536e0bf6eSScott Long } 3276914da7d0SScott Long /* 3277914da7d0SScott Long * If the container matched, continue 3278914da7d0SScott Long * in the list. 3279914da7d0SScott Long */ 328036e0bf6eSScott Long if (found) { 328136e0bf6eSScott Long i++; 328236e0bf6eSScott Long continue; 328336e0bf6eSScott Long } 328436e0bf6eSScott Long 328536e0bf6eSScott Long /* 3286914da7d0SScott Long * This is a new container. Do all the 328770545d1aSScott Long * appropriate things to set it up. 328870545d1aSScott Long */ 3289cbfd045bSScott Long aac_add_container(sc, mir, 1); 329036e0bf6eSScott Long added = 1; 329136e0bf6eSScott Long } 329236e0bf6eSScott Long i++; 3293795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3294cbfd045bSScott Long aac_release_sync_fib(sc); 329536e0bf6eSScott Long 329636e0bf6eSScott Long /* 3297914da7d0SScott Long * Go through our list of containers and see which ones 3298914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3299914da7d0SScott Long * list them they must have been deleted. Do the 3300914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3301914da7d0SScott Long * the co->co_found field. 330236e0bf6eSScott Long */ 330336e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 330436e0bf6eSScott Long while (co != NULL) { 330536e0bf6eSScott Long if (co->co_found == 0) { 33067cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3307c6df6f53SWarner Losh bus_topo_lock(); 3308914da7d0SScott Long device_delete_child(sc->aac_dev, 3309914da7d0SScott Long co->co_disk); 3310c6df6f53SWarner Losh bus_topo_unlock(); 33117cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 331236e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3313bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3314914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3315914da7d0SScott Long co_link); 3316bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3317ba1d57e7SScott Long free(co, M_AACBUF); 331836e0bf6eSScott Long co = co_next; 331936e0bf6eSScott Long } else { 332036e0bf6eSScott Long co->co_found = 0; 332136e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 332236e0bf6eSScott Long } 332336e0bf6eSScott Long } 332436e0bf6eSScott Long 332536e0bf6eSScott Long /* Attach the newly created containers */ 33267cb209f5SScott Long if (added) { 33277cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3328c6df6f53SWarner Losh bus_topo_lock(); 332936e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 3330c6df6f53SWarner Losh bus_topo_unlock(); 33317cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 33327cb209f5SScott Long } 333336e0bf6eSScott Long 333436e0bf6eSScott Long break; 333536e0bf6eSScott Long 3336851f59d7SEd Maste case AifEnEnclosureManagement: 3337851f59d7SEd Maste switch (aif->data.EN.data.EEE.eventType) { 3338851f59d7SEd Maste case AIF_EM_DRIVE_INSERTION: 3339851f59d7SEd Maste case AIF_EM_DRIVE_REMOVAL: 3340851f59d7SEd Maste channel = aif->data.EN.data.EEE.unitID; 3341851f59d7SEd Maste if (sc->cam_rescan_cb != NULL) 3342851f59d7SEd Maste sc->cam_rescan_cb(sc, 3343851f59d7SEd Maste (channel >> 24) & 0xF, 3344851f59d7SEd Maste (channel & 0xFFFF)); 3345851f59d7SEd Maste break; 3346851f59d7SEd Maste } 3347851f59d7SEd Maste break; 3348851f59d7SEd Maste 3349851f59d7SEd Maste case AifEnAddJBOD: 3350851f59d7SEd Maste case AifEnDeleteJBOD: 3351851f59d7SEd Maste channel = aif->data.EN.data.ECE.container; 3352851f59d7SEd Maste if (sc->cam_rescan_cb != NULL) 3353851f59d7SEd Maste sc->cam_rescan_cb(sc, (channel >> 24) & 0xF, 3354851f59d7SEd Maste AAC_CAM_TARGET_WILDCARD); 3355851f59d7SEd Maste break; 3356851f59d7SEd Maste 335736e0bf6eSScott Long default: 335836e0bf6eSScott Long break; 335936e0bf6eSScott Long } 336036e0bf6eSScott Long 336136e0bf6eSScott Long default: 336236e0bf6eSScott Long break; 336336e0bf6eSScott Long } 336436e0bf6eSScott Long 336536e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3366bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3367a723a548SEd Maste current = sc->aifq_idx; 3368a723a548SEd Maste next = (current + 1) % AAC_AIFQ_LENGTH; 3369a723a548SEd Maste if (next == 0) 3370a723a548SEd Maste sc->aifq_filled = 1; 3371a723a548SEd Maste bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3372a723a548SEd Maste /* modify AIF contexts */ 3373a723a548SEd Maste if (sc->aifq_filled) { 3374a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3375a723a548SEd Maste if (next == ctx->ctx_idx) 3376a723a548SEd Maste ctx->ctx_wrap = 1; 3377a723a548SEd Maste else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3378a723a548SEd Maste ctx->ctx_idx = next; 3379a723a548SEd Maste } 3380a723a548SEd Maste } 3381a723a548SEd Maste sc->aifq_idx = next; 3382b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 338335863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 338435863739SMike Smith wakeup(sc->aac_aifq); 3385b3457b51SScott Long /* Wakeup any poll()ers */ 3386512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 3387bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 338835863739SMike Smith } 338935863739SMike Smith 3390914da7d0SScott Long /* 33910b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 339236e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 339336e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 339436e0bf6eSScott Long * returning what the card reported. 339535863739SMike Smith */ 339635863739SMike Smith static int 3397fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 339835863739SMike Smith { 339935863739SMike Smith struct aac_rev_check rev_check; 340035863739SMike Smith struct aac_rev_check_resp rev_check_resp; 340135863739SMike Smith int error = 0; 340235863739SMike Smith 340331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 340435863739SMike Smith 340535863739SMike Smith /* 340635863739SMike Smith * Copyin the revision struct from userspace 340735863739SMike Smith */ 3408c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3409c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 341035863739SMike Smith return error; 341135863739SMike Smith } 341235863739SMike Smith 341331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3414914da7d0SScott Long rev_check.callingRevision.buildNumber); 341535863739SMike Smith 341635863739SMike Smith /* 341735863739SMike Smith * Doctor up the response struct. 341835863739SMike Smith */ 341935863739SMike Smith rev_check_resp.possiblyCompatible = 1; 34208e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.major = 34218e7e6335SEd Maste AAC_DRIVER_MAJOR_VERSION; 34228e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.minor = 34238e7e6335SEd Maste AAC_DRIVER_MINOR_VERSION; 34248e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.type = 34258e7e6335SEd Maste AAC_DRIVER_TYPE; 34268e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.dash = 34278e7e6335SEd Maste AAC_DRIVER_BUGFIX_LEVEL; 3428914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 34298e7e6335SEd Maste AAC_DRIVER_BUILD; 343035863739SMike Smith 3431c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3432c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 343335863739SMike Smith } 343435863739SMike Smith 3435914da7d0SScott Long /* 3436a723a548SEd Maste * Pass the fib context to the caller 3437a723a548SEd Maste */ 3438a723a548SEd Maste static int 3439a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg) 3440a723a548SEd Maste { 3441a723a548SEd Maste struct aac_fib_context *fibctx, *ctx; 3442a723a548SEd Maste int error = 0; 3443a723a548SEd Maste 344431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3445a723a548SEd Maste 3446a723a548SEd Maste fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3447a723a548SEd Maste if (fibctx == NULL) 3448a723a548SEd Maste return (ENOMEM); 3449a723a548SEd Maste 3450a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3451a723a548SEd Maste /* all elements are already 0, add to queue */ 3452a723a548SEd Maste if (sc->fibctx == NULL) 3453a723a548SEd Maste sc->fibctx = fibctx; 3454a723a548SEd Maste else { 3455a723a548SEd Maste for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3456a723a548SEd Maste ; 3457a723a548SEd Maste ctx->next = fibctx; 3458a723a548SEd Maste fibctx->prev = ctx; 3459a723a548SEd Maste } 3460a723a548SEd Maste 3461a723a548SEd Maste /* evaluate unique value */ 3462a723a548SEd Maste fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3463a723a548SEd Maste ctx = sc->fibctx; 3464a723a548SEd Maste while (ctx != fibctx) { 3465a723a548SEd Maste if (ctx->unique == fibctx->unique) { 3466a723a548SEd Maste fibctx->unique++; 3467a723a548SEd Maste ctx = sc->fibctx; 3468a723a548SEd Maste } else { 3469a723a548SEd Maste ctx = ctx->next; 3470a723a548SEd Maste } 3471a723a548SEd Maste } 3472a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3473a723a548SEd Maste 3474a723a548SEd Maste error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3475a723a548SEd Maste if (error) 3476a723a548SEd Maste aac_close_aif(sc, (caddr_t)ctx); 3477a723a548SEd Maste return error; 3478a723a548SEd Maste } 3479a723a548SEd Maste 3480a723a548SEd Maste /* 3481a723a548SEd Maste * Close the caller's fib context 3482a723a548SEd Maste */ 3483a723a548SEd Maste static int 3484a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg) 3485a723a548SEd Maste { 3486a723a548SEd Maste struct aac_fib_context *ctx; 3487a723a548SEd Maste 348831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3489a723a548SEd Maste 3490a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3491a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3492a723a548SEd Maste if (ctx->unique == *(uint32_t *)&arg) { 3493a723a548SEd Maste if (ctx == sc->fibctx) 3494a723a548SEd Maste sc->fibctx = NULL; 3495a723a548SEd Maste else { 3496a723a548SEd Maste ctx->prev->next = ctx->next; 3497a723a548SEd Maste if (ctx->next) 3498a723a548SEd Maste ctx->next->prev = ctx->prev; 3499a723a548SEd Maste } 3500a723a548SEd Maste break; 3501a723a548SEd Maste } 3502a723a548SEd Maste } 3503a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3504a723a548SEd Maste if (ctx) 3505a723a548SEd Maste free(ctx, M_AACBUF); 3506a723a548SEd Maste 3507a723a548SEd Maste return 0; 3508a723a548SEd Maste } 3509a723a548SEd Maste 3510a723a548SEd Maste /* 351135863739SMike Smith * Pass the caller the next AIF in their queue 351235863739SMike Smith */ 351335863739SMike Smith static int 3514fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 351535863739SMike Smith { 351635863739SMike Smith struct get_adapter_fib_ioctl agf; 3517a723a548SEd Maste struct aac_fib_context *ctx; 35189e2e96d8SScott Long int error; 351935863739SMike Smith 352031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 352135863739SMike Smith 3522f287c3e4SBrooks Davis #ifdef COMPAT_FREEBSD32 3523f287c3e4SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) { 3524f287c3e4SBrooks Davis struct get_adapter_fib_ioctl32 agf32; 3525f287c3e4SBrooks Davis error = copyin(arg, &agf32, sizeof(agf32)); 3526f287c3e4SBrooks Davis if (error == 0) { 3527f287c3e4SBrooks Davis agf.AdapterFibContext = agf32.AdapterFibContext; 3528f287c3e4SBrooks Davis agf.Wait = agf32.Wait; 3529f287c3e4SBrooks Davis agf.AifFib = (caddr_t)(uintptr_t)agf32.AifFib; 3530f287c3e4SBrooks Davis } 3531f287c3e4SBrooks Davis } else 3532f287c3e4SBrooks Davis #endif 3533f287c3e4SBrooks Davis error = copyin(arg, &agf, sizeof(agf)); 3534f287c3e4SBrooks Davis if (error == 0) { 3535a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3536a723a548SEd Maste if (agf.AdapterFibContext == ctx->unique) 3537a723a548SEd Maste break; 3538a723a548SEd Maste } 3539a723a548SEd Maste if (!ctx) 3540a723a548SEd Maste return (EFAULT); 354135863739SMike Smith 3542a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 3543a723a548SEd Maste if (error == EAGAIN && agf.Wait) { 354431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 354535863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 354635863739SMike Smith while (error == EAGAIN) { 3547914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3548914da7d0SScott Long PCATCH, "aacaif", 0); 354935863739SMike Smith if (error == 0) 3550a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 355135863739SMike Smith } 355235863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 355335863739SMike Smith } 355435863739SMike Smith } 355535863739SMike Smith return(error); 355635863739SMike Smith } 355735863739SMike Smith 3558914da7d0SScott Long /* 35590b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 35600b94a66eSMike Smith */ 35610b94a66eSMike Smith static int 3562a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 35630b94a66eSMike Smith { 3564a723a548SEd Maste int current, error; 35650b94a66eSMike Smith 356631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 35670b94a66eSMike Smith 3568bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3569a723a548SEd Maste current = ctx->ctx_idx; 3570a723a548SEd Maste if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3571a723a548SEd Maste /* empty */ 3572bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 35733df780cfSScott Long return (EAGAIN); 35743df780cfSScott Long } 3575a723a548SEd Maste error = 3576a723a548SEd Maste copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 357736e0bf6eSScott Long if (error) 357870545d1aSScott Long device_printf(sc->aac_dev, 357970545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 3580a723a548SEd Maste else { 3581a723a548SEd Maste ctx->ctx_wrap = 0; 3582a723a548SEd Maste ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3583a723a548SEd Maste } 3584bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 35850b94a66eSMike Smith return(error); 35860b94a66eSMike Smith } 358736e0bf6eSScott Long 35887cb209f5SScott Long static int 35897cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 35907cb209f5SScott Long { 35917cb209f5SScott Long struct aac_pci_info { 35927cb209f5SScott Long u_int32_t bus; 35937cb209f5SScott Long u_int32_t slot; 35947cb209f5SScott Long } pciinf; 35957cb209f5SScott Long int error; 35967cb209f5SScott Long 359731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 35987cb209f5SScott Long 35997cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 36007cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 36017cb209f5SScott Long 36027cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 36037cb209f5SScott Long sizeof(struct aac_pci_info)); 36047cb209f5SScott Long 36057cb209f5SScott Long return (error); 36067cb209f5SScott Long } 36077cb209f5SScott Long 36086d307336SEd Maste static int 36096d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr) 36106d307336SEd Maste { 36116d307336SEd Maste struct aac_features f; 36126d307336SEd Maste int error; 36136d307336SEd Maste 36146d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 36156d307336SEd Maste 36166d307336SEd Maste if ((error = copyin(uptr, &f, sizeof (f))) != 0) 36176d307336SEd Maste return (error); 36186d307336SEd Maste 36196d307336SEd Maste /* 36206d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 36216d307336SEd Maste * ALL zero in the featuresState, the driver will return the current 36226d307336SEd Maste * state of all the supported features, the data field will not be 36236d307336SEd Maste * valid. 36246d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 36256d307336SEd Maste * a specific bit set in the featuresState, the driver will return the 36266d307336SEd Maste * current state of this specific feature and whatever data that are 36276d307336SEd Maste * associated with the feature in the data field or perform whatever 36286d307336SEd Maste * action needed indicates in the data field. 36296d307336SEd Maste */ 36306d307336SEd Maste if (f.feat.fValue == 0) { 36316d307336SEd Maste f.feat.fBits.largeLBA = 36326d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 36336d307336SEd Maste /* TODO: In the future, add other features state here as well */ 36346d307336SEd Maste } else { 36356d307336SEd Maste if (f.feat.fBits.largeLBA) 36366d307336SEd Maste f.feat.fBits.largeLBA = 36376d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 36386d307336SEd Maste /* TODO: Add other features state and data in the future */ 36396d307336SEd Maste } 36406d307336SEd Maste 36416d307336SEd Maste error = copyout(&f, uptr, sizeof (f)); 36426d307336SEd Maste return (error); 36436d307336SEd Maste } 36446d307336SEd Maste 3645914da7d0SScott Long /* 364636e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 364736e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 364836e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 364936e0bf6eSScott Long */ 365036e0bf6eSScott Long static int 365136e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 365236e0bf6eSScott Long { 365336e0bf6eSScott Long struct aac_query_disk query_disk; 365436e0bf6eSScott Long struct aac_container *co; 3655914da7d0SScott Long struct aac_disk *disk; 365636e0bf6eSScott Long int error, id; 365736e0bf6eSScott Long 365831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 365936e0bf6eSScott Long 3660914da7d0SScott Long disk = NULL; 3661914da7d0SScott Long 3662914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3663914da7d0SScott Long sizeof(struct aac_query_disk)); 366436e0bf6eSScott Long if (error) 366536e0bf6eSScott Long return (error); 366636e0bf6eSScott Long 366736e0bf6eSScott Long id = query_disk.ContainerNumber; 366836e0bf6eSScott Long if (id == -1) 366936e0bf6eSScott Long return (EINVAL); 367036e0bf6eSScott Long 3671bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 367236e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 367336e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 367436e0bf6eSScott Long break; 367536e0bf6eSScott Long } 367636e0bf6eSScott Long 367736e0bf6eSScott Long if (co == NULL) { 367836e0bf6eSScott Long query_disk.Valid = 0; 367936e0bf6eSScott Long query_disk.Locked = 0; 368036e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 368136e0bf6eSScott Long } else { 368236e0bf6eSScott Long disk = device_get_softc(co->co_disk); 368336e0bf6eSScott Long query_disk.Valid = 1; 3684914da7d0SScott Long query_disk.Locked = 3685914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 368636e0bf6eSScott Long query_disk.Deleted = 0; 3687b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 368836e0bf6eSScott Long query_disk.Target = disk->unit; 368936e0bf6eSScott Long query_disk.Lun = 0; 369036e0bf6eSScott Long query_disk.UnMapped = 0; 36917540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 36920b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 369336e0bf6eSScott Long } 3694bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 369536e0bf6eSScott Long 3696914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3697914da7d0SScott Long sizeof(struct aac_query_disk)); 369836e0bf6eSScott Long 369936e0bf6eSScott Long return (error); 370036e0bf6eSScott Long } 370136e0bf6eSScott Long 3702fe3cb0e1SScott Long static void 3703fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3704fe3cb0e1SScott Long { 3705fe3cb0e1SScott Long struct aac_fib *fib; 3706fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3707fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3708fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3709fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3710fe3cb0e1SScott Long struct aac_getbusinf businfo; 371170545d1aSScott Long struct aac_sim *caminf; 3712fe3cb0e1SScott Long device_t child; 3713fe3cb0e1SScott Long int i, found, error; 3714fe3cb0e1SScott Long 37151ffe41c1SChristian S.J. Peron mtx_lock(&sc->aac_io_lock); 371603b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3717fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 371839ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3719fe3cb0e1SScott Long 3720fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3721fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3722fe3cb0e1SScott Long c_cmd->param = 0; 3723fe3cb0e1SScott Long 3724fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3725fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3726fe3cb0e1SScott Long if (error) { 3727fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3728fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3729fe3cb0e1SScott Long aac_release_sync_fib(sc); 37301ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3731fe3cb0e1SScott Long return; 3732fe3cb0e1SScott Long } 3733fe3cb0e1SScott Long 3734fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3735fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3736fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3737fe3cb0e1SScott Long c_resp->Status); 3738fe3cb0e1SScott Long aac_release_sync_fib(sc); 37391ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3740fe3cb0e1SScott Long return; 3741fe3cb0e1SScott Long } 3742fe3cb0e1SScott Long 3743fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3744fe3cb0e1SScott Long 3745fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 374639ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 374739ee03c3SScott Long 3748fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3749fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3750fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3751fe3cb0e1SScott Long vmi->ObjId = 0; 3752fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3753fe3cb0e1SScott Long 3754fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 375542ef13a2SEd Maste sizeof(struct aac_vmi_businf_resp)); 3756fe3cb0e1SScott Long if (error) { 3757fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3758fe3cb0e1SScott Long error); 3759fe3cb0e1SScott Long aac_release_sync_fib(sc); 37601ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3761fe3cb0e1SScott Long return; 3762fe3cb0e1SScott Long } 3763fe3cb0e1SScott Long 3764fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3765fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3766fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3767fe3cb0e1SScott Long vmi_resp->Status); 3768fe3cb0e1SScott Long aac_release_sync_fib(sc); 37691ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3770fe3cb0e1SScott Long return; 3771fe3cb0e1SScott Long } 3772fe3cb0e1SScott Long 3773fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3774fe3cb0e1SScott Long aac_release_sync_fib(sc); 37751ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3776fe3cb0e1SScott Long 3777fe3cb0e1SScott Long found = 0; 3778fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3779fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3780fe3cb0e1SScott Long continue; 3781fe3cb0e1SScott Long 3782a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3783a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3784b5f516cdSScott Long if (caminf == NULL) { 3785b5f516cdSScott Long device_printf(sc->aac_dev, 3786b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3787b5f516cdSScott Long break; 378874b8d63dSPedro F. Giffuni } 3789fe3cb0e1SScott Long 3790fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3791fe3cb0e1SScott Long if (child == NULL) { 3792b5f516cdSScott Long device_printf(sc->aac_dev, 3793b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3794b5f516cdSScott Long i); 3795b5f516cdSScott Long free(caminf, M_AACBUF); 3796b5f516cdSScott Long break; 3797fe3cb0e1SScott Long } 3798fe3cb0e1SScott Long 3799fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3800fe3cb0e1SScott Long caminf->BusNumber = i; 3801fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3802fe3cb0e1SScott Long caminf->aac_sc = sc; 3803ddb8683eSScott Long caminf->sim_dev = child; 3804fe3cb0e1SScott Long 3805fe3cb0e1SScott Long device_set_ivars(child, caminf); 3806fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 380770545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3808fe3cb0e1SScott Long 3809fe3cb0e1SScott Long found = 1; 3810fe3cb0e1SScott Long } 3811fe3cb0e1SScott Long 3812fe3cb0e1SScott Long if (found) 3813fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3814fe3cb0e1SScott Long } 3815