135863739SMike Smith /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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> 3335863739SMike Smith /* 3435863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3535863739SMike Smith */ 367cb209f5SScott Long #define AAC_DRIVERNAME "aac" 3735863739SMike Smith 38f6c4dd3fSScott Long #include "opt_aac.h" 39f6c4dd3fSScott Long 4036e0bf6eSScott Long /* #include <stddef.h> */ 4135863739SMike Smith #include <sys/param.h> 4235863739SMike Smith #include <sys/systm.h> 4335863739SMike Smith #include <sys/malloc.h> 4435863739SMike Smith #include <sys/kernel.h> 4536e0bf6eSScott Long #include <sys/kthread.h> 46f287c3e4SBrooks Davis #include <sys/proc.h> 473d04a9d7SScott Long #include <sys/sysctl.h> 48f287c3e4SBrooks Davis #include <sys/sysent.h> 49b3457b51SScott Long #include <sys/poll.h> 50891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 5135863739SMike Smith 5235863739SMike Smith #include <sys/bus.h> 5335863739SMike Smith #include <sys/conf.h> 5435863739SMike Smith #include <sys/signalvar.h> 550b94a66eSMike Smith #include <sys/time.h> 5636e0bf6eSScott Long #include <sys/eventhandler.h> 577cb209f5SScott Long #include <sys/rman.h> 5835863739SMike Smith 5935863739SMike Smith #include <machine/bus.h> 6035863739SMike Smith #include <machine/resource.h> 6135863739SMike Smith 627cb209f5SScott Long #include <dev/pci/pcireg.h> 637cb209f5SScott Long #include <dev/pci/pcivar.h> 647cb209f5SScott Long 6535863739SMike Smith #include <dev/aac/aacreg.h> 660b0594cdSScott Long #include <sys/aac_ioctl.h> 6735863739SMike Smith #include <dev/aac/aacvar.h> 6835863739SMike Smith #include <dev/aac/aac_tables.h> 6935863739SMike Smith 7035863739SMike Smith static void aac_startup(void *arg); 71914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 72cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 73fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 74ff0991c4SAttilio Rao static void aac_daemon(void *arg); 7535863739SMike Smith 7635863739SMike Smith /* Command Processing */ 770b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7835863739SMike Smith static void aac_complete(void *context, int pending); 7935863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8035863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 81d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 8270545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8335863739SMike Smith 8435863739SMike Smith /* Command Buffer Management */ 85cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 86cd481291SScott Long int nseg, int error); 87c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 88c6eafcf2SScott Long int nseg, int error); 890b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 908480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9135863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9235863739SMike Smith 9335863739SMike Smith /* Hardware Interface */ 9404f4d586SEd Maste static int aac_alloc(struct aac_softc *sc); 95c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 96c6eafcf2SScott Long int error); 97fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9835863739SMike Smith static int aac_init(struct aac_softc *sc); 9935863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 100c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 101c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 10204f4d586SEd Maste static int aac_setup_intr(struct aac_softc *sc); 103c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 104f6c4dd3fSScott Long struct aac_command *cm); 105c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 106914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10736e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10836e0bf6eSScott Long struct aac_fib *fib); 10935863739SMike Smith 11035863739SMike Smith /* StrongARM interface */ 11135863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 11235863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 11335863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 11435863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 11535863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 116c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 117c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 118a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 11935863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 12035863739SMike Smith 121da4882c2SMarius Strobl const struct aac_interface aac_sa_interface = { 12235863739SMike Smith aac_sa_get_fwstatus, 12335863739SMike Smith aac_sa_qnotify, 12435863739SMike Smith aac_sa_get_istatus, 12535863739SMike Smith aac_sa_clear_istatus, 12635863739SMike Smith aac_sa_set_mailbox, 127a6d35632SScott Long aac_sa_get_mailbox, 1287cb209f5SScott Long aac_sa_set_interrupts, 1297cb209f5SScott Long NULL, NULL, NULL 13035863739SMike Smith }; 13135863739SMike Smith 13235863739SMike Smith /* i960Rx interface */ 13335863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 13435863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 13535863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 13635863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 13735863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 138c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 139c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 140a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 14135863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1427cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1437cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1447cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 14535863739SMike Smith 146da4882c2SMarius Strobl const struct aac_interface aac_rx_interface = { 14735863739SMike Smith aac_rx_get_fwstatus, 14835863739SMike Smith aac_rx_qnotify, 14935863739SMike Smith aac_rx_get_istatus, 15035863739SMike Smith aac_rx_clear_istatus, 15135863739SMike Smith aac_rx_set_mailbox, 152a6d35632SScott Long aac_rx_get_mailbox, 1537cb209f5SScott Long aac_rx_set_interrupts, 1547cb209f5SScott Long aac_rx_send_command, 1557cb209f5SScott Long aac_rx_get_outb_queue, 1567cb209f5SScott Long aac_rx_set_outb_queue 15735863739SMike Smith }; 15835863739SMike Smith 1594afedc31SScott Long /* Rocket/MIPS interface */ 1604afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1614afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1624afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1634afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1644afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1654afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1664afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1674afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1684afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1697cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1707cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1717cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1724afedc31SScott Long 173da4882c2SMarius Strobl const struct aac_interface aac_rkt_interface = { 1744afedc31SScott Long aac_rkt_get_fwstatus, 1754afedc31SScott Long aac_rkt_qnotify, 1764afedc31SScott Long aac_rkt_get_istatus, 1774afedc31SScott Long aac_rkt_clear_istatus, 1784afedc31SScott Long aac_rkt_set_mailbox, 1794afedc31SScott Long aac_rkt_get_mailbox, 1807cb209f5SScott Long aac_rkt_set_interrupts, 1817cb209f5SScott Long aac_rkt_send_command, 1827cb209f5SScott Long aac_rkt_get_outb_queue, 1837cb209f5SScott Long aac_rkt_set_outb_queue 1844afedc31SScott Long }; 1854afedc31SScott Long 18635863739SMike Smith /* Debugging and Diagnostics */ 18735863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 188da4882c2SMarius Strobl static const char *aac_describe_code(const struct aac_code_lookup *table, 189c6eafcf2SScott Long u_int32_t code); 19035863739SMike Smith 19135863739SMike Smith /* Management Interface */ 19235863739SMike Smith static d_open_t aac_open; 19335863739SMike Smith static d_ioctl_t aac_ioctl; 194b3457b51SScott Long static d_poll_t aac_poll; 195dfe2c294SAttilio Rao static void aac_cdevpriv_dtor(void *arg); 196c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 197f355c0e0SEd Maste static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 198c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 19936e0bf6eSScott Long struct aac_fib *fib); 200fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 201a723a548SEd Maste static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 202a723a548SEd Maste static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 203fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 204a723a548SEd Maste static int aac_return_aif(struct aac_softc *sc, 205a723a548SEd Maste struct aac_fib_context *ctx, caddr_t uptr); 20636e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2077cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2086d307336SEd Maste static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 2097cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2107cb209f5SScott Long struct aac_event *event, void *arg); 21104f4d586SEd Maste static struct aac_mntinforesp * 21204f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); 21335863739SMike Smith 21435863739SMike Smith static struct cdevsw aac_cdevsw = { 215dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 216dfdbb320SWarner Losh .d_flags = 0, 2177ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2187ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2197ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2207ac40f5fSPoul-Henning Kamp .d_name = "aac", 22135863739SMike Smith }; 22235863739SMike Smith 223d745c852SEd Schouten static MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 22436e0bf6eSScott Long 2253d04a9d7SScott Long /* sysctl node */ 2267029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 2277029da5cSPawel Biernacki "AAC driver parameters"); 2283d04a9d7SScott Long 229914da7d0SScott Long /* 230914da7d0SScott Long * Device Interface 231914da7d0SScott Long */ 23235863739SMike Smith 233914da7d0SScott Long /* 2344109ba51SEd Maste * Initialize the controller and softc 23535863739SMike Smith */ 23635863739SMike Smith int 23735863739SMike Smith aac_attach(struct aac_softc *sc) 23835863739SMike Smith { 23935863739SMike Smith int error, unit; 24035863739SMike Smith 24131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24235863739SMike Smith 24335863739SMike Smith /* 2444109ba51SEd Maste * Initialize per-controller queues. 24535863739SMike Smith */ 2460b94a66eSMike Smith aac_initq_free(sc); 2470b94a66eSMike Smith aac_initq_ready(sc); 2480b94a66eSMike Smith aac_initq_busy(sc); 2490b94a66eSMike Smith aac_initq_bio(sc); 25035863739SMike Smith 25135863739SMike Smith /* 2524109ba51SEd Maste * Initialize command-completion task. 25335863739SMike Smith */ 25435863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 25535863739SMike Smith 25635863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25735863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25835863739SMike Smith 25935863739SMike Smith /* 260fe94b852SScott Long * Check that the firmware on the card is supported. 261fe94b852SScott Long */ 262fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 263fe94b852SScott Long return(error); 264fe94b852SScott Long 265f6b1c44dSScott Long /* 266f6b1c44dSScott Long * Initialize locks 267f6b1c44dSScott Long */ 268bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 269bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 270bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 271f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 272065dd78cSScott Long TAILQ_INIT(&sc->aac_ev_cmfree); 273f6b1c44dSScott Long 274ff0991c4SAttilio Rao /* Initialize the clock daemon callout. */ 275ff0991c4SAttilio Rao callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 276ff0991c4SAttilio Rao 2770b94a66eSMike Smith /* 2784109ba51SEd Maste * Initialize the adapter. 27935863739SMike Smith */ 28004f4d586SEd Maste if ((error = aac_alloc(sc)) != 0) 28104f4d586SEd Maste return(error); 2820b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 28335863739SMike Smith return(error); 28435863739SMike Smith 28535863739SMike Smith /* 2867cb209f5SScott Long * Allocate and connect our interrupt. 2877cb209f5SScott Long */ 28804f4d586SEd Maste if ((error = aac_setup_intr(sc)) != 0) 28904f4d586SEd Maste return(error); 2907cb209f5SScott Long 2917cb209f5SScott Long /* 29235863739SMike Smith * Print a little information about the controller. 29335863739SMike Smith */ 29435863739SMike Smith aac_describe_controller(sc); 29535863739SMike Smith 29635863739SMike Smith /* 2971423dcd6SEd Maste * Add sysctls. 2981423dcd6SEd Maste */ 2991423dcd6SEd Maste SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->aac_dev), 3001423dcd6SEd Maste SYSCTL_CHILDREN(device_get_sysctl_tree(sc->aac_dev)), 3011423dcd6SEd Maste OID_AUTO, "firmware_build", CTLFLAG_RD, 3021423dcd6SEd Maste &sc->aac_revision.buildNumber, 0, 3031423dcd6SEd Maste "firmware build number"); 3041423dcd6SEd Maste 3051423dcd6SEd Maste /* 306ae543596SScott Long * Register to probe our containers later. 307ae543596SScott Long */ 30835863739SMike Smith sc->aac_ich.ich_func = aac_startup; 30935863739SMike Smith sc->aac_ich.ich_arg = sc; 31035863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 311914da7d0SScott Long device_printf(sc->aac_dev, 312914da7d0SScott Long "can't establish configuration hook\n"); 31335863739SMike Smith return(ENXIO); 31435863739SMike Smith } 31535863739SMike Smith 31635863739SMike Smith /* 31735863739SMike Smith * Make the control device. 31835863739SMike Smith */ 31935863739SMike Smith unit = device_get_unit(sc->aac_dev); 3209e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3219e9466baSRobert Watson 0640, "aac%d", unit); 322157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3234aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 32435863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 32535863739SMike Smith 32636e0bf6eSScott Long /* Create the AIF thread */ 3273745c395SJulian Elischer if (kproc_create((void(*)(void *))aac_command_thread, sc, 328316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 329a620bad0SEd Maste panic("Could not create AIF thread"); 33036e0bf6eSScott Long 33136e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3325f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3335f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3345f54d522SScott Long device_printf(sc->aac_dev, 3355f54d522SScott Long "shutdown event registration failed\n"); 33636e0bf6eSScott Long 337fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 338a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 33970545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 340fe3cb0e1SScott Long aac_get_bus_info(sc); 34170545d1aSScott Long } 342fe3cb0e1SScott Long 343ff0991c4SAttilio Rao mtx_lock(&sc->aac_io_lock); 344867b1d34SEd Maste callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 345ff0991c4SAttilio Rao mtx_unlock(&sc->aac_io_lock); 346ff0991c4SAttilio Rao 34735863739SMike Smith return(0); 34835863739SMike Smith } 34935863739SMike Smith 350ff0991c4SAttilio Rao static void 351ff0991c4SAttilio Rao aac_daemon(void *arg) 352ff0991c4SAttilio Rao { 353ff0991c4SAttilio Rao struct timeval tv; 354ff0991c4SAttilio Rao struct aac_softc *sc; 355ff0991c4SAttilio Rao struct aac_fib *fib; 356ff0991c4SAttilio Rao 357ff0991c4SAttilio Rao sc = arg; 358ff0991c4SAttilio Rao mtx_assert(&sc->aac_io_lock, MA_OWNED); 359ff0991c4SAttilio Rao 360ff0991c4SAttilio Rao if (callout_pending(&sc->aac_daemontime) || 361ff0991c4SAttilio Rao callout_active(&sc->aac_daemontime) == 0) 362ff0991c4SAttilio Rao return; 363ff0991c4SAttilio Rao getmicrotime(&tv); 364ff0991c4SAttilio Rao aac_alloc_sync_fib(sc, &fib); 365ff0991c4SAttilio Rao *(uint32_t *)fib->data = tv.tv_sec; 366ff0991c4SAttilio Rao aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); 367ff0991c4SAttilio Rao aac_release_sync_fib(sc); 368ff0991c4SAttilio Rao callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 369ff0991c4SAttilio Rao } 370ff0991c4SAttilio Rao 3717cb209f5SScott Long void 3727cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event) 3737cb209f5SScott Long { 3747cb209f5SScott Long 3757cb209f5SScott Long switch (event->ev_type & AAC_EVENT_MASK) { 3767cb209f5SScott Long case AAC_EVENT_CMFREE: 3777cb209f5SScott Long TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 3787cb209f5SScott Long break; 3797cb209f5SScott Long default: 3807cb209f5SScott Long device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 3817cb209f5SScott Long event->ev_type); 3827cb209f5SScott Long break; 3837cb209f5SScott Long } 3847cb209f5SScott Long } 3857cb209f5SScott Long 386914da7d0SScott Long /* 38704f4d586SEd Maste * Request information of container #cid 38804f4d586SEd Maste */ 38904f4d586SEd Maste static struct aac_mntinforesp * 39004f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) 39104f4d586SEd Maste { 39204f4d586SEd Maste struct aac_mntinfo *mi; 39304f4d586SEd Maste 39404f4d586SEd Maste mi = (struct aac_mntinfo *)&fib->data[0]; 395523da39bSEd Maste /* use 64-bit LBA if enabled */ 396523da39bSEd Maste mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? 397523da39bSEd Maste VM_NameServe64 : VM_NameServe; 39804f4d586SEd Maste mi->MntType = FT_FILESYS; 39904f4d586SEd Maste mi->MntCount = cid; 40004f4d586SEd Maste 40104f4d586SEd Maste if (aac_sync_fib(sc, ContainerCommand, 0, fib, 40204f4d586SEd Maste sizeof(struct aac_mntinfo))) { 403dbb34a64SEd Maste device_printf(sc->aac_dev, "Error probing container %d\n", cid); 40404f4d586SEd Maste return (NULL); 40504f4d586SEd Maste } 40604f4d586SEd Maste 40704f4d586SEd Maste return ((struct aac_mntinforesp *)&fib->data[0]); 40804f4d586SEd Maste } 40904f4d586SEd Maste 41004f4d586SEd Maste /* 41135863739SMike Smith * Probe for containers, create disks. 41235863739SMike Smith */ 41335863739SMike Smith static void 41435863739SMike Smith aac_startup(void *arg) 41535863739SMike Smith { 416914da7d0SScott Long struct aac_softc *sc; 417cbfd045bSScott Long struct aac_fib *fib; 41804f4d586SEd Maste struct aac_mntinforesp *mir; 419795d7dc0SScott Long int count = 0, i = 0; 42035863739SMike Smith 421914da7d0SScott Long sc = (struct aac_softc *)arg; 42231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 423914da7d0SScott Long 4247cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 42503b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 426cbfd045bSScott Long 42735863739SMike Smith /* loop over possible containers */ 42836e0bf6eSScott Long do { 42904f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 43035863739SMike Smith continue; 43104f4d586SEd Maste if (i == 0) 432795d7dc0SScott Long count = mir->MntRespCount; 433cbfd045bSScott Long aac_add_container(sc, mir, 0); 43436e0bf6eSScott Long i++; 435795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 436cbfd045bSScott Long 437cbfd045bSScott Long aac_release_sync_fib(sc); 4387cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 43935863739SMike Smith 440cc336c78SScott Long /* mark the controller up */ 441cc336c78SScott Long sc->aac_state &= ~AAC_STATE_SUSPEND; 442cc336c78SScott Long 44335863739SMike Smith /* poke the bus to actually attach the child devices */ 44435863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 44535863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 44635863739SMike Smith 447cc336c78SScott Long /* disconnect ourselves from the intrhook chain */ 448cc336c78SScott Long config_intrhook_disestablish(&sc->aac_ich); 44935863739SMike Smith 45035863739SMike Smith /* enable interrupts now */ 45135863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 45235863739SMike Smith } 45335863739SMike Smith 454914da7d0SScott Long /* 4554109ba51SEd Maste * Create a device to represent a new container 456914da7d0SScott Long */ 457914da7d0SScott Long static void 458cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 459914da7d0SScott Long { 460914da7d0SScott Long struct aac_container *co; 461914da7d0SScott Long device_t child; 462914da7d0SScott Long 463914da7d0SScott Long /* 464914da7d0SScott Long * Check container volume type for validity. Note that many of 465914da7d0SScott Long * the possible types may never show up. 466914da7d0SScott Long */ 467914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 468a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 469a761a1caSScott Long M_NOWAIT | M_ZERO); 470914da7d0SScott Long if (co == NULL) 471a620bad0SEd Maste panic("Out of memory?!"); 47231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", 473914da7d0SScott Long mir->MntTable[0].ObjectId, 474914da7d0SScott Long mir->MntTable[0].FileSystemName, 475914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 476914da7d0SScott Long 477fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 478914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 479914da7d0SScott Long else 480914da7d0SScott Long device_set_ivars(child, co); 481914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 482914da7d0SScott Long mir->MntTable[0].VolType)); 483914da7d0SScott Long co->co_disk = child; 484914da7d0SScott Long co->co_found = f; 485914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 486914da7d0SScott Long sizeof(struct aac_mntobj)); 487bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 488914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 489bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 490914da7d0SScott Long } 491914da7d0SScott Long } 492914da7d0SScott Long 493914da7d0SScott Long /* 49404f4d586SEd Maste * Allocate resources associated with (sc) 49504f4d586SEd Maste */ 49604f4d586SEd Maste static int 49704f4d586SEd Maste aac_alloc(struct aac_softc *sc) 49804f4d586SEd Maste { 49931a0399eSEd Maste 50031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 50131a0399eSEd Maste 50204f4d586SEd Maste /* 50304f4d586SEd Maste * Create DMA tag for mapping buffers into controller-addressable space. 50404f4d586SEd Maste */ 50504f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 50604f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 50704f4d586SEd Maste (sc->flags & AAC_FLAGS_SG_64BIT) ? 50804f4d586SEd Maste BUS_SPACE_MAXADDR : 50904f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 51004f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 51104f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 5126f954fb3SAlexander Motin sc->aac_max_sectors << 9, /* maxsize */ 51304f4d586SEd Maste sc->aac_sg_tablesize, /* nsegments */ 5146f954fb3SAlexander Motin BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 51504f4d586SEd Maste BUS_DMA_ALLOCNOW, /* flags */ 51604f4d586SEd Maste busdma_lock_mutex, /* lockfunc */ 51704f4d586SEd Maste &sc->aac_io_lock, /* lockfuncarg */ 51804f4d586SEd Maste &sc->aac_buffer_dmat)) { 51904f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 52004f4d586SEd Maste return (ENOMEM); 52104f4d586SEd Maste } 52204f4d586SEd Maste 52304f4d586SEd Maste /* 52404f4d586SEd Maste * Create DMA tag for mapping FIBs into controller-addressable space.. 52504f4d586SEd Maste */ 52604f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 52704f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 52804f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 52904f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 53004f4d586SEd Maste 0x7fffffff, /* lowaddr */ 53104f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 53204f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 53304f4d586SEd Maste sc->aac_max_fibs_alloc * 53404f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 53504f4d586SEd Maste 1, /* nsegments */ 53604f4d586SEd Maste sc->aac_max_fibs_alloc * 53704f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 53804f4d586SEd Maste 0, /* flags */ 53904f4d586SEd Maste NULL, NULL, /* No locking needed */ 54004f4d586SEd Maste &sc->aac_fib_dmat)) { 541c2ede4b3SMartin Blapp device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 54204f4d586SEd Maste return (ENOMEM); 54304f4d586SEd Maste } 54404f4d586SEd Maste 54504f4d586SEd Maste /* 54604f4d586SEd Maste * Create DMA tag for the common structure and allocate it. 54704f4d586SEd Maste */ 54804f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 54904f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 55004f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 55104f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 55204f4d586SEd Maste 0x7fffffff, /* lowaddr */ 55304f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 55404f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 55504f4d586SEd Maste 8192 + sizeof(struct aac_common), /* maxsize */ 55604f4d586SEd Maste 1, /* nsegments */ 55704f4d586SEd Maste BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 55804f4d586SEd Maste 0, /* flags */ 55904f4d586SEd Maste NULL, NULL, /* No locking needed */ 56004f4d586SEd Maste &sc->aac_common_dmat)) { 56104f4d586SEd Maste device_printf(sc->aac_dev, 56204f4d586SEd Maste "can't allocate common structure DMA tag\n"); 56304f4d586SEd Maste return (ENOMEM); 56404f4d586SEd Maste } 56504f4d586SEd Maste if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 56604f4d586SEd Maste BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 56704f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate common structure\n"); 56804f4d586SEd Maste return (ENOMEM); 56904f4d586SEd Maste } 57004f4d586SEd Maste 57104f4d586SEd Maste /* 57204f4d586SEd Maste * Work around a bug in the 2120 and 2200 that cannot DMA commands 57304f4d586SEd Maste * below address 8192 in physical memory. 57404f4d586SEd Maste * XXX If the padding is not needed, can it be put to use instead 57504f4d586SEd Maste * of ignored? 57604f4d586SEd Maste */ 57704f4d586SEd Maste (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 57804f4d586SEd Maste sc->aac_common, 8192 + sizeof(*sc->aac_common), 57904f4d586SEd Maste aac_common_map, sc, 0); 58004f4d586SEd Maste 58104f4d586SEd Maste if (sc->aac_common_busaddr < 8192) { 58204f4d586SEd Maste sc->aac_common = (struct aac_common *) 58304f4d586SEd Maste ((uint8_t *)sc->aac_common + 8192); 58404f4d586SEd Maste sc->aac_common_busaddr += 8192; 58504f4d586SEd Maste } 58604f4d586SEd Maste bzero(sc->aac_common, sizeof(*sc->aac_common)); 58704f4d586SEd Maste 58804f4d586SEd Maste /* Allocate some FIBs and associated command structs */ 58904f4d586SEd Maste TAILQ_INIT(&sc->aac_fibmap_tqh); 59004f4d586SEd Maste sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 59104f4d586SEd Maste M_AACBUF, M_WAITOK|M_ZERO); 59223e876b1SJung-uk Kim while (sc->total_fibs < sc->aac_max_fibs) { 59304f4d586SEd Maste if (aac_alloc_commands(sc) != 0) 59404f4d586SEd Maste break; 59504f4d586SEd Maste } 59604f4d586SEd Maste if (sc->total_fibs == 0) 59704f4d586SEd Maste return (ENOMEM); 59804f4d586SEd Maste 59904f4d586SEd Maste return (0); 60004f4d586SEd Maste } 60104f4d586SEd Maste 60204f4d586SEd Maste /* 60335863739SMike Smith * Free all of the resources associated with (sc) 60435863739SMike Smith * 60535863739SMike Smith * Should not be called if the controller is active. 60635863739SMike Smith */ 60735863739SMike Smith void 60835863739SMike Smith aac_free(struct aac_softc *sc) 60935863739SMike Smith { 610ffb37f33SScott Long 61131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 61235863739SMike Smith 61335863739SMike Smith /* remove the control device */ 61435863739SMike Smith if (sc->aac_dev_t != NULL) 61535863739SMike Smith destroy_dev(sc->aac_dev_t); 61635863739SMike Smith 6170b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 6188480cc63SScott Long aac_free_commands(sc); 6190b94a66eSMike Smith if (sc->aac_fib_dmat) 6200b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 62135863739SMike Smith 622ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 623ffb37f33SScott Long 62435863739SMike Smith /* destroy the common area */ 62535863739SMike Smith if (sc->aac_common) { 62635863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 627c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 628c6eafcf2SScott Long sc->aac_common_dmamap); 62935863739SMike Smith } 6300b94a66eSMike Smith if (sc->aac_common_dmat) 6310b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 63235863739SMike Smith 63335863739SMike Smith /* disconnect the interrupt handler */ 63435863739SMike Smith if (sc->aac_intr) 63535863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 636bbc03f1bSMarius Strobl if (sc->aac_irq != NULL) { 637da4882c2SMarius Strobl bus_release_resource(sc->aac_dev, SYS_RES_IRQ, 638da4882c2SMarius Strobl rman_get_rid(sc->aac_irq), sc->aac_irq); 639bbc03f1bSMarius Strobl pci_release_msi(sc->aac_dev); 640bbc03f1bSMarius Strobl } 64135863739SMike Smith 64235863739SMike Smith /* destroy data-transfer DMA tag */ 64335863739SMike Smith if (sc->aac_buffer_dmat) 64435863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 64535863739SMike Smith 64635863739SMike Smith /* destroy the parent DMA tag */ 64735863739SMike Smith if (sc->aac_parent_dmat) 64835863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 64935863739SMike Smith 65035863739SMike Smith /* release the register window mapping */ 651ff0991c4SAttilio Rao if (sc->aac_regs_res0 != NULL) 652914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 653da4882c2SMarius Strobl rman_get_rid(sc->aac_regs_res0), sc->aac_regs_res0); 654ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) 655ff0991c4SAttilio Rao bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 656da4882c2SMarius Strobl rman_get_rid(sc->aac_regs_res1), sc->aac_regs_res1); 65735863739SMike Smith } 65835863739SMike Smith 659914da7d0SScott Long /* 66035863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 66135863739SMike Smith */ 66235863739SMike Smith int 66335863739SMike Smith aac_detach(device_t dev) 66435863739SMike Smith { 665914da7d0SScott Long struct aac_softc *sc; 66670545d1aSScott Long struct aac_container *co; 66770545d1aSScott Long struct aac_sim *sim; 66835863739SMike Smith int error; 66935863739SMike Smith 670914da7d0SScott Long sc = device_get_softc(dev); 67131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 672914da7d0SScott Long 673ff0991c4SAttilio Rao callout_drain(&sc->aac_daemontime); 674ff0991c4SAttilio Rao 6751bd320ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 6761bd320ecSAttilio Rao while (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 6771bd320ecSAttilio Rao sc->aifflags |= AAC_AIFFLAGS_EXIT; 6781bd320ecSAttilio Rao wakeup(sc->aifthread); 6791bd320ecSAttilio Rao msleep(sc->aac_dev, &sc->aac_io_lock, PUSER, "aacdch", 0); 6801bd320ecSAttilio Rao } 6811bd320ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 6821bd320ecSAttilio Rao KASSERT((sc->aifflags & AAC_AIFFLAGS_RUNNING) == 0, 6831bd320ecSAttilio Rao ("%s: invalid detach state", __func__)); 6841bd320ecSAttilio Rao 68570545d1aSScott Long /* Remove the child containers */ 686a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 68770545d1aSScott Long error = device_delete_child(dev, co->co_disk); 68870545d1aSScott Long if (error) 68970545d1aSScott Long return (error); 69065ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 691a761a1caSScott Long free(co, M_AACBUF); 69270545d1aSScott Long } 69370545d1aSScott Long 69470545d1aSScott Long /* Remove the CAM SIMs */ 695a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 696a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 69770545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 69870545d1aSScott Long if (error) 69970545d1aSScott Long return (error); 700a761a1caSScott Long free(sim, M_AACBUF); 70170545d1aSScott Long } 70270545d1aSScott Long 70335863739SMike Smith if ((error = aac_shutdown(dev))) 70435863739SMike Smith return(error); 70535863739SMike Smith 7065f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 7075f54d522SScott Long 70835863739SMike Smith aac_free(sc); 70935863739SMike Smith 710dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 711dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 712dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 713dc9efde5SScott Long 71435863739SMike Smith return(0); 71535863739SMike Smith } 71635863739SMike Smith 717914da7d0SScott Long /* 71835863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 71935863739SMike Smith * 72035863739SMike Smith * This function is called before detach or system shutdown. 72135863739SMike Smith * 7220b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 72335863739SMike Smith * allow shutdown if any device is open. 72435863739SMike Smith */ 72535863739SMike Smith int 72635863739SMike Smith aac_shutdown(device_t dev) 72735863739SMike Smith { 728914da7d0SScott Long struct aac_softc *sc; 729cbfd045bSScott Long struct aac_fib *fib; 730cbfd045bSScott Long struct aac_close_command *cc; 73135863739SMike Smith 732914da7d0SScott Long sc = device_get_softc(dev); 73331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 734914da7d0SScott Long 73535863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 73635863739SMike Smith 73735863739SMike Smith /* 73835863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 73935863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 74035863739SMike Smith * We've been closed and all I/O completed already 74135863739SMike Smith */ 74235863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 74335863739SMike Smith 7447cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 74503b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 746cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 747cbfd045bSScott Long 74839ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 749cbfd045bSScott Long cc->Command = VM_CloseAll; 750cbfd045bSScott Long cc->ContainerId = 0xffffffff; 751cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 752cbfd045bSScott Long sizeof(struct aac_close_command))) 75335863739SMike Smith printf("FAILED.\n"); 75470545d1aSScott Long else 75570545d1aSScott Long printf("done\n"); 75670545d1aSScott Long #if 0 757914da7d0SScott Long else { 758cbfd045bSScott Long fib->data[0] = 0; 75936e0bf6eSScott Long /* 760914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 76136e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 76236e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 76336e0bf6eSScott Long * driver module with the intent to reload it later. 76436e0bf6eSScott Long */ 765cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 766cbfd045bSScott Long fib, 1)) { 76735863739SMike Smith printf("FAILED.\n"); 76835863739SMike Smith } else { 76935863739SMike Smith printf("done.\n"); 77035863739SMike Smith } 77135863739SMike Smith } 77270545d1aSScott Long #endif 77335863739SMike Smith 77435863739SMike Smith AAC_MASK_INTERRUPTS(sc); 7753576af8fSScott Long aac_release_sync_fib(sc); 7767cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 77735863739SMike Smith 77835863739SMike Smith return(0); 77935863739SMike Smith } 78035863739SMike Smith 781914da7d0SScott Long /* 78235863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 78335863739SMike Smith */ 78435863739SMike Smith int 78535863739SMike Smith aac_suspend(device_t dev) 78635863739SMike Smith { 787914da7d0SScott Long struct aac_softc *sc; 78835863739SMike Smith 789914da7d0SScott Long sc = device_get_softc(dev); 790914da7d0SScott Long 79131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 79235863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 79335863739SMike Smith 79435863739SMike Smith AAC_MASK_INTERRUPTS(sc); 79535863739SMike Smith return(0); 79635863739SMike Smith } 79735863739SMike Smith 798914da7d0SScott Long /* 79935863739SMike Smith * Bring the controller back to a state ready for operation. 80035863739SMike Smith */ 80135863739SMike Smith int 80235863739SMike Smith aac_resume(device_t dev) 80335863739SMike Smith { 804914da7d0SScott Long struct aac_softc *sc; 80535863739SMike Smith 806914da7d0SScott Long sc = device_get_softc(dev); 807914da7d0SScott Long 80831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 80935863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 81035863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 81135863739SMike Smith return(0); 81235863739SMike Smith } 81335863739SMike Smith 814914da7d0SScott Long /* 8157cb209f5SScott Long * Interrupt handler for NEW_COMM interface. 81635863739SMike Smith */ 81735863739SMike Smith void 8187cb209f5SScott Long aac_new_intr(void *arg) 8197cb209f5SScott Long { 8207cb209f5SScott Long struct aac_softc *sc; 8217cb209f5SScott Long u_int32_t index, fast; 8227cb209f5SScott Long struct aac_command *cm; 8237cb209f5SScott Long struct aac_fib *fib; 8247cb209f5SScott Long int i; 8257cb209f5SScott Long 8267cb209f5SScott Long sc = (struct aac_softc *)arg; 8277cb209f5SScott Long 82831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 8297cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 8307cb209f5SScott Long while (1) { 8317cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8327cb209f5SScott Long if (index == 0xffffffff) 8337cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8347cb209f5SScott Long if (index == 0xffffffff) 8357cb209f5SScott Long break; 8367cb209f5SScott Long if (index & 2) { 8377cb209f5SScott Long if (index == 0xfffffffe) { 8387cb209f5SScott Long /* XXX This means that the controller wants 8397cb209f5SScott Long * more work. Ignore it for now. 8407cb209f5SScott Long */ 8417cb209f5SScott Long continue; 8427cb209f5SScott Long } 8437cb209f5SScott Long /* AIF */ 8447cb209f5SScott Long fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 8457cb209f5SScott Long M_NOWAIT | M_ZERO); 8467cb209f5SScott Long if (fib == NULL) { 8477cb209f5SScott Long /* If we're really this short on memory, 8487cb209f5SScott Long * hopefully breaking out of the handler will 8497cb209f5SScott Long * allow something to get freed. This 8507cb209f5SScott Long * actually sucks a whole lot. 8517cb209f5SScott Long */ 8527cb209f5SScott Long break; 8537cb209f5SScott Long } 8547cb209f5SScott Long index &= ~2; 8557cb209f5SScott Long for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 856ff0991c4SAttilio Rao ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); 8577cb209f5SScott Long aac_handle_aif(sc, fib); 8587cb209f5SScott Long free(fib, M_AACBUF); 8597cb209f5SScott Long 8607cb209f5SScott Long /* 8617cb209f5SScott Long * AIF memory is owned by the adapter, so let it 8627cb209f5SScott Long * know that we are done with it. 8637cb209f5SScott Long */ 8647cb209f5SScott Long AAC_SET_OUTB_QUEUE(sc, index); 8657cb209f5SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 8667cb209f5SScott Long } else { 8677cb209f5SScott Long fast = index & 1; 8687cb209f5SScott Long cm = sc->aac_commands + (index >> 2); 8697cb209f5SScott Long fib = cm->cm_fib; 8707cb209f5SScott Long if (fast) { 8717cb209f5SScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 8727cb209f5SScott Long *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 8737cb209f5SScott Long } 8747cb209f5SScott Long aac_remove_busy(cm); 8757cb209f5SScott Long aac_unmap_command(cm); 8767cb209f5SScott Long cm->cm_flags |= AAC_CMD_COMPLETED; 8777cb209f5SScott Long 8787cb209f5SScott Long /* is there a completion handler? */ 8797cb209f5SScott Long if (cm->cm_complete != NULL) { 8807cb209f5SScott Long cm->cm_complete(cm); 8817cb209f5SScott Long } else { 8827cb209f5SScott Long /* assume that someone is sleeping on this 8837cb209f5SScott Long * command 8847cb209f5SScott Long */ 8857cb209f5SScott Long wakeup(cm); 8867cb209f5SScott Long } 8877cb209f5SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 8887cb209f5SScott Long } 8897cb209f5SScott Long } 8907cb209f5SScott Long /* see if we can start some more I/O */ 8917cb209f5SScott Long if ((sc->flags & AAC_QUEUE_FRZN) == 0) 8927cb209f5SScott Long aac_startio(sc); 8937cb209f5SScott Long 8947cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 8957cb209f5SScott Long } 8967cb209f5SScott Long 897e46b9eeaSEd Maste /* 898e46b9eeaSEd Maste * Interrupt filter for !NEW_COMM interface. 899e46b9eeaSEd Maste */ 900ef544f63SPaolo Pisati int 901e46b9eeaSEd Maste aac_filter(void *arg) 90235863739SMike Smith { 903914da7d0SScott Long struct aac_softc *sc; 90470545d1aSScott Long u_int16_t reason; 90535863739SMike Smith 906914da7d0SScott Long sc = (struct aac_softc *)arg; 907914da7d0SScott Long 90831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 909f30ac74cSScott Long /* 9109148fa21SScott Long * Read the status register directly. This is faster than taking the 9119148fa21SScott Long * driver lock and reading the queues directly. It also saves having 9129148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 9139148fa21SScott Long * ugly. 914f30ac74cSScott Long */ 91535863739SMike Smith reason = AAC_GET_ISTATUS(sc); 916f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 917f30ac74cSScott Long 9189c3a7fceSScott Long /* handle completion processing */ 9199148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 920cbc4d2dbSJohn Baldwin taskqueue_enqueue(taskqueue_fast, &sc->aac_task_complete); 92135863739SMike Smith 9229148fa21SScott Long /* controller wants to talk to us */ 9239148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 92470545d1aSScott Long /* 9259148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 9269148fa21SScott Long * that start with a NULL. 92770545d1aSScott Long */ 9289148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 9299148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 9309148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 93170545d1aSScott Long 9329148fa21SScott Long /* 9339148fa21SScott Long * This might miss doing the actual wakeup. However, the 934a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 9359148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 9369148fa21SScott Long * priority that they can handle hanging out for a few seconds 9379148fa21SScott Long * if needed. 9389148fa21SScott Long */ 93936e0bf6eSScott Long wakeup(sc->aifthread); 94036e0bf6eSScott Long } 941ef544f63SPaolo Pisati return (FILTER_HANDLED); 9429148fa21SScott Long } 94335863739SMike Smith 944c6eafcf2SScott Long /* 945914da7d0SScott Long * Command Processing 946914da7d0SScott Long */ 94735863739SMike Smith 948914da7d0SScott Long /* 94935863739SMike Smith * Start as much queued I/O as possible on the controller 95035863739SMike Smith */ 951fe3cb0e1SScott Long void 95235863739SMike Smith aac_startio(struct aac_softc *sc) 95335863739SMike Smith { 95435863739SMike Smith struct aac_command *cm; 955397fa34fSScott Long int error; 95635863739SMike Smith 95731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 95835863739SMike Smith 95935863739SMike Smith for (;;) { 960914da7d0SScott Long /* 961397fa34fSScott Long * This flag might be set if the card is out of resources. 962397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 963397fa34fSScott Long */ 964397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 965397fa34fSScott Long break; 966397fa34fSScott Long 967397fa34fSScott Long /* 968914da7d0SScott Long * Try to get a command that's been put off for lack of 969914da7d0SScott Long * resources 970914da7d0SScott Long */ 97135863739SMike Smith cm = aac_dequeue_ready(sc); 97235863739SMike Smith 973914da7d0SScott Long /* 974914da7d0SScott Long * Try to build a command off the bio queue (ignore error 975914da7d0SScott Long * return) 976914da7d0SScott Long */ 9770b94a66eSMike Smith if (cm == NULL) 97835863739SMike Smith aac_bio_command(sc, &cm); 97935863739SMike Smith 98035863739SMike Smith /* nothing to do? */ 98135863739SMike Smith if (cm == NULL) 98235863739SMike Smith break; 98335863739SMike Smith 984cd481291SScott Long /* don't map more than once */ 985cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 9864102d44bSScott Long panic("aac: command %p already mapped", cm); 98735863739SMike Smith 988397fa34fSScott Long /* 989397fa34fSScott Long * Set up the command to go to the controller. If there are no 990397fa34fSScott Long * data buffers associated with the command then it can bypass 991397fa34fSScott Long * busdma. 992397fa34fSScott Long */ 993cd481291SScott Long if (cm->cm_datalen != 0) { 9948fce673cSMarius Strobl if (cm->cm_flags & AAC_REQ_BIO) 9958fce673cSMarius Strobl error = bus_dmamap_load_bio( 9968fce673cSMarius Strobl sc->aac_buffer_dmat, cm->cm_datamap, 9978fce673cSMarius Strobl (struct bio *)cm->cm_private, 9988fce673cSMarius Strobl aac_map_command_sg, cm, 0); 9998fce673cSMarius Strobl else 1000397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 1001397fa34fSScott Long cm->cm_datamap, cm->cm_data, 10028fce673cSMarius Strobl cm->cm_datalen, aac_map_command_sg, cm, 0); 1003cd481291SScott Long if (error == EINPROGRESS) { 100431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); 1005cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 1006614c22b2SScott Long } else if (error != 0) 1007397fa34fSScott Long panic("aac_startio: unexpected error %d from " 1008a620bad0SEd Maste "busdma", error); 1009397fa34fSScott Long } else 10108778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 1011cd481291SScott Long } 101235863739SMike Smith } 101335863739SMike Smith 1014914da7d0SScott Long /* 101535863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 101635863739SMike Smith */ 101735863739SMike Smith static void 101870545d1aSScott Long aac_command_thread(struct aac_softc *sc) 101935863739SMike Smith { 102035863739SMike Smith struct aac_fib *fib; 102135863739SMike Smith u_int32_t fib_size; 10229148fa21SScott Long int size, retval; 102335863739SMike Smith 102431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 102535863739SMike Smith 1026bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1027a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 102836e0bf6eSScott Long 1029a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1030a32a982dSScott Long retval = 0; 1031a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1032a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1033a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 103436e0bf6eSScott Long 10359148fa21SScott Long /* 10369148fa21SScott Long * First see if any FIBs need to be allocated. This needs 10379148fa21SScott Long * to be called without the driver lock because contigmalloc 10381bd320ecSAttilio Rao * can sleep. 10399148fa21SScott Long */ 10409148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1041bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 1042a32a982dSScott Long aac_alloc_commands(sc); 1043bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 10444102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1045a32a982dSScott Long aac_startio(sc); 1046a32a982dSScott Long } 10479148fa21SScott Long 10489148fa21SScott Long /* 10499148fa21SScott Long * While we're here, check to see if any commands are stuck. 10509148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 10519148fa21SScott Long * always fire. 10529148fa21SScott Long */ 10539148fa21SScott Long if (retval == EWOULDBLOCK) 105470545d1aSScott Long aac_timeout(sc); 105570545d1aSScott Long 105670545d1aSScott Long /* Check the hardware printf message buffer */ 10579148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 105870545d1aSScott Long aac_print_printf(sc); 105970545d1aSScott Long 10609148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 10617cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 10627cb209f5SScott Long continue; 10637cb209f5SScott Long for (;;) { 10647cb209f5SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 10657cb209f5SScott Long &fib_size, &fib)) 10667cb209f5SScott Long break; 106735863739SMike Smith 106836e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 106936e0bf6eSScott Long 107035863739SMike Smith switch (fib->Header.Command) { 107135863739SMike Smith case AifRequest: 107236e0bf6eSScott Long aac_handle_aif(sc, fib); 107335863739SMike Smith break; 107435863739SMike Smith default: 1075914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 1076914da7d0SScott Long "from controller\n"); 107735863739SMike Smith break; 107835863739SMike Smith } 107935863739SMike Smith 108036e0bf6eSScott Long if ((fib->Header.XferState == 0) || 10817cb209f5SScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 108236e0bf6eSScott Long break; 10837cb209f5SScott Long } 108436e0bf6eSScott Long 108570545d1aSScott Long /* Return the AIF to the controller. */ 108636e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 108736e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 108836e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 108936e0bf6eSScott Long 109036e0bf6eSScott Long /* XXX Compute the Size field? */ 109136e0bf6eSScott Long size = fib->Header.Size; 109236e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 109336e0bf6eSScott Long size = sizeof(struct aac_fib); 109436e0bf6eSScott Long fib->Header.Size = size; 109536e0bf6eSScott Long } 109636e0bf6eSScott Long /* 1097914da7d0SScott Long * Since we did not generate this command, it 1098914da7d0SScott Long * cannot go through the normal 1099914da7d0SScott Long * enqueue->startio chain. 110036e0bf6eSScott Long */ 1101914da7d0SScott Long aac_enqueue_response(sc, 1102914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 1103914da7d0SScott Long fib); 110436e0bf6eSScott Long } 110536e0bf6eSScott Long } 110636e0bf6eSScott Long } 110736e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1108bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 110936e0bf6eSScott Long wakeup(sc->aac_dev); 111036e0bf6eSScott Long 11113745c395SJulian Elischer kproc_exit(0); 111235863739SMike Smith } 111335863739SMike Smith 1114914da7d0SScott Long /* 11159c3a7fceSScott Long * Process completed commands. 111635863739SMike Smith */ 111735863739SMike Smith static void 11189c3a7fceSScott Long aac_complete(void *context, int pending) 111935863739SMike Smith { 11209c3a7fceSScott Long struct aac_softc *sc; 112135863739SMike Smith struct aac_command *cm; 112235863739SMike Smith struct aac_fib *fib; 112335863739SMike Smith u_int32_t fib_size; 112435863739SMike Smith 11259c3a7fceSScott Long sc = (struct aac_softc *)context; 112631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 11279c3a7fceSScott Long 1128bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1129ae543596SScott Long 11309c3a7fceSScott Long /* pull completed commands off the queue */ 113135863739SMike Smith for (;;) { 113235863739SMike Smith /* look for completed FIBs on our queue */ 1133914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1134914da7d0SScott Long &fib)) 113535863739SMike Smith break; /* nothing to do */ 113635863739SMike Smith 1137ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 1138cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 113935863739SMike Smith if (cm == NULL) { 114035863739SMike Smith AAC_PRINT_FIB(sc, fib); 11419c3a7fceSScott Long break; 11429c3a7fceSScott Long } 11433e507710SEd Maste if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0) 11443e507710SEd Maste device_printf(sc->aac_dev, 11453e507710SEd Maste "COMMAND %p COMPLETED AFTER %d SECONDS\n", 11463e507710SEd Maste cm, (int)(time_uptime-cm->cm_timestamp)); 11473e507710SEd Maste 11480b94a66eSMike Smith aac_remove_busy(cm); 11497cb209f5SScott Long 1150ecd1c51fSScott Long aac_unmap_command(cm); 115135863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 115235863739SMike Smith 115335863739SMike Smith /* is there a completion handler? */ 115435863739SMike Smith if (cm->cm_complete != NULL) { 115535863739SMike Smith cm->cm_complete(cm); 115635863739SMike Smith } else { 115735863739SMike Smith /* assume that someone is sleeping on this command */ 115835863739SMike Smith wakeup(cm); 115935863739SMike Smith } 116035863739SMike Smith } 11610b94a66eSMike Smith 11620b94a66eSMike Smith /* see if we can start some more I/O */ 1163cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 11640b94a66eSMike Smith aac_startio(sc); 1165ae543596SScott Long 1166bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 116735863739SMike Smith } 116835863739SMike Smith 1169914da7d0SScott Long /* 117035863739SMike Smith * Handle a bio submitted from a disk device. 117135863739SMike Smith */ 117235863739SMike Smith void 117335863739SMike Smith aac_submit_bio(struct bio *bp) 117435863739SMike Smith { 1175914da7d0SScott Long struct aac_disk *ad; 1176914da7d0SScott Long struct aac_softc *sc; 117735863739SMike Smith 11787540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1179914da7d0SScott Long sc = ad->ad_controller; 118031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1181914da7d0SScott Long 118235863739SMike Smith /* queue the BIO and try to get some work done */ 11830b94a66eSMike Smith aac_enqueue_bio(sc, bp); 118435863739SMike Smith aac_startio(sc); 118535863739SMike Smith } 118635863739SMike Smith 1187914da7d0SScott Long /* 118835863739SMike Smith * Get a bio and build a command to go with it. 118935863739SMike Smith */ 119035863739SMike Smith static int 119135863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 119235863739SMike Smith { 119335863739SMike Smith struct aac_command *cm; 119435863739SMike Smith struct aac_fib *fib; 119535863739SMike Smith struct aac_disk *ad; 119635863739SMike Smith struct bio *bp; 119735863739SMike Smith 119831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 119935863739SMike Smith 120035863739SMike Smith /* get the resources we will need */ 120135863739SMike Smith cm = NULL; 1202a32a982dSScott Long bp = NULL; 120335863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 120435863739SMike Smith goto fail; 1205a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 1206a32a982dSScott Long goto fail; 120735863739SMike Smith 120835863739SMike Smith /* fill out the command */ 12090b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 12100b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 12118fce673cSMarius Strobl cm->cm_flags = AAC_REQ_BIO; 121235863739SMike Smith cm->cm_private = bp; 12132b3b0f17SScott Long cm->cm_timestamp = time_uptime; 121435863739SMike Smith 121535863739SMike Smith /* build the FIB */ 121635863739SMike Smith fib = cm->cm_fib; 1217b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 121835863739SMike Smith fib->Header.XferState = 121935863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 122035863739SMike Smith AAC_FIBSTATE_INITIALISED | 1221f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 122235863739SMike Smith AAC_FIBSTATE_FROMHOST | 122335863739SMike Smith AAC_FIBSTATE_REXPECTED | 1224f30ac74cSScott Long AAC_FIBSTATE_NORM | 1225f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 1226f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 122735863739SMike Smith 122835863739SMike Smith /* build the read/write request */ 12297540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1230b85f5808SScott Long 12317cb209f5SScott Long if (sc->flags & AAC_FLAGS_RAW_IO) { 12327cb209f5SScott Long struct aac_raw_io *raw; 12337cb209f5SScott Long raw = (struct aac_raw_io *)&fib->data[0]; 12347cb209f5SScott Long fib->Header.Command = RawIo; 12357cb209f5SScott Long raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 12367cb209f5SScott Long raw->ByteCount = bp->bio_bcount; 12377cb209f5SScott Long raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 12387cb209f5SScott Long raw->BpTotal = 0; 12397cb209f5SScott Long raw->BpComplete = 0; 12407cb209f5SScott Long fib->Header.Size += sizeof(struct aac_raw_io); 12417cb209f5SScott Long cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 12427cb209f5SScott Long if (bp->bio_cmd == BIO_READ) { 12437cb209f5SScott Long raw->Flags = 1; 12447cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 12457cb209f5SScott Long } else { 12467cb209f5SScott Long raw->Flags = 0; 12477cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 12487cb209f5SScott Long } 12497cb209f5SScott Long } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1250b85f5808SScott Long fib->Header.Command = ContainerCommand; 12519e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 1252b85f5808SScott Long struct aac_blockread *br; 125335863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 125435863739SMike Smith br->Command = VM_CtBlockRead; 125535863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 125635863739SMike Smith br->BlockNumber = bp->bio_pblkno; 125735863739SMike Smith br->ByteCount = bp->bio_bcount; 125835863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 125935863739SMike Smith cm->cm_sgtable = &br->SgMap; 126035863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 126135863739SMike Smith } else { 1262b85f5808SScott Long struct aac_blockwrite *bw; 126335863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 126435863739SMike Smith bw->Command = VM_CtBlockWrite; 126535863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 126635863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 126735863739SMike Smith bw->ByteCount = bp->bio_bcount; 1268b85f5808SScott Long bw->Stable = CUNSTABLE; 126935863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 127035863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 127135863739SMike Smith cm->cm_sgtable = &bw->SgMap; 127235863739SMike Smith } 1273b85f5808SScott Long } else { 1274b85f5808SScott Long fib->Header.Command = ContainerCommand64; 1275b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 1276b85f5808SScott Long struct aac_blockread64 *br; 1277b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 1278b85f5808SScott Long br->Command = VM_CtHostRead64; 1279b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1280b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1281b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 1282b85f5808SScott Long br->Pad = 0; 1283b85f5808SScott Long br->Flags = 0; 1284b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 128554e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAIN; 1286eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1287b85f5808SScott Long } else { 1288b85f5808SScott Long struct aac_blockwrite64 *bw; 1289b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 1290b85f5808SScott Long bw->Command = VM_CtHostWrite64; 1291b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1292b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1293b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 1294b85f5808SScott Long bw->Pad = 0; 1295b85f5808SScott Long bw->Flags = 0; 1296b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 129754e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAOUT; 1298eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1299b85f5808SScott Long } 1300b85f5808SScott Long } 130135863739SMike Smith 130235863739SMike Smith *cmp = cm; 130335863739SMike Smith return(0); 130435863739SMike Smith 130535863739SMike Smith fail: 13067cb209f5SScott Long if (bp != NULL) 13077cb209f5SScott Long aac_enqueue_bio(sc, bp); 130835863739SMike Smith if (cm != NULL) 130935863739SMike Smith aac_release_command(cm); 131035863739SMike Smith return(ENOMEM); 131135863739SMike Smith } 131235863739SMike Smith 1313914da7d0SScott Long /* 131435863739SMike Smith * Handle a bio-instigated command that has been completed. 131535863739SMike Smith */ 131635863739SMike Smith static void 131735863739SMike Smith aac_bio_complete(struct aac_command *cm) 131835863739SMike Smith { 131935863739SMike Smith struct aac_blockread_response *brr; 132035863739SMike Smith struct aac_blockwrite_response *bwr; 132135863739SMike Smith struct bio *bp; 132235863739SMike Smith AAC_FSAStatus status; 132335863739SMike Smith 132435863739SMike Smith /* fetch relevant status and then release the command */ 132535863739SMike Smith bp = (struct bio *)cm->cm_private; 13269e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 132735863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 132835863739SMike Smith status = brr->Status; 132935863739SMike Smith } else { 133035863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 133135863739SMike Smith status = bwr->Status; 133235863739SMike Smith } 133335863739SMike Smith aac_release_command(cm); 133435863739SMike Smith 133535863739SMike Smith /* fix up the bio based on status */ 133635863739SMike Smith if (status == ST_OK) { 133735863739SMike Smith bp->bio_resid = 0; 133835863739SMike Smith } else { 133935863739SMike Smith bp->bio_error = EIO; 134035863739SMike Smith bp->bio_flags |= BIO_ERROR; 134135863739SMike Smith } 13420b94a66eSMike Smith aac_biodone(bp); 134335863739SMike Smith } 134435863739SMike Smith 1345914da7d0SScott Long /* 134635863739SMike Smith * Submit a command to the controller, return when it completes. 1347b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1348b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1349d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1350d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1351d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1352d8a0a473SScott Long * card completing a command late and spamming the command and data 1353d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 135435863739SMike Smith */ 135535863739SMike Smith static int 1356d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 135735863739SMike Smith { 1358ae543596SScott Long struct aac_softc *sc; 1359d8a0a473SScott Long int error; 136035863739SMike Smith 1361ae543596SScott Long sc = cm->cm_sc; 136231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1363ae543596SScott Long 136435863739SMike Smith /* Put the command on the ready queue and get things going */ 136535863739SMike Smith aac_enqueue_ready(cm); 1366ae543596SScott Long aac_startio(sc); 1367ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 136835863739SMike Smith return(error); 136935863739SMike Smith } 137035863739SMike Smith 1371914da7d0SScott Long /* 1372914da7d0SScott Long *Command Buffer Management 1373914da7d0SScott Long */ 137435863739SMike Smith 1375914da7d0SScott Long /* 137635863739SMike Smith * Allocate a command. 137735863739SMike Smith */ 1378fe3cb0e1SScott Long int 137935863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 138035863739SMike Smith { 138135863739SMike Smith struct aac_command *cm; 138235863739SMike Smith 138331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 138435863739SMike Smith 1385ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1386b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 13871bd320ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 1388ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 13891bd320ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 1390ae543596SScott Long wakeup(sc->aifthread); 1391b85f5808SScott Long } 1392ae543596SScott Long return (EBUSY); 1393ffb37f33SScott Long } 139435863739SMike Smith 13950b94a66eSMike Smith *cmp = cm; 13960b94a66eSMike Smith return(0); 13970b94a66eSMike Smith } 13980b94a66eSMike Smith 1399914da7d0SScott Long /* 14000b94a66eSMike Smith * Release a command back to the freelist. 14010b94a66eSMike Smith */ 1402fe3cb0e1SScott Long void 14030b94a66eSMike Smith aac_release_command(struct aac_command *cm) 14040b94a66eSMike Smith { 14057cb209f5SScott Long struct aac_event *event; 14067cb209f5SScott Long struct aac_softc *sc; 14077cb209f5SScott Long 140831a0399eSEd Maste sc = cm->cm_sc; 140931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 14100b94a66eSMike Smith 14114109ba51SEd Maste /* (re)initialize the command/FIB */ 1412b2b39b04SJohn Baldwin cm->cm_datalen = 0; 141335863739SMike Smith cm->cm_sgtable = NULL; 141435863739SMike Smith cm->cm_flags = 0; 141535863739SMike Smith cm->cm_complete = NULL; 141635863739SMike Smith cm->cm_private = NULL; 1417dbfc5960SEd Maste cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 141835863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 141935863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 142035863739SMike Smith cm->cm_fib->Header.Flags = 0; 14217cb209f5SScott Long cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 142235863739SMike Smith 142335863739SMike Smith /* 142435863739SMike Smith * These are duplicated in aac_start to cover the case where an 142535863739SMike Smith * intermediate stage may have destroyed them. They're left 14264109ba51SEd Maste * initialized here for debugging purposes only. 142735863739SMike Smith */ 1428f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1429f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 143035863739SMike Smith 143135863739SMike Smith aac_enqueue_free(cm); 14327cb209f5SScott Long 14332ad1c92dSEd Maste if ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 14347cb209f5SScott Long TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 14357cb209f5SScott Long event->ev_callback(sc, event, event->ev_arg); 14367cb209f5SScott Long } 143735863739SMike Smith } 143835863739SMike Smith 1439914da7d0SScott Long /* 14400b94a66eSMike Smith * Map helper for command/FIB allocation. 144135863739SMike Smith */ 144235863739SMike Smith static void 14430b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 144435863739SMike Smith { 14457cb209f5SScott Long uint64_t *fibphys; 1446914da7d0SScott Long 14477cb209f5SScott Long fibphys = (uint64_t *)arg; 144835863739SMike Smith 1449ffb37f33SScott Long *fibphys = segs[0].ds_addr; 145035863739SMike Smith } 145135863739SMike Smith 1452914da7d0SScott Long /* 14534109ba51SEd Maste * Allocate and initialize commands/FIBs for this adapter. 145435863739SMike Smith */ 14550b94a66eSMike Smith static int 14560b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 145735863739SMike Smith { 145835863739SMike Smith struct aac_command *cm; 1459ffb37f33SScott Long struct aac_fibmap *fm; 14607cb209f5SScott Long uint64_t fibphys; 1461ffb37f33SScott Long int i, error; 146235863739SMike Smith 146331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 146435863739SMike Smith 14657cb209f5SScott Long if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1466ffb37f33SScott Long return (ENOMEM); 1467ffb37f33SScott Long 14688480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1469a6d35632SScott Long if (fm == NULL) 1470a6d35632SScott Long return (ENOMEM); 1471ffb37f33SScott Long 14720b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1473ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1474ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 147570545d1aSScott Long device_printf(sc->aac_dev, 147670545d1aSScott Long "Not enough contiguous memory available.\n"); 14778480cc63SScott Long free(fm, M_AACBUF); 14780b94a66eSMike Smith return (ENOMEM); 147935863739SMike Smith } 1480128aa5a0SScott Long 1481cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1482cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 14837cb209f5SScott Long sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1484ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1485128aa5a0SScott Long 14864109ba51SEd Maste /* initialize constant fields in the command structure */ 14877cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 14887cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 14898480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1490ffb37f33SScott Long fm->aac_commands = cm; 149135863739SMike Smith cm->cm_sc = sc; 14927cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 14937cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 14947cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1495cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 149635863739SMike Smith 1497ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 149893cfca22SScott Long &cm->cm_datamap)) != 0) 14998480cc63SScott Long break; 150093cfca22SScott Long mtx_lock(&sc->aac_io_lock); 150193cfca22SScott Long aac_release_command(cm); 15028480cc63SScott Long sc->total_fibs++; 150393cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 150435863739SMike Smith } 1505ffb37f33SScott Long 15068480cc63SScott Long if (i > 0) { 150793cfca22SScott Long mtx_lock(&sc->aac_io_lock); 1508ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 150931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1510bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 15110b94a66eSMike Smith return (0); 151235863739SMike Smith } 151335863739SMike Smith 15148480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 15158480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15168480cc63SScott Long free(fm, M_AACBUF); 15178480cc63SScott Long return (ENOMEM); 15188480cc63SScott Long } 15198480cc63SScott Long 1520914da7d0SScott Long /* 15210b94a66eSMike Smith * Free FIBs owned by this adapter. 152235863739SMike Smith */ 152335863739SMike Smith static void 15248480cc63SScott Long aac_free_commands(struct aac_softc *sc) 152535863739SMike Smith { 15268480cc63SScott Long struct aac_fibmap *fm; 1527ffb37f33SScott Long struct aac_command *cm; 152835863739SMike Smith int i; 152935863739SMike Smith 153031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 153135863739SMike Smith 15328480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 15338480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 15348480cc63SScott Long /* 15358480cc63SScott Long * We check against total_fibs to handle partially 15368480cc63SScott Long * allocated blocks. 15378480cc63SScott Long */ 15387cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1539ffb37f33SScott Long cm = fm->aac_commands + i; 1540ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1541ffb37f33SScott Long } 1542ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1543ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15448480cc63SScott Long free(fm, M_AACBUF); 15458480cc63SScott Long } 154635863739SMike Smith } 154735863739SMike Smith 1548914da7d0SScott Long /* 154935863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 155035863739SMike Smith */ 155135863739SMike Smith static void 155235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 155335863739SMike Smith { 1554cd481291SScott Long struct aac_softc *sc; 1555914da7d0SScott Long struct aac_command *cm; 1556914da7d0SScott Long struct aac_fib *fib; 155735863739SMike Smith int i; 155835863739SMike Smith 1559914da7d0SScott Long cm = (struct aac_command *)arg; 1560cd481291SScott Long sc = cm->cm_sc; 1561914da7d0SScott Long fib = cm->cm_fib; 156231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1563914da7d0SScott Long 156435863739SMike Smith /* copy into the FIB */ 1565b85f5808SScott Long if (cm->cm_sgtable != NULL) { 15667cb209f5SScott Long if (fib->Header.Command == RawIo) { 15677cb209f5SScott Long struct aac_sg_tableraw *sg; 15687cb209f5SScott Long sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 15697cb209f5SScott Long sg->SgCount = nseg; 15707cb209f5SScott Long for (i = 0; i < nseg; i++) { 15717cb209f5SScott Long sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 15727cb209f5SScott Long sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 15737cb209f5SScott Long sg->SgEntryRaw[i].Next = 0; 15747cb209f5SScott Long sg->SgEntryRaw[i].Prev = 0; 15757cb209f5SScott Long sg->SgEntryRaw[i].Flags = 0; 15767cb209f5SScott Long } 15777cb209f5SScott Long /* update the FIB size for the s/g count */ 15787cb209f5SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 15797cb209f5SScott Long } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1580b85f5808SScott Long struct aac_sg_table *sg; 1581b85f5808SScott Long sg = cm->cm_sgtable; 158235863739SMike Smith sg->SgCount = nseg; 158335863739SMike Smith for (i = 0; i < nseg; i++) { 158435863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 158535863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 158635863739SMike Smith } 158735863739SMike Smith /* update the FIB size for the s/g count */ 158835863739SMike Smith fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1589b85f5808SScott Long } else { 1590b85f5808SScott Long struct aac_sg_table64 *sg; 1591b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1592b85f5808SScott Long sg->SgCount = nseg; 1593b85f5808SScott Long for (i = 0; i < nseg; i++) { 1594b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1595b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 159635863739SMike Smith } 1597b85f5808SScott Long /* update the FIB size for the s/g count */ 1598b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1599b85f5808SScott Long } 1600b85f5808SScott Long } 160135863739SMike Smith 1602cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1603cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 16047cb209f5SScott Long * the SenderFibAddress over to make room for the fast response bit 16057cb209f5SScott Long * and for the AIF bit 160635863739SMike Smith */ 16077cb209f5SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 16087cb209f5SScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 160935863739SMike Smith 1610cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1611cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 161235863739SMike Smith 161335863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1614c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1615c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 161635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1617c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1618c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 161935863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1620cd481291SScott Long 16217cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 16227cb209f5SScott Long int count = 10000000L; 16237cb209f5SScott Long while (AAC_SEND_COMMAND(sc, cm) != 0) { 16247cb209f5SScott Long if (--count == 0) { 16257cb209f5SScott Long aac_unmap_command(cm); 16267cb209f5SScott Long sc->flags |= AAC_QUEUE_FRZN; 16277cb209f5SScott Long aac_requeue_ready(cm); 16287cb209f5SScott Long } 16297cb209f5SScott Long DELAY(5); /* wait 5 usec. */ 16307cb209f5SScott Long } 16317cb209f5SScott Long } else { 1632397fa34fSScott Long /* Put the FIB on the outbound queue */ 16334102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 16344102d44bSScott Long aac_unmap_command(cm); 1635397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1636cd481291SScott Long aac_requeue_ready(cm); 16374102d44bSScott Long } 16387cb209f5SScott Long } 163935863739SMike Smith } 164035863739SMike Smith 1641914da7d0SScott Long /* 164235863739SMike Smith * Unmap a command from controller-visible space. 164335863739SMike Smith */ 164435863739SMike Smith static void 164535863739SMike Smith aac_unmap_command(struct aac_command *cm) 164635863739SMike Smith { 1647914da7d0SScott Long struct aac_softc *sc; 164835863739SMike Smith 1649914da7d0SScott Long sc = cm->cm_sc; 165031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1651914da7d0SScott Long 165235863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 165335863739SMike Smith return; 165435863739SMike Smith 165535863739SMike Smith if (cm->cm_datalen != 0) { 165635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1657c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1658c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 165935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1660c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1661c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 166235863739SMike Smith 166335863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 166435863739SMike Smith } 166535863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 166635863739SMike Smith } 166735863739SMike Smith 1668914da7d0SScott Long /* 1669914da7d0SScott Long * Hardware Interface 1670914da7d0SScott Long */ 167135863739SMike Smith 1672914da7d0SScott Long /* 16734109ba51SEd Maste * Initialize the adapter. 167435863739SMike Smith */ 167535863739SMike Smith static void 167635863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 167735863739SMike Smith { 1678914da7d0SScott Long struct aac_softc *sc; 167935863739SMike Smith 1680914da7d0SScott Long sc = (struct aac_softc *)arg; 168131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1682914da7d0SScott Long 168335863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 168435863739SMike Smith } 168535863739SMike Smith 1686a6d35632SScott Long static int 1687a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1688a6d35632SScott Long { 168904f4d586SEd Maste u_int32_t code, major, minor, options = 0, atu_size = 0; 1690da4882c2SMarius Strobl int rid, status; 169104f4d586SEd Maste time_t then; 1692a6d35632SScott Long 169331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 169404f4d586SEd Maste /* 169504f4d586SEd Maste * Wait for the adapter to come ready. 169604f4d586SEd Maste */ 169704f4d586SEd Maste then = time_uptime; 169804f4d586SEd Maste do { 169904f4d586SEd Maste code = AAC_GET_FWSTATUS(sc); 170004f4d586SEd Maste if (code & AAC_SELF_TEST_FAILED) { 170104f4d586SEd Maste device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 170204f4d586SEd Maste return(ENXIO); 170304f4d586SEd Maste } 170404f4d586SEd Maste if (code & AAC_KERNEL_PANIC) { 170504f4d586SEd Maste device_printf(sc->aac_dev, 1706a620bad0SEd Maste "FATAL: controller kernel panic"); 170704f4d586SEd Maste return(ENXIO); 170804f4d586SEd Maste } 170904f4d586SEd Maste if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 171004f4d586SEd Maste device_printf(sc->aac_dev, 171104f4d586SEd Maste "FATAL: controller not coming ready, " 171204f4d586SEd Maste "status %x\n", code); 171304f4d586SEd Maste return(ENXIO); 171404f4d586SEd Maste } 171504f4d586SEd Maste } while (!(code & AAC_UP_AND_RUNNING)); 1716a6d35632SScott Long 1717fe94b852SScott Long /* 1718fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1719fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1720fe94b852SScott Long */ 1721a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1722fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1723fe94b852SScott Long NULL)) { 1724fe94b852SScott Long device_printf(sc->aac_dev, 1725fe94b852SScott Long "Error reading firmware version\n"); 1726fe94b852SScott Long return (EIO); 1727fe94b852SScott Long } 1728fe94b852SScott Long 1729fe94b852SScott Long /* These numbers are stored as ASCII! */ 1730a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1731a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1732fe94b852SScott Long if (major == 1) { 1733fe94b852SScott Long device_printf(sc->aac_dev, 1734fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1735fe94b852SScott Long major, minor); 1736fe94b852SScott Long return (EINVAL); 1737fe94b852SScott Long } 1738fe94b852SScott Long } 1739fe94b852SScott Long 1740a6d35632SScott Long /* 1741a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1742a441b3fcSScott Long * work-arounds to enable. Some firmware revs don't support this 1743a441b3fcSScott Long * command. 1744a6d35632SScott Long */ 1745a441b3fcSScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1746a441b3fcSScott Long if (status != AAC_SRB_STS_INVALID_REQUEST) { 1747a441b3fcSScott Long device_printf(sc->aac_dev, 1748a441b3fcSScott Long "RequestAdapterInfo failed\n"); 1749a6d35632SScott Long return (EIO); 1750a6d35632SScott Long } 1751a441b3fcSScott Long } else { 1752a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 17537cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1754a6d35632SScott Long sc->supported_options = options; 1755a6d35632SScott Long 1756a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1757a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1758a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1759a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1760a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1761cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1762cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1763a441b3fcSScott Long device_printf(sc->aac_dev, 1764a441b3fcSScott Long "Enabling 64-bit address support\n"); 1765a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1766a6d35632SScott Long } 1767a441b3fcSScott Long if ((options & AAC_SUPPORTED_NEW_COMM) 1768da4882c2SMarius Strobl && sc->aac_if->aif_send_command) 17697cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 17707cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 17717cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1772a441b3fcSScott Long } 1773a6d35632SScott Long 1774a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 17757cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 17767cb209f5SScott Long 17777cb209f5SScott Long /* Remap mem. resource, if required */ 17787cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1779ff0991c4SAttilio Rao atu_size > rman_get_size(sc->aac_regs_res1)) { 1780da4882c2SMarius Strobl rid = rman_get_rid(sc->aac_regs_res1); 1781da4882c2SMarius Strobl bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, rid, 1782da4882c2SMarius Strobl sc->aac_regs_res1); 1783c47476d7SJustin Hibbits sc->aac_regs_res1 = bus_alloc_resource_anywhere(sc->aac_dev, 1784c47476d7SJustin Hibbits SYS_RES_MEMORY, &rid, atu_size, RF_ACTIVE); 1785ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 1786ff0991c4SAttilio Rao sc->aac_regs_res1 = bus_alloc_resource_any( 1787da4882c2SMarius Strobl sc->aac_dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 1788ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 17897cb209f5SScott Long device_printf(sc->aac_dev, 17907cb209f5SScott Long "couldn't allocate register window\n"); 17917cb209f5SScott Long return (ENXIO); 17927cb209f5SScott Long } 17937cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 17947cb209f5SScott Long } 1795ff0991c4SAttilio Rao sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 1796ff0991c4SAttilio Rao sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 1797ff0991c4SAttilio Rao 1798ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK) { 1799ff0991c4SAttilio Rao sc->aac_regs_res0 = sc->aac_regs_res1; 1800ff0991c4SAttilio Rao sc->aac_btag0 = sc->aac_btag1; 1801ff0991c4SAttilio Rao sc->aac_bhandle0 = sc->aac_bhandle1; 1802ff0991c4SAttilio Rao } 18037cb209f5SScott Long } 18047cb209f5SScott Long 18057cb209f5SScott Long /* Read preferred settings */ 18067cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 18077cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 18087cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 1809a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18107e7a458eSEd Maste - sizeof(struct aac_blockwrite64)) 18117e7a458eSEd Maste / sizeof(struct aac_sg_entry64); 1812a6d35632SScott Long else 1813a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18147e7a458eSEd Maste - sizeof(struct aac_blockwrite)) 18157e7a458eSEd Maste / sizeof(struct aac_sg_entry); 1816a441b3fcSScott Long 18177cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 18187cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 18197cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 18207cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 18217cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 18227cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 18237cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 18247cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 18257cb209f5SScott Long } 18267cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 18277cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 18287cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1829a6d35632SScott Long 1830f355c0e0SEd Maste if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1831f355c0e0SEd Maste sc->flags |= AAC_FLAGS_RAW_IO; 1832f355c0e0SEd Maste device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1833f355c0e0SEd Maste } 1834523da39bSEd Maste if ((sc->flags & AAC_FLAGS_RAW_IO) && 1835523da39bSEd Maste (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1836523da39bSEd Maste sc->flags |= AAC_FLAGS_LBA_64BIT; 1837523da39bSEd Maste device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1838523da39bSEd Maste } 1839f355c0e0SEd Maste 1840fe94b852SScott Long return (0); 1841fe94b852SScott Long } 1842fe94b852SScott Long 184335863739SMike Smith static int 184435863739SMike Smith aac_init(struct aac_softc *sc) 184535863739SMike Smith { 184635863739SMike Smith struct aac_adapter_init *ip; 184704f4d586SEd Maste u_int32_t qoffset; 1848a6d35632SScott Long int error; 184935863739SMike Smith 185031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1851ffb37f33SScott Long 185235863739SMike Smith /* 1853914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1854914da7d0SScott Long * physical location of various important shared data structures. 185535863739SMike Smith */ 185635863739SMike Smith ip = &sc->aac_common->ac_init; 185735863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18587cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18597cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18607cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18617cb209f5SScott Long } 1862f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 186335863739SMike Smith 1864c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1865c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1866149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 186735863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 186835863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 186935863739SMike Smith 1870c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1871c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 187235863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 187335863739SMike Smith 18744b00f859SScott Long /* 18754b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18764b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18774b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18784b00f859SScott Long * Round up since the granularity is so high. 18794b00f859SScott Long */ 1880f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18814b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 18824b00f859SScott Long ip->HostPhysMemPages = 18834b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1884204c0befSScott Long } 18852b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 188635863739SMike Smith 18877cb209f5SScott Long ip->InitFlags = 0; 18887cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 1889e71d3b9cSEd Maste ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED; 18907cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 18917cb209f5SScott Long } 18927cb209f5SScott Long 18937cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 18947cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 18957cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 18967cb209f5SScott Long 189735863739SMike Smith /* 18984109ba51SEd Maste * Initialize FIB queues. Note that it appears that the layout of the 1899c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1900c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 190135863739SMike Smith * 190235863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1903914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1904914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1905914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1906914da7d0SScott Long * does. 190735863739SMike Smith * 1908914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1909914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1910914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1911914da7d0SScott Long * virtue of a table. 191235863739SMike Smith */ 1913b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 19140bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 19150bcbebd6SScott Long sc->aac_queues = 19160bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1917b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 191835863739SMike Smith 1919c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1920c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1921c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1922c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1923c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1924c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1925c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1926c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1927c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1928c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1929c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1930c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1931c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1932c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1933c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1934c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1935c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1936c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1937c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1938c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1939c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1940c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1941c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1942c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1943c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1944c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1945c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1946c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1947c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1948c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1949c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1950c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1951c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1952c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1953c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1954c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1955c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1956c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1957c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1958c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1959c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1960c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1961c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1962c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1963c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1964c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1965c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1966c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 196735863739SMike Smith 196835863739SMike Smith /* 196935863739SMike Smith * Do controller-type-specific initialisation 197035863739SMike Smith */ 197135863739SMike Smith switch (sc->aac_hwif) { 197235863739SMike Smith case AAC_HWIF_I960RX: 1973ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); 197435863739SMike Smith break; 19754afedc31SScott Long case AAC_HWIF_RKT: 1976ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); 19774afedc31SScott Long break; 19784afedc31SScott Long default: 19794afedc31SScott Long break; 198035863739SMike Smith } 198135863739SMike Smith 198235863739SMike Smith /* 198335863739SMike Smith * Give the init structure to the controller. 198435863739SMike Smith */ 198535863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1986914da7d0SScott Long sc->aac_common_busaddr + 1987914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1988914da7d0SScott Long NULL)) { 1989914da7d0SScott Long device_printf(sc->aac_dev, 1990914da7d0SScott Long "error establishing init structure\n"); 1991a6d35632SScott Long error = EIO; 1992a6d35632SScott Long goto out; 199335863739SMike Smith } 199435863739SMike Smith 1995a6d35632SScott Long error = 0; 1996a6d35632SScott Long out: 1997a6d35632SScott Long return(error); 199835863739SMike Smith } 199935863739SMike Smith 200004f4d586SEd Maste static int 200104f4d586SEd Maste aac_setup_intr(struct aac_softc *sc) 200204f4d586SEd Maste { 2003da4882c2SMarius Strobl 200404f4d586SEd Maste if (sc->flags & AAC_FLAGS_NEW_COMM) { 200504f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 200604f4d586SEd Maste INTR_MPSAFE|INTR_TYPE_BIO, NULL, 200704f4d586SEd Maste aac_new_intr, sc, &sc->aac_intr)) { 200804f4d586SEd Maste device_printf(sc->aac_dev, "can't set up interrupt\n"); 200904f4d586SEd Maste return (EINVAL); 201004f4d586SEd Maste } 201104f4d586SEd Maste } else { 201204f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2013e46b9eeaSEd Maste INTR_TYPE_BIO, aac_filter, NULL, 201404f4d586SEd Maste sc, &sc->aac_intr)) { 201504f4d586SEd Maste device_printf(sc->aac_dev, 2016e46b9eeaSEd Maste "can't set up interrupt filter\n"); 201704f4d586SEd Maste return (EINVAL); 201804f4d586SEd Maste } 201904f4d586SEd Maste } 202004f4d586SEd Maste return (0); 202104f4d586SEd Maste } 202204f4d586SEd Maste 2023914da7d0SScott Long /* 202435863739SMike Smith * Send a synchronous command to the controller and wait for a result. 20257cb209f5SScott Long * Indicate if the controller completed the command with an error status. 202635863739SMike Smith */ 202735863739SMike Smith static int 202835863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 202935863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 203035863739SMike Smith u_int32_t *sp) 203135863739SMike Smith { 203235863739SMike Smith time_t then; 203335863739SMike Smith u_int32_t status; 203435863739SMike Smith 203531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 203635863739SMike Smith 203735863739SMike Smith /* populate the mailbox */ 203835863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 203935863739SMike Smith 204035863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 204135863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 204235863739SMike Smith 204335863739SMike Smith /* then set it to signal the adapter */ 204435863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 204535863739SMike Smith 204635863739SMike Smith /* spin waiting for the command to complete */ 20472b3b0f17SScott Long then = time_uptime; 204835863739SMike Smith do { 20492b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 205031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 205135863739SMike Smith return(EIO); 205235863739SMike Smith } 205335863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 205435863739SMike Smith 205535863739SMike Smith /* clear the completion flag */ 205635863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 205735863739SMike Smith 205835863739SMike Smith /* get the command status */ 2059a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 206035863739SMike Smith if (sp != NULL) 206135863739SMike Smith *sp = status; 20627cb209f5SScott Long 2063a441b3fcSScott Long if (status != AAC_SRB_STS_SUCCESS) 20647cb209f5SScott Long return (-1); 20650b94a66eSMike Smith return(0); 206635863739SMike Smith } 206735863739SMike Smith 2068cbfd045bSScott Long int 206935863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2070cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 207135863739SMike Smith { 207231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 20737cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 207435863739SMike Smith 207535863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 207635863739SMike Smith return(EINVAL); 207735863739SMike Smith 207835863739SMike Smith /* 207935863739SMike Smith * Set up the sync FIB 208035863739SMike Smith */ 2081914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2082914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2083c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 208435863739SMike Smith fib->Header.XferState |= xferstate; 208535863739SMike Smith fib->Header.Command = command; 208635863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 208742ef13a2SEd Maste fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 208835863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2089b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2090c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2091914da7d0SScott Long offsetof(struct aac_common, 2092914da7d0SScott Long ac_sync_fib); 209335863739SMike Smith 209435863739SMike Smith /* 209535863739SMike Smith * Give the FIB to the controller, wait for a response. 209635863739SMike Smith */ 2097914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2098914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 209931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 210035863739SMike Smith return(EIO); 210135863739SMike Smith } 210235863739SMike Smith 210335863739SMike Smith return (0); 210435863739SMike Smith } 210535863739SMike Smith 2106914da7d0SScott Long /* 210735863739SMike Smith * Adapter-space FIB queue manipulation 210835863739SMike Smith * 210935863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 211035863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 211135863739SMike Smith */ 2112da4882c2SMarius Strobl static const struct { 211335863739SMike Smith int size; 211435863739SMike Smith int notify; 211535863739SMike Smith } aac_qinfo[] = { 211635863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 211735863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 211835863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 211935863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 212035863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 212135863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 212235863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 212335863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 212435863739SMike Smith }; 212535863739SMike Smith 212635863739SMike Smith /* 2127c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2128c6eafcf2SScott Long * EBUSY if the queue is full. 212935863739SMike Smith * 21300b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2131914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2132914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2133c6eafcf2SScott Long * separate queue/notify interface). 213435863739SMike Smith */ 213535863739SMike Smith static int 2136f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 213735863739SMike Smith { 213835863739SMike Smith u_int32_t pi, ci; 21399e2e96d8SScott Long int error; 2140f6c4dd3fSScott Long u_int32_t fib_size; 2141f6c4dd3fSScott Long u_int32_t fib_addr; 2142f6c4dd3fSScott Long 214331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 214436e0bf6eSScott Long 2145f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2146f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 214735863739SMike Smith 214835863739SMike Smith /* get the producer/consumer indices */ 214935863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215035863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215135863739SMike Smith 215235863739SMike Smith /* wrap the queue? */ 215335863739SMike Smith if (pi >= aac_qinfo[queue].size) 215435863739SMike Smith pi = 0; 215535863739SMike Smith 215635863739SMike Smith /* check for queue full */ 215735863739SMike Smith if ((pi + 1) == ci) { 215835863739SMike Smith error = EBUSY; 215935863739SMike Smith goto out; 216035863739SMike Smith } 216135863739SMike Smith 2162614c22b2SScott Long /* 2163614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2164614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2165614c22b2SScott Long */ 2166614c22b2SScott Long aac_enqueue_busy(cm); 2167614c22b2SScott Long 216835863739SMike Smith /* populate queue entry */ 216935863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 217035863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 217135863739SMike Smith 217235863739SMike Smith /* update producer index */ 217335863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 217435863739SMike Smith 217535863739SMike Smith /* notify the adapter if we know how */ 217635863739SMike Smith if (aac_qinfo[queue].notify != 0) 217735863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 217835863739SMike Smith 217935863739SMike Smith error = 0; 218035863739SMike Smith 218135863739SMike Smith out: 218235863739SMike Smith return(error); 218335863739SMike Smith } 218435863739SMike Smith 218535863739SMike Smith /* 218636e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 218736e0bf6eSScott Long * success or ENOENT if the queue is empty. 218835863739SMike Smith */ 218935863739SMike Smith static int 2190c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2191c6eafcf2SScott Long struct aac_fib **fib_addr) 219235863739SMike Smith { 219335863739SMike Smith u_int32_t pi, ci; 2194149af931SScott Long u_int32_t fib_index; 21959e2e96d8SScott Long int error; 2196f6c4dd3fSScott Long int notify; 219735863739SMike Smith 219831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 219935863739SMike Smith 220035863739SMike Smith /* get the producer/consumer indices */ 220135863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 220235863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 220335863739SMike Smith 220435863739SMike Smith /* check for queue empty */ 220535863739SMike Smith if (ci == pi) { 220635863739SMike Smith error = ENOENT; 220735863739SMike Smith goto out; 220835863739SMike Smith } 220935863739SMike Smith 22107753acd2SScott Long /* wrap the pi so the following test works */ 22117753acd2SScott Long if (pi >= aac_qinfo[queue].size) 22127753acd2SScott Long pi = 0; 22137753acd2SScott Long 2214f6c4dd3fSScott Long notify = 0; 2215f6c4dd3fSScott Long if (ci == pi + 1) 2216f6c4dd3fSScott Long notify++; 2217f6c4dd3fSScott Long 221835863739SMike Smith /* wrap the queue? */ 221935863739SMike Smith if (ci >= aac_qinfo[queue].size) 222035863739SMike Smith ci = 0; 222135863739SMike Smith 222235863739SMike Smith /* fetch the entry */ 222335863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2224149af931SScott Long 2225149af931SScott Long switch (queue) { 2226149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2227149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2228149af931SScott Long /* 2229149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2230149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2231149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2232149af931SScott Long * Therefore, we have to convert it to an index. 2233149af931SScott Long */ 2234149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2235149af931SScott Long sizeof(struct aac_fib); 2236149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2237149af931SScott Long break; 2238149af931SScott Long 2239149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2240149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2241149af931SScott Long { 2242149af931SScott Long struct aac_command *cm; 2243149af931SScott Long 2244149af931SScott Long /* 2245149af931SScott Long * As above, an index is used instead of an actual address. 2246149af931SScott Long * Gotta shift the index to account for the fast response 2247149af931SScott Long * bit. No other correction is needed since this value was 2248149af931SScott Long * originally provided by the driver via the SenderFibAddress 2249149af931SScott Long * field. 2250149af931SScott Long */ 2251149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 22527cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2253149af931SScott Long *fib_addr = cm->cm_fib; 225435863739SMike Smith 2255f30ac74cSScott Long /* 2256f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2257149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2258f30ac74cSScott Long */ 2259149af931SScott Long if (fib_index & 0x01) { 2260f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2261f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2262f30ac74cSScott Long } 2263149af931SScott Long break; 2264149af931SScott Long } 2265149af931SScott Long default: 2266149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2267149af931SScott Long break; 2268149af931SScott Long } 2269149af931SScott Long 227035863739SMike Smith /* update consumer index */ 227135863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 227235863739SMike Smith 227335863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2274f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 227535863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227635863739SMike Smith error = 0; 227735863739SMike Smith 227835863739SMike Smith out: 227935863739SMike Smith return(error); 228035863739SMike Smith } 228135863739SMike Smith 2282914da7d0SScott Long /* 228336e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 228436e0bf6eSScott Long */ 228536e0bf6eSScott Long static int 228636e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 228736e0bf6eSScott Long { 228836e0bf6eSScott Long u_int32_t pi, ci; 22899e2e96d8SScott Long int error; 229036e0bf6eSScott Long u_int32_t fib_size; 229136e0bf6eSScott Long u_int32_t fib_addr; 229236e0bf6eSScott Long 229331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 229436e0bf6eSScott Long 229536e0bf6eSScott Long /* Tell the adapter where the FIB is */ 229636e0bf6eSScott Long fib_size = fib->Header.Size; 229736e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 229836e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 229936e0bf6eSScott Long 230036e0bf6eSScott Long /* get the producer/consumer indices */ 230136e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 230236e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 230336e0bf6eSScott Long 230436e0bf6eSScott Long /* wrap the queue? */ 230536e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 230636e0bf6eSScott Long pi = 0; 230736e0bf6eSScott Long 230836e0bf6eSScott Long /* check for queue full */ 230936e0bf6eSScott Long if ((pi + 1) == ci) { 231036e0bf6eSScott Long error = EBUSY; 231136e0bf6eSScott Long goto out; 231236e0bf6eSScott Long } 231336e0bf6eSScott Long 231436e0bf6eSScott Long /* populate queue entry */ 231536e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 231636e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 231736e0bf6eSScott Long 231836e0bf6eSScott Long /* update producer index */ 231936e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 232036e0bf6eSScott Long 232136e0bf6eSScott Long /* notify the adapter if we know how */ 232236e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 232336e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 232436e0bf6eSScott Long 232536e0bf6eSScott Long error = 0; 232636e0bf6eSScott Long 232736e0bf6eSScott Long out: 232836e0bf6eSScott Long return(error); 232936e0bf6eSScott Long } 233036e0bf6eSScott Long 2331914da7d0SScott Long /* 23320b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 23330b94a66eSMike Smith * and complain about them. 23340b94a66eSMike Smith */ 23350b94a66eSMike Smith static void 23360b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 23370b94a66eSMike Smith { 23380b94a66eSMike Smith struct aac_command *cm; 23390b94a66eSMike Smith time_t deadline; 234015c37be0SScott Long int timedout, code; 23410b94a66eSMike Smith 2342f6c4dd3fSScott Long /* 234370545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2344914da7d0SScott Long * only. 2345914da7d0SScott Long */ 234615c37be0SScott Long timedout = 0; 23472b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 23480b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2349f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 23503e507710SEd Maste && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { 23510b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2352914da7d0SScott Long device_printf(sc->aac_dev, 23535aa4bb5bSEd Maste "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n", 23545aa4bb5bSEd Maste cm, cm->cm_fib->Header.Command, 23555aa4bb5bSEd Maste (int)(time_uptime-cm->cm_timestamp)); 23560b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 235715c37be0SScott Long timedout++; 23580b94a66eSMike Smith } 23590b94a66eSMike Smith } 23600b94a66eSMike Smith 236115c37be0SScott Long if (timedout) { 236215c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 236315c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 236415c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 236515c37be0SScott Long "longer running! code= 0x%x\n", code); 236615c37be0SScott Long } 236715c37be0SScott Long } 23680b94a66eSMike Smith } 23690b94a66eSMike Smith 2370914da7d0SScott Long /* 2371914da7d0SScott Long * Interface Function Vectors 2372914da7d0SScott Long */ 237335863739SMike Smith 2374914da7d0SScott Long /* 237535863739SMike Smith * Read the current firmware status word. 237635863739SMike Smith */ 237735863739SMike Smith static int 237835863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 237935863739SMike Smith { 238031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 238135863739SMike Smith 2382ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); 238335863739SMike Smith } 238435863739SMike Smith 238535863739SMike Smith static int 238635863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 238735863739SMike Smith { 238831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 238935863739SMike Smith 23904824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 23914824be88SEd Maste AAC_RX_OMR0 : AAC_RX_FWSTATUS)); 239235863739SMike Smith } 239335863739SMike Smith 2394b3457b51SScott Long static int 23954afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 23964afedc31SScott Long { 239731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 23984afedc31SScott Long 23994824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 24004824be88SEd Maste AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); 24014afedc31SScott Long } 24024afedc31SScott Long 2403914da7d0SScott Long /* 240435863739SMike Smith * Notify the controller of a change in a given queue 240535863739SMike Smith */ 240635863739SMike Smith 240735863739SMike Smith static void 240835863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 240935863739SMike Smith { 241031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241135863739SMike Smith 2412ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 241335863739SMike Smith } 241435863739SMike Smith 241535863739SMike Smith static void 241635863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 241735863739SMike Smith { 241831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241935863739SMike Smith 2420ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); 242135863739SMike Smith } 242235863739SMike Smith 2423b3457b51SScott Long static void 24244afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 24254afedc31SScott Long { 242631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24274afedc31SScott Long 2428ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); 24294afedc31SScott Long } 24304afedc31SScott Long 2431914da7d0SScott Long /* 243235863739SMike Smith * Get the interrupt reason bits 243335863739SMike Smith */ 243435863739SMike Smith static int 243535863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 243635863739SMike Smith { 243731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 243835863739SMike Smith 2439ff0991c4SAttilio Rao return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); 244035863739SMike Smith } 244135863739SMike Smith 244235863739SMike Smith static int 244335863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 244435863739SMike Smith { 244531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244635863739SMike Smith 2447ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); 244835863739SMike Smith } 244935863739SMike Smith 2450b3457b51SScott Long static int 24514afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 24524afedc31SScott Long { 245331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24544afedc31SScott Long 2455ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); 24564afedc31SScott Long } 24574afedc31SScott Long 2458914da7d0SScott Long /* 245935863739SMike Smith * Clear some interrupt reason bits 246035863739SMike Smith */ 246135863739SMike Smith static void 246235863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 246335863739SMike Smith { 246431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 246535863739SMike Smith 2466ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 246735863739SMike Smith } 246835863739SMike Smith 246935863739SMike Smith static void 247035863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 247135863739SMike Smith { 247231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 247335863739SMike Smith 2474ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); 247535863739SMike Smith } 247635863739SMike Smith 2477b3457b51SScott Long static void 24784afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 24794afedc31SScott Long { 248031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24814afedc31SScott Long 2482ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); 24834afedc31SScott Long } 24844afedc31SScott Long 2485914da7d0SScott Long /* 248635863739SMike Smith * Populate the mailbox and set the command word 248735863739SMike Smith */ 248835863739SMike Smith static void 248935863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 249035863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249135863739SMike Smith { 249231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 249335863739SMike Smith 2494ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); 2495ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2496ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2497ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2498ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 249935863739SMike Smith } 250035863739SMike Smith 250135863739SMike Smith static void 250235863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 250335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 250435863739SMike Smith { 250531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 250635863739SMike Smith 2507ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); 2508ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2509ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2510ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2511ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 251235863739SMike Smith } 251335863739SMike Smith 2514b3457b51SScott Long static void 25154afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25164afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 25174afedc31SScott Long { 251831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25194afedc31SScott Long 2520ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); 2521ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2522ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2523ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2524ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 25254afedc31SScott Long } 25264afedc31SScott Long 2527914da7d0SScott Long /* 252835863739SMike Smith * Fetch the immediate command status word 252935863739SMike Smith */ 253035863739SMike Smith static int 2531a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 253235863739SMike Smith { 253331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 253435863739SMike Smith 2535ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 253635863739SMike Smith } 253735863739SMike Smith 253835863739SMike Smith static int 2539a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 254035863739SMike Smith { 254131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 254235863739SMike Smith 2543ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 254435863739SMike Smith } 254535863739SMike Smith 2546b3457b51SScott Long static int 25474afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 25484afedc31SScott Long { 254931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25504afedc31SScott Long 2551ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 25524afedc31SScott Long } 25534afedc31SScott Long 2554914da7d0SScott Long /* 255535863739SMike Smith * Set/clear interrupt masks 255635863739SMike Smith */ 255735863739SMike Smith static void 255835863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 255935863739SMike Smith { 256031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 256135863739SMike Smith 256235863739SMike Smith if (enable) { 2563ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 256435863739SMike Smith } else { 2565ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 256635863739SMike Smith } 256735863739SMike Smith } 256835863739SMike Smith 256935863739SMike Smith static void 257035863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 257135863739SMike Smith { 257231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 257335863739SMike Smith 257435863739SMike Smith if (enable) { 25757cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2576ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 25777cb209f5SScott Long else 2578ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 257935863739SMike Smith } else { 2580ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); 258135863739SMike Smith } 258235863739SMike Smith } 258335863739SMike Smith 2584b3457b51SScott Long static void 25854afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 25864afedc31SScott Long { 258731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 25884afedc31SScott Long 25894afedc31SScott Long if (enable) { 25907cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2591ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 25927cb209f5SScott Long else 2593ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 25944afedc31SScott Long } else { 2595ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); 25964afedc31SScott Long } 25974afedc31SScott Long } 25984afedc31SScott Long 2599914da7d0SScott Long /* 26007cb209f5SScott Long * New comm. interface: Send command functions 26017cb209f5SScott Long */ 26027cb209f5SScott Long static int 26037cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 26047cb209f5SScott Long { 26057cb209f5SScott Long u_int32_t index, device; 26067cb209f5SScott Long 260731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 26087cb209f5SScott Long 2609ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 26107cb209f5SScott Long if (index == 0xffffffffL) 2611ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 26127cb209f5SScott Long if (index == 0xffffffffL) 26137cb209f5SScott Long return index; 26147cb209f5SScott Long aac_enqueue_busy(cm); 26157cb209f5SScott Long device = index; 2616ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26177cb209f5SScott Long device += 4; 2618ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26197cb209f5SScott Long device += 4; 2620ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2621ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); 26227cb209f5SScott Long return 0; 26237cb209f5SScott Long } 26247cb209f5SScott Long 26257cb209f5SScott Long static int 26267cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 26277cb209f5SScott Long { 26287cb209f5SScott Long u_int32_t index, device; 26297cb209f5SScott Long 263031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 26317cb209f5SScott Long 2632ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 26337cb209f5SScott Long if (index == 0xffffffffL) 2634ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 26357cb209f5SScott Long if (index == 0xffffffffL) 26367cb209f5SScott Long return index; 26377cb209f5SScott Long aac_enqueue_busy(cm); 26387cb209f5SScott Long device = index; 2639ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26407cb209f5SScott Long device += 4; 2641ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26427cb209f5SScott Long device += 4; 2643ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2644ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); 26457cb209f5SScott Long return 0; 26467cb209f5SScott Long } 26477cb209f5SScott Long 26487cb209f5SScott Long /* 26497cb209f5SScott Long * New comm. interface: get, set outbound queue index 26507cb209f5SScott Long */ 26517cb209f5SScott Long static int 26527cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 26537cb209f5SScott Long { 265431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26557cb209f5SScott Long 2656ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); 26577cb209f5SScott Long } 26587cb209f5SScott Long 26597cb209f5SScott Long static int 26607cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 26617cb209f5SScott Long { 266231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26637cb209f5SScott Long 2664ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); 26657cb209f5SScott Long } 26667cb209f5SScott Long 26677cb209f5SScott Long static void 26687cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 26697cb209f5SScott Long { 267031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26717cb209f5SScott Long 2672ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); 26737cb209f5SScott Long } 26747cb209f5SScott Long 26757cb209f5SScott Long static void 26767cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 26777cb209f5SScott Long { 267831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26797cb209f5SScott Long 2680ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); 26817cb209f5SScott Long } 26827cb209f5SScott Long 26837cb209f5SScott Long /* 2684914da7d0SScott Long * Debugging and Diagnostics 2685914da7d0SScott Long */ 268635863739SMike Smith 2687914da7d0SScott Long /* 268835863739SMike Smith * Print some information about the controller. 268935863739SMike Smith */ 269035863739SMike Smith static void 269135863739SMike Smith aac_describe_controller(struct aac_softc *sc) 269235863739SMike Smith { 2693cbfd045bSScott Long struct aac_fib *fib; 269435863739SMike Smith struct aac_adapter_info *info; 26957ea2d558SEd Maste char *adapter_type = "Adaptec RAID controller"; 269635863739SMike Smith 269731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 269835863739SMike Smith 269981b3da08SScott Long mtx_lock(&sc->aac_io_lock); 270003b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2701cbfd045bSScott Long 2702cbfd045bSScott Long fib->data[0] = 0; 2703cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 270435863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2705fe3cb0e1SScott Long aac_release_sync_fib(sc); 270681b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 270735863739SMike Smith return; 270835863739SMike Smith } 270935863739SMike Smith 2710bd971c49SScott Long /* save the kernel revision structure for later use */ 2711bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2712bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2713bd971c49SScott Long 2714bd971c49SScott Long if (bootverbose) { 2715b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2716b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2717c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2718b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2719b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2720b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2721914da7d0SScott Long aac_describe_code(aac_battery_platform, 2722914da7d0SScott Long info->batteryPlatform)); 272335863739SMike Smith 2724bd971c49SScott Long device_printf(sc->aac_dev, 2725bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 272635863739SMike Smith info->KernelRevision.external.comp.major, 272735863739SMike Smith info->KernelRevision.external.comp.minor, 272835863739SMike Smith info->KernelRevision.external.comp.dash, 272936e0bf6eSScott Long info->KernelRevision.buildNumber, 273036e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2731fe3cb0e1SScott Long 2732a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2733a6d35632SScott Long sc->supported_options, 2734a6d35632SScott Long "\20" 2735a6d35632SScott Long "\1SNAPSHOT" 2736a6d35632SScott Long "\2CLUSTERS" 2737a6d35632SScott Long "\3WCACHE" 2738a6d35632SScott Long "\4DATA64" 2739a6d35632SScott Long "\5HOSTTIME" 2740a6d35632SScott Long "\6RAID50" 2741a6d35632SScott Long "\7WINDOW4GB" 2742a6d35632SScott Long "\10SCSIUPGD" 2743a6d35632SScott Long "\11SOFTERR" 2744a6d35632SScott Long "\12NORECOND" 2745a6d35632SScott Long "\13SGMAP64" 2746a6d35632SScott Long "\14ALARM" 27477cb209f5SScott Long "\15NONDASD" 27487cb209f5SScott Long "\16SCSIMGT" 27497cb209f5SScott Long "\17RAIDSCSI" 27507cb209f5SScott Long "\21ADPTINFO" 27517cb209f5SScott Long "\22NEWCOMM" 27527cb209f5SScott Long "\23ARRAY64BIT" 27537cb209f5SScott Long "\24HEATSENSOR"); 2754a6d35632SScott Long } 275555aa1136SEd Maste 275655aa1136SEd Maste if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 275755aa1136SEd Maste fib->data[0] = 0; 275855aa1136SEd Maste if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 275955aa1136SEd Maste device_printf(sc->aac_dev, 276055aa1136SEd Maste "RequestSupplementAdapterInfo failed\n"); 276155aa1136SEd Maste else 276255aa1136SEd Maste adapter_type = ((struct aac_supplement_adapter_info *) 276355aa1136SEd Maste &fib->data[0])->AdapterTypeText; 276455aa1136SEd Maste } 276555aa1136SEd Maste device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 276655aa1136SEd Maste adapter_type, 27678e7e6335SEd Maste AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 27688e7e6335SEd Maste AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 276955aa1136SEd Maste 2770bd971c49SScott Long aac_release_sync_fib(sc); 277181b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 277235863739SMike Smith } 277335863739SMike Smith 2774914da7d0SScott Long /* 277535863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 277635863739SMike Smith * same. 277735863739SMike Smith */ 2778da4882c2SMarius Strobl static const char * 2779da4882c2SMarius Strobl aac_describe_code(const struct aac_code_lookup *table, u_int32_t code) 278035863739SMike Smith { 278135863739SMike Smith int i; 278235863739SMike Smith 278335863739SMike Smith for (i = 0; table[i].string != NULL; i++) 278435863739SMike Smith if (table[i].code == code) 278535863739SMike Smith return(table[i].string); 278635863739SMike Smith return(table[i + 1].string); 278735863739SMike Smith } 278835863739SMike Smith 2789914da7d0SScott Long /* 2790914da7d0SScott Long * Management Interface 2791914da7d0SScott Long */ 279235863739SMike Smith 279335863739SMike Smith static int 279400b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 279535863739SMike Smith { 2796914da7d0SScott Long struct aac_softc *sc; 279735863739SMike Smith 2798914da7d0SScott Long sc = dev->si_drv1; 279931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 280004f798ecSAttilio Rao device_busy(sc->aac_dev); 2801dfe2c294SAttilio Rao devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); 280235863739SMike Smith 280335863739SMike Smith return 0; 280435863739SMike Smith } 280535863739SMike Smith 280635863739SMike Smith static int 280700b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 280835863739SMike Smith { 2809914da7d0SScott Long union aac_statrequest *as; 2810914da7d0SScott Long struct aac_softc *sc; 28110b94a66eSMike Smith int error = 0; 281235863739SMike Smith 2813914da7d0SScott Long as = (union aac_statrequest *)arg; 2814914da7d0SScott Long sc = dev->si_drv1; 281531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2816914da7d0SScott Long 281735863739SMike Smith switch (cmd) { 28180b94a66eSMike Smith case AACIO_STATS: 28190b94a66eSMike Smith switch (as->as_item) { 28200b94a66eSMike Smith case AACQ_FREE: 28210b94a66eSMike Smith case AACQ_BIO: 28220b94a66eSMike Smith case AACQ_READY: 28230b94a66eSMike Smith case AACQ_BUSY: 2824c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2825c6eafcf2SScott Long sizeof(struct aac_qstat)); 28260b94a66eSMike Smith break; 28270b94a66eSMike Smith default: 28280b94a66eSMike Smith error = ENOENT; 28290b94a66eSMike Smith break; 28300b94a66eSMike Smith } 28310b94a66eSMike Smith break; 28320b94a66eSMike Smith 283335863739SMike Smith case FSACTL_SENDFIB: 2834f355c0e0SEd Maste case FSACTL_SEND_LARGE_FIB: 2835fb0c27d7SScott Long arg = *(caddr_t*)arg; 2836fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 2837f355c0e0SEd Maste case FSACTL_LNX_SEND_LARGE_FIB: 283831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 283935863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 284035863739SMike Smith break; 2841f355c0e0SEd Maste case FSACTL_SEND_RAW_SRB: 2842f355c0e0SEd Maste arg = *(caddr_t*)arg; 2843f355c0e0SEd Maste case FSACTL_LNX_SEND_RAW_SRB: 284431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2845f355c0e0SEd Maste error = aac_ioctl_send_raw_srb(sc, arg); 2846f355c0e0SEd Maste break; 284735863739SMike Smith case FSACTL_AIF_THREAD: 2848fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 284931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 285035863739SMike Smith error = EINVAL; 285135863739SMike Smith break; 285235863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2853fb0c27d7SScott Long arg = *(caddr_t*)arg; 2854fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 285531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2856a723a548SEd Maste error = aac_open_aif(sc, arg); 285735863739SMike Smith break; 285835863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2859fb0c27d7SScott Long arg = *(caddr_t*)arg; 2860fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 286131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2862fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 286335863739SMike Smith break; 286435863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2865a723a548SEd Maste arg = *(caddr_t*)arg; 2866fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 286731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2868a723a548SEd Maste error = aac_close_aif(sc, arg); 286935863739SMike Smith break; 287035863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2871fb0c27d7SScott Long arg = *(caddr_t*)arg; 2872fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 287331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2874fb0c27d7SScott Long error = aac_rev_check(sc, arg); 287535863739SMike Smith break; 287636e0bf6eSScott Long case FSACTL_QUERY_DISK: 287736e0bf6eSScott Long arg = *(caddr_t*)arg; 287836e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 287931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 288036e0bf6eSScott Long error = aac_query_disk(sc, arg); 288136e0bf6eSScott Long break; 288236e0bf6eSScott Long case FSACTL_DELETE_DISK: 288336e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2884914da7d0SScott Long /* 2885914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2886914da7d0SScott Long * container, rather we rely on an AIF coming from the 2887914da7d0SScott Long * controller 2888914da7d0SScott Long */ 288936e0bf6eSScott Long error = 0; 289036e0bf6eSScott Long break; 28917cb209f5SScott Long case FSACTL_GET_PCI_INFO: 28927cb209f5SScott Long arg = *(caddr_t*)arg; 28937cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 289431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 28957cb209f5SScott Long error = aac_get_pci_info(sc, arg); 28967cb209f5SScott Long break; 28976d307336SEd Maste case FSACTL_GET_FEATURES: 28986d307336SEd Maste arg = *(caddr_t*)arg; 28996d307336SEd Maste case FSACTL_LNX_GET_FEATURES: 29006d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 29016d307336SEd Maste error = aac_supported_features(sc, arg); 29026d307336SEd Maste break; 290335863739SMike Smith default: 290431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 290535863739SMike Smith error = EINVAL; 290635863739SMike Smith break; 290735863739SMike Smith } 290835863739SMike Smith return(error); 290935863739SMike Smith } 291035863739SMike Smith 2911b3457b51SScott Long static int 291200b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td) 2913b3457b51SScott Long { 2914b3457b51SScott Long struct aac_softc *sc; 2915ef0b687cSEd Maste struct aac_fib_context *ctx; 2916b3457b51SScott Long int revents; 2917b3457b51SScott Long 2918b3457b51SScott Long sc = dev->si_drv1; 2919b3457b51SScott Long revents = 0; 2920b3457b51SScott Long 2921bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2922b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2923ef0b687cSEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2924ef0b687cSEd Maste if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2925b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2926ef0b687cSEd Maste break; 2927ef0b687cSEd Maste } 2928ef0b687cSEd Maste } 2929b3457b51SScott Long } 2930bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2931b3457b51SScott Long 2932b3457b51SScott Long if (revents == 0) { 2933b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2934b3457b51SScott Long selrecord(td, &sc->rcv_select); 2935b3457b51SScott Long } 2936b3457b51SScott Long 2937b3457b51SScott Long return (revents); 2938b3457b51SScott Long } 2939b3457b51SScott Long 29407cb209f5SScott Long static void 29417cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 29427cb209f5SScott Long { 29437cb209f5SScott Long 29447cb209f5SScott Long switch (event->ev_type) { 29457cb209f5SScott Long case AAC_EVENT_CMFREE: 29460c40d5beSEd Maste mtx_assert(&sc->aac_io_lock, MA_OWNED); 29471a681311SLuoqi Chen if (aac_alloc_command(sc, (struct aac_command **)arg)) { 29487cb209f5SScott Long aac_add_event(sc, event); 29497cb209f5SScott Long return; 29507cb209f5SScott Long } 29517cb209f5SScott Long free(event, M_AACBUF); 29528eeb2ca6SScott Long wakeup(arg); 29537cb209f5SScott Long break; 29547cb209f5SScott Long default: 29557cb209f5SScott Long break; 29567cb209f5SScott Long } 29577cb209f5SScott Long } 29587cb209f5SScott Long 2959914da7d0SScott Long /* 296035863739SMike Smith * Send a FIB supplied from userspace 296135863739SMike Smith */ 296235863739SMike Smith static int 296335863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 296435863739SMike Smith { 296535863739SMike Smith struct aac_command *cm; 296635863739SMike Smith int size, error; 296735863739SMike Smith 296831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 296935863739SMike Smith 297035863739SMike Smith cm = NULL; 297135863739SMike Smith 297235863739SMike Smith /* 297335863739SMike Smith * Get a command 297435863739SMike Smith */ 2975bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 297635863739SMike Smith if (aac_alloc_command(sc, &cm)) { 29777cb209f5SScott Long struct aac_event *event; 29787cb209f5SScott Long 29797cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 29807cb209f5SScott Long M_NOWAIT | M_ZERO); 29817cb209f5SScott Long if (event == NULL) { 298235863739SMike Smith error = EBUSY; 2983f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 298435863739SMike Smith goto out; 298535863739SMike Smith } 29867cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 29877cb209f5SScott Long event->ev_callback = aac_ioctl_event; 29887cb209f5SScott Long event->ev_arg = &cm; 29897cb209f5SScott Long aac_add_event(sc, event); 29908eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 29917cb209f5SScott Long } 299293cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 299335863739SMike Smith 299435863739SMike Smith /* 299535863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 299635863739SMike Smith */ 2997914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 2998914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 299935863739SMike Smith goto out; 300035863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 3001f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3002f355c0e0SEd Maste device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 3003f355c0e0SEd Maste size, sc->aac_max_fib_size); 3004f355c0e0SEd Maste size = sc->aac_max_fib_size; 300535863739SMike Smith } 300635863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 300735863739SMike Smith goto out; 300835863739SMike Smith cm->cm_fib->Header.Size = size; 30092b3b0f17SScott Long cm->cm_timestamp = time_uptime; 301035863739SMike Smith 301135863739SMike Smith /* 301235863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 301335863739SMike Smith */ 301493cfca22SScott Long mtx_lock(&sc->aac_io_lock); 3015f16627aaSEd Maste error = aac_wait_command(cm); 3016f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 3017f16627aaSEd Maste if (error != 0) { 301870545d1aSScott Long device_printf(sc->aac_dev, 301970545d1aSScott Long "aac_wait_command return %d\n", error); 302035863739SMike Smith goto out; 3021b3457b51SScott Long } 302235863739SMike Smith 302335863739SMike Smith /* 302435863739SMike Smith * Copy the FIB and data back out to the caller. 302535863739SMike Smith */ 302635863739SMike Smith size = cm->cm_fib->Header.Size; 3027f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3028f355c0e0SEd Maste device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 3029f355c0e0SEd Maste size, sc->aac_max_fib_size); 3030f355c0e0SEd Maste size = sc->aac_max_fib_size; 303135863739SMike Smith } 303235863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 303335863739SMike Smith 303435863739SMike Smith out: 3035f6c4dd3fSScott Long if (cm != NULL) { 3036f16627aaSEd Maste mtx_lock(&sc->aac_io_lock); 303735863739SMike Smith aac_release_command(cm); 3038bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 3039f16627aaSEd Maste } 304035863739SMike Smith return(error); 304135863739SMike Smith } 304235863739SMike Smith 3043914da7d0SScott Long /* 3044f355c0e0SEd Maste * Send a passthrough FIB supplied from userspace 3045f355c0e0SEd Maste */ 3046f355c0e0SEd Maste static int 3047f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 3048f355c0e0SEd Maste { 30497b90e5ecSAttilio Rao struct aac_command *cm; 30507b90e5ecSAttilio Rao struct aac_event *event; 30517b90e5ecSAttilio Rao struct aac_fib *fib; 30527b90e5ecSAttilio Rao struct aac_srb *srbcmd, *user_srb; 30537b90e5ecSAttilio Rao struct aac_sg_entry *sge; 30547b90e5ecSAttilio Rao void *srb_sg_address, *ureply; 30557b90e5ecSAttilio Rao uint32_t fibsize, srb_sg_bytecount; 30567b90e5ecSAttilio Rao int error, transfer_data; 30577b90e5ecSAttilio Rao 30587b90e5ecSAttilio Rao fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 30597b90e5ecSAttilio Rao 30607b90e5ecSAttilio Rao cm = NULL; 30617b90e5ecSAttilio Rao transfer_data = 0; 30627b90e5ecSAttilio Rao fibsize = 0; 30637b90e5ecSAttilio Rao user_srb = (struct aac_srb *)arg; 30647b90e5ecSAttilio Rao 30657b90e5ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 30667b90e5ecSAttilio Rao if (aac_alloc_command(sc, &cm)) { 30677b90e5ecSAttilio Rao event = malloc(sizeof(struct aac_event), M_AACBUF, 30687b90e5ecSAttilio Rao M_NOWAIT | M_ZERO); 30697b90e5ecSAttilio Rao if (event == NULL) { 30707b90e5ecSAttilio Rao error = EBUSY; 30717b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 30727b90e5ecSAttilio Rao goto out; 30737b90e5ecSAttilio Rao } 30747b90e5ecSAttilio Rao event->ev_type = AAC_EVENT_CMFREE; 30757b90e5ecSAttilio Rao event->ev_callback = aac_ioctl_event; 30767b90e5ecSAttilio Rao event->ev_arg = &cm; 30777b90e5ecSAttilio Rao aac_add_event(sc, event); 30787b90e5ecSAttilio Rao msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0); 30797b90e5ecSAttilio Rao } 30807b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 30817b90e5ecSAttilio Rao 30827b90e5ecSAttilio Rao cm->cm_data = NULL; 30837b90e5ecSAttilio Rao fib = cm->cm_fib; 30847b90e5ecSAttilio Rao srbcmd = (struct aac_srb *)fib->data; 30857b90e5ecSAttilio Rao error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t)); 30867b90e5ecSAttilio Rao if (error != 0) 30877b90e5ecSAttilio Rao goto out; 30887b90e5ecSAttilio Rao if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) { 30897b90e5ecSAttilio Rao error = EINVAL; 30907b90e5ecSAttilio Rao goto out; 30917b90e5ecSAttilio Rao } 30927b90e5ecSAttilio Rao error = copyin(user_srb, srbcmd, fibsize); 30937b90e5ecSAttilio Rao if (error != 0) 30947b90e5ecSAttilio Rao goto out; 30957b90e5ecSAttilio Rao srbcmd->function = 0; 30967b90e5ecSAttilio Rao srbcmd->retry_limit = 0; 30977b90e5ecSAttilio Rao if (srbcmd->sg_map.SgCount > 1) { 30987b90e5ecSAttilio Rao error = EINVAL; 30997b90e5ecSAttilio Rao goto out; 31007b90e5ecSAttilio Rao } 31017b90e5ecSAttilio Rao 31027b90e5ecSAttilio Rao /* Retrieve correct SG entries. */ 31037b90e5ecSAttilio Rao if (fibsize == (sizeof(struct aac_srb) + 31047b90e5ecSAttilio Rao srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { 3105f4a18258SSean Bruno struct aac_sg_entry sg; 3106f4a18258SSean Bruno 31077b90e5ecSAttilio Rao sge = srbcmd->sg_map.SgEntry; 3108f4a18258SSean Bruno 3109f4a18258SSean Bruno if ((error = copyin(sge, &sg, sizeof(sg))) != 0) 3110f4a18258SSean Bruno goto out; 3111f4a18258SSean Bruno 3112f4a18258SSean Bruno srb_sg_bytecount = sg.SgByteCount; 3113f4a18258SSean Bruno srb_sg_address = (void *)(uintptr_t)sg.SgAddress; 31147b90e5ecSAttilio Rao } 31157b90e5ecSAttilio Rao #ifdef __amd64__ 31167b90e5ecSAttilio Rao else if (fibsize == (sizeof(struct aac_srb) + 31177b90e5ecSAttilio Rao srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { 31185cd9d254SJohn Baldwin struct aac_sg_entry64 *sge64; 3119f4a18258SSean Bruno struct aac_sg_entry64 sg; 3120f4a18258SSean Bruno 31217b90e5ecSAttilio Rao sge = NULL; 31227b90e5ecSAttilio Rao sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; 3123f4a18258SSean Bruno 3124f4a18258SSean Bruno if ((error = copyin(sge64, &sg, sizeof(sg))) != 0) 3125f4a18258SSean Bruno goto out; 3126f4a18258SSean Bruno 3127f4a18258SSean Bruno srb_sg_bytecount = sg.SgByteCount; 3128f4a18258SSean Bruno srb_sg_address = (void *)sg.SgAddress; 31297b90e5ecSAttilio Rao if (sge64->SgAddress > 0xffffffffull && 31307b90e5ecSAttilio Rao (sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 31317b90e5ecSAttilio Rao error = EINVAL; 31327b90e5ecSAttilio Rao goto out; 31337b90e5ecSAttilio Rao } 31347b90e5ecSAttilio Rao } 31357b90e5ecSAttilio Rao #endif 31367b90e5ecSAttilio Rao else { 31377b90e5ecSAttilio Rao error = EINVAL; 31387b90e5ecSAttilio Rao goto out; 31397b90e5ecSAttilio Rao } 31407b90e5ecSAttilio Rao ureply = (char *)arg + fibsize; 31417b90e5ecSAttilio Rao srbcmd->data_len = srb_sg_bytecount; 31427b90e5ecSAttilio Rao if (srbcmd->sg_map.SgCount == 1) 31437b90e5ecSAttilio Rao transfer_data = 1; 31447b90e5ecSAttilio Rao 31457b90e5ecSAttilio Rao cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; 31467b90e5ecSAttilio Rao if (transfer_data) { 31477b90e5ecSAttilio Rao cm->cm_datalen = srb_sg_bytecount; 31487b90e5ecSAttilio Rao cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT); 31497b90e5ecSAttilio Rao if (cm->cm_data == NULL) { 31507b90e5ecSAttilio Rao error = ENOMEM; 31517b90e5ecSAttilio Rao goto out; 31527b90e5ecSAttilio Rao } 31537b90e5ecSAttilio Rao if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) 31547b90e5ecSAttilio Rao cm->cm_flags |= AAC_CMD_DATAIN; 31557b90e5ecSAttilio Rao if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { 31567b90e5ecSAttilio Rao cm->cm_flags |= AAC_CMD_DATAOUT; 31577b90e5ecSAttilio Rao error = copyin(srb_sg_address, cm->cm_data, 31587b90e5ecSAttilio Rao cm->cm_datalen); 31597b90e5ecSAttilio Rao if (error != 0) 31607b90e5ecSAttilio Rao goto out; 31617b90e5ecSAttilio Rao } 31627b90e5ecSAttilio Rao } 31637b90e5ecSAttilio Rao 31647b90e5ecSAttilio Rao fib->Header.Size = sizeof(struct aac_fib_header) + 31657b90e5ecSAttilio Rao sizeof(struct aac_srb); 31667b90e5ecSAttilio Rao fib->Header.XferState = 31677b90e5ecSAttilio Rao AAC_FIBSTATE_HOSTOWNED | 31687b90e5ecSAttilio Rao AAC_FIBSTATE_INITIALISED | 31697b90e5ecSAttilio Rao AAC_FIBSTATE_EMPTY | 31707b90e5ecSAttilio Rao AAC_FIBSTATE_FROMHOST | 31717b90e5ecSAttilio Rao AAC_FIBSTATE_REXPECTED | 31727b90e5ecSAttilio Rao AAC_FIBSTATE_NORM | 31737b90e5ecSAttilio Rao AAC_FIBSTATE_ASYNC | 31747b90e5ecSAttilio Rao AAC_FIBSTATE_FAST_RESPONSE; 31757b90e5ecSAttilio Rao fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ? 31767b90e5ecSAttilio Rao ScsiPortCommandU64 : ScsiPortCommand; 31777b90e5ecSAttilio Rao 31787b90e5ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 31797b90e5ecSAttilio Rao aac_wait_command(cm); 31807b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 31817b90e5ecSAttilio Rao 31827b90e5ecSAttilio Rao if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) { 31837b90e5ecSAttilio Rao error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen); 31847b90e5ecSAttilio Rao if (error != 0) 31857b90e5ecSAttilio Rao goto out; 31867b90e5ecSAttilio Rao } 31877b90e5ecSAttilio Rao error = copyout(fib->data, ureply, sizeof(struct aac_srb_response)); 31887b90e5ecSAttilio Rao out: 31897b90e5ecSAttilio Rao if (cm != NULL) { 31907b90e5ecSAttilio Rao if (cm->cm_data != NULL) 31917b90e5ecSAttilio Rao free(cm->cm_data, M_AACBUF); 31927b90e5ecSAttilio Rao mtx_lock(&sc->aac_io_lock); 31937b90e5ecSAttilio Rao aac_release_command(cm); 31947b90e5ecSAttilio Rao mtx_unlock(&sc->aac_io_lock); 31957b90e5ecSAttilio Rao } 31967b90e5ecSAttilio Rao return(error); 3197f355c0e0SEd Maste } 3198f355c0e0SEd Maste 3199f355c0e0SEd Maste /* 3200dfe2c294SAttilio Rao * cdevpriv interface private destructor. 3201dfe2c294SAttilio Rao */ 3202dfe2c294SAttilio Rao static void 3203dfe2c294SAttilio Rao aac_cdevpriv_dtor(void *arg) 3204dfe2c294SAttilio Rao { 3205dfe2c294SAttilio Rao struct aac_softc *sc; 3206dfe2c294SAttilio Rao 3207dfe2c294SAttilio Rao sc = arg; 3208dfe2c294SAttilio Rao fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3209dfe2c294SAttilio Rao device_unbusy(sc->aac_dev); 3210dfe2c294SAttilio Rao } 3211dfe2c294SAttilio Rao 3212dfe2c294SAttilio Rao /* 321335863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 321436e0bf6eSScott Long * If the queue fills up, then drop the older entries. 321535863739SMike Smith */ 321635863739SMike Smith static void 321736e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 321835863739SMike Smith { 321936e0bf6eSScott Long struct aac_aif_command *aif; 322036e0bf6eSScott Long struct aac_container *co, *co_next; 3221a723a548SEd Maste struct aac_fib_context *ctx; 322204f4d586SEd Maste struct aac_mntinforesp *mir; 3223a723a548SEd Maste int next, current, found; 3224795d7dc0SScott Long int count = 0, added = 0, i = 0; 3225851f59d7SEd Maste uint32_t channel; 322635863739SMike Smith 322731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 322835863739SMike Smith 322936e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 323036e0bf6eSScott Long aac_print_aif(sc, aif); 323136e0bf6eSScott Long 323236e0bf6eSScott Long /* Is it an event that we should care about? */ 323336e0bf6eSScott Long switch (aif->command) { 323436e0bf6eSScott Long case AifCmdEventNotify: 323536e0bf6eSScott Long switch (aif->data.EN.type) { 323636e0bf6eSScott Long case AifEnAddContainer: 323736e0bf6eSScott Long case AifEnDeleteContainer: 323836e0bf6eSScott Long /* 3239914da7d0SScott Long * A container was added or deleted, but the message 3240914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3241914da7d0SScott Long * containers and sort things out. 324236e0bf6eSScott Long */ 324303b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 324436e0bf6eSScott Long do { 324536e0bf6eSScott Long /* 3246914da7d0SScott Long * Ask the controller for its containers one at 3247914da7d0SScott Long * a time. 3248914da7d0SScott Long * XXX What if the controller's list changes 3249914da7d0SScott Long * midway through this enumaration? 325036e0bf6eSScott Long * XXX This should be done async. 325136e0bf6eSScott Long */ 325204f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 325336e0bf6eSScott Long continue; 325404f4d586SEd Maste if (i == 0) 3255795d7dc0SScott Long count = mir->MntRespCount; 325636e0bf6eSScott Long /* 3257914da7d0SScott Long * Check the container against our list. 3258914da7d0SScott Long * co->co_found was already set to 0 in a 3259914da7d0SScott Long * previous run. 326036e0bf6eSScott Long */ 3261cbfd045bSScott Long if ((mir->Status == ST_OK) && 3262cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 326336e0bf6eSScott Long found = 0; 3264914da7d0SScott Long TAILQ_FOREACH(co, 3265914da7d0SScott Long &sc->aac_container_tqh, 3266914da7d0SScott Long co_link) { 326736e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3268cbfd045bSScott Long mir->MntTable[0].ObjectId) { 326936e0bf6eSScott Long co->co_found = 1; 327036e0bf6eSScott Long found = 1; 327136e0bf6eSScott Long break; 327236e0bf6eSScott Long } 327336e0bf6eSScott Long } 3274914da7d0SScott Long /* 3275914da7d0SScott Long * If the container matched, continue 3276914da7d0SScott Long * in the list. 3277914da7d0SScott Long */ 327836e0bf6eSScott Long if (found) { 327936e0bf6eSScott Long i++; 328036e0bf6eSScott Long continue; 328136e0bf6eSScott Long } 328236e0bf6eSScott Long 328336e0bf6eSScott Long /* 3284914da7d0SScott Long * This is a new container. Do all the 328570545d1aSScott Long * appropriate things to set it up. 328670545d1aSScott Long */ 3287cbfd045bSScott Long aac_add_container(sc, mir, 1); 328836e0bf6eSScott Long added = 1; 328936e0bf6eSScott Long } 329036e0bf6eSScott Long i++; 3291795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3292cbfd045bSScott Long aac_release_sync_fib(sc); 329336e0bf6eSScott Long 329436e0bf6eSScott Long /* 3295914da7d0SScott Long * Go through our list of containers and see which ones 3296914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3297914da7d0SScott Long * list them they must have been deleted. Do the 3298914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3299914da7d0SScott Long * the co->co_found field. 330036e0bf6eSScott Long */ 330136e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 330236e0bf6eSScott Long while (co != NULL) { 330336e0bf6eSScott Long if (co->co_found == 0) { 33047cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3305c6df6f53SWarner Losh bus_topo_lock(); 3306914da7d0SScott Long device_delete_child(sc->aac_dev, 3307914da7d0SScott Long co->co_disk); 3308c6df6f53SWarner Losh bus_topo_unlock(); 33097cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 331036e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3311bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3312914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3313914da7d0SScott Long co_link); 3314bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3315ba1d57e7SScott Long free(co, M_AACBUF); 331636e0bf6eSScott Long co = co_next; 331736e0bf6eSScott Long } else { 331836e0bf6eSScott Long co->co_found = 0; 331936e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 332036e0bf6eSScott Long } 332136e0bf6eSScott Long } 332236e0bf6eSScott Long 332336e0bf6eSScott Long /* Attach the newly created containers */ 33247cb209f5SScott Long if (added) { 33257cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3326c6df6f53SWarner Losh bus_topo_lock(); 332736e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 3328c6df6f53SWarner Losh bus_topo_unlock(); 33297cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 33307cb209f5SScott Long } 333136e0bf6eSScott Long 333236e0bf6eSScott Long break; 333336e0bf6eSScott Long 3334851f59d7SEd Maste case AifEnEnclosureManagement: 3335851f59d7SEd Maste switch (aif->data.EN.data.EEE.eventType) { 3336851f59d7SEd Maste case AIF_EM_DRIVE_INSERTION: 3337851f59d7SEd Maste case AIF_EM_DRIVE_REMOVAL: 3338851f59d7SEd Maste channel = aif->data.EN.data.EEE.unitID; 3339851f59d7SEd Maste if (sc->cam_rescan_cb != NULL) 3340851f59d7SEd Maste sc->cam_rescan_cb(sc, 3341851f59d7SEd Maste (channel >> 24) & 0xF, 3342851f59d7SEd Maste (channel & 0xFFFF)); 3343851f59d7SEd Maste break; 3344851f59d7SEd Maste } 3345851f59d7SEd Maste break; 3346851f59d7SEd Maste 3347851f59d7SEd Maste case AifEnAddJBOD: 3348851f59d7SEd Maste case AifEnDeleteJBOD: 3349851f59d7SEd Maste channel = aif->data.EN.data.ECE.container; 3350851f59d7SEd Maste if (sc->cam_rescan_cb != NULL) 3351851f59d7SEd Maste sc->cam_rescan_cb(sc, (channel >> 24) & 0xF, 3352851f59d7SEd Maste AAC_CAM_TARGET_WILDCARD); 3353851f59d7SEd Maste break; 3354851f59d7SEd Maste 335536e0bf6eSScott Long default: 335636e0bf6eSScott Long break; 335736e0bf6eSScott Long } 335836e0bf6eSScott Long 335936e0bf6eSScott Long default: 336036e0bf6eSScott Long break; 336136e0bf6eSScott Long } 336236e0bf6eSScott Long 336336e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3364bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3365a723a548SEd Maste current = sc->aifq_idx; 3366a723a548SEd Maste next = (current + 1) % AAC_AIFQ_LENGTH; 3367a723a548SEd Maste if (next == 0) 3368a723a548SEd Maste sc->aifq_filled = 1; 3369a723a548SEd Maste bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3370a723a548SEd Maste /* modify AIF contexts */ 3371a723a548SEd Maste if (sc->aifq_filled) { 3372a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3373a723a548SEd Maste if (next == ctx->ctx_idx) 3374a723a548SEd Maste ctx->ctx_wrap = 1; 3375a723a548SEd Maste else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3376a723a548SEd Maste ctx->ctx_idx = next; 3377a723a548SEd Maste } 3378a723a548SEd Maste } 3379a723a548SEd Maste sc->aifq_idx = next; 3380b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 338135863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 338235863739SMike Smith wakeup(sc->aac_aifq); 3383b3457b51SScott Long /* Wakeup any poll()ers */ 3384512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 3385bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 338635863739SMike Smith } 338735863739SMike Smith 3388914da7d0SScott Long /* 33890b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 339036e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 339136e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 339236e0bf6eSScott Long * returning what the card reported. 339335863739SMike Smith */ 339435863739SMike Smith static int 3395fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 339635863739SMike Smith { 339735863739SMike Smith struct aac_rev_check rev_check; 339835863739SMike Smith struct aac_rev_check_resp rev_check_resp; 339935863739SMike Smith int error = 0; 340035863739SMike Smith 340131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 340235863739SMike Smith 340335863739SMike Smith /* 340435863739SMike Smith * Copyin the revision struct from userspace 340535863739SMike Smith */ 3406c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3407c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 340835863739SMike Smith return error; 340935863739SMike Smith } 341035863739SMike Smith 341131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3412914da7d0SScott Long rev_check.callingRevision.buildNumber); 341335863739SMike Smith 341435863739SMike Smith /* 341535863739SMike Smith * Doctor up the response struct. 341635863739SMike Smith */ 341735863739SMike Smith rev_check_resp.possiblyCompatible = 1; 34188e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.major = 34198e7e6335SEd Maste AAC_DRIVER_MAJOR_VERSION; 34208e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.minor = 34218e7e6335SEd Maste AAC_DRIVER_MINOR_VERSION; 34228e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.type = 34238e7e6335SEd Maste AAC_DRIVER_TYPE; 34248e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.dash = 34258e7e6335SEd Maste AAC_DRIVER_BUGFIX_LEVEL; 3426914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 34278e7e6335SEd Maste AAC_DRIVER_BUILD; 342835863739SMike Smith 3429c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3430c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 343135863739SMike Smith } 343235863739SMike Smith 3433914da7d0SScott Long /* 3434a723a548SEd Maste * Pass the fib context to the caller 3435a723a548SEd Maste */ 3436a723a548SEd Maste static int 3437a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg) 3438a723a548SEd Maste { 3439a723a548SEd Maste struct aac_fib_context *fibctx, *ctx; 3440a723a548SEd Maste int error = 0; 3441a723a548SEd Maste 344231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3443a723a548SEd Maste 3444a723a548SEd Maste fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3445a723a548SEd Maste if (fibctx == NULL) 3446a723a548SEd Maste return (ENOMEM); 3447a723a548SEd Maste 3448a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3449a723a548SEd Maste /* all elements are already 0, add to queue */ 3450a723a548SEd Maste if (sc->fibctx == NULL) 3451a723a548SEd Maste sc->fibctx = fibctx; 3452a723a548SEd Maste else { 3453a723a548SEd Maste for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3454a723a548SEd Maste ; 3455a723a548SEd Maste ctx->next = fibctx; 3456a723a548SEd Maste fibctx->prev = ctx; 3457a723a548SEd Maste } 3458a723a548SEd Maste 3459a723a548SEd Maste /* evaluate unique value */ 3460a723a548SEd Maste fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3461a723a548SEd Maste ctx = sc->fibctx; 3462a723a548SEd Maste while (ctx != fibctx) { 3463a723a548SEd Maste if (ctx->unique == fibctx->unique) { 3464a723a548SEd Maste fibctx->unique++; 3465a723a548SEd Maste ctx = sc->fibctx; 3466a723a548SEd Maste } else { 3467a723a548SEd Maste ctx = ctx->next; 3468a723a548SEd Maste } 3469a723a548SEd Maste } 3470a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3471a723a548SEd Maste 3472a723a548SEd Maste error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3473a723a548SEd Maste if (error) 3474a723a548SEd Maste aac_close_aif(sc, (caddr_t)ctx); 3475a723a548SEd Maste return error; 3476a723a548SEd Maste } 3477a723a548SEd Maste 3478a723a548SEd Maste /* 3479a723a548SEd Maste * Close the caller's fib context 3480a723a548SEd Maste */ 3481a723a548SEd Maste static int 3482a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg) 3483a723a548SEd Maste { 3484a723a548SEd Maste struct aac_fib_context *ctx; 3485a723a548SEd Maste 348631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3487a723a548SEd Maste 3488a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3489a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3490a723a548SEd Maste if (ctx->unique == *(uint32_t *)&arg) { 3491a723a548SEd Maste if (ctx == sc->fibctx) 3492a723a548SEd Maste sc->fibctx = NULL; 3493a723a548SEd Maste else { 3494a723a548SEd Maste ctx->prev->next = ctx->next; 3495a723a548SEd Maste if (ctx->next) 3496a723a548SEd Maste ctx->next->prev = ctx->prev; 3497a723a548SEd Maste } 3498a723a548SEd Maste break; 3499a723a548SEd Maste } 3500a723a548SEd Maste } 3501a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3502a723a548SEd Maste if (ctx) 3503a723a548SEd Maste free(ctx, M_AACBUF); 3504a723a548SEd Maste 3505a723a548SEd Maste return 0; 3506a723a548SEd Maste } 3507a723a548SEd Maste 3508a723a548SEd Maste /* 350935863739SMike Smith * Pass the caller the next AIF in their queue 351035863739SMike Smith */ 351135863739SMike Smith static int 3512fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 351335863739SMike Smith { 351435863739SMike Smith struct get_adapter_fib_ioctl agf; 3515a723a548SEd Maste struct aac_fib_context *ctx; 35169e2e96d8SScott Long int error; 351735863739SMike Smith 351831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 351935863739SMike Smith 3520f287c3e4SBrooks Davis #ifdef COMPAT_FREEBSD32 3521f287c3e4SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) { 3522f287c3e4SBrooks Davis struct get_adapter_fib_ioctl32 agf32; 3523f287c3e4SBrooks Davis error = copyin(arg, &agf32, sizeof(agf32)); 3524f287c3e4SBrooks Davis if (error == 0) { 3525f287c3e4SBrooks Davis agf.AdapterFibContext = agf32.AdapterFibContext; 3526f287c3e4SBrooks Davis agf.Wait = agf32.Wait; 3527f287c3e4SBrooks Davis agf.AifFib = (caddr_t)(uintptr_t)agf32.AifFib; 3528f287c3e4SBrooks Davis } 3529f287c3e4SBrooks Davis } else 3530f287c3e4SBrooks Davis #endif 3531f287c3e4SBrooks Davis error = copyin(arg, &agf, sizeof(agf)); 3532f287c3e4SBrooks Davis if (error == 0) { 3533a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3534a723a548SEd Maste if (agf.AdapterFibContext == ctx->unique) 3535a723a548SEd Maste break; 3536a723a548SEd Maste } 3537a723a548SEd Maste if (!ctx) 3538a723a548SEd Maste return (EFAULT); 353935863739SMike Smith 3540a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 3541a723a548SEd Maste if (error == EAGAIN && agf.Wait) { 354231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 354335863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 354435863739SMike Smith while (error == EAGAIN) { 3545914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3546914da7d0SScott Long PCATCH, "aacaif", 0); 354735863739SMike Smith if (error == 0) 3548a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 354935863739SMike Smith } 355035863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 355135863739SMike Smith } 355235863739SMike Smith } 355335863739SMike Smith return(error); 355435863739SMike Smith } 355535863739SMike Smith 3556914da7d0SScott Long /* 35570b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 35580b94a66eSMike Smith */ 35590b94a66eSMike Smith static int 3560a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 35610b94a66eSMike Smith { 3562a723a548SEd Maste int current, error; 35630b94a66eSMike Smith 356431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 35650b94a66eSMike Smith 3566bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3567a723a548SEd Maste current = ctx->ctx_idx; 3568a723a548SEd Maste if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3569a723a548SEd Maste /* empty */ 3570bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 35713df780cfSScott Long return (EAGAIN); 35723df780cfSScott Long } 3573a723a548SEd Maste error = 3574a723a548SEd Maste copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 357536e0bf6eSScott Long if (error) 357670545d1aSScott Long device_printf(sc->aac_dev, 357770545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 3578a723a548SEd Maste else { 3579a723a548SEd Maste ctx->ctx_wrap = 0; 3580a723a548SEd Maste ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3581a723a548SEd Maste } 3582bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 35830b94a66eSMike Smith return(error); 35840b94a66eSMike Smith } 358536e0bf6eSScott Long 35867cb209f5SScott Long static int 35877cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 35887cb209f5SScott Long { 35897cb209f5SScott Long struct aac_pci_info { 35907cb209f5SScott Long u_int32_t bus; 35917cb209f5SScott Long u_int32_t slot; 35927cb209f5SScott Long } pciinf; 35937cb209f5SScott Long int error; 35947cb209f5SScott Long 359531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 35967cb209f5SScott Long 35977cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 35987cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 35997cb209f5SScott Long 36007cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 36017cb209f5SScott Long sizeof(struct aac_pci_info)); 36027cb209f5SScott Long 36037cb209f5SScott Long return (error); 36047cb209f5SScott Long } 36057cb209f5SScott Long 36066d307336SEd Maste static int 36076d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr) 36086d307336SEd Maste { 36096d307336SEd Maste struct aac_features f; 36106d307336SEd Maste int error; 36116d307336SEd Maste 36126d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 36136d307336SEd Maste 36146d307336SEd Maste if ((error = copyin(uptr, &f, sizeof (f))) != 0) 36156d307336SEd Maste return (error); 36166d307336SEd Maste 36176d307336SEd Maste /* 36186d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 36196d307336SEd Maste * ALL zero in the featuresState, the driver will return the current 36206d307336SEd Maste * state of all the supported features, the data field will not be 36216d307336SEd Maste * valid. 36226d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 36236d307336SEd Maste * a specific bit set in the featuresState, the driver will return the 36246d307336SEd Maste * current state of this specific feature and whatever data that are 36256d307336SEd Maste * associated with the feature in the data field or perform whatever 36266d307336SEd Maste * action needed indicates in the data field. 36276d307336SEd Maste */ 36286d307336SEd Maste if (f.feat.fValue == 0) { 36296d307336SEd Maste f.feat.fBits.largeLBA = 36306d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 36316d307336SEd Maste /* TODO: In the future, add other features state here as well */ 36326d307336SEd Maste } else { 36336d307336SEd Maste if (f.feat.fBits.largeLBA) 36346d307336SEd Maste f.feat.fBits.largeLBA = 36356d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 36366d307336SEd Maste /* TODO: Add other features state and data in the future */ 36376d307336SEd Maste } 36386d307336SEd Maste 36396d307336SEd Maste error = copyout(&f, uptr, sizeof (f)); 36406d307336SEd Maste return (error); 36416d307336SEd Maste } 36426d307336SEd Maste 3643914da7d0SScott Long /* 364436e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 364536e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 364636e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 364736e0bf6eSScott Long */ 364836e0bf6eSScott Long static int 364936e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 365036e0bf6eSScott Long { 365136e0bf6eSScott Long struct aac_query_disk query_disk; 365236e0bf6eSScott Long struct aac_container *co; 3653914da7d0SScott Long struct aac_disk *disk; 365436e0bf6eSScott Long int error, id; 365536e0bf6eSScott Long 365631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 365736e0bf6eSScott Long 3658914da7d0SScott Long disk = NULL; 3659914da7d0SScott Long 3660914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3661914da7d0SScott Long sizeof(struct aac_query_disk)); 366236e0bf6eSScott Long if (error) 366336e0bf6eSScott Long return (error); 366436e0bf6eSScott Long 366536e0bf6eSScott Long id = query_disk.ContainerNumber; 366636e0bf6eSScott Long if (id == -1) 366736e0bf6eSScott Long return (EINVAL); 366836e0bf6eSScott Long 3669bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 367036e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 367136e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 367236e0bf6eSScott Long break; 367336e0bf6eSScott Long } 367436e0bf6eSScott Long 367536e0bf6eSScott Long if (co == NULL) { 367636e0bf6eSScott Long query_disk.Valid = 0; 367736e0bf6eSScott Long query_disk.Locked = 0; 367836e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 367936e0bf6eSScott Long } else { 368036e0bf6eSScott Long disk = device_get_softc(co->co_disk); 368136e0bf6eSScott Long query_disk.Valid = 1; 3682914da7d0SScott Long query_disk.Locked = 3683914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 368436e0bf6eSScott Long query_disk.Deleted = 0; 3685b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 368636e0bf6eSScott Long query_disk.Target = disk->unit; 368736e0bf6eSScott Long query_disk.Lun = 0; 368836e0bf6eSScott Long query_disk.UnMapped = 0; 36897540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 36900b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 369136e0bf6eSScott Long } 3692bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 369336e0bf6eSScott Long 3694914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3695914da7d0SScott Long sizeof(struct aac_query_disk)); 369636e0bf6eSScott Long 369736e0bf6eSScott Long return (error); 369836e0bf6eSScott Long } 369936e0bf6eSScott Long 3700fe3cb0e1SScott Long static void 3701fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3702fe3cb0e1SScott Long { 3703fe3cb0e1SScott Long struct aac_fib *fib; 3704fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3705fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3706fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3707fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3708fe3cb0e1SScott Long struct aac_getbusinf businfo; 370970545d1aSScott Long struct aac_sim *caminf; 3710fe3cb0e1SScott Long device_t child; 3711fe3cb0e1SScott Long int i, found, error; 3712fe3cb0e1SScott Long 37131ffe41c1SChristian S.J. Peron mtx_lock(&sc->aac_io_lock); 371403b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3715fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 371639ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3717fe3cb0e1SScott Long 3718fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3719fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3720fe3cb0e1SScott Long c_cmd->param = 0; 3721fe3cb0e1SScott Long 3722fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3723fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3724fe3cb0e1SScott Long if (error) { 3725fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3726fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3727fe3cb0e1SScott Long aac_release_sync_fib(sc); 37281ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3729fe3cb0e1SScott Long return; 3730fe3cb0e1SScott Long } 3731fe3cb0e1SScott Long 3732fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3733fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3734fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3735fe3cb0e1SScott Long c_resp->Status); 3736fe3cb0e1SScott Long aac_release_sync_fib(sc); 37371ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3738fe3cb0e1SScott Long return; 3739fe3cb0e1SScott Long } 3740fe3cb0e1SScott Long 3741fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3742fe3cb0e1SScott Long 3743fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 374439ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 374539ee03c3SScott Long 3746fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3747fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3748fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3749fe3cb0e1SScott Long vmi->ObjId = 0; 3750fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3751fe3cb0e1SScott Long 3752fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 375342ef13a2SEd Maste sizeof(struct aac_vmi_businf_resp)); 3754fe3cb0e1SScott Long if (error) { 3755fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3756fe3cb0e1SScott Long error); 3757fe3cb0e1SScott Long aac_release_sync_fib(sc); 37581ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3759fe3cb0e1SScott Long return; 3760fe3cb0e1SScott Long } 3761fe3cb0e1SScott Long 3762fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3763fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3764fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3765fe3cb0e1SScott Long vmi_resp->Status); 3766fe3cb0e1SScott Long aac_release_sync_fib(sc); 37671ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3768fe3cb0e1SScott Long return; 3769fe3cb0e1SScott Long } 3770fe3cb0e1SScott Long 3771fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3772fe3cb0e1SScott Long aac_release_sync_fib(sc); 37731ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3774fe3cb0e1SScott Long 3775fe3cb0e1SScott Long found = 0; 3776fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3777fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3778fe3cb0e1SScott Long continue; 3779fe3cb0e1SScott Long 3780a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3781a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3782b5f516cdSScott Long if (caminf == NULL) { 3783b5f516cdSScott Long device_printf(sc->aac_dev, 3784b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3785b5f516cdSScott Long break; 378674b8d63dSPedro F. Giffuni } 3787fe3cb0e1SScott Long 3788*5b56413dSWarner Losh child = device_add_child(sc->aac_dev, "aacp", DEVICE_UNIT_ANY); 3789fe3cb0e1SScott Long if (child == NULL) { 3790b5f516cdSScott Long device_printf(sc->aac_dev, 3791b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3792b5f516cdSScott Long i); 3793b5f516cdSScott Long free(caminf, M_AACBUF); 3794b5f516cdSScott Long break; 3795fe3cb0e1SScott Long } 3796fe3cb0e1SScott Long 3797fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3798fe3cb0e1SScott Long caminf->BusNumber = i; 3799fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3800fe3cb0e1SScott Long caminf->aac_sc = sc; 3801ddb8683eSScott Long caminf->sim_dev = child; 3802fe3cb0e1SScott Long 3803fe3cb0e1SScott Long device_set_ivars(child, caminf); 3804fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 380570545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3806fe3cb0e1SScott Long 3807fe3cb0e1SScott Long found = 1; 3808fe3cb0e1SScott Long } 3809fe3cb0e1SScott Long 3810fe3cb0e1SScott Long if (found) 3811fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3812fe3cb0e1SScott Long } 3813