135863739SMike Smith /*- 235863739SMike Smith * Copyright (c) 2000 Michael Smith 3c6eafcf2SScott Long * Copyright (c) 2001 Scott Long 435863739SMike Smith * Copyright (c) 2000 BSDi 5c6eafcf2SScott Long * Copyright (c) 2001 Adaptec, Inc. 635863739SMike Smith * All rights reserved. 735863739SMike Smith * 835863739SMike Smith * Redistribution and use in source and binary forms, with or without 935863739SMike Smith * modification, are permitted provided that the following conditions 1035863739SMike Smith * are met: 1135863739SMike Smith * 1. Redistributions of source code must retain the above copyright 1235863739SMike Smith * notice, this list of conditions and the following disclaimer. 1335863739SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1435863739SMike Smith * notice, this list of conditions and the following disclaimer in the 1535863739SMike Smith * documentation and/or other materials provided with the distribution. 1635863739SMike Smith * 1735863739SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1835863739SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1935863739SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2035863739SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2135863739SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2235863739SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2335863739SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2435863739SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2535863739SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2635863739SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2735863739SMike Smith * SUCH DAMAGE. 2835863739SMike Smith */ 2935863739SMike Smith 30aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 32aad970f1SDavid E. O'Brien 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> 463d04a9d7SScott Long #include <sys/sysctl.h> 47b3457b51SScott Long #include <sys/poll.h> 48891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 4935863739SMike Smith 5035863739SMike Smith #include <sys/bus.h> 5135863739SMike Smith #include <sys/conf.h> 5235863739SMike Smith #include <sys/signalvar.h> 530b94a66eSMike Smith #include <sys/time.h> 5436e0bf6eSScott Long #include <sys/eventhandler.h> 557cb209f5SScott Long #include <sys/rman.h> 5635863739SMike Smith 5735863739SMike Smith #include <machine/bus.h> 58b5f516cdSScott Long #include <sys/bus_dma.h> 5935863739SMike Smith #include <machine/resource.h> 6035863739SMike Smith 617cb209f5SScott Long #include <dev/pci/pcireg.h> 627cb209f5SScott Long #include <dev/pci/pcivar.h> 637cb209f5SScott Long 6435863739SMike Smith #include <dev/aac/aacreg.h> 650b0594cdSScott Long #include <sys/aac_ioctl.h> 6635863739SMike Smith #include <dev/aac/aacvar.h> 6735863739SMike Smith #include <dev/aac/aac_tables.h> 6835863739SMike Smith 6935863739SMike Smith static void aac_startup(void *arg); 70914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 71cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 72fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 73ff0991c4SAttilio Rao static void aac_daemon(void *arg); 7435863739SMike Smith 7535863739SMike Smith /* Command Processing */ 760b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7735863739SMike Smith static void aac_complete(void *context, int pending); 7835863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7935863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 80d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 8170545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8235863739SMike Smith 8335863739SMike Smith /* Command Buffer Management */ 84cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 85cd481291SScott Long int nseg, int error); 86c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 87c6eafcf2SScott Long int nseg, int error); 880b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 898480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9035863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9135863739SMike Smith 9235863739SMike Smith /* Hardware Interface */ 9304f4d586SEd Maste static int aac_alloc(struct aac_softc *sc); 94c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 95c6eafcf2SScott Long int error); 96fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9735863739SMike Smith static int aac_init(struct aac_softc *sc); 9835863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 99c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 100c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 10104f4d586SEd Maste static int aac_setup_intr(struct aac_softc *sc); 102c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 103f6c4dd3fSScott Long struct aac_command *cm); 104c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 105914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10636e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10736e0bf6eSScott Long struct aac_fib *fib); 10835863739SMike Smith 10935863739SMike Smith /* StrongARM interface */ 11035863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 11135863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 11235863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 11335863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 11435863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 115c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 116c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 117a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 11835863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 11935863739SMike Smith 12035863739SMike Smith struct aac_interface aac_sa_interface = { 12135863739SMike Smith aac_sa_get_fwstatus, 12235863739SMike Smith aac_sa_qnotify, 12335863739SMike Smith aac_sa_get_istatus, 12435863739SMike Smith aac_sa_clear_istatus, 12535863739SMike Smith aac_sa_set_mailbox, 126a6d35632SScott Long aac_sa_get_mailbox, 1277cb209f5SScott Long aac_sa_set_interrupts, 1287cb209f5SScott Long NULL, NULL, NULL 12935863739SMike Smith }; 13035863739SMike Smith 13135863739SMike Smith /* i960Rx interface */ 13235863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 13335863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 13435863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 13535863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 13635863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 137c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 138c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 139a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 14035863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1417cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1427cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1437cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 14435863739SMike Smith 14535863739SMike Smith struct aac_interface aac_rx_interface = { 14635863739SMike Smith aac_rx_get_fwstatus, 14735863739SMike Smith aac_rx_qnotify, 14835863739SMike Smith aac_rx_get_istatus, 14935863739SMike Smith aac_rx_clear_istatus, 15035863739SMike Smith aac_rx_set_mailbox, 151a6d35632SScott Long aac_rx_get_mailbox, 1527cb209f5SScott Long aac_rx_set_interrupts, 1537cb209f5SScott Long aac_rx_send_command, 1547cb209f5SScott Long aac_rx_get_outb_queue, 1557cb209f5SScott Long aac_rx_set_outb_queue 15635863739SMike Smith }; 15735863739SMike Smith 1584afedc31SScott Long /* Rocket/MIPS interface */ 1594afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1604afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1614afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1624afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1634afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1644afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1654afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1664afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1674afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1687cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1697cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1707cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1714afedc31SScott Long 1724afedc31SScott Long struct aac_interface aac_rkt_interface = { 1734afedc31SScott Long aac_rkt_get_fwstatus, 1744afedc31SScott Long aac_rkt_qnotify, 1754afedc31SScott Long aac_rkt_get_istatus, 1764afedc31SScott Long aac_rkt_clear_istatus, 1774afedc31SScott Long aac_rkt_set_mailbox, 1784afedc31SScott Long aac_rkt_get_mailbox, 1797cb209f5SScott Long aac_rkt_set_interrupts, 1807cb209f5SScott Long aac_rkt_send_command, 1817cb209f5SScott Long aac_rkt_get_outb_queue, 1827cb209f5SScott Long aac_rkt_set_outb_queue 1834afedc31SScott Long }; 1844afedc31SScott Long 18535863739SMike Smith /* Debugging and Diagnostics */ 18635863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 1876965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 188c6eafcf2SScott Long u_int32_t code); 18935863739SMike Smith 19035863739SMike Smith /* Management Interface */ 19135863739SMike Smith static d_open_t aac_open; 19235863739SMike Smith static d_close_t aac_close; 19335863739SMike Smith static d_ioctl_t aac_ioctl; 194b3457b51SScott Long static d_poll_t aac_poll; 195c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 196f355c0e0SEd Maste static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 197c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 19836e0bf6eSScott Long struct aac_fib *fib); 199fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 200a723a548SEd Maste static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 201a723a548SEd Maste static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 202fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 203a723a548SEd Maste static int aac_return_aif(struct aac_softc *sc, 204a723a548SEd Maste struct aac_fib_context *ctx, caddr_t uptr); 20536e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2067cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2076d307336SEd Maste static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 2087cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2097cb209f5SScott Long struct aac_event *event, void *arg); 21004f4d586SEd Maste static struct aac_mntinforesp * 21104f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); 21235863739SMike Smith 21335863739SMike Smith static struct cdevsw aac_cdevsw = { 214dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 215dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 2167ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2177ac40f5fSPoul-Henning Kamp .d_close = aac_close, 2187ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2197ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2207ac40f5fSPoul-Henning Kamp .d_name = "aac", 22135863739SMike Smith }; 22235863739SMike Smith 22336e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 22436e0bf6eSScott Long 2253d04a9d7SScott Long /* sysctl node */ 2263d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2273d04a9d7SScott Long 228914da7d0SScott Long /* 229914da7d0SScott Long * Device Interface 230914da7d0SScott Long */ 23135863739SMike Smith 232914da7d0SScott Long /* 2334109ba51SEd Maste * Initialize the controller and softc 23435863739SMike Smith */ 23535863739SMike Smith int 23635863739SMike Smith aac_attach(struct aac_softc *sc) 23735863739SMike Smith { 23835863739SMike Smith int error, unit; 23935863739SMike Smith 24031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24135863739SMike Smith 24235863739SMike Smith /* 2434109ba51SEd Maste * Initialize per-controller queues. 24435863739SMike Smith */ 2450b94a66eSMike Smith aac_initq_free(sc); 2460b94a66eSMike Smith aac_initq_ready(sc); 2470b94a66eSMike Smith aac_initq_busy(sc); 2480b94a66eSMike Smith aac_initq_bio(sc); 24935863739SMike Smith 25035863739SMike Smith /* 2514109ba51SEd Maste * Initialize command-completion task. 25235863739SMike Smith */ 25335863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 25435863739SMike Smith 25535863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 25635863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 25735863739SMike Smith 25835863739SMike Smith /* 259fe94b852SScott Long * Check that the firmware on the card is supported. 260fe94b852SScott Long */ 261fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 262fe94b852SScott Long return(error); 263fe94b852SScott Long 264f6b1c44dSScott Long /* 265f6b1c44dSScott Long * Initialize locks 266f6b1c44dSScott Long */ 267bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 268bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 269bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 270f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 271065dd78cSScott Long TAILQ_INIT(&sc->aac_ev_cmfree); 272f6b1c44dSScott Long 273ff0991c4SAttilio Rao /* Initialize the clock daemon callout. */ 274ff0991c4SAttilio Rao callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 275ff0991c4SAttilio Rao 2760b94a66eSMike Smith /* 2774109ba51SEd Maste * Initialize the adapter. 27835863739SMike Smith */ 27904f4d586SEd Maste if ((error = aac_alloc(sc)) != 0) 28004f4d586SEd Maste return(error); 2810b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 28235863739SMike Smith return(error); 28335863739SMike Smith 28435863739SMike Smith /* 2857cb209f5SScott Long * Allocate and connect our interrupt. 2867cb209f5SScott Long */ 28704f4d586SEd Maste if ((error = aac_setup_intr(sc)) != 0) 28804f4d586SEd Maste return(error); 2897cb209f5SScott Long 2907cb209f5SScott Long /* 29135863739SMike Smith * Print a little information about the controller. 29235863739SMike Smith */ 29335863739SMike Smith aac_describe_controller(sc); 29435863739SMike Smith 29535863739SMike Smith /* 296ae543596SScott Long * Register to probe our containers later. 297ae543596SScott Long */ 29835863739SMike Smith sc->aac_ich.ich_func = aac_startup; 29935863739SMike Smith sc->aac_ich.ich_arg = sc; 30035863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 301914da7d0SScott Long device_printf(sc->aac_dev, 302914da7d0SScott Long "can't establish configuration hook\n"); 30335863739SMike Smith return(ENXIO); 30435863739SMike Smith } 30535863739SMike Smith 30635863739SMike Smith /* 30735863739SMike Smith * Make the control device. 30835863739SMike Smith */ 30935863739SMike Smith unit = device_get_unit(sc->aac_dev); 3109e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3119e9466baSRobert Watson 0640, "aac%d", unit); 312157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3134aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 31435863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 31535863739SMike Smith 31636e0bf6eSScott Long /* Create the AIF thread */ 3173745c395SJulian Elischer if (kproc_create((void(*)(void *))aac_command_thread, sc, 318316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 319a620bad0SEd Maste panic("Could not create AIF thread"); 32036e0bf6eSScott Long 32136e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3225f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3235f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3245f54d522SScott Long device_printf(sc->aac_dev, 3255f54d522SScott Long "shutdown event registration failed\n"); 32636e0bf6eSScott Long 327fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 328a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 32970545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 330fe3cb0e1SScott Long aac_get_bus_info(sc); 33170545d1aSScott Long } 332fe3cb0e1SScott Long 333ff0991c4SAttilio Rao mtx_lock(&sc->aac_io_lock); 334867b1d34SEd Maste callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 335ff0991c4SAttilio Rao mtx_unlock(&sc->aac_io_lock); 336ff0991c4SAttilio Rao 33735863739SMike Smith return(0); 33835863739SMike Smith } 33935863739SMike Smith 340ff0991c4SAttilio Rao static void 341ff0991c4SAttilio Rao aac_daemon(void *arg) 342ff0991c4SAttilio Rao { 343ff0991c4SAttilio Rao struct timeval tv; 344ff0991c4SAttilio Rao struct aac_softc *sc; 345ff0991c4SAttilio Rao struct aac_fib *fib; 346ff0991c4SAttilio Rao 347ff0991c4SAttilio Rao sc = arg; 348ff0991c4SAttilio Rao mtx_assert(&sc->aac_io_lock, MA_OWNED); 349ff0991c4SAttilio Rao 350ff0991c4SAttilio Rao if (callout_pending(&sc->aac_daemontime) || 351ff0991c4SAttilio Rao callout_active(&sc->aac_daemontime) == 0) 352ff0991c4SAttilio Rao return; 353ff0991c4SAttilio Rao getmicrotime(&tv); 354ff0991c4SAttilio Rao aac_alloc_sync_fib(sc, &fib); 355ff0991c4SAttilio Rao *(uint32_t *)fib->data = tv.tv_sec; 356ff0991c4SAttilio Rao aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); 357ff0991c4SAttilio Rao aac_release_sync_fib(sc); 358ff0991c4SAttilio Rao callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 359ff0991c4SAttilio Rao } 360ff0991c4SAttilio Rao 3617cb209f5SScott Long void 3627cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event) 3637cb209f5SScott Long { 3647cb209f5SScott Long 3657cb209f5SScott Long switch (event->ev_type & AAC_EVENT_MASK) { 3667cb209f5SScott Long case AAC_EVENT_CMFREE: 3677cb209f5SScott Long TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 3687cb209f5SScott Long break; 3697cb209f5SScott Long default: 3707cb209f5SScott Long device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 3717cb209f5SScott Long event->ev_type); 3727cb209f5SScott Long break; 3737cb209f5SScott Long } 3747cb209f5SScott Long 3757cb209f5SScott Long return; 3767cb209f5SScott Long } 3777cb209f5SScott Long 378914da7d0SScott Long /* 37904f4d586SEd Maste * Request information of container #cid 38004f4d586SEd Maste */ 38104f4d586SEd Maste static struct aac_mntinforesp * 38204f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) 38304f4d586SEd Maste { 38404f4d586SEd Maste struct aac_mntinfo *mi; 38504f4d586SEd Maste 38604f4d586SEd Maste mi = (struct aac_mntinfo *)&fib->data[0]; 387523da39bSEd Maste /* use 64-bit LBA if enabled */ 388523da39bSEd Maste mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? 389523da39bSEd Maste VM_NameServe64 : VM_NameServe; 39004f4d586SEd Maste mi->MntType = FT_FILESYS; 39104f4d586SEd Maste mi->MntCount = cid; 39204f4d586SEd Maste 39304f4d586SEd Maste if (aac_sync_fib(sc, ContainerCommand, 0, fib, 39404f4d586SEd Maste sizeof(struct aac_mntinfo))) { 395a620bad0SEd Maste printf("Error probing container %d\n", cid); 39604f4d586SEd Maste return (NULL); 39704f4d586SEd Maste } 39804f4d586SEd Maste 39904f4d586SEd Maste return ((struct aac_mntinforesp *)&fib->data[0]); 40004f4d586SEd Maste } 40104f4d586SEd Maste 40204f4d586SEd Maste /* 40335863739SMike Smith * Probe for containers, create disks. 40435863739SMike Smith */ 40535863739SMike Smith static void 40635863739SMike Smith aac_startup(void *arg) 40735863739SMike Smith { 408914da7d0SScott Long struct aac_softc *sc; 409cbfd045bSScott Long struct aac_fib *fib; 41004f4d586SEd Maste struct aac_mntinforesp *mir; 411795d7dc0SScott Long int count = 0, i = 0; 41235863739SMike Smith 413914da7d0SScott Long sc = (struct aac_softc *)arg; 41431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 415914da7d0SScott Long 41635863739SMike Smith /* disconnect ourselves from the intrhook chain */ 41735863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 41835863739SMike Smith 4197cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 42003b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 421cbfd045bSScott Long 42235863739SMike Smith /* loop over possible containers */ 42336e0bf6eSScott Long do { 42404f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 42535863739SMike Smith continue; 42604f4d586SEd Maste if (i == 0) 427795d7dc0SScott Long count = mir->MntRespCount; 428cbfd045bSScott Long aac_add_container(sc, mir, 0); 42936e0bf6eSScott Long i++; 430795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 431cbfd045bSScott Long 432cbfd045bSScott Long aac_release_sync_fib(sc); 4337cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 43435863739SMike Smith 43535863739SMike Smith /* poke the bus to actually attach the child devices */ 43635863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 43735863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 43835863739SMike Smith 43935863739SMike Smith /* mark the controller up */ 44035863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 44135863739SMike Smith 44235863739SMike Smith /* enable interrupts now */ 44335863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 44435863739SMike Smith } 44535863739SMike Smith 446914da7d0SScott Long /* 4474109ba51SEd Maste * Create a device to represent a new container 448914da7d0SScott Long */ 449914da7d0SScott Long static void 450cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 451914da7d0SScott Long { 452914da7d0SScott Long struct aac_container *co; 453914da7d0SScott Long device_t child; 454914da7d0SScott Long 455914da7d0SScott Long /* 456914da7d0SScott Long * Check container volume type for validity. Note that many of 457914da7d0SScott Long * the possible types may never show up. 458914da7d0SScott Long */ 459914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 460a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 461a761a1caSScott Long M_NOWAIT | M_ZERO); 462914da7d0SScott Long if (co == NULL) 463a620bad0SEd Maste panic("Out of memory?!"); 46431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", 465914da7d0SScott Long mir->MntTable[0].ObjectId, 466914da7d0SScott Long mir->MntTable[0].FileSystemName, 467914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 468914da7d0SScott Long 469fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 470914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 471914da7d0SScott Long else 472914da7d0SScott Long device_set_ivars(child, co); 473914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 474914da7d0SScott Long mir->MntTable[0].VolType)); 475914da7d0SScott Long co->co_disk = child; 476914da7d0SScott Long co->co_found = f; 477914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 478914da7d0SScott Long sizeof(struct aac_mntobj)); 479bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 480914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 481bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 482914da7d0SScott Long } 483914da7d0SScott Long } 484914da7d0SScott Long 485914da7d0SScott Long /* 48604f4d586SEd Maste * Allocate resources associated with (sc) 48704f4d586SEd Maste */ 48804f4d586SEd Maste static int 48904f4d586SEd Maste aac_alloc(struct aac_softc *sc) 49004f4d586SEd Maste { 49131a0399eSEd Maste 49231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 49331a0399eSEd Maste 49404f4d586SEd Maste /* 49504f4d586SEd Maste * Create DMA tag for mapping buffers into controller-addressable space. 49604f4d586SEd Maste */ 49704f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 49804f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 49904f4d586SEd Maste (sc->flags & AAC_FLAGS_SG_64BIT) ? 50004f4d586SEd Maste BUS_SPACE_MAXADDR : 50104f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 50204f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 50304f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 50404f4d586SEd Maste MAXBSIZE, /* maxsize */ 50504f4d586SEd Maste sc->aac_sg_tablesize, /* nsegments */ 50604f4d586SEd Maste MAXBSIZE, /* maxsegsize */ 50704f4d586SEd Maste BUS_DMA_ALLOCNOW, /* flags */ 50804f4d586SEd Maste busdma_lock_mutex, /* lockfunc */ 50904f4d586SEd Maste &sc->aac_io_lock, /* lockfuncarg */ 51004f4d586SEd Maste &sc->aac_buffer_dmat)) { 51104f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 51204f4d586SEd Maste return (ENOMEM); 51304f4d586SEd Maste } 51404f4d586SEd Maste 51504f4d586SEd Maste /* 51604f4d586SEd Maste * Create DMA tag for mapping FIBs into controller-addressable space.. 51704f4d586SEd Maste */ 51804f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 51904f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 52004f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 52104f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 52204f4d586SEd Maste 0x7fffffff, /* lowaddr */ 52304f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 52404f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 52504f4d586SEd Maste sc->aac_max_fibs_alloc * 52604f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 52704f4d586SEd Maste 1, /* nsegments */ 52804f4d586SEd Maste sc->aac_max_fibs_alloc * 52904f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 53004f4d586SEd Maste 0, /* flags */ 53104f4d586SEd Maste NULL, NULL, /* No locking needed */ 53204f4d586SEd Maste &sc->aac_fib_dmat)) { 533c2ede4b3SMartin Blapp device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); 53404f4d586SEd Maste return (ENOMEM); 53504f4d586SEd Maste } 53604f4d586SEd Maste 53704f4d586SEd Maste /* 53804f4d586SEd Maste * Create DMA tag for the common structure and allocate it. 53904f4d586SEd Maste */ 54004f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 54104f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 54204f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 54304f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 54404f4d586SEd Maste 0x7fffffff, /* lowaddr */ 54504f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 54604f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 54704f4d586SEd Maste 8192 + sizeof(struct aac_common), /* maxsize */ 54804f4d586SEd Maste 1, /* nsegments */ 54904f4d586SEd Maste BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 55004f4d586SEd Maste 0, /* flags */ 55104f4d586SEd Maste NULL, NULL, /* No locking needed */ 55204f4d586SEd Maste &sc->aac_common_dmat)) { 55304f4d586SEd Maste device_printf(sc->aac_dev, 55404f4d586SEd Maste "can't allocate common structure DMA tag\n"); 55504f4d586SEd Maste return (ENOMEM); 55604f4d586SEd Maste } 55704f4d586SEd Maste if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 55804f4d586SEd Maste BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 55904f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate common structure\n"); 56004f4d586SEd Maste return (ENOMEM); 56104f4d586SEd Maste } 56204f4d586SEd Maste 56304f4d586SEd Maste /* 56404f4d586SEd Maste * Work around a bug in the 2120 and 2200 that cannot DMA commands 56504f4d586SEd Maste * below address 8192 in physical memory. 56604f4d586SEd Maste * XXX If the padding is not needed, can it be put to use instead 56704f4d586SEd Maste * of ignored? 56804f4d586SEd Maste */ 56904f4d586SEd Maste (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 57004f4d586SEd Maste sc->aac_common, 8192 + sizeof(*sc->aac_common), 57104f4d586SEd Maste aac_common_map, sc, 0); 57204f4d586SEd Maste 57304f4d586SEd Maste if (sc->aac_common_busaddr < 8192) { 57404f4d586SEd Maste sc->aac_common = (struct aac_common *) 57504f4d586SEd Maste ((uint8_t *)sc->aac_common + 8192); 57604f4d586SEd Maste sc->aac_common_busaddr += 8192; 57704f4d586SEd Maste } 57804f4d586SEd Maste bzero(sc->aac_common, sizeof(*sc->aac_common)); 57904f4d586SEd Maste 58004f4d586SEd Maste /* Allocate some FIBs and associated command structs */ 58104f4d586SEd Maste TAILQ_INIT(&sc->aac_fibmap_tqh); 58204f4d586SEd Maste sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 58304f4d586SEd Maste M_AACBUF, M_WAITOK|M_ZERO); 58423e876b1SJung-uk Kim while (sc->total_fibs < sc->aac_max_fibs) { 58504f4d586SEd Maste if (aac_alloc_commands(sc) != 0) 58604f4d586SEd Maste break; 58704f4d586SEd Maste } 58804f4d586SEd Maste if (sc->total_fibs == 0) 58904f4d586SEd Maste return (ENOMEM); 59004f4d586SEd Maste 59104f4d586SEd Maste return (0); 59204f4d586SEd Maste } 59304f4d586SEd Maste 59404f4d586SEd Maste /* 59535863739SMike Smith * Free all of the resources associated with (sc) 59635863739SMike Smith * 59735863739SMike Smith * Should not be called if the controller is active. 59835863739SMike Smith */ 59935863739SMike Smith void 60035863739SMike Smith aac_free(struct aac_softc *sc) 60135863739SMike Smith { 602ffb37f33SScott Long 60331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 60435863739SMike Smith 60535863739SMike Smith /* remove the control device */ 60635863739SMike Smith if (sc->aac_dev_t != NULL) 60735863739SMike Smith destroy_dev(sc->aac_dev_t); 60835863739SMike Smith 6090b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 6108480cc63SScott Long aac_free_commands(sc); 6110b94a66eSMike Smith if (sc->aac_fib_dmat) 6120b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 61335863739SMike Smith 614ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 615ffb37f33SScott Long 61635863739SMike Smith /* destroy the common area */ 61735863739SMike Smith if (sc->aac_common) { 61835863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 619c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 620c6eafcf2SScott Long sc->aac_common_dmamap); 62135863739SMike Smith } 6220b94a66eSMike Smith if (sc->aac_common_dmat) 6230b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 62435863739SMike Smith 62535863739SMike Smith /* disconnect the interrupt handler */ 62635863739SMike Smith if (sc->aac_intr) 62735863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 62835863739SMike Smith if (sc->aac_irq != NULL) 629c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 630c6eafcf2SScott Long sc->aac_irq); 63135863739SMike Smith 63235863739SMike Smith /* destroy data-transfer DMA tag */ 63335863739SMike Smith if (sc->aac_buffer_dmat) 63435863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 63535863739SMike Smith 63635863739SMike Smith /* destroy the parent DMA tag */ 63735863739SMike Smith if (sc->aac_parent_dmat) 63835863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 63935863739SMike Smith 64035863739SMike Smith /* release the register window mapping */ 641ff0991c4SAttilio Rao if (sc->aac_regs_res0 != NULL) 642914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 643ff0991c4SAttilio Rao sc->aac_regs_rid0, sc->aac_regs_res0); 644ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) 645ff0991c4SAttilio Rao bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 646ff0991c4SAttilio Rao sc->aac_regs_rid1, sc->aac_regs_res1); 64735863739SMike Smith } 64835863739SMike Smith 649914da7d0SScott Long /* 65035863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 65135863739SMike Smith */ 65235863739SMike Smith int 65335863739SMike Smith aac_detach(device_t dev) 65435863739SMike Smith { 655914da7d0SScott Long struct aac_softc *sc; 65670545d1aSScott Long struct aac_container *co; 65770545d1aSScott Long struct aac_sim *sim; 65835863739SMike Smith int error; 65935863739SMike Smith 660914da7d0SScott Long sc = device_get_softc(dev); 66131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 662914da7d0SScott Long 66335863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 66435863739SMike Smith return(EBUSY); 66535863739SMike Smith 666ff0991c4SAttilio Rao callout_drain(&sc->aac_daemontime); 667ff0991c4SAttilio Rao 66870545d1aSScott Long /* Remove the child containers */ 669a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 67070545d1aSScott Long error = device_delete_child(dev, co->co_disk); 67170545d1aSScott Long if (error) 67270545d1aSScott Long return (error); 67365ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 674a761a1caSScott Long free(co, M_AACBUF); 67570545d1aSScott Long } 67670545d1aSScott Long 67770545d1aSScott Long /* Remove the CAM SIMs */ 678a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 679a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 68070545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 68170545d1aSScott Long if (error) 68270545d1aSScott Long return (error); 683a761a1caSScott Long free(sim, M_AACBUF); 68470545d1aSScott Long } 68570545d1aSScott Long 68636e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 68736e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 68836e0bf6eSScott Long wakeup(sc->aifthread); 68936e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 69036e0bf6eSScott Long } 69136e0bf6eSScott Long 69236e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 693a620bad0SEd Maste panic("Cannot shutdown AIF thread"); 69436e0bf6eSScott Long 69535863739SMike Smith if ((error = aac_shutdown(dev))) 69635863739SMike Smith return(error); 69735863739SMike Smith 6985f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 6995f54d522SScott Long 70035863739SMike Smith aac_free(sc); 70135863739SMike Smith 702dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 703dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 704dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 705dc9efde5SScott Long 70635863739SMike Smith return(0); 70735863739SMike Smith } 70835863739SMike Smith 709914da7d0SScott Long /* 71035863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 71135863739SMike Smith * 71235863739SMike Smith * This function is called before detach or system shutdown. 71335863739SMike Smith * 7140b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 71535863739SMike Smith * allow shutdown if any device is open. 71635863739SMike Smith */ 71735863739SMike Smith int 71835863739SMike Smith aac_shutdown(device_t dev) 71935863739SMike Smith { 720914da7d0SScott Long struct aac_softc *sc; 721cbfd045bSScott Long struct aac_fib *fib; 722cbfd045bSScott Long struct aac_close_command *cc; 72335863739SMike Smith 724914da7d0SScott Long sc = device_get_softc(dev); 72531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 726914da7d0SScott Long 72735863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 72835863739SMike Smith 72935863739SMike Smith /* 73035863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 73135863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 73235863739SMike Smith * We've been closed and all I/O completed already 73335863739SMike Smith */ 73435863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 73535863739SMike Smith 7367cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 73703b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 738cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 739cbfd045bSScott Long 74039ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 741cbfd045bSScott Long cc->Command = VM_CloseAll; 742cbfd045bSScott Long cc->ContainerId = 0xffffffff; 743cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 744cbfd045bSScott Long sizeof(struct aac_close_command))) 74535863739SMike Smith printf("FAILED.\n"); 74670545d1aSScott Long else 74770545d1aSScott Long printf("done\n"); 74870545d1aSScott Long #if 0 749914da7d0SScott Long else { 750cbfd045bSScott Long fib->data[0] = 0; 75136e0bf6eSScott Long /* 752914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 75336e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 75436e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 75536e0bf6eSScott Long * driver module with the intent to reload it later. 75636e0bf6eSScott Long */ 757cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 758cbfd045bSScott Long fib, 1)) { 75935863739SMike Smith printf("FAILED.\n"); 76035863739SMike Smith } else { 76135863739SMike Smith printf("done.\n"); 76235863739SMike Smith } 76335863739SMike Smith } 76470545d1aSScott Long #endif 76535863739SMike Smith 76635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 7673576af8fSScott Long aac_release_sync_fib(sc); 7687cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 76935863739SMike Smith 77035863739SMike Smith return(0); 77135863739SMike Smith } 77235863739SMike Smith 773914da7d0SScott Long /* 77435863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 77535863739SMike Smith */ 77635863739SMike Smith int 77735863739SMike Smith aac_suspend(device_t dev) 77835863739SMike Smith { 779914da7d0SScott Long struct aac_softc *sc; 78035863739SMike Smith 781914da7d0SScott Long sc = device_get_softc(dev); 782914da7d0SScott Long 78331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 78435863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 78535863739SMike Smith 78635863739SMike Smith AAC_MASK_INTERRUPTS(sc); 78735863739SMike Smith return(0); 78835863739SMike Smith } 78935863739SMike Smith 790914da7d0SScott Long /* 79135863739SMike Smith * Bring the controller back to a state ready for operation. 79235863739SMike Smith */ 79335863739SMike Smith int 79435863739SMike Smith aac_resume(device_t dev) 79535863739SMike Smith { 796914da7d0SScott Long struct aac_softc *sc; 79735863739SMike Smith 798914da7d0SScott Long sc = device_get_softc(dev); 799914da7d0SScott Long 80031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 80135863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 80235863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 80335863739SMike Smith return(0); 80435863739SMike Smith } 80535863739SMike Smith 806914da7d0SScott Long /* 8077cb209f5SScott Long * Interrupt handler for NEW_COMM interface. 80835863739SMike Smith */ 80935863739SMike Smith void 8107cb209f5SScott Long aac_new_intr(void *arg) 8117cb209f5SScott Long { 8127cb209f5SScott Long struct aac_softc *sc; 8137cb209f5SScott Long u_int32_t index, fast; 8147cb209f5SScott Long struct aac_command *cm; 8157cb209f5SScott Long struct aac_fib *fib; 8167cb209f5SScott Long int i; 8177cb209f5SScott Long 8187cb209f5SScott Long sc = (struct aac_softc *)arg; 8197cb209f5SScott Long 82031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 8217cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 8227cb209f5SScott Long while (1) { 8237cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8247cb209f5SScott Long if (index == 0xffffffff) 8257cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8267cb209f5SScott Long if (index == 0xffffffff) 8277cb209f5SScott Long break; 8287cb209f5SScott Long if (index & 2) { 8297cb209f5SScott Long if (index == 0xfffffffe) { 8307cb209f5SScott Long /* XXX This means that the controller wants 8317cb209f5SScott Long * more work. Ignore it for now. 8327cb209f5SScott Long */ 8337cb209f5SScott Long continue; 8347cb209f5SScott Long } 8357cb209f5SScott Long /* AIF */ 8367cb209f5SScott Long fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 8377cb209f5SScott Long M_NOWAIT | M_ZERO); 8387cb209f5SScott Long if (fib == NULL) { 8397cb209f5SScott Long /* If we're really this short on memory, 8407cb209f5SScott Long * hopefully breaking out of the handler will 8417cb209f5SScott Long * allow something to get freed. This 8427cb209f5SScott Long * actually sucks a whole lot. 8437cb209f5SScott Long */ 8447cb209f5SScott Long break; 8457cb209f5SScott Long } 8467cb209f5SScott Long index &= ~2; 8477cb209f5SScott Long for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 848ff0991c4SAttilio Rao ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); 8497cb209f5SScott Long aac_handle_aif(sc, fib); 8507cb209f5SScott Long free(fib, M_AACBUF); 8517cb209f5SScott Long 8527cb209f5SScott Long /* 8537cb209f5SScott Long * AIF memory is owned by the adapter, so let it 8547cb209f5SScott Long * know that we are done with it. 8557cb209f5SScott Long */ 8567cb209f5SScott Long AAC_SET_OUTB_QUEUE(sc, index); 8577cb209f5SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 8587cb209f5SScott Long } else { 8597cb209f5SScott Long fast = index & 1; 8607cb209f5SScott Long cm = sc->aac_commands + (index >> 2); 8617cb209f5SScott Long fib = cm->cm_fib; 8627cb209f5SScott Long if (fast) { 8637cb209f5SScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 8647cb209f5SScott Long *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 8657cb209f5SScott Long } 8667cb209f5SScott Long aac_remove_busy(cm); 8677cb209f5SScott Long aac_unmap_command(cm); 8687cb209f5SScott Long cm->cm_flags |= AAC_CMD_COMPLETED; 8697cb209f5SScott Long 8707cb209f5SScott Long /* is there a completion handler? */ 8717cb209f5SScott Long if (cm->cm_complete != NULL) { 8727cb209f5SScott Long cm->cm_complete(cm); 8737cb209f5SScott Long } else { 8747cb209f5SScott Long /* assume that someone is sleeping on this 8757cb209f5SScott Long * command 8767cb209f5SScott Long */ 8777cb209f5SScott Long wakeup(cm); 8787cb209f5SScott Long } 8797cb209f5SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 8807cb209f5SScott Long } 8817cb209f5SScott Long } 8827cb209f5SScott Long /* see if we can start some more I/O */ 8837cb209f5SScott Long if ((sc->flags & AAC_QUEUE_FRZN) == 0) 8847cb209f5SScott Long aac_startio(sc); 8857cb209f5SScott Long 8867cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 8877cb209f5SScott Long } 8887cb209f5SScott Long 889e46b9eeaSEd Maste /* 890e46b9eeaSEd Maste * Interrupt filter for !NEW_COMM interface. 891e46b9eeaSEd Maste */ 892ef544f63SPaolo Pisati int 893e46b9eeaSEd Maste aac_filter(void *arg) 89435863739SMike Smith { 895914da7d0SScott Long struct aac_softc *sc; 89670545d1aSScott Long u_int16_t reason; 89735863739SMike Smith 898914da7d0SScott Long sc = (struct aac_softc *)arg; 899914da7d0SScott Long 90031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 901f30ac74cSScott Long /* 9029148fa21SScott Long * Read the status register directly. This is faster than taking the 9039148fa21SScott Long * driver lock and reading the queues directly. It also saves having 9049148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 9059148fa21SScott Long * ugly. 906f30ac74cSScott Long */ 90735863739SMike Smith reason = AAC_GET_ISTATUS(sc); 908f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 909f30ac74cSScott Long 9109c3a7fceSScott Long /* handle completion processing */ 9119148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 9129148fa21SScott Long taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 91335863739SMike Smith 9149148fa21SScott Long /* controller wants to talk to us */ 9159148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 91670545d1aSScott Long /* 9179148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 9189148fa21SScott Long * that start with a NULL. 91970545d1aSScott Long */ 9209148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 9219148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 9229148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 92370545d1aSScott Long 9249148fa21SScott Long /* 9259148fa21SScott Long * This might miss doing the actual wakeup. However, the 926a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 9279148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 9289148fa21SScott Long * priority that they can handle hanging out for a few seconds 9299148fa21SScott Long * if needed. 9309148fa21SScott Long */ 93136e0bf6eSScott Long wakeup(sc->aifthread); 93236e0bf6eSScott Long } 933ef544f63SPaolo Pisati return (FILTER_HANDLED); 9349148fa21SScott Long } 93535863739SMike Smith 936c6eafcf2SScott Long /* 937914da7d0SScott Long * Command Processing 938914da7d0SScott Long */ 93935863739SMike Smith 940914da7d0SScott Long /* 94135863739SMike Smith * Start as much queued I/O as possible on the controller 94235863739SMike Smith */ 943fe3cb0e1SScott Long void 94435863739SMike Smith aac_startio(struct aac_softc *sc) 94535863739SMike Smith { 94635863739SMike Smith struct aac_command *cm; 947397fa34fSScott Long int error; 94835863739SMike Smith 94931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 95035863739SMike Smith 95135863739SMike Smith for (;;) { 952914da7d0SScott Long /* 953397fa34fSScott Long * This flag might be set if the card is out of resources. 954397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 955397fa34fSScott Long */ 956397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 957397fa34fSScott Long break; 958397fa34fSScott Long 959397fa34fSScott Long /* 960914da7d0SScott Long * Try to get a command that's been put off for lack of 961914da7d0SScott Long * resources 962914da7d0SScott Long */ 96335863739SMike Smith cm = aac_dequeue_ready(sc); 96435863739SMike Smith 965914da7d0SScott Long /* 966914da7d0SScott Long * Try to build a command off the bio queue (ignore error 967914da7d0SScott Long * return) 968914da7d0SScott Long */ 9690b94a66eSMike Smith if (cm == NULL) 97035863739SMike Smith aac_bio_command(sc, &cm); 97135863739SMike Smith 97235863739SMike Smith /* nothing to do? */ 97335863739SMike Smith if (cm == NULL) 97435863739SMike Smith break; 97535863739SMike Smith 976cd481291SScott Long /* don't map more than once */ 977cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 9784102d44bSScott Long panic("aac: command %p already mapped", cm); 97935863739SMike Smith 980397fa34fSScott Long /* 981397fa34fSScott Long * Set up the command to go to the controller. If there are no 982397fa34fSScott Long * data buffers associated with the command then it can bypass 983397fa34fSScott Long * busdma. 984397fa34fSScott Long */ 985cd481291SScott Long if (cm->cm_datalen != 0) { 986397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 987397fa34fSScott Long cm->cm_datamap, cm->cm_data, 988397fa34fSScott Long cm->cm_datalen, 989cd481291SScott Long aac_map_command_sg, cm, 0); 990cd481291SScott Long if (error == EINPROGRESS) { 99131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); 992cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 993cd481291SScott Long error = 0; 994614c22b2SScott Long } else if (error != 0) 995397fa34fSScott Long panic("aac_startio: unexpected error %d from " 996a620bad0SEd Maste "busdma", error); 997397fa34fSScott Long } else 9988778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 999cd481291SScott Long } 100035863739SMike Smith } 100135863739SMike Smith 1002914da7d0SScott Long /* 100335863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 100435863739SMike Smith */ 100535863739SMike Smith static void 100670545d1aSScott Long aac_command_thread(struct aac_softc *sc) 100735863739SMike Smith { 100835863739SMike Smith struct aac_fib *fib; 100935863739SMike Smith u_int32_t fib_size; 10109148fa21SScott Long int size, retval; 101135863739SMike Smith 101231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 101335863739SMike Smith 1014bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1015a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 101636e0bf6eSScott Long 1017a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1018a32a982dSScott Long 1019a32a982dSScott Long retval = 0; 1020a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1021a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1022a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 102336e0bf6eSScott Long 10249148fa21SScott Long /* 10259148fa21SScott Long * First see if any FIBs need to be allocated. This needs 10269148fa21SScott Long * to be called without the driver lock because contigmalloc 10279148fa21SScott Long * will grab Giant, and would result in an LOR. 10289148fa21SScott Long */ 10299148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1030bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 1031a32a982dSScott Long aac_alloc_commands(sc); 1032bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 10334102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1034a32a982dSScott Long aac_startio(sc); 1035a32a982dSScott Long } 10369148fa21SScott Long 10379148fa21SScott Long /* 10389148fa21SScott Long * While we're here, check to see if any commands are stuck. 10399148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 10409148fa21SScott Long * always fire. 10419148fa21SScott Long */ 10429148fa21SScott Long if (retval == EWOULDBLOCK) 104370545d1aSScott Long aac_timeout(sc); 104470545d1aSScott Long 104570545d1aSScott Long /* Check the hardware printf message buffer */ 10469148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 104770545d1aSScott Long aac_print_printf(sc); 104870545d1aSScott Long 10499148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 10507cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 10517cb209f5SScott Long continue; 10527cb209f5SScott Long for (;;) { 10537cb209f5SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 10547cb209f5SScott Long &fib_size, &fib)) 10557cb209f5SScott Long break; 105635863739SMike Smith 105736e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 105836e0bf6eSScott Long 105935863739SMike Smith switch (fib->Header.Command) { 106035863739SMike Smith case AifRequest: 106136e0bf6eSScott Long aac_handle_aif(sc, fib); 106235863739SMike Smith break; 106335863739SMike Smith default: 1064914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 1065914da7d0SScott Long "from controller\n"); 106635863739SMike Smith break; 106735863739SMike Smith } 106835863739SMike Smith 106936e0bf6eSScott Long if ((fib->Header.XferState == 0) || 10707cb209f5SScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 107136e0bf6eSScott Long break; 10727cb209f5SScott Long } 107336e0bf6eSScott Long 107470545d1aSScott Long /* Return the AIF to the controller. */ 107536e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 107636e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 107736e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 107836e0bf6eSScott Long 107936e0bf6eSScott Long /* XXX Compute the Size field? */ 108036e0bf6eSScott Long size = fib->Header.Size; 108136e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 108236e0bf6eSScott Long size = sizeof(struct aac_fib); 108336e0bf6eSScott Long fib->Header.Size = size; 108436e0bf6eSScott Long } 108536e0bf6eSScott Long /* 1086914da7d0SScott Long * Since we did not generate this command, it 1087914da7d0SScott Long * cannot go through the normal 1088914da7d0SScott Long * enqueue->startio chain. 108936e0bf6eSScott Long */ 1090914da7d0SScott Long aac_enqueue_response(sc, 1091914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 1092914da7d0SScott Long fib); 109336e0bf6eSScott Long } 109436e0bf6eSScott Long } 109536e0bf6eSScott Long } 109636e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1097bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 109836e0bf6eSScott Long wakeup(sc->aac_dev); 109936e0bf6eSScott Long 11003745c395SJulian Elischer kproc_exit(0); 110135863739SMike Smith } 110235863739SMike Smith 1103914da7d0SScott Long /* 11049c3a7fceSScott Long * Process completed commands. 110535863739SMike Smith */ 110635863739SMike Smith static void 11079c3a7fceSScott Long aac_complete(void *context, int pending) 110835863739SMike Smith { 11099c3a7fceSScott Long struct aac_softc *sc; 111035863739SMike Smith struct aac_command *cm; 111135863739SMike Smith struct aac_fib *fib; 111235863739SMike Smith u_int32_t fib_size; 111335863739SMike Smith 11149c3a7fceSScott Long sc = (struct aac_softc *)context; 111531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 11169c3a7fceSScott Long 1117bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1118ae543596SScott Long 11199c3a7fceSScott Long /* pull completed commands off the queue */ 112035863739SMike Smith for (;;) { 112135863739SMike Smith /* look for completed FIBs on our queue */ 1122914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1123914da7d0SScott Long &fib)) 112435863739SMike Smith break; /* nothing to do */ 112535863739SMike Smith 1126ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 1127cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 112835863739SMike Smith if (cm == NULL) { 112935863739SMike Smith AAC_PRINT_FIB(sc, fib); 11309c3a7fceSScott Long break; 11319c3a7fceSScott Long } 11320b94a66eSMike Smith aac_remove_busy(cm); 11337cb209f5SScott Long 1134ecd1c51fSScott Long aac_unmap_command(cm); 113535863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 113635863739SMike Smith 113735863739SMike Smith /* is there a completion handler? */ 113835863739SMike Smith if (cm->cm_complete != NULL) { 113935863739SMike Smith cm->cm_complete(cm); 114035863739SMike Smith } else { 114135863739SMike Smith /* assume that someone is sleeping on this command */ 114235863739SMike Smith wakeup(cm); 114335863739SMike Smith } 114435863739SMike Smith } 11450b94a66eSMike Smith 11460b94a66eSMike Smith /* see if we can start some more I/O */ 1147cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 11480b94a66eSMike Smith aac_startio(sc); 1149ae543596SScott Long 1150bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 115135863739SMike Smith } 115235863739SMike Smith 1153914da7d0SScott Long /* 115435863739SMike Smith * Handle a bio submitted from a disk device. 115535863739SMike Smith */ 115635863739SMike Smith void 115735863739SMike Smith aac_submit_bio(struct bio *bp) 115835863739SMike Smith { 1159914da7d0SScott Long struct aac_disk *ad; 1160914da7d0SScott Long struct aac_softc *sc; 116135863739SMike Smith 11627540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1163914da7d0SScott Long sc = ad->ad_controller; 116431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1165914da7d0SScott Long 116635863739SMike Smith /* queue the BIO and try to get some work done */ 11670b94a66eSMike Smith aac_enqueue_bio(sc, bp); 116835863739SMike Smith aac_startio(sc); 116935863739SMike Smith } 117035863739SMike Smith 1171914da7d0SScott Long /* 117235863739SMike Smith * Get a bio and build a command to go with it. 117335863739SMike Smith */ 117435863739SMike Smith static int 117535863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 117635863739SMike Smith { 117735863739SMike Smith struct aac_command *cm; 117835863739SMike Smith struct aac_fib *fib; 117935863739SMike Smith struct aac_disk *ad; 118035863739SMike Smith struct bio *bp; 118135863739SMike Smith 118231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 118335863739SMike Smith 118435863739SMike Smith /* get the resources we will need */ 118535863739SMike Smith cm = NULL; 1186a32a982dSScott Long bp = NULL; 118735863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 118835863739SMike Smith goto fail; 1189a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 1190a32a982dSScott Long goto fail; 119135863739SMike Smith 119235863739SMike Smith /* fill out the command */ 11930b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 11940b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 11950b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 119635863739SMike Smith cm->cm_private = bp; 11972b3b0f17SScott Long cm->cm_timestamp = time_uptime; 119835863739SMike Smith 119935863739SMike Smith /* build the FIB */ 120035863739SMike Smith fib = cm->cm_fib; 1201b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 120235863739SMike Smith fib->Header.XferState = 120335863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 120435863739SMike Smith AAC_FIBSTATE_INITIALISED | 1205f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 120635863739SMike Smith AAC_FIBSTATE_FROMHOST | 120735863739SMike Smith AAC_FIBSTATE_REXPECTED | 1208f30ac74cSScott Long AAC_FIBSTATE_NORM | 1209f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 1210f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 121135863739SMike Smith 121235863739SMike Smith /* build the read/write request */ 12137540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1214b85f5808SScott Long 12157cb209f5SScott Long if (sc->flags & AAC_FLAGS_RAW_IO) { 12167cb209f5SScott Long struct aac_raw_io *raw; 12177cb209f5SScott Long raw = (struct aac_raw_io *)&fib->data[0]; 12187cb209f5SScott Long fib->Header.Command = RawIo; 12197cb209f5SScott Long raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 12207cb209f5SScott Long raw->ByteCount = bp->bio_bcount; 12217cb209f5SScott Long raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 12227cb209f5SScott Long raw->BpTotal = 0; 12237cb209f5SScott Long raw->BpComplete = 0; 12247cb209f5SScott Long fib->Header.Size += sizeof(struct aac_raw_io); 12257cb209f5SScott Long cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 12267cb209f5SScott Long if (bp->bio_cmd == BIO_READ) { 12277cb209f5SScott Long raw->Flags = 1; 12287cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 12297cb209f5SScott Long } else { 12307cb209f5SScott Long raw->Flags = 0; 12317cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 12327cb209f5SScott Long } 12337cb209f5SScott Long } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1234b85f5808SScott Long fib->Header.Command = ContainerCommand; 12359e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 1236b85f5808SScott Long struct aac_blockread *br; 123735863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 123835863739SMike Smith br->Command = VM_CtBlockRead; 123935863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 124035863739SMike Smith br->BlockNumber = bp->bio_pblkno; 124135863739SMike Smith br->ByteCount = bp->bio_bcount; 124235863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 124335863739SMike Smith cm->cm_sgtable = &br->SgMap; 124435863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 124535863739SMike Smith } else { 1246b85f5808SScott Long struct aac_blockwrite *bw; 124735863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 124835863739SMike Smith bw->Command = VM_CtBlockWrite; 124935863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 125035863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 125135863739SMike Smith bw->ByteCount = bp->bio_bcount; 1252b85f5808SScott Long bw->Stable = CUNSTABLE; 125335863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 125435863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 125535863739SMike Smith cm->cm_sgtable = &bw->SgMap; 125635863739SMike Smith } 1257b85f5808SScott Long } else { 1258b85f5808SScott Long fib->Header.Command = ContainerCommand64; 1259b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 1260b85f5808SScott Long struct aac_blockread64 *br; 1261b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 1262b85f5808SScott Long br->Command = VM_CtHostRead64; 1263b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1264b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1265b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 1266b85f5808SScott Long br->Pad = 0; 1267b85f5808SScott Long br->Flags = 0; 1268b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 126954e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAIN; 1270eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1271b85f5808SScott Long } else { 1272b85f5808SScott Long struct aac_blockwrite64 *bw; 1273b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 1274b85f5808SScott Long bw->Command = VM_CtHostWrite64; 1275b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1276b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1277b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 1278b85f5808SScott Long bw->Pad = 0; 1279b85f5808SScott Long bw->Flags = 0; 1280b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 128154e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAOUT; 1282eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1283b85f5808SScott Long } 1284b85f5808SScott Long } 128535863739SMike Smith 128635863739SMike Smith *cmp = cm; 128735863739SMike Smith return(0); 128835863739SMike Smith 128935863739SMike Smith fail: 12907cb209f5SScott Long if (bp != NULL) 12917cb209f5SScott Long aac_enqueue_bio(sc, bp); 129235863739SMike Smith if (cm != NULL) 129335863739SMike Smith aac_release_command(cm); 129435863739SMike Smith return(ENOMEM); 129535863739SMike Smith } 129635863739SMike Smith 1297914da7d0SScott Long /* 129835863739SMike Smith * Handle a bio-instigated command that has been completed. 129935863739SMike Smith */ 130035863739SMike Smith static void 130135863739SMike Smith aac_bio_complete(struct aac_command *cm) 130235863739SMike Smith { 130335863739SMike Smith struct aac_blockread_response *brr; 130435863739SMike Smith struct aac_blockwrite_response *bwr; 130535863739SMike Smith struct bio *bp; 130635863739SMike Smith AAC_FSAStatus status; 130735863739SMike Smith 130835863739SMike Smith /* fetch relevant status and then release the command */ 130935863739SMike Smith bp = (struct bio *)cm->cm_private; 13109e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 131135863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 131235863739SMike Smith status = brr->Status; 131335863739SMike Smith } else { 131435863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 131535863739SMike Smith status = bwr->Status; 131635863739SMike Smith } 131735863739SMike Smith aac_release_command(cm); 131835863739SMike Smith 131935863739SMike Smith /* fix up the bio based on status */ 132035863739SMike Smith if (status == ST_OK) { 132135863739SMike Smith bp->bio_resid = 0; 132235863739SMike Smith } else { 132335863739SMike Smith bp->bio_error = EIO; 132435863739SMike Smith bp->bio_flags |= BIO_ERROR; 13250b94a66eSMike Smith /* pass an error string out to the disk layer */ 1326914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1327914da7d0SScott Long status); 132835863739SMike Smith } 13290b94a66eSMike Smith aac_biodone(bp); 133035863739SMike Smith } 133135863739SMike Smith 1332914da7d0SScott Long /* 133335863739SMike Smith * Submit a command to the controller, return when it completes. 1334b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1335b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1336d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1337d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1338d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1339d8a0a473SScott Long * card completing a command late and spamming the command and data 1340d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 134135863739SMike Smith */ 134235863739SMike Smith static int 1343d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 134435863739SMike Smith { 1345ae543596SScott Long struct aac_softc *sc; 1346d8a0a473SScott Long int error; 134735863739SMike Smith 1348ae543596SScott Long sc = cm->cm_sc; 134931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1350ae543596SScott Long 135135863739SMike Smith /* Put the command on the ready queue and get things going */ 135235863739SMike Smith aac_enqueue_ready(cm); 1353ae543596SScott Long aac_startio(sc); 1354ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 135535863739SMike Smith return(error); 135635863739SMike Smith } 135735863739SMike Smith 1358914da7d0SScott Long /* 1359914da7d0SScott Long *Command Buffer Management 1360914da7d0SScott Long */ 136135863739SMike Smith 1362914da7d0SScott Long /* 136335863739SMike Smith * Allocate a command. 136435863739SMike Smith */ 1365fe3cb0e1SScott Long int 136635863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 136735863739SMike Smith { 136835863739SMike Smith struct aac_command *cm; 136935863739SMike Smith 137031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 137135863739SMike Smith 1372ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1373b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1374ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1375ae543596SScott Long wakeup(sc->aifthread); 1376b85f5808SScott Long } 1377ae543596SScott Long return (EBUSY); 1378ffb37f33SScott Long } 137935863739SMike Smith 13800b94a66eSMike Smith *cmp = cm; 13810b94a66eSMike Smith return(0); 13820b94a66eSMike Smith } 13830b94a66eSMike Smith 1384914da7d0SScott Long /* 13850b94a66eSMike Smith * Release a command back to the freelist. 13860b94a66eSMike Smith */ 1387fe3cb0e1SScott Long void 13880b94a66eSMike Smith aac_release_command(struct aac_command *cm) 13890b94a66eSMike Smith { 13907cb209f5SScott Long struct aac_event *event; 13917cb209f5SScott Long struct aac_softc *sc; 13927cb209f5SScott Long 139331a0399eSEd Maste sc = cm->cm_sc; 139431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 13950b94a66eSMike Smith 13964109ba51SEd Maste /* (re)initialize the command/FIB */ 139735863739SMike Smith cm->cm_sgtable = NULL; 139835863739SMike Smith cm->cm_flags = 0; 139935863739SMike Smith cm->cm_complete = NULL; 140035863739SMike Smith cm->cm_private = NULL; 1401dbfc5960SEd Maste cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 140235863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 140335863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 140435863739SMike Smith cm->cm_fib->Header.Flags = 0; 14057cb209f5SScott Long cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 140635863739SMike Smith 140735863739SMike Smith /* 140835863739SMike Smith * These are duplicated in aac_start to cover the case where an 140935863739SMike Smith * intermediate stage may have destroyed them. They're left 14104109ba51SEd Maste * initialized here for debugging purposes only. 141135863739SMike Smith */ 1412f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1413f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 141435863739SMike Smith 141535863739SMike Smith aac_enqueue_free(cm); 14167cb209f5SScott Long 1417eb5cbaa0SEd Maste /* 1418eb5cbaa0SEd Maste * Dequeue all events so that there's no risk of events getting 1419eb5cbaa0SEd Maste * stranded. 1420eb5cbaa0SEd Maste */ 1421eb5cbaa0SEd Maste while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 14227cb209f5SScott Long TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 14237cb209f5SScott Long event->ev_callback(sc, event, event->ev_arg); 14247cb209f5SScott Long } 142535863739SMike Smith } 142635863739SMike Smith 1427914da7d0SScott Long /* 14280b94a66eSMike Smith * Map helper for command/FIB allocation. 142935863739SMike Smith */ 143035863739SMike Smith static void 14310b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 143235863739SMike Smith { 14337cb209f5SScott Long uint64_t *fibphys; 1434914da7d0SScott Long 14357cb209f5SScott Long fibphys = (uint64_t *)arg; 143635863739SMike Smith 1437ffb37f33SScott Long *fibphys = segs[0].ds_addr; 143835863739SMike Smith } 143935863739SMike Smith 1440914da7d0SScott Long /* 14414109ba51SEd Maste * Allocate and initialize commands/FIBs for this adapter. 144235863739SMike Smith */ 14430b94a66eSMike Smith static int 14440b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 144535863739SMike Smith { 144635863739SMike Smith struct aac_command *cm; 1447ffb37f33SScott Long struct aac_fibmap *fm; 14487cb209f5SScott Long uint64_t fibphys; 1449ffb37f33SScott Long int i, error; 145035863739SMike Smith 145131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 145235863739SMike Smith 14537cb209f5SScott Long if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1454ffb37f33SScott Long return (ENOMEM); 1455ffb37f33SScott Long 14568480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1457a6d35632SScott Long if (fm == NULL) 1458a6d35632SScott Long return (ENOMEM); 1459ffb37f33SScott Long 14600b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1461ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1462ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 146370545d1aSScott Long device_printf(sc->aac_dev, 146470545d1aSScott Long "Not enough contiguous memory available.\n"); 14658480cc63SScott Long free(fm, M_AACBUF); 14660b94a66eSMike Smith return (ENOMEM); 146735863739SMike Smith } 1468128aa5a0SScott Long 1469cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1470cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 14717cb209f5SScott Long sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1472ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1473128aa5a0SScott Long 14744109ba51SEd Maste /* initialize constant fields in the command structure */ 14757cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 14767cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 14778480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1478ffb37f33SScott Long fm->aac_commands = cm; 147935863739SMike Smith cm->cm_sc = sc; 14807cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 14817cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 14827cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1483cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 148435863739SMike Smith 1485ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 148693cfca22SScott Long &cm->cm_datamap)) != 0) 14878480cc63SScott Long break; 148893cfca22SScott Long mtx_lock(&sc->aac_io_lock); 148993cfca22SScott Long aac_release_command(cm); 14908480cc63SScott Long sc->total_fibs++; 149193cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 149235863739SMike Smith } 1493ffb37f33SScott Long 14948480cc63SScott Long if (i > 0) { 149593cfca22SScott Long mtx_lock(&sc->aac_io_lock); 1496ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 149731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1498bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 14990b94a66eSMike Smith return (0); 150035863739SMike Smith } 150135863739SMike Smith 15028480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 15038480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15048480cc63SScott Long free(fm, M_AACBUF); 15058480cc63SScott Long return (ENOMEM); 15068480cc63SScott Long } 15078480cc63SScott Long 1508914da7d0SScott Long /* 15090b94a66eSMike Smith * Free FIBs owned by this adapter. 151035863739SMike Smith */ 151135863739SMike Smith static void 15128480cc63SScott Long aac_free_commands(struct aac_softc *sc) 151335863739SMike Smith { 15148480cc63SScott Long struct aac_fibmap *fm; 1515ffb37f33SScott Long struct aac_command *cm; 151635863739SMike Smith int i; 151735863739SMike Smith 151831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 151935863739SMike Smith 15208480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 15218480cc63SScott Long 15228480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 15238480cc63SScott Long /* 15248480cc63SScott Long * We check against total_fibs to handle partially 15258480cc63SScott Long * allocated blocks. 15268480cc63SScott Long */ 15277cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1528ffb37f33SScott Long cm = fm->aac_commands + i; 1529ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1530ffb37f33SScott Long } 1531ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1532ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15338480cc63SScott Long free(fm, M_AACBUF); 15348480cc63SScott Long } 153535863739SMike Smith } 153635863739SMike Smith 1537914da7d0SScott Long /* 153835863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 153935863739SMike Smith */ 154035863739SMike Smith static void 154135863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 154235863739SMike Smith { 1543cd481291SScott Long struct aac_softc *sc; 1544914da7d0SScott Long struct aac_command *cm; 1545914da7d0SScott Long struct aac_fib *fib; 154635863739SMike Smith int i; 154735863739SMike Smith 1548914da7d0SScott Long cm = (struct aac_command *)arg; 1549cd481291SScott Long sc = cm->cm_sc; 1550914da7d0SScott Long fib = cm->cm_fib; 155131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1552914da7d0SScott Long 155335863739SMike Smith /* copy into the FIB */ 1554b85f5808SScott Long if (cm->cm_sgtable != NULL) { 15557cb209f5SScott Long if (fib->Header.Command == RawIo) { 15567cb209f5SScott Long struct aac_sg_tableraw *sg; 15577cb209f5SScott Long sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 15587cb209f5SScott Long sg->SgCount = nseg; 15597cb209f5SScott Long for (i = 0; i < nseg; i++) { 15607cb209f5SScott Long sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 15617cb209f5SScott Long sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 15627cb209f5SScott Long sg->SgEntryRaw[i].Next = 0; 15637cb209f5SScott Long sg->SgEntryRaw[i].Prev = 0; 15647cb209f5SScott Long sg->SgEntryRaw[i].Flags = 0; 15657cb209f5SScott Long } 15667cb209f5SScott Long /* update the FIB size for the s/g count */ 15677cb209f5SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 15687cb209f5SScott Long } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1569b85f5808SScott Long struct aac_sg_table *sg; 1570b85f5808SScott Long sg = cm->cm_sgtable; 157135863739SMike Smith sg->SgCount = nseg; 157235863739SMike Smith for (i = 0; i < nseg; i++) { 157335863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 157435863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 157535863739SMike Smith } 157635863739SMike Smith /* update the FIB size for the s/g count */ 157735863739SMike Smith fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1578b85f5808SScott Long } else { 1579b85f5808SScott Long struct aac_sg_table64 *sg; 1580b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1581b85f5808SScott Long sg->SgCount = nseg; 1582b85f5808SScott Long for (i = 0; i < nseg; i++) { 1583b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1584b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 158535863739SMike Smith } 1586b85f5808SScott Long /* update the FIB size for the s/g count */ 1587b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1588b85f5808SScott Long } 1589b85f5808SScott Long } 159035863739SMike Smith 1591cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1592cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 15937cb209f5SScott Long * the SenderFibAddress over to make room for the fast response bit 15947cb209f5SScott Long * and for the AIF bit 159535863739SMike Smith */ 15967cb209f5SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 15977cb209f5SScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 159835863739SMike Smith 1599cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1600cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 160135863739SMike Smith 160235863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1603c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1604c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 160535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1606c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1607c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 160835863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1609cd481291SScott Long 16107cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 16117cb209f5SScott Long int count = 10000000L; 16127cb209f5SScott Long while (AAC_SEND_COMMAND(sc, cm) != 0) { 16137cb209f5SScott Long if (--count == 0) { 16147cb209f5SScott Long aac_unmap_command(cm); 16157cb209f5SScott Long sc->flags |= AAC_QUEUE_FRZN; 16167cb209f5SScott Long aac_requeue_ready(cm); 16177cb209f5SScott Long } 16187cb209f5SScott Long DELAY(5); /* wait 5 usec. */ 16197cb209f5SScott Long } 16207cb209f5SScott Long } else { 1621397fa34fSScott Long /* Put the FIB on the outbound queue */ 16224102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 16234102d44bSScott Long aac_unmap_command(cm); 1624397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1625cd481291SScott Long aac_requeue_ready(cm); 16264102d44bSScott Long } 16277cb209f5SScott Long } 1628cd481291SScott Long 1629cd481291SScott Long return; 163035863739SMike Smith } 163135863739SMike Smith 1632914da7d0SScott Long /* 163335863739SMike Smith * Unmap a command from controller-visible space. 163435863739SMike Smith */ 163535863739SMike Smith static void 163635863739SMike Smith aac_unmap_command(struct aac_command *cm) 163735863739SMike Smith { 1638914da7d0SScott Long struct aac_softc *sc; 163935863739SMike Smith 1640914da7d0SScott Long sc = cm->cm_sc; 164131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1642914da7d0SScott Long 164335863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 164435863739SMike Smith return; 164535863739SMike Smith 164635863739SMike Smith if (cm->cm_datalen != 0) { 164735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1648c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1649c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 165035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1651c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1652c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 165335863739SMike Smith 165435863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 165535863739SMike Smith } 165635863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 165735863739SMike Smith } 165835863739SMike Smith 1659914da7d0SScott Long /* 1660914da7d0SScott Long * Hardware Interface 1661914da7d0SScott Long */ 166235863739SMike Smith 1663914da7d0SScott Long /* 16644109ba51SEd Maste * Initialize the adapter. 166535863739SMike Smith */ 166635863739SMike Smith static void 166735863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 166835863739SMike Smith { 1669914da7d0SScott Long struct aac_softc *sc; 167035863739SMike Smith 1671914da7d0SScott Long sc = (struct aac_softc *)arg; 167231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1673914da7d0SScott Long 167435863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 167535863739SMike Smith } 167635863739SMike Smith 1677a6d35632SScott Long static int 1678a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1679a6d35632SScott Long { 168004f4d586SEd Maste u_int32_t code, major, minor, options = 0, atu_size = 0; 1681a441b3fcSScott Long int status; 168204f4d586SEd Maste time_t then; 1683a6d35632SScott Long 168431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 168504f4d586SEd Maste /* 168604f4d586SEd Maste * Wait for the adapter to come ready. 168704f4d586SEd Maste */ 168804f4d586SEd Maste then = time_uptime; 168904f4d586SEd Maste do { 169004f4d586SEd Maste code = AAC_GET_FWSTATUS(sc); 169104f4d586SEd Maste if (code & AAC_SELF_TEST_FAILED) { 169204f4d586SEd Maste device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 169304f4d586SEd Maste return(ENXIO); 169404f4d586SEd Maste } 169504f4d586SEd Maste if (code & AAC_KERNEL_PANIC) { 169604f4d586SEd Maste device_printf(sc->aac_dev, 1697a620bad0SEd Maste "FATAL: controller kernel panic"); 169804f4d586SEd Maste return(ENXIO); 169904f4d586SEd Maste } 170004f4d586SEd Maste if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 170104f4d586SEd Maste device_printf(sc->aac_dev, 170204f4d586SEd Maste "FATAL: controller not coming ready, " 170304f4d586SEd Maste "status %x\n", code); 170404f4d586SEd Maste return(ENXIO); 170504f4d586SEd Maste } 170604f4d586SEd Maste } while (!(code & AAC_UP_AND_RUNNING)); 1707a6d35632SScott Long 1708fe94b852SScott Long /* 1709fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1710fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1711fe94b852SScott Long */ 1712a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1713fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1714fe94b852SScott Long NULL)) { 1715fe94b852SScott Long device_printf(sc->aac_dev, 1716fe94b852SScott Long "Error reading firmware version\n"); 1717fe94b852SScott Long return (EIO); 1718fe94b852SScott Long } 1719fe94b852SScott Long 1720fe94b852SScott Long /* These numbers are stored as ASCII! */ 1721a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1722a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1723fe94b852SScott Long if (major == 1) { 1724fe94b852SScott Long device_printf(sc->aac_dev, 1725fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1726fe94b852SScott Long major, minor); 1727fe94b852SScott Long return (EINVAL); 1728fe94b852SScott Long } 1729fe94b852SScott Long } 1730fe94b852SScott Long 1731a6d35632SScott Long /* 1732a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1733a441b3fcSScott Long * work-arounds to enable. Some firmware revs don't support this 1734a441b3fcSScott Long * command. 1735a6d35632SScott Long */ 1736a441b3fcSScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1737a441b3fcSScott Long if (status != AAC_SRB_STS_INVALID_REQUEST) { 1738a441b3fcSScott Long device_printf(sc->aac_dev, 1739a441b3fcSScott Long "RequestAdapterInfo failed\n"); 1740a6d35632SScott Long return (EIO); 1741a6d35632SScott Long } 1742a441b3fcSScott Long } else { 1743a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 17447cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1745a6d35632SScott Long sc->supported_options = options; 1746a6d35632SScott Long 1747a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1748a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1749a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1750a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1751a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1752cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1753cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1754a441b3fcSScott Long device_printf(sc->aac_dev, 1755a441b3fcSScott Long "Enabling 64-bit address support\n"); 1756a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1757a6d35632SScott Long } 1758a441b3fcSScott Long if ((options & AAC_SUPPORTED_NEW_COMM) 1759a441b3fcSScott Long && sc->aac_if.aif_send_command) 17607cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 17617cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 17627cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1763a441b3fcSScott Long } 1764a6d35632SScott Long 1765a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 17667cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 17677cb209f5SScott Long 17687cb209f5SScott Long /* Remap mem. resource, if required */ 17697cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1770ff0991c4SAttilio Rao atu_size > rman_get_size(sc->aac_regs_res1)) { 17717cb209f5SScott Long bus_release_resource( 17727cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 1773ff0991c4SAttilio Rao sc->aac_regs_rid1, sc->aac_regs_res1); 1774ff0991c4SAttilio Rao sc->aac_regs_res1 = bus_alloc_resource( 1775ff0991c4SAttilio Rao sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1, 17767cb209f5SScott Long 0ul, ~0ul, atu_size, RF_ACTIVE); 1777ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 1778ff0991c4SAttilio Rao sc->aac_regs_res1 = bus_alloc_resource_any( 17797cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 1780ff0991c4SAttilio Rao &sc->aac_regs_rid1, RF_ACTIVE); 1781ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 17827cb209f5SScott Long device_printf(sc->aac_dev, 17837cb209f5SScott Long "couldn't allocate register window\n"); 17847cb209f5SScott Long return (ENXIO); 17857cb209f5SScott Long } 17867cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 17877cb209f5SScott Long } 1788ff0991c4SAttilio Rao sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 1789ff0991c4SAttilio Rao sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 1790ff0991c4SAttilio Rao 1791ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK) { 1792ff0991c4SAttilio Rao sc->aac_regs_res0 = sc->aac_regs_res1; 1793ff0991c4SAttilio Rao sc->aac_regs_rid0 = sc->aac_regs_rid1; 1794ff0991c4SAttilio Rao sc->aac_btag0 = sc->aac_btag1; 1795ff0991c4SAttilio Rao sc->aac_bhandle0 = sc->aac_bhandle1; 1796ff0991c4SAttilio Rao } 17977cb209f5SScott Long } 17987cb209f5SScott Long 17997cb209f5SScott Long /* Read preferred settings */ 18007cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 18017cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 18027cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 1803a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18047e7a458eSEd Maste - sizeof(struct aac_blockwrite64)) 18057e7a458eSEd Maste / sizeof(struct aac_sg_entry64); 1806a6d35632SScott Long else 1807a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18087e7a458eSEd Maste - sizeof(struct aac_blockwrite)) 18097e7a458eSEd Maste / sizeof(struct aac_sg_entry); 1810a441b3fcSScott Long 18117cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 18127cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 18137cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 18147cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 18157cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 18167cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 18177cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 18187cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 18197cb209f5SScott Long } 18207cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 18217cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 18227cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1823a6d35632SScott Long 1824f355c0e0SEd Maste if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1825f355c0e0SEd Maste sc->flags |= AAC_FLAGS_RAW_IO; 1826f355c0e0SEd Maste device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1827f355c0e0SEd Maste } 1828523da39bSEd Maste if ((sc->flags & AAC_FLAGS_RAW_IO) && 1829523da39bSEd Maste (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1830523da39bSEd Maste sc->flags |= AAC_FLAGS_LBA_64BIT; 1831523da39bSEd Maste device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1832523da39bSEd Maste } 1833f355c0e0SEd Maste 1834fe94b852SScott Long return (0); 1835fe94b852SScott Long } 1836fe94b852SScott Long 183735863739SMike Smith static int 183835863739SMike Smith aac_init(struct aac_softc *sc) 183935863739SMike Smith { 184035863739SMike Smith struct aac_adapter_init *ip; 184104f4d586SEd Maste u_int32_t qoffset; 1842a6d35632SScott Long int error; 184335863739SMike Smith 184431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1845ffb37f33SScott Long 184635863739SMike Smith /* 1847914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1848914da7d0SScott Long * physical location of various important shared data structures. 184935863739SMike Smith */ 185035863739SMike Smith ip = &sc->aac_common->ac_init; 185135863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18527cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18537cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18547cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18557cb209f5SScott Long } 1856f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 185735863739SMike Smith 1858c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1859c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1860149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 186135863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 186235863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 186335863739SMike Smith 1864c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1865c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 186635863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 186735863739SMike Smith 18684b00f859SScott Long /* 18694b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18704b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18714b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18724b00f859SScott Long * Round up since the granularity is so high. 18734b00f859SScott Long */ 1874f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18754b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 18764b00f859SScott Long ip->HostPhysMemPages = 18774b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1878204c0befSScott Long } 18792b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 188035863739SMike Smith 18817cb209f5SScott Long ip->InitFlags = 0; 18827cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 18837cb209f5SScott Long ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 18847cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 18857cb209f5SScott Long } 18867cb209f5SScott Long 18877cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 18887cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 18897cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 18907cb209f5SScott Long 189135863739SMike Smith /* 18924109ba51SEd Maste * Initialize FIB queues. Note that it appears that the layout of the 1893c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1894c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 189535863739SMike Smith * 189635863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1897914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1898914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1899914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1900914da7d0SScott Long * does. 190135863739SMike Smith * 1902914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1903914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1904914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1905914da7d0SScott Long * virtue of a table. 190635863739SMike Smith */ 1907b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 19080bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 19090bcbebd6SScott Long sc->aac_queues = 19100bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1911b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 191235863739SMike Smith 1913c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1914c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1915c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1916c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1917c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1918c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1919c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1920c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1921c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1922c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1923c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1924c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1925c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1926c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1927c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1928c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1929c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1930c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1931c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1932c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1933c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1934c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1935c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1936c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1937c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1938c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1939c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1940c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1941c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1942c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1943c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1944c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1945c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1946c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1947c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1948c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1949c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1950c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1951c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1952c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1953c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1954c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1955c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1956c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1957c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1958c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1959c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1960c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 196135863739SMike Smith 196235863739SMike Smith /* 196335863739SMike Smith * Do controller-type-specific initialisation 196435863739SMike Smith */ 196535863739SMike Smith switch (sc->aac_hwif) { 196635863739SMike Smith case AAC_HWIF_I960RX: 1967ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); 196835863739SMike Smith break; 19694afedc31SScott Long case AAC_HWIF_RKT: 1970ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); 19714afedc31SScott Long break; 19724afedc31SScott Long default: 19734afedc31SScott Long break; 197435863739SMike Smith } 197535863739SMike Smith 197635863739SMike Smith /* 197735863739SMike Smith * Give the init structure to the controller. 197835863739SMike Smith */ 197935863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1980914da7d0SScott Long sc->aac_common_busaddr + 1981914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1982914da7d0SScott Long NULL)) { 1983914da7d0SScott Long device_printf(sc->aac_dev, 1984914da7d0SScott Long "error establishing init structure\n"); 1985a6d35632SScott Long error = EIO; 1986a6d35632SScott Long goto out; 198735863739SMike Smith } 198835863739SMike Smith 1989a6d35632SScott Long error = 0; 1990a6d35632SScott Long out: 1991a6d35632SScott Long return(error); 199235863739SMike Smith } 199335863739SMike Smith 199404f4d586SEd Maste static int 199504f4d586SEd Maste aac_setup_intr(struct aac_softc *sc) 199604f4d586SEd Maste { 199704f4d586SEd Maste sc->aac_irq_rid = 0; 199804f4d586SEd Maste if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 199904f4d586SEd Maste &sc->aac_irq_rid, 200004f4d586SEd Maste RF_SHAREABLE | 200104f4d586SEd Maste RF_ACTIVE)) == NULL) { 200204f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate interrupt\n"); 200304f4d586SEd Maste return (EINVAL); 200404f4d586SEd Maste } 200504f4d586SEd Maste if (sc->flags & AAC_FLAGS_NEW_COMM) { 200604f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 200704f4d586SEd Maste INTR_MPSAFE|INTR_TYPE_BIO, NULL, 200804f4d586SEd Maste aac_new_intr, sc, &sc->aac_intr)) { 200904f4d586SEd Maste device_printf(sc->aac_dev, "can't set up interrupt\n"); 201004f4d586SEd Maste return (EINVAL); 201104f4d586SEd Maste } 201204f4d586SEd Maste } else { 201304f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2014e46b9eeaSEd Maste INTR_TYPE_BIO, aac_filter, NULL, 201504f4d586SEd Maste sc, &sc->aac_intr)) { 201604f4d586SEd Maste device_printf(sc->aac_dev, 2017e46b9eeaSEd Maste "can't set up interrupt filter\n"); 201804f4d586SEd Maste return (EINVAL); 201904f4d586SEd Maste } 202004f4d586SEd Maste } 202104f4d586SEd Maste return (0); 202204f4d586SEd Maste } 202304f4d586SEd Maste 2024914da7d0SScott Long /* 202535863739SMike Smith * Send a synchronous command to the controller and wait for a result. 20267cb209f5SScott Long * Indicate if the controller completed the command with an error status. 202735863739SMike Smith */ 202835863739SMike Smith static int 202935863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 203035863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 203135863739SMike Smith u_int32_t *sp) 203235863739SMike Smith { 203335863739SMike Smith time_t then; 203435863739SMike Smith u_int32_t status; 203535863739SMike Smith 203631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 203735863739SMike Smith 203835863739SMike Smith /* populate the mailbox */ 203935863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 204035863739SMike Smith 204135863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 204235863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 204335863739SMike Smith 204435863739SMike Smith /* then set it to signal the adapter */ 204535863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 204635863739SMike Smith 204735863739SMike Smith /* spin waiting for the command to complete */ 20482b3b0f17SScott Long then = time_uptime; 204935863739SMike Smith do { 20502b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 205131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 205235863739SMike Smith return(EIO); 205335863739SMike Smith } 205435863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 205535863739SMike Smith 205635863739SMike Smith /* clear the completion flag */ 205735863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 205835863739SMike Smith 205935863739SMike Smith /* get the command status */ 2060a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 206135863739SMike Smith if (sp != NULL) 206235863739SMike Smith *sp = status; 20637cb209f5SScott Long 2064a441b3fcSScott Long if (status != AAC_SRB_STS_SUCCESS) 20657cb209f5SScott Long return (-1); 20660b94a66eSMike Smith return(0); 206735863739SMike Smith } 206835863739SMike Smith 2069cbfd045bSScott Long int 207035863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2071cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 207235863739SMike Smith { 207331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 20747cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 207535863739SMike Smith 207635863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 207735863739SMike Smith return(EINVAL); 207835863739SMike Smith 207935863739SMike Smith /* 208035863739SMike Smith * Set up the sync FIB 208135863739SMike Smith */ 2082914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2083914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2084c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 208535863739SMike Smith fib->Header.XferState |= xferstate; 208635863739SMike Smith fib->Header.Command = command; 208735863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 208842ef13a2SEd Maste fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 208935863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2090b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2091c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2092914da7d0SScott Long offsetof(struct aac_common, 2093914da7d0SScott Long ac_sync_fib); 209435863739SMike Smith 209535863739SMike Smith /* 209635863739SMike Smith * Give the FIB to the controller, wait for a response. 209735863739SMike Smith */ 2098914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2099914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 210031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 210135863739SMike Smith return(EIO); 210235863739SMike Smith } 210335863739SMike Smith 210435863739SMike Smith return (0); 210535863739SMike Smith } 210635863739SMike Smith 2107914da7d0SScott Long /* 210835863739SMike Smith * Adapter-space FIB queue manipulation 210935863739SMike Smith * 211035863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 211135863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 211235863739SMike Smith */ 211335863739SMike Smith static struct { 211435863739SMike Smith int size; 211535863739SMike Smith int notify; 211635863739SMike Smith } aac_qinfo[] = { 211735863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 211835863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 211935863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 212035863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 212135863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 212235863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 212335863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 212435863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 212535863739SMike Smith }; 212635863739SMike Smith 212735863739SMike Smith /* 2128c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2129c6eafcf2SScott Long * EBUSY if the queue is full. 213035863739SMike Smith * 21310b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2132914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2133914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2134c6eafcf2SScott Long * separate queue/notify interface). 213535863739SMike Smith */ 213635863739SMike Smith static int 2137f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 213835863739SMike Smith { 213935863739SMike Smith u_int32_t pi, ci; 21409e2e96d8SScott Long int error; 2141f6c4dd3fSScott Long u_int32_t fib_size; 2142f6c4dd3fSScott Long u_int32_t fib_addr; 2143f6c4dd3fSScott Long 214431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 214536e0bf6eSScott Long 2146f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2147f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 214835863739SMike Smith 214935863739SMike Smith /* get the producer/consumer indices */ 215035863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215135863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215235863739SMike Smith 215335863739SMike Smith /* wrap the queue? */ 215435863739SMike Smith if (pi >= aac_qinfo[queue].size) 215535863739SMike Smith pi = 0; 215635863739SMike Smith 215735863739SMike Smith /* check for queue full */ 215835863739SMike Smith if ((pi + 1) == ci) { 215935863739SMike Smith error = EBUSY; 216035863739SMike Smith goto out; 216135863739SMike Smith } 216235863739SMike Smith 2163614c22b2SScott Long /* 2164614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2165614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2166614c22b2SScott Long */ 2167614c22b2SScott Long aac_enqueue_busy(cm); 2168614c22b2SScott Long 216935863739SMike Smith /* populate queue entry */ 217035863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 217135863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 217235863739SMike Smith 217335863739SMike Smith /* update producer index */ 217435863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 217535863739SMike Smith 217635863739SMike Smith /* notify the adapter if we know how */ 217735863739SMike Smith if (aac_qinfo[queue].notify != 0) 217835863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 217935863739SMike Smith 218035863739SMike Smith error = 0; 218135863739SMike Smith 218235863739SMike Smith out: 218335863739SMike Smith return(error); 218435863739SMike Smith } 218535863739SMike Smith 218635863739SMike Smith /* 218736e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 218836e0bf6eSScott Long * success or ENOENT if the queue is empty. 218935863739SMike Smith */ 219035863739SMike Smith static int 2191c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2192c6eafcf2SScott Long struct aac_fib **fib_addr) 219335863739SMike Smith { 219435863739SMike Smith u_int32_t pi, ci; 2195149af931SScott Long u_int32_t fib_index; 21969e2e96d8SScott Long int error; 2197f6c4dd3fSScott Long int notify; 219835863739SMike Smith 219931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 220035863739SMike Smith 220135863739SMike Smith /* get the producer/consumer indices */ 220235863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 220335863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 220435863739SMike Smith 220535863739SMike Smith /* check for queue empty */ 220635863739SMike Smith if (ci == pi) { 220735863739SMike Smith error = ENOENT; 220835863739SMike Smith goto out; 220935863739SMike Smith } 221035863739SMike Smith 22117753acd2SScott Long /* wrap the pi so the following test works */ 22127753acd2SScott Long if (pi >= aac_qinfo[queue].size) 22137753acd2SScott Long pi = 0; 22147753acd2SScott Long 2215f6c4dd3fSScott Long notify = 0; 2216f6c4dd3fSScott Long if (ci == pi + 1) 2217f6c4dd3fSScott Long notify++; 2218f6c4dd3fSScott Long 221935863739SMike Smith /* wrap the queue? */ 222035863739SMike Smith if (ci >= aac_qinfo[queue].size) 222135863739SMike Smith ci = 0; 222235863739SMike Smith 222335863739SMike Smith /* fetch the entry */ 222435863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2225149af931SScott Long 2226149af931SScott Long switch (queue) { 2227149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2228149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2229149af931SScott Long /* 2230149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2231149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2232149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2233149af931SScott Long * Therefore, we have to convert it to an index. 2234149af931SScott Long */ 2235149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2236149af931SScott Long sizeof(struct aac_fib); 2237149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2238149af931SScott Long break; 2239149af931SScott Long 2240149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2241149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2242149af931SScott Long { 2243149af931SScott Long struct aac_command *cm; 2244149af931SScott Long 2245149af931SScott Long /* 2246149af931SScott Long * As above, an index is used instead of an actual address. 2247149af931SScott Long * Gotta shift the index to account for the fast response 2248149af931SScott Long * bit. No other correction is needed since this value was 2249149af931SScott Long * originally provided by the driver via the SenderFibAddress 2250149af931SScott Long * field. 2251149af931SScott Long */ 2252149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 22537cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2254149af931SScott Long *fib_addr = cm->cm_fib; 225535863739SMike Smith 2256f30ac74cSScott Long /* 2257f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2258149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2259f30ac74cSScott Long */ 2260149af931SScott Long if (fib_index & 0x01) { 2261f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2262f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2263f30ac74cSScott Long } 2264149af931SScott Long break; 2265149af931SScott Long } 2266149af931SScott Long default: 2267149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2268149af931SScott Long break; 2269149af931SScott Long } 2270149af931SScott Long 227135863739SMike Smith /* update consumer index */ 227235863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 227335863739SMike Smith 227435863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2275f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 227635863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227735863739SMike Smith error = 0; 227835863739SMike Smith 227935863739SMike Smith out: 228035863739SMike Smith return(error); 228135863739SMike Smith } 228235863739SMike Smith 2283914da7d0SScott Long /* 228436e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 228536e0bf6eSScott Long */ 228636e0bf6eSScott Long static int 228736e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 228836e0bf6eSScott Long { 228936e0bf6eSScott Long u_int32_t pi, ci; 22909e2e96d8SScott Long int error; 229136e0bf6eSScott Long u_int32_t fib_size; 229236e0bf6eSScott Long u_int32_t fib_addr; 229336e0bf6eSScott Long 229431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 229536e0bf6eSScott Long 229636e0bf6eSScott Long /* Tell the adapter where the FIB is */ 229736e0bf6eSScott Long fib_size = fib->Header.Size; 229836e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 229936e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 230036e0bf6eSScott Long 230136e0bf6eSScott Long /* get the producer/consumer indices */ 230236e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 230336e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 230436e0bf6eSScott Long 230536e0bf6eSScott Long /* wrap the queue? */ 230636e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 230736e0bf6eSScott Long pi = 0; 230836e0bf6eSScott Long 230936e0bf6eSScott Long /* check for queue full */ 231036e0bf6eSScott Long if ((pi + 1) == ci) { 231136e0bf6eSScott Long error = EBUSY; 231236e0bf6eSScott Long goto out; 231336e0bf6eSScott Long } 231436e0bf6eSScott Long 231536e0bf6eSScott Long /* populate queue entry */ 231636e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 231736e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 231836e0bf6eSScott Long 231936e0bf6eSScott Long /* update producer index */ 232036e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 232136e0bf6eSScott Long 232236e0bf6eSScott Long /* notify the adapter if we know how */ 232336e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 232436e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 232536e0bf6eSScott Long 232636e0bf6eSScott Long error = 0; 232736e0bf6eSScott Long 232836e0bf6eSScott Long out: 232936e0bf6eSScott Long return(error); 233036e0bf6eSScott Long } 233136e0bf6eSScott Long 2332914da7d0SScott Long /* 23330b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 23340b94a66eSMike Smith * and complain about them. 23350b94a66eSMike Smith */ 23360b94a66eSMike Smith static void 23370b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 23380b94a66eSMike Smith { 23390b94a66eSMike Smith struct aac_command *cm; 23400b94a66eSMike Smith time_t deadline; 234115c37be0SScott Long int timedout, code; 23420b94a66eSMike Smith 2343f6c4dd3fSScott Long /* 234470545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2345914da7d0SScott Long * only. 2346914da7d0SScott Long */ 234715c37be0SScott Long timedout = 0; 23482b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 23490b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2350f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2351f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 23520b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2353914da7d0SScott Long device_printf(sc->aac_dev, 23545aa4bb5bSEd Maste "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n", 23555aa4bb5bSEd Maste cm, cm->cm_fib->Header.Command, 23565aa4bb5bSEd Maste (int)(time_uptime-cm->cm_timestamp)); 23570b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 235815c37be0SScott Long timedout++; 23590b94a66eSMike Smith } 23600b94a66eSMike Smith } 23610b94a66eSMike Smith 236215c37be0SScott Long if (timedout) { 236315c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 236415c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 236515c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 236615c37be0SScott Long "longer running! code= 0x%x\n", code); 236715c37be0SScott Long } 236815c37be0SScott Long } 23690b94a66eSMike Smith return; 23700b94a66eSMike Smith } 23710b94a66eSMike Smith 2372914da7d0SScott Long /* 2373914da7d0SScott Long * Interface Function Vectors 2374914da7d0SScott Long */ 237535863739SMike Smith 2376914da7d0SScott Long /* 237735863739SMike Smith * Read the current firmware status word. 237835863739SMike Smith */ 237935863739SMike Smith static int 238035863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 238135863739SMike Smith { 238231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 238335863739SMike Smith 2384ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); 238535863739SMike Smith } 238635863739SMike Smith 238735863739SMike Smith static int 238835863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 238935863739SMike Smith { 239031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 239135863739SMike Smith 23924824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 23934824be88SEd Maste AAC_RX_OMR0 : AAC_RX_FWSTATUS)); 239435863739SMike Smith } 239535863739SMike Smith 2396b3457b51SScott Long static int 23974afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 23984afedc31SScott Long { 239931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24004afedc31SScott Long 24014824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 24024824be88SEd Maste AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); 24034afedc31SScott Long } 24044afedc31SScott Long 2405914da7d0SScott Long /* 240635863739SMike Smith * Notify the controller of a change in a given queue 240735863739SMike Smith */ 240835863739SMike Smith 240935863739SMike Smith static void 241035863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 241135863739SMike Smith { 241231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241335863739SMike Smith 2414ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 241535863739SMike Smith } 241635863739SMike Smith 241735863739SMike Smith static void 241835863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 241935863739SMike Smith { 242031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 242135863739SMike Smith 2422ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); 242335863739SMike Smith } 242435863739SMike Smith 2425b3457b51SScott Long static void 24264afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 24274afedc31SScott Long { 242831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24294afedc31SScott Long 2430ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); 24314afedc31SScott Long } 24324afedc31SScott Long 2433914da7d0SScott Long /* 243435863739SMike Smith * Get the interrupt reason bits 243535863739SMike Smith */ 243635863739SMike Smith static int 243735863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 243835863739SMike Smith { 243931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244035863739SMike Smith 2441ff0991c4SAttilio Rao return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); 244235863739SMike Smith } 244335863739SMike Smith 244435863739SMike Smith static int 244535863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 244635863739SMike Smith { 244731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244835863739SMike Smith 2449ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); 245035863739SMike Smith } 245135863739SMike Smith 2452b3457b51SScott Long static int 24534afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 24544afedc31SScott Long { 245531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24564afedc31SScott Long 2457ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); 24584afedc31SScott Long } 24594afedc31SScott Long 2460914da7d0SScott Long /* 246135863739SMike Smith * Clear some interrupt reason bits 246235863739SMike Smith */ 246335863739SMike Smith static void 246435863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 246535863739SMike Smith { 246631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 246735863739SMike Smith 2468ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 246935863739SMike Smith } 247035863739SMike Smith 247135863739SMike Smith static void 247235863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 247335863739SMike Smith { 247431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 247535863739SMike Smith 2476ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); 247735863739SMike Smith } 247835863739SMike Smith 2479b3457b51SScott Long static void 24804afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 24814afedc31SScott Long { 248231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24834afedc31SScott Long 2484ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); 24854afedc31SScott Long } 24864afedc31SScott Long 2487914da7d0SScott Long /* 248835863739SMike Smith * Populate the mailbox and set the command word 248935863739SMike Smith */ 249035863739SMike Smith static void 249135863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 249235863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249335863739SMike Smith { 249431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 249535863739SMike Smith 2496ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); 2497ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2498ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2499ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2500ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 250135863739SMike Smith } 250235863739SMike Smith 250335863739SMike Smith static void 250435863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 250535863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 250635863739SMike Smith { 250731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 250835863739SMike Smith 2509ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); 2510ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2511ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2512ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2513ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 251435863739SMike Smith } 251535863739SMike Smith 2516b3457b51SScott Long static void 25174afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25184afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 25194afedc31SScott Long { 252031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25214afedc31SScott Long 2522ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); 2523ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2524ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2525ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2526ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 25274afedc31SScott Long } 25284afedc31SScott Long 2529914da7d0SScott Long /* 253035863739SMike Smith * Fetch the immediate command status word 253135863739SMike Smith */ 253235863739SMike Smith static int 2533a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 253435863739SMike Smith { 253531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 253635863739SMike Smith 2537ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 253835863739SMike Smith } 253935863739SMike Smith 254035863739SMike Smith static int 2541a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 254235863739SMike Smith { 254331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 254435863739SMike Smith 2545ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 254635863739SMike Smith } 254735863739SMike Smith 2548b3457b51SScott Long static int 25494afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 25504afedc31SScott Long { 255131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25524afedc31SScott Long 2553ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 25544afedc31SScott Long } 25554afedc31SScott Long 2556914da7d0SScott Long /* 255735863739SMike Smith * Set/clear interrupt masks 255835863739SMike Smith */ 255935863739SMike Smith static void 256035863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 256135863739SMike Smith { 256231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 256335863739SMike Smith 256435863739SMike Smith if (enable) { 2565ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 256635863739SMike Smith } else { 2567ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 256835863739SMike Smith } 256935863739SMike Smith } 257035863739SMike Smith 257135863739SMike Smith static void 257235863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 257335863739SMike Smith { 257431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 257535863739SMike Smith 257635863739SMike Smith if (enable) { 25777cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2578ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 25797cb209f5SScott Long else 2580ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 258135863739SMike Smith } else { 2582ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); 258335863739SMike Smith } 258435863739SMike Smith } 258535863739SMike Smith 2586b3457b51SScott Long static void 25874afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 25884afedc31SScott Long { 258931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 25904afedc31SScott Long 25914afedc31SScott Long if (enable) { 25927cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2593ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 25947cb209f5SScott Long else 2595ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 25964afedc31SScott Long } else { 2597ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); 25984afedc31SScott Long } 25994afedc31SScott Long } 26004afedc31SScott Long 2601914da7d0SScott Long /* 26027cb209f5SScott Long * New comm. interface: Send command functions 26037cb209f5SScott Long */ 26047cb209f5SScott Long static int 26057cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 26067cb209f5SScott Long { 26077cb209f5SScott Long u_int32_t index, device; 26087cb209f5SScott Long 260931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 26107cb209f5SScott Long 2611ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 26127cb209f5SScott Long if (index == 0xffffffffL) 2613ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 26147cb209f5SScott Long if (index == 0xffffffffL) 26157cb209f5SScott Long return index; 26167cb209f5SScott Long aac_enqueue_busy(cm); 26177cb209f5SScott Long device = index; 2618ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26197cb209f5SScott Long device += 4; 2620ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26217cb209f5SScott Long device += 4; 2622ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2623ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); 26247cb209f5SScott Long return 0; 26257cb209f5SScott Long } 26267cb209f5SScott Long 26277cb209f5SScott Long static int 26287cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 26297cb209f5SScott Long { 26307cb209f5SScott Long u_int32_t index, device; 26317cb209f5SScott Long 263231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 26337cb209f5SScott Long 2634ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 26357cb209f5SScott Long if (index == 0xffffffffL) 2636ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 26377cb209f5SScott Long if (index == 0xffffffffL) 26387cb209f5SScott Long return index; 26397cb209f5SScott Long aac_enqueue_busy(cm); 26407cb209f5SScott Long device = index; 2641ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26427cb209f5SScott Long device += 4; 2643ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26447cb209f5SScott Long device += 4; 2645ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2646ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); 26477cb209f5SScott Long return 0; 26487cb209f5SScott Long } 26497cb209f5SScott Long 26507cb209f5SScott Long /* 26517cb209f5SScott Long * New comm. interface: get, set outbound queue index 26527cb209f5SScott Long */ 26537cb209f5SScott Long static int 26547cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 26557cb209f5SScott Long { 265631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26577cb209f5SScott Long 2658ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); 26597cb209f5SScott Long } 26607cb209f5SScott Long 26617cb209f5SScott Long static int 26627cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 26637cb209f5SScott Long { 266431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26657cb209f5SScott Long 2666ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); 26677cb209f5SScott Long } 26687cb209f5SScott Long 26697cb209f5SScott Long static void 26707cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 26717cb209f5SScott Long { 267231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26737cb209f5SScott Long 2674ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); 26757cb209f5SScott Long } 26767cb209f5SScott Long 26777cb209f5SScott Long static void 26787cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 26797cb209f5SScott Long { 268031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26817cb209f5SScott Long 2682ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); 26837cb209f5SScott Long } 26847cb209f5SScott Long 26857cb209f5SScott Long /* 2686914da7d0SScott Long * Debugging and Diagnostics 2687914da7d0SScott Long */ 268835863739SMike Smith 2689914da7d0SScott Long /* 269035863739SMike Smith * Print some information about the controller. 269135863739SMike Smith */ 269235863739SMike Smith static void 269335863739SMike Smith aac_describe_controller(struct aac_softc *sc) 269435863739SMike Smith { 2695cbfd045bSScott Long struct aac_fib *fib; 269635863739SMike Smith struct aac_adapter_info *info; 26977ea2d558SEd Maste char *adapter_type = "Adaptec RAID controller"; 269835863739SMike Smith 269931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 270035863739SMike Smith 270181b3da08SScott Long mtx_lock(&sc->aac_io_lock); 270203b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2703cbfd045bSScott Long 2704cbfd045bSScott Long fib->data[0] = 0; 2705cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 270635863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2707fe3cb0e1SScott Long aac_release_sync_fib(sc); 270881b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 270935863739SMike Smith return; 271035863739SMike Smith } 271135863739SMike Smith 2712bd971c49SScott Long /* save the kernel revision structure for later use */ 2713bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2714bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2715bd971c49SScott Long 2716bd971c49SScott Long if (bootverbose) { 2717b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2718b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2719c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2720b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2721b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2722b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2723914da7d0SScott Long aac_describe_code(aac_battery_platform, 2724914da7d0SScott Long info->batteryPlatform)); 272535863739SMike Smith 2726bd971c49SScott Long device_printf(sc->aac_dev, 2727bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 272835863739SMike Smith info->KernelRevision.external.comp.major, 272935863739SMike Smith info->KernelRevision.external.comp.minor, 273035863739SMike Smith info->KernelRevision.external.comp.dash, 273136e0bf6eSScott Long info->KernelRevision.buildNumber, 273236e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2733fe3cb0e1SScott Long 2734a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2735a6d35632SScott Long sc->supported_options, 2736a6d35632SScott Long "\20" 2737a6d35632SScott Long "\1SNAPSHOT" 2738a6d35632SScott Long "\2CLUSTERS" 2739a6d35632SScott Long "\3WCACHE" 2740a6d35632SScott Long "\4DATA64" 2741a6d35632SScott Long "\5HOSTTIME" 2742a6d35632SScott Long "\6RAID50" 2743a6d35632SScott Long "\7WINDOW4GB" 2744a6d35632SScott Long "\10SCSIUPGD" 2745a6d35632SScott Long "\11SOFTERR" 2746a6d35632SScott Long "\12NORECOND" 2747a6d35632SScott Long "\13SGMAP64" 2748a6d35632SScott Long "\14ALARM" 27497cb209f5SScott Long "\15NONDASD" 27507cb209f5SScott Long "\16SCSIMGT" 27517cb209f5SScott Long "\17RAIDSCSI" 27527cb209f5SScott Long "\21ADPTINFO" 27537cb209f5SScott Long "\22NEWCOMM" 27547cb209f5SScott Long "\23ARRAY64BIT" 27557cb209f5SScott Long "\24HEATSENSOR"); 2756a6d35632SScott Long } 275755aa1136SEd Maste 275855aa1136SEd Maste if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 275955aa1136SEd Maste fib->data[0] = 0; 276055aa1136SEd Maste if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 276155aa1136SEd Maste device_printf(sc->aac_dev, 276255aa1136SEd Maste "RequestSupplementAdapterInfo failed\n"); 276355aa1136SEd Maste else 276455aa1136SEd Maste adapter_type = ((struct aac_supplement_adapter_info *) 276555aa1136SEd Maste &fib->data[0])->AdapterTypeText; 276655aa1136SEd Maste } 276755aa1136SEd Maste device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 276855aa1136SEd Maste adapter_type, 27698e7e6335SEd Maste AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, 27708e7e6335SEd Maste AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); 277155aa1136SEd Maste 2772bd971c49SScott Long aac_release_sync_fib(sc); 277381b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 277435863739SMike Smith } 277535863739SMike Smith 2776914da7d0SScott Long /* 277735863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 277835863739SMike Smith * same. 277935863739SMike Smith */ 278035863739SMike Smith static char * 278135863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 278235863739SMike Smith { 278335863739SMike Smith int i; 278435863739SMike Smith 278535863739SMike Smith for (i = 0; table[i].string != NULL; i++) 278635863739SMike Smith if (table[i].code == code) 278735863739SMike Smith return(table[i].string); 278835863739SMike Smith return(table[i + 1].string); 278935863739SMike Smith } 279035863739SMike Smith 2791914da7d0SScott Long /* 2792914da7d0SScott Long * Management Interface 2793914da7d0SScott Long */ 279435863739SMike Smith 279535863739SMike Smith static int 279600b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 279735863739SMike Smith { 2798914da7d0SScott Long struct aac_softc *sc; 279935863739SMike Smith 2800914da7d0SScott Long sc = dev->si_drv1; 280131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2802a723a548SEd Maste sc->aac_open_cnt++; 280335863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 280435863739SMike Smith 280535863739SMike Smith return 0; 280635863739SMike Smith } 280735863739SMike Smith 280835863739SMike Smith static int 280900b4e54aSWarner Losh aac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 281035863739SMike Smith { 2811914da7d0SScott Long struct aac_softc *sc; 281235863739SMike Smith 2813914da7d0SScott Long sc = dev->si_drv1; 281431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2815a723a548SEd Maste sc->aac_open_cnt--; 281635863739SMike Smith /* Mark this unit as no longer open */ 2817a723a548SEd Maste if (sc->aac_open_cnt == 0) 281835863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 281935863739SMike Smith 282035863739SMike Smith return 0; 282135863739SMike Smith } 282235863739SMike Smith 282335863739SMike Smith static int 282400b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 282535863739SMike Smith { 2826914da7d0SScott Long union aac_statrequest *as; 2827914da7d0SScott Long struct aac_softc *sc; 28280b94a66eSMike Smith int error = 0; 282935863739SMike Smith 2830914da7d0SScott Long as = (union aac_statrequest *)arg; 2831914da7d0SScott Long sc = dev->si_drv1; 283231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2833914da7d0SScott Long 283435863739SMike Smith switch (cmd) { 28350b94a66eSMike Smith case AACIO_STATS: 28360b94a66eSMike Smith switch (as->as_item) { 28370b94a66eSMike Smith case AACQ_FREE: 28380b94a66eSMike Smith case AACQ_BIO: 28390b94a66eSMike Smith case AACQ_READY: 28400b94a66eSMike Smith case AACQ_BUSY: 2841c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2842c6eafcf2SScott Long sizeof(struct aac_qstat)); 28430b94a66eSMike Smith break; 28440b94a66eSMike Smith default: 28450b94a66eSMike Smith error = ENOENT; 28460b94a66eSMike Smith break; 28470b94a66eSMike Smith } 28480b94a66eSMike Smith break; 28490b94a66eSMike Smith 285035863739SMike Smith case FSACTL_SENDFIB: 2851f355c0e0SEd Maste case FSACTL_SEND_LARGE_FIB: 2852fb0c27d7SScott Long arg = *(caddr_t*)arg; 2853fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 2854f355c0e0SEd Maste case FSACTL_LNX_SEND_LARGE_FIB: 285531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 285635863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 285735863739SMike Smith break; 2858f355c0e0SEd Maste case FSACTL_SEND_RAW_SRB: 2859f355c0e0SEd Maste arg = *(caddr_t*)arg; 2860f355c0e0SEd Maste case FSACTL_LNX_SEND_RAW_SRB: 286131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2862f355c0e0SEd Maste error = aac_ioctl_send_raw_srb(sc, arg); 2863f355c0e0SEd Maste break; 286435863739SMike Smith case FSACTL_AIF_THREAD: 2865fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 286631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 286735863739SMike Smith error = EINVAL; 286835863739SMike Smith break; 286935863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2870fb0c27d7SScott Long arg = *(caddr_t*)arg; 2871fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 287231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2873a723a548SEd Maste error = aac_open_aif(sc, arg); 287435863739SMike Smith break; 287535863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2876fb0c27d7SScott Long arg = *(caddr_t*)arg; 2877fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 287831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2879fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 288035863739SMike Smith break; 288135863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2882a723a548SEd Maste arg = *(caddr_t*)arg; 2883fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 288431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2885a723a548SEd Maste error = aac_close_aif(sc, arg); 288635863739SMike Smith break; 288735863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2888fb0c27d7SScott Long arg = *(caddr_t*)arg; 2889fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 289031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2891fb0c27d7SScott Long error = aac_rev_check(sc, arg); 289235863739SMike Smith break; 289336e0bf6eSScott Long case FSACTL_QUERY_DISK: 289436e0bf6eSScott Long arg = *(caddr_t*)arg; 289536e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 289631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 289736e0bf6eSScott Long error = aac_query_disk(sc, arg); 289836e0bf6eSScott Long break; 289936e0bf6eSScott Long case FSACTL_DELETE_DISK: 290036e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2901914da7d0SScott Long /* 2902914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2903914da7d0SScott Long * container, rather we rely on an AIF coming from the 2904914da7d0SScott Long * controller 2905914da7d0SScott Long */ 290636e0bf6eSScott Long error = 0; 290736e0bf6eSScott Long break; 29087cb209f5SScott Long case FSACTL_GET_PCI_INFO: 29097cb209f5SScott Long arg = *(caddr_t*)arg; 29107cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 291131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 29127cb209f5SScott Long error = aac_get_pci_info(sc, arg); 29137cb209f5SScott Long break; 29146d307336SEd Maste case FSACTL_GET_FEATURES: 29156d307336SEd Maste arg = *(caddr_t*)arg; 29166d307336SEd Maste case FSACTL_LNX_GET_FEATURES: 29176d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 29186d307336SEd Maste error = aac_supported_features(sc, arg); 29196d307336SEd Maste break; 292035863739SMike Smith default: 292131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 292235863739SMike Smith error = EINVAL; 292335863739SMike Smith break; 292435863739SMike Smith } 292535863739SMike Smith return(error); 292635863739SMike Smith } 292735863739SMike Smith 2928b3457b51SScott Long static int 292900b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td) 2930b3457b51SScott Long { 2931b3457b51SScott Long struct aac_softc *sc; 2932ef0b687cSEd Maste struct aac_fib_context *ctx; 2933b3457b51SScott Long int revents; 2934b3457b51SScott Long 2935b3457b51SScott Long sc = dev->si_drv1; 2936b3457b51SScott Long revents = 0; 2937b3457b51SScott Long 2938bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2939b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2940ef0b687cSEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 2941ef0b687cSEd Maste if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 2942b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2943ef0b687cSEd Maste break; 2944ef0b687cSEd Maste } 2945ef0b687cSEd Maste } 2946b3457b51SScott Long } 2947bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2948b3457b51SScott Long 2949b3457b51SScott Long if (revents == 0) { 2950b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2951b3457b51SScott Long selrecord(td, &sc->rcv_select); 2952b3457b51SScott Long } 2953b3457b51SScott Long 2954b3457b51SScott Long return (revents); 2955b3457b51SScott Long } 2956b3457b51SScott Long 29577cb209f5SScott Long static void 29587cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 29597cb209f5SScott Long { 29607cb209f5SScott Long 29617cb209f5SScott Long switch (event->ev_type) { 29627cb209f5SScott Long case AAC_EVENT_CMFREE: 29630c40d5beSEd Maste mtx_assert(&sc->aac_io_lock, MA_OWNED); 29641a681311SLuoqi Chen if (aac_alloc_command(sc, (struct aac_command **)arg)) { 29657cb209f5SScott Long aac_add_event(sc, event); 29667cb209f5SScott Long return; 29677cb209f5SScott Long } 29687cb209f5SScott Long free(event, M_AACBUF); 29698eeb2ca6SScott Long wakeup(arg); 29707cb209f5SScott Long break; 29717cb209f5SScott Long default: 29727cb209f5SScott Long break; 29737cb209f5SScott Long } 29747cb209f5SScott Long } 29757cb209f5SScott Long 2976914da7d0SScott Long /* 297735863739SMike Smith * Send a FIB supplied from userspace 297835863739SMike Smith */ 297935863739SMike Smith static int 298035863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 298135863739SMike Smith { 298235863739SMike Smith struct aac_command *cm; 298335863739SMike Smith int size, error; 298435863739SMike Smith 298531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 298635863739SMike Smith 298735863739SMike Smith cm = NULL; 298835863739SMike Smith 298935863739SMike Smith /* 299035863739SMike Smith * Get a command 299135863739SMike Smith */ 2992bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 299335863739SMike Smith if (aac_alloc_command(sc, &cm)) { 29947cb209f5SScott Long struct aac_event *event; 29957cb209f5SScott Long 29967cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 29977cb209f5SScott Long M_NOWAIT | M_ZERO); 29987cb209f5SScott Long if (event == NULL) { 299935863739SMike Smith error = EBUSY; 3000f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 300135863739SMike Smith goto out; 300235863739SMike Smith } 30037cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 30047cb209f5SScott Long event->ev_callback = aac_ioctl_event; 30057cb209f5SScott Long event->ev_arg = &cm; 30067cb209f5SScott Long aac_add_event(sc, event); 30078eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 30087cb209f5SScott Long } 300993cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 301035863739SMike Smith 301135863739SMike Smith /* 301235863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 301335863739SMike Smith */ 3014914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 3015914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 301635863739SMike Smith goto out; 301735863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 3018f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3019f355c0e0SEd Maste device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 3020f355c0e0SEd Maste size, sc->aac_max_fib_size); 3021f355c0e0SEd Maste size = sc->aac_max_fib_size; 302235863739SMike Smith } 302335863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 302435863739SMike Smith goto out; 302535863739SMike Smith cm->cm_fib->Header.Size = size; 30262b3b0f17SScott Long cm->cm_timestamp = time_uptime; 302735863739SMike Smith 302835863739SMike Smith /* 302935863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 303035863739SMike Smith */ 303193cfca22SScott Long mtx_lock(&sc->aac_io_lock); 3032f16627aaSEd Maste error = aac_wait_command(cm); 3033f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 3034f16627aaSEd Maste if (error != 0) { 303570545d1aSScott Long device_printf(sc->aac_dev, 303670545d1aSScott Long "aac_wait_command return %d\n", error); 303735863739SMike Smith goto out; 3038b3457b51SScott Long } 303935863739SMike Smith 304035863739SMike Smith /* 304135863739SMike Smith * Copy the FIB and data back out to the caller. 304235863739SMike Smith */ 304335863739SMike Smith size = cm->cm_fib->Header.Size; 3044f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3045f355c0e0SEd Maste device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 3046f355c0e0SEd Maste size, sc->aac_max_fib_size); 3047f355c0e0SEd Maste size = sc->aac_max_fib_size; 304835863739SMike Smith } 304935863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 305035863739SMike Smith 305135863739SMike Smith out: 3052f6c4dd3fSScott Long if (cm != NULL) { 3053f16627aaSEd Maste mtx_lock(&sc->aac_io_lock); 305435863739SMike Smith aac_release_command(cm); 3055bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 3056f16627aaSEd Maste } 305735863739SMike Smith return(error); 305835863739SMike Smith } 305935863739SMike Smith 3060914da7d0SScott Long /* 3061f355c0e0SEd Maste * Send a passthrough FIB supplied from userspace 3062f355c0e0SEd Maste */ 3063f355c0e0SEd Maste static int 3064f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 3065f355c0e0SEd Maste { 3066f355c0e0SEd Maste return (EINVAL); 3067f355c0e0SEd Maste } 3068f355c0e0SEd Maste 3069f355c0e0SEd Maste /* 307035863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 307136e0bf6eSScott Long * If the queue fills up, then drop the older entries. 307235863739SMike Smith */ 307335863739SMike Smith static void 307436e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 307535863739SMike Smith { 307636e0bf6eSScott Long struct aac_aif_command *aif; 307736e0bf6eSScott Long struct aac_container *co, *co_next; 3078a723a548SEd Maste struct aac_fib_context *ctx; 307904f4d586SEd Maste struct aac_mntinforesp *mir; 3080a723a548SEd Maste int next, current, found; 3081795d7dc0SScott Long int count = 0, added = 0, i = 0; 308235863739SMike Smith 308331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 308435863739SMike Smith 308536e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 308636e0bf6eSScott Long aac_print_aif(sc, aif); 308736e0bf6eSScott Long 308836e0bf6eSScott Long /* Is it an event that we should care about? */ 308936e0bf6eSScott Long switch (aif->command) { 309036e0bf6eSScott Long case AifCmdEventNotify: 309136e0bf6eSScott Long switch (aif->data.EN.type) { 309236e0bf6eSScott Long case AifEnAddContainer: 309336e0bf6eSScott Long case AifEnDeleteContainer: 309436e0bf6eSScott Long /* 3095914da7d0SScott Long * A container was added or deleted, but the message 3096914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3097914da7d0SScott Long * containers and sort things out. 309836e0bf6eSScott Long */ 309903b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 310036e0bf6eSScott Long do { 310136e0bf6eSScott Long /* 3102914da7d0SScott Long * Ask the controller for its containers one at 3103914da7d0SScott Long * a time. 3104914da7d0SScott Long * XXX What if the controller's list changes 3105914da7d0SScott Long * midway through this enumaration? 310636e0bf6eSScott Long * XXX This should be done async. 310736e0bf6eSScott Long */ 310804f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 310936e0bf6eSScott Long continue; 311004f4d586SEd Maste if (i == 0) 3111795d7dc0SScott Long count = mir->MntRespCount; 311236e0bf6eSScott Long /* 3113914da7d0SScott Long * Check the container against our list. 3114914da7d0SScott Long * co->co_found was already set to 0 in a 3115914da7d0SScott Long * previous run. 311636e0bf6eSScott Long */ 3117cbfd045bSScott Long if ((mir->Status == ST_OK) && 3118cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 311936e0bf6eSScott Long found = 0; 3120914da7d0SScott Long TAILQ_FOREACH(co, 3121914da7d0SScott Long &sc->aac_container_tqh, 3122914da7d0SScott Long co_link) { 312336e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3124cbfd045bSScott Long mir->MntTable[0].ObjectId) { 312536e0bf6eSScott Long co->co_found = 1; 312636e0bf6eSScott Long found = 1; 312736e0bf6eSScott Long break; 312836e0bf6eSScott Long } 312936e0bf6eSScott Long } 3130914da7d0SScott Long /* 3131914da7d0SScott Long * If the container matched, continue 3132914da7d0SScott Long * in the list. 3133914da7d0SScott Long */ 313436e0bf6eSScott Long if (found) { 313536e0bf6eSScott Long i++; 313636e0bf6eSScott Long continue; 313736e0bf6eSScott Long } 313836e0bf6eSScott Long 313936e0bf6eSScott Long /* 3140914da7d0SScott Long * This is a new container. Do all the 314170545d1aSScott Long * appropriate things to set it up. 314270545d1aSScott Long */ 3143cbfd045bSScott Long aac_add_container(sc, mir, 1); 314436e0bf6eSScott Long added = 1; 314536e0bf6eSScott Long } 314636e0bf6eSScott Long i++; 3147795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3148cbfd045bSScott Long aac_release_sync_fib(sc); 314936e0bf6eSScott Long 315036e0bf6eSScott Long /* 3151914da7d0SScott Long * Go through our list of containers and see which ones 3152914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3153914da7d0SScott Long * list them they must have been deleted. Do the 3154914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3155914da7d0SScott Long * the co->co_found field. 315636e0bf6eSScott Long */ 315736e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 315836e0bf6eSScott Long while (co != NULL) { 315936e0bf6eSScott Long if (co->co_found == 0) { 31607cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3161a56fe095SJohn Baldwin mtx_lock(&Giant); 3162914da7d0SScott Long device_delete_child(sc->aac_dev, 3163914da7d0SScott Long co->co_disk); 3164a56fe095SJohn Baldwin mtx_unlock(&Giant); 31657cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 316636e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3167bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3168914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3169914da7d0SScott Long co_link); 3170bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3171ba1d57e7SScott Long free(co, M_AACBUF); 317236e0bf6eSScott Long co = co_next; 317336e0bf6eSScott Long } else { 317436e0bf6eSScott Long co->co_found = 0; 317536e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 317636e0bf6eSScott Long } 317736e0bf6eSScott Long } 317836e0bf6eSScott Long 317936e0bf6eSScott Long /* Attach the newly created containers */ 31807cb209f5SScott Long if (added) { 31817cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3182a56fe095SJohn Baldwin mtx_lock(&Giant); 318336e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 3184a56fe095SJohn Baldwin mtx_unlock(&Giant); 31857cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 31867cb209f5SScott Long } 318736e0bf6eSScott Long 318836e0bf6eSScott Long break; 318936e0bf6eSScott Long 319036e0bf6eSScott Long default: 319136e0bf6eSScott Long break; 319236e0bf6eSScott Long } 319336e0bf6eSScott Long 319436e0bf6eSScott Long default: 319536e0bf6eSScott Long break; 319636e0bf6eSScott Long } 319736e0bf6eSScott Long 319836e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3199bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3200a723a548SEd Maste current = sc->aifq_idx; 3201a723a548SEd Maste next = (current + 1) % AAC_AIFQ_LENGTH; 3202a723a548SEd Maste if (next == 0) 3203a723a548SEd Maste sc->aifq_filled = 1; 3204a723a548SEd Maste bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3205a723a548SEd Maste /* modify AIF contexts */ 3206a723a548SEd Maste if (sc->aifq_filled) { 3207a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3208a723a548SEd Maste if (next == ctx->ctx_idx) 3209a723a548SEd Maste ctx->ctx_wrap = 1; 3210a723a548SEd Maste else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3211a723a548SEd Maste ctx->ctx_idx = next; 3212a723a548SEd Maste } 3213a723a548SEd Maste } 3214a723a548SEd Maste sc->aifq_idx = next; 3215b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 321635863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 321735863739SMike Smith wakeup(sc->aac_aifq); 3218b3457b51SScott Long /* Wakeup any poll()ers */ 3219512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 3220bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 322136e0bf6eSScott Long 322236e0bf6eSScott Long return; 322335863739SMike Smith } 322435863739SMike Smith 3225914da7d0SScott Long /* 32260b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 322736e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 322836e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 322936e0bf6eSScott Long * returning what the card reported. 323035863739SMike Smith */ 323135863739SMike Smith static int 3232fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 323335863739SMike Smith { 323435863739SMike Smith struct aac_rev_check rev_check; 323535863739SMike Smith struct aac_rev_check_resp rev_check_resp; 323635863739SMike Smith int error = 0; 323735863739SMike Smith 323831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 323935863739SMike Smith 324035863739SMike Smith /* 324135863739SMike Smith * Copyin the revision struct from userspace 324235863739SMike Smith */ 3243c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3244c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 324535863739SMike Smith return error; 324635863739SMike Smith } 324735863739SMike Smith 324831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3249914da7d0SScott Long rev_check.callingRevision.buildNumber); 325035863739SMike Smith 325135863739SMike Smith /* 325235863739SMike Smith * Doctor up the response struct. 325335863739SMike Smith */ 325435863739SMike Smith rev_check_resp.possiblyCompatible = 1; 32558e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.major = 32568e7e6335SEd Maste AAC_DRIVER_MAJOR_VERSION; 32578e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.minor = 32588e7e6335SEd Maste AAC_DRIVER_MINOR_VERSION; 32598e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.type = 32608e7e6335SEd Maste AAC_DRIVER_TYPE; 32618e7e6335SEd Maste rev_check_resp.adapterSWRevision.external.comp.dash = 32628e7e6335SEd Maste AAC_DRIVER_BUGFIX_LEVEL; 3263914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 32648e7e6335SEd Maste AAC_DRIVER_BUILD; 326535863739SMike Smith 3266c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3267c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 326835863739SMike Smith } 326935863739SMike Smith 3270914da7d0SScott Long /* 3271a723a548SEd Maste * Pass the fib context to the caller 3272a723a548SEd Maste */ 3273a723a548SEd Maste static int 3274a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg) 3275a723a548SEd Maste { 3276a723a548SEd Maste struct aac_fib_context *fibctx, *ctx; 3277a723a548SEd Maste int error = 0; 3278a723a548SEd Maste 327931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3280a723a548SEd Maste 3281a723a548SEd Maste fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3282a723a548SEd Maste if (fibctx == NULL) 3283a723a548SEd Maste return (ENOMEM); 3284a723a548SEd Maste 3285a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3286a723a548SEd Maste /* all elements are already 0, add to queue */ 3287a723a548SEd Maste if (sc->fibctx == NULL) 3288a723a548SEd Maste sc->fibctx = fibctx; 3289a723a548SEd Maste else { 3290a723a548SEd Maste for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3291a723a548SEd Maste ; 3292a723a548SEd Maste ctx->next = fibctx; 3293a723a548SEd Maste fibctx->prev = ctx; 3294a723a548SEd Maste } 3295a723a548SEd Maste 3296a723a548SEd Maste /* evaluate unique value */ 3297a723a548SEd Maste fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3298a723a548SEd Maste ctx = sc->fibctx; 3299a723a548SEd Maste while (ctx != fibctx) { 3300a723a548SEd Maste if (ctx->unique == fibctx->unique) { 3301a723a548SEd Maste fibctx->unique++; 3302a723a548SEd Maste ctx = sc->fibctx; 3303a723a548SEd Maste } else { 3304a723a548SEd Maste ctx = ctx->next; 3305a723a548SEd Maste } 3306a723a548SEd Maste } 3307a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3308a723a548SEd Maste 3309a723a548SEd Maste error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3310a723a548SEd Maste if (error) 3311a723a548SEd Maste aac_close_aif(sc, (caddr_t)ctx); 3312a723a548SEd Maste return error; 3313a723a548SEd Maste } 3314a723a548SEd Maste 3315a723a548SEd Maste /* 3316a723a548SEd Maste * Close the caller's fib context 3317a723a548SEd Maste */ 3318a723a548SEd Maste static int 3319a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg) 3320a723a548SEd Maste { 3321a723a548SEd Maste struct aac_fib_context *ctx; 3322a723a548SEd Maste 332331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3324a723a548SEd Maste 3325a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3326a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3327a723a548SEd Maste if (ctx->unique == *(uint32_t *)&arg) { 3328a723a548SEd Maste if (ctx == sc->fibctx) 3329a723a548SEd Maste sc->fibctx = NULL; 3330a723a548SEd Maste else { 3331a723a548SEd Maste ctx->prev->next = ctx->next; 3332a723a548SEd Maste if (ctx->next) 3333a723a548SEd Maste ctx->next->prev = ctx->prev; 3334a723a548SEd Maste } 3335a723a548SEd Maste break; 3336a723a548SEd Maste } 3337a723a548SEd Maste } 3338a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3339a723a548SEd Maste if (ctx) 3340a723a548SEd Maste free(ctx, M_AACBUF); 3341a723a548SEd Maste 3342a723a548SEd Maste return 0; 3343a723a548SEd Maste } 3344a723a548SEd Maste 3345a723a548SEd Maste /* 334635863739SMike Smith * Pass the caller the next AIF in their queue 334735863739SMike Smith */ 334835863739SMike Smith static int 3349fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 335035863739SMike Smith { 335135863739SMike Smith struct get_adapter_fib_ioctl agf; 3352a723a548SEd Maste struct aac_fib_context *ctx; 33539e2e96d8SScott Long int error; 335435863739SMike Smith 335531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 335635863739SMike Smith 335735863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3358a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3359a723a548SEd Maste if (agf.AdapterFibContext == ctx->unique) 3360a723a548SEd Maste break; 3361a723a548SEd Maste } 3362a723a548SEd Maste if (!ctx) 3363a723a548SEd Maste return (EFAULT); 336435863739SMike Smith 3365a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 3366a723a548SEd Maste if (error == EAGAIN && agf.Wait) { 336731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 336835863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 336935863739SMike Smith while (error == EAGAIN) { 3370914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3371914da7d0SScott Long PCATCH, "aacaif", 0); 337235863739SMike Smith if (error == 0) 3373a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 337435863739SMike Smith } 337535863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 337635863739SMike Smith } 337735863739SMike Smith } 337835863739SMike Smith return(error); 337935863739SMike Smith } 338035863739SMike Smith 3381914da7d0SScott Long /* 33820b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 33830b94a66eSMike Smith */ 33840b94a66eSMike Smith static int 3385a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 33860b94a66eSMike Smith { 3387a723a548SEd Maste int current, error; 33880b94a66eSMike Smith 338931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 33900b94a66eSMike Smith 3391bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3392a723a548SEd Maste current = ctx->ctx_idx; 3393a723a548SEd Maste if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3394a723a548SEd Maste /* empty */ 3395bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 33963df780cfSScott Long return (EAGAIN); 33973df780cfSScott Long } 3398a723a548SEd Maste error = 3399a723a548SEd Maste copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 340036e0bf6eSScott Long if (error) 340170545d1aSScott Long device_printf(sc->aac_dev, 340270545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 3403a723a548SEd Maste else { 3404a723a548SEd Maste ctx->ctx_wrap = 0; 3405a723a548SEd Maste ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3406a723a548SEd Maste } 3407bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 34080b94a66eSMike Smith return(error); 34090b94a66eSMike Smith } 341036e0bf6eSScott Long 34117cb209f5SScott Long static int 34127cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 34137cb209f5SScott Long { 34147cb209f5SScott Long struct aac_pci_info { 34157cb209f5SScott Long u_int32_t bus; 34167cb209f5SScott Long u_int32_t slot; 34177cb209f5SScott Long } pciinf; 34187cb209f5SScott Long int error; 34197cb209f5SScott Long 342031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 34217cb209f5SScott Long 34227cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 34237cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 34247cb209f5SScott Long 34257cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 34267cb209f5SScott Long sizeof(struct aac_pci_info)); 34277cb209f5SScott Long 34287cb209f5SScott Long return (error); 34297cb209f5SScott Long } 34307cb209f5SScott Long 34316d307336SEd Maste static int 34326d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr) 34336d307336SEd Maste { 34346d307336SEd Maste struct aac_features f; 34356d307336SEd Maste int error; 34366d307336SEd Maste 34376d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 34386d307336SEd Maste 34396d307336SEd Maste if ((error = copyin(uptr, &f, sizeof (f))) != 0) 34406d307336SEd Maste return (error); 34416d307336SEd Maste 34426d307336SEd Maste /* 34436d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 34446d307336SEd Maste * ALL zero in the featuresState, the driver will return the current 34456d307336SEd Maste * state of all the supported features, the data field will not be 34466d307336SEd Maste * valid. 34476d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 34486d307336SEd Maste * a specific bit set in the featuresState, the driver will return the 34496d307336SEd Maste * current state of this specific feature and whatever data that are 34506d307336SEd Maste * associated with the feature in the data field or perform whatever 34516d307336SEd Maste * action needed indicates in the data field. 34526d307336SEd Maste */ 34536d307336SEd Maste if (f.feat.fValue == 0) { 34546d307336SEd Maste f.feat.fBits.largeLBA = 34556d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 34566d307336SEd Maste /* TODO: In the future, add other features state here as well */ 34576d307336SEd Maste } else { 34586d307336SEd Maste if (f.feat.fBits.largeLBA) 34596d307336SEd Maste f.feat.fBits.largeLBA = 34606d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 34616d307336SEd Maste /* TODO: Add other features state and data in the future */ 34626d307336SEd Maste } 34636d307336SEd Maste 34646d307336SEd Maste error = copyout(&f, uptr, sizeof (f)); 34656d307336SEd Maste return (error); 34666d307336SEd Maste } 34676d307336SEd Maste 3468914da7d0SScott Long /* 346936e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 347036e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 347136e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 347236e0bf6eSScott Long */ 347336e0bf6eSScott Long static int 347436e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 347536e0bf6eSScott Long { 347636e0bf6eSScott Long struct aac_query_disk query_disk; 347736e0bf6eSScott Long struct aac_container *co; 3478914da7d0SScott Long struct aac_disk *disk; 347936e0bf6eSScott Long int error, id; 348036e0bf6eSScott Long 348131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 348236e0bf6eSScott Long 3483914da7d0SScott Long disk = NULL; 3484914da7d0SScott Long 3485914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3486914da7d0SScott Long sizeof(struct aac_query_disk)); 348736e0bf6eSScott Long if (error) 348836e0bf6eSScott Long return (error); 348936e0bf6eSScott Long 349036e0bf6eSScott Long id = query_disk.ContainerNumber; 349136e0bf6eSScott Long if (id == -1) 349236e0bf6eSScott Long return (EINVAL); 349336e0bf6eSScott Long 3494bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 349536e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 349636e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 349736e0bf6eSScott Long break; 349836e0bf6eSScott Long } 349936e0bf6eSScott Long 350036e0bf6eSScott Long if (co == NULL) { 350136e0bf6eSScott Long query_disk.Valid = 0; 350236e0bf6eSScott Long query_disk.Locked = 0; 350336e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 350436e0bf6eSScott Long } else { 350536e0bf6eSScott Long disk = device_get_softc(co->co_disk); 350636e0bf6eSScott Long query_disk.Valid = 1; 3507914da7d0SScott Long query_disk.Locked = 3508914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 350936e0bf6eSScott Long query_disk.Deleted = 0; 3510b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 351136e0bf6eSScott Long query_disk.Target = disk->unit; 351236e0bf6eSScott Long query_disk.Lun = 0; 351336e0bf6eSScott Long query_disk.UnMapped = 0; 35147540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 35150b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 351636e0bf6eSScott Long } 3517bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 351836e0bf6eSScott Long 3519914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3520914da7d0SScott Long sizeof(struct aac_query_disk)); 352136e0bf6eSScott Long 352236e0bf6eSScott Long return (error); 352336e0bf6eSScott Long } 352436e0bf6eSScott Long 3525fe3cb0e1SScott Long static void 3526fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3527fe3cb0e1SScott Long { 3528fe3cb0e1SScott Long struct aac_fib *fib; 3529fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3530fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3531fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3532fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3533fe3cb0e1SScott Long struct aac_getbusinf businfo; 353470545d1aSScott Long struct aac_sim *caminf; 3535fe3cb0e1SScott Long device_t child; 3536fe3cb0e1SScott Long int i, found, error; 3537fe3cb0e1SScott Long 35381ffe41c1SChristian S.J. Peron mtx_lock(&sc->aac_io_lock); 353903b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3540fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 354139ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3542fe3cb0e1SScott Long 3543fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3544fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3545fe3cb0e1SScott Long c_cmd->param = 0; 3546fe3cb0e1SScott Long 3547fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3548fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3549fe3cb0e1SScott Long if (error) { 3550fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3551fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3552fe3cb0e1SScott Long aac_release_sync_fib(sc); 35531ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3554fe3cb0e1SScott Long return; 3555fe3cb0e1SScott Long } 3556fe3cb0e1SScott Long 3557fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3558fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3559fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3560fe3cb0e1SScott Long c_resp->Status); 3561fe3cb0e1SScott Long aac_release_sync_fib(sc); 35621ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3563fe3cb0e1SScott Long return; 3564fe3cb0e1SScott Long } 3565fe3cb0e1SScott Long 3566fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3567fe3cb0e1SScott Long 3568fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 356939ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 357039ee03c3SScott Long 3571fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3572fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3573fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3574fe3cb0e1SScott Long vmi->ObjId = 0; 3575fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3576fe3cb0e1SScott Long 3577fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 357842ef13a2SEd Maste sizeof(struct aac_vmi_businf_resp)); 3579fe3cb0e1SScott Long if (error) { 3580fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3581fe3cb0e1SScott Long error); 3582fe3cb0e1SScott Long aac_release_sync_fib(sc); 35831ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3584fe3cb0e1SScott Long return; 3585fe3cb0e1SScott Long } 3586fe3cb0e1SScott Long 3587fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3588fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3589fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3590fe3cb0e1SScott Long vmi_resp->Status); 3591fe3cb0e1SScott Long aac_release_sync_fib(sc); 35921ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3593fe3cb0e1SScott Long return; 3594fe3cb0e1SScott Long } 3595fe3cb0e1SScott Long 3596fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3597fe3cb0e1SScott Long aac_release_sync_fib(sc); 35981ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3599fe3cb0e1SScott Long 3600fe3cb0e1SScott Long found = 0; 3601fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3602fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3603fe3cb0e1SScott Long continue; 3604fe3cb0e1SScott Long 3605a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3606a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3607b5f516cdSScott Long if (caminf == NULL) { 3608b5f516cdSScott Long device_printf(sc->aac_dev, 3609b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3610b5f516cdSScott Long break; 36117cb209f5SScott Long }; 3612fe3cb0e1SScott Long 3613fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3614fe3cb0e1SScott Long if (child == NULL) { 3615b5f516cdSScott Long device_printf(sc->aac_dev, 3616b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3617b5f516cdSScott Long i); 3618b5f516cdSScott Long free(caminf, M_AACBUF); 3619b5f516cdSScott Long break; 3620fe3cb0e1SScott Long } 3621fe3cb0e1SScott Long 3622fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3623fe3cb0e1SScott Long caminf->BusNumber = i; 3624fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3625fe3cb0e1SScott Long caminf->aac_sc = sc; 3626ddb8683eSScott Long caminf->sim_dev = child; 3627fe3cb0e1SScott Long 3628fe3cb0e1SScott Long device_set_ivars(child, caminf); 3629fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 363070545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3631fe3cb0e1SScott Long 3632fe3cb0e1SScott Long found = 1; 3633fe3cb0e1SScott Long } 3634fe3cb0e1SScott Long 3635fe3cb0e1SScott Long if (found) 3636fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3637fe3cb0e1SScott Long 3638fe3cb0e1SScott Long return; 3639fe3cb0e1SScott Long } 3640