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_DRIVER_BUILD_DATE __DATE__ " " __TIME__ 387cb209f5SScott Long #define AAC_DRIVERNAME "aac" 3935863739SMike Smith 40f6c4dd3fSScott Long #include "opt_aac.h" 41f6c4dd3fSScott Long 4236e0bf6eSScott Long /* #include <stddef.h> */ 4335863739SMike Smith #include <sys/param.h> 4435863739SMike Smith #include <sys/systm.h> 4535863739SMike Smith #include <sys/malloc.h> 4635863739SMike Smith #include <sys/kernel.h> 4736e0bf6eSScott Long #include <sys/kthread.h> 483d04a9d7SScott Long #include <sys/sysctl.h> 49b3457b51SScott Long #include <sys/poll.h> 50891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 5135863739SMike Smith 5235863739SMike Smith #include <sys/bus.h> 5335863739SMike Smith #include <sys/conf.h> 5435863739SMike Smith #include <sys/signalvar.h> 550b94a66eSMike Smith #include <sys/time.h> 5636e0bf6eSScott Long #include <sys/eventhandler.h> 577cb209f5SScott Long #include <sys/rman.h> 5835863739SMike Smith 5935863739SMike Smith #include <machine/bus.h> 60b5f516cdSScott Long #include <sys/bus_dma.h> 6135863739SMike Smith #include <machine/resource.h> 6235863739SMike Smith 637cb209f5SScott Long #include <dev/pci/pcireg.h> 647cb209f5SScott Long #include <dev/pci/pcivar.h> 657cb209f5SScott Long 6635863739SMike Smith #include <dev/aac/aacreg.h> 670b0594cdSScott Long #include <sys/aac_ioctl.h> 6835863739SMike Smith #include <dev/aac/aacvar.h> 6935863739SMike Smith #include <dev/aac/aac_tables.h> 7035863739SMike Smith 7135863739SMike Smith static void aac_startup(void *arg); 72914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 73cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 74fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 7535863739SMike Smith 7635863739SMike Smith /* Command Processing */ 770b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7835863739SMike Smith static void aac_complete(void *context, int pending); 7935863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8035863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 81d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 8270545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8335863739SMike Smith 8435863739SMike Smith /* Command Buffer Management */ 85cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 86cd481291SScott Long int nseg, int error); 87c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 88c6eafcf2SScott Long int nseg, int error); 890b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 908480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9135863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9235863739SMike Smith 9335863739SMike Smith /* Hardware Interface */ 94c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 95c6eafcf2SScott Long int error); 96fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9735863739SMike Smith static int aac_init(struct aac_softc *sc); 9835863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 99c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 100c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 101c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 102f6c4dd3fSScott Long struct aac_command *cm); 103c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 104914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10536e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10636e0bf6eSScott Long struct aac_fib *fib); 10735863739SMike Smith 108b3457b51SScott Long /* Falcon/PPC interface */ 109b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 110b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 111b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 112b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 113b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 114b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 115b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 116a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 117b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 118b3457b51SScott Long 119b3457b51SScott Long struct aac_interface aac_fa_interface = { 120b3457b51SScott Long aac_fa_get_fwstatus, 121b3457b51SScott Long aac_fa_qnotify, 122b3457b51SScott Long aac_fa_get_istatus, 123b3457b51SScott Long aac_fa_clear_istatus, 124b3457b51SScott Long aac_fa_set_mailbox, 125a6d35632SScott Long aac_fa_get_mailbox, 1267cb209f5SScott Long aac_fa_set_interrupts, 1277cb209f5SScott Long NULL, NULL, NULL 128b3457b51SScott Long }; 129b3457b51SScott Long 13035863739SMike Smith /* StrongARM interface */ 13135863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13235863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13335863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13435863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13535863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 136c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 137c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 138a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13935863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 14035863739SMike Smith 14135863739SMike Smith struct aac_interface aac_sa_interface = { 14235863739SMike Smith aac_sa_get_fwstatus, 14335863739SMike Smith aac_sa_qnotify, 14435863739SMike Smith aac_sa_get_istatus, 14535863739SMike Smith aac_sa_clear_istatus, 14635863739SMike Smith aac_sa_set_mailbox, 147a6d35632SScott Long aac_sa_get_mailbox, 1487cb209f5SScott Long aac_sa_set_interrupts, 1497cb209f5SScott Long NULL, NULL, NULL 15035863739SMike Smith }; 15135863739SMike Smith 15235863739SMike Smith /* i960Rx interface */ 15335863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15435863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15535863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15635863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15735863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 158c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 159c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 160a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 16135863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1627cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1637cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1647cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 16535863739SMike Smith 16635863739SMike Smith struct aac_interface aac_rx_interface = { 16735863739SMike Smith aac_rx_get_fwstatus, 16835863739SMike Smith aac_rx_qnotify, 16935863739SMike Smith aac_rx_get_istatus, 17035863739SMike Smith aac_rx_clear_istatus, 17135863739SMike Smith aac_rx_set_mailbox, 172a6d35632SScott Long aac_rx_get_mailbox, 1737cb209f5SScott Long aac_rx_set_interrupts, 1747cb209f5SScott Long aac_rx_send_command, 1757cb209f5SScott Long aac_rx_get_outb_queue, 1767cb209f5SScott Long aac_rx_set_outb_queue 17735863739SMike Smith }; 17835863739SMike Smith 1794afedc31SScott Long /* Rocket/MIPS interface */ 1804afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1814afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1824afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1834afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1844afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1854afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1864afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1874afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1884afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1897cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1907cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1917cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1924afedc31SScott Long 1934afedc31SScott Long struct aac_interface aac_rkt_interface = { 1944afedc31SScott Long aac_rkt_get_fwstatus, 1954afedc31SScott Long aac_rkt_qnotify, 1964afedc31SScott Long aac_rkt_get_istatus, 1974afedc31SScott Long aac_rkt_clear_istatus, 1984afedc31SScott Long aac_rkt_set_mailbox, 1994afedc31SScott Long aac_rkt_get_mailbox, 2007cb209f5SScott Long aac_rkt_set_interrupts, 2017cb209f5SScott Long aac_rkt_send_command, 2027cb209f5SScott Long aac_rkt_get_outb_queue, 2037cb209f5SScott Long aac_rkt_set_outb_queue 2044afedc31SScott Long }; 2054afedc31SScott Long 20635863739SMike Smith /* Debugging and Diagnostics */ 20735863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 2086965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 209c6eafcf2SScott Long u_int32_t code); 21035863739SMike Smith 21135863739SMike Smith /* Management Interface */ 21235863739SMike Smith static d_open_t aac_open; 21335863739SMike Smith static d_close_t aac_close; 21435863739SMike Smith static d_ioctl_t aac_ioctl; 215b3457b51SScott Long static d_poll_t aac_poll; 216c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 217c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 21836e0bf6eSScott Long struct aac_fib *fib); 219fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 220fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 221fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 22236e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2237cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2247cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2257cb209f5SScott Long struct aac_event *event, void *arg); 22635863739SMike Smith 22735863739SMike Smith static struct cdevsw aac_cdevsw = { 228dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 229dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 2307ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2317ac40f5fSPoul-Henning Kamp .d_close = aac_close, 2327ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2337ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2347ac40f5fSPoul-Henning Kamp .d_name = "aac", 23535863739SMike Smith }; 23635863739SMike Smith 23736e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 23836e0bf6eSScott Long 2393d04a9d7SScott Long /* sysctl node */ 2403d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2413d04a9d7SScott Long 242914da7d0SScott Long /* 243914da7d0SScott Long * Device Interface 244914da7d0SScott Long */ 24535863739SMike Smith 246914da7d0SScott Long /* 24735863739SMike Smith * Initialise the controller and softc 24835863739SMike Smith */ 24935863739SMike Smith int 25035863739SMike Smith aac_attach(struct aac_softc *sc) 25135863739SMike Smith { 25235863739SMike Smith int error, unit; 25335863739SMike Smith 25435863739SMike Smith debug_called(1); 25535863739SMike Smith 25635863739SMike Smith /* 25735863739SMike Smith * Initialise per-controller queues. 25835863739SMike Smith */ 2590b94a66eSMike Smith aac_initq_free(sc); 2600b94a66eSMike Smith aac_initq_ready(sc); 2610b94a66eSMike Smith aac_initq_busy(sc); 2620b94a66eSMike Smith aac_initq_bio(sc); 26335863739SMike Smith 26435863739SMike Smith /* 26535863739SMike Smith * Initialise command-completion task. 26635863739SMike Smith */ 26735863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 26835863739SMike Smith 26935863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 27035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 27135863739SMike Smith 27235863739SMike Smith /* 273fe94b852SScott Long * Check that the firmware on the card is supported. 274fe94b852SScott Long */ 275fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 276fe94b852SScott Long return(error); 277fe94b852SScott Long 278f6b1c44dSScott Long /* 279f6b1c44dSScott Long * Initialize locks 280f6b1c44dSScott Long */ 281bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 282bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 283bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 284f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 285f6b1c44dSScott Long 2863df780cfSScott Long /* Initialize the local AIF queue pointers */ 2873df780cfSScott Long sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH; 288cbfd045bSScott 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, 3087cb209f5SScott Long INTR_MPSAFE|INTR_TYPE_BIO, aac_new_intr, 3097cb209f5SScott Long 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, 3157cb209f5SScott Long INTR_FAST|INTR_TYPE_BIO, aac_fast_intr, 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, 3217cb209f5SScott Long aac_fast_intr, sc, &sc->aac_intr)) { 3227cb209f5SScott Long device_printf(sc->aac_dev, 3237cb209f5SScott Long "can't set up MPSAFE interrupt\n"); 3247cb209f5SScott Long return (EINVAL); 3257cb209f5SScott Long } 3267cb209f5SScott Long } 3277cb209f5SScott Long } 3287cb209f5SScott Long 3297cb209f5SScott Long /* 33035863739SMike Smith * Print a little information about the controller. 33135863739SMike Smith */ 33235863739SMike Smith aac_describe_controller(sc); 33335863739SMike Smith 33435863739SMike Smith /* 335ae543596SScott Long * Register to probe our containers later. 336ae543596SScott Long */ 33735863739SMike Smith sc->aac_ich.ich_func = aac_startup; 33835863739SMike Smith sc->aac_ich.ich_arg = sc; 33935863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 340914da7d0SScott Long device_printf(sc->aac_dev, 341914da7d0SScott Long "can't establish configuration hook\n"); 34235863739SMike Smith return(ENXIO); 34335863739SMike Smith } 34435863739SMike Smith 34535863739SMike Smith /* 34635863739SMike Smith * Make the control device. 34735863739SMike Smith */ 34835863739SMike Smith unit = device_get_unit(sc->aac_dev); 3499e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3509e9466baSRobert Watson 0640, "aac%d", unit); 351157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3524aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 35335863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 35435863739SMike Smith 35536e0bf6eSScott Long /* Create the AIF thread */ 35670545d1aSScott Long if (kthread_create((void(*)(void *))aac_command_thread, sc, 357316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 35836e0bf6eSScott Long panic("Could not create AIF thread\n"); 35936e0bf6eSScott Long 36036e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3615f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3625f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3635f54d522SScott Long device_printf(sc->aac_dev, 3645f54d522SScott Long "shutdown event registration failed\n"); 36536e0bf6eSScott Long 366fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 367a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 36870545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 369fe3cb0e1SScott Long aac_get_bus_info(sc); 37070545d1aSScott Long } 371fe3cb0e1SScott Long 37235863739SMike Smith return(0); 37335863739SMike Smith } 37435863739SMike Smith 3757cb209f5SScott Long void 3767cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event) 3777cb209f5SScott Long { 3787cb209f5SScott Long 3797cb209f5SScott Long switch (event->ev_type & AAC_EVENT_MASK) { 3807cb209f5SScott Long case AAC_EVENT_CMFREE: 3817cb209f5SScott Long TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 3827cb209f5SScott Long break; 3837cb209f5SScott Long default: 3847cb209f5SScott Long device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 3857cb209f5SScott Long event->ev_type); 3867cb209f5SScott Long break; 3877cb209f5SScott Long } 3887cb209f5SScott Long 3897cb209f5SScott Long return; 3907cb209f5SScott Long } 3917cb209f5SScott Long 392914da7d0SScott Long /* 39335863739SMike Smith * Probe for containers, create disks. 39435863739SMike Smith */ 39535863739SMike Smith static void 39635863739SMike Smith aac_startup(void *arg) 39735863739SMike Smith { 398914da7d0SScott Long struct aac_softc *sc; 399cbfd045bSScott Long struct aac_fib *fib; 400cbfd045bSScott Long struct aac_mntinfo *mi; 401cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 402795d7dc0SScott Long int count = 0, i = 0; 40335863739SMike Smith 40435863739SMike Smith debug_called(1); 40535863739SMike Smith 406914da7d0SScott Long sc = (struct aac_softc *)arg; 407914da7d0SScott Long 40835863739SMike Smith /* disconnect ourselves from the intrhook chain */ 40935863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 41035863739SMike Smith 4117cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 41203b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 413cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 414cbfd045bSScott Long 41535863739SMike Smith /* loop over possible containers */ 41636e0bf6eSScott Long do { 41735863739SMike Smith /* request information on this container */ 41839ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 41939ee03c3SScott Long mi->Command = VM_NameServe; 42039ee03c3SScott Long mi->MntType = FT_FILESYS; 421cbfd045bSScott Long mi->MntCount = i; 422cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 423cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 424795d7dc0SScott Long printf("error probing container %d", i); 42535863739SMike Smith continue; 42635863739SMike Smith } 42735863739SMike Smith 428cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 429795d7dc0SScott Long /* XXX Need to check if count changed */ 430795d7dc0SScott Long count = mir->MntRespCount; 431cbfd045bSScott Long aac_add_container(sc, mir, 0); 43236e0bf6eSScott Long i++; 433795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 434cbfd045bSScott Long 435cbfd045bSScott Long aac_release_sync_fib(sc); 4367cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 43735863739SMike Smith 43835863739SMike Smith /* poke the bus to actually attach the child devices */ 43935863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 44035863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 44135863739SMike Smith 44235863739SMike Smith /* mark the controller up */ 44335863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 44435863739SMike Smith 44535863739SMike Smith /* enable interrupts now */ 44635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 44735863739SMike Smith } 44835863739SMike Smith 449914da7d0SScott Long /* 450914da7d0SScott Long * Create a device to respresent a new container 451914da7d0SScott Long */ 452914da7d0SScott Long static void 453cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 454914da7d0SScott Long { 455914da7d0SScott Long struct aac_container *co; 456914da7d0SScott Long device_t child; 457914da7d0SScott Long 458914da7d0SScott Long /* 459914da7d0SScott Long * Check container volume type for validity. Note that many of 460914da7d0SScott Long * the possible types may never show up. 461914da7d0SScott Long */ 462914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 463a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 464a761a1caSScott Long M_NOWAIT | M_ZERO); 465914da7d0SScott Long if (co == NULL) 466914da7d0SScott Long panic("Out of memory?!\n"); 467914da7d0SScott Long debug(1, "id %x name '%.16s' size %u type %d", 468914da7d0SScott Long mir->MntTable[0].ObjectId, 469914da7d0SScott Long mir->MntTable[0].FileSystemName, 470914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 471914da7d0SScott Long 472fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 473914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 474914da7d0SScott Long else 475914da7d0SScott Long device_set_ivars(child, co); 476914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 477914da7d0SScott Long mir->MntTable[0].VolType)); 478914da7d0SScott Long co->co_disk = child; 479914da7d0SScott Long co->co_found = f; 480914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 481914da7d0SScott Long sizeof(struct aac_mntobj)); 482bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 483914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 484bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 485914da7d0SScott Long } 486914da7d0SScott Long } 487914da7d0SScott Long 488914da7d0SScott Long /* 48935863739SMike Smith * Free all of the resources associated with (sc) 49035863739SMike Smith * 49135863739SMike Smith * Should not be called if the controller is active. 49235863739SMike Smith */ 49335863739SMike Smith void 49435863739SMike Smith aac_free(struct aac_softc *sc) 49535863739SMike Smith { 496ffb37f33SScott Long 49735863739SMike Smith debug_called(1); 49835863739SMike Smith 49935863739SMike Smith /* remove the control device */ 50035863739SMike Smith if (sc->aac_dev_t != NULL) 50135863739SMike Smith destroy_dev(sc->aac_dev_t); 50235863739SMike Smith 5030b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 5048480cc63SScott Long aac_free_commands(sc); 5050b94a66eSMike Smith if (sc->aac_fib_dmat) 5060b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 50735863739SMike Smith 508ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 509ffb37f33SScott Long 51035863739SMike Smith /* destroy the common area */ 51135863739SMike Smith if (sc->aac_common) { 51235863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 513c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 514c6eafcf2SScott Long sc->aac_common_dmamap); 51535863739SMike Smith } 5160b94a66eSMike Smith if (sc->aac_common_dmat) 5170b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 51835863739SMike Smith 51935863739SMike Smith /* disconnect the interrupt handler */ 52035863739SMike Smith if (sc->aac_intr) 52135863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 52235863739SMike Smith if (sc->aac_irq != NULL) 523c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 524c6eafcf2SScott Long sc->aac_irq); 52535863739SMike Smith 52635863739SMike Smith /* destroy data-transfer DMA tag */ 52735863739SMike Smith if (sc->aac_buffer_dmat) 52835863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 52935863739SMike Smith 53035863739SMike Smith /* destroy the parent DMA tag */ 53135863739SMike Smith if (sc->aac_parent_dmat) 53235863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 53335863739SMike Smith 53435863739SMike Smith /* release the register window mapping */ 53535863739SMike Smith if (sc->aac_regs_resource != NULL) 536914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 537914da7d0SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 53835863739SMike Smith } 53935863739SMike Smith 540914da7d0SScott Long /* 54135863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 54235863739SMike Smith */ 54335863739SMike Smith int 54435863739SMike Smith aac_detach(device_t dev) 54535863739SMike Smith { 546914da7d0SScott Long struct aac_softc *sc; 54770545d1aSScott Long struct aac_container *co; 54870545d1aSScott Long struct aac_sim *sim; 54935863739SMike Smith int error; 55035863739SMike Smith 55135863739SMike Smith debug_called(1); 55235863739SMike Smith 553914da7d0SScott Long sc = device_get_softc(dev); 554914da7d0SScott Long 55535863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 55635863739SMike Smith return(EBUSY); 55735863739SMike Smith 55870545d1aSScott Long /* Remove the child containers */ 559a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 56070545d1aSScott Long error = device_delete_child(dev, co->co_disk); 56170545d1aSScott Long if (error) 56270545d1aSScott Long return (error); 56365ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 564a761a1caSScott Long free(co, M_AACBUF); 56570545d1aSScott Long } 56670545d1aSScott Long 56770545d1aSScott Long /* Remove the CAM SIMs */ 568a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 569a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 57070545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 57170545d1aSScott Long if (error) 57270545d1aSScott Long return (error); 573a761a1caSScott Long free(sim, M_AACBUF); 57470545d1aSScott Long } 57570545d1aSScott Long 57636e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 57736e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 57836e0bf6eSScott Long wakeup(sc->aifthread); 57936e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 58036e0bf6eSScott Long } 58136e0bf6eSScott Long 58236e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 58336e0bf6eSScott Long panic("Cannot shutdown AIF thread\n"); 58436e0bf6eSScott Long 58535863739SMike Smith if ((error = aac_shutdown(dev))) 58635863739SMike Smith return(error); 58735863739SMike Smith 5885f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 5895f54d522SScott Long 59035863739SMike Smith aac_free(sc); 59135863739SMike Smith 592dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 593dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 594dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 595dc9efde5SScott Long 59635863739SMike Smith return(0); 59735863739SMike Smith } 59835863739SMike Smith 599914da7d0SScott Long /* 60035863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 60135863739SMike Smith * 60235863739SMike Smith * This function is called before detach or system shutdown. 60335863739SMike Smith * 6040b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 60535863739SMike Smith * allow shutdown if any device is open. 60635863739SMike Smith */ 60735863739SMike Smith int 60835863739SMike Smith aac_shutdown(device_t dev) 60935863739SMike Smith { 610914da7d0SScott Long struct aac_softc *sc; 611cbfd045bSScott Long struct aac_fib *fib; 612cbfd045bSScott Long struct aac_close_command *cc; 61335863739SMike Smith 61435863739SMike Smith debug_called(1); 61535863739SMike Smith 616914da7d0SScott Long sc = device_get_softc(dev); 617914da7d0SScott Long 61835863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 61935863739SMike Smith 62035863739SMike Smith /* 62135863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 62235863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 62335863739SMike Smith * We've been closed and all I/O completed already 62435863739SMike Smith */ 62535863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 62635863739SMike Smith 6277cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 62803b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 629cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 630cbfd045bSScott Long 63139ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 632cbfd045bSScott Long cc->Command = VM_CloseAll; 633cbfd045bSScott Long cc->ContainerId = 0xffffffff; 634cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 635cbfd045bSScott Long sizeof(struct aac_close_command))) 63635863739SMike Smith printf("FAILED.\n"); 63770545d1aSScott Long else 63870545d1aSScott Long printf("done\n"); 63970545d1aSScott Long #if 0 640914da7d0SScott Long else { 641cbfd045bSScott Long fib->data[0] = 0; 64236e0bf6eSScott Long /* 643914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 64436e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 64536e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 64636e0bf6eSScott Long * driver module with the intent to reload it later. 64736e0bf6eSScott Long */ 648cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 649cbfd045bSScott Long fib, 1)) { 65035863739SMike Smith printf("FAILED.\n"); 65135863739SMike Smith } else { 65235863739SMike Smith printf("done.\n"); 65335863739SMike Smith } 65435863739SMike Smith } 65570545d1aSScott Long #endif 65635863739SMike Smith 65735863739SMike Smith AAC_MASK_INTERRUPTS(sc); 6583576af8fSScott Long aac_release_sync_fib(sc); 6597cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 66035863739SMike Smith 66135863739SMike Smith return(0); 66235863739SMike Smith } 66335863739SMike Smith 664914da7d0SScott Long /* 66535863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 66635863739SMike Smith */ 66735863739SMike Smith int 66835863739SMike Smith aac_suspend(device_t dev) 66935863739SMike Smith { 670914da7d0SScott Long struct aac_softc *sc; 67135863739SMike Smith 67235863739SMike Smith debug_called(1); 673914da7d0SScott Long 674914da7d0SScott Long sc = device_get_softc(dev); 675914da7d0SScott Long 67635863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 67735863739SMike Smith 67835863739SMike Smith AAC_MASK_INTERRUPTS(sc); 67935863739SMike Smith return(0); 68035863739SMike Smith } 68135863739SMike Smith 682914da7d0SScott Long /* 68335863739SMike Smith * Bring the controller back to a state ready for operation. 68435863739SMike Smith */ 68535863739SMike Smith int 68635863739SMike Smith aac_resume(device_t dev) 68735863739SMike Smith { 688914da7d0SScott Long struct aac_softc *sc; 68935863739SMike Smith 69035863739SMike Smith debug_called(1); 691914da7d0SScott Long 692914da7d0SScott Long sc = device_get_softc(dev); 693914da7d0SScott Long 69435863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 69535863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 69635863739SMike Smith return(0); 69735863739SMike Smith } 69835863739SMike Smith 699914da7d0SScott Long /* 7007cb209f5SScott Long * Interrupt handler for NEW_COMM interface. 70135863739SMike Smith */ 70235863739SMike Smith void 7037cb209f5SScott Long aac_new_intr(void *arg) 7047cb209f5SScott Long { 7057cb209f5SScott Long struct aac_softc *sc; 7067cb209f5SScott Long u_int32_t index, fast; 7077cb209f5SScott Long struct aac_command *cm; 7087cb209f5SScott Long struct aac_fib *fib; 7097cb209f5SScott Long int i; 7107cb209f5SScott Long 7117cb209f5SScott Long debug_called(2); 7127cb209f5SScott Long 7137cb209f5SScott Long sc = (struct aac_softc *)arg; 7147cb209f5SScott Long 7157cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 7167cb209f5SScott Long while (1) { 7177cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 7187cb209f5SScott Long if (index == 0xffffffff) 7197cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 7207cb209f5SScott Long if (index == 0xffffffff) 7217cb209f5SScott Long break; 7227cb209f5SScott Long if (index & 2) { 7237cb209f5SScott Long if (index == 0xfffffffe) { 7247cb209f5SScott Long /* XXX This means that the controller wants 7257cb209f5SScott Long * more work. Ignore it for now. 7267cb209f5SScott Long */ 7277cb209f5SScott Long continue; 7287cb209f5SScott Long } 7297cb209f5SScott Long /* AIF */ 7307cb209f5SScott Long fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 7317cb209f5SScott Long M_NOWAIT | M_ZERO); 7327cb209f5SScott Long if (fib == NULL) { 7337cb209f5SScott Long /* If we're really this short on memory, 7347cb209f5SScott Long * hopefully breaking out of the handler will 7357cb209f5SScott Long * allow something to get freed. This 7367cb209f5SScott Long * actually sucks a whole lot. 7377cb209f5SScott Long */ 7387cb209f5SScott Long break; 7397cb209f5SScott Long } 7407cb209f5SScott Long index &= ~2; 7417cb209f5SScott Long for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 7427cb209f5SScott Long ((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4); 7437cb209f5SScott Long aac_handle_aif(sc, fib); 7447cb209f5SScott Long free(fib, M_AACBUF); 7457cb209f5SScott Long 7467cb209f5SScott Long /* 7477cb209f5SScott Long * AIF memory is owned by the adapter, so let it 7487cb209f5SScott Long * know that we are done with it. 7497cb209f5SScott Long */ 7507cb209f5SScott Long AAC_SET_OUTB_QUEUE(sc, index); 7517cb209f5SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 7527cb209f5SScott Long } else { 7537cb209f5SScott Long fast = index & 1; 7547cb209f5SScott Long cm = sc->aac_commands + (index >> 2); 7557cb209f5SScott Long fib = cm->cm_fib; 7567cb209f5SScott Long if (fast) { 7577cb209f5SScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 7587cb209f5SScott Long *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 7597cb209f5SScott Long } 7607cb209f5SScott Long aac_remove_busy(cm); 7617cb209f5SScott Long aac_unmap_command(cm); 7627cb209f5SScott Long cm->cm_flags |= AAC_CMD_COMPLETED; 7637cb209f5SScott Long 7647cb209f5SScott Long /* is there a completion handler? */ 7657cb209f5SScott Long if (cm->cm_complete != NULL) { 7667cb209f5SScott Long cm->cm_complete(cm); 7677cb209f5SScott Long } else { 7687cb209f5SScott Long /* assume that someone is sleeping on this 7697cb209f5SScott Long * command 7707cb209f5SScott Long */ 7717cb209f5SScott Long wakeup(cm); 7727cb209f5SScott Long } 7737cb209f5SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 7747cb209f5SScott Long } 7757cb209f5SScott Long } 7767cb209f5SScott Long /* see if we can start some more I/O */ 7777cb209f5SScott Long if ((sc->flags & AAC_QUEUE_FRZN) == 0) 7787cb209f5SScott Long aac_startio(sc); 7797cb209f5SScott Long 7807cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 7817cb209f5SScott Long } 7827cb209f5SScott Long 7837cb209f5SScott Long void 7847cb209f5SScott Long aac_fast_intr(void *arg) 78535863739SMike Smith { 786914da7d0SScott Long struct aac_softc *sc; 78770545d1aSScott Long u_int16_t reason; 78835863739SMike Smith 78935863739SMike Smith debug_called(2); 79035863739SMike Smith 791914da7d0SScott Long sc = (struct aac_softc *)arg; 792914da7d0SScott Long 793f30ac74cSScott Long /* 7949148fa21SScott Long * Read the status register directly. This is faster than taking the 7959148fa21SScott Long * driver lock and reading the queues directly. It also saves having 7969148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 7979148fa21SScott Long * ugly. 798f30ac74cSScott Long */ 79935863739SMike Smith reason = AAC_GET_ISTATUS(sc); 800f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 801f30ac74cSScott Long 8029c3a7fceSScott Long /* handle completion processing */ 8039148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 8049148fa21SScott Long taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 80535863739SMike Smith 8069148fa21SScott Long /* controller wants to talk to us */ 8079148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 80870545d1aSScott Long /* 8099148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 8109148fa21SScott Long * that start with a NULL. 81170545d1aSScott Long */ 8129148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 8139148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 8149148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 81570545d1aSScott Long 8169148fa21SScott Long /* 8179148fa21SScott Long * This might miss doing the actual wakeup. However, the 818a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 8199148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 8209148fa21SScott Long * priority that they can handle hanging out for a few seconds 8219148fa21SScott Long * if needed. 8229148fa21SScott Long */ 82336e0bf6eSScott Long wakeup(sc->aifthread); 82436e0bf6eSScott Long } 8259148fa21SScott Long } 82635863739SMike Smith 827c6eafcf2SScott Long /* 828914da7d0SScott Long * Command Processing 829914da7d0SScott Long */ 83035863739SMike Smith 831914da7d0SScott Long /* 83235863739SMike Smith * Start as much queued I/O as possible on the controller 83335863739SMike Smith */ 834fe3cb0e1SScott Long void 83535863739SMike Smith aac_startio(struct aac_softc *sc) 83635863739SMike Smith { 83735863739SMike Smith struct aac_command *cm; 838397fa34fSScott Long int error; 83935863739SMike Smith 84035863739SMike Smith debug_called(2); 84135863739SMike Smith 84235863739SMike Smith for (;;) { 843914da7d0SScott Long /* 844397fa34fSScott Long * This flag might be set if the card is out of resources. 845397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 846397fa34fSScott Long */ 847397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 848397fa34fSScott Long break; 849397fa34fSScott Long 850397fa34fSScott Long /* 851914da7d0SScott Long * Try to get a command that's been put off for lack of 852914da7d0SScott Long * resources 853914da7d0SScott Long */ 85435863739SMike Smith cm = aac_dequeue_ready(sc); 85535863739SMike Smith 856914da7d0SScott Long /* 857914da7d0SScott Long * Try to build a command off the bio queue (ignore error 858914da7d0SScott Long * return) 859914da7d0SScott Long */ 8600b94a66eSMike Smith if (cm == NULL) 86135863739SMike Smith aac_bio_command(sc, &cm); 86235863739SMike Smith 86335863739SMike Smith /* nothing to do? */ 86435863739SMike Smith if (cm == NULL) 86535863739SMike Smith break; 86635863739SMike Smith 867cd481291SScott Long /* don't map more than once */ 868cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 8694102d44bSScott Long panic("aac: command %p already mapped", cm); 87035863739SMike Smith 871397fa34fSScott Long /* 872397fa34fSScott Long * Set up the command to go to the controller. If there are no 873397fa34fSScott Long * data buffers associated with the command then it can bypass 874397fa34fSScott Long * busdma. 875397fa34fSScott Long */ 876cd481291SScott Long if (cm->cm_datalen != 0) { 877397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 878397fa34fSScott Long cm->cm_datamap, cm->cm_data, 879397fa34fSScott Long cm->cm_datalen, 880cd481291SScott Long aac_map_command_sg, cm, 0); 881cd481291SScott Long if (error == EINPROGRESS) { 882cd481291SScott Long debug(1, "freezing queue\n"); 883cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 884cd481291SScott Long error = 0; 885614c22b2SScott Long } else if (error != 0) 886397fa34fSScott Long panic("aac_startio: unexpected error %d from " 887397fa34fSScott Long "busdma\n", error); 888397fa34fSScott Long } else 8898778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 890cd481291SScott Long } 89135863739SMike Smith } 89235863739SMike Smith 893914da7d0SScott Long /* 89435863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 89535863739SMike Smith */ 89635863739SMike Smith static void 89770545d1aSScott Long aac_command_thread(struct aac_softc *sc) 89835863739SMike Smith { 89935863739SMike Smith struct aac_fib *fib; 90035863739SMike Smith u_int32_t fib_size; 9019148fa21SScott Long int size, retval; 90235863739SMike Smith 90336e0bf6eSScott Long debug_called(2); 90435863739SMike Smith 905bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 906a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 90736e0bf6eSScott Long 908a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 909a32a982dSScott Long 910a32a982dSScott Long retval = 0; 911a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 912a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 913a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 91436e0bf6eSScott Long 9159148fa21SScott Long /* 9169148fa21SScott Long * First see if any FIBs need to be allocated. This needs 9179148fa21SScott Long * to be called without the driver lock because contigmalloc 9189148fa21SScott Long * will grab Giant, and would result in an LOR. 9199148fa21SScott Long */ 9209148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 921bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 922a32a982dSScott Long aac_alloc_commands(sc); 923bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 9244102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 925a32a982dSScott Long aac_startio(sc); 926a32a982dSScott Long } 9279148fa21SScott Long 9289148fa21SScott Long /* 9299148fa21SScott Long * While we're here, check to see if any commands are stuck. 9309148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 9319148fa21SScott Long * always fire. 9329148fa21SScott Long */ 9339148fa21SScott Long if (retval == EWOULDBLOCK) 93470545d1aSScott Long aac_timeout(sc); 93570545d1aSScott Long 93670545d1aSScott Long /* Check the hardware printf message buffer */ 9379148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 93870545d1aSScott Long aac_print_printf(sc); 93970545d1aSScott Long 9409148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 9417cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 9427cb209f5SScott Long continue; 9437cb209f5SScott Long for (;;) { 9447cb209f5SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 9457cb209f5SScott Long &fib_size, &fib)) 9467cb209f5SScott Long break; 94735863739SMike Smith 94836e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 94936e0bf6eSScott Long 95035863739SMike Smith switch (fib->Header.Command) { 95135863739SMike Smith case AifRequest: 95236e0bf6eSScott Long aac_handle_aif(sc, fib); 95335863739SMike Smith break; 95435863739SMike Smith default: 955914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 956914da7d0SScott Long "from controller\n"); 95735863739SMike Smith break; 95835863739SMike Smith } 95935863739SMike Smith 96036e0bf6eSScott Long if ((fib->Header.XferState == 0) || 9617cb209f5SScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 96236e0bf6eSScott Long break; 9637cb209f5SScott Long } 96436e0bf6eSScott Long 96570545d1aSScott Long /* Return the AIF to the controller. */ 96636e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 96736e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 96836e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 96936e0bf6eSScott Long 97036e0bf6eSScott Long /* XXX Compute the Size field? */ 97136e0bf6eSScott Long size = fib->Header.Size; 97236e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 97336e0bf6eSScott Long size = sizeof(struct aac_fib); 97436e0bf6eSScott Long fib->Header.Size = size; 97536e0bf6eSScott Long } 97636e0bf6eSScott Long /* 977914da7d0SScott Long * Since we did not generate this command, it 978914da7d0SScott Long * cannot go through the normal 979914da7d0SScott Long * enqueue->startio chain. 98036e0bf6eSScott Long */ 981914da7d0SScott Long aac_enqueue_response(sc, 982914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 983914da7d0SScott Long fib); 98436e0bf6eSScott Long } 98536e0bf6eSScott Long } 98636e0bf6eSScott Long } 98736e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 988bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 98936e0bf6eSScott Long wakeup(sc->aac_dev); 99036e0bf6eSScott Long 99136e0bf6eSScott Long kthread_exit(0); 99235863739SMike Smith } 99335863739SMike Smith 994914da7d0SScott Long /* 9959c3a7fceSScott Long * Process completed commands. 99635863739SMike Smith */ 99735863739SMike Smith static void 9989c3a7fceSScott Long aac_complete(void *context, int pending) 99935863739SMike Smith { 10009c3a7fceSScott Long struct aac_softc *sc; 100135863739SMike Smith struct aac_command *cm; 100235863739SMike Smith struct aac_fib *fib; 100335863739SMike Smith u_int32_t fib_size; 100435863739SMike Smith 100535863739SMike Smith debug_called(2); 100635863739SMike Smith 10079c3a7fceSScott Long sc = (struct aac_softc *)context; 10089c3a7fceSScott Long 1009bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1010ae543596SScott Long 10119c3a7fceSScott Long /* pull completed commands off the queue */ 101235863739SMike Smith for (;;) { 101335863739SMike Smith /* look for completed FIBs on our queue */ 1014914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1015914da7d0SScott Long &fib)) 101635863739SMike Smith break; /* nothing to do */ 101735863739SMike Smith 1018ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 1019cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 102035863739SMike Smith if (cm == NULL) { 102135863739SMike Smith AAC_PRINT_FIB(sc, fib); 10229c3a7fceSScott Long break; 10239c3a7fceSScott Long } 10240b94a66eSMike Smith aac_remove_busy(cm); 10257cb209f5SScott Long 1026ecd1c51fSScott Long aac_unmap_command(cm); 102735863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 102835863739SMike Smith 102935863739SMike Smith /* is there a completion handler? */ 103035863739SMike Smith if (cm->cm_complete != NULL) { 103135863739SMike Smith cm->cm_complete(cm); 103235863739SMike Smith } else { 103335863739SMike Smith /* assume that someone is sleeping on this command */ 103435863739SMike Smith wakeup(cm); 103535863739SMike Smith } 103635863739SMike Smith } 10370b94a66eSMike Smith 10380b94a66eSMike Smith /* see if we can start some more I/O */ 1039cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 10400b94a66eSMike Smith aac_startio(sc); 1041ae543596SScott Long 1042bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 104335863739SMike Smith } 104435863739SMike Smith 1045914da7d0SScott Long /* 104635863739SMike Smith * Handle a bio submitted from a disk device. 104735863739SMike Smith */ 104835863739SMike Smith void 104935863739SMike Smith aac_submit_bio(struct bio *bp) 105035863739SMike Smith { 1051914da7d0SScott Long struct aac_disk *ad; 1052914da7d0SScott Long struct aac_softc *sc; 105335863739SMike Smith 105435863739SMike Smith debug_called(2); 105535863739SMike Smith 10567540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1057914da7d0SScott Long sc = ad->ad_controller; 1058914da7d0SScott Long 105935863739SMike Smith /* queue the BIO and try to get some work done */ 10600b94a66eSMike Smith aac_enqueue_bio(sc, bp); 106135863739SMike Smith aac_startio(sc); 106235863739SMike Smith } 106335863739SMike Smith 1064914da7d0SScott Long /* 106535863739SMike Smith * Get a bio and build a command to go with it. 106635863739SMike Smith */ 106735863739SMike Smith static int 106835863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 106935863739SMike Smith { 107035863739SMike Smith struct aac_command *cm; 107135863739SMike Smith struct aac_fib *fib; 107235863739SMike Smith struct aac_disk *ad; 107335863739SMike Smith struct bio *bp; 107435863739SMike Smith 107535863739SMike Smith debug_called(2); 107635863739SMike Smith 107735863739SMike Smith /* get the resources we will need */ 107835863739SMike Smith cm = NULL; 1079a32a982dSScott Long bp = NULL; 108035863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 108135863739SMike Smith goto fail; 1082a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 1083a32a982dSScott Long goto fail; 108435863739SMike Smith 108535863739SMike Smith /* fill out the command */ 10860b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 10870b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 10880b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 108935863739SMike Smith cm->cm_private = bp; 10902b3b0f17SScott Long cm->cm_timestamp = time_uptime; 109136e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 109235863739SMike Smith 109335863739SMike Smith /* build the FIB */ 109435863739SMike Smith fib = cm->cm_fib; 1095b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 109635863739SMike Smith fib->Header.XferState = 109735863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 109835863739SMike Smith AAC_FIBSTATE_INITIALISED | 1099f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 110035863739SMike Smith AAC_FIBSTATE_FROMHOST | 110135863739SMike Smith AAC_FIBSTATE_REXPECTED | 1102f30ac74cSScott Long AAC_FIBSTATE_NORM | 1103f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 1104f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 110535863739SMike Smith 110635863739SMike Smith /* build the read/write request */ 11077540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1108b85f5808SScott Long 11097cb209f5SScott Long if (sc->flags & AAC_FLAGS_RAW_IO) { 11107cb209f5SScott Long struct aac_raw_io *raw; 11117cb209f5SScott Long raw = (struct aac_raw_io *)&fib->data[0]; 11127cb209f5SScott Long fib->Header.Command = RawIo; 11137cb209f5SScott Long raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 11147cb209f5SScott Long raw->ByteCount = bp->bio_bcount; 11157cb209f5SScott Long raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 11167cb209f5SScott Long raw->BpTotal = 0; 11177cb209f5SScott Long raw->BpComplete = 0; 11187cb209f5SScott Long fib->Header.Size += sizeof(struct aac_raw_io); 11197cb209f5SScott Long cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 11207cb209f5SScott Long if (bp->bio_cmd == BIO_READ) { 11217cb209f5SScott Long raw->Flags = 1; 11227cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 11237cb209f5SScott Long } else { 11247cb209f5SScott Long raw->Flags = 0; 11257cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 11267cb209f5SScott Long } 11277cb209f5SScott Long } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1128b85f5808SScott Long fib->Header.Command = ContainerCommand; 11299e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 1130b85f5808SScott Long struct aac_blockread *br; 113135863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 113235863739SMike Smith br->Command = VM_CtBlockRead; 113335863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 113435863739SMike Smith br->BlockNumber = bp->bio_pblkno; 113535863739SMike Smith br->ByteCount = bp->bio_bcount; 113635863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 113735863739SMike Smith cm->cm_sgtable = &br->SgMap; 113835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 113935863739SMike Smith } else { 1140b85f5808SScott Long struct aac_blockwrite *bw; 114135863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 114235863739SMike Smith bw->Command = VM_CtBlockWrite; 114335863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 114435863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 114535863739SMike Smith bw->ByteCount = bp->bio_bcount; 1146b85f5808SScott Long bw->Stable = CUNSTABLE; 114735863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 114835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 114935863739SMike Smith cm->cm_sgtable = &bw->SgMap; 115035863739SMike Smith } 1151b85f5808SScott Long } else { 1152b85f5808SScott Long fib->Header.Command = ContainerCommand64; 1153b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 1154b85f5808SScott Long struct aac_blockread64 *br; 1155b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 1156b85f5808SScott Long br->Command = VM_CtHostRead64; 1157b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1158b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1159b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 1160b85f5808SScott Long br->Pad = 0; 1161b85f5808SScott Long br->Flags = 0; 1162b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 1163b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 1164eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1165b85f5808SScott Long } else { 1166b85f5808SScott Long struct aac_blockwrite64 *bw; 1167b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 1168b85f5808SScott Long bw->Command = VM_CtHostWrite64; 1169b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1170b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1171b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 1172b85f5808SScott Long bw->Pad = 0; 1173b85f5808SScott Long bw->Flags = 0; 1174b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 1175b85f5808SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 1176eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1177b85f5808SScott Long } 1178b85f5808SScott Long } 117935863739SMike Smith 118035863739SMike Smith *cmp = cm; 118135863739SMike Smith return(0); 118235863739SMike Smith 118335863739SMike Smith fail: 11847cb209f5SScott Long if (bp != NULL) 11857cb209f5SScott Long aac_enqueue_bio(sc, bp); 118635863739SMike Smith if (cm != NULL) 118735863739SMike Smith aac_release_command(cm); 118835863739SMike Smith return(ENOMEM); 118935863739SMike Smith } 119035863739SMike Smith 1191914da7d0SScott Long /* 119235863739SMike Smith * Handle a bio-instigated command that has been completed. 119335863739SMike Smith */ 119435863739SMike Smith static void 119535863739SMike Smith aac_bio_complete(struct aac_command *cm) 119635863739SMike Smith { 119735863739SMike Smith struct aac_blockread_response *brr; 119835863739SMike Smith struct aac_blockwrite_response *bwr; 119935863739SMike Smith struct bio *bp; 120035863739SMike Smith AAC_FSAStatus status; 120135863739SMike Smith 120235863739SMike Smith /* fetch relevant status and then release the command */ 120335863739SMike Smith bp = (struct bio *)cm->cm_private; 12049e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 120535863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 120635863739SMike Smith status = brr->Status; 120735863739SMike Smith } else { 120835863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 120935863739SMike Smith status = bwr->Status; 121035863739SMike Smith } 121135863739SMike Smith aac_release_command(cm); 121235863739SMike Smith 121335863739SMike Smith /* fix up the bio based on status */ 121435863739SMike Smith if (status == ST_OK) { 121535863739SMike Smith bp->bio_resid = 0; 121635863739SMike Smith } else { 121735863739SMike Smith bp->bio_error = EIO; 121835863739SMike Smith bp->bio_flags |= BIO_ERROR; 12190b94a66eSMike Smith /* pass an error string out to the disk layer */ 1220914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1221914da7d0SScott Long status); 122235863739SMike Smith } 12230b94a66eSMike Smith aac_biodone(bp); 122435863739SMike Smith } 122535863739SMike Smith 1226914da7d0SScott Long /* 122735863739SMike Smith * Submit a command to the controller, return when it completes. 1228b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1229b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1230d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1231d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1232d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1233d8a0a473SScott Long * card completing a command late and spamming the command and data 1234d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 123535863739SMike Smith */ 123635863739SMike Smith static int 1237d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 123835863739SMike Smith { 1239ae543596SScott Long struct aac_softc *sc; 1240d8a0a473SScott Long int error; 124135863739SMike Smith 124235863739SMike Smith debug_called(2); 124335863739SMike Smith 1244ae543596SScott Long sc = cm->cm_sc; 1245ae543596SScott Long 124635863739SMike Smith /* Put the command on the ready queue and get things going */ 124736e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 124835863739SMike Smith aac_enqueue_ready(cm); 1249ae543596SScott Long aac_startio(sc); 1250ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 125135863739SMike Smith return(error); 125235863739SMike Smith } 125335863739SMike Smith 1254914da7d0SScott Long /* 1255914da7d0SScott Long *Command Buffer Management 1256914da7d0SScott Long */ 125735863739SMike Smith 1258914da7d0SScott Long /* 125935863739SMike Smith * Allocate a command. 126035863739SMike Smith */ 1261fe3cb0e1SScott Long int 126235863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 126335863739SMike Smith { 126435863739SMike Smith struct aac_command *cm; 126535863739SMike Smith 126635863739SMike Smith debug_called(3); 126735863739SMike Smith 1268ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1269b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1270ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1271ae543596SScott Long wakeup(sc->aifthread); 1272b85f5808SScott Long } 1273ae543596SScott Long return (EBUSY); 1274ffb37f33SScott Long } 127535863739SMike Smith 12760b94a66eSMike Smith *cmp = cm; 12770b94a66eSMike Smith return(0); 12780b94a66eSMike Smith } 12790b94a66eSMike Smith 1280914da7d0SScott Long /* 12810b94a66eSMike Smith * Release a command back to the freelist. 12820b94a66eSMike Smith */ 1283fe3cb0e1SScott Long void 12840b94a66eSMike Smith aac_release_command(struct aac_command *cm) 12850b94a66eSMike Smith { 12867cb209f5SScott Long struct aac_event *event; 12877cb209f5SScott Long struct aac_softc *sc; 12887cb209f5SScott Long 12890b94a66eSMike Smith debug_called(3); 12900b94a66eSMike Smith 12910b94a66eSMike Smith /* (re)initialise the command/FIB */ 129235863739SMike Smith cm->cm_sgtable = NULL; 129335863739SMike Smith cm->cm_flags = 0; 129435863739SMike Smith cm->cm_complete = NULL; 129535863739SMike Smith cm->cm_private = NULL; 129635863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 129735863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 129835863739SMike Smith cm->cm_fib->Header.Flags = 0; 12997cb209f5SScott Long cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 130035863739SMike Smith 130135863739SMike Smith /* 130235863739SMike Smith * These are duplicated in aac_start to cover the case where an 130335863739SMike Smith * intermediate stage may have destroyed them. They're left 130435863739SMike Smith * initialised here for debugging purposes only. 130535863739SMike Smith */ 1306f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1307f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 130835863739SMike Smith 130935863739SMike Smith aac_enqueue_free(cm); 13107cb209f5SScott Long 13117cb209f5SScott Long sc = cm->cm_sc; 13127cb209f5SScott Long event = TAILQ_FIRST(&sc->aac_ev_cmfree); 13137cb209f5SScott Long if (event != NULL) { 13147cb209f5SScott Long TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 13157cb209f5SScott Long event->ev_callback(sc, event, event->ev_arg); 13167cb209f5SScott Long } 131735863739SMike Smith } 131835863739SMike Smith 1319914da7d0SScott Long /* 13200b94a66eSMike Smith * Map helper for command/FIB allocation. 132135863739SMike Smith */ 132235863739SMike Smith static void 13230b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 132435863739SMike Smith { 13257cb209f5SScott Long uint64_t *fibphys; 1326914da7d0SScott Long 13277cb209f5SScott Long fibphys = (uint64_t *)arg; 132835863739SMike Smith 132935863739SMike Smith debug_called(3); 133035863739SMike Smith 1331ffb37f33SScott Long *fibphys = segs[0].ds_addr; 133235863739SMike Smith } 133335863739SMike Smith 1334914da7d0SScott Long /* 13350b94a66eSMike Smith * Allocate and initialise commands/FIBs for this adapter. 133635863739SMike Smith */ 13370b94a66eSMike Smith static int 13380b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 133935863739SMike Smith { 134035863739SMike Smith struct aac_command *cm; 1341ffb37f33SScott Long struct aac_fibmap *fm; 13427cb209f5SScott Long uint64_t fibphys; 1343ffb37f33SScott Long int i, error; 134435863739SMike Smith 1345a6d35632SScott Long debug_called(2); 134635863739SMike Smith 13477cb209f5SScott Long if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1348ffb37f33SScott Long return (ENOMEM); 1349ffb37f33SScott Long 13508480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1351a6d35632SScott Long if (fm == NULL) 1352a6d35632SScott Long return (ENOMEM); 1353ffb37f33SScott Long 13540b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1355ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1356ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 135770545d1aSScott Long device_printf(sc->aac_dev, 135870545d1aSScott Long "Not enough contiguous memory available.\n"); 13598480cc63SScott Long free(fm, M_AACBUF); 13600b94a66eSMike Smith return (ENOMEM); 136135863739SMike Smith } 1362128aa5a0SScott Long 1363cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1364cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 13657cb209f5SScott Long sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1366ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1367128aa5a0SScott Long 13680b94a66eSMike Smith /* initialise constant fields in the command structure */ 1369bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 13707cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 13717cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 13728480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1373ffb37f33SScott Long fm->aac_commands = cm; 137435863739SMike Smith cm->cm_sc = sc; 13757cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 13767cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 13777cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1378cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 137935863739SMike Smith 1380ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 1381ffb37f33SScott Long &cm->cm_datamap)) == 0) 138235863739SMike Smith aac_release_command(cm); 1383ffb37f33SScott Long else 13848480cc63SScott Long break; 13858480cc63SScott Long sc->total_fibs++; 138635863739SMike Smith } 1387ffb37f33SScott Long 13888480cc63SScott Long if (i > 0) { 1389ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1390a6d35632SScott Long debug(1, "total_fibs= %d\n", sc->total_fibs); 1391bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 13920b94a66eSMike Smith return (0); 139335863739SMike Smith } 139435863739SMike Smith 1395bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 13968480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 13978480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 13988480cc63SScott Long free(fm, M_AACBUF); 13998480cc63SScott Long return (ENOMEM); 14008480cc63SScott Long } 14018480cc63SScott Long 1402914da7d0SScott Long /* 14030b94a66eSMike Smith * Free FIBs owned by this adapter. 140435863739SMike Smith */ 140535863739SMike Smith static void 14068480cc63SScott Long aac_free_commands(struct aac_softc *sc) 140735863739SMike Smith { 14088480cc63SScott Long struct aac_fibmap *fm; 1409ffb37f33SScott Long struct aac_command *cm; 141035863739SMike Smith int i; 141135863739SMike Smith 141235863739SMike Smith debug_called(1); 141335863739SMike Smith 14148480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 14158480cc63SScott Long 14168480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 14178480cc63SScott Long /* 14188480cc63SScott Long * We check against total_fibs to handle partially 14198480cc63SScott Long * allocated blocks. 14208480cc63SScott Long */ 14217cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1422ffb37f33SScott Long cm = fm->aac_commands + i; 1423ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1424ffb37f33SScott Long } 1425ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1426ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 14278480cc63SScott Long free(fm, M_AACBUF); 14288480cc63SScott Long } 142935863739SMike Smith } 143035863739SMike Smith 1431914da7d0SScott Long /* 143235863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 143335863739SMike Smith */ 143435863739SMike Smith static void 143535863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 143635863739SMike Smith { 1437cd481291SScott Long struct aac_softc *sc; 1438914da7d0SScott Long struct aac_command *cm; 1439914da7d0SScott Long struct aac_fib *fib; 144035863739SMike Smith int i; 144135863739SMike Smith 144235863739SMike Smith debug_called(3); 144335863739SMike Smith 1444914da7d0SScott Long cm = (struct aac_command *)arg; 1445cd481291SScott Long sc = cm->cm_sc; 1446914da7d0SScott Long fib = cm->cm_fib; 1447914da7d0SScott Long 144835863739SMike Smith /* copy into the FIB */ 1449b85f5808SScott Long if (cm->cm_sgtable != NULL) { 14507cb209f5SScott Long if (fib->Header.Command == RawIo) { 14517cb209f5SScott Long struct aac_sg_tableraw *sg; 14527cb209f5SScott Long sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 14537cb209f5SScott Long sg->SgCount = nseg; 14547cb209f5SScott Long for (i = 0; i < nseg; i++) { 14557cb209f5SScott Long sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 14567cb209f5SScott Long sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 14577cb209f5SScott Long sg->SgEntryRaw[i].Next = 0; 14587cb209f5SScott Long sg->SgEntryRaw[i].Prev = 0; 14597cb209f5SScott Long sg->SgEntryRaw[i].Flags = 0; 14607cb209f5SScott Long } 14617cb209f5SScott Long /* update the FIB size for the s/g count */ 14627cb209f5SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 14637cb209f5SScott Long } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1464b85f5808SScott Long struct aac_sg_table *sg; 1465b85f5808SScott Long sg = cm->cm_sgtable; 146635863739SMike Smith sg->SgCount = nseg; 146735863739SMike Smith for (i = 0; i < nseg; i++) { 146835863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 146935863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 147035863739SMike Smith } 147135863739SMike Smith /* update the FIB size for the s/g count */ 147235863739SMike Smith fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1473b85f5808SScott Long } else { 1474b85f5808SScott Long struct aac_sg_table64 *sg; 1475b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1476b85f5808SScott Long sg->SgCount = nseg; 1477b85f5808SScott Long for (i = 0; i < nseg; i++) { 1478b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1479b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 148035863739SMike Smith } 1481b85f5808SScott Long /* update the FIB size for the s/g count */ 1482b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1483b85f5808SScott Long } 1484b85f5808SScott Long } 148535863739SMike Smith 1486cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1487cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 14887cb209f5SScott Long * the SenderFibAddress over to make room for the fast response bit 14897cb209f5SScott Long * and for the AIF bit 149035863739SMike Smith */ 14917cb209f5SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 14927cb209f5SScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 149335863739SMike Smith 1494cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1495cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 149635863739SMike Smith 149735863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1498c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1499c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 150035863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1501c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1502c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 150335863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1504cd481291SScott Long 15057cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 15067cb209f5SScott Long int count = 10000000L; 15077cb209f5SScott Long while (AAC_SEND_COMMAND(sc, cm) != 0) { 15087cb209f5SScott Long if (--count == 0) { 15097cb209f5SScott Long aac_unmap_command(cm); 15107cb209f5SScott Long sc->flags |= AAC_QUEUE_FRZN; 15117cb209f5SScott Long aac_requeue_ready(cm); 15127cb209f5SScott Long } 15137cb209f5SScott Long DELAY(5); /* wait 5 usec. */ 15147cb209f5SScott Long } 15157cb209f5SScott Long } else { 1516397fa34fSScott Long /* Put the FIB on the outbound queue */ 15174102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 15184102d44bSScott Long aac_unmap_command(cm); 1519397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1520cd481291SScott Long aac_requeue_ready(cm); 15214102d44bSScott Long } 15227cb209f5SScott Long } 1523cd481291SScott Long 1524cd481291SScott Long return; 152535863739SMike Smith } 152635863739SMike Smith 1527914da7d0SScott Long /* 152835863739SMike Smith * Unmap a command from controller-visible space. 152935863739SMike Smith */ 153035863739SMike Smith static void 153135863739SMike Smith aac_unmap_command(struct aac_command *cm) 153235863739SMike Smith { 1533914da7d0SScott Long struct aac_softc *sc; 153435863739SMike Smith 153535863739SMike Smith debug_called(2); 153635863739SMike Smith 1537914da7d0SScott Long sc = cm->cm_sc; 1538914da7d0SScott Long 153935863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 154035863739SMike Smith return; 154135863739SMike Smith 154235863739SMike Smith if (cm->cm_datalen != 0) { 154335863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1544c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1545c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 154635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1547c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1548c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 154935863739SMike Smith 155035863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 155135863739SMike Smith } 155235863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 155335863739SMike Smith } 155435863739SMike Smith 1555914da7d0SScott Long /* 1556914da7d0SScott Long * Hardware Interface 1557914da7d0SScott Long */ 155835863739SMike Smith 1559914da7d0SScott Long /* 156035863739SMike Smith * Initialise the adapter. 156135863739SMike Smith */ 156235863739SMike Smith static void 156335863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 156435863739SMike Smith { 1565914da7d0SScott Long struct aac_softc *sc; 156635863739SMike Smith 156735863739SMike Smith debug_called(1); 156835863739SMike Smith 1569914da7d0SScott Long sc = (struct aac_softc *)arg; 1570914da7d0SScott Long 157135863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 157235863739SMike Smith } 157335863739SMike Smith 1574a6d35632SScott Long static int 1575a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1576a6d35632SScott Long { 15777cb209f5SScott Long u_int32_t major, minor, options, atu_size; 1578a6d35632SScott Long 1579a6d35632SScott Long debug_called(1); 1580a6d35632SScott Long 1581fe94b852SScott Long /* 1582fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1583fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1584fe94b852SScott Long */ 1585a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1586fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1587fe94b852SScott Long NULL)) { 1588fe94b852SScott Long device_printf(sc->aac_dev, 1589fe94b852SScott Long "Error reading firmware version\n"); 1590fe94b852SScott Long return (EIO); 1591fe94b852SScott Long } 1592fe94b852SScott Long 1593fe94b852SScott Long /* These numbers are stored as ASCII! */ 1594a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1595a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1596fe94b852SScott Long if (major == 1) { 1597fe94b852SScott Long device_printf(sc->aac_dev, 1598fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1599fe94b852SScott Long major, minor); 1600fe94b852SScott Long return (EINVAL); 1601fe94b852SScott Long } 1602fe94b852SScott Long } 1603fe94b852SScott Long 1604a6d35632SScott Long /* 1605a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1606a6d35632SScott Long * work-arounds to enable. 1607a6d35632SScott Long */ 1608a6d35632SScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) { 1609a6d35632SScott Long device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 1610a6d35632SScott Long return (EIO); 1611a6d35632SScott Long } 1612a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 16137cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1614a6d35632SScott Long sc->supported_options = options; 1615a6d35632SScott Long 1616a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1617a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1618a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1619a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1620a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1621cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1622cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1623a6d35632SScott Long device_printf(sc->aac_dev, "Enabling 64-bit address support\n"); 1624a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1625a6d35632SScott Long } 16267cb209f5SScott Long if ((options & AAC_SUPPORTED_NEW_COMM) && sc->aac_if.aif_send_command) 16277cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 16287cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 16297cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1630a6d35632SScott Long 1631a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 16327cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 16337cb209f5SScott Long 16347cb209f5SScott Long /* Remap mem. resource, if required */ 16357cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 16367cb209f5SScott Long atu_size > rman_get_size(sc->aac_regs_resource)) { 16377cb209f5SScott Long bus_release_resource( 16387cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 16397cb209f5SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 16407cb209f5SScott Long sc->aac_regs_resource = bus_alloc_resource( 16417cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid, 16427cb209f5SScott Long 0ul, ~0ul, atu_size, RF_ACTIVE); 16437cb209f5SScott Long if (sc->aac_regs_resource == NULL) { 16447cb209f5SScott Long sc->aac_regs_resource = bus_alloc_resource_any( 16457cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 16467cb209f5SScott Long &sc->aac_regs_rid, RF_ACTIVE); 16477cb209f5SScott Long if (sc->aac_regs_resource == NULL) { 16487cb209f5SScott Long device_printf(sc->aac_dev, 16497cb209f5SScott Long "couldn't allocate register window\n"); 16507cb209f5SScott Long return (ENXIO); 16517cb209f5SScott Long } 16527cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 16537cb209f5SScott Long } 16547cb209f5SScott Long sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); 16557cb209f5SScott Long sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); 16567cb209f5SScott Long } 16577cb209f5SScott Long 16587cb209f5SScott Long /* Read preferred settings */ 16597cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 16607cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 16617cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 16627cb209f5SScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite64) 16637cb209f5SScott Long + sizeof(struct aac_sg_table64)) / sizeof(struct aac_sg_table64); 1664a6d35632SScott Long else 16657cb209f5SScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite) 16667cb209f5SScott Long + sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_table); 16677cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 16687cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 16697cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 16707cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 16717cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 16727cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 16737cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 16747cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 16757cb209f5SScott Long } 16767cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 16777cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 16787cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1679a6d35632SScott Long 1680fe94b852SScott Long return (0); 1681fe94b852SScott Long } 1682fe94b852SScott Long 168335863739SMike Smith static int 168435863739SMike Smith aac_init(struct aac_softc *sc) 168535863739SMike Smith { 168635863739SMike Smith struct aac_adapter_init *ip; 168735863739SMike Smith time_t then; 1688b88ffdc8SScott Long u_int32_t code, qoffset; 1689a6d35632SScott Long int error; 169035863739SMike Smith 169135863739SMike Smith debug_called(1); 169235863739SMike Smith 169335863739SMike Smith /* 169435863739SMike Smith * First wait for the adapter to come ready. 169535863739SMike Smith */ 16962b3b0f17SScott Long then = time_uptime; 169735863739SMike Smith do { 169835863739SMike Smith code = AAC_GET_FWSTATUS(sc); 169935863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 170035863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 170135863739SMike Smith return(ENXIO); 170235863739SMike Smith } 170335863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1704914da7d0SScott Long device_printf(sc->aac_dev, 1705914da7d0SScott Long "FATAL: controller kernel panic\n"); 170635863739SMike Smith return(ENXIO); 170735863739SMike Smith } 17082b3b0f17SScott Long if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1709914da7d0SScott Long device_printf(sc->aac_dev, 1710914da7d0SScott Long "FATAL: controller not coming ready, " 1711c6eafcf2SScott Long "status %x\n", code); 171235863739SMike Smith return(ENXIO); 171335863739SMike Smith } 171435863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 171535863739SMike Smith 1716a6d35632SScott Long error = ENOMEM; 1717a6d35632SScott Long /* 1718a6d35632SScott Long * Create DMA tag for mapping buffers into controller-addressable space. 1719a6d35632SScott Long */ 1720a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1721a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1722a6d35632SScott Long (sc->flags & AAC_FLAGS_SG_64BIT) ? 1723a6d35632SScott Long BUS_SPACE_MAXADDR : 1724a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1725a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1726a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1727a6d35632SScott Long MAXBSIZE, /* maxsize */ 17287cb209f5SScott Long sc->aac_sg_tablesize, /* nsegments */ 1729a6d35632SScott Long MAXBSIZE, /* maxsegsize */ 1730a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1731f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 1732f6b1c44dSScott Long &sc->aac_io_lock, /* lockfuncarg */ 1733a6d35632SScott Long &sc->aac_buffer_dmat)) { 1734a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1735a6d35632SScott Long goto out; 1736a6d35632SScott Long } 1737a6d35632SScott Long 1738a6d35632SScott Long /* 1739a6d35632SScott Long * Create DMA tag for mapping FIBs into controller-addressable space.. 1740a6d35632SScott Long */ 1741a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1742a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1743a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1744a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1745a6d35632SScott Long 0x7fffffff, /* lowaddr */ 1746a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1747a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 17487cb209f5SScott Long sc->aac_max_fibs_alloc * 17497cb209f5SScott Long sc->aac_max_fib_size, /* maxsize */ 1750a6d35632SScott Long 1, /* nsegments */ 17517cb209f5SScott Long sc->aac_max_fibs_alloc * 17527cb209f5SScott Long sc->aac_max_fib_size, /* maxsegsize */ 17531248408dSScott Long 0, /* flags */ 1754f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 1755a6d35632SScott Long &sc->aac_fib_dmat)) { 1756a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1757a6d35632SScott Long goto out; 1758a6d35632SScott Long } 1759a6d35632SScott Long 176035863739SMike Smith /* 176135863739SMike Smith * Create DMA tag for the common structure and allocate it. 176235863739SMike Smith */ 176335863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1764c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1765a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1766a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1767a6d35632SScott Long 0x7fffffff, /* lowaddr */ 176835863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 176935863739SMike Smith NULL, NULL, /* filter, filterarg */ 1770ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1771914da7d0SScott Long 1, /* nsegments */ 177235863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 17731248408dSScott Long 0, /* flags */ 1774f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 177535863739SMike Smith &sc->aac_common_dmat)) { 1776914da7d0SScott Long device_printf(sc->aac_dev, 1777914da7d0SScott Long "can't allocate common structure DMA tag\n"); 1778a6d35632SScott Long goto out; 177935863739SMike Smith } 1780c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1781c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 178235863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 1783a6d35632SScott Long goto out; 178435863739SMike Smith } 1785ffb37f33SScott Long 1786ffb37f33SScott Long /* 1787ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1788ffb37f33SScott Long * below address 8192 in physical memory. 1789ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1790ffb37f33SScott Long * of ignored? 1791ffb37f33SScott Long */ 1792cd481291SScott Long (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1793ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1794ffb37f33SScott Long aac_common_map, sc, 0); 1795ffb37f33SScott Long 1796ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1797eec256deSAlexander Kabaev sc->aac_common = (struct aac_common *) 1798eec256deSAlexander Kabaev ((uint8_t *)sc->aac_common + 8192); 1799ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1800ffb37f33SScott Long } 180135863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 180235863739SMike Smith 1803ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1804ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 18057cb209f5SScott Long sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 18068480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 18078480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1808ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1809ffb37f33SScott Long break; 1810ffb37f33SScott Long } 1811ffb37f33SScott Long if (sc->total_fibs == 0) 1812a6d35632SScott Long goto out; 1813ffb37f33SScott Long 181435863739SMike Smith /* 1815914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1816914da7d0SScott Long * physical location of various important shared data structures. 181735863739SMike Smith */ 181835863739SMike Smith ip = &sc->aac_common->ac_init; 181935863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18207cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18217cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18227cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18237cb209f5SScott Long } 1824f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 182535863739SMike Smith 1826c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1827c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1828149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 182935863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 183035863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 183135863739SMike Smith 1832c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1833c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 183435863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 183535863739SMike Smith 18364b00f859SScott Long /* 18374b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18384b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18394b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18404b00f859SScott Long * Round up since the granularity is so high. 18414b00f859SScott Long */ 1842f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18434b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 18444b00f859SScott Long ip->HostPhysMemPages = 18454b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1846204c0befSScott Long } 18472b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 184835863739SMike Smith 18497cb209f5SScott Long ip->InitFlags = 0; 18507cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 18517cb209f5SScott Long ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 18527cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 18537cb209f5SScott Long } 18547cb209f5SScott Long 18557cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 18567cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 18577cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 18587cb209f5SScott Long 185935863739SMike Smith /* 1860c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1861c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1862c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 186335863739SMike Smith * 186435863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1865914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1866914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1867914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1868914da7d0SScott Long * does. 186935863739SMike Smith * 1870914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1871914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1872914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1873914da7d0SScott Long * virtue of a table. 187435863739SMike Smith */ 1875b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 18760bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 18770bcbebd6SScott Long sc->aac_queues = 18780bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1879b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 188035863739SMike Smith 1881c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1882c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1883c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1884c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1885c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1886c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1887c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1888c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1889c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1890c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1891c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1892c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1893c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1894c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1895c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1896c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1897c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1898c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1899c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1900c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1901c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1902c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1903c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1904c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1905c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1906c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1907c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1908c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1909c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1910c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1911c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1912c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1913c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1914c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1915c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1916c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1917c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1918c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1919c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1920c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1921c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1922c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1923c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1924c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1925c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1926c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1927c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1928c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 192935863739SMike Smith 193035863739SMike Smith /* 193135863739SMike Smith * Do controller-type-specific initialisation 193235863739SMike Smith */ 193335863739SMike Smith switch (sc->aac_hwif) { 193435863739SMike Smith case AAC_HWIF_I960RX: 193535863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 193635863739SMike Smith break; 19374afedc31SScott Long case AAC_HWIF_RKT: 19384afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); 19394afedc31SScott Long break; 19404afedc31SScott Long default: 19414afedc31SScott Long break; 194235863739SMike Smith } 194335863739SMike Smith 194435863739SMike Smith /* 194535863739SMike Smith * Give the init structure to the controller. 194635863739SMike Smith */ 194735863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1948914da7d0SScott Long sc->aac_common_busaddr + 1949914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1950914da7d0SScott Long NULL)) { 1951914da7d0SScott Long device_printf(sc->aac_dev, 1952914da7d0SScott Long "error establishing init structure\n"); 1953a6d35632SScott Long error = EIO; 1954a6d35632SScott Long goto out; 195535863739SMike Smith } 195635863739SMike Smith 1957a6d35632SScott Long error = 0; 1958a6d35632SScott Long out: 1959a6d35632SScott Long return(error); 196035863739SMike Smith } 196135863739SMike Smith 1962914da7d0SScott Long /* 196335863739SMike Smith * Send a synchronous command to the controller and wait for a result. 19647cb209f5SScott Long * Indicate if the controller completed the command with an error status. 196535863739SMike Smith */ 196635863739SMike Smith static int 196735863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 196835863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 196935863739SMike Smith u_int32_t *sp) 197035863739SMike Smith { 197135863739SMike Smith time_t then; 197235863739SMike Smith u_int32_t status; 197335863739SMike Smith 197435863739SMike Smith debug_called(3); 197535863739SMike Smith 197635863739SMike Smith /* populate the mailbox */ 197735863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 197835863739SMike Smith 197935863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 198035863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 198135863739SMike Smith 198235863739SMike Smith /* then set it to signal the adapter */ 198335863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 198435863739SMike Smith 198535863739SMike Smith /* spin waiting for the command to complete */ 19862b3b0f17SScott Long then = time_uptime; 198735863739SMike Smith do { 19882b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 1989a6d35632SScott Long debug(1, "timed out"); 199035863739SMike Smith return(EIO); 199135863739SMike Smith } 199235863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 199335863739SMike Smith 199435863739SMike Smith /* clear the completion flag */ 199535863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 199635863739SMike Smith 199735863739SMike Smith /* get the command status */ 1998a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 199935863739SMike Smith if (sp != NULL) 200035863739SMike Smith *sp = status; 20017cb209f5SScott Long 20027cb209f5SScott Long if (status != 0x01) 20037cb209f5SScott Long return (-1); 20040b94a66eSMike Smith return(0); 200535863739SMike Smith } 200635863739SMike Smith 2007cbfd045bSScott Long int 200835863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2009cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 201035863739SMike Smith { 201135863739SMike Smith debug_called(3); 20127cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 201335863739SMike Smith 201435863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 201535863739SMike Smith return(EINVAL); 201635863739SMike Smith 201735863739SMike Smith /* 201835863739SMike Smith * Set up the sync FIB 201935863739SMike Smith */ 2020914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2021914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2022c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 202335863739SMike Smith fib->Header.XferState |= xferstate; 202435863739SMike Smith fib->Header.Command = command; 202535863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 202635863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 202735863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2028b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2029c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2030914da7d0SScott Long offsetof(struct aac_common, 2031914da7d0SScott Long ac_sync_fib); 203235863739SMike Smith 203335863739SMike Smith /* 203435863739SMike Smith * Give the FIB to the controller, wait for a response. 203535863739SMike Smith */ 2036914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2037914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 203835863739SMike Smith debug(2, "IO error"); 203935863739SMike Smith return(EIO); 204035863739SMike Smith } 204135863739SMike Smith 204235863739SMike Smith return (0); 204335863739SMike Smith } 204435863739SMike Smith 2045914da7d0SScott Long /* 204635863739SMike Smith * Adapter-space FIB queue manipulation 204735863739SMike Smith * 204835863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 204935863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 205035863739SMike Smith */ 205135863739SMike Smith static struct { 205235863739SMike Smith int size; 205335863739SMike Smith int notify; 205435863739SMike Smith } aac_qinfo[] = { 205535863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 205635863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 205735863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 205835863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 205935863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 206035863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 206135863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 206235863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 206335863739SMike Smith }; 206435863739SMike Smith 206535863739SMike Smith /* 2066c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2067c6eafcf2SScott Long * EBUSY if the queue is full. 206835863739SMike Smith * 20690b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2070914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2071914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2072c6eafcf2SScott Long * separate queue/notify interface). 207335863739SMike Smith */ 207435863739SMike Smith static int 2075f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 207635863739SMike Smith { 207735863739SMike Smith u_int32_t pi, ci; 20789e2e96d8SScott Long int error; 2079f6c4dd3fSScott Long u_int32_t fib_size; 2080f6c4dd3fSScott Long u_int32_t fib_addr; 2081f6c4dd3fSScott Long 208236e0bf6eSScott Long debug_called(3); 208336e0bf6eSScott Long 2084f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2085f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 208635863739SMike Smith 208735863739SMike Smith /* get the producer/consumer indices */ 208835863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 208935863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 209035863739SMike Smith 209135863739SMike Smith /* wrap the queue? */ 209235863739SMike Smith if (pi >= aac_qinfo[queue].size) 209335863739SMike Smith pi = 0; 209435863739SMike Smith 209535863739SMike Smith /* check for queue full */ 209635863739SMike Smith if ((pi + 1) == ci) { 209735863739SMike Smith error = EBUSY; 209835863739SMike Smith goto out; 209935863739SMike Smith } 210035863739SMike Smith 2101614c22b2SScott Long /* 2102614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2103614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2104614c22b2SScott Long */ 2105614c22b2SScott Long aac_enqueue_busy(cm); 2106614c22b2SScott Long 210735863739SMike Smith /* populate queue entry */ 210835863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 210935863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 211035863739SMike Smith 211135863739SMike Smith /* update producer index */ 211235863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 211335863739SMike Smith 211435863739SMike Smith /* notify the adapter if we know how */ 211535863739SMike Smith if (aac_qinfo[queue].notify != 0) 211635863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 211735863739SMike Smith 211835863739SMike Smith error = 0; 211935863739SMike Smith 212035863739SMike Smith out: 212135863739SMike Smith return(error); 212235863739SMike Smith } 212335863739SMike Smith 212435863739SMike Smith /* 212536e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 212636e0bf6eSScott Long * success or ENOENT if the queue is empty. 212735863739SMike Smith */ 212835863739SMike Smith static int 2129c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2130c6eafcf2SScott Long struct aac_fib **fib_addr) 213135863739SMike Smith { 213235863739SMike Smith u_int32_t pi, ci; 2133149af931SScott Long u_int32_t fib_index; 21349e2e96d8SScott Long int error; 2135f6c4dd3fSScott Long int notify; 213635863739SMike Smith 213735863739SMike Smith debug_called(3); 213835863739SMike Smith 213935863739SMike Smith /* get the producer/consumer indices */ 214035863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 214135863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 214235863739SMike Smith 214335863739SMike Smith /* check for queue empty */ 214435863739SMike Smith if (ci == pi) { 214535863739SMike Smith error = ENOENT; 214635863739SMike Smith goto out; 214735863739SMike Smith } 214835863739SMike Smith 21497753acd2SScott Long /* wrap the pi so the following test works */ 21507753acd2SScott Long if (pi >= aac_qinfo[queue].size) 21517753acd2SScott Long pi = 0; 21527753acd2SScott Long 2153f6c4dd3fSScott Long notify = 0; 2154f6c4dd3fSScott Long if (ci == pi + 1) 2155f6c4dd3fSScott Long notify++; 2156f6c4dd3fSScott Long 215735863739SMike Smith /* wrap the queue? */ 215835863739SMike Smith if (ci >= aac_qinfo[queue].size) 215935863739SMike Smith ci = 0; 216035863739SMike Smith 216135863739SMike Smith /* fetch the entry */ 216235863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2163149af931SScott Long 2164149af931SScott Long switch (queue) { 2165149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2166149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2167149af931SScott Long /* 2168149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2169149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2170149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2171149af931SScott Long * Therefore, we have to convert it to an index. 2172149af931SScott Long */ 2173149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2174149af931SScott Long sizeof(struct aac_fib); 2175149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2176149af931SScott Long break; 2177149af931SScott Long 2178149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2179149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2180149af931SScott Long { 2181149af931SScott Long struct aac_command *cm; 2182149af931SScott Long 2183149af931SScott Long /* 2184149af931SScott Long * As above, an index is used instead of an actual address. 2185149af931SScott Long * Gotta shift the index to account for the fast response 2186149af931SScott Long * bit. No other correction is needed since this value was 2187149af931SScott Long * originally provided by the driver via the SenderFibAddress 2188149af931SScott Long * field. 2189149af931SScott Long */ 2190149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 21917cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2192149af931SScott Long *fib_addr = cm->cm_fib; 219335863739SMike Smith 2194f30ac74cSScott Long /* 2195f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2196149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2197f30ac74cSScott Long */ 2198149af931SScott Long if (fib_index & 0x01) { 2199f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2200f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2201f30ac74cSScott Long } 2202149af931SScott Long break; 2203149af931SScott Long } 2204149af931SScott Long default: 2205149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2206149af931SScott Long break; 2207149af931SScott Long } 2208149af931SScott Long 220935863739SMike Smith /* update consumer index */ 221035863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 221135863739SMike Smith 221235863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2213f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 221435863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 221535863739SMike Smith error = 0; 221635863739SMike Smith 221735863739SMike Smith out: 221835863739SMike Smith return(error); 221935863739SMike Smith } 222035863739SMike Smith 2221914da7d0SScott Long /* 222236e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 222336e0bf6eSScott Long */ 222436e0bf6eSScott Long static int 222536e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 222636e0bf6eSScott Long { 222736e0bf6eSScott Long u_int32_t pi, ci; 22289e2e96d8SScott Long int error; 222936e0bf6eSScott Long u_int32_t fib_size; 223036e0bf6eSScott Long u_int32_t fib_addr; 223136e0bf6eSScott Long 223236e0bf6eSScott Long debug_called(1); 223336e0bf6eSScott Long 223436e0bf6eSScott Long /* Tell the adapter where the FIB is */ 223536e0bf6eSScott Long fib_size = fib->Header.Size; 223636e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 223736e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 223836e0bf6eSScott Long 223936e0bf6eSScott Long /* get the producer/consumer indices */ 224036e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 224136e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 224236e0bf6eSScott Long 224336e0bf6eSScott Long /* wrap the queue? */ 224436e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 224536e0bf6eSScott Long pi = 0; 224636e0bf6eSScott Long 224736e0bf6eSScott Long /* check for queue full */ 224836e0bf6eSScott Long if ((pi + 1) == ci) { 224936e0bf6eSScott Long error = EBUSY; 225036e0bf6eSScott Long goto out; 225136e0bf6eSScott Long } 225236e0bf6eSScott Long 225336e0bf6eSScott Long /* populate queue entry */ 225436e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 225536e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 225636e0bf6eSScott Long 225736e0bf6eSScott Long /* update producer index */ 225836e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 225936e0bf6eSScott Long 226036e0bf6eSScott Long /* notify the adapter if we know how */ 226136e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 226236e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 226336e0bf6eSScott Long 226436e0bf6eSScott Long error = 0; 226536e0bf6eSScott Long 226636e0bf6eSScott Long out: 226736e0bf6eSScott Long return(error); 226836e0bf6eSScott Long } 226936e0bf6eSScott Long 2270914da7d0SScott Long /* 22710b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 22720b94a66eSMike Smith * and complain about them. 22730b94a66eSMike Smith */ 22740b94a66eSMike Smith static void 22750b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 22760b94a66eSMike Smith { 22770b94a66eSMike Smith struct aac_command *cm; 22780b94a66eSMike Smith time_t deadline; 227915c37be0SScott Long int timedout, code; 22800b94a66eSMike Smith 2281f6c4dd3fSScott Long /* 228270545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2283914da7d0SScott Long * only. 2284914da7d0SScott Long */ 228515c37be0SScott Long timedout = 0; 22862b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 22870b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2288f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2289f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 22900b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2291914da7d0SScott Long device_printf(sc->aac_dev, 2292914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 22932b3b0f17SScott Long cm, (int)(time_uptime-cm->cm_timestamp)); 22940b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 229515c37be0SScott Long timedout++; 22960b94a66eSMike Smith } 22970b94a66eSMike Smith } 22980b94a66eSMike Smith 229915c37be0SScott Long if (timedout) { 230015c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 230115c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 230215c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 230315c37be0SScott Long "longer running! code= 0x%x\n", code); 230415c37be0SScott Long } 230515c37be0SScott Long } 23060b94a66eSMike Smith return; 23070b94a66eSMike Smith } 23080b94a66eSMike Smith 2309914da7d0SScott Long /* 2310914da7d0SScott Long * Interface Function Vectors 2311914da7d0SScott Long */ 231235863739SMike Smith 2313914da7d0SScott Long /* 231435863739SMike Smith * Read the current firmware status word. 231535863739SMike Smith */ 231635863739SMike Smith static int 231735863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 231835863739SMike Smith { 231935863739SMike Smith debug_called(3); 232035863739SMike Smith 232135863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 232235863739SMike Smith } 232335863739SMike Smith 232435863739SMike Smith static int 232535863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 232635863739SMike Smith { 232735863739SMike Smith debug_called(3); 232835863739SMike Smith 232935863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 233035863739SMike Smith } 233135863739SMike Smith 2332b3457b51SScott Long static int 2333b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2334b3457b51SScott Long { 2335b3457b51SScott Long int val; 2336b3457b51SScott Long 2337b3457b51SScott Long debug_called(3); 2338b3457b51SScott Long 2339b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2340b3457b51SScott Long return (val); 2341b3457b51SScott Long } 2342b3457b51SScott Long 23434afedc31SScott Long static int 23444afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 23454afedc31SScott Long { 23464afedc31SScott Long debug_called(3); 23474afedc31SScott Long 23484afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); 23494afedc31SScott Long } 23504afedc31SScott Long 2351914da7d0SScott Long /* 235235863739SMike Smith * Notify the controller of a change in a given queue 235335863739SMike Smith */ 235435863739SMike Smith 235535863739SMike Smith static void 235635863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 235735863739SMike Smith { 235835863739SMike Smith debug_called(3); 235935863739SMike Smith 236035863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 236135863739SMike Smith } 236235863739SMike Smith 236335863739SMike Smith static void 236435863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 236535863739SMike Smith { 236635863739SMike Smith debug_called(3); 236735863739SMike Smith 236835863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 236935863739SMike Smith } 237035863739SMike Smith 2371b3457b51SScott Long static void 2372b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2373b3457b51SScott Long { 2374b3457b51SScott Long debug_called(3); 2375b3457b51SScott Long 2376b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2377b3457b51SScott Long AAC_FA_HACK(sc); 2378b3457b51SScott Long } 2379b3457b51SScott Long 23804afedc31SScott Long static void 23814afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 23824afedc31SScott Long { 23834afedc31SScott Long debug_called(3); 23844afedc31SScott Long 23854afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); 23864afedc31SScott Long } 23874afedc31SScott Long 2388914da7d0SScott Long /* 238935863739SMike Smith * Get the interrupt reason bits 239035863739SMike Smith */ 239135863739SMike Smith static int 239235863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 239335863739SMike Smith { 239435863739SMike Smith debug_called(3); 239535863739SMike Smith 239635863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 239735863739SMike Smith } 239835863739SMike Smith 239935863739SMike Smith static int 240035863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 240135863739SMike Smith { 240235863739SMike Smith debug_called(3); 240335863739SMike Smith 240435863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 240535863739SMike Smith } 240635863739SMike Smith 2407b3457b51SScott Long static int 2408b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2409b3457b51SScott Long { 2410b3457b51SScott Long int val; 2411b3457b51SScott Long 2412b3457b51SScott Long debug_called(3); 2413b3457b51SScott Long 2414b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2415b3457b51SScott Long return (val); 2416b3457b51SScott Long } 2417b3457b51SScott Long 24184afedc31SScott Long static int 24194afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 24204afedc31SScott Long { 24214afedc31SScott Long debug_called(3); 24224afedc31SScott Long 24234afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_ODBR)); 24244afedc31SScott Long } 24254afedc31SScott Long 2426914da7d0SScott Long /* 242735863739SMike Smith * Clear some interrupt reason bits 242835863739SMike Smith */ 242935863739SMike Smith static void 243035863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 243135863739SMike Smith { 243235863739SMike Smith debug_called(3); 243335863739SMike Smith 243435863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 243535863739SMike Smith } 243635863739SMike Smith 243735863739SMike Smith static void 243835863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 243935863739SMike Smith { 244035863739SMike Smith debug_called(3); 244135863739SMike Smith 244235863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 244335863739SMike Smith } 244435863739SMike Smith 2445b3457b51SScott Long static void 2446b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2447b3457b51SScott Long { 2448b3457b51SScott Long debug_called(3); 2449b3457b51SScott Long 2450b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2451b3457b51SScott Long AAC_FA_HACK(sc); 2452b3457b51SScott Long } 2453b3457b51SScott Long 24544afedc31SScott Long static void 24554afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 24564afedc31SScott Long { 24574afedc31SScott Long debug_called(3); 24584afedc31SScott Long 24594afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, mask); 24604afedc31SScott Long } 24614afedc31SScott Long 2462914da7d0SScott Long /* 246335863739SMike Smith * Populate the mailbox and set the command word 246435863739SMike Smith */ 246535863739SMike Smith static void 246635863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 246735863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 246835863739SMike Smith { 246935863739SMike Smith debug_called(4); 247035863739SMike Smith 247135863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 247235863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 247335863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 247435863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 247535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 247635863739SMike Smith } 247735863739SMike Smith 247835863739SMike Smith static void 247935863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 248035863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 248135863739SMike Smith { 248235863739SMike Smith debug_called(4); 248335863739SMike Smith 248435863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 248535863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 248635863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 248735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 248835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 248935863739SMike Smith } 249035863739SMike Smith 2491b3457b51SScott Long static void 2492b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2493b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2494b3457b51SScott Long { 2495b3457b51SScott Long debug_called(4); 2496b3457b51SScott Long 2497b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2498b3457b51SScott Long AAC_FA_HACK(sc); 2499b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2500b3457b51SScott Long AAC_FA_HACK(sc); 2501b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2502b3457b51SScott Long AAC_FA_HACK(sc); 2503b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2504b3457b51SScott Long AAC_FA_HACK(sc); 2505b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2506b3457b51SScott Long AAC_FA_HACK(sc); 2507b3457b51SScott Long } 2508b3457b51SScott Long 25094afedc31SScott Long static void 25104afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25114afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 25124afedc31SScott Long { 25134afedc31SScott Long debug_called(4); 25144afedc31SScott Long 25154afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); 25164afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 25174afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 25184afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 25194afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 25204afedc31SScott Long } 25214afedc31SScott Long 2522914da7d0SScott Long /* 252335863739SMike Smith * Fetch the immediate command status word 252435863739SMike Smith */ 252535863739SMike Smith static int 2526a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 252735863739SMike Smith { 252835863739SMike Smith debug_called(4); 252935863739SMike Smith 2530a6d35632SScott Long return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 253135863739SMike Smith } 253235863739SMike Smith 253335863739SMike Smith static int 2534a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 253535863739SMike Smith { 253635863739SMike Smith debug_called(4); 253735863739SMike Smith 2538a6d35632SScott Long return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 253935863739SMike Smith } 254035863739SMike Smith 2541b3457b51SScott Long static int 2542a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2543b3457b51SScott Long { 2544b3457b51SScott Long int val; 2545b3457b51SScott Long 2546b3457b51SScott Long debug_called(4); 2547b3457b51SScott Long 2548a6d35632SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2549b3457b51SScott Long return (val); 2550b3457b51SScott Long } 2551b3457b51SScott Long 25524afedc31SScott Long static int 25534afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 25544afedc31SScott Long { 25554afedc31SScott Long debug_called(4); 25564afedc31SScott Long 25574afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 25584afedc31SScott Long } 25594afedc31SScott Long 2560914da7d0SScott Long /* 256135863739SMike Smith * Set/clear interrupt masks 256235863739SMike Smith */ 256335863739SMike Smith static void 256435863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 256535863739SMike Smith { 256635863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 256735863739SMike Smith 256835863739SMike Smith if (enable) { 256935863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 257035863739SMike Smith } else { 257135863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 257235863739SMike Smith } 257335863739SMike Smith } 257435863739SMike Smith 257535863739SMike Smith static void 257635863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 257735863739SMike Smith { 257835863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 257935863739SMike Smith 258035863739SMike Smith if (enable) { 25817cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 25827cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 25837cb209f5SScott Long else 258435863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 258535863739SMike Smith } else { 258635863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 258735863739SMike Smith } 258835863739SMike Smith } 258935863739SMike Smith 2590b3457b51SScott Long static void 2591b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2592b3457b51SScott Long { 2593b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2594b3457b51SScott Long 2595b3457b51SScott Long if (enable) { 2596b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2597b3457b51SScott Long AAC_FA_HACK(sc); 2598b3457b51SScott Long } else { 2599b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2600b3457b51SScott Long AAC_FA_HACK(sc); 2601b3457b51SScott Long } 2602b3457b51SScott Long } 2603b3457b51SScott Long 26044afedc31SScott Long static void 26054afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 26064afedc31SScott Long { 26074afedc31SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 26084afedc31SScott Long 26094afedc31SScott Long if (enable) { 26107cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 26117cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 26127cb209f5SScott Long else 26134afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 26144afedc31SScott Long } else { 26154afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); 26164afedc31SScott Long } 26174afedc31SScott Long } 26184afedc31SScott Long 2619914da7d0SScott Long /* 26207cb209f5SScott Long * New comm. interface: Send command functions 26217cb209f5SScott Long */ 26227cb209f5SScott Long static int 26237cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 26247cb209f5SScott Long { 26257cb209f5SScott Long u_int32_t index, device; 26267cb209f5SScott Long 26277cb209f5SScott Long debug(2, "send command (new comm.)"); 26287cb209f5SScott Long 26297cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RX_IQUE); 26307cb209f5SScott Long if (index == 0xffffffffL) 26317cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RX_IQUE); 26327cb209f5SScott Long if (index == 0xffffffffL) 26337cb209f5SScott Long return index; 26347cb209f5SScott Long aac_enqueue_busy(cm); 26357cb209f5SScott Long device = index; 26367cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26377cb209f5SScott Long device += 4; 26387cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26397cb209f5SScott Long device += 4; 26407cb209f5SScott Long AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 26417cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_IQUE, index); 26427cb209f5SScott Long return 0; 26437cb209f5SScott Long } 26447cb209f5SScott Long 26457cb209f5SScott Long static int 26467cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 26477cb209f5SScott Long { 26487cb209f5SScott Long u_int32_t index, device; 26497cb209f5SScott Long 26507cb209f5SScott Long debug(2, "send command (new comm.)"); 26517cb209f5SScott Long 26527cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RKT_IQUE); 26537cb209f5SScott Long if (index == 0xffffffffL) 26547cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RKT_IQUE); 26557cb209f5SScott Long if (index == 0xffffffffL) 26567cb209f5SScott Long return index; 26577cb209f5SScott Long aac_enqueue_busy(cm); 26587cb209f5SScott Long device = index; 26597cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26607cb209f5SScott Long device += 4; 26617cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26627cb209f5SScott Long device += 4; 26637cb209f5SScott Long AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 26647cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_IQUE, index); 26657cb209f5SScott Long return 0; 26667cb209f5SScott Long } 26677cb209f5SScott Long 26687cb209f5SScott Long /* 26697cb209f5SScott Long * New comm. interface: get, set outbound queue index 26707cb209f5SScott Long */ 26717cb209f5SScott Long static int 26727cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 26737cb209f5SScott Long { 26747cb209f5SScott Long debug_called(3); 26757cb209f5SScott Long 26767cb209f5SScott Long return(AAC_GETREG4(sc, AAC_RX_OQUE)); 26777cb209f5SScott Long } 26787cb209f5SScott Long 26797cb209f5SScott Long static int 26807cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 26817cb209f5SScott Long { 26827cb209f5SScott Long debug_called(3); 26837cb209f5SScott Long 26847cb209f5SScott Long return(AAC_GETREG4(sc, AAC_RKT_OQUE)); 26857cb209f5SScott Long } 26867cb209f5SScott Long 26877cb209f5SScott Long static void 26887cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 26897cb209f5SScott Long { 26907cb209f5SScott Long debug_called(3); 26917cb209f5SScott Long 26927cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_OQUE, index); 26937cb209f5SScott Long } 26947cb209f5SScott Long 26957cb209f5SScott Long static void 26967cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 26977cb209f5SScott Long { 26987cb209f5SScott Long debug_called(3); 26997cb209f5SScott Long 27007cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_OQUE, index); 27017cb209f5SScott Long } 27027cb209f5SScott Long 27037cb209f5SScott Long /* 2704914da7d0SScott Long * Debugging and Diagnostics 2705914da7d0SScott Long */ 270635863739SMike Smith 2707914da7d0SScott Long /* 270835863739SMike Smith * Print some information about the controller. 270935863739SMike Smith */ 271035863739SMike Smith static void 271135863739SMike Smith aac_describe_controller(struct aac_softc *sc) 271235863739SMike Smith { 2713cbfd045bSScott Long struct aac_fib *fib; 271435863739SMike Smith struct aac_adapter_info *info; 271535863739SMike Smith 271635863739SMike Smith debug_called(2); 271735863739SMike Smith 271881b3da08SScott Long mtx_lock(&sc->aac_io_lock); 271903b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2720cbfd045bSScott Long 2721cbfd045bSScott Long fib->data[0] = 0; 2722cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 272335863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2724fe3cb0e1SScott Long aac_release_sync_fib(sc); 272581b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 272635863739SMike Smith return; 272735863739SMike Smith } 272835863739SMike Smith 2729bd971c49SScott Long /* save the kernel revision structure for later use */ 2730bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2731bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2732bd971c49SScott Long 27337cb209f5SScott Long device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n", 27347cb209f5SScott Long AAC_DRIVER_VERSION >> 24, 27357cb209f5SScott Long (AAC_DRIVER_VERSION >> 16) & 0xFF, 27367cb209f5SScott Long AAC_DRIVER_VERSION & 0xFF, 27377cb209f5SScott Long AAC_DRIVER_BUILD); 27387cb209f5SScott Long 2739bd971c49SScott Long if (bootverbose) { 2740b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2741b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2742c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2743b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2744b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2745b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2746914da7d0SScott Long aac_describe_code(aac_battery_platform, 2747914da7d0SScott Long info->batteryPlatform)); 274835863739SMike Smith 2749bd971c49SScott Long device_printf(sc->aac_dev, 2750bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 275135863739SMike Smith info->KernelRevision.external.comp.major, 275235863739SMike Smith info->KernelRevision.external.comp.minor, 275335863739SMike Smith info->KernelRevision.external.comp.dash, 275436e0bf6eSScott Long info->KernelRevision.buildNumber, 275536e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2756fe3cb0e1SScott Long 2757a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2758a6d35632SScott Long sc->supported_options, 2759a6d35632SScott Long "\20" 2760a6d35632SScott Long "\1SNAPSHOT" 2761a6d35632SScott Long "\2CLUSTERS" 2762a6d35632SScott Long "\3WCACHE" 2763a6d35632SScott Long "\4DATA64" 2764a6d35632SScott Long "\5HOSTTIME" 2765a6d35632SScott Long "\6RAID50" 2766a6d35632SScott Long "\7WINDOW4GB" 2767a6d35632SScott Long "\10SCSIUPGD" 2768a6d35632SScott Long "\11SOFTERR" 2769a6d35632SScott Long "\12NORECOND" 2770a6d35632SScott Long "\13SGMAP64" 2771a6d35632SScott Long "\14ALARM" 27727cb209f5SScott Long "\15NONDASD" 27737cb209f5SScott Long "\16SCSIMGT" 27747cb209f5SScott Long "\17RAIDSCSI" 27757cb209f5SScott Long "\21ADPTINFO" 27767cb209f5SScott Long "\22NEWCOMM" 27777cb209f5SScott Long "\23ARRAY64BIT" 27787cb209f5SScott Long "\24HEATSENSOR"); 2779a6d35632SScott Long } 2780bd971c49SScott Long aac_release_sync_fib(sc); 278181b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 278235863739SMike Smith } 278335863739SMike Smith 2784914da7d0SScott Long /* 278535863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 278635863739SMike Smith * same. 278735863739SMike Smith */ 278835863739SMike Smith static char * 278935863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 279035863739SMike Smith { 279135863739SMike Smith int i; 279235863739SMike Smith 279335863739SMike Smith for (i = 0; table[i].string != NULL; i++) 279435863739SMike Smith if (table[i].code == code) 279535863739SMike Smith return(table[i].string); 279635863739SMike Smith return(table[i + 1].string); 279735863739SMike Smith } 279835863739SMike Smith 2799914da7d0SScott Long /* 2800914da7d0SScott Long * Management Interface 2801914da7d0SScott Long */ 280235863739SMike Smith 280335863739SMike Smith static int 280489c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 280535863739SMike Smith { 2806914da7d0SScott Long struct aac_softc *sc; 280735863739SMike Smith 280835863739SMike Smith debug_called(2); 280935863739SMike Smith 2810914da7d0SScott Long sc = dev->si_drv1; 2811914da7d0SScott Long 281235863739SMike Smith /* Check to make sure the device isn't already open */ 281335863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 281435863739SMike Smith return EBUSY; 281535863739SMike Smith } 281635863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 281735863739SMike Smith 281835863739SMike Smith return 0; 281935863739SMike Smith } 282035863739SMike Smith 282135863739SMike Smith static int 282289c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 282335863739SMike Smith { 2824914da7d0SScott Long struct aac_softc *sc; 282535863739SMike Smith 282635863739SMike Smith debug_called(2); 282735863739SMike Smith 2828914da7d0SScott Long sc = dev->si_drv1; 2829914da7d0SScott Long 283035863739SMike Smith /* Mark this unit as no longer open */ 283135863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 283235863739SMike Smith 283335863739SMike Smith return 0; 283435863739SMike Smith } 283535863739SMike Smith 283635863739SMike Smith static int 283789c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 283835863739SMike Smith { 2839914da7d0SScott Long union aac_statrequest *as; 2840914da7d0SScott Long struct aac_softc *sc; 28410b94a66eSMike Smith int error = 0; 2842b88ffdc8SScott Long uint32_t cookie; 284335863739SMike Smith 284435863739SMike Smith debug_called(2); 284535863739SMike Smith 2846914da7d0SScott Long as = (union aac_statrequest *)arg; 2847914da7d0SScott Long sc = dev->si_drv1; 2848914da7d0SScott Long 284935863739SMike Smith switch (cmd) { 28500b94a66eSMike Smith case AACIO_STATS: 28510b94a66eSMike Smith switch (as->as_item) { 28520b94a66eSMike Smith case AACQ_FREE: 28530b94a66eSMike Smith case AACQ_BIO: 28540b94a66eSMike Smith case AACQ_READY: 28550b94a66eSMike Smith case AACQ_BUSY: 2856c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2857c6eafcf2SScott Long sizeof(struct aac_qstat)); 28580b94a66eSMike Smith break; 28590b94a66eSMike Smith default: 28600b94a66eSMike Smith error = ENOENT; 28610b94a66eSMike Smith break; 28620b94a66eSMike Smith } 28630b94a66eSMike Smith break; 28640b94a66eSMike Smith 286535863739SMike Smith case FSACTL_SENDFIB: 2866fb0c27d7SScott Long arg = *(caddr_t*)arg; 2867fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 28680b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 286935863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 287035863739SMike Smith break; 287135863739SMike Smith case FSACTL_AIF_THREAD: 2872fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 28730b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 287435863739SMike Smith error = EINVAL; 287535863739SMike Smith break; 287635863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2877fb0c27d7SScott Long arg = *(caddr_t*)arg; 2878fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 28790b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 288035863739SMike Smith /* 288135863739SMike Smith * Pass the caller out an AdapterFibContext. 288235863739SMike Smith * 288335863739SMike Smith * Note that because we only support one opener, we 288435863739SMike Smith * basically ignore this. Set the caller's context to a magic 288535863739SMike Smith * number just in case. 28860b94a66eSMike Smith * 28870b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 28880b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2889914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2890914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 289135863739SMike Smith */ 2892b88ffdc8SScott Long cookie = (uint32_t)(uintptr_t)sc->aifthread; 2893b88ffdc8SScott Long error = copyout(&cookie, arg, sizeof(cookie)); 289435863739SMike Smith break; 289535863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2896fb0c27d7SScott Long arg = *(caddr_t*)arg; 2897fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 28980b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2899fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 290035863739SMike Smith break; 290135863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2902fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 29030b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 290435863739SMike Smith /* don't do anything here */ 290535863739SMike Smith break; 290635863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2907fb0c27d7SScott Long arg = *(caddr_t*)arg; 2908fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 29090b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2910fb0c27d7SScott Long error = aac_rev_check(sc, arg); 291135863739SMike Smith break; 291236e0bf6eSScott Long case FSACTL_QUERY_DISK: 291336e0bf6eSScott Long arg = *(caddr_t*)arg; 291436e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 291536e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 291636e0bf6eSScott Long error = aac_query_disk(sc, arg); 291736e0bf6eSScott Long break; 291836e0bf6eSScott Long case FSACTL_DELETE_DISK: 291936e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2920914da7d0SScott Long /* 2921914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2922914da7d0SScott Long * container, rather we rely on an AIF coming from the 2923914da7d0SScott Long * controller 2924914da7d0SScott Long */ 292536e0bf6eSScott Long error = 0; 292636e0bf6eSScott Long break; 29277cb209f5SScott Long case FSACTL_GET_PCI_INFO: 29287cb209f5SScott Long arg = *(caddr_t*)arg; 29297cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 29307cb209f5SScott Long debug(1, "FSACTL_GET_PCI_INFO"); 29317cb209f5SScott Long error = aac_get_pci_info(sc, arg); 29327cb209f5SScott Long break; 293335863739SMike Smith default: 2934b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 293535863739SMike Smith error = EINVAL; 293635863739SMike Smith break; 293735863739SMike Smith } 293835863739SMike Smith return(error); 293935863739SMike Smith } 294035863739SMike Smith 2941b3457b51SScott Long static int 294289c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 2943b3457b51SScott Long { 2944b3457b51SScott Long struct aac_softc *sc; 2945b3457b51SScott Long int revents; 2946b3457b51SScott Long 2947b3457b51SScott Long sc = dev->si_drv1; 2948b3457b51SScott Long revents = 0; 2949b3457b51SScott Long 2950bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2951b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2952b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2953b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2954b3457b51SScott Long } 2955bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2956b3457b51SScott Long 2957b3457b51SScott Long if (revents == 0) { 2958b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2959b3457b51SScott Long selrecord(td, &sc->rcv_select); 2960b3457b51SScott Long } 2961b3457b51SScott Long 2962b3457b51SScott Long return (revents); 2963b3457b51SScott Long } 2964b3457b51SScott Long 29657cb209f5SScott Long static void 29667cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 29677cb209f5SScott Long { 29687cb209f5SScott Long 29697cb209f5SScott Long switch (event->ev_type) { 29707cb209f5SScott Long case AAC_EVENT_CMFREE: 29717cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 29727cb209f5SScott Long if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) { 29737cb209f5SScott Long aac_add_event(sc, event); 29747cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 29757cb209f5SScott Long return; 29767cb209f5SScott Long } 29777cb209f5SScott Long free(event, M_AACBUF); 29788eeb2ca6SScott Long wakeup(arg); 29797cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 29807cb209f5SScott Long break; 29817cb209f5SScott Long default: 29827cb209f5SScott Long break; 29837cb209f5SScott Long } 29847cb209f5SScott Long } 29857cb209f5SScott Long 2986914da7d0SScott Long /* 298735863739SMike Smith * Send a FIB supplied from userspace 298835863739SMike Smith */ 298935863739SMike Smith static int 299035863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 299135863739SMike Smith { 299235863739SMike Smith struct aac_command *cm; 299335863739SMike Smith int size, error; 299435863739SMike Smith 299535863739SMike Smith debug_called(2); 299635863739SMike Smith 299735863739SMike Smith cm = NULL; 299835863739SMike Smith 299935863739SMike Smith /* 300035863739SMike Smith * Get a command 300135863739SMike Smith */ 3002bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 300335863739SMike Smith if (aac_alloc_command(sc, &cm)) { 30047cb209f5SScott Long struct aac_event *event; 30057cb209f5SScott Long 30067cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 30077cb209f5SScott Long M_NOWAIT | M_ZERO); 30087cb209f5SScott Long if (event == NULL) { 300935863739SMike Smith error = EBUSY; 301035863739SMike Smith goto out; 301135863739SMike Smith } 30127cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 30137cb209f5SScott Long event->ev_callback = aac_ioctl_event; 30147cb209f5SScott Long event->ev_arg = &cm; 30157cb209f5SScott Long aac_add_event(sc, event); 30168eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 30177cb209f5SScott Long } 301835863739SMike Smith 301935863739SMike Smith /* 302035863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 302135863739SMike Smith */ 3022914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 3023914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 302435863739SMike Smith goto out; 302535863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 302635863739SMike Smith if (size > sizeof(struct aac_fib)) { 3027b88ffdc8SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 3028914da7d0SScott Long size, sizeof(struct aac_fib)); 302935863739SMike Smith size = sizeof(struct aac_fib); 303035863739SMike Smith } 303135863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 303235863739SMike Smith goto out; 303335863739SMike Smith cm->cm_fib->Header.Size = size; 30342b3b0f17SScott Long cm->cm_timestamp = time_uptime; 303535863739SMike Smith 303635863739SMike Smith /* 303735863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 303835863739SMike Smith */ 3039d8a0a473SScott Long if ((error = aac_wait_command(cm)) != 0) { 304070545d1aSScott Long device_printf(sc->aac_dev, 304170545d1aSScott Long "aac_wait_command return %d\n", error); 304235863739SMike Smith goto out; 3043b3457b51SScott Long } 304435863739SMike Smith 304535863739SMike Smith /* 304635863739SMike Smith * Copy the FIB and data back out to the caller. 304735863739SMike Smith */ 304835863739SMike Smith size = cm->cm_fib->Header.Size; 304935863739SMike Smith if (size > sizeof(struct aac_fib)) { 3050b88ffdc8SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 3051914da7d0SScott Long size, sizeof(struct aac_fib)); 305235863739SMike Smith size = sizeof(struct aac_fib); 305335863739SMike Smith } 305435863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 305535863739SMike Smith 305635863739SMike Smith out: 3057f6c4dd3fSScott Long if (cm != NULL) { 305835863739SMike Smith aac_release_command(cm); 3059f6c4dd3fSScott Long } 3060ae543596SScott Long 3061bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 306235863739SMike Smith return(error); 306335863739SMike Smith } 306435863739SMike Smith 3065914da7d0SScott Long /* 306635863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 306736e0bf6eSScott Long * If the queue fills up, then drop the older entries. 306835863739SMike Smith */ 306935863739SMike Smith static void 307036e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 307135863739SMike Smith { 307236e0bf6eSScott Long struct aac_aif_command *aif; 307336e0bf6eSScott Long struct aac_container *co, *co_next; 3074cbfd045bSScott Long struct aac_mntinfo *mi; 3075cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 307636e0bf6eSScott Long u_int16_t rsize; 3077b3457b51SScott Long int next, found; 3078795d7dc0SScott Long int count = 0, added = 0, i = 0; 307935863739SMike Smith 308035863739SMike Smith debug_called(2); 308135863739SMike Smith 308236e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 308336e0bf6eSScott Long aac_print_aif(sc, aif); 308436e0bf6eSScott Long 308536e0bf6eSScott Long /* Is it an event that we should care about? */ 308636e0bf6eSScott Long switch (aif->command) { 308736e0bf6eSScott Long case AifCmdEventNotify: 308836e0bf6eSScott Long switch (aif->data.EN.type) { 308936e0bf6eSScott Long case AifEnAddContainer: 309036e0bf6eSScott Long case AifEnDeleteContainer: 309136e0bf6eSScott Long /* 3092914da7d0SScott Long * A container was added or deleted, but the message 3093914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3094914da7d0SScott Long * containers and sort things out. 309536e0bf6eSScott Long */ 309603b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3097cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 309836e0bf6eSScott Long do { 309936e0bf6eSScott Long /* 3100914da7d0SScott Long * Ask the controller for its containers one at 3101914da7d0SScott Long * a time. 3102914da7d0SScott Long * XXX What if the controller's list changes 3103914da7d0SScott Long * midway through this enumaration? 310436e0bf6eSScott Long * XXX This should be done async. 310536e0bf6eSScott Long */ 310639ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 310739ee03c3SScott Long mi->Command = VM_NameServe; 310839ee03c3SScott Long mi->MntType = FT_FILESYS; 3109cbfd045bSScott Long mi->MntCount = i; 311036e0bf6eSScott Long rsize = sizeof(mir); 3111cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 3112cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 3113795d7dc0SScott Long printf("Error probing container %d\n", 3114914da7d0SScott Long i); 311536e0bf6eSScott Long continue; 311636e0bf6eSScott Long } 3117cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 3118795d7dc0SScott Long /* XXX Need to check if count changed */ 3119795d7dc0SScott Long count = mir->MntRespCount; 312036e0bf6eSScott Long /* 3121914da7d0SScott Long * Check the container against our list. 3122914da7d0SScott Long * co->co_found was already set to 0 in a 3123914da7d0SScott Long * previous run. 312436e0bf6eSScott Long */ 3125cbfd045bSScott Long if ((mir->Status == ST_OK) && 3126cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 312736e0bf6eSScott Long found = 0; 3128914da7d0SScott Long TAILQ_FOREACH(co, 3129914da7d0SScott Long &sc->aac_container_tqh, 3130914da7d0SScott Long co_link) { 313136e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3132cbfd045bSScott Long mir->MntTable[0].ObjectId) { 313336e0bf6eSScott Long co->co_found = 1; 313436e0bf6eSScott Long found = 1; 313536e0bf6eSScott Long break; 313636e0bf6eSScott Long } 313736e0bf6eSScott Long } 3138914da7d0SScott Long /* 3139914da7d0SScott Long * If the container matched, continue 3140914da7d0SScott Long * in the list. 3141914da7d0SScott Long */ 314236e0bf6eSScott Long if (found) { 314336e0bf6eSScott Long i++; 314436e0bf6eSScott Long continue; 314536e0bf6eSScott Long } 314636e0bf6eSScott Long 314736e0bf6eSScott Long /* 3148914da7d0SScott Long * This is a new container. Do all the 314970545d1aSScott Long * appropriate things to set it up. 315070545d1aSScott Long */ 3151cbfd045bSScott Long aac_add_container(sc, mir, 1); 315236e0bf6eSScott Long added = 1; 315336e0bf6eSScott Long } 315436e0bf6eSScott Long i++; 3155795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3156cbfd045bSScott Long aac_release_sync_fib(sc); 315736e0bf6eSScott Long 315836e0bf6eSScott Long /* 3159914da7d0SScott Long * Go through our list of containers and see which ones 3160914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3161914da7d0SScott Long * list them they must have been deleted. Do the 3162914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3163914da7d0SScott Long * the co->co_found field. 316436e0bf6eSScott Long */ 316536e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 316636e0bf6eSScott Long while (co != NULL) { 316736e0bf6eSScott Long if (co->co_found == 0) { 31687cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 31697cb209f5SScott Long mtx_lock(&Giant); 3170914da7d0SScott Long device_delete_child(sc->aac_dev, 3171914da7d0SScott Long co->co_disk); 31727cb209f5SScott Long mtx_unlock(&Giant); 31737cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 317436e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3175bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3176914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3177914da7d0SScott Long co_link); 3178bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3179ba1d57e7SScott Long free(co, M_AACBUF); 318036e0bf6eSScott Long co = co_next; 318136e0bf6eSScott Long } else { 318236e0bf6eSScott Long co->co_found = 0; 318336e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 318436e0bf6eSScott Long } 318536e0bf6eSScott Long } 318636e0bf6eSScott Long 318736e0bf6eSScott Long /* Attach the newly created containers */ 31887cb209f5SScott Long if (added) { 31897cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 31907cb209f5SScott Long mtx_lock(&Giant); 319136e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 31927cb209f5SScott Long mtx_unlock(&Giant); 31937cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 31947cb209f5SScott Long } 319536e0bf6eSScott Long 319636e0bf6eSScott Long break; 319736e0bf6eSScott Long 319836e0bf6eSScott Long default: 319936e0bf6eSScott Long break; 320036e0bf6eSScott Long } 320136e0bf6eSScott Long 320236e0bf6eSScott Long default: 320336e0bf6eSScott Long break; 320436e0bf6eSScott Long } 320536e0bf6eSScott Long 320636e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3207bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 320835863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 320935863739SMike Smith if (next != sc->aac_aifq_tail) { 321035863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 321135863739SMike Smith sc->aac_aifq_head = next; 3212b3457b51SScott Long 3213b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 321435863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 321535863739SMike Smith wakeup(sc->aac_aifq); 3216b3457b51SScott Long /* Wakeup any poll()ers */ 3217512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 321835863739SMike Smith } 3219bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 322036e0bf6eSScott Long 322136e0bf6eSScott Long return; 322235863739SMike Smith } 322335863739SMike Smith 3224914da7d0SScott Long /* 32250b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 322636e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 322736e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 322836e0bf6eSScott Long * returning what the card reported. 322935863739SMike Smith */ 323035863739SMike Smith static int 3231fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 323235863739SMike Smith { 323335863739SMike Smith struct aac_rev_check rev_check; 323435863739SMike Smith struct aac_rev_check_resp rev_check_resp; 323535863739SMike Smith int error = 0; 323635863739SMike Smith 323735863739SMike Smith debug_called(2); 323835863739SMike Smith 323935863739SMike Smith /* 324035863739SMike Smith * Copyin the revision struct from userspace 324135863739SMike Smith */ 3242c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3243c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 324435863739SMike Smith return error; 324535863739SMike Smith } 324635863739SMike Smith 3247914da7d0SScott Long debug(2, "Userland revision= %d\n", 3248914da7d0SScott Long rev_check.callingRevision.buildNumber); 324935863739SMike Smith 325035863739SMike Smith /* 325135863739SMike Smith * Doctor up the response struct. 325235863739SMike Smith */ 325335863739SMike Smith rev_check_resp.possiblyCompatible = 1; 3254914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 3255914da7d0SScott Long sc->aac_revision.external.ul; 3256914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 3257914da7d0SScott Long sc->aac_revision.buildNumber; 325835863739SMike Smith 3259c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3260c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 326135863739SMike Smith } 326235863739SMike Smith 3263914da7d0SScott Long /* 326435863739SMike Smith * Pass the caller the next AIF in their queue 326535863739SMike Smith */ 326635863739SMike Smith static int 3267fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 326835863739SMike Smith { 326935863739SMike Smith struct get_adapter_fib_ioctl agf; 32709e2e96d8SScott Long int error; 327135863739SMike Smith 327235863739SMike Smith debug_called(2); 327335863739SMike Smith 327435863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 327535863739SMike Smith 327635863739SMike Smith /* 327735863739SMike Smith * Check the magic number that we gave the caller. 327835863739SMike Smith */ 3279b88ffdc8SScott Long if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 328035863739SMike Smith error = EFAULT; 328135863739SMike Smith } else { 3282fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 328335863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 328435863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 328535863739SMike Smith while (error == EAGAIN) { 3286914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3287914da7d0SScott Long PCATCH, "aacaif", 0); 328835863739SMike Smith if (error == 0) 3289914da7d0SScott Long error = aac_return_aif(sc, 3290914da7d0SScott Long agf.AifFib); 329135863739SMike Smith } 329235863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 329335863739SMike Smith } 329435863739SMike Smith } 329535863739SMike Smith } 329635863739SMike Smith return(error); 329735863739SMike Smith } 329835863739SMike Smith 3299914da7d0SScott Long /* 33000b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 33010b94a66eSMike Smith */ 33020b94a66eSMike Smith static int 3303fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 33040b94a66eSMike Smith { 33053df780cfSScott Long int next, error; 33060b94a66eSMike Smith 33070b94a66eSMike Smith debug_called(2); 33080b94a66eSMike Smith 3309bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 33100b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 3311bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 33123df780cfSScott Long return (EAGAIN); 33133df780cfSScott Long } 33143df780cfSScott Long 33153df780cfSScott Long next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 33163df780cfSScott Long error = copyout(&sc->aac_aifq[next], uptr, 3317c6eafcf2SScott Long sizeof(struct aac_aif_command)); 331836e0bf6eSScott Long if (error) 331970545d1aSScott Long device_printf(sc->aac_dev, 332070545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 33213df780cfSScott Long else 33223df780cfSScott Long sc->aac_aifq_tail = next; 33233df780cfSScott Long 3324bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 33250b94a66eSMike Smith return(error); 33260b94a66eSMike Smith } 332736e0bf6eSScott Long 33287cb209f5SScott Long static int 33297cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 33307cb209f5SScott Long { 33317cb209f5SScott Long struct aac_pci_info { 33327cb209f5SScott Long u_int32_t bus; 33337cb209f5SScott Long u_int32_t slot; 33347cb209f5SScott Long } pciinf; 33357cb209f5SScott Long int error; 33367cb209f5SScott Long 33377cb209f5SScott Long debug_called(2); 33387cb209f5SScott Long 33397cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 33407cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 33417cb209f5SScott Long 33427cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 33437cb209f5SScott Long sizeof(struct aac_pci_info)); 33447cb209f5SScott Long 33457cb209f5SScott Long return (error); 33467cb209f5SScott Long } 33477cb209f5SScott Long 3348914da7d0SScott Long /* 334936e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 335036e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 335136e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 335236e0bf6eSScott Long */ 335336e0bf6eSScott Long static int 335436e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 335536e0bf6eSScott Long { 335636e0bf6eSScott Long struct aac_query_disk query_disk; 335736e0bf6eSScott Long struct aac_container *co; 3358914da7d0SScott Long struct aac_disk *disk; 335936e0bf6eSScott Long int error, id; 336036e0bf6eSScott Long 336136e0bf6eSScott Long debug_called(2); 336236e0bf6eSScott Long 3363914da7d0SScott Long disk = NULL; 3364914da7d0SScott Long 3365914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3366914da7d0SScott Long sizeof(struct aac_query_disk)); 336736e0bf6eSScott Long if (error) 336836e0bf6eSScott Long return (error); 336936e0bf6eSScott Long 337036e0bf6eSScott Long id = query_disk.ContainerNumber; 337136e0bf6eSScott Long if (id == -1) 337236e0bf6eSScott Long return (EINVAL); 337336e0bf6eSScott Long 3374bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 337536e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 337636e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 337736e0bf6eSScott Long break; 337836e0bf6eSScott Long } 337936e0bf6eSScott Long 338036e0bf6eSScott Long if (co == NULL) { 338136e0bf6eSScott Long query_disk.Valid = 0; 338236e0bf6eSScott Long query_disk.Locked = 0; 338336e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 338436e0bf6eSScott Long } else { 338536e0bf6eSScott Long disk = device_get_softc(co->co_disk); 338636e0bf6eSScott Long query_disk.Valid = 1; 3387914da7d0SScott Long query_disk.Locked = 3388914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 338936e0bf6eSScott Long query_disk.Deleted = 0; 3390b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 339136e0bf6eSScott Long query_disk.Target = disk->unit; 339236e0bf6eSScott Long query_disk.Lun = 0; 339336e0bf6eSScott Long query_disk.UnMapped = 0; 33947540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 33950b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 339636e0bf6eSScott Long } 3397bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 339836e0bf6eSScott Long 3399914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3400914da7d0SScott Long sizeof(struct aac_query_disk)); 340136e0bf6eSScott Long 340236e0bf6eSScott Long return (error); 340336e0bf6eSScott Long } 340436e0bf6eSScott Long 3405fe3cb0e1SScott Long static void 3406fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3407fe3cb0e1SScott Long { 3408fe3cb0e1SScott Long struct aac_fib *fib; 3409fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3410fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3411fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3412fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3413fe3cb0e1SScott Long struct aac_getbusinf businfo; 341470545d1aSScott Long struct aac_sim *caminf; 3415fe3cb0e1SScott Long device_t child; 3416fe3cb0e1SScott Long int i, found, error; 3417fe3cb0e1SScott Long 341803b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3419fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 342039ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3421fe3cb0e1SScott Long 3422fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3423fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3424fe3cb0e1SScott Long c_cmd->param = 0; 3425fe3cb0e1SScott Long 3426fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3427fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3428fe3cb0e1SScott Long if (error) { 3429fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3430fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3431fe3cb0e1SScott Long aac_release_sync_fib(sc); 3432fe3cb0e1SScott Long return; 3433fe3cb0e1SScott Long } 3434fe3cb0e1SScott Long 3435fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3436fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3437fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3438fe3cb0e1SScott Long c_resp->Status); 3439fe3cb0e1SScott Long aac_release_sync_fib(sc); 3440fe3cb0e1SScott Long return; 3441fe3cb0e1SScott Long } 3442fe3cb0e1SScott Long 3443fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3444fe3cb0e1SScott Long 3445fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 344639ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 344739ee03c3SScott Long 3448fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3449fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3450fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3451fe3cb0e1SScott Long vmi->ObjId = 0; 3452fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3453fe3cb0e1SScott Long 3454fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3455fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 3456fe3cb0e1SScott Long if (error) { 3457fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3458fe3cb0e1SScott Long error); 3459fe3cb0e1SScott Long aac_release_sync_fib(sc); 3460fe3cb0e1SScott Long return; 3461fe3cb0e1SScott Long } 3462fe3cb0e1SScott Long 3463fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3464fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3465fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3466fe3cb0e1SScott Long vmi_resp->Status); 3467fe3cb0e1SScott Long aac_release_sync_fib(sc); 3468fe3cb0e1SScott Long return; 3469fe3cb0e1SScott Long } 3470fe3cb0e1SScott Long 3471fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3472fe3cb0e1SScott Long aac_release_sync_fib(sc); 3473fe3cb0e1SScott Long 3474fe3cb0e1SScott Long found = 0; 3475fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3476fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3477fe3cb0e1SScott Long continue; 3478fe3cb0e1SScott Long 3479a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3480a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3481b5f516cdSScott Long if (caminf == NULL) { 3482b5f516cdSScott Long device_printf(sc->aac_dev, 3483b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3484b5f516cdSScott Long break; 34857cb209f5SScott Long }; 3486fe3cb0e1SScott Long 3487fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3488fe3cb0e1SScott Long if (child == NULL) { 3489b5f516cdSScott Long device_printf(sc->aac_dev, 3490b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3491b5f516cdSScott Long i); 3492b5f516cdSScott Long free(caminf, M_AACBUF); 3493b5f516cdSScott Long break; 3494fe3cb0e1SScott Long } 3495fe3cb0e1SScott Long 3496fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3497fe3cb0e1SScott Long caminf->BusNumber = i; 3498fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3499fe3cb0e1SScott Long caminf->aac_sc = sc; 3500ddb8683eSScott Long caminf->sim_dev = child; 3501fe3cb0e1SScott Long 3502fe3cb0e1SScott Long device_set_ivars(child, caminf); 3503fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 350470545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3505fe3cb0e1SScott Long 3506fe3cb0e1SScott Long found = 1; 3507fe3cb0e1SScott Long } 3508fe3cb0e1SScott Long 3509fe3cb0e1SScott Long if (found) 3510fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3511fe3cb0e1SScott Long 3512fe3cb0e1SScott Long return; 3513fe3cb0e1SScott Long } 3514