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_DRIVER_VERSION 0x02000000 377cb209f5SScott Long #define AAC_DRIVERNAME "aac" 3835863739SMike Smith 39f6c4dd3fSScott Long #include "opt_aac.h" 40f6c4dd3fSScott Long 4136e0bf6eSScott Long /* #include <stddef.h> */ 4235863739SMike Smith #include <sys/param.h> 4335863739SMike Smith #include <sys/systm.h> 4435863739SMike Smith #include <sys/malloc.h> 4535863739SMike Smith #include <sys/kernel.h> 4636e0bf6eSScott Long #include <sys/kthread.h> 473d04a9d7SScott Long #include <sys/sysctl.h> 48b3457b51SScott Long #include <sys/poll.h> 49891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 5035863739SMike Smith 5135863739SMike Smith #include <sys/bus.h> 5235863739SMike Smith #include <sys/conf.h> 5335863739SMike Smith #include <sys/signalvar.h> 540b94a66eSMike Smith #include <sys/time.h> 5536e0bf6eSScott Long #include <sys/eventhandler.h> 567cb209f5SScott Long #include <sys/rman.h> 5735863739SMike Smith 5835863739SMike Smith #include <machine/bus.h> 59b5f516cdSScott Long #include <sys/bus_dma.h> 6035863739SMike Smith #include <machine/resource.h> 6135863739SMike Smith 627cb209f5SScott Long #include <dev/pci/pcireg.h> 637cb209f5SScott Long #include <dev/pci/pcivar.h> 647cb209f5SScott Long 6535863739SMike Smith #include <dev/aac/aacreg.h> 660b0594cdSScott Long #include <sys/aac_ioctl.h> 6735863739SMike Smith #include <dev/aac/aacvar.h> 6835863739SMike Smith #include <dev/aac/aac_tables.h> 6935863739SMike Smith 7035863739SMike Smith static void aac_startup(void *arg); 71914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 72cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 73fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 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 */ 93c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 94c6eafcf2SScott Long int error); 95fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9635863739SMike Smith static int aac_init(struct aac_softc *sc); 9735863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 98c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 99c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 100c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 101f6c4dd3fSScott Long struct aac_command *cm); 102c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 103914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10436e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10536e0bf6eSScott Long struct aac_fib *fib); 10635863739SMike Smith 107b3457b51SScott Long /* Falcon/PPC interface */ 108b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 109b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 110b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 111b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 112b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 113b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 114b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 115a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 116b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 117b3457b51SScott Long 118b3457b51SScott Long struct aac_interface aac_fa_interface = { 119b3457b51SScott Long aac_fa_get_fwstatus, 120b3457b51SScott Long aac_fa_qnotify, 121b3457b51SScott Long aac_fa_get_istatus, 122b3457b51SScott Long aac_fa_clear_istatus, 123b3457b51SScott Long aac_fa_set_mailbox, 124a6d35632SScott Long aac_fa_get_mailbox, 1257cb209f5SScott Long aac_fa_set_interrupts, 1267cb209f5SScott Long NULL, NULL, NULL 127b3457b51SScott Long }; 128b3457b51SScott Long 12935863739SMike Smith /* StrongARM interface */ 13035863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13135863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13235863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13335863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13435863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 135c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 136c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 137a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13835863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 13935863739SMike Smith 14035863739SMike Smith struct aac_interface aac_sa_interface = { 14135863739SMike Smith aac_sa_get_fwstatus, 14235863739SMike Smith aac_sa_qnotify, 14335863739SMike Smith aac_sa_get_istatus, 14435863739SMike Smith aac_sa_clear_istatus, 14535863739SMike Smith aac_sa_set_mailbox, 146a6d35632SScott Long aac_sa_get_mailbox, 1477cb209f5SScott Long aac_sa_set_interrupts, 1487cb209f5SScott Long NULL, NULL, NULL 14935863739SMike Smith }; 15035863739SMike Smith 15135863739SMike Smith /* i960Rx interface */ 15235863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15335863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15435863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15535863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15635863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 157c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 158c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 159a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 16035863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1617cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1627cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1637cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 16435863739SMike Smith 16535863739SMike Smith struct aac_interface aac_rx_interface = { 16635863739SMike Smith aac_rx_get_fwstatus, 16735863739SMike Smith aac_rx_qnotify, 16835863739SMike Smith aac_rx_get_istatus, 16935863739SMike Smith aac_rx_clear_istatus, 17035863739SMike Smith aac_rx_set_mailbox, 171a6d35632SScott Long aac_rx_get_mailbox, 1727cb209f5SScott Long aac_rx_set_interrupts, 1737cb209f5SScott Long aac_rx_send_command, 1747cb209f5SScott Long aac_rx_get_outb_queue, 1757cb209f5SScott Long aac_rx_set_outb_queue 17635863739SMike Smith }; 17735863739SMike Smith 1784afedc31SScott Long /* Rocket/MIPS interface */ 1794afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1804afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1814afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1824afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1834afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1844afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1854afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1864afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1874afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1887cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1897cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1907cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1914afedc31SScott Long 1924afedc31SScott Long struct aac_interface aac_rkt_interface = { 1934afedc31SScott Long aac_rkt_get_fwstatus, 1944afedc31SScott Long aac_rkt_qnotify, 1954afedc31SScott Long aac_rkt_get_istatus, 1964afedc31SScott Long aac_rkt_clear_istatus, 1974afedc31SScott Long aac_rkt_set_mailbox, 1984afedc31SScott Long aac_rkt_get_mailbox, 1997cb209f5SScott Long aac_rkt_set_interrupts, 2007cb209f5SScott Long aac_rkt_send_command, 2017cb209f5SScott Long aac_rkt_get_outb_queue, 2027cb209f5SScott Long aac_rkt_set_outb_queue 2034afedc31SScott Long }; 2044afedc31SScott Long 20535863739SMike Smith /* Debugging and Diagnostics */ 20635863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 2076965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 208c6eafcf2SScott Long u_int32_t code); 20935863739SMike Smith 21035863739SMike Smith /* Management Interface */ 21135863739SMike Smith static d_open_t aac_open; 21235863739SMike Smith static d_close_t aac_close; 21335863739SMike Smith static d_ioctl_t aac_ioctl; 214b3457b51SScott Long static d_poll_t aac_poll; 215c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 216c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 21736e0bf6eSScott Long struct aac_fib *fib); 218fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 219a723a548SEd Maste static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 220a723a548SEd Maste static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 221fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 222a723a548SEd Maste static int aac_return_aif(struct aac_softc *sc, 223a723a548SEd Maste struct aac_fib_context *ctx, caddr_t uptr); 22436e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2257cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2267cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2277cb209f5SScott Long struct aac_event *event, void *arg); 22835863739SMike Smith 22935863739SMike Smith static struct cdevsw aac_cdevsw = { 230dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 231dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 2327ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2337ac40f5fSPoul-Henning Kamp .d_close = aac_close, 2347ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2357ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2367ac40f5fSPoul-Henning Kamp .d_name = "aac", 23735863739SMike Smith }; 23835863739SMike Smith 23936e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 24036e0bf6eSScott Long 2413d04a9d7SScott Long /* sysctl node */ 2423d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2433d04a9d7SScott Long 244914da7d0SScott Long /* 245914da7d0SScott Long * Device Interface 246914da7d0SScott Long */ 24735863739SMike Smith 248914da7d0SScott Long /* 24935863739SMike Smith * Initialise the controller and softc 25035863739SMike Smith */ 25135863739SMike Smith int 25235863739SMike Smith aac_attach(struct aac_softc *sc) 25335863739SMike Smith { 25435863739SMike Smith int error, unit; 25535863739SMike Smith 25635863739SMike Smith debug_called(1); 25735863739SMike Smith 25835863739SMike Smith /* 25935863739SMike Smith * Initialise per-controller queues. 26035863739SMike Smith */ 2610b94a66eSMike Smith aac_initq_free(sc); 2620b94a66eSMike Smith aac_initq_ready(sc); 2630b94a66eSMike Smith aac_initq_busy(sc); 2640b94a66eSMike Smith aac_initq_bio(sc); 26535863739SMike Smith 26635863739SMike Smith /* 26735863739SMike Smith * Initialise command-completion task. 26835863739SMike Smith */ 26935863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 27035863739SMike Smith 27135863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 27235863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 27335863739SMike Smith 27435863739SMike Smith /* 275fe94b852SScott Long * Check that the firmware on the card is supported. 276fe94b852SScott Long */ 277fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 278fe94b852SScott Long return(error); 279fe94b852SScott Long 280f6b1c44dSScott Long /* 281f6b1c44dSScott Long * Initialize locks 282f6b1c44dSScott Long */ 283bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 284bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 285bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 286f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 287065dd78cSScott Long TAILQ_INIT(&sc->aac_ev_cmfree); 288f6b1c44dSScott Long 2890b94a66eSMike Smith /* 29035863739SMike Smith * Initialise the adapter. 29135863739SMike Smith */ 2920b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 29335863739SMike Smith return(error); 29435863739SMike Smith 29535863739SMike Smith /* 2967cb209f5SScott Long * Allocate and connect our interrupt. 2977cb209f5SScott Long */ 2987cb209f5SScott Long sc->aac_irq_rid = 0; 2997cb209f5SScott Long if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 3007cb209f5SScott Long &sc->aac_irq_rid, 3017cb209f5SScott Long RF_SHAREABLE | 3027cb209f5SScott Long RF_ACTIVE)) == NULL) { 3037cb209f5SScott Long device_printf(sc->aac_dev, "can't allocate interrupt\n"); 3047cb209f5SScott Long return (EINVAL); 3057cb209f5SScott Long } 3067cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 3077cb209f5SScott Long if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 308ef544f63SPaolo Pisati INTR_MPSAFE|INTR_TYPE_BIO, NULL, 309ef544f63SPaolo Pisati aac_new_intr, sc, &sc->aac_intr)) { 3107cb209f5SScott Long device_printf(sc->aac_dev, "can't set up interrupt\n"); 3117cb209f5SScott Long return (EINVAL); 3127cb209f5SScott Long } 3137cb209f5SScott Long } else { 3147cb209f5SScott Long if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 315ef544f63SPaolo Pisati INTR_TYPE_BIO, aac_fast_intr, NULL, 3167cb209f5SScott Long sc, &sc->aac_intr)) { 3177cb209f5SScott Long device_printf(sc->aac_dev, 3187cb209f5SScott Long "can't set up FAST interrupt\n"); 3197cb209f5SScott Long if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 3207cb209f5SScott Long INTR_MPSAFE|INTR_TYPE_BIO, 321ef544f63SPaolo Pisati NULL, (driver_intr_t *)aac_fast_intr, 322ef544f63SPaolo Pisati sc, &sc->aac_intr)) { 3237cb209f5SScott Long device_printf(sc->aac_dev, 3247cb209f5SScott Long "can't set up MPSAFE interrupt\n"); 3257cb209f5SScott Long return (EINVAL); 3267cb209f5SScott Long } 3277cb209f5SScott Long } 3287cb209f5SScott Long } 3297cb209f5SScott Long 3307cb209f5SScott Long /* 33135863739SMike Smith * Print a little information about the controller. 33235863739SMike Smith */ 33335863739SMike Smith aac_describe_controller(sc); 33435863739SMike Smith 33535863739SMike Smith /* 336ae543596SScott Long * Register to probe our containers later. 337ae543596SScott Long */ 33835863739SMike Smith sc->aac_ich.ich_func = aac_startup; 33935863739SMike Smith sc->aac_ich.ich_arg = sc; 34035863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 341914da7d0SScott Long device_printf(sc->aac_dev, 342914da7d0SScott Long "can't establish configuration hook\n"); 34335863739SMike Smith return(ENXIO); 34435863739SMike Smith } 34535863739SMike Smith 34635863739SMike Smith /* 34735863739SMike Smith * Make the control device. 34835863739SMike Smith */ 34935863739SMike Smith unit = device_get_unit(sc->aac_dev); 3509e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3519e9466baSRobert Watson 0640, "aac%d", unit); 352157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3534aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 35435863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 35535863739SMike Smith 35636e0bf6eSScott Long /* Create the AIF thread */ 3573745c395SJulian Elischer if (kproc_create((void(*)(void *))aac_command_thread, sc, 358316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 35936e0bf6eSScott Long panic("Could not create AIF thread\n"); 36036e0bf6eSScott Long 36136e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3625f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3635f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3645f54d522SScott Long device_printf(sc->aac_dev, 3655f54d522SScott Long "shutdown event registration failed\n"); 36636e0bf6eSScott Long 367fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 368a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 36970545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 370fe3cb0e1SScott Long aac_get_bus_info(sc); 37170545d1aSScott Long } 372fe3cb0e1SScott Long 37335863739SMike Smith return(0); 37435863739SMike Smith } 37535863739SMike Smith 3767cb209f5SScott Long void 3777cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event) 3787cb209f5SScott Long { 3797cb209f5SScott Long 3807cb209f5SScott Long switch (event->ev_type & AAC_EVENT_MASK) { 3817cb209f5SScott Long case AAC_EVENT_CMFREE: 3827cb209f5SScott Long TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 3837cb209f5SScott Long break; 3847cb209f5SScott Long default: 3857cb209f5SScott Long device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 3867cb209f5SScott Long event->ev_type); 3877cb209f5SScott Long break; 3887cb209f5SScott Long } 3897cb209f5SScott Long 3907cb209f5SScott Long return; 3917cb209f5SScott Long } 3927cb209f5SScott Long 393914da7d0SScott Long /* 39435863739SMike Smith * Probe for containers, create disks. 39535863739SMike Smith */ 39635863739SMike Smith static void 39735863739SMike Smith aac_startup(void *arg) 39835863739SMike Smith { 399914da7d0SScott Long struct aac_softc *sc; 400cbfd045bSScott Long struct aac_fib *fib; 401cbfd045bSScott Long struct aac_mntinfo *mi; 402cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 403795d7dc0SScott Long int count = 0, i = 0; 40435863739SMike Smith 40535863739SMike Smith debug_called(1); 40635863739SMike Smith 407914da7d0SScott Long sc = (struct aac_softc *)arg; 408914da7d0SScott Long 40935863739SMike Smith /* disconnect ourselves from the intrhook chain */ 41035863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 41135863739SMike Smith 4127cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 41303b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 414cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 415cbfd045bSScott Long 41635863739SMike Smith /* loop over possible containers */ 41736e0bf6eSScott Long do { 41835863739SMike Smith /* request information on this container */ 41939ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 42039ee03c3SScott Long mi->Command = VM_NameServe; 42139ee03c3SScott Long mi->MntType = FT_FILESYS; 422cbfd045bSScott Long mi->MntCount = i; 423cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 424cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 425795d7dc0SScott Long printf("error probing container %d", i); 42635863739SMike Smith continue; 42735863739SMike Smith } 42835863739SMike Smith 429cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 430795d7dc0SScott Long /* XXX Need to check if count changed */ 431795d7dc0SScott Long count = mir->MntRespCount; 432cbfd045bSScott Long aac_add_container(sc, mir, 0); 43336e0bf6eSScott Long i++; 434795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 435cbfd045bSScott Long 436cbfd045bSScott Long aac_release_sync_fib(sc); 4377cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 43835863739SMike Smith 43935863739SMike Smith /* poke the bus to actually attach the child devices */ 44035863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 44135863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 44235863739SMike Smith 44335863739SMike Smith /* mark the controller up */ 44435863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 44535863739SMike Smith 44635863739SMike Smith /* enable interrupts now */ 44735863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 44835863739SMike Smith } 44935863739SMike Smith 450914da7d0SScott Long /* 451914da7d0SScott Long * Create a device to respresent a new container 452914da7d0SScott Long */ 453914da7d0SScott Long static void 454cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 455914da7d0SScott Long { 456914da7d0SScott Long struct aac_container *co; 457914da7d0SScott Long device_t child; 458914da7d0SScott Long 459914da7d0SScott Long /* 460914da7d0SScott Long * Check container volume type for validity. Note that many of 461914da7d0SScott Long * the possible types may never show up. 462914da7d0SScott Long */ 463914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 464a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 465a761a1caSScott Long M_NOWAIT | M_ZERO); 466914da7d0SScott Long if (co == NULL) 467914da7d0SScott Long panic("Out of memory?!\n"); 468914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 469914da7d0SScott Long mir->MntTable[0].ObjectId, 470914da7d0SScott Long mir->MntTable[0].FileSystemName, 471914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 472914da7d0SScott Long 473fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 474914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 475914da7d0SScott Long else 476914da7d0SScott Long device_set_ivars(child, co); 477914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 478914da7d0SScott Long mir->MntTable[0].VolType)); 479914da7d0SScott Long co->co_disk = child; 480914da7d0SScott Long co->co_found = f; 481914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 482914da7d0SScott Long sizeof(struct aac_mntobj)); 483bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 484914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 485bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 486914da7d0SScott Long } 487914da7d0SScott Long } 488914da7d0SScott Long 489914da7d0SScott Long /* 49035863739SMike Smith * Free all of the resources associated with (sc) 49135863739SMike Smith * 49235863739SMike Smith * Should not be called if the controller is active. 49335863739SMike Smith */ 49435863739SMike Smith void 49535863739SMike Smith aac_free(struct aac_softc *sc) 49635863739SMike Smith { 497ffb37f33SScott Long 49835863739SMike Smith debug_called(1); 49935863739SMike Smith 50035863739SMike Smith /* remove the control device */ 50135863739SMike Smith if (sc->aac_dev_t != NULL) 50235863739SMike Smith destroy_dev(sc->aac_dev_t); 50335863739SMike Smith 5040b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 5058480cc63SScott Long aac_free_commands(sc); 5060b94a66eSMike Smith if (sc->aac_fib_dmat) 5070b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 50835863739SMike Smith 509ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 510ffb37f33SScott Long 51135863739SMike Smith /* destroy the common area */ 51235863739SMike Smith if (sc->aac_common) { 51335863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 514c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 515c6eafcf2SScott Long sc->aac_common_dmamap); 51635863739SMike Smith } 5170b94a66eSMike Smith if (sc->aac_common_dmat) 5180b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 51935863739SMike Smith 52035863739SMike Smith /* disconnect the interrupt handler */ 52135863739SMike Smith if (sc->aac_intr) 52235863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 52335863739SMike Smith if (sc->aac_irq != NULL) 524c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 525c6eafcf2SScott Long sc->aac_irq); 52635863739SMike Smith 52735863739SMike Smith /* destroy data-transfer DMA tag */ 52835863739SMike Smith if (sc->aac_buffer_dmat) 52935863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 53035863739SMike Smith 53135863739SMike Smith /* destroy the parent DMA tag */ 53235863739SMike Smith if (sc->aac_parent_dmat) 53335863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 53435863739SMike Smith 53535863739SMike Smith /* release the register window mapping */ 53635863739SMike Smith if (sc->aac_regs_resource != NULL) 537914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 538914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 53935863739SMike Smith } 54035863739SMike Smith 541914da7d0SScott Long /* 54235863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 54335863739SMike Smith */ 54435863739SMike Smith int 54535863739SMike Smith aac_detach(device_t dev) 54635863739SMike Smith { 547914da7d0SScott Long struct aac_softc *sc; 54870545d1aSScott Long struct aac_container *co; 54970545d1aSScott Long struct aac_sim *sim; 55035863739SMike Smith int error; 55135863739SMike Smith 55235863739SMike Smith debug_called(1); 55335863739SMike Smith 554914da7d0SScott Long sc = device_get_softc(dev); 555914da7d0SScott Long 55635863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 55735863739SMike Smith return(EBUSY); 55835863739SMike Smith 55970545d1aSScott Long /* Remove the child containers */ 560a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 56170545d1aSScott Long error = device_delete_child(dev, co->co_disk); 56270545d1aSScott Long if (error) 56370545d1aSScott Long return (error); 56465ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 565a761a1caSScott Long free(co, M_AACBUF); 56670545d1aSScott Long } 56770545d1aSScott Long 56870545d1aSScott Long /* Remove the CAM SIMs */ 569a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 570a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 57170545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 57270545d1aSScott Long if (error) 57370545d1aSScott Long return (error); 574a761a1caSScott Long free(sim, M_AACBUF); 57570545d1aSScott Long } 57670545d1aSScott Long 57736e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 57836e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 57936e0bf6eSScott Long wakeup(sc->aifthread); 58036e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 58136e0bf6eSScott Long } 58236e0bf6eSScott Long 58336e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 58436e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 58536e0bf6eSScott Long 58635863739SMike Smith if ((error = aac_shutdown(dev))) 58735863739SMike Smith return(error); 58835863739SMike Smith 5895f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 5905f54d522SScott Long 59135863739SMike Smith aac_free(sc); 59235863739SMike Smith 593dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 594dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 595dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 596dc9efde5SScott Long 59735863739SMike Smith return(0); 59835863739SMike Smith } 59935863739SMike Smith 600914da7d0SScott Long /* 60135863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 60235863739SMike Smith * 60335863739SMike Smith * This function is called before detach or system shutdown. 60435863739SMike Smith * 6050b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 60635863739SMike Smith * allow shutdown if any device is open. 60735863739SMike Smith */ 60835863739SMike Smith int 60935863739SMike Smith aac_shutdown(device_t dev) 61035863739SMike Smith { 611914da7d0SScott Long struct aac_softc *sc; 612cbfd045bSScott Long struct aac_fib *fib; 613cbfd045bSScott Long struct aac_close_command *cc; 61435863739SMike Smith 61535863739SMike Smith debug_called(1); 61635863739SMike Smith 617914da7d0SScott Long sc = device_get_softc(dev); 618914da7d0SScott Long 61935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 62035863739SMike Smith 62135863739SMike Smith /* 62235863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 62335863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 62435863739SMike Smith * We've been closed and all I/O completed already 62535863739SMike Smith */ 62635863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 62735863739SMike Smith 6287cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 62903b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 630cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 631cbfd045bSScott Long 63239ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 633cbfd045bSScott Long cc->Command = VM_CloseAll; 634cbfd045bSScott Long cc->ContainerId = 0xffffffff; 635cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 636cbfd045bSScott Long sizeof(struct aac_close_command))) 63735863739SMike Smith printf("FAILED.\n"); 63870545d1aSScott Long else 63970545d1aSScott Long printf("done\n"); 64070545d1aSScott Long #if 0 641914da7d0SScott Long else { 642cbfd045bSScott Long fib->data[0] = 0; 64336e0bf6eSScott Long /* 644914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 64536e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 64636e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 64736e0bf6eSScott Long * driver module with the intent to reload it later. 64836e0bf6eSScott Long */ 649cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 650cbfd045bSScott Long fib, 1)) { 65135863739SMike Smith printf("FAILED.\n"); 65235863739SMike Smith } else { 65335863739SMike Smith printf("done.\n"); 65435863739SMike Smith } 65535863739SMike Smith } 65670545d1aSScott Long #endif 65735863739SMike Smith 65835863739SMike Smith AAC_MASK_INTERRUPTS(sc); 6593576af8fSScott Long aac_release_sync_fib(sc); 6607cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 66135863739SMike Smith 66235863739SMike Smith return(0); 66335863739SMike Smith } 66435863739SMike Smith 665914da7d0SScott Long /* 66635863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 66735863739SMike Smith */ 66835863739SMike Smith int 66935863739SMike Smith aac_suspend(device_t dev) 67035863739SMike Smith { 671914da7d0SScott Long struct aac_softc *sc; 67235863739SMike Smith 67335863739SMike Smith debug_called(1); 674914da7d0SScott Long 675914da7d0SScott Long sc = device_get_softc(dev); 676914da7d0SScott Long 67735863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 67835863739SMike Smith 67935863739SMike Smith AAC_MASK_INTERRUPTS(sc); 68035863739SMike Smith return(0); 68135863739SMike Smith } 68235863739SMike Smith 683914da7d0SScott Long /* 68435863739SMike Smith * Bring the controller back to a state ready for operation. 68535863739SMike Smith */ 68635863739SMike Smith int 68735863739SMike Smith aac_resume(device_t dev) 68835863739SMike Smith { 689914da7d0SScott Long struct aac_softc *sc; 69035863739SMike Smith 69135863739SMike Smith debug_called(1); 692914da7d0SScott Long 693914da7d0SScott Long sc = device_get_softc(dev); 694914da7d0SScott Long 69535863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 69635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 69735863739SMike Smith return(0); 69835863739SMike Smith } 69935863739SMike Smith 700914da7d0SScott Long /* 7017cb209f5SScott Long * Interrupt handler for NEW_COMM interface. 70235863739SMike Smith */ 70335863739SMike Smith void 7047cb209f5SScott Long aac_new_intr(void *arg) 7057cb209f5SScott Long { 7067cb209f5SScott Long struct aac_softc *sc; 7077cb209f5SScott Long u_int32_t index, fast; 7087cb209f5SScott Long struct aac_command *cm; 7097cb209f5SScott Long struct aac_fib *fib; 7107cb209f5SScott Long int i; 7117cb209f5SScott Long 7127cb209f5SScott Long debug_called(2); 7137cb209f5SScott Long 7147cb209f5SScott Long sc = (struct aac_softc *)arg; 7157cb209f5SScott Long 7167cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 7177cb209f5SScott Long while (1) { 7187cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 7197cb209f5SScott Long if (index == 0xffffffff) 7207cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 7217cb209f5SScott Long if (index == 0xffffffff) 7227cb209f5SScott Long break; 7237cb209f5SScott Long if (index & 2) { 7247cb209f5SScott Long if (index == 0xfffffffe) { 7257cb209f5SScott Long /* XXX This means that the controller wants 7267cb209f5SScott Long * more work. Ignore it for now. 7277cb209f5SScott Long */ 7287cb209f5SScott Long continue; 7297cb209f5SScott Long } 7307cb209f5SScott Long /* AIF */ 7317cb209f5SScott Long fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 7327cb209f5SScott Long M_NOWAIT | M_ZERO); 7337cb209f5SScott Long if (fib == NULL) { 7347cb209f5SScott Long /* If we're really this short on memory, 7357cb209f5SScott Long * hopefully breaking out of the handler will 7367cb209f5SScott Long * allow something to get freed. This 7377cb209f5SScott Long * actually sucks a whole lot. 7387cb209f5SScott Long */ 7397cb209f5SScott Long break; 7407cb209f5SScott Long } 7417cb209f5SScott Long index &= ~2; 7427cb209f5SScott Long for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 7437cb209f5SScott Long ((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4); 7447cb209f5SScott Long aac_handle_aif(sc, fib); 7457cb209f5SScott Long free(fib, M_AACBUF); 7467cb209f5SScott Long 7477cb209f5SScott Long /* 7487cb209f5SScott Long * AIF memory is owned by the adapter, so let it 7497cb209f5SScott Long * know that we are done with it. 7507cb209f5SScott Long */ 7517cb209f5SScott Long AAC_SET_OUTB_QUEUE(sc, index); 7527cb209f5SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 7537cb209f5SScott Long } else { 7547cb209f5SScott Long fast = index & 1; 7557cb209f5SScott Long cm = sc->aac_commands + (index >> 2); 7567cb209f5SScott Long fib = cm->cm_fib; 7577cb209f5SScott Long if (fast) { 7587cb209f5SScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 7597cb209f5SScott Long *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 7607cb209f5SScott Long } 7617cb209f5SScott Long aac_remove_busy(cm); 7627cb209f5SScott Long aac_unmap_command(cm); 7637cb209f5SScott Long cm->cm_flags |= AAC_CMD_COMPLETED; 7647cb209f5SScott Long 7657cb209f5SScott Long /* is there a completion handler? */ 7667cb209f5SScott Long if (cm->cm_complete != NULL) { 7677cb209f5SScott Long cm->cm_complete(cm); 7687cb209f5SScott Long } else { 7697cb209f5SScott Long /* assume that someone is sleeping on this 7707cb209f5SScott Long * command 7717cb209f5SScott Long */ 7727cb209f5SScott Long wakeup(cm); 7737cb209f5SScott Long } 7747cb209f5SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 7757cb209f5SScott Long } 7767cb209f5SScott Long } 7777cb209f5SScott Long /* see if we can start some more I/O */ 7787cb209f5SScott Long if ((sc->flags & AAC_QUEUE_FRZN) == 0) 7797cb209f5SScott Long aac_startio(sc); 7807cb209f5SScott Long 7817cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 7827cb209f5SScott Long } 7837cb209f5SScott Long 784ef544f63SPaolo Pisati int 7857cb209f5SScott Long aac_fast_intr(void *arg) 78635863739SMike Smith { 787914da7d0SScott Long struct aac_softc *sc; 78870545d1aSScott Long u_int16_t reason; 78935863739SMike Smith 79035863739SMike Smith debug_called(2); 79135863739SMike Smith 792914da7d0SScott Long sc = (struct aac_softc *)arg; 793914da7d0SScott Long 794f30ac74cSScott Long /* 7959148fa21SScott Long * Read the status register directly. This is faster than taking the 7969148fa21SScott Long * driver lock and reading the queues directly. It also saves having 7979148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 7989148fa21SScott Long * ugly. 799f30ac74cSScott Long */ 80035863739SMike Smith reason = AAC_GET_ISTATUS(sc); 801f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 802f30ac74cSScott Long 8039c3a7fceSScott Long /* handle completion processing */ 8049148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 8059148fa21SScott Long taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 80635863739SMike Smith 8079148fa21SScott Long /* controller wants to talk to us */ 8089148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 80970545d1aSScott Long /* 8109148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 8119148fa21SScott Long * that start with a NULL. 81270545d1aSScott Long */ 8139148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 8149148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 8159148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 81670545d1aSScott Long 8179148fa21SScott Long /* 8189148fa21SScott Long * This might miss doing the actual wakeup. However, the 819a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 8209148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 8219148fa21SScott Long * priority that they can handle hanging out for a few seconds 8229148fa21SScott Long * if needed. 8239148fa21SScott Long */ 82436e0bf6eSScott Long wakeup(sc->aifthread); 82536e0bf6eSScott Long } 826ef544f63SPaolo Pisati return (FILTER_HANDLED); 8279148fa21SScott Long } 82835863739SMike Smith 829c6eafcf2SScott Long /* 830914da7d0SScott Long * Command Processing 831914da7d0SScott Long */ 83235863739SMike Smith 833914da7d0SScott Long /* 83435863739SMike Smith * Start as much queued I/O as possible on the controller 83535863739SMike Smith */ 836fe3cb0e1SScott Long void 83735863739SMike Smith aac_startio(struct aac_softc *sc) 83835863739SMike Smith { 83935863739SMike Smith struct aac_command *cm; 840397fa34fSScott Long int error; 84135863739SMike Smith 84235863739SMike Smith debug_called(2); 84335863739SMike Smith 84435863739SMike Smith for (;;) { 845914da7d0SScott Long /* 846397fa34fSScott Long * This flag might be set if the card is out of resources. 847397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 848397fa34fSScott Long */ 849397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 850397fa34fSScott Long break; 851397fa34fSScott Long 852397fa34fSScott Long /* 853914da7d0SScott Long * Try to get a command that's been put off for lack of 854914da7d0SScott Long * resources 855914da7d0SScott Long */ 85635863739SMike Smith cm = aac_dequeue_ready(sc); 85735863739SMike Smith 858914da7d0SScott Long /* 859914da7d0SScott Long * Try to build a command off the bio queue (ignore error 860914da7d0SScott Long * return) 861914da7d0SScott Long */ 8620b94a66eSMike Smith if (cm == NULL) 86335863739SMike Smith aac_bio_command(sc, &cm); 86435863739SMike Smith 86535863739SMike Smith /* nothing to do? */ 86635863739SMike Smith if (cm == NULL) 86735863739SMike Smith break; 86835863739SMike Smith 869cd481291SScott Long /* don't map more than once */ 870cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 8714102d44bSScott Long panic("aac: command %p already mapped", cm); 87235863739SMike Smith 873397fa34fSScott Long /* 874397fa34fSScott Long * Set up the command to go to the controller. If there are no 875397fa34fSScott Long * data buffers associated with the command then it can bypass 876397fa34fSScott Long * busdma. 877397fa34fSScott Long */ 878cd481291SScott Long if (cm->cm_datalen != 0) { 879397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 880397fa34fSScott Long cm->cm_datamap, cm->cm_data, 881397fa34fSScott Long cm->cm_datalen, 882cd481291SScott Long aac_map_command_sg, cm, 0); 883cd481291SScott Long if (error == EINPROGRESS) { 884cd481291SScott Long debug(1, "freezing queue\n"); 885cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 886cd481291SScott Long error = 0; 887614c22b2SScott Long } else if (error != 0) 888397fa34fSScott Long panic("aac_startio: unexpected error %d from " 889397fa34fSScott Long "busdma\n", error); 890397fa34fSScott Long } else 8918778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 892cd481291SScott Long } 89335863739SMike Smith } 89435863739SMike Smith 895914da7d0SScott Long /* 89635863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 89735863739SMike Smith */ 89835863739SMike Smith static void 89970545d1aSScott Long aac_command_thread(struct aac_softc *sc) 90035863739SMike Smith { 90135863739SMike Smith struct aac_fib *fib; 90235863739SMike Smith u_int32_t fib_size; 9039148fa21SScott Long int size, retval; 90435863739SMike Smith 90536e0bf6eSScott Long debug_called(2); 90635863739SMike Smith 907bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 908a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 90936e0bf6eSScott Long 910a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 911a32a982dSScott Long 912a32a982dSScott Long retval = 0; 913a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 914a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 915a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 91636e0bf6eSScott Long 9179148fa21SScott Long /* 9189148fa21SScott Long * First see if any FIBs need to be allocated. This needs 9199148fa21SScott Long * to be called without the driver lock because contigmalloc 9209148fa21SScott Long * will grab Giant, and would result in an LOR. 9219148fa21SScott Long */ 9229148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 923bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 924a32a982dSScott Long aac_alloc_commands(sc); 925bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 9264102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 927a32a982dSScott Long aac_startio(sc); 928a32a982dSScott Long } 9299148fa21SScott Long 9309148fa21SScott Long /* 9319148fa21SScott Long * While we're here, check to see if any commands are stuck. 9329148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 9339148fa21SScott Long * always fire. 9349148fa21SScott Long */ 9359148fa21SScott Long if (retval == EWOULDBLOCK) 93670545d1aSScott Long aac_timeout(sc); 93770545d1aSScott Long 93870545d1aSScott Long /* Check the hardware printf message buffer */ 9399148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 94070545d1aSScott Long aac_print_printf(sc); 94170545d1aSScott Long 9429148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 9437cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 9447cb209f5SScott Long continue; 9457cb209f5SScott Long for (;;) { 9467cb209f5SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 9477cb209f5SScott Long &fib_size, &fib)) 9487cb209f5SScott Long break; 94935863739SMike Smith 95036e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 95136e0bf6eSScott Long 95235863739SMike Smith switch (fib->Header.Command) { 95335863739SMike Smith case AifRequest: 95436e0bf6eSScott Long aac_handle_aif(sc, fib); 95535863739SMike Smith break; 95635863739SMike Smith default: 957914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 958914da7d0SScott Long "from controller\n"); 95935863739SMike Smith break; 96035863739SMike Smith } 96135863739SMike Smith 96236e0bf6eSScott Long if ((fib->Header.XferState == 0) || 9637cb209f5SScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 96436e0bf6eSScott Long break; 9657cb209f5SScott Long } 96636e0bf6eSScott Long 96770545d1aSScott Long /* Return the AIF to the controller. */ 96836e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 96936e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 97036e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 97136e0bf6eSScott Long 97236e0bf6eSScott Long /* XXX Compute the Size field? */ 97336e0bf6eSScott Long size = fib->Header.Size; 97436e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 97536e0bf6eSScott Long size = sizeof(struct aac_fib); 97636e0bf6eSScott Long fib->Header.Size = size; 97736e0bf6eSScott Long } 97836e0bf6eSScott Long /* 979914da7d0SScott Long * Since we did not generate this command, it 980914da7d0SScott Long * cannot go through the normal 981914da7d0SScott Long * enqueue->startio chain. 98236e0bf6eSScott Long */ 983914da7d0SScott Long aac_enqueue_response(sc, 984914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 985914da7d0SScott Long fib); 98636e0bf6eSScott Long } 98736e0bf6eSScott Long } 98836e0bf6eSScott Long } 98936e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 990bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 99136e0bf6eSScott Long wakeup(sc->aac_dev); 99236e0bf6eSScott Long 9933745c395SJulian Elischer kproc_exit(0); 99435863739SMike Smith } 99535863739SMike Smith 996914da7d0SScott Long /* 9979c3a7fceSScott Long * Process completed commands. 99835863739SMike Smith */ 99935863739SMike Smith static void 10009c3a7fceSScott Long aac_complete(void *context, int pending) 100135863739SMike Smith { 10029c3a7fceSScott Long struct aac_softc *sc; 100335863739SMike Smith struct aac_command *cm; 100435863739SMike Smith struct aac_fib *fib; 100535863739SMike Smith u_int32_t fib_size; 100635863739SMike Smith 100735863739SMike Smith debug_called(2); 100835863739SMike Smith 10099c3a7fceSScott Long sc = (struct aac_softc *)context; 10109c3a7fceSScott Long 1011bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1012ae543596SScott Long 10139c3a7fceSScott Long /* pull completed commands off the queue */ 101435863739SMike Smith for (;;) { 101535863739SMike Smith /* look for completed FIBs on our queue */ 1016914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1017914da7d0SScott Long &fib)) 101835863739SMike Smith break; /* nothing to do */ 101935863739SMike Smith 1020ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 1021cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 102235863739SMike Smith if (cm == NULL) { 102335863739SMike Smith AAC_PRINT_FIB(sc, fib); 10249c3a7fceSScott Long break; 10259c3a7fceSScott Long } 10260b94a66eSMike Smith aac_remove_busy(cm); 10277cb209f5SScott Long 1028ecd1c51fSScott Long aac_unmap_command(cm); 102935863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 103035863739SMike Smith 103135863739SMike Smith /* is there a completion handler? */ 103235863739SMike Smith if (cm->cm_complete != NULL) { 103335863739SMike Smith cm->cm_complete(cm); 103435863739SMike Smith } else { 103535863739SMike Smith /* assume that someone is sleeping on this command */ 103635863739SMike Smith wakeup(cm); 103735863739SMike Smith } 103835863739SMike Smith } 10390b94a66eSMike Smith 10400b94a66eSMike Smith /* see if we can start some more I/O */ 1041cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 10420b94a66eSMike Smith aac_startio(sc); 1043ae543596SScott Long 1044bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 104535863739SMike Smith } 104635863739SMike Smith 1047914da7d0SScott Long /* 104835863739SMike Smith * Handle a bio submitted from a disk device. 104935863739SMike Smith */ 105035863739SMike Smith void 105135863739SMike Smith aac_submit_bio(struct bio *bp) 105235863739SMike Smith { 1053914da7d0SScott Long struct aac_disk *ad; 1054914da7d0SScott Long struct aac_softc *sc; 105535863739SMike Smith 105635863739SMike Smith debug_called(2); 105735863739SMike Smith 10587540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1059914da7d0SScott Long sc = ad->ad_controller; 1060914da7d0SScott Long 106135863739SMike Smith /* queue the BIO and try to get some work done */ 10620b94a66eSMike Smith aac_enqueue_bio(sc, bp); 106335863739SMike Smith aac_startio(sc); 106435863739SMike Smith } 106535863739SMike Smith 1066914da7d0SScott Long /* 106735863739SMike Smith * Get a bio and build a command to go with it. 106835863739SMike Smith */ 106935863739SMike Smith static int 107035863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 107135863739SMike Smith { 107235863739SMike Smith struct aac_command *cm; 107335863739SMike Smith struct aac_fib *fib; 107435863739SMike Smith struct aac_disk *ad; 107535863739SMike Smith struct bio *bp; 107635863739SMike Smith 107735863739SMike Smith debug_called(2); 107835863739SMike Smith 107935863739SMike Smith /* get the resources we will need */ 108035863739SMike Smith cm = NULL; 1081a32a982dSScott Long bp = NULL; 108235863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 108335863739SMike Smith goto fail; 1084a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 1085a32a982dSScott Long goto fail; 108635863739SMike Smith 108735863739SMike Smith /* fill out the command */ 10880b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 10890b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 10900b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 109135863739SMike Smith cm->cm_private = bp; 10922b3b0f17SScott Long cm->cm_timestamp = time_uptime; 109336e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 109435863739SMike Smith 109535863739SMike Smith /* build the FIB */ 109635863739SMike Smith fib = cm->cm_fib; 1097b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 109835863739SMike Smith fib->Header.XferState = 109935863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 110035863739SMike Smith AAC_FIBSTATE_INITIALISED | 1101f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 110235863739SMike Smith AAC_FIBSTATE_FROMHOST | 110335863739SMike Smith AAC_FIBSTATE_REXPECTED | 1104f30ac74cSScott Long AAC_FIBSTATE_NORM | 1105f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 1106f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 110735863739SMike Smith 110835863739SMike Smith /* build the read/write request */ 11097540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1110b85f5808SScott Long 11117cb209f5SScott Long if (sc->flags & AAC_FLAGS_RAW_IO) { 11127cb209f5SScott Long struct aac_raw_io *raw; 11137cb209f5SScott Long raw = (struct aac_raw_io *)&fib->data[0]; 11147cb209f5SScott Long fib->Header.Command = RawIo; 11157cb209f5SScott Long raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 11167cb209f5SScott Long raw->ByteCount = bp->bio_bcount; 11177cb209f5SScott Long raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 11187cb209f5SScott Long raw->BpTotal = 0; 11197cb209f5SScott Long raw->BpComplete = 0; 11207cb209f5SScott Long fib->Header.Size += sizeof(struct aac_raw_io); 11217cb209f5SScott Long cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 11227cb209f5SScott Long if (bp->bio_cmd == BIO_READ) { 11237cb209f5SScott Long raw->Flags = 1; 11247cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 11257cb209f5SScott Long } else { 11267cb209f5SScott Long raw->Flags = 0; 11277cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 11287cb209f5SScott Long } 11297cb209f5SScott Long } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1130b85f5808SScott Long fib->Header.Command = ContainerCommand; 11319e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 1132b85f5808SScott Long struct aac_blockread *br; 113335863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 113435863739SMike Smith br->Command = VM_CtBlockRead; 113535863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 113635863739SMike Smith br->BlockNumber = bp->bio_pblkno; 113735863739SMike Smith br->ByteCount = bp->bio_bcount; 113835863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 113935863739SMike Smith cm->cm_sgtable = &br->SgMap; 114035863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 114135863739SMike Smith } else { 1142b85f5808SScott Long struct aac_blockwrite *bw; 114335863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 114435863739SMike Smith bw->Command = VM_CtBlockWrite; 114535863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 114635863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 114735863739SMike Smith bw->ByteCount = bp->bio_bcount; 1148b85f5808SScott Long bw->Stable = CUNSTABLE; 114935863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 115035863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 115135863739SMike Smith cm->cm_sgtable = &bw->SgMap; 115235863739SMike Smith } 1153b85f5808SScott Long } else { 1154b85f5808SScott Long fib->Header.Command = ContainerCommand64; 1155b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 1156b85f5808SScott Long struct aac_blockread64 *br; 1157b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 1158b85f5808SScott Long br->Command = VM_CtHostRead64; 1159b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1160b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1161b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 1162b85f5808SScott Long br->Pad = 0; 1163b85f5808SScott Long br->Flags = 0; 1164b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 1165b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 1166eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1167b85f5808SScott Long } else { 1168b85f5808SScott Long struct aac_blockwrite64 *bw; 1169b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 1170b85f5808SScott Long bw->Command = VM_CtHostWrite64; 1171b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1172b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1173b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 1174b85f5808SScott Long bw->Pad = 0; 1175b85f5808SScott Long bw->Flags = 0; 1176b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 1177b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 1178eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1179b85f5808SScott Long } 1180b85f5808SScott Long } 118135863739SMike Smith 118235863739SMike Smith *cmp = cm; 118335863739SMike Smith return(0); 118435863739SMike Smith 118535863739SMike Smith fail: 11867cb209f5SScott Long if (bp != NULL) 11877cb209f5SScott Long aac_enqueue_bio(sc, bp); 118835863739SMike Smith if (cm != NULL) 118935863739SMike Smith aac_release_command(cm); 119035863739SMike Smith return(ENOMEM); 119135863739SMike Smith } 119235863739SMike Smith 1193914da7d0SScott Long /* 119435863739SMike Smith * Handle a bio-instigated command that has been completed. 119535863739SMike Smith */ 119635863739SMike Smith static void 119735863739SMike Smith aac_bio_complete(struct aac_command *cm) 119835863739SMike Smith { 119935863739SMike Smith struct aac_blockread_response *brr; 120035863739SMike Smith struct aac_blockwrite_response *bwr; 120135863739SMike Smith struct bio *bp; 120235863739SMike Smith AAC_FSAStatus status; 120335863739SMike Smith 120435863739SMike Smith /* fetch relevant status and then release the command */ 120535863739SMike Smith bp = (struct bio *)cm->cm_private; 12069e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 120735863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 120835863739SMike Smith status = brr->Status; 120935863739SMike Smith } else { 121035863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 121135863739SMike Smith status = bwr->Status; 121235863739SMike Smith } 121335863739SMike Smith aac_release_command(cm); 121435863739SMike Smith 121535863739SMike Smith /* fix up the bio based on status */ 121635863739SMike Smith if (status == ST_OK) { 121735863739SMike Smith bp->bio_resid = 0; 121835863739SMike Smith } else { 121935863739SMike Smith bp->bio_error = EIO; 122035863739SMike Smith bp->bio_flags |= BIO_ERROR; 12210b94a66eSMike Smith /* pass an error string out to the disk layer */ 1222914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1223914da7d0SScott Long status); 122435863739SMike Smith } 12250b94a66eSMike Smith aac_biodone(bp); 122635863739SMike Smith } 122735863739SMike Smith 1228914da7d0SScott Long /* 122935863739SMike Smith * Submit a command to the controller, return when it completes. 1230b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1231b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1232d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1233d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1234d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1235d8a0a473SScott Long * card completing a command late and spamming the command and data 1236d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 123735863739SMike Smith */ 123835863739SMike Smith static int 1239d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 124035863739SMike Smith { 1241ae543596SScott Long struct aac_softc *sc; 1242d8a0a473SScott Long int error; 124335863739SMike Smith 124435863739SMike Smith debug_called(2); 124535863739SMike Smith 1246ae543596SScott Long sc = cm->cm_sc; 1247ae543596SScott Long 124835863739SMike Smith /* Put the command on the ready queue and get things going */ 124936e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 125035863739SMike Smith aac_enqueue_ready(cm); 1251ae543596SScott Long aac_startio(sc); 1252ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 125335863739SMike Smith return(error); 125435863739SMike Smith } 125535863739SMike Smith 1256914da7d0SScott Long /* 1257914da7d0SScott Long *Command Buffer Management 1258914da7d0SScott Long */ 125935863739SMike Smith 1260914da7d0SScott Long /* 126135863739SMike Smith * Allocate a command. 126235863739SMike Smith */ 1263fe3cb0e1SScott Long int 126435863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 126535863739SMike Smith { 126635863739SMike Smith struct aac_command *cm; 126735863739SMike Smith 126835863739SMike Smith debug_called(3); 126935863739SMike Smith 1270ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1271b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1272ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1273ae543596SScott Long wakeup(sc->aifthread); 1274b85f5808SScott Long } 1275ae543596SScott Long return (EBUSY); 1276ffb37f33SScott Long } 127735863739SMike Smith 12780b94a66eSMike Smith *cmp = cm; 12790b94a66eSMike Smith return(0); 12800b94a66eSMike Smith } 12810b94a66eSMike Smith 1282914da7d0SScott Long /* 12830b94a66eSMike Smith * Release a command back to the freelist. 12840b94a66eSMike Smith */ 1285fe3cb0e1SScott Long void 12860b94a66eSMike Smith aac_release_command(struct aac_command *cm) 12870b94a66eSMike Smith { 12887cb209f5SScott Long struct aac_event *event; 12897cb209f5SScott Long struct aac_softc *sc; 12907cb209f5SScott Long 12910b94a66eSMike Smith debug_called(3); 12920b94a66eSMike Smith 12930b94a66eSMike Smith /* (re)initialise the command/FIB */ 129435863739SMike Smith cm->cm_sgtable = NULL; 129535863739SMike Smith cm->cm_flags = 0; 129635863739SMike Smith cm->cm_complete = NULL; 129735863739SMike Smith cm->cm_private = NULL; 129835863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 129935863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 130035863739SMike Smith cm->cm_fib->Header.Flags = 0; 13017cb209f5SScott Long cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 130235863739SMike Smith 130335863739SMike Smith /* 130435863739SMike Smith * These are duplicated in aac_start to cover the case where an 130535863739SMike Smith * intermediate stage may have destroyed them. They're left 130635863739SMike Smith * initialised here for debugging purposes only. 130735863739SMike Smith */ 1308f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1309f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 131035863739SMike Smith 131135863739SMike Smith aac_enqueue_free(cm); 13127cb209f5SScott Long 1313eb5cbaa0SEd Maste /* 1314eb5cbaa0SEd Maste * Dequeue all events so that there's no risk of events getting 1315eb5cbaa0SEd Maste * stranded. 1316eb5cbaa0SEd Maste */ 13177cb209f5SScott Long sc = cm->cm_sc; 1318eb5cbaa0SEd Maste while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 13197cb209f5SScott Long TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 13207cb209f5SScott Long event->ev_callback(sc, event, event->ev_arg); 13217cb209f5SScott Long } 132235863739SMike Smith } 132335863739SMike Smith 1324914da7d0SScott Long /* 13250b94a66eSMike Smith * Map helper for command/FIB allocation. 132635863739SMike Smith */ 132735863739SMike Smith static void 13280b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 132935863739SMike Smith { 13307cb209f5SScott Long uint64_t *fibphys; 1331914da7d0SScott Long 13327cb209f5SScott Long fibphys = (uint64_t *)arg; 133335863739SMike Smith 133435863739SMike Smith debug_called(3); 133535863739SMike Smith 1336ffb37f33SScott Long *fibphys = segs[0].ds_addr; 133735863739SMike Smith } 133835863739SMike Smith 1339914da7d0SScott Long /* 13400b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 134135863739SMike Smith */ 13420b94a66eSMike Smith static int 13430b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 134435863739SMike Smith { 134535863739SMike Smith struct aac_command *cm; 1346ffb37f33SScott Long struct aac_fibmap *fm; 13477cb209f5SScott Long uint64_t fibphys; 1348ffb37f33SScott Long int i, error; 134935863739SMike Smith 1350a6d35632SScott Long debug_called(2); 135135863739SMike Smith 13527cb209f5SScott Long if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1353ffb37f33SScott Long return (ENOMEM); 1354ffb37f33SScott Long 13558480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1356a6d35632SScott Long if (fm == NULL) 1357a6d35632SScott Long return (ENOMEM); 1358ffb37f33SScott Long 13590b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1360ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1361ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 136270545d1aSScott Long device_printf(sc->aac_dev, 136370545d1aSScott Long "Not enough contiguous memory available.\n"); 13648480cc63SScott Long free(fm, M_AACBUF); 13650b94a66eSMike Smith return (ENOMEM); 136635863739SMike Smith } 1367128aa5a0SScott Long 1368cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1369cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 13707cb209f5SScott Long sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1371ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1372128aa5a0SScott Long 13730b94a66eSMike Smith /* initialise constant fields in the command structure */ 13747cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 13757cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 13768480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1377ffb37f33SScott Long fm->aac_commands = cm; 137835863739SMike Smith cm->cm_sc = sc; 13797cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 13807cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 13817cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1382cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 138335863739SMike Smith 1384ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 138593cfca22SScott Long &cm->cm_datamap)) != 0) 13868480cc63SScott Long break; 138793cfca22SScott Long mtx_lock(&sc->aac_io_lock); 138893cfca22SScott Long aac_release_command(cm); 13898480cc63SScott Long sc->total_fibs++; 139093cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 139135863739SMike Smith } 1392ffb37f33SScott Long 13938480cc63SScott Long if (i > 0) { 139493cfca22SScott Long mtx_lock(&sc->aac_io_lock); 1395ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1396a6d35632SScott Long debug(1, "total_fibs= %d\n", sc->total_fibs); 1397bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 13980b94a66eSMike Smith return (0); 139935863739SMike Smith } 140035863739SMike Smith 14018480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 14028480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 14038480cc63SScott Long free(fm, M_AACBUF); 14048480cc63SScott Long return (ENOMEM); 14058480cc63SScott Long } 14068480cc63SScott Long 1407914da7d0SScott Long /* 14080b94a66eSMike Smith * Free FIBs owned by this adapter. 140935863739SMike Smith */ 141035863739SMike Smith static void 14118480cc63SScott Long aac_free_commands(struct aac_softc *sc) 141235863739SMike Smith { 14138480cc63SScott Long struct aac_fibmap *fm; 1414ffb37f33SScott Long struct aac_command *cm; 141535863739SMike Smith int i; 141635863739SMike Smith 141735863739SMike Smith debug_called(1); 141835863739SMike Smith 14198480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 14208480cc63SScott Long 14218480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 14228480cc63SScott Long /* 14238480cc63SScott Long * We check against total_fibs to handle partially 14248480cc63SScott Long * allocated blocks. 14258480cc63SScott Long */ 14267cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1427ffb37f33SScott Long cm = fm->aac_commands + i; 1428ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1429ffb37f33SScott Long } 1430ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1431ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 14328480cc63SScott Long free(fm, M_AACBUF); 14338480cc63SScott Long } 143435863739SMike Smith } 143535863739SMike Smith 1436914da7d0SScott Long /* 143735863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 143835863739SMike Smith */ 143935863739SMike Smith static void 144035863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 144135863739SMike Smith { 1442cd481291SScott Long struct aac_softc *sc; 1443914da7d0SScott Long struct aac_command *cm; 1444914da7d0SScott Long struct aac_fib *fib; 144535863739SMike Smith int i; 144635863739SMike Smith 144735863739SMike Smith debug_called(3); 144835863739SMike Smith 1449914da7d0SScott Long cm = (struct aac_command *)arg; 1450cd481291SScott Long sc = cm->cm_sc; 1451914da7d0SScott Long fib = cm->cm_fib; 1452914da7d0SScott Long 145335863739SMike Smith /* copy into the FIB */ 1454b85f5808SScott Long if (cm->cm_sgtable != NULL) { 14557cb209f5SScott Long if (fib->Header.Command == RawIo) { 14567cb209f5SScott Long struct aac_sg_tableraw *sg; 14577cb209f5SScott Long sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 14587cb209f5SScott Long sg->SgCount = nseg; 14597cb209f5SScott Long for (i = 0; i < nseg; i++) { 14607cb209f5SScott Long sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 14617cb209f5SScott Long sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 14627cb209f5SScott Long sg->SgEntryRaw[i].Next = 0; 14637cb209f5SScott Long sg->SgEntryRaw[i].Prev = 0; 14647cb209f5SScott Long sg->SgEntryRaw[i].Flags = 0; 14657cb209f5SScott Long } 14667cb209f5SScott Long /* update the FIB size for the s/g count */ 14677cb209f5SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 14687cb209f5SScott Long } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1469b85f5808SScott Long struct aac_sg_table *sg; 1470b85f5808SScott Long sg = cm->cm_sgtable; 147135863739SMike Smith sg->SgCount = nseg; 147235863739SMike Smith for (i = 0; i < nseg; i++) { 147335863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 147435863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 147535863739SMike Smith } 147635863739SMike Smith /* update the FIB size for the s/g count */ 147735863739SMike Smith fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1478b85f5808SScott Long } else { 1479b85f5808SScott Long struct aac_sg_table64 *sg; 1480b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1481b85f5808SScott Long sg->SgCount = nseg; 1482b85f5808SScott Long for (i = 0; i < nseg; i++) { 1483b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1484b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 148535863739SMike Smith } 1486b85f5808SScott Long /* update the FIB size for the s/g count */ 1487b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1488b85f5808SScott Long } 1489b85f5808SScott Long } 149035863739SMike Smith 1491cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1492cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 14937cb209f5SScott Long * the SenderFibAddress over to make room for the fast response bit 14947cb209f5SScott Long * and for the AIF bit 149535863739SMike Smith */ 14967cb209f5SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 14977cb209f5SScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 149835863739SMike Smith 1499cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1500cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 150135863739SMike Smith 150235863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1503c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1504c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 150535863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1506c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1507c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 150835863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1509cd481291SScott Long 15107cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 15117cb209f5SScott Long int count = 10000000L; 15127cb209f5SScott Long while (AAC_SEND_COMMAND(sc, cm) != 0) { 15137cb209f5SScott Long if (--count == 0) { 15147cb209f5SScott Long aac_unmap_command(cm); 15157cb209f5SScott Long sc->flags |= AAC_QUEUE_FRZN; 15167cb209f5SScott Long aac_requeue_ready(cm); 15177cb209f5SScott Long } 15187cb209f5SScott Long DELAY(5); /* wait 5 usec. */ 15197cb209f5SScott Long } 15207cb209f5SScott Long } else { 1521397fa34fSScott Long /* Put the FIB on the outbound queue */ 15224102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 15234102d44bSScott Long aac_unmap_command(cm); 1524397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1525cd481291SScott Long aac_requeue_ready(cm); 15264102d44bSScott Long } 15277cb209f5SScott Long } 1528cd481291SScott Long 1529cd481291SScott Long return; 153035863739SMike Smith } 153135863739SMike Smith 1532914da7d0SScott Long /* 153335863739SMike Smith * Unmap a command from controller-visible space. 153435863739SMike Smith */ 153535863739SMike Smith static void 153635863739SMike Smith aac_unmap_command(struct aac_command *cm) 153735863739SMike Smith { 1538914da7d0SScott Long struct aac_softc *sc; 153935863739SMike Smith 154035863739SMike Smith debug_called(2); 154135863739SMike Smith 1542914da7d0SScott Long sc = cm->cm_sc; 1543914da7d0SScott Long 154435863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 154535863739SMike Smith return; 154635863739SMike Smith 154735863739SMike Smith if (cm->cm_datalen != 0) { 154835863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1549c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1550c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 155135863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1552c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1553c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 155435863739SMike Smith 155535863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 155635863739SMike Smith } 155735863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 155835863739SMike Smith } 155935863739SMike Smith 1560914da7d0SScott Long /* 1561914da7d0SScott Long * Hardware Interface 1562914da7d0SScott Long */ 156335863739SMike Smith 1564914da7d0SScott Long /* 156535863739SMike Smith * Initialise the adapter. 156635863739SMike Smith */ 156735863739SMike Smith static void 156835863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 156935863739SMike Smith { 1570914da7d0SScott Long struct aac_softc *sc; 157135863739SMike Smith 157235863739SMike Smith debug_called(1); 157335863739SMike Smith 1574914da7d0SScott Long sc = (struct aac_softc *)arg; 1575914da7d0SScott Long 157635863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 157735863739SMike Smith } 157835863739SMike Smith 1579a6d35632SScott Long static int 1580a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1581a6d35632SScott Long { 1582a441b3fcSScott Long u_int32_t major, minor, options = 0, atu_size = 0; 1583a441b3fcSScott Long int status; 1584a6d35632SScott Long 1585a6d35632SScott Long debug_called(1); 1586a6d35632SScott Long 1587fe94b852SScott Long /* 1588fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1589fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1590fe94b852SScott Long */ 1591a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1592fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1593fe94b852SScott Long NULL)) { 1594fe94b852SScott Long device_printf(sc->aac_dev, 1595fe94b852SScott Long "Error reading firmware version\n"); 1596fe94b852SScott Long return (EIO); 1597fe94b852SScott Long } 1598fe94b852SScott Long 1599fe94b852SScott Long /* These numbers are stored as ASCII! */ 1600a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1601a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1602fe94b852SScott Long if (major == 1) { 1603fe94b852SScott Long device_printf(sc->aac_dev, 1604fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1605fe94b852SScott Long major, minor); 1606fe94b852SScott Long return (EINVAL); 1607fe94b852SScott Long } 1608fe94b852SScott Long } 1609fe94b852SScott Long 1610a6d35632SScott Long /* 1611a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1612a441b3fcSScott Long * work-arounds to enable. Some firmware revs don't support this 1613a441b3fcSScott Long * command. 1614a6d35632SScott Long */ 1615a441b3fcSScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1616a441b3fcSScott Long if (status != AAC_SRB_STS_INVALID_REQUEST) { 1617a441b3fcSScott Long device_printf(sc->aac_dev, 1618a441b3fcSScott Long "RequestAdapterInfo failed\n"); 1619a6d35632SScott Long return (EIO); 1620a6d35632SScott Long } 1621a441b3fcSScott Long } else { 1622a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 16237cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1624a6d35632SScott Long sc->supported_options = options; 1625a6d35632SScott Long 1626a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1627a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1628a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1629a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1630a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1631cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1632cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1633a441b3fcSScott Long device_printf(sc->aac_dev, 1634a441b3fcSScott Long "Enabling 64-bit address support\n"); 1635a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1636a6d35632SScott Long } 1637a441b3fcSScott Long if ((options & AAC_SUPPORTED_NEW_COMM) 1638a441b3fcSScott Long && sc->aac_if.aif_send_command) 16397cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 16407cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 16417cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1642a441b3fcSScott Long } 1643a6d35632SScott Long 1644a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 16457cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 16467cb209f5SScott Long 16477cb209f5SScott Long /* Remap mem. resource, if required */ 16487cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 16497cb209f5SScott Long atu_size > rman_get_size(sc->aac_regs_resource)) { 16507cb209f5SScott Long bus_release_resource( 16517cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 16527cb209f5SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 16537cb209f5SScott Long sc->aac_regs_resource = bus_alloc_resource( 16547cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid, 16557cb209f5SScott Long 0ul, ~0ul, atu_size, RF_ACTIVE); 16567cb209f5SScott Long if (sc->aac_regs_resource == NULL) { 16577cb209f5SScott Long sc->aac_regs_resource = bus_alloc_resource_any( 16587cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 16597cb209f5SScott Long &sc->aac_regs_rid, RF_ACTIVE); 16607cb209f5SScott Long if (sc->aac_regs_resource == NULL) { 16617cb209f5SScott Long device_printf(sc->aac_dev, 16627cb209f5SScott Long "couldn't allocate register window\n"); 16637cb209f5SScott Long return (ENXIO); 16647cb209f5SScott Long } 16657cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 16667cb209f5SScott Long } 16677cb209f5SScott Long sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); 16687cb209f5SScott Long sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); 16697cb209f5SScott Long } 16707cb209f5SScott Long 16717cb209f5SScott Long /* Read preferred settings */ 16727cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 16737cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 16747cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 1675a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 16767e7a458eSEd Maste - sizeof(struct aac_blockwrite64)) 16777e7a458eSEd Maste / sizeof(struct aac_sg_entry64); 1678a6d35632SScott Long else 1679a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 16807e7a458eSEd Maste - sizeof(struct aac_blockwrite)) 16817e7a458eSEd Maste / sizeof(struct aac_sg_entry); 1682a441b3fcSScott Long 16837cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 16847cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 16857cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 16867cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 16877cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 16887cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 16897cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 16907cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 16917cb209f5SScott Long } 16927cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 16937cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 16947cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1695a6d35632SScott Long 1696fe94b852SScott Long return (0); 1697fe94b852SScott Long } 1698fe94b852SScott Long 169935863739SMike Smith static int 170035863739SMike Smith aac_init(struct aac_softc *sc) 170135863739SMike Smith { 170235863739SMike Smith struct aac_adapter_init *ip; 170335863739SMike Smith time_t then; 1704b88ffdc8SScott Long u_int32_t code, qoffset; 1705a6d35632SScott Long int error; 170635863739SMike Smith 170735863739SMike Smith debug_called(1); 170835863739SMike Smith 170935863739SMike Smith /* 171035863739SMike Smith * First wait for the adapter to come ready. 171135863739SMike Smith */ 17122b3b0f17SScott Long then = time_uptime; 171335863739SMike Smith do { 171435863739SMike Smith code = AAC_GET_FWSTATUS(sc); 171535863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 171635863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 171735863739SMike Smith return(ENXIO); 171835863739SMike Smith } 171935863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1720914da7d0SScott Long device_printf(sc->aac_dev, 1721914da7d0SScott Long "FATAL: controller kernel panic\n"); 172235863739SMike Smith return(ENXIO); 172335863739SMike Smith } 17242b3b0f17SScott Long if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1725914da7d0SScott Long device_printf(sc->aac_dev, 1726914da7d0SScott Long "FATAL: controller not coming ready, " 1727c6eafcf2SScott Long "status %x\n", code); 172835863739SMike Smith return(ENXIO); 172935863739SMike Smith } 173035863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 173135863739SMike Smith 1732a6d35632SScott Long error = ENOMEM; 1733a6d35632SScott Long /* 1734a6d35632SScott Long * Create DMA tag for mapping buffers into controller-addressable space. 1735a6d35632SScott Long */ 1736a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1737a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1738a6d35632SScott Long (sc->flags & AAC_FLAGS_SG_64BIT) ? 1739a6d35632SScott Long BUS_SPACE_MAXADDR : 1740a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1741a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1742a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1743a6d35632SScott Long MAXBSIZE, /* maxsize */ 17447cb209f5SScott Long sc->aac_sg_tablesize, /* nsegments */ 1745a6d35632SScott Long MAXBSIZE, /* maxsegsize */ 1746a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1747f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 1748f6b1c44dSScott Long &sc->aac_io_lock, /* lockfuncarg */ 1749a6d35632SScott Long &sc->aac_buffer_dmat)) { 1750a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1751a6d35632SScott Long goto out; 1752a6d35632SScott Long } 1753a6d35632SScott Long 1754a6d35632SScott Long /* 1755a6d35632SScott Long * Create DMA tag for mapping FIBs into controller-addressable space.. 1756a6d35632SScott Long */ 1757a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1758a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1759a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1760a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1761a6d35632SScott Long 0x7fffffff, /* lowaddr */ 1762a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1763a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 17647cb209f5SScott Long sc->aac_max_fibs_alloc * 17657cb209f5SScott Long sc->aac_max_fib_size, /* maxsize */ 1766a6d35632SScott Long 1, /* nsegments */ 17677cb209f5SScott Long sc->aac_max_fibs_alloc * 17687cb209f5SScott Long sc->aac_max_fib_size, /* maxsegsize */ 17691248408dSScott Long 0, /* flags */ 1770f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 1771a6d35632SScott Long &sc->aac_fib_dmat)) { 1772a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1773a6d35632SScott Long goto out; 1774a6d35632SScott Long } 1775a6d35632SScott Long 177635863739SMike Smith /* 177735863739SMike Smith * Create DMA tag for the common structure and allocate it. 177835863739SMike Smith */ 177935863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1780c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1781a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1782a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1783a6d35632SScott Long 0x7fffffff, /* lowaddr */ 178435863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 178535863739SMike Smith NULL, NULL, /* filter, filterarg */ 1786ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1787914da7d0SScott Long 1, /* nsegments */ 178835863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 17891248408dSScott Long 0, /* flags */ 1790f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 179135863739SMike Smith &sc->aac_common_dmat)) { 1792914da7d0SScott Long device_printf(sc->aac_dev, 1793914da7d0SScott Long "can't allocate common structure DMA tag\n"); 1794a6d35632SScott Long goto out; 179535863739SMike Smith } 1796c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1797c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 179835863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 1799a6d35632SScott Long goto out; 180035863739SMike Smith } 1801ffb37f33SScott Long 1802ffb37f33SScott Long /* 1803ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1804ffb37f33SScott Long * below address 8192 in physical memory. 1805ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1806ffb37f33SScott Long * of ignored? 1807ffb37f33SScott Long */ 1808cd481291SScott Long (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1809ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1810ffb37f33SScott Long aac_common_map, sc, 0); 1811ffb37f33SScott Long 1812ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1813eec256deSAlexander Kabaev sc->aac_common = (struct aac_common *) 1814eec256deSAlexander Kabaev ((uint8_t *)sc->aac_common + 8192); 1815ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1816ffb37f33SScott Long } 181735863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 181835863739SMike Smith 1819ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1820ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 18217cb209f5SScott Long sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 18228480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 18238480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1824ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1825ffb37f33SScott Long break; 1826ffb37f33SScott Long } 1827ffb37f33SScott Long if (sc->total_fibs == 0) 1828a6d35632SScott Long goto out; 1829ffb37f33SScott Long 183035863739SMike Smith /* 1831914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1832914da7d0SScott Long * physical location of various important shared data structures. 183335863739SMike Smith */ 183435863739SMike Smith ip = &sc->aac_common->ac_init; 183535863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18367cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18377cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18387cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18397cb209f5SScott Long } 1840f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 184135863739SMike Smith 1842c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1843c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1844149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 184535863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 184635863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 184735863739SMike Smith 1848c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1849c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 185035863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 185135863739SMike Smith 18524b00f859SScott Long /* 18534b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18544b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18554b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18564b00f859SScott Long * Round up since the granularity is so high. 18574b00f859SScott Long */ 1858f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18594b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 18604b00f859SScott Long ip->HostPhysMemPages = 18614b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1862204c0befSScott Long } 18632b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 186435863739SMike Smith 18657cb209f5SScott Long ip->InitFlags = 0; 18667cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 18677cb209f5SScott Long ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 18687cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 18697cb209f5SScott Long } 18707cb209f5SScott Long 18717cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 18727cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 18737cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 18747cb209f5SScott Long 187535863739SMike Smith /* 1876c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1877c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1878c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 187935863739SMike Smith * 188035863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1881914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1882914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1883914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1884914da7d0SScott Long * does. 188535863739SMike Smith * 1886914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1887914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1888914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1889914da7d0SScott Long * virtue of a table. 189035863739SMike Smith */ 1891b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 18920bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 18930bcbebd6SScott Long sc->aac_queues = 18940bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1895b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 189635863739SMike Smith 1897c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1898c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1899c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1900c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1901c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1902c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1903c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1904c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1905c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1906c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1907c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1908c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1909c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1910c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1911c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1912c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1913c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1914c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1915c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1916c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1917c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1918c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1919c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1920c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1921c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1922c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1923c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1924c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1925c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1926c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1927c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1928c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1929c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1930c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1931c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1932c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1933c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1934c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1935c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1936c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1937c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1938c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1939c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1940c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1941c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1942c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1943c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1944c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 194535863739SMike Smith 194635863739SMike Smith /* 194735863739SMike Smith * Do controller-type-specific initialisation 194835863739SMike Smith */ 194935863739SMike Smith switch (sc->aac_hwif) { 195035863739SMike Smith case AAC_HWIF_I960RX: 195135863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 195235863739SMike Smith break; 19534afedc31SScott Long case AAC_HWIF_RKT: 19544afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); 19554afedc31SScott Long break; 19564afedc31SScott Long default: 19574afedc31SScott Long break; 195835863739SMike Smith } 195935863739SMike Smith 196035863739SMike Smith /* 196135863739SMike Smith * Give the init structure to the controller. 196235863739SMike Smith */ 196335863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1964914da7d0SScott Long sc->aac_common_busaddr + 1965914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1966914da7d0SScott Long NULL)) { 1967914da7d0SScott Long device_printf(sc->aac_dev, 1968914da7d0SScott Long "error establishing init structure\n"); 1969a6d35632SScott Long error = EIO; 1970a6d35632SScott Long goto out; 197135863739SMike Smith } 197235863739SMike Smith 1973a6d35632SScott Long error = 0; 1974a6d35632SScott Long out: 1975a6d35632SScott Long return(error); 197635863739SMike Smith } 197735863739SMike Smith 1978914da7d0SScott Long /* 197935863739SMike Smith * Send a synchronous command to the controller and wait for a result. 19807cb209f5SScott Long * Indicate if the controller completed the command with an error status. 198135863739SMike Smith */ 198235863739SMike Smith static int 198335863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 198435863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 198535863739SMike Smith u_int32_t *sp) 198635863739SMike Smith { 198735863739SMike Smith time_t then; 198835863739SMike Smith u_int32_t status; 198935863739SMike Smith 199035863739SMike Smith debug_called(3); 199135863739SMike Smith 199235863739SMike Smith /* populate the mailbox */ 199335863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 199435863739SMike Smith 199535863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 199635863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 199735863739SMike Smith 199835863739SMike Smith /* then set it to signal the adapter */ 199935863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 200035863739SMike Smith 200135863739SMike Smith /* spin waiting for the command to complete */ 20022b3b0f17SScott Long then = time_uptime; 200335863739SMike Smith do { 20042b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 2005a6d35632SScott Long debug(1, "timed out"); 200635863739SMike Smith return(EIO); 200735863739SMike Smith } 200835863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 200935863739SMike Smith 201035863739SMike Smith /* clear the completion flag */ 201135863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 201235863739SMike Smith 201335863739SMike Smith /* get the command status */ 2014a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 201535863739SMike Smith if (sp != NULL) 201635863739SMike Smith *sp = status; 20177cb209f5SScott Long 2018a441b3fcSScott Long if (status != AAC_SRB_STS_SUCCESS) 20197cb209f5SScott Long return (-1); 20200b94a66eSMike Smith return(0); 202135863739SMike Smith } 202235863739SMike Smith 2023cbfd045bSScott Long int 202435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2025cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 202635863739SMike Smith { 202735863739SMike Smith debug_called(3); 20287cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 202935863739SMike Smith 203035863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 203135863739SMike Smith return(EINVAL); 203235863739SMike Smith 203335863739SMike Smith /* 203435863739SMike Smith * Set up the sync FIB 203535863739SMike Smith */ 2036914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2037914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2038c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 203935863739SMike Smith fib->Header.XferState |= xferstate; 204035863739SMike Smith fib->Header.Command = command; 204135863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 204235863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 204335863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2044b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2045c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2046914da7d0SScott Long offsetof(struct aac_common, 2047914da7d0SScott Long ac_sync_fib); 204835863739SMike Smith 204935863739SMike Smith /* 205035863739SMike Smith * Give the FIB to the controller, wait for a response. 205135863739SMike Smith */ 2052914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2053914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 205435863739SMike Smith debug(2, "IO error"); 205535863739SMike Smith return(EIO); 205635863739SMike Smith } 205735863739SMike Smith 205835863739SMike Smith return (0); 205935863739SMike Smith } 206035863739SMike Smith 2061914da7d0SScott Long /* 206235863739SMike Smith * Adapter-space FIB queue manipulation 206335863739SMike Smith * 206435863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 206535863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 206635863739SMike Smith */ 206735863739SMike Smith static struct { 206835863739SMike Smith int size; 206935863739SMike Smith int notify; 207035863739SMike Smith } aac_qinfo[] = { 207135863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 207235863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 207335863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 207435863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 207535863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 207635863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 207735863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 207835863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 207935863739SMike Smith }; 208035863739SMike Smith 208135863739SMike Smith /* 2082c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2083c6eafcf2SScott Long * EBUSY if the queue is full. 208435863739SMike Smith * 20850b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2086914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2087914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2088c6eafcf2SScott Long * separate queue/notify interface). 208935863739SMike Smith */ 209035863739SMike Smith static int 2091f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 209235863739SMike Smith { 209335863739SMike Smith u_int32_t pi, ci; 20949e2e96d8SScott Long int error; 2095f6c4dd3fSScott Long u_int32_t fib_size; 2096f6c4dd3fSScott Long u_int32_t fib_addr; 2097f6c4dd3fSScott Long 209836e0bf6eSScott Long debug_called(3); 209936e0bf6eSScott Long 2100f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2101f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 210235863739SMike Smith 210335863739SMike Smith /* get the producer/consumer indices */ 210435863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 210535863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 210635863739SMike Smith 210735863739SMike Smith /* wrap the queue? */ 210835863739SMike Smith if (pi >= aac_qinfo[queue].size) 210935863739SMike Smith pi = 0; 211035863739SMike Smith 211135863739SMike Smith /* check for queue full */ 211235863739SMike Smith if ((pi + 1) == ci) { 211335863739SMike Smith error = EBUSY; 211435863739SMike Smith goto out; 211535863739SMike Smith } 211635863739SMike Smith 2117614c22b2SScott Long /* 2118614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2119614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2120614c22b2SScott Long */ 2121614c22b2SScott Long aac_enqueue_busy(cm); 2122614c22b2SScott Long 212335863739SMike Smith /* populate queue entry */ 212435863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 212535863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 212635863739SMike Smith 212735863739SMike Smith /* update producer index */ 212835863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 212935863739SMike Smith 213035863739SMike Smith /* notify the adapter if we know how */ 213135863739SMike Smith if (aac_qinfo[queue].notify != 0) 213235863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 213335863739SMike Smith 213435863739SMike Smith error = 0; 213535863739SMike Smith 213635863739SMike Smith out: 213735863739SMike Smith return(error); 213835863739SMike Smith } 213935863739SMike Smith 214035863739SMike Smith /* 214136e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 214236e0bf6eSScott Long * success or ENOENT if the queue is empty. 214335863739SMike Smith */ 214435863739SMike Smith static int 2145c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2146c6eafcf2SScott Long struct aac_fib **fib_addr) 214735863739SMike Smith { 214835863739SMike Smith u_int32_t pi, ci; 2149149af931SScott Long u_int32_t fib_index; 21509e2e96d8SScott Long int error; 2151f6c4dd3fSScott Long int notify; 215235863739SMike Smith 215335863739SMike Smith debug_called(3); 215435863739SMike Smith 215535863739SMike Smith /* get the producer/consumer indices */ 215635863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215735863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215835863739SMike Smith 215935863739SMike Smith /* check for queue empty */ 216035863739SMike Smith if (ci == pi) { 216135863739SMike Smith error = ENOENT; 216235863739SMike Smith goto out; 216335863739SMike Smith } 216435863739SMike Smith 21657753acd2SScott Long /* wrap the pi so the following test works */ 21667753acd2SScott Long if (pi >= aac_qinfo[queue].size) 21677753acd2SScott Long pi = 0; 21687753acd2SScott Long 2169f6c4dd3fSScott Long notify = 0; 2170f6c4dd3fSScott Long if (ci == pi + 1) 2171f6c4dd3fSScott Long notify++; 2172f6c4dd3fSScott Long 217335863739SMike Smith /* wrap the queue? */ 217435863739SMike Smith if (ci >= aac_qinfo[queue].size) 217535863739SMike Smith ci = 0; 217635863739SMike Smith 217735863739SMike Smith /* fetch the entry */ 217835863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2179149af931SScott Long 2180149af931SScott Long switch (queue) { 2181149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2182149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2183149af931SScott Long /* 2184149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2185149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2186149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2187149af931SScott Long * Therefore, we have to convert it to an index. 2188149af931SScott Long */ 2189149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2190149af931SScott Long sizeof(struct aac_fib); 2191149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2192149af931SScott Long break; 2193149af931SScott Long 2194149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2195149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2196149af931SScott Long { 2197149af931SScott Long struct aac_command *cm; 2198149af931SScott Long 2199149af931SScott Long /* 2200149af931SScott Long * As above, an index is used instead of an actual address. 2201149af931SScott Long * Gotta shift the index to account for the fast response 2202149af931SScott Long * bit. No other correction is needed since this value was 2203149af931SScott Long * originally provided by the driver via the SenderFibAddress 2204149af931SScott Long * field. 2205149af931SScott Long */ 2206149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 22077cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2208149af931SScott Long *fib_addr = cm->cm_fib; 220935863739SMike Smith 2210f30ac74cSScott Long /* 2211f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2212149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2213f30ac74cSScott Long */ 2214149af931SScott Long if (fib_index & 0x01) { 2215f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2216f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2217f30ac74cSScott Long } 2218149af931SScott Long break; 2219149af931SScott Long } 2220149af931SScott Long default: 2221149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2222149af931SScott Long break; 2223149af931SScott Long } 2224149af931SScott Long 222535863739SMike Smith /* update consumer index */ 222635863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 222735863739SMike Smith 222835863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2229f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 223035863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 223135863739SMike Smith error = 0; 223235863739SMike Smith 223335863739SMike Smith out: 223435863739SMike Smith return(error); 223535863739SMike Smith } 223635863739SMike Smith 2237914da7d0SScott Long /* 223836e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 223936e0bf6eSScott Long */ 224036e0bf6eSScott Long static int 224136e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 224236e0bf6eSScott Long { 224336e0bf6eSScott Long u_int32_t pi, ci; 22449e2e96d8SScott Long int error; 224536e0bf6eSScott Long u_int32_t fib_size; 224636e0bf6eSScott Long u_int32_t fib_addr; 224736e0bf6eSScott Long 224836e0bf6eSScott Long debug_called(1); 224936e0bf6eSScott Long 225036e0bf6eSScott Long /* Tell the adapter where the FIB is */ 225136e0bf6eSScott Long fib_size = fib->Header.Size; 225236e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 225336e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 225436e0bf6eSScott Long 225536e0bf6eSScott Long /* get the producer/consumer indices */ 225636e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 225736e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 225836e0bf6eSScott Long 225936e0bf6eSScott Long /* wrap the queue? */ 226036e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 226136e0bf6eSScott Long pi = 0; 226236e0bf6eSScott Long 226336e0bf6eSScott Long /* check for queue full */ 226436e0bf6eSScott Long if ((pi + 1) == ci) { 226536e0bf6eSScott Long error = EBUSY; 226636e0bf6eSScott Long goto out; 226736e0bf6eSScott Long } 226836e0bf6eSScott Long 226936e0bf6eSScott Long /* populate queue entry */ 227036e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 227136e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 227236e0bf6eSScott Long 227336e0bf6eSScott Long /* update producer index */ 227436e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 227536e0bf6eSScott Long 227636e0bf6eSScott Long /* notify the adapter if we know how */ 227736e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 227836e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227936e0bf6eSScott Long 228036e0bf6eSScott Long error = 0; 228136e0bf6eSScott Long 228236e0bf6eSScott Long out: 228336e0bf6eSScott Long return(error); 228436e0bf6eSScott Long } 228536e0bf6eSScott Long 2286914da7d0SScott Long /* 22870b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 22880b94a66eSMike Smith * and complain about them. 22890b94a66eSMike Smith */ 22900b94a66eSMike Smith static void 22910b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 22920b94a66eSMike Smith { 22930b94a66eSMike Smith struct aac_command *cm; 22940b94a66eSMike Smith time_t deadline; 229515c37be0SScott Long int timedout, code; 22960b94a66eSMike Smith 2297f6c4dd3fSScott Long /* 229870545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2299914da7d0SScott Long * only. 2300914da7d0SScott Long */ 230115c37be0SScott Long timedout = 0; 23022b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 23030b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2304f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2305f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 23060b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2307914da7d0SScott Long device_printf(sc->aac_dev, 2308914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 23092b3b0f17SScott Long cm, (int)(time_uptime-cm->cm_timestamp)); 23100b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 231115c37be0SScott Long timedout++; 23120b94a66eSMike Smith } 23130b94a66eSMike Smith } 23140b94a66eSMike Smith 231515c37be0SScott Long if (timedout) { 231615c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 231715c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 231815c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 231915c37be0SScott Long "longer running! code= 0x%x\n", code); 232015c37be0SScott Long } 232115c37be0SScott Long } 23220b94a66eSMike Smith return; 23230b94a66eSMike Smith } 23240b94a66eSMike Smith 2325914da7d0SScott Long /* 2326914da7d0SScott Long * Interface Function Vectors 2327914da7d0SScott Long */ 232835863739SMike Smith 2329914da7d0SScott Long /* 233035863739SMike Smith * Read the current firmware status word. 233135863739SMike Smith */ 233235863739SMike Smith static int 233335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 233435863739SMike Smith { 233535863739SMike Smith debug_called(3); 233635863739SMike Smith 233735863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 233835863739SMike Smith } 233935863739SMike Smith 234035863739SMike Smith static int 234135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 234235863739SMike Smith { 234335863739SMike Smith debug_called(3); 234435863739SMike Smith 234535863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 234635863739SMike Smith } 234735863739SMike Smith 2348b3457b51SScott Long static int 2349b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2350b3457b51SScott Long { 2351b3457b51SScott Long int val; 2352b3457b51SScott Long 2353b3457b51SScott Long debug_called(3); 2354b3457b51SScott Long 2355b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2356b3457b51SScott Long return (val); 2357b3457b51SScott Long } 2358b3457b51SScott Long 23594afedc31SScott Long static int 23604afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 23614afedc31SScott Long { 23624afedc31SScott Long debug_called(3); 23634afedc31SScott Long 23644afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); 23654afedc31SScott Long } 23664afedc31SScott Long 2367914da7d0SScott Long /* 236835863739SMike Smith * Notify the controller of a change in a given queue 236935863739SMike Smith */ 237035863739SMike Smith 237135863739SMike Smith static void 237235863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 237335863739SMike Smith { 237435863739SMike Smith debug_called(3); 237535863739SMike Smith 237635863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 237735863739SMike Smith } 237835863739SMike Smith 237935863739SMike Smith static void 238035863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 238135863739SMike Smith { 238235863739SMike Smith debug_called(3); 238335863739SMike Smith 238435863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 238535863739SMike Smith } 238635863739SMike Smith 2387b3457b51SScott Long static void 2388b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2389b3457b51SScott Long { 2390b3457b51SScott Long debug_called(3); 2391b3457b51SScott Long 2392b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2393b3457b51SScott Long AAC_FA_HACK(sc); 2394b3457b51SScott Long } 2395b3457b51SScott Long 23964afedc31SScott Long static void 23974afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 23984afedc31SScott Long { 23994afedc31SScott Long debug_called(3); 24004afedc31SScott Long 24014afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); 24024afedc31SScott Long } 24034afedc31SScott Long 2404914da7d0SScott Long /* 240535863739SMike Smith * Get the interrupt reason bits 240635863739SMike Smith */ 240735863739SMike Smith static int 240835863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 240935863739SMike Smith { 241035863739SMike Smith debug_called(3); 241135863739SMike Smith 241235863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 241335863739SMike Smith } 241435863739SMike Smith 241535863739SMike Smith static int 241635863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 241735863739SMike Smith { 241835863739SMike Smith debug_called(3); 241935863739SMike Smith 242035863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 242135863739SMike Smith } 242235863739SMike Smith 2423b3457b51SScott Long static int 2424b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2425b3457b51SScott Long { 2426b3457b51SScott Long int val; 2427b3457b51SScott Long 2428b3457b51SScott Long debug_called(3); 2429b3457b51SScott Long 2430b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2431b3457b51SScott Long return (val); 2432b3457b51SScott Long } 2433b3457b51SScott Long 24344afedc31SScott Long static int 24354afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 24364afedc31SScott Long { 24374afedc31SScott Long debug_called(3); 24384afedc31SScott Long 24394afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_ODBR)); 24404afedc31SScott Long } 24414afedc31SScott Long 2442914da7d0SScott Long /* 244335863739SMike Smith * Clear some interrupt reason bits 244435863739SMike Smith */ 244535863739SMike Smith static void 244635863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 244735863739SMike Smith { 244835863739SMike Smith debug_called(3); 244935863739SMike Smith 245035863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 245135863739SMike Smith } 245235863739SMike Smith 245335863739SMike Smith static void 245435863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 245535863739SMike Smith { 245635863739SMike Smith debug_called(3); 245735863739SMike Smith 245835863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 245935863739SMike Smith } 246035863739SMike Smith 2461b3457b51SScott Long static void 2462b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2463b3457b51SScott Long { 2464b3457b51SScott Long debug_called(3); 2465b3457b51SScott Long 2466b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2467b3457b51SScott Long AAC_FA_HACK(sc); 2468b3457b51SScott Long } 2469b3457b51SScott Long 24704afedc31SScott Long static void 24714afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 24724afedc31SScott Long { 24734afedc31SScott Long debug_called(3); 24744afedc31SScott Long 24754afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, mask); 24764afedc31SScott Long } 24774afedc31SScott Long 2478914da7d0SScott Long /* 247935863739SMike Smith * Populate the mailbox and set the command word 248035863739SMike Smith */ 248135863739SMike Smith static void 248235863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 248335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 248435863739SMike Smith { 248535863739SMike Smith debug_called(4); 248635863739SMike Smith 248735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 248835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 248935863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 249035863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 249135863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 249235863739SMike Smith } 249335863739SMike Smith 249435863739SMike Smith static void 249535863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 249635863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249735863739SMike Smith { 249835863739SMike Smith debug_called(4); 249935863739SMike Smith 250035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 250135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 250235863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 250335863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 250435863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 250535863739SMike Smith } 250635863739SMike Smith 2507b3457b51SScott Long static void 2508b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2509b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2510b3457b51SScott Long { 2511b3457b51SScott Long debug_called(4); 2512b3457b51SScott Long 2513b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2514b3457b51SScott Long AAC_FA_HACK(sc); 2515b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2516b3457b51SScott Long AAC_FA_HACK(sc); 2517b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2518b3457b51SScott Long AAC_FA_HACK(sc); 2519b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2520b3457b51SScott Long AAC_FA_HACK(sc); 2521b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2522b3457b51SScott Long AAC_FA_HACK(sc); 2523b3457b51SScott Long } 2524b3457b51SScott Long 25254afedc31SScott Long static void 25264afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25274afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 25284afedc31SScott Long { 25294afedc31SScott Long debug_called(4); 25304afedc31SScott Long 25314afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); 25324afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 25334afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 25344afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 25354afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 25364afedc31SScott Long } 25374afedc31SScott Long 2538914da7d0SScott Long /* 253935863739SMike Smith * Fetch the immediate command status word 254035863739SMike Smith */ 254135863739SMike Smith static int 2542a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 254335863739SMike Smith { 254435863739SMike Smith debug_called(4); 254535863739SMike Smith 2546a6d35632SScott Long return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 254735863739SMike Smith } 254835863739SMike Smith 254935863739SMike Smith static int 2550a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 255135863739SMike Smith { 255235863739SMike Smith debug_called(4); 255335863739SMike Smith 2554a6d35632SScott Long return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 255535863739SMike Smith } 255635863739SMike Smith 2557b3457b51SScott Long static int 2558a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2559b3457b51SScott Long { 2560b3457b51SScott Long int val; 2561b3457b51SScott Long 2562b3457b51SScott Long debug_called(4); 2563b3457b51SScott Long 2564a6d35632SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2565b3457b51SScott Long return (val); 2566b3457b51SScott Long } 2567b3457b51SScott Long 25684afedc31SScott Long static int 25694afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 25704afedc31SScott Long { 25714afedc31SScott Long debug_called(4); 25724afedc31SScott Long 25734afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 25744afedc31SScott Long } 25754afedc31SScott Long 2576914da7d0SScott Long /* 257735863739SMike Smith * Set/clear interrupt masks 257835863739SMike Smith */ 257935863739SMike Smith static void 258035863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 258135863739SMike Smith { 258235863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 258335863739SMike Smith 258435863739SMike Smith if (enable) { 258535863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 258635863739SMike Smith } else { 258735863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 258835863739SMike Smith } 258935863739SMike Smith } 259035863739SMike Smith 259135863739SMike Smith static void 259235863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 259335863739SMike Smith { 259435863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 259535863739SMike Smith 259635863739SMike Smith if (enable) { 25977cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 25987cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 25997cb209f5SScott Long else 260035863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 260135863739SMike Smith } else { 260235863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 260335863739SMike Smith } 260435863739SMike Smith } 260535863739SMike Smith 2606b3457b51SScott Long static void 2607b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2608b3457b51SScott Long { 2609b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2610b3457b51SScott Long 2611b3457b51SScott Long if (enable) { 2612b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2613b3457b51SScott Long AAC_FA_HACK(sc); 2614b3457b51SScott Long } else { 2615b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2616b3457b51SScott Long AAC_FA_HACK(sc); 2617b3457b51SScott Long } 2618b3457b51SScott Long } 2619b3457b51SScott Long 26204afedc31SScott Long static void 26214afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 26224afedc31SScott Long { 26234afedc31SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 26244afedc31SScott Long 26254afedc31SScott Long if (enable) { 26267cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 26277cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 26287cb209f5SScott Long else 26294afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 26304afedc31SScott Long } else { 26314afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); 26324afedc31SScott Long } 26334afedc31SScott Long } 26344afedc31SScott Long 2635914da7d0SScott Long /* 26367cb209f5SScott Long * New comm. interface: Send command functions 26377cb209f5SScott Long */ 26387cb209f5SScott Long static int 26397cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 26407cb209f5SScott Long { 26417cb209f5SScott Long u_int32_t index, device; 26427cb209f5SScott Long 26437cb209f5SScott Long debug(2, "send command (new comm.)"); 26447cb209f5SScott Long 26457cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RX_IQUE); 26467cb209f5SScott Long if (index == 0xffffffffL) 26477cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RX_IQUE); 26487cb209f5SScott Long if (index == 0xffffffffL) 26497cb209f5SScott Long return index; 26507cb209f5SScott Long aac_enqueue_busy(cm); 26517cb209f5SScott Long device = index; 26527cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26537cb209f5SScott Long device += 4; 26547cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26557cb209f5SScott Long device += 4; 26567cb209f5SScott Long AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 26577cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_IQUE, index); 26587cb209f5SScott Long return 0; 26597cb209f5SScott Long } 26607cb209f5SScott Long 26617cb209f5SScott Long static int 26627cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 26637cb209f5SScott Long { 26647cb209f5SScott Long u_int32_t index, device; 26657cb209f5SScott Long 26667cb209f5SScott Long debug(2, "send command (new comm.)"); 26677cb209f5SScott Long 26687cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RKT_IQUE); 26697cb209f5SScott Long if (index == 0xffffffffL) 26707cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RKT_IQUE); 26717cb209f5SScott Long if (index == 0xffffffffL) 26727cb209f5SScott Long return index; 26737cb209f5SScott Long aac_enqueue_busy(cm); 26747cb209f5SScott Long device = index; 26757cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26767cb209f5SScott Long device += 4; 26777cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26787cb209f5SScott Long device += 4; 26797cb209f5SScott Long AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 26807cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_IQUE, index); 26817cb209f5SScott Long return 0; 26827cb209f5SScott Long } 26837cb209f5SScott Long 26847cb209f5SScott Long /* 26857cb209f5SScott Long * New comm. interface: get, set outbound queue index 26867cb209f5SScott Long */ 26877cb209f5SScott Long static int 26887cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 26897cb209f5SScott Long { 26907cb209f5SScott Long debug_called(3); 26917cb209f5SScott Long 26927cb209f5SScott Long return(AAC_GETREG4(sc, AAC_RX_OQUE)); 26937cb209f5SScott Long } 26947cb209f5SScott Long 26957cb209f5SScott Long static int 26967cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 26977cb209f5SScott Long { 26987cb209f5SScott Long debug_called(3); 26997cb209f5SScott Long 27007cb209f5SScott Long return(AAC_GETREG4(sc, AAC_RKT_OQUE)); 27017cb209f5SScott Long } 27027cb209f5SScott Long 27037cb209f5SScott Long static void 27047cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 27057cb209f5SScott Long { 27067cb209f5SScott Long debug_called(3); 27077cb209f5SScott Long 27087cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_OQUE, index); 27097cb209f5SScott Long } 27107cb209f5SScott Long 27117cb209f5SScott Long static void 27127cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 27137cb209f5SScott Long { 27147cb209f5SScott Long debug_called(3); 27157cb209f5SScott Long 27167cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_OQUE, index); 27177cb209f5SScott Long } 27187cb209f5SScott Long 27197cb209f5SScott Long /* 2720914da7d0SScott Long * Debugging and Diagnostics 2721914da7d0SScott Long */ 272235863739SMike Smith 2723914da7d0SScott Long /* 272435863739SMike Smith * Print some information about the controller. 272535863739SMike Smith */ 272635863739SMike Smith static void 272735863739SMike Smith aac_describe_controller(struct aac_softc *sc) 272835863739SMike Smith { 2729cbfd045bSScott Long struct aac_fib *fib; 273035863739SMike Smith struct aac_adapter_info *info; 27317ea2d558SEd Maste char *adapter_type = "Adaptec RAID controller"; 273235863739SMike Smith 273335863739SMike Smith debug_called(2); 273435863739SMike Smith 273581b3da08SScott Long mtx_lock(&sc->aac_io_lock); 273603b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2737cbfd045bSScott Long 27387ea2d558SEd Maste if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 27397ea2d558SEd Maste fib->data[0] = 0; 27407ea2d558SEd Maste if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 27417ea2d558SEd Maste device_printf(sc->aac_dev, 27427ea2d558SEd Maste "RequestSupplementAdapterInfo failed\n"); 27437ea2d558SEd Maste else 27447ea2d558SEd Maste adapter_type = ((struct aac_supplement_adapter_info *) 27457ea2d558SEd Maste &fib->data[0])->AdapterTypeText; 27467ea2d558SEd Maste } 27477ea2d558SEd Maste device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 27487ea2d558SEd Maste adapter_type, 27497ea2d558SEd Maste AAC_DRIVER_VERSION >> 24, 27507ea2d558SEd Maste (AAC_DRIVER_VERSION >> 16) & 0xFF, 27517ea2d558SEd Maste AAC_DRIVER_VERSION & 0xFF, 27527ea2d558SEd Maste AAC_DRIVER_BUILD); 27537ea2d558SEd Maste 2754cbfd045bSScott Long fib->data[0] = 0; 2755cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 275635863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2757fe3cb0e1SScott Long aac_release_sync_fib(sc); 275881b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 275935863739SMike Smith return; 276035863739SMike Smith } 276135863739SMike Smith 2762bd971c49SScott Long /* save the kernel revision structure for later use */ 2763bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2764bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2765bd971c49SScott Long 27667cb209f5SScott Long 2767bd971c49SScott Long if (bootverbose) { 2768b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2769b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2770c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2771b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2772b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2773b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2774914da7d0SScott Long aac_describe_code(aac_battery_platform, 2775914da7d0SScott Long info->batteryPlatform)); 277635863739SMike Smith 2777bd971c49SScott Long device_printf(sc->aac_dev, 2778bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 277935863739SMike Smith info->KernelRevision.external.comp.major, 278035863739SMike Smith info->KernelRevision.external.comp.minor, 278135863739SMike Smith info->KernelRevision.external.comp.dash, 278236e0bf6eSScott Long info->KernelRevision.buildNumber, 278336e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2784fe3cb0e1SScott Long 2785a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2786a6d35632SScott Long sc->supported_options, 2787a6d35632SScott Long "\20" 2788a6d35632SScott Long "\1SNAPSHOT" 2789a6d35632SScott Long "\2CLUSTERS" 2790a6d35632SScott Long "\3WCACHE" 2791a6d35632SScott Long "\4DATA64" 2792a6d35632SScott Long "\5HOSTTIME" 2793a6d35632SScott Long "\6RAID50" 2794a6d35632SScott Long "\7WINDOW4GB" 2795a6d35632SScott Long "\10SCSIUPGD" 2796a6d35632SScott Long "\11SOFTERR" 2797a6d35632SScott Long "\12NORECOND" 2798a6d35632SScott Long "\13SGMAP64" 2799a6d35632SScott Long "\14ALARM" 28007cb209f5SScott Long "\15NONDASD" 28017cb209f5SScott Long "\16SCSIMGT" 28027cb209f5SScott Long "\17RAIDSCSI" 28037cb209f5SScott Long "\21ADPTINFO" 28047cb209f5SScott Long "\22NEWCOMM" 28057cb209f5SScott Long "\23ARRAY64BIT" 28067cb209f5SScott Long "\24HEATSENSOR"); 2807a6d35632SScott Long } 2808bd971c49SScott Long aac_release_sync_fib(sc); 280981b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 281035863739SMike Smith } 281135863739SMike Smith 2812914da7d0SScott Long /* 281335863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 281435863739SMike Smith * same. 281535863739SMike Smith */ 281635863739SMike Smith static char * 281735863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 281835863739SMike Smith { 281935863739SMike Smith int i; 282035863739SMike Smith 282135863739SMike Smith for (i = 0; table[i].string != NULL; i++) 282235863739SMike Smith if (table[i].code == code) 282335863739SMike Smith return(table[i].string); 282435863739SMike Smith return(table[i + 1].string); 282535863739SMike Smith } 282635863739SMike Smith 2827914da7d0SScott Long /* 2828914da7d0SScott Long * Management Interface 2829914da7d0SScott Long */ 283035863739SMike Smith 283135863739SMike Smith static int 283289c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 283335863739SMike Smith { 2834914da7d0SScott Long struct aac_softc *sc; 283535863739SMike Smith 283635863739SMike Smith debug_called(2); 283735863739SMike Smith 2838914da7d0SScott Long sc = dev->si_drv1; 2839a723a548SEd Maste sc->aac_open_cnt++; 284035863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 284135863739SMike Smith 284235863739SMike Smith return 0; 284335863739SMike Smith } 284435863739SMike Smith 284535863739SMike Smith static int 284689c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 284735863739SMike Smith { 2848914da7d0SScott Long struct aac_softc *sc; 284935863739SMike Smith 285035863739SMike Smith debug_called(2); 285135863739SMike Smith 2852914da7d0SScott Long sc = dev->si_drv1; 2853a723a548SEd Maste sc->aac_open_cnt--; 285435863739SMike Smith /* Mark this unit as no longer open */ 2855a723a548SEd Maste if (sc->aac_open_cnt == 0) 285635863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 285735863739SMike Smith 285835863739SMike Smith return 0; 285935863739SMike Smith } 286035863739SMike Smith 286135863739SMike Smith static int 286289c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 286335863739SMike Smith { 2864914da7d0SScott Long union aac_statrequest *as; 2865914da7d0SScott Long struct aac_softc *sc; 28660b94a66eSMike Smith int error = 0; 286735863739SMike Smith 286835863739SMike Smith debug_called(2); 286935863739SMike Smith 2870914da7d0SScott Long as = (union aac_statrequest *)arg; 2871914da7d0SScott Long sc = dev->si_drv1; 2872914da7d0SScott Long 287335863739SMike Smith switch (cmd) { 28740b94a66eSMike Smith case AACIO_STATS: 28750b94a66eSMike Smith switch (as->as_item) { 28760b94a66eSMike Smith case AACQ_FREE: 28770b94a66eSMike Smith case AACQ_BIO: 28780b94a66eSMike Smith case AACQ_READY: 28790b94a66eSMike Smith case AACQ_BUSY: 2880c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2881c6eafcf2SScott Long sizeof(struct aac_qstat)); 28820b94a66eSMike Smith break; 28830b94a66eSMike Smith default: 28840b94a66eSMike Smith error = ENOENT; 28850b94a66eSMike Smith break; 28860b94a66eSMike Smith } 28870b94a66eSMike Smith break; 28880b94a66eSMike Smith 288935863739SMike Smith case FSACTL_SENDFIB: 2890fb0c27d7SScott Long arg = *(caddr_t*)arg; 2891fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 28920b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 289335863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 289435863739SMike Smith break; 289535863739SMike Smith case FSACTL_AIF_THREAD: 2896fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 28970b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 289835863739SMike Smith error = EINVAL; 289935863739SMike Smith break; 290035863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2901fb0c27d7SScott Long arg = *(caddr_t*)arg; 2902fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 29030b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2904a723a548SEd Maste error = aac_open_aif(sc, arg); 290535863739SMike Smith break; 290635863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2907fb0c27d7SScott Long arg = *(caddr_t*)arg; 2908fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 29090b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2910fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 291135863739SMike Smith break; 291235863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2913a723a548SEd Maste arg = *(caddr_t*)arg; 2914fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 29150b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2916a723a548SEd Maste error = aac_close_aif(sc, arg); 291735863739SMike Smith break; 291835863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2919fb0c27d7SScott Long arg = *(caddr_t*)arg; 2920fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 29210b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2922fb0c27d7SScott Long error = aac_rev_check(sc, arg); 292335863739SMike Smith break; 292436e0bf6eSScott Long case FSACTL_QUERY_DISK: 292536e0bf6eSScott Long arg = *(caddr_t*)arg; 292636e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 292736e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 292836e0bf6eSScott Long error = aac_query_disk(sc, arg); 292936e0bf6eSScott Long break; 293036e0bf6eSScott Long case FSACTL_DELETE_DISK: 293136e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2932914da7d0SScott Long /* 2933914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2934914da7d0SScott Long * container, rather we rely on an AIF coming from the 2935914da7d0SScott Long * controller 2936914da7d0SScott Long */ 293736e0bf6eSScott Long error = 0; 293836e0bf6eSScott Long break; 29397cb209f5SScott Long case FSACTL_GET_PCI_INFO: 29407cb209f5SScott Long arg = *(caddr_t*)arg; 29417cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 29427cb209f5SScott Long debug(1, "FSACTL_GET_PCI_INFO"); 29437cb209f5SScott Long error = aac_get_pci_info(sc, arg); 29447cb209f5SScott Long break; 294535863739SMike Smith default: 2946b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 294735863739SMike Smith error = EINVAL; 294835863739SMike Smith break; 294935863739SMike Smith } 295035863739SMike Smith return(error); 295135863739SMike Smith } 295235863739SMike Smith 2953b3457b51SScott Long static int 295489c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 2955b3457b51SScott Long { 2956b3457b51SScott Long struct aac_softc *sc; 2957b3457b51SScott Long int revents; 2958b3457b51SScott Long 2959b3457b51SScott Long sc = dev->si_drv1; 2960b3457b51SScott Long revents = 0; 2961b3457b51SScott Long 2962bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2963b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2964a723a548SEd Maste if (sc->aifq_idx != 0 || sc->aifq_filled) 2965b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2966b3457b51SScott Long } 2967bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2968b3457b51SScott Long 2969b3457b51SScott Long if (revents == 0) { 2970b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2971b3457b51SScott Long selrecord(td, &sc->rcv_select); 2972b3457b51SScott Long } 2973b3457b51SScott Long 2974b3457b51SScott Long return (revents); 2975b3457b51SScott Long } 2976b3457b51SScott Long 29777cb209f5SScott Long static void 29787cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 29797cb209f5SScott Long { 29807cb209f5SScott Long 29817cb209f5SScott Long switch (event->ev_type) { 29827cb209f5SScott Long case AAC_EVENT_CMFREE: 29830c40d5beSEd Maste mtx_assert(&sc->aac_io_lock, MA_OWNED); 29841a681311SLuoqi Chen if (aac_alloc_command(sc, (struct aac_command **)arg)) { 29857cb209f5SScott Long aac_add_event(sc, event); 29867cb209f5SScott Long return; 29877cb209f5SScott Long } 29887cb209f5SScott Long free(event, M_AACBUF); 29898eeb2ca6SScott Long wakeup(arg); 29907cb209f5SScott Long break; 29917cb209f5SScott Long default: 29927cb209f5SScott Long break; 29937cb209f5SScott Long } 29947cb209f5SScott Long } 29957cb209f5SScott Long 2996914da7d0SScott Long /* 299735863739SMike Smith * Send a FIB supplied from userspace 299835863739SMike Smith */ 299935863739SMike Smith static int 300035863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 300135863739SMike Smith { 300235863739SMike Smith struct aac_command *cm; 300335863739SMike Smith int size, error; 300435863739SMike Smith 300535863739SMike Smith debug_called(2); 300635863739SMike Smith 300735863739SMike Smith cm = NULL; 300835863739SMike Smith 300935863739SMike Smith /* 301035863739SMike Smith * Get a command 301135863739SMike Smith */ 3012bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 301335863739SMike Smith if (aac_alloc_command(sc, &cm)) { 30147cb209f5SScott Long struct aac_event *event; 30157cb209f5SScott Long 30167cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 30177cb209f5SScott Long M_NOWAIT | M_ZERO); 30187cb209f5SScott Long if (event == NULL) { 301935863739SMike Smith error = EBUSY; 3020f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 302135863739SMike Smith goto out; 302235863739SMike Smith } 30237cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 30247cb209f5SScott Long event->ev_callback = aac_ioctl_event; 30257cb209f5SScott Long event->ev_arg = &cm; 30267cb209f5SScott Long aac_add_event(sc, event); 30278eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 30287cb209f5SScott Long } 302993cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 303035863739SMike Smith 303135863739SMike Smith /* 303235863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 303335863739SMike Smith */ 3034914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 3035914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 303635863739SMike Smith goto out; 303735863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 303835863739SMike Smith if (size > sizeof(struct aac_fib)) { 3039b88ffdc8SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 3040914da7d0SScott Long size, sizeof(struct aac_fib)); 304135863739SMike Smith size = sizeof(struct aac_fib); 304235863739SMike Smith } 304335863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 304435863739SMike Smith goto out; 304535863739SMike Smith cm->cm_fib->Header.Size = size; 30462b3b0f17SScott Long cm->cm_timestamp = time_uptime; 304735863739SMike Smith 304835863739SMike Smith /* 304935863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 305035863739SMike Smith */ 305193cfca22SScott Long mtx_lock(&sc->aac_io_lock); 3052f16627aaSEd Maste error = aac_wait_command(cm); 3053f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 3054f16627aaSEd Maste if (error != 0) { 305570545d1aSScott Long device_printf(sc->aac_dev, 305670545d1aSScott Long "aac_wait_command return %d\n", error); 305735863739SMike Smith goto out; 3058b3457b51SScott Long } 305935863739SMike Smith 306035863739SMike Smith /* 306135863739SMike Smith * Copy the FIB and data back out to the caller. 306235863739SMike Smith */ 306335863739SMike Smith size = cm->cm_fib->Header.Size; 306435863739SMike Smith if (size > sizeof(struct aac_fib)) { 3065b88ffdc8SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 3066914da7d0SScott Long size, sizeof(struct aac_fib)); 306735863739SMike Smith size = sizeof(struct aac_fib); 306835863739SMike Smith } 306935863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 307035863739SMike Smith 307135863739SMike Smith out: 3072f6c4dd3fSScott Long if (cm != NULL) { 3073f16627aaSEd Maste mtx_lock(&sc->aac_io_lock); 307435863739SMike Smith aac_release_command(cm); 3075bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 3076f16627aaSEd Maste } 307735863739SMike Smith return(error); 307835863739SMike Smith } 307935863739SMike Smith 3080914da7d0SScott Long /* 308135863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 308236e0bf6eSScott Long * If the queue fills up, then drop the older entries. 308335863739SMike Smith */ 308435863739SMike Smith static void 308536e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 308635863739SMike Smith { 308736e0bf6eSScott Long struct aac_aif_command *aif; 308836e0bf6eSScott Long struct aac_container *co, *co_next; 3089a723a548SEd Maste struct aac_fib_context *ctx; 3090cbfd045bSScott Long struct aac_mntinfo *mi; 3091cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 309236e0bf6eSScott Long u_int16_t rsize; 3093a723a548SEd Maste int next, current, found; 3094795d7dc0SScott Long int count = 0, added = 0, i = 0; 309535863739SMike Smith 309635863739SMike Smith debug_called(2); 309735863739SMike Smith 309836e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 309936e0bf6eSScott Long aac_print_aif(sc, aif); 310036e0bf6eSScott Long 310136e0bf6eSScott Long /* Is it an event that we should care about? */ 310236e0bf6eSScott Long switch (aif->command) { 310336e0bf6eSScott Long case AifCmdEventNotify: 310436e0bf6eSScott Long switch (aif->data.EN.type) { 310536e0bf6eSScott Long case AifEnAddContainer: 310636e0bf6eSScott Long case AifEnDeleteContainer: 310736e0bf6eSScott Long /* 3108914da7d0SScott Long * A container was added or deleted, but the message 3109914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3110914da7d0SScott Long * containers and sort things out. 311136e0bf6eSScott Long */ 311203b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3113cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 311436e0bf6eSScott Long do { 311536e0bf6eSScott Long /* 3116914da7d0SScott Long * Ask the controller for its containers one at 3117914da7d0SScott Long * a time. 3118914da7d0SScott Long * XXX What if the controller's list changes 3119914da7d0SScott Long * midway through this enumaration? 312036e0bf6eSScott Long * XXX This should be done async. 312136e0bf6eSScott Long */ 312239ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 312339ee03c3SScott Long mi->Command = VM_NameServe; 312439ee03c3SScott Long mi->MntType = FT_FILESYS; 3125cbfd045bSScott Long mi->MntCount = i; 312636e0bf6eSScott Long rsize = sizeof(mir); 3127cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 3128cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 3129795d7dc0SScott Long printf("Error probing container %d\n", 3130914da7d0SScott Long i); 313136e0bf6eSScott Long continue; 313236e0bf6eSScott Long } 3133cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 3134795d7dc0SScott Long /* XXX Need to check if count changed */ 3135795d7dc0SScott Long count = mir->MntRespCount; 313636e0bf6eSScott Long /* 3137914da7d0SScott Long * Check the container against our list. 3138914da7d0SScott Long * co->co_found was already set to 0 in a 3139914da7d0SScott Long * previous run. 314036e0bf6eSScott Long */ 3141cbfd045bSScott Long if ((mir->Status == ST_OK) && 3142cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 314336e0bf6eSScott Long found = 0; 3144914da7d0SScott Long TAILQ_FOREACH(co, 3145914da7d0SScott Long &sc->aac_container_tqh, 3146914da7d0SScott Long co_link) { 314736e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3148cbfd045bSScott Long mir->MntTable[0].ObjectId) { 314936e0bf6eSScott Long co->co_found = 1; 315036e0bf6eSScott Long found = 1; 315136e0bf6eSScott Long break; 315236e0bf6eSScott Long } 315336e0bf6eSScott Long } 3154914da7d0SScott Long /* 3155914da7d0SScott Long * If the container matched, continue 3156914da7d0SScott Long * in the list. 3157914da7d0SScott Long */ 315836e0bf6eSScott Long if (found) { 315936e0bf6eSScott Long i++; 316036e0bf6eSScott Long continue; 316136e0bf6eSScott Long } 316236e0bf6eSScott Long 316336e0bf6eSScott Long /* 3164914da7d0SScott Long * This is a new container. Do all the 316570545d1aSScott Long * appropriate things to set it up. 316670545d1aSScott Long */ 3167cbfd045bSScott Long aac_add_container(sc, mir, 1); 316836e0bf6eSScott Long added = 1; 316936e0bf6eSScott Long } 317036e0bf6eSScott Long i++; 3171795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3172cbfd045bSScott Long aac_release_sync_fib(sc); 317336e0bf6eSScott Long 317436e0bf6eSScott Long /* 3175914da7d0SScott Long * Go through our list of containers and see which ones 3176914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3177914da7d0SScott Long * list them they must have been deleted. Do the 3178914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3179914da7d0SScott Long * the co->co_found field. 318036e0bf6eSScott Long */ 318136e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 318236e0bf6eSScott Long while (co != NULL) { 318336e0bf6eSScott Long if (co->co_found == 0) { 31847cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 31857cb209f5SScott Long mtx_lock(&Giant); 3186914da7d0SScott Long device_delete_child(sc->aac_dev, 3187914da7d0SScott Long co->co_disk); 31887cb209f5SScott Long mtx_unlock(&Giant); 31897cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 319036e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3191bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3192914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3193914da7d0SScott Long co_link); 3194bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3195ba1d57e7SScott Long free(co, M_AACBUF); 319636e0bf6eSScott Long co = co_next; 319736e0bf6eSScott Long } else { 319836e0bf6eSScott Long co->co_found = 0; 319936e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 320036e0bf6eSScott Long } 320136e0bf6eSScott Long } 320236e0bf6eSScott Long 320336e0bf6eSScott Long /* Attach the newly created containers */ 32047cb209f5SScott Long if (added) { 32057cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 32067cb209f5SScott Long mtx_lock(&Giant); 320736e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 32087cb209f5SScott Long mtx_unlock(&Giant); 32097cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 32107cb209f5SScott Long } 321136e0bf6eSScott Long 321236e0bf6eSScott Long break; 321336e0bf6eSScott Long 321436e0bf6eSScott Long default: 321536e0bf6eSScott Long break; 321636e0bf6eSScott Long } 321736e0bf6eSScott Long 321836e0bf6eSScott Long default: 321936e0bf6eSScott Long break; 322036e0bf6eSScott Long } 322136e0bf6eSScott Long 322236e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3223bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3224a723a548SEd Maste current = sc->aifq_idx; 3225a723a548SEd Maste next = (current + 1) % AAC_AIFQ_LENGTH; 3226a723a548SEd Maste if (next == 0) 3227a723a548SEd Maste sc->aifq_filled = 1; 3228a723a548SEd Maste bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3229a723a548SEd Maste /* modify AIF contexts */ 3230a723a548SEd Maste if (sc->aifq_filled) { 3231a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3232a723a548SEd Maste if (next == ctx->ctx_idx) 3233a723a548SEd Maste ctx->ctx_wrap = 1; 3234a723a548SEd Maste else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3235a723a548SEd Maste ctx->ctx_idx = next; 3236a723a548SEd Maste } 3237a723a548SEd Maste } 3238a723a548SEd Maste sc->aifq_idx = next; 3239b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 324035863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 324135863739SMike Smith wakeup(sc->aac_aifq); 3242b3457b51SScott Long /* Wakeup any poll()ers */ 3243512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 3244bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 324536e0bf6eSScott Long 324636e0bf6eSScott Long return; 324735863739SMike Smith } 324835863739SMike Smith 3249914da7d0SScott Long /* 32500b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 325136e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 325236e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 325336e0bf6eSScott Long * returning what the card reported. 325435863739SMike Smith */ 325535863739SMike Smith static int 3256fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 325735863739SMike Smith { 325835863739SMike Smith struct aac_rev_check rev_check; 325935863739SMike Smith struct aac_rev_check_resp rev_check_resp; 326035863739SMike Smith int error = 0; 326135863739SMike Smith 326235863739SMike Smith debug_called(2); 326335863739SMike Smith 326435863739SMike Smith /* 326535863739SMike Smith * Copyin the revision struct from userspace 326635863739SMike Smith */ 3267c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3268c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 326935863739SMike Smith return error; 327035863739SMike Smith } 327135863739SMike Smith 3272914da7d0SScott Long debug(2, "Userland revision= %d\n", 3273914da7d0SScott Long rev_check.callingRevision.buildNumber); 327435863739SMike Smith 327535863739SMike Smith /* 327635863739SMike Smith * Doctor up the response struct. 327735863739SMike Smith */ 327835863739SMike Smith rev_check_resp.possiblyCompatible = 1; 3279914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 3280914da7d0SScott Long sc->aac_revision.external.ul; 3281914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 3282914da7d0SScott Long sc->aac_revision.buildNumber; 328335863739SMike Smith 3284c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3285c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 328635863739SMike Smith } 328735863739SMike Smith 3288914da7d0SScott Long /* 3289a723a548SEd Maste * Pass the fib context to the caller 3290a723a548SEd Maste */ 3291a723a548SEd Maste static int 3292a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg) 3293a723a548SEd Maste { 3294a723a548SEd Maste struct aac_fib_context *fibctx, *ctx; 3295a723a548SEd Maste int error = 0; 3296a723a548SEd Maste 3297a723a548SEd Maste debug_called(2); 3298a723a548SEd Maste 3299a723a548SEd Maste fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3300a723a548SEd Maste if (fibctx == NULL) 3301a723a548SEd Maste return (ENOMEM); 3302a723a548SEd Maste 3303a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3304a723a548SEd Maste /* all elements are already 0, add to queue */ 3305a723a548SEd Maste if (sc->fibctx == NULL) 3306a723a548SEd Maste sc->fibctx = fibctx; 3307a723a548SEd Maste else { 3308a723a548SEd Maste for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3309a723a548SEd Maste ; 3310a723a548SEd Maste ctx->next = fibctx; 3311a723a548SEd Maste fibctx->prev = ctx; 3312a723a548SEd Maste } 3313a723a548SEd Maste 3314a723a548SEd Maste /* evaluate unique value */ 3315a723a548SEd Maste fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3316a723a548SEd Maste ctx = sc->fibctx; 3317a723a548SEd Maste while (ctx != fibctx) { 3318a723a548SEd Maste if (ctx->unique == fibctx->unique) { 3319a723a548SEd Maste fibctx->unique++; 3320a723a548SEd Maste ctx = sc->fibctx; 3321a723a548SEd Maste } else { 3322a723a548SEd Maste ctx = ctx->next; 3323a723a548SEd Maste } 3324a723a548SEd Maste } 3325a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3326a723a548SEd Maste 3327a723a548SEd Maste error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3328a723a548SEd Maste if (error) 3329a723a548SEd Maste aac_close_aif(sc, (caddr_t)ctx); 3330a723a548SEd Maste return error; 3331a723a548SEd Maste } 3332a723a548SEd Maste 3333a723a548SEd Maste /* 3334a723a548SEd Maste * Close the caller's fib context 3335a723a548SEd Maste */ 3336a723a548SEd Maste static int 3337a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg) 3338a723a548SEd Maste { 3339a723a548SEd Maste struct aac_fib_context *ctx; 3340a723a548SEd Maste 3341a723a548SEd Maste debug_called(2); 3342a723a548SEd Maste 3343a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3344a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3345a723a548SEd Maste if (ctx->unique == *(uint32_t *)&arg) { 3346a723a548SEd Maste if (ctx == sc->fibctx) 3347a723a548SEd Maste sc->fibctx = NULL; 3348a723a548SEd Maste else { 3349a723a548SEd Maste ctx->prev->next = ctx->next; 3350a723a548SEd Maste if (ctx->next) 3351a723a548SEd Maste ctx->next->prev = ctx->prev; 3352a723a548SEd Maste } 3353a723a548SEd Maste break; 3354a723a548SEd Maste } 3355a723a548SEd Maste } 3356a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3357a723a548SEd Maste if (ctx) 3358a723a548SEd Maste free(ctx, M_AACBUF); 3359a723a548SEd Maste 3360a723a548SEd Maste return 0; 3361a723a548SEd Maste } 3362a723a548SEd Maste 3363a723a548SEd Maste /* 336435863739SMike Smith * Pass the caller the next AIF in their queue 336535863739SMike Smith */ 336635863739SMike Smith static int 3367fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 336835863739SMike Smith { 336935863739SMike Smith struct get_adapter_fib_ioctl agf; 3370a723a548SEd Maste struct aac_fib_context *ctx; 33719e2e96d8SScott Long int error; 337235863739SMike Smith 337335863739SMike Smith debug_called(2); 337435863739SMike Smith 337535863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3376a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3377a723a548SEd Maste if (agf.AdapterFibContext == ctx->unique) 3378a723a548SEd Maste break; 3379a723a548SEd Maste } 3380a723a548SEd Maste if (!ctx) 3381a723a548SEd Maste return (EFAULT); 338235863739SMike Smith 3383a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 3384a723a548SEd Maste if (error == EAGAIN && agf.Wait) { 3385a723a548SEd Maste debug(2, "aac_getnext_aif(): waiting for AIF"); 338635863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 338735863739SMike Smith while (error == EAGAIN) { 3388914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3389914da7d0SScott Long PCATCH, "aacaif", 0); 339035863739SMike Smith if (error == 0) 3391a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 339235863739SMike Smith } 339335863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 339435863739SMike Smith } 339535863739SMike Smith } 339635863739SMike Smith return(error); 339735863739SMike Smith } 339835863739SMike Smith 3399914da7d0SScott Long /* 34000b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 34010b94a66eSMike Smith */ 34020b94a66eSMike Smith static int 3403a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 34040b94a66eSMike Smith { 3405a723a548SEd Maste int current, error; 34060b94a66eSMike Smith 34070b94a66eSMike Smith debug_called(2); 34080b94a66eSMike Smith 3409bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3410a723a548SEd Maste current = ctx->ctx_idx; 3411a723a548SEd Maste if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3412a723a548SEd Maste /* empty */ 3413bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 34143df780cfSScott Long return (EAGAIN); 34153df780cfSScott Long } 3416a723a548SEd Maste error = 3417a723a548SEd Maste copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 341836e0bf6eSScott Long if (error) 341970545d1aSScott Long device_printf(sc->aac_dev, 342070545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 3421a723a548SEd Maste else { 3422a723a548SEd Maste ctx->ctx_wrap = 0; 3423a723a548SEd Maste ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3424a723a548SEd Maste } 3425bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 34260b94a66eSMike Smith return(error); 34270b94a66eSMike Smith } 342836e0bf6eSScott Long 34297cb209f5SScott Long static int 34307cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 34317cb209f5SScott Long { 34327cb209f5SScott Long struct aac_pci_info { 34337cb209f5SScott Long u_int32_t bus; 34347cb209f5SScott Long u_int32_t slot; 34357cb209f5SScott Long } pciinf; 34367cb209f5SScott Long int error; 34377cb209f5SScott Long 34387cb209f5SScott Long debug_called(2); 34397cb209f5SScott Long 34407cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 34417cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 34427cb209f5SScott Long 34437cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 34447cb209f5SScott Long sizeof(struct aac_pci_info)); 34457cb209f5SScott Long 34467cb209f5SScott Long return (error); 34477cb209f5SScott Long } 34487cb209f5SScott Long 3449914da7d0SScott Long /* 345036e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 345136e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 345236e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 345336e0bf6eSScott Long */ 345436e0bf6eSScott Long static int 345536e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 345636e0bf6eSScott Long { 345736e0bf6eSScott Long struct aac_query_disk query_disk; 345836e0bf6eSScott Long struct aac_container *co; 3459914da7d0SScott Long struct aac_disk *disk; 346036e0bf6eSScott Long int error, id; 346136e0bf6eSScott Long 346236e0bf6eSScott Long debug_called(2); 346336e0bf6eSScott Long 3464914da7d0SScott Long disk = NULL; 3465914da7d0SScott Long 3466914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3467914da7d0SScott Long sizeof(struct aac_query_disk)); 346836e0bf6eSScott Long if (error) 346936e0bf6eSScott Long return (error); 347036e0bf6eSScott Long 347136e0bf6eSScott Long id = query_disk.ContainerNumber; 347236e0bf6eSScott Long if (id == -1) 347336e0bf6eSScott Long return (EINVAL); 347436e0bf6eSScott Long 3475bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 347636e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 347736e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 347836e0bf6eSScott Long break; 347936e0bf6eSScott Long } 348036e0bf6eSScott Long 348136e0bf6eSScott Long if (co == NULL) { 348236e0bf6eSScott Long query_disk.Valid = 0; 348336e0bf6eSScott Long query_disk.Locked = 0; 348436e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 348536e0bf6eSScott Long } else { 348636e0bf6eSScott Long disk = device_get_softc(co->co_disk); 348736e0bf6eSScott Long query_disk.Valid = 1; 3488914da7d0SScott Long query_disk.Locked = 3489914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 349036e0bf6eSScott Long query_disk.Deleted = 0; 3491b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 349236e0bf6eSScott Long query_disk.Target = disk->unit; 349336e0bf6eSScott Long query_disk.Lun = 0; 349436e0bf6eSScott Long query_disk.UnMapped = 0; 34957540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 34960b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 349736e0bf6eSScott Long } 3498bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 349936e0bf6eSScott Long 3500914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3501914da7d0SScott Long sizeof(struct aac_query_disk)); 350236e0bf6eSScott Long 350336e0bf6eSScott Long return (error); 350436e0bf6eSScott Long } 350536e0bf6eSScott Long 3506fe3cb0e1SScott Long static void 3507fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3508fe3cb0e1SScott Long { 3509fe3cb0e1SScott Long struct aac_fib *fib; 3510fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3511fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3512fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3513fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3514fe3cb0e1SScott Long struct aac_getbusinf businfo; 351570545d1aSScott Long struct aac_sim *caminf; 3516fe3cb0e1SScott Long device_t child; 3517fe3cb0e1SScott Long int i, found, error; 3518fe3cb0e1SScott Long 35191ffe41c1SChristian S.J. Peron mtx_lock(&sc->aac_io_lock); 352003b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3521fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 352239ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3523fe3cb0e1SScott Long 3524fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3525fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3526fe3cb0e1SScott Long c_cmd->param = 0; 3527fe3cb0e1SScott Long 3528fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3529fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3530fe3cb0e1SScott Long if (error) { 3531fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3532fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3533fe3cb0e1SScott Long aac_release_sync_fib(sc); 35341ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3535fe3cb0e1SScott Long return; 3536fe3cb0e1SScott Long } 3537fe3cb0e1SScott Long 3538fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3539fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3540fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3541fe3cb0e1SScott Long c_resp->Status); 3542fe3cb0e1SScott Long aac_release_sync_fib(sc); 35431ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3544fe3cb0e1SScott Long return; 3545fe3cb0e1SScott Long } 3546fe3cb0e1SScott Long 3547fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3548fe3cb0e1SScott Long 3549fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 355039ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 355139ee03c3SScott Long 3552fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3553fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3554fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3555fe3cb0e1SScott Long vmi->ObjId = 0; 3556fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3557fe3cb0e1SScott Long 3558fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3559fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 3560fe3cb0e1SScott Long if (error) { 3561fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3562fe3cb0e1SScott Long error); 3563fe3cb0e1SScott Long aac_release_sync_fib(sc); 35641ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3565fe3cb0e1SScott Long return; 3566fe3cb0e1SScott Long } 3567fe3cb0e1SScott Long 3568fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3569fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3570fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3571fe3cb0e1SScott Long vmi_resp->Status); 3572fe3cb0e1SScott Long aac_release_sync_fib(sc); 35731ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3574fe3cb0e1SScott Long return; 3575fe3cb0e1SScott Long } 3576fe3cb0e1SScott Long 3577fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3578fe3cb0e1SScott Long aac_release_sync_fib(sc); 35791ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3580fe3cb0e1SScott Long 3581fe3cb0e1SScott Long found = 0; 3582fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3583fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3584fe3cb0e1SScott Long continue; 3585fe3cb0e1SScott Long 3586a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3587a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3588b5f516cdSScott Long if (caminf == NULL) { 3589b5f516cdSScott Long device_printf(sc->aac_dev, 3590b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3591b5f516cdSScott Long break; 35927cb209f5SScott Long }; 3593fe3cb0e1SScott Long 3594fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3595fe3cb0e1SScott Long if (child == NULL) { 3596b5f516cdSScott Long device_printf(sc->aac_dev, 3597b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3598b5f516cdSScott Long i); 3599b5f516cdSScott Long free(caminf, M_AACBUF); 3600b5f516cdSScott Long break; 3601fe3cb0e1SScott Long } 3602fe3cb0e1SScott Long 3603fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3604fe3cb0e1SScott Long caminf->BusNumber = i; 3605fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3606fe3cb0e1SScott Long caminf->aac_sc = sc; 3607ddb8683eSScott Long caminf->sim_dev = child; 3608fe3cb0e1SScott Long 3609fe3cb0e1SScott Long device_set_ivars(child, caminf); 3610fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 361170545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3612fe3cb0e1SScott Long 3613fe3cb0e1SScott Long found = 1; 3614fe3cb0e1SScott Long } 3615fe3cb0e1SScott Long 3616fe3cb0e1SScott Long if (found) 3617fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3618fe3cb0e1SScott Long 3619fe3cb0e1SScott Long return; 3620fe3cb0e1SScott Long } 3621