135863739SMike Smith /*- 235863739SMike Smith * Copyright (c) 2000 Michael Smith 3c6eafcf2SScott Long * Copyright (c) 2001 Scott Long 435863739SMike Smith * Copyright (c) 2000 BSDi 5c6eafcf2SScott Long * Copyright (c) 2001 Adaptec, Inc. 635863739SMike Smith * All rights reserved. 735863739SMike Smith * 835863739SMike Smith * Redistribution and use in source and binary forms, with or without 935863739SMike Smith * modification, are permitted provided that the following conditions 1035863739SMike Smith * are met: 1135863739SMike Smith * 1. Redistributions of source code must retain the above copyright 1235863739SMike Smith * notice, this list of conditions and the following disclaimer. 1335863739SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1435863739SMike Smith * notice, this list of conditions and the following disclaimer in the 1535863739SMike Smith * documentation and/or other materials provided with the distribution. 1635863739SMike Smith * 1735863739SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1835863739SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1935863739SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2035863739SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2135863739SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2235863739SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2335863739SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2435863739SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2535863739SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2635863739SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2735863739SMike Smith * SUCH DAMAGE. 2835863739SMike Smith */ 2935863739SMike Smith 30aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 32aad970f1SDavid E. O'Brien 3335863739SMike Smith /* 3435863739SMike Smith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. 3535863739SMike Smith */ 367cb209f5SScott Long #define AAC_DRIVER_VERSION 0x02000000 377cb209f5SScott Long #define AAC_DRIVERNAME "aac" 3835863739SMike Smith 39f6c4dd3fSScott Long #include "opt_aac.h" 40f6c4dd3fSScott Long 4136e0bf6eSScott Long /* #include <stddef.h> */ 4235863739SMike Smith #include <sys/param.h> 4335863739SMike Smith #include <sys/systm.h> 4435863739SMike Smith #include <sys/malloc.h> 4535863739SMike Smith #include <sys/kernel.h> 4636e0bf6eSScott Long #include <sys/kthread.h> 473d04a9d7SScott Long #include <sys/sysctl.h> 48b3457b51SScott Long #include <sys/poll.h> 49891619a6SPoul-Henning Kamp #include <sys/ioccom.h> 5035863739SMike Smith 5135863739SMike Smith #include <sys/bus.h> 5235863739SMike Smith #include <sys/conf.h> 5335863739SMike Smith #include <sys/signalvar.h> 540b94a66eSMike Smith #include <sys/time.h> 5536e0bf6eSScott Long #include <sys/eventhandler.h> 567cb209f5SScott Long #include <sys/rman.h> 5735863739SMike Smith 5835863739SMike Smith #include <machine/bus.h> 59b5f516cdSScott Long #include <sys/bus_dma.h> 6035863739SMike Smith #include <machine/resource.h> 6135863739SMike Smith 627cb209f5SScott Long #include <dev/pci/pcireg.h> 637cb209f5SScott Long #include <dev/pci/pcivar.h> 647cb209f5SScott Long 6535863739SMike Smith #include <dev/aac/aacreg.h> 660b0594cdSScott Long #include <sys/aac_ioctl.h> 6735863739SMike Smith #include <dev/aac/aacvar.h> 6835863739SMike Smith #include <dev/aac/aac_tables.h> 6935863739SMike Smith 7035863739SMike Smith static void aac_startup(void *arg); 71914da7d0SScott Long static void aac_add_container(struct aac_softc *sc, 72cbfd045bSScott Long struct aac_mntinforesp *mir, int f); 73fe3cb0e1SScott Long static void aac_get_bus_info(struct aac_softc *sc); 7435863739SMike Smith 7535863739SMike Smith /* Command Processing */ 760b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7735863739SMike Smith static void aac_complete(void *context, int pending); 7835863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 7935863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 80d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 8170545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8235863739SMike Smith 8335863739SMike Smith /* Command Buffer Management */ 84cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 85cd481291SScott Long int nseg, int error); 86c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 87c6eafcf2SScott Long int nseg, int error); 880b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 898480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9035863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9135863739SMike Smith 9235863739SMike Smith /* Hardware Interface */ 93c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 94c6eafcf2SScott Long int error); 95fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9635863739SMike Smith static int aac_init(struct aac_softc *sc); 9735863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 98c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 99c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 100c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 101f6c4dd3fSScott Long struct aac_command *cm); 102c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 103914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10436e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10536e0bf6eSScott Long struct aac_fib *fib); 10635863739SMike Smith 107b3457b51SScott Long /* Falcon/PPC interface */ 108b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 109b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 110b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 111b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 112b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 113b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 114b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 115a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 116b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 117b3457b51SScott Long 118b3457b51SScott Long struct aac_interface aac_fa_interface = { 119b3457b51SScott Long aac_fa_get_fwstatus, 120b3457b51SScott Long aac_fa_qnotify, 121b3457b51SScott Long aac_fa_get_istatus, 122b3457b51SScott Long aac_fa_clear_istatus, 123b3457b51SScott Long aac_fa_set_mailbox, 124a6d35632SScott Long aac_fa_get_mailbox, 1257cb209f5SScott Long aac_fa_set_interrupts, 1267cb209f5SScott Long NULL, NULL, NULL 127b3457b51SScott Long }; 128b3457b51SScott Long 12935863739SMike Smith /* StrongARM interface */ 13035863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13135863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13235863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13335863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13435863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 135c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 136c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 137a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 13835863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 13935863739SMike Smith 14035863739SMike Smith struct aac_interface aac_sa_interface = { 14135863739SMike Smith aac_sa_get_fwstatus, 14235863739SMike Smith aac_sa_qnotify, 14335863739SMike Smith aac_sa_get_istatus, 14435863739SMike Smith aac_sa_clear_istatus, 14535863739SMike Smith aac_sa_set_mailbox, 146a6d35632SScott Long aac_sa_get_mailbox, 1477cb209f5SScott Long aac_sa_set_interrupts, 1487cb209f5SScott Long NULL, NULL, NULL 14935863739SMike Smith }; 15035863739SMike Smith 15135863739SMike Smith /* i960Rx interface */ 15235863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15335863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15435863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15535863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15635863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 157c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 158c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 159a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 16035863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1617cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1627cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1637cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 16435863739SMike Smith 16535863739SMike Smith struct aac_interface aac_rx_interface = { 16635863739SMike Smith aac_rx_get_fwstatus, 16735863739SMike Smith aac_rx_qnotify, 16835863739SMike Smith aac_rx_get_istatus, 16935863739SMike Smith aac_rx_clear_istatus, 17035863739SMike Smith aac_rx_set_mailbox, 171a6d35632SScott Long aac_rx_get_mailbox, 1727cb209f5SScott Long aac_rx_set_interrupts, 1737cb209f5SScott Long aac_rx_send_command, 1747cb209f5SScott Long aac_rx_get_outb_queue, 1757cb209f5SScott Long aac_rx_set_outb_queue 17635863739SMike Smith }; 17735863739SMike Smith 1784afedc31SScott Long /* Rocket/MIPS interface */ 1794afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1804afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1814afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1824afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1834afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1844afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1854afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1864afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1874afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1887cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1897cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1907cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1914afedc31SScott Long 1924afedc31SScott Long struct aac_interface aac_rkt_interface = { 1934afedc31SScott Long aac_rkt_get_fwstatus, 1944afedc31SScott Long aac_rkt_qnotify, 1954afedc31SScott Long aac_rkt_get_istatus, 1964afedc31SScott Long aac_rkt_clear_istatus, 1974afedc31SScott Long aac_rkt_set_mailbox, 1984afedc31SScott Long aac_rkt_get_mailbox, 1997cb209f5SScott Long aac_rkt_set_interrupts, 2007cb209f5SScott Long aac_rkt_send_command, 2017cb209f5SScott Long aac_rkt_get_outb_queue, 2027cb209f5SScott Long aac_rkt_set_outb_queue 2034afedc31SScott Long }; 2044afedc31SScott Long 20535863739SMike Smith /* Debugging and Diagnostics */ 20635863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 2076965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 208c6eafcf2SScott Long u_int32_t code); 20935863739SMike Smith 21035863739SMike Smith /* Management Interface */ 21135863739SMike Smith static d_open_t aac_open; 21235863739SMike Smith static d_close_t aac_close; 21335863739SMike Smith static d_ioctl_t aac_ioctl; 214b3457b51SScott Long static d_poll_t aac_poll; 215c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 216c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 21736e0bf6eSScott Long struct aac_fib *fib); 218fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 219fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 220fb0c27d7SScott Long static int aac_return_aif(struct aac_softc *sc, caddr_t uptr); 22136e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2227cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2237cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2247cb209f5SScott Long struct aac_event *event, void *arg); 22535863739SMike Smith 22635863739SMike Smith static struct cdevsw aac_cdevsw = { 227dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 228dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 2297ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2307ac40f5fSPoul-Henning Kamp .d_close = aac_close, 2317ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2327ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2337ac40f5fSPoul-Henning Kamp .d_name = "aac", 23435863739SMike Smith }; 23535863739SMike Smith 23636e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 23736e0bf6eSScott Long 2383d04a9d7SScott Long /* sysctl node */ 2393d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2403d04a9d7SScott Long 241914da7d0SScott Long /* 242914da7d0SScott Long * Device Interface 243914da7d0SScott Long */ 24435863739SMike Smith 245914da7d0SScott Long /* 24635863739SMike Smith * Initialise the controller and softc 24735863739SMike Smith */ 24835863739SMike Smith int 24935863739SMike Smith aac_attach(struct aac_softc *sc) 25035863739SMike Smith { 25135863739SMike Smith int error, unit; 25235863739SMike Smith 25335863739SMike Smith debug_called(1); 25435863739SMike Smith 25535863739SMike Smith /* 25635863739SMike Smith * Initialise per-controller queues. 25735863739SMike Smith */ 2580b94a66eSMike Smith aac_initq_free(sc); 2590b94a66eSMike Smith aac_initq_ready(sc); 2600b94a66eSMike Smith aac_initq_busy(sc); 2610b94a66eSMike Smith aac_initq_bio(sc); 26235863739SMike Smith 26335863739SMike Smith /* 26435863739SMike Smith * Initialise command-completion task. 26535863739SMike Smith */ 26635863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 26735863739SMike Smith 26835863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 26935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 27035863739SMike Smith 27135863739SMike Smith /* 272fe94b852SScott Long * Check that the firmware on the card is supported. 273fe94b852SScott Long */ 274fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 275fe94b852SScott Long return(error); 276fe94b852SScott Long 277f6b1c44dSScott Long /* 278f6b1c44dSScott Long * Initialize locks 279f6b1c44dSScott Long */ 280bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 281bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 282bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 283f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 284065dd78cSScott Long TAILQ_INIT(&sc->aac_ev_cmfree); 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 */ 13697cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 13707cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 13718480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1372ffb37f33SScott Long fm->aac_commands = cm; 137335863739SMike Smith cm->cm_sc = sc; 13747cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 13757cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 13767cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1377cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 137835863739SMike Smith 1379ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 138093cfca22SScott Long &cm->cm_datamap)) != 0) 13818480cc63SScott Long break; 138293cfca22SScott Long mtx_lock(&sc->aac_io_lock); 138393cfca22SScott Long aac_release_command(cm); 13848480cc63SScott Long sc->total_fibs++; 138593cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 138635863739SMike Smith } 1387ffb37f33SScott Long 13888480cc63SScott Long if (i > 0) { 138993cfca22SScott Long mtx_lock(&sc->aac_io_lock); 1390ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 1391a6d35632SScott Long debug(1, "total_fibs= %d\n", sc->total_fibs); 1392bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 13930b94a66eSMike Smith return (0); 139435863739SMike Smith } 139535863739SMike Smith 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 { 1577a441b3fcSScott Long u_int32_t major, minor, options = 0, atu_size = 0; 1578a441b3fcSScott Long int status; 1579a6d35632SScott Long 1580a6d35632SScott Long debug_called(1); 1581a6d35632SScott Long 1582fe94b852SScott Long /* 1583fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1584fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1585fe94b852SScott Long */ 1586a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1587fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1588fe94b852SScott Long NULL)) { 1589fe94b852SScott Long device_printf(sc->aac_dev, 1590fe94b852SScott Long "Error reading firmware version\n"); 1591fe94b852SScott Long return (EIO); 1592fe94b852SScott Long } 1593fe94b852SScott Long 1594fe94b852SScott Long /* These numbers are stored as ASCII! */ 1595a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1596a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1597fe94b852SScott Long if (major == 1) { 1598fe94b852SScott Long device_printf(sc->aac_dev, 1599fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1600fe94b852SScott Long major, minor); 1601fe94b852SScott Long return (EINVAL); 1602fe94b852SScott Long } 1603fe94b852SScott Long } 1604fe94b852SScott Long 1605a6d35632SScott Long /* 1606a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1607a441b3fcSScott Long * work-arounds to enable. Some firmware revs don't support this 1608a441b3fcSScott Long * command. 1609a6d35632SScott Long */ 1610a441b3fcSScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1611a441b3fcSScott Long if (status != AAC_SRB_STS_INVALID_REQUEST) { 1612a441b3fcSScott Long device_printf(sc->aac_dev, 1613a441b3fcSScott Long "RequestAdapterInfo failed\n"); 1614a6d35632SScott Long return (EIO); 1615a6d35632SScott Long } 1616a441b3fcSScott Long } else { 1617a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 16187cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1619a6d35632SScott Long sc->supported_options = options; 1620a6d35632SScott Long 1621a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1622a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1623a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1624a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1625a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1626cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1627cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1628a441b3fcSScott Long device_printf(sc->aac_dev, 1629a441b3fcSScott Long "Enabling 64-bit address support\n"); 1630a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1631a6d35632SScott Long } 1632a441b3fcSScott Long if ((options & AAC_SUPPORTED_NEW_COMM) 1633a441b3fcSScott Long && sc->aac_if.aif_send_command) 16347cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 16357cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 16367cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1637a441b3fcSScott Long } 1638a6d35632SScott Long 1639a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 16407cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 16417cb209f5SScott Long 16427cb209f5SScott Long /* Remap mem. resource, if required */ 16437cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 16447cb209f5SScott Long atu_size > rman_get_size(sc->aac_regs_resource)) { 16457cb209f5SScott Long bus_release_resource( 16467cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 16477cb209f5SScott Long sc->aac_regs_rid, sc->aac_regs_resource); 16487cb209f5SScott Long sc->aac_regs_resource = bus_alloc_resource( 16497cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid, 16507cb209f5SScott Long 0ul, ~0ul, atu_size, RF_ACTIVE); 16517cb209f5SScott Long if (sc->aac_regs_resource == NULL) { 16527cb209f5SScott Long sc->aac_regs_resource = bus_alloc_resource_any( 16537cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 16547cb209f5SScott Long &sc->aac_regs_rid, RF_ACTIVE); 16557cb209f5SScott Long if (sc->aac_regs_resource == NULL) { 16567cb209f5SScott Long device_printf(sc->aac_dev, 16577cb209f5SScott Long "couldn't allocate register window\n"); 16587cb209f5SScott Long return (ENXIO); 16597cb209f5SScott Long } 16607cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 16617cb209f5SScott Long } 16627cb209f5SScott Long sc->aac_btag = rman_get_bustag(sc->aac_regs_resource); 16637cb209f5SScott Long sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource); 16647cb209f5SScott Long } 16657cb209f5SScott Long 16667cb209f5SScott Long /* Read preferred settings */ 16677cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 16687cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 16697cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 1670a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1671a441b3fcSScott Long - sizeof(struct aac_blockwrite64) 1672a441b3fcSScott Long + sizeof(struct aac_sg_table64)) 1673a441b3fcSScott Long / sizeof(struct aac_sg_table64); 1674a6d35632SScott Long else 1675a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 1676a441b3fcSScott Long - sizeof(struct aac_blockwrite) 1677a441b3fcSScott Long + sizeof(struct aac_sg_table)) 1678a441b3fcSScott Long / sizeof(struct aac_sg_table); 1679a441b3fcSScott Long 16807cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 16817cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 16827cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 16837cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 16847cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 16857cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 16867cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 16877cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 16887cb209f5SScott Long } 16897cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 16907cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 16917cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1692a6d35632SScott Long 1693fe94b852SScott Long return (0); 1694fe94b852SScott Long } 1695fe94b852SScott Long 169635863739SMike Smith static int 169735863739SMike Smith aac_init(struct aac_softc *sc) 169835863739SMike Smith { 169935863739SMike Smith struct aac_adapter_init *ip; 170035863739SMike Smith time_t then; 1701b88ffdc8SScott Long u_int32_t code, qoffset; 1702a6d35632SScott Long int error; 170335863739SMike Smith 170435863739SMike Smith debug_called(1); 170535863739SMike Smith 170635863739SMike Smith /* 170735863739SMike Smith * First wait for the adapter to come ready. 170835863739SMike Smith */ 17092b3b0f17SScott Long then = time_uptime; 171035863739SMike Smith do { 171135863739SMike Smith code = AAC_GET_FWSTATUS(sc); 171235863739SMike Smith if (code & AAC_SELF_TEST_FAILED) { 171335863739SMike Smith device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 171435863739SMike Smith return(ENXIO); 171535863739SMike Smith } 171635863739SMike Smith if (code & AAC_KERNEL_PANIC) { 1717914da7d0SScott Long device_printf(sc->aac_dev, 1718914da7d0SScott Long "FATAL: controller kernel panic\n"); 171935863739SMike Smith return(ENXIO); 172035863739SMike Smith } 17212b3b0f17SScott Long if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 1722914da7d0SScott Long device_printf(sc->aac_dev, 1723914da7d0SScott Long "FATAL: controller not coming ready, " 1724c6eafcf2SScott Long "status %x\n", code); 172535863739SMike Smith return(ENXIO); 172635863739SMike Smith } 172735863739SMike Smith } while (!(code & AAC_UP_AND_RUNNING)); 172835863739SMike Smith 1729a6d35632SScott Long error = ENOMEM; 1730a6d35632SScott Long /* 1731a6d35632SScott Long * Create DMA tag for mapping buffers into controller-addressable space. 1732a6d35632SScott Long */ 1733a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1734a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1735a6d35632SScott Long (sc->flags & AAC_FLAGS_SG_64BIT) ? 1736a6d35632SScott Long BUS_SPACE_MAXADDR : 1737a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1738a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1739a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 1740a6d35632SScott Long MAXBSIZE, /* maxsize */ 17417cb209f5SScott Long sc->aac_sg_tablesize, /* nsegments */ 1742a6d35632SScott Long MAXBSIZE, /* maxsegsize */ 1743a6d35632SScott Long BUS_DMA_ALLOCNOW, /* flags */ 1744f6b1c44dSScott Long busdma_lock_mutex, /* lockfunc */ 1745f6b1c44dSScott Long &sc->aac_io_lock, /* lockfuncarg */ 1746a6d35632SScott Long &sc->aac_buffer_dmat)) { 1747a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 1748a6d35632SScott Long goto out; 1749a6d35632SScott Long } 1750a6d35632SScott Long 1751a6d35632SScott Long /* 1752a6d35632SScott Long * Create DMA tag for mapping FIBs into controller-addressable space.. 1753a6d35632SScott Long */ 1754a6d35632SScott Long if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1755a6d35632SScott Long 1, 0, /* algnmnt, boundary */ 1756a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1757a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1758a6d35632SScott Long 0x7fffffff, /* lowaddr */ 1759a6d35632SScott Long BUS_SPACE_MAXADDR, /* highaddr */ 1760a6d35632SScott Long NULL, NULL, /* filter, filterarg */ 17617cb209f5SScott Long sc->aac_max_fibs_alloc * 17627cb209f5SScott Long sc->aac_max_fib_size, /* maxsize */ 1763a6d35632SScott Long 1, /* nsegments */ 17647cb209f5SScott Long sc->aac_max_fibs_alloc * 17657cb209f5SScott Long sc->aac_max_fib_size, /* maxsegsize */ 17661248408dSScott Long 0, /* flags */ 1767f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 1768a6d35632SScott Long &sc->aac_fib_dmat)) { 1769a6d35632SScott Long device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 1770a6d35632SScott Long goto out; 1771a6d35632SScott Long } 1772a6d35632SScott Long 177335863739SMike Smith /* 177435863739SMike Smith * Create DMA tag for the common structure and allocate it. 177535863739SMike Smith */ 177635863739SMike Smith if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 1777c6eafcf2SScott Long 1, 0, /* algnmnt, boundary */ 1778a6d35632SScott Long (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 1779a6d35632SScott Long BUS_SPACE_MAXADDR_32BIT : 1780a6d35632SScott Long 0x7fffffff, /* lowaddr */ 178135863739SMike Smith BUS_SPACE_MAXADDR, /* highaddr */ 178235863739SMike Smith NULL, NULL, /* filter, filterarg */ 1783ffb37f33SScott Long 8192 + sizeof(struct aac_common), /* maxsize */ 1784914da7d0SScott Long 1, /* nsegments */ 178535863739SMike Smith BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 17861248408dSScott Long 0, /* flags */ 1787f6b1c44dSScott Long NULL, NULL, /* No locking needed */ 178835863739SMike Smith &sc->aac_common_dmat)) { 1789914da7d0SScott Long device_printf(sc->aac_dev, 1790914da7d0SScott Long "can't allocate common structure DMA tag\n"); 1791a6d35632SScott Long goto out; 179235863739SMike Smith } 1793c6eafcf2SScott Long if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 1794c6eafcf2SScott Long BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 179535863739SMike Smith device_printf(sc->aac_dev, "can't allocate common structure\n"); 1796a6d35632SScott Long goto out; 179735863739SMike Smith } 1798ffb37f33SScott Long 1799ffb37f33SScott Long /* 1800ffb37f33SScott Long * Work around a bug in the 2120 and 2200 that cannot DMA commands 1801ffb37f33SScott Long * below address 8192 in physical memory. 1802ffb37f33SScott Long * XXX If the padding is not needed, can it be put to use instead 1803ffb37f33SScott Long * of ignored? 1804ffb37f33SScott Long */ 1805cd481291SScott Long (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 1806ffb37f33SScott Long sc->aac_common, 8192 + sizeof(*sc->aac_common), 1807ffb37f33SScott Long aac_common_map, sc, 0); 1808ffb37f33SScott Long 1809ffb37f33SScott Long if (sc->aac_common_busaddr < 8192) { 1810eec256deSAlexander Kabaev sc->aac_common = (struct aac_common *) 1811eec256deSAlexander Kabaev ((uint8_t *)sc->aac_common + 8192); 1812ffb37f33SScott Long sc->aac_common_busaddr += 8192; 1813ffb37f33SScott Long } 181435863739SMike Smith bzero(sc->aac_common, sizeof(*sc->aac_common)); 181535863739SMike Smith 1816ffb37f33SScott Long /* Allocate some FIBs and associated command structs */ 1817ffb37f33SScott Long TAILQ_INIT(&sc->aac_fibmap_tqh); 18187cb209f5SScott Long sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 18198480cc63SScott Long M_AACBUF, M_WAITOK|M_ZERO); 18208480cc63SScott Long while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 1821ffb37f33SScott Long if (aac_alloc_commands(sc) != 0) 1822ffb37f33SScott Long break; 1823ffb37f33SScott Long } 1824ffb37f33SScott Long if (sc->total_fibs == 0) 1825a6d35632SScott Long goto out; 1826ffb37f33SScott Long 182735863739SMike Smith /* 1828914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1829914da7d0SScott Long * physical location of various important shared data structures. 183035863739SMike Smith */ 183135863739SMike Smith ip = &sc->aac_common->ac_init; 183235863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18337cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18347cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18357cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18367cb209f5SScott Long } 1837f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 183835863739SMike Smith 1839c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1840c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1841149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 184235863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 184335863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 184435863739SMike Smith 1845c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1846c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 184735863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 184835863739SMike Smith 18494b00f859SScott Long /* 18504b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18514b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18524b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18534b00f859SScott Long * Round up since the granularity is so high. 18544b00f859SScott Long */ 1855f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18564b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 18574b00f859SScott Long ip->HostPhysMemPages = 18584b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1859204c0befSScott Long } 18602b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 186135863739SMike Smith 18627cb209f5SScott Long ip->InitFlags = 0; 18637cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 18647cb209f5SScott Long ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 18657cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 18667cb209f5SScott Long } 18677cb209f5SScott Long 18687cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 18697cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 18707cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 18717cb209f5SScott Long 187235863739SMike Smith /* 1873c6eafcf2SScott Long * Initialise FIB queues. Note that it appears that the layout of the 1874c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1875c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 187635863739SMike Smith * 187735863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1878914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1879914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1880914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1881914da7d0SScott Long * does. 188235863739SMike Smith * 1883914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1884914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1885914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1886914da7d0SScott Long * virtue of a table. 188735863739SMike Smith */ 1888b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 18890bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 18900bcbebd6SScott Long sc->aac_queues = 18910bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1892b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 189335863739SMike Smith 1894c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1895c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1896c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1897c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1898c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1899c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1900c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1901c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1902c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1903c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1904c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1905c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1906c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1907c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1908c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1909c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1910c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1911c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1912c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1913c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1914c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1915c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1916c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1917c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1918c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1919c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1920c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1921c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1922c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1923c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1924c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1925c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1926c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1927c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1928c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1929c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1930c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1931c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1932c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1933c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1934c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1935c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1936c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1937c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1938c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1939c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1940c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1941c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 194235863739SMike Smith 194335863739SMike Smith /* 194435863739SMike Smith * Do controller-type-specific initialisation 194535863739SMike Smith */ 194635863739SMike Smith switch (sc->aac_hwif) { 194735863739SMike Smith case AAC_HWIF_I960RX: 194835863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, ~0); 194935863739SMike Smith break; 19504afedc31SScott Long case AAC_HWIF_RKT: 19514afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, ~0); 19524afedc31SScott Long break; 19534afedc31SScott Long default: 19544afedc31SScott Long break; 195535863739SMike Smith } 195635863739SMike Smith 195735863739SMike Smith /* 195835863739SMike Smith * Give the init structure to the controller. 195935863739SMike Smith */ 196035863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 1961914da7d0SScott Long sc->aac_common_busaddr + 1962914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 1963914da7d0SScott Long NULL)) { 1964914da7d0SScott Long device_printf(sc->aac_dev, 1965914da7d0SScott Long "error establishing init structure\n"); 1966a6d35632SScott Long error = EIO; 1967a6d35632SScott Long goto out; 196835863739SMike Smith } 196935863739SMike Smith 1970a6d35632SScott Long error = 0; 1971a6d35632SScott Long out: 1972a6d35632SScott Long return(error); 197335863739SMike Smith } 197435863739SMike Smith 1975914da7d0SScott Long /* 197635863739SMike Smith * Send a synchronous command to the controller and wait for a result. 19777cb209f5SScott Long * Indicate if the controller completed the command with an error status. 197835863739SMike Smith */ 197935863739SMike Smith static int 198035863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 198135863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 198235863739SMike Smith u_int32_t *sp) 198335863739SMike Smith { 198435863739SMike Smith time_t then; 198535863739SMike Smith u_int32_t status; 198635863739SMike Smith 198735863739SMike Smith debug_called(3); 198835863739SMike Smith 198935863739SMike Smith /* populate the mailbox */ 199035863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 199135863739SMike Smith 199235863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 199335863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 199435863739SMike Smith 199535863739SMike Smith /* then set it to signal the adapter */ 199635863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 199735863739SMike Smith 199835863739SMike Smith /* spin waiting for the command to complete */ 19992b3b0f17SScott Long then = time_uptime; 200035863739SMike Smith do { 20012b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 2002a6d35632SScott Long debug(1, "timed out"); 200335863739SMike Smith return(EIO); 200435863739SMike Smith } 200535863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 200635863739SMike Smith 200735863739SMike Smith /* clear the completion flag */ 200835863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 200935863739SMike Smith 201035863739SMike Smith /* get the command status */ 2011a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 201235863739SMike Smith if (sp != NULL) 201335863739SMike Smith *sp = status; 20147cb209f5SScott Long 2015a441b3fcSScott Long if (status != AAC_SRB_STS_SUCCESS) 20167cb209f5SScott Long return (-1); 20170b94a66eSMike Smith return(0); 201835863739SMike Smith } 201935863739SMike Smith 2020cbfd045bSScott Long int 202135863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2022cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 202335863739SMike Smith { 202435863739SMike Smith debug_called(3); 20257cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 202635863739SMike Smith 202735863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 202835863739SMike Smith return(EINVAL); 202935863739SMike Smith 203035863739SMike Smith /* 203135863739SMike Smith * Set up the sync FIB 203235863739SMike Smith */ 2033914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2034914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2035c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 203635863739SMike Smith fib->Header.XferState |= xferstate; 203735863739SMike Smith fib->Header.Command = command; 203835863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 203935863739SMike Smith fib->Header.Size = sizeof(struct aac_fib) + datasize; 204035863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2041b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2042c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2043914da7d0SScott Long offsetof(struct aac_common, 2044914da7d0SScott Long ac_sync_fib); 204535863739SMike Smith 204635863739SMike Smith /* 204735863739SMike Smith * Give the FIB to the controller, wait for a response. 204835863739SMike Smith */ 2049914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2050914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 205135863739SMike Smith debug(2, "IO error"); 205235863739SMike Smith return(EIO); 205335863739SMike Smith } 205435863739SMike Smith 205535863739SMike Smith return (0); 205635863739SMike Smith } 205735863739SMike Smith 2058914da7d0SScott Long /* 205935863739SMike Smith * Adapter-space FIB queue manipulation 206035863739SMike Smith * 206135863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 206235863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 206335863739SMike Smith */ 206435863739SMike Smith static struct { 206535863739SMike Smith int size; 206635863739SMike Smith int notify; 206735863739SMike Smith } aac_qinfo[] = { 206835863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 206935863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 207035863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 207135863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 207235863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 207335863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 207435863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 207535863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 207635863739SMike Smith }; 207735863739SMike Smith 207835863739SMike Smith /* 2079c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2080c6eafcf2SScott Long * EBUSY if the queue is full. 208135863739SMike Smith * 20820b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2083914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2084914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2085c6eafcf2SScott Long * separate queue/notify interface). 208635863739SMike Smith */ 208735863739SMike Smith static int 2088f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 208935863739SMike Smith { 209035863739SMike Smith u_int32_t pi, ci; 20919e2e96d8SScott Long int error; 2092f6c4dd3fSScott Long u_int32_t fib_size; 2093f6c4dd3fSScott Long u_int32_t fib_addr; 2094f6c4dd3fSScott Long 209536e0bf6eSScott Long debug_called(3); 209636e0bf6eSScott Long 2097f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2098f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 209935863739SMike Smith 210035863739SMike Smith /* get the producer/consumer indices */ 210135863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 210235863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 210335863739SMike Smith 210435863739SMike Smith /* wrap the queue? */ 210535863739SMike Smith if (pi >= aac_qinfo[queue].size) 210635863739SMike Smith pi = 0; 210735863739SMike Smith 210835863739SMike Smith /* check for queue full */ 210935863739SMike Smith if ((pi + 1) == ci) { 211035863739SMike Smith error = EBUSY; 211135863739SMike Smith goto out; 211235863739SMike Smith } 211335863739SMike Smith 2114614c22b2SScott Long /* 2115614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2116614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2117614c22b2SScott Long */ 2118614c22b2SScott Long aac_enqueue_busy(cm); 2119614c22b2SScott Long 212035863739SMike Smith /* populate queue entry */ 212135863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 212235863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 212335863739SMike Smith 212435863739SMike Smith /* update producer index */ 212535863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 212635863739SMike Smith 212735863739SMike Smith /* notify the adapter if we know how */ 212835863739SMike Smith if (aac_qinfo[queue].notify != 0) 212935863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 213035863739SMike Smith 213135863739SMike Smith error = 0; 213235863739SMike Smith 213335863739SMike Smith out: 213435863739SMike Smith return(error); 213535863739SMike Smith } 213635863739SMike Smith 213735863739SMike Smith /* 213836e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 213936e0bf6eSScott Long * success or ENOENT if the queue is empty. 214035863739SMike Smith */ 214135863739SMike Smith static int 2142c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2143c6eafcf2SScott Long struct aac_fib **fib_addr) 214435863739SMike Smith { 214535863739SMike Smith u_int32_t pi, ci; 2146149af931SScott Long u_int32_t fib_index; 21479e2e96d8SScott Long int error; 2148f6c4dd3fSScott Long int notify; 214935863739SMike Smith 215035863739SMike Smith debug_called(3); 215135863739SMike Smith 215235863739SMike Smith /* get the producer/consumer indices */ 215335863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 215435863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 215535863739SMike Smith 215635863739SMike Smith /* check for queue empty */ 215735863739SMike Smith if (ci == pi) { 215835863739SMike Smith error = ENOENT; 215935863739SMike Smith goto out; 216035863739SMike Smith } 216135863739SMike Smith 21627753acd2SScott Long /* wrap the pi so the following test works */ 21637753acd2SScott Long if (pi >= aac_qinfo[queue].size) 21647753acd2SScott Long pi = 0; 21657753acd2SScott Long 2166f6c4dd3fSScott Long notify = 0; 2167f6c4dd3fSScott Long if (ci == pi + 1) 2168f6c4dd3fSScott Long notify++; 2169f6c4dd3fSScott Long 217035863739SMike Smith /* wrap the queue? */ 217135863739SMike Smith if (ci >= aac_qinfo[queue].size) 217235863739SMike Smith ci = 0; 217335863739SMike Smith 217435863739SMike Smith /* fetch the entry */ 217535863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2176149af931SScott Long 2177149af931SScott Long switch (queue) { 2178149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2179149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2180149af931SScott Long /* 2181149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2182149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2183149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2184149af931SScott Long * Therefore, we have to convert it to an index. 2185149af931SScott Long */ 2186149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2187149af931SScott Long sizeof(struct aac_fib); 2188149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2189149af931SScott Long break; 2190149af931SScott Long 2191149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2192149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2193149af931SScott Long { 2194149af931SScott Long struct aac_command *cm; 2195149af931SScott Long 2196149af931SScott Long /* 2197149af931SScott Long * As above, an index is used instead of an actual address. 2198149af931SScott Long * Gotta shift the index to account for the fast response 2199149af931SScott Long * bit. No other correction is needed since this value was 2200149af931SScott Long * originally provided by the driver via the SenderFibAddress 2201149af931SScott Long * field. 2202149af931SScott Long */ 2203149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 22047cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2205149af931SScott Long *fib_addr = cm->cm_fib; 220635863739SMike Smith 2207f30ac74cSScott Long /* 2208f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2209149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2210f30ac74cSScott Long */ 2211149af931SScott Long if (fib_index & 0x01) { 2212f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2213f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2214f30ac74cSScott Long } 2215149af931SScott Long break; 2216149af931SScott Long } 2217149af931SScott Long default: 2218149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2219149af931SScott Long break; 2220149af931SScott Long } 2221149af931SScott Long 222235863739SMike Smith /* update consumer index */ 222335863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 222435863739SMike Smith 222535863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2226f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 222735863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 222835863739SMike Smith error = 0; 222935863739SMike Smith 223035863739SMike Smith out: 223135863739SMike Smith return(error); 223235863739SMike Smith } 223335863739SMike Smith 2234914da7d0SScott Long /* 223536e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 223636e0bf6eSScott Long */ 223736e0bf6eSScott Long static int 223836e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 223936e0bf6eSScott Long { 224036e0bf6eSScott Long u_int32_t pi, ci; 22419e2e96d8SScott Long int error; 224236e0bf6eSScott Long u_int32_t fib_size; 224336e0bf6eSScott Long u_int32_t fib_addr; 224436e0bf6eSScott Long 224536e0bf6eSScott Long debug_called(1); 224636e0bf6eSScott Long 224736e0bf6eSScott Long /* Tell the adapter where the FIB is */ 224836e0bf6eSScott Long fib_size = fib->Header.Size; 224936e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 225036e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 225136e0bf6eSScott Long 225236e0bf6eSScott Long /* get the producer/consumer indices */ 225336e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 225436e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 225536e0bf6eSScott Long 225636e0bf6eSScott Long /* wrap the queue? */ 225736e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 225836e0bf6eSScott Long pi = 0; 225936e0bf6eSScott Long 226036e0bf6eSScott Long /* check for queue full */ 226136e0bf6eSScott Long if ((pi + 1) == ci) { 226236e0bf6eSScott Long error = EBUSY; 226336e0bf6eSScott Long goto out; 226436e0bf6eSScott Long } 226536e0bf6eSScott Long 226636e0bf6eSScott Long /* populate queue entry */ 226736e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 226836e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 226936e0bf6eSScott Long 227036e0bf6eSScott Long /* update producer index */ 227136e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 227236e0bf6eSScott Long 227336e0bf6eSScott Long /* notify the adapter if we know how */ 227436e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 227536e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 227636e0bf6eSScott Long 227736e0bf6eSScott Long error = 0; 227836e0bf6eSScott Long 227936e0bf6eSScott Long out: 228036e0bf6eSScott Long return(error); 228136e0bf6eSScott Long } 228236e0bf6eSScott Long 2283914da7d0SScott Long /* 22840b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 22850b94a66eSMike Smith * and complain about them. 22860b94a66eSMike Smith */ 22870b94a66eSMike Smith static void 22880b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 22890b94a66eSMike Smith { 22900b94a66eSMike Smith struct aac_command *cm; 22910b94a66eSMike Smith time_t deadline; 229215c37be0SScott Long int timedout, code; 22930b94a66eSMike Smith 2294f6c4dd3fSScott Long /* 229570545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2296914da7d0SScott Long * only. 2297914da7d0SScott Long */ 229815c37be0SScott Long timedout = 0; 22992b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 23000b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2301f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2302f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 23030b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2304914da7d0SScott Long device_printf(sc->aac_dev, 2305914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 23062b3b0f17SScott Long cm, (int)(time_uptime-cm->cm_timestamp)); 23070b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 230815c37be0SScott Long timedout++; 23090b94a66eSMike Smith } 23100b94a66eSMike Smith } 23110b94a66eSMike Smith 231215c37be0SScott Long if (timedout) { 231315c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 231415c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 231515c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 231615c37be0SScott Long "longer running! code= 0x%x\n", code); 231715c37be0SScott Long } 231815c37be0SScott Long } 23190b94a66eSMike Smith return; 23200b94a66eSMike Smith } 23210b94a66eSMike Smith 2322914da7d0SScott Long /* 2323914da7d0SScott Long * Interface Function Vectors 2324914da7d0SScott Long */ 232535863739SMike Smith 2326914da7d0SScott Long /* 232735863739SMike Smith * Read the current firmware status word. 232835863739SMike Smith */ 232935863739SMike Smith static int 233035863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 233135863739SMike Smith { 233235863739SMike Smith debug_called(3); 233335863739SMike Smith 233435863739SMike Smith return(AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 233535863739SMike Smith } 233635863739SMike Smith 233735863739SMike Smith static int 233835863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 233935863739SMike Smith { 234035863739SMike Smith debug_called(3); 234135863739SMike Smith 234235863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 234335863739SMike Smith } 234435863739SMike Smith 2345b3457b51SScott Long static int 2346b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2347b3457b51SScott Long { 2348b3457b51SScott Long int val; 2349b3457b51SScott Long 2350b3457b51SScott Long debug_called(3); 2351b3457b51SScott Long 2352b3457b51SScott Long val = AAC_GETREG4(sc, AAC_FA_FWSTATUS); 2353b3457b51SScott Long return (val); 2354b3457b51SScott Long } 2355b3457b51SScott Long 23564afedc31SScott Long static int 23574afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 23584afedc31SScott Long { 23594afedc31SScott Long debug_called(3); 23604afedc31SScott Long 23614afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); 23624afedc31SScott Long } 23634afedc31SScott Long 2364914da7d0SScott Long /* 236535863739SMike Smith * Notify the controller of a change in a given queue 236635863739SMike Smith */ 236735863739SMike Smith 236835863739SMike Smith static void 236935863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 237035863739SMike Smith { 237135863739SMike Smith debug_called(3); 237235863739SMike Smith 237335863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 237435863739SMike Smith } 237535863739SMike Smith 237635863739SMike Smith static void 237735863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 237835863739SMike Smith { 237935863739SMike Smith debug_called(3); 238035863739SMike Smith 238135863739SMike Smith AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 238235863739SMike Smith } 238335863739SMike Smith 2384b3457b51SScott Long static void 2385b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2386b3457b51SScott Long { 2387b3457b51SScott Long debug_called(3); 2388b3457b51SScott Long 2389b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2390b3457b51SScott Long AAC_FA_HACK(sc); 2391b3457b51SScott Long } 2392b3457b51SScott Long 23934afedc31SScott Long static void 23944afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 23954afedc31SScott Long { 23964afedc31SScott Long debug_called(3); 23974afedc31SScott Long 23984afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); 23994afedc31SScott Long } 24004afedc31SScott Long 2401914da7d0SScott Long /* 240235863739SMike Smith * Get the interrupt reason bits 240335863739SMike Smith */ 240435863739SMike Smith static int 240535863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 240635863739SMike Smith { 240735863739SMike Smith debug_called(3); 240835863739SMike Smith 240935863739SMike Smith return(AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 241035863739SMike Smith } 241135863739SMike Smith 241235863739SMike Smith static int 241335863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 241435863739SMike Smith { 241535863739SMike Smith debug_called(3); 241635863739SMike Smith 241735863739SMike Smith return(AAC_GETREG4(sc, AAC_RX_ODBR)); 241835863739SMike Smith } 241935863739SMike Smith 2420b3457b51SScott Long static int 2421b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2422b3457b51SScott Long { 2423b3457b51SScott Long int val; 2424b3457b51SScott Long 2425b3457b51SScott Long debug_called(3); 2426b3457b51SScott Long 2427b3457b51SScott Long val = AAC_GETREG2(sc, AAC_FA_DOORBELL0); 2428b3457b51SScott Long return (val); 2429b3457b51SScott Long } 2430b3457b51SScott Long 24314afedc31SScott Long static int 24324afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 24334afedc31SScott Long { 24344afedc31SScott Long debug_called(3); 24354afedc31SScott Long 24364afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_ODBR)); 24374afedc31SScott Long } 24384afedc31SScott Long 2439914da7d0SScott Long /* 244035863739SMike Smith * Clear some interrupt reason bits 244135863739SMike Smith */ 244235863739SMike Smith static void 244335863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 244435863739SMike Smith { 244535863739SMike Smith debug_called(3); 244635863739SMike Smith 244735863739SMike Smith AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 244835863739SMike Smith } 244935863739SMike Smith 245035863739SMike Smith static void 245135863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 245235863739SMike Smith { 245335863739SMike Smith debug_called(3); 245435863739SMike Smith 245535863739SMike Smith AAC_SETREG4(sc, AAC_RX_ODBR, mask); 245635863739SMike Smith } 245735863739SMike Smith 2458b3457b51SScott Long static void 2459b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2460b3457b51SScott Long { 2461b3457b51SScott Long debug_called(3); 2462b3457b51SScott Long 2463b3457b51SScott Long AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2464b3457b51SScott Long AAC_FA_HACK(sc); 2465b3457b51SScott Long } 2466b3457b51SScott Long 24674afedc31SScott Long static void 24684afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 24694afedc31SScott Long { 24704afedc31SScott Long debug_called(3); 24714afedc31SScott Long 24724afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_ODBR, mask); 24734afedc31SScott Long } 24744afedc31SScott Long 2475914da7d0SScott Long /* 247635863739SMike Smith * Populate the mailbox and set the command word 247735863739SMike Smith */ 247835863739SMike Smith static void 247935863739SMike Smith aac_sa_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_SA_MAILBOX, command); 248535863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 248635863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 248735863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 248835863739SMike Smith AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 248935863739SMike Smith } 249035863739SMike Smith 249135863739SMike Smith static void 249235863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 249335863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 249435863739SMike Smith { 249535863739SMike Smith debug_called(4); 249635863739SMike Smith 249735863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 249835863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 249935863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 250035863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 250135863739SMike Smith AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 250235863739SMike Smith } 250335863739SMike Smith 2504b3457b51SScott Long static void 2505b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2506b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2507b3457b51SScott Long { 2508b3457b51SScott Long debug_called(4); 2509b3457b51SScott Long 2510b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX, command); 2511b3457b51SScott Long AAC_FA_HACK(sc); 2512b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2513b3457b51SScott Long AAC_FA_HACK(sc); 2514b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2515b3457b51SScott Long AAC_FA_HACK(sc); 2516b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2517b3457b51SScott Long AAC_FA_HACK(sc); 2518b3457b51SScott Long AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2519b3457b51SScott Long AAC_FA_HACK(sc); 2520b3457b51SScott Long } 2521b3457b51SScott Long 25224afedc31SScott Long static void 25234afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25244afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 25254afedc31SScott Long { 25264afedc31SScott Long debug_called(4); 25274afedc31SScott Long 25284afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); 25294afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 25304afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 25314afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 25324afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 25334afedc31SScott Long } 25344afedc31SScott Long 2535914da7d0SScott Long /* 253635863739SMike Smith * Fetch the immediate command status word 253735863739SMike Smith */ 253835863739SMike Smith static int 2539a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 254035863739SMike Smith { 254135863739SMike Smith debug_called(4); 254235863739SMike Smith 2543a6d35632SScott Long return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 254435863739SMike Smith } 254535863739SMike Smith 254635863739SMike Smith static int 2547a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 254835863739SMike Smith { 254935863739SMike Smith debug_called(4); 255035863739SMike Smith 2551a6d35632SScott Long return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 255235863739SMike Smith } 255335863739SMike Smith 2554b3457b51SScott Long static int 2555a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2556b3457b51SScott Long { 2557b3457b51SScott Long int val; 2558b3457b51SScott Long 2559b3457b51SScott Long debug_called(4); 2560b3457b51SScott Long 2561a6d35632SScott Long val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2562b3457b51SScott Long return (val); 2563b3457b51SScott Long } 2564b3457b51SScott Long 25654afedc31SScott Long static int 25664afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 25674afedc31SScott Long { 25684afedc31SScott Long debug_called(4); 25694afedc31SScott Long 25704afedc31SScott Long return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 25714afedc31SScott Long } 25724afedc31SScott Long 2573914da7d0SScott Long /* 257435863739SMike Smith * Set/clear interrupt masks 257535863739SMike Smith */ 257635863739SMike Smith static void 257735863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 257835863739SMike Smith { 257935863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 258035863739SMike Smith 258135863739SMike Smith if (enable) { 258235863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 258335863739SMike Smith } else { 258435863739SMike Smith AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 258535863739SMike Smith } 258635863739SMike Smith } 258735863739SMike Smith 258835863739SMike Smith static void 258935863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 259035863739SMike Smith { 259135863739SMike Smith debug(2, "%sable interrupts", enable ? "en" : "dis"); 259235863739SMike Smith 259335863739SMike Smith if (enable) { 25947cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 25957cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 25967cb209f5SScott Long else 259735863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 259835863739SMike Smith } else { 259935863739SMike Smith AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 260035863739SMike Smith } 260135863739SMike Smith } 260235863739SMike Smith 2603b3457b51SScott Long static void 2604b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2605b3457b51SScott Long { 2606b3457b51SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 2607b3457b51SScott Long 2608b3457b51SScott Long if (enable) { 2609b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2610b3457b51SScott Long AAC_FA_HACK(sc); 2611b3457b51SScott Long } else { 2612b3457b51SScott Long AAC_SETREG2((sc), AAC_FA_MASK0, ~0); 2613b3457b51SScott Long AAC_FA_HACK(sc); 2614b3457b51SScott Long } 2615b3457b51SScott Long } 2616b3457b51SScott Long 26174afedc31SScott Long static void 26184afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 26194afedc31SScott Long { 26204afedc31SScott Long debug(2, "%sable interrupts", enable ? "en" : "dis"); 26214afedc31SScott Long 26224afedc31SScott Long if (enable) { 26237cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 26247cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 26257cb209f5SScott Long else 26264afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 26274afedc31SScott Long } else { 26284afedc31SScott Long AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); 26294afedc31SScott Long } 26304afedc31SScott Long } 26314afedc31SScott Long 2632914da7d0SScott Long /* 26337cb209f5SScott Long * New comm. interface: Send command functions 26347cb209f5SScott Long */ 26357cb209f5SScott Long static int 26367cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 26377cb209f5SScott Long { 26387cb209f5SScott Long u_int32_t index, device; 26397cb209f5SScott Long 26407cb209f5SScott Long debug(2, "send command (new comm.)"); 26417cb209f5SScott Long 26427cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RX_IQUE); 26437cb209f5SScott Long if (index == 0xffffffffL) 26447cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RX_IQUE); 26457cb209f5SScott Long if (index == 0xffffffffL) 26467cb209f5SScott Long return index; 26477cb209f5SScott Long aac_enqueue_busy(cm); 26487cb209f5SScott Long device = index; 26497cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26507cb209f5SScott Long device += 4; 26517cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26527cb209f5SScott Long device += 4; 26537cb209f5SScott Long AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 26547cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_IQUE, index); 26557cb209f5SScott Long return 0; 26567cb209f5SScott Long } 26577cb209f5SScott Long 26587cb209f5SScott Long static int 26597cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 26607cb209f5SScott Long { 26617cb209f5SScott Long u_int32_t index, device; 26627cb209f5SScott Long 26637cb209f5SScott Long debug(2, "send command (new comm.)"); 26647cb209f5SScott Long 26657cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RKT_IQUE); 26667cb209f5SScott Long if (index == 0xffffffffL) 26677cb209f5SScott Long index = AAC_GETREG4(sc, AAC_RKT_IQUE); 26687cb209f5SScott Long if (index == 0xffffffffL) 26697cb209f5SScott Long return index; 26707cb209f5SScott Long aac_enqueue_busy(cm); 26717cb209f5SScott Long device = index; 26727cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 26737cb209f5SScott Long device += 4; 26747cb209f5SScott Long AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 26757cb209f5SScott Long device += 4; 26767cb209f5SScott Long AAC_SETREG4(sc, device, cm->cm_fib->Header.Size); 26777cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_IQUE, index); 26787cb209f5SScott Long return 0; 26797cb209f5SScott Long } 26807cb209f5SScott Long 26817cb209f5SScott Long /* 26827cb209f5SScott Long * New comm. interface: get, set outbound queue index 26837cb209f5SScott Long */ 26847cb209f5SScott Long static int 26857cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 26867cb209f5SScott Long { 26877cb209f5SScott Long debug_called(3); 26887cb209f5SScott Long 26897cb209f5SScott Long return(AAC_GETREG4(sc, AAC_RX_OQUE)); 26907cb209f5SScott Long } 26917cb209f5SScott Long 26927cb209f5SScott Long static int 26937cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 26947cb209f5SScott Long { 26957cb209f5SScott Long debug_called(3); 26967cb209f5SScott Long 26977cb209f5SScott Long return(AAC_GETREG4(sc, AAC_RKT_OQUE)); 26987cb209f5SScott Long } 26997cb209f5SScott Long 27007cb209f5SScott Long static void 27017cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 27027cb209f5SScott Long { 27037cb209f5SScott Long debug_called(3); 27047cb209f5SScott Long 27057cb209f5SScott Long AAC_SETREG4(sc, AAC_RX_OQUE, index); 27067cb209f5SScott Long } 27077cb209f5SScott Long 27087cb209f5SScott Long static void 27097cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 27107cb209f5SScott Long { 27117cb209f5SScott Long debug_called(3); 27127cb209f5SScott Long 27137cb209f5SScott Long AAC_SETREG4(sc, AAC_RKT_OQUE, index); 27147cb209f5SScott Long } 27157cb209f5SScott Long 27167cb209f5SScott Long /* 2717914da7d0SScott Long * Debugging and Diagnostics 2718914da7d0SScott Long */ 271935863739SMike Smith 2720914da7d0SScott Long /* 272135863739SMike Smith * Print some information about the controller. 272235863739SMike Smith */ 272335863739SMike Smith static void 272435863739SMike Smith aac_describe_controller(struct aac_softc *sc) 272535863739SMike Smith { 2726cbfd045bSScott Long struct aac_fib *fib; 272735863739SMike Smith struct aac_adapter_info *info; 272835863739SMike Smith 272935863739SMike Smith debug_called(2); 273035863739SMike Smith 273181b3da08SScott Long mtx_lock(&sc->aac_io_lock); 273203b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2733cbfd045bSScott Long 2734cbfd045bSScott Long fib->data[0] = 0; 2735cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 273635863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2737fe3cb0e1SScott Long aac_release_sync_fib(sc); 273881b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 273935863739SMike Smith return; 274035863739SMike Smith } 274135863739SMike Smith 2742bd971c49SScott Long /* save the kernel revision structure for later use */ 2743bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2744bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2745bd971c49SScott Long 27467cb209f5SScott Long device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n", 27477cb209f5SScott Long AAC_DRIVER_VERSION >> 24, 27487cb209f5SScott Long (AAC_DRIVER_VERSION >> 16) & 0xFF, 27497cb209f5SScott Long AAC_DRIVER_VERSION & 0xFF, 27507cb209f5SScott Long AAC_DRIVER_BUILD); 27517cb209f5SScott Long 2752bd971c49SScott Long if (bootverbose) { 2753b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2754b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2755c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2756b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2757b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2758b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2759914da7d0SScott Long aac_describe_code(aac_battery_platform, 2760914da7d0SScott Long info->batteryPlatform)); 276135863739SMike Smith 2762bd971c49SScott Long device_printf(sc->aac_dev, 2763bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 276435863739SMike Smith info->KernelRevision.external.comp.major, 276535863739SMike Smith info->KernelRevision.external.comp.minor, 276635863739SMike Smith info->KernelRevision.external.comp.dash, 276736e0bf6eSScott Long info->KernelRevision.buildNumber, 276836e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2769fe3cb0e1SScott Long 2770a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2771a6d35632SScott Long sc->supported_options, 2772a6d35632SScott Long "\20" 2773a6d35632SScott Long "\1SNAPSHOT" 2774a6d35632SScott Long "\2CLUSTERS" 2775a6d35632SScott Long "\3WCACHE" 2776a6d35632SScott Long "\4DATA64" 2777a6d35632SScott Long "\5HOSTTIME" 2778a6d35632SScott Long "\6RAID50" 2779a6d35632SScott Long "\7WINDOW4GB" 2780a6d35632SScott Long "\10SCSIUPGD" 2781a6d35632SScott Long "\11SOFTERR" 2782a6d35632SScott Long "\12NORECOND" 2783a6d35632SScott Long "\13SGMAP64" 2784a6d35632SScott Long "\14ALARM" 27857cb209f5SScott Long "\15NONDASD" 27867cb209f5SScott Long "\16SCSIMGT" 27877cb209f5SScott Long "\17RAIDSCSI" 27887cb209f5SScott Long "\21ADPTINFO" 27897cb209f5SScott Long "\22NEWCOMM" 27907cb209f5SScott Long "\23ARRAY64BIT" 27917cb209f5SScott Long "\24HEATSENSOR"); 2792a6d35632SScott Long } 2793bd971c49SScott Long aac_release_sync_fib(sc); 279481b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 279535863739SMike Smith } 279635863739SMike Smith 2797914da7d0SScott Long /* 279835863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 279935863739SMike Smith * same. 280035863739SMike Smith */ 280135863739SMike Smith static char * 280235863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 280335863739SMike Smith { 280435863739SMike Smith int i; 280535863739SMike Smith 280635863739SMike Smith for (i = 0; table[i].string != NULL; i++) 280735863739SMike Smith if (table[i].code == code) 280835863739SMike Smith return(table[i].string); 280935863739SMike Smith return(table[i + 1].string); 281035863739SMike Smith } 281135863739SMike Smith 2812914da7d0SScott Long /* 2813914da7d0SScott Long * Management Interface 2814914da7d0SScott Long */ 281535863739SMike Smith 281635863739SMike Smith static int 281789c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td) 281835863739SMike Smith { 2819914da7d0SScott Long struct aac_softc *sc; 282035863739SMike Smith 282135863739SMike Smith debug_called(2); 282235863739SMike Smith 2823914da7d0SScott Long sc = dev->si_drv1; 2824914da7d0SScott Long 282535863739SMike Smith /* Check to make sure the device isn't already open */ 282635863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) { 282735863739SMike Smith return EBUSY; 282835863739SMike Smith } 282935863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 283035863739SMike Smith 283135863739SMike Smith return 0; 283235863739SMike Smith } 283335863739SMike Smith 283435863739SMike Smith static int 283589c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 283635863739SMike Smith { 2837914da7d0SScott Long struct aac_softc *sc; 283835863739SMike Smith 283935863739SMike Smith debug_called(2); 284035863739SMike Smith 2841914da7d0SScott Long sc = dev->si_drv1; 2842914da7d0SScott Long 284335863739SMike Smith /* Mark this unit as no longer open */ 284435863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 284535863739SMike Smith 284635863739SMike Smith return 0; 284735863739SMike Smith } 284835863739SMike Smith 284935863739SMike Smith static int 285089c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) 285135863739SMike Smith { 2852914da7d0SScott Long union aac_statrequest *as; 2853914da7d0SScott Long struct aac_softc *sc; 28540b94a66eSMike Smith int error = 0; 2855b88ffdc8SScott Long uint32_t cookie; 285635863739SMike Smith 285735863739SMike Smith debug_called(2); 285835863739SMike Smith 2859914da7d0SScott Long as = (union aac_statrequest *)arg; 2860914da7d0SScott Long sc = dev->si_drv1; 2861914da7d0SScott Long 286235863739SMike Smith switch (cmd) { 28630b94a66eSMike Smith case AACIO_STATS: 28640b94a66eSMike Smith switch (as->as_item) { 28650b94a66eSMike Smith case AACQ_FREE: 28660b94a66eSMike Smith case AACQ_BIO: 28670b94a66eSMike Smith case AACQ_READY: 28680b94a66eSMike Smith case AACQ_BUSY: 2869c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2870c6eafcf2SScott Long sizeof(struct aac_qstat)); 28710b94a66eSMike Smith break; 28720b94a66eSMike Smith default: 28730b94a66eSMike Smith error = ENOENT; 28740b94a66eSMike Smith break; 28750b94a66eSMike Smith } 28760b94a66eSMike Smith break; 28770b94a66eSMike Smith 287835863739SMike Smith case FSACTL_SENDFIB: 2879fb0c27d7SScott Long arg = *(caddr_t*)arg; 2880fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 28810b94a66eSMike Smith debug(1, "FSACTL_SENDFIB"); 288235863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 288335863739SMike Smith break; 288435863739SMike Smith case FSACTL_AIF_THREAD: 2885fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 28860b94a66eSMike Smith debug(1, "FSACTL_AIF_THREAD"); 288735863739SMike Smith error = EINVAL; 288835863739SMike Smith break; 288935863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2890fb0c27d7SScott Long arg = *(caddr_t*)arg; 2891fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 28920b94a66eSMike Smith debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB"); 289335863739SMike Smith /* 289435863739SMike Smith * Pass the caller out an AdapterFibContext. 289535863739SMike Smith * 289635863739SMike Smith * Note that because we only support one opener, we 289735863739SMike Smith * basically ignore this. Set the caller's context to a magic 289835863739SMike Smith * number just in case. 28990b94a66eSMike Smith * 29000b94a66eSMike Smith * The Linux code hands the driver a pointer into kernel space, 29010b94a66eSMike Smith * and then trusts it when the caller hands it back. Aiee! 2902914da7d0SScott Long * Here, we give it the proc pointer of the per-adapter aif 2903914da7d0SScott Long * thread. It's only used as a sanity check in other calls. 290435863739SMike Smith */ 2905b88ffdc8SScott Long cookie = (uint32_t)(uintptr_t)sc->aifthread; 2906b88ffdc8SScott Long error = copyout(&cookie, arg, sizeof(cookie)); 290735863739SMike Smith break; 290835863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2909fb0c27d7SScott Long arg = *(caddr_t*)arg; 2910fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 29110b94a66eSMike Smith debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2912fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 291335863739SMike Smith break; 291435863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2915fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 29160b94a66eSMike Smith debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 291735863739SMike Smith /* don't do anything here */ 291835863739SMike Smith break; 291935863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2920fb0c27d7SScott Long arg = *(caddr_t*)arg; 2921fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 29220b94a66eSMike Smith debug(1, "FSACTL_MINIPORT_REV_CHECK"); 2923fb0c27d7SScott Long error = aac_rev_check(sc, arg); 292435863739SMike Smith break; 292536e0bf6eSScott Long case FSACTL_QUERY_DISK: 292636e0bf6eSScott Long arg = *(caddr_t*)arg; 292736e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 292836e0bf6eSScott Long debug(1, "FSACTL_QUERY_DISK"); 292936e0bf6eSScott Long error = aac_query_disk(sc, arg); 293036e0bf6eSScott Long break; 293136e0bf6eSScott Long case FSACTL_DELETE_DISK: 293236e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 2933914da7d0SScott Long /* 2934914da7d0SScott Long * We don't trust the underland to tell us when to delete a 2935914da7d0SScott Long * container, rather we rely on an AIF coming from the 2936914da7d0SScott Long * controller 2937914da7d0SScott Long */ 293836e0bf6eSScott Long error = 0; 293936e0bf6eSScott Long break; 29407cb209f5SScott Long case FSACTL_GET_PCI_INFO: 29417cb209f5SScott Long arg = *(caddr_t*)arg; 29427cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 29437cb209f5SScott Long debug(1, "FSACTL_GET_PCI_INFO"); 29447cb209f5SScott Long error = aac_get_pci_info(sc, arg); 29457cb209f5SScott Long break; 294635863739SMike Smith default: 2947b3457b51SScott Long debug(1, "unsupported cmd 0x%lx\n", cmd); 294835863739SMike Smith error = EINVAL; 294935863739SMike Smith break; 295035863739SMike Smith } 295135863739SMike Smith return(error); 295235863739SMike Smith } 295335863739SMike Smith 2954b3457b51SScott Long static int 295589c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td) 2956b3457b51SScott Long { 2957b3457b51SScott Long struct aac_softc *sc; 2958b3457b51SScott Long int revents; 2959b3457b51SScott Long 2960b3457b51SScott Long sc = dev->si_drv1; 2961b3457b51SScott Long revents = 0; 2962b3457b51SScott Long 2963bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 2964b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 2965b3457b51SScott Long if (sc->aac_aifq_tail != sc->aac_aifq_head) 2966b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 2967b3457b51SScott Long } 2968bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 2969b3457b51SScott Long 2970b3457b51SScott Long if (revents == 0) { 2971b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 2972b3457b51SScott Long selrecord(td, &sc->rcv_select); 2973b3457b51SScott Long } 2974b3457b51SScott Long 2975b3457b51SScott Long return (revents); 2976b3457b51SScott Long } 2977b3457b51SScott Long 29787cb209f5SScott Long static void 29797cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 29807cb209f5SScott Long { 29817cb209f5SScott Long 29827cb209f5SScott Long switch (event->ev_type) { 29837cb209f5SScott Long case AAC_EVENT_CMFREE: 29847cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 29851a681311SLuoqi Chen if (aac_alloc_command(sc, (struct aac_command **)arg)) { 29867cb209f5SScott Long aac_add_event(sc, event); 29877cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 29887cb209f5SScott Long return; 29897cb209f5SScott Long } 29907cb209f5SScott Long free(event, M_AACBUF); 29918eeb2ca6SScott Long wakeup(arg); 29927cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 29937cb209f5SScott Long break; 29947cb209f5SScott Long default: 29957cb209f5SScott Long break; 29967cb209f5SScott Long } 29977cb209f5SScott Long } 29987cb209f5SScott Long 2999914da7d0SScott Long /* 300035863739SMike Smith * Send a FIB supplied from userspace 300135863739SMike Smith */ 300235863739SMike Smith static int 300335863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 300435863739SMike Smith { 300535863739SMike Smith struct aac_command *cm; 300635863739SMike Smith int size, error; 300735863739SMike Smith 300835863739SMike Smith debug_called(2); 300935863739SMike Smith 301035863739SMike Smith cm = NULL; 301135863739SMike Smith 301235863739SMike Smith /* 301335863739SMike Smith * Get a command 301435863739SMike Smith */ 3015bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 301635863739SMike Smith if (aac_alloc_command(sc, &cm)) { 30177cb209f5SScott Long struct aac_event *event; 30187cb209f5SScott Long 30197cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 30207cb209f5SScott Long M_NOWAIT | M_ZERO); 30217cb209f5SScott Long if (event == NULL) { 302235863739SMike Smith error = EBUSY; 302335863739SMike Smith goto out; 302435863739SMike Smith } 30257cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 30267cb209f5SScott Long event->ev_callback = aac_ioctl_event; 30277cb209f5SScott Long event->ev_arg = &cm; 30287cb209f5SScott Long aac_add_event(sc, event); 30298eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 30307cb209f5SScott Long } 303193cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 303235863739SMike Smith 303335863739SMike Smith /* 303435863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 303535863739SMike Smith */ 3036914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 3037914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 303835863739SMike Smith goto out; 303935863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 304035863739SMike Smith if (size > sizeof(struct aac_fib)) { 3041b88ffdc8SScott Long device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n", 3042914da7d0SScott Long size, sizeof(struct aac_fib)); 304335863739SMike Smith size = sizeof(struct aac_fib); 304435863739SMike Smith } 304535863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 304635863739SMike Smith goto out; 304735863739SMike Smith cm->cm_fib->Header.Size = size; 30482b3b0f17SScott Long cm->cm_timestamp = time_uptime; 304935863739SMike Smith 305035863739SMike Smith /* 305135863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 305235863739SMike Smith */ 305393cfca22SScott Long mtx_lock(&sc->aac_io_lock); 3054d8a0a473SScott Long if ((error = aac_wait_command(cm)) != 0) { 305570545d1aSScott Long device_printf(sc->aac_dev, 305670545d1aSScott Long "aac_wait_command return %d\n", error); 305735863739SMike Smith goto out; 3058b3457b51SScott Long } 305993cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 306035863739SMike Smith 306135863739SMike Smith /* 306235863739SMike Smith * Copy the FIB and data back out to the caller. 306335863739SMike Smith */ 306435863739SMike Smith size = cm->cm_fib->Header.Size; 306535863739SMike Smith if (size > sizeof(struct aac_fib)) { 3066b88ffdc8SScott Long device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n", 3067914da7d0SScott Long size, sizeof(struct aac_fib)); 306835863739SMike Smith size = sizeof(struct aac_fib); 306935863739SMike Smith } 307035863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 307193cfca22SScott Long mtx_lock(&sc->aac_io_lock); 307235863739SMike Smith 307335863739SMike Smith out: 3074f6c4dd3fSScott Long if (cm != NULL) { 307535863739SMike Smith aac_release_command(cm); 3076f6c4dd3fSScott Long } 3077ae543596SScott Long 3078bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 307935863739SMike Smith return(error); 308035863739SMike Smith } 308135863739SMike Smith 3082914da7d0SScott Long /* 308335863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 308436e0bf6eSScott Long * If the queue fills up, then drop the older entries. 308535863739SMike Smith */ 308635863739SMike Smith static void 308736e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 308835863739SMike Smith { 308936e0bf6eSScott Long struct aac_aif_command *aif; 309036e0bf6eSScott Long struct aac_container *co, *co_next; 3091cbfd045bSScott Long struct aac_mntinfo *mi; 3092cbfd045bSScott Long struct aac_mntinforesp *mir = NULL; 309336e0bf6eSScott Long u_int16_t rsize; 3094b3457b51SScott Long int next, found; 3095795d7dc0SScott Long int count = 0, added = 0, i = 0; 309635863739SMike Smith 309735863739SMike Smith debug_called(2); 309835863739SMike Smith 309936e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 310036e0bf6eSScott Long aac_print_aif(sc, aif); 310136e0bf6eSScott Long 310236e0bf6eSScott Long /* Is it an event that we should care about? */ 310336e0bf6eSScott Long switch (aif->command) { 310436e0bf6eSScott Long case AifCmdEventNotify: 310536e0bf6eSScott Long switch (aif->data.EN.type) { 310636e0bf6eSScott Long case AifEnAddContainer: 310736e0bf6eSScott Long case AifEnDeleteContainer: 310836e0bf6eSScott Long /* 3109914da7d0SScott Long * A container was added or deleted, but the message 3110914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3111914da7d0SScott Long * containers and sort things out. 311236e0bf6eSScott Long */ 311303b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3114cbfd045bSScott Long mi = (struct aac_mntinfo *)&fib->data[0]; 311536e0bf6eSScott Long do { 311636e0bf6eSScott Long /* 3117914da7d0SScott Long * Ask the controller for its containers one at 3118914da7d0SScott Long * a time. 3119914da7d0SScott Long * XXX What if the controller's list changes 3120914da7d0SScott Long * midway through this enumaration? 312136e0bf6eSScott Long * XXX This should be done async. 312236e0bf6eSScott Long */ 312339ee03c3SScott Long bzero(mi, sizeof(struct aac_mntinfo)); 312439ee03c3SScott Long mi->Command = VM_NameServe; 312539ee03c3SScott Long mi->MntType = FT_FILESYS; 3126cbfd045bSScott Long mi->MntCount = i; 312736e0bf6eSScott Long rsize = sizeof(mir); 3128cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 3129cbfd045bSScott Long sizeof(struct aac_mntinfo))) { 3130795d7dc0SScott Long printf("Error probing container %d\n", 3131914da7d0SScott Long i); 313236e0bf6eSScott Long continue; 313336e0bf6eSScott Long } 3134cbfd045bSScott Long mir = (struct aac_mntinforesp *)&fib->data[0]; 3135795d7dc0SScott Long /* XXX Need to check if count changed */ 3136795d7dc0SScott Long count = mir->MntRespCount; 313736e0bf6eSScott Long /* 3138914da7d0SScott Long * Check the container against our list. 3139914da7d0SScott Long * co->co_found was already set to 0 in a 3140914da7d0SScott Long * previous run. 314136e0bf6eSScott Long */ 3142cbfd045bSScott Long if ((mir->Status == ST_OK) && 3143cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 314436e0bf6eSScott Long found = 0; 3145914da7d0SScott Long TAILQ_FOREACH(co, 3146914da7d0SScott Long &sc->aac_container_tqh, 3147914da7d0SScott Long co_link) { 314836e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3149cbfd045bSScott Long mir->MntTable[0].ObjectId) { 315036e0bf6eSScott Long co->co_found = 1; 315136e0bf6eSScott Long found = 1; 315236e0bf6eSScott Long break; 315336e0bf6eSScott Long } 315436e0bf6eSScott Long } 3155914da7d0SScott Long /* 3156914da7d0SScott Long * If the container matched, continue 3157914da7d0SScott Long * in the list. 3158914da7d0SScott Long */ 315936e0bf6eSScott Long if (found) { 316036e0bf6eSScott Long i++; 316136e0bf6eSScott Long continue; 316236e0bf6eSScott Long } 316336e0bf6eSScott Long 316436e0bf6eSScott Long /* 3165914da7d0SScott Long * This is a new container. Do all the 316670545d1aSScott Long * appropriate things to set it up. 316770545d1aSScott Long */ 3168cbfd045bSScott Long aac_add_container(sc, mir, 1); 316936e0bf6eSScott Long added = 1; 317036e0bf6eSScott Long } 317136e0bf6eSScott Long i++; 3172795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3173cbfd045bSScott Long aac_release_sync_fib(sc); 317436e0bf6eSScott Long 317536e0bf6eSScott Long /* 3176914da7d0SScott Long * Go through our list of containers and see which ones 3177914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3178914da7d0SScott Long * list them they must have been deleted. Do the 3179914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3180914da7d0SScott Long * the co->co_found field. 318136e0bf6eSScott Long */ 318236e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 318336e0bf6eSScott Long while (co != NULL) { 318436e0bf6eSScott Long if (co->co_found == 0) { 31857cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 31867cb209f5SScott Long mtx_lock(&Giant); 3187914da7d0SScott Long device_delete_child(sc->aac_dev, 3188914da7d0SScott Long co->co_disk); 31897cb209f5SScott Long mtx_unlock(&Giant); 31907cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 319136e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3192bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3193914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3194914da7d0SScott Long co_link); 3195bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3196ba1d57e7SScott Long free(co, M_AACBUF); 319736e0bf6eSScott Long co = co_next; 319836e0bf6eSScott Long } else { 319936e0bf6eSScott Long co->co_found = 0; 320036e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 320136e0bf6eSScott Long } 320236e0bf6eSScott Long } 320336e0bf6eSScott Long 320436e0bf6eSScott Long /* Attach the newly created containers */ 32057cb209f5SScott Long if (added) { 32067cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 32077cb209f5SScott Long mtx_lock(&Giant); 320836e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 32097cb209f5SScott Long mtx_unlock(&Giant); 32107cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 32117cb209f5SScott Long } 321236e0bf6eSScott Long 321336e0bf6eSScott Long break; 321436e0bf6eSScott Long 321536e0bf6eSScott Long default: 321636e0bf6eSScott Long break; 321736e0bf6eSScott Long } 321836e0bf6eSScott Long 321936e0bf6eSScott Long default: 322036e0bf6eSScott Long break; 322136e0bf6eSScott Long } 322236e0bf6eSScott Long 322336e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3224bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 322535863739SMike Smith next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH; 322635863739SMike Smith if (next != sc->aac_aifq_tail) { 322735863739SMike Smith bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command)); 322835863739SMike Smith sc->aac_aifq_head = next; 3229b3457b51SScott Long 3230b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 323135863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 323235863739SMike Smith wakeup(sc->aac_aifq); 3233b3457b51SScott Long /* Wakeup any poll()ers */ 3234512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 323535863739SMike Smith } 3236bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 323736e0bf6eSScott Long 323836e0bf6eSScott Long return; 323935863739SMike Smith } 324035863739SMike Smith 3241914da7d0SScott Long /* 32420b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 324336e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 324436e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 324536e0bf6eSScott Long * returning what the card reported. 324635863739SMike Smith */ 324735863739SMike Smith static int 3248fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 324935863739SMike Smith { 325035863739SMike Smith struct aac_rev_check rev_check; 325135863739SMike Smith struct aac_rev_check_resp rev_check_resp; 325235863739SMike Smith int error = 0; 325335863739SMike Smith 325435863739SMike Smith debug_called(2); 325535863739SMike Smith 325635863739SMike Smith /* 325735863739SMike Smith * Copyin the revision struct from userspace 325835863739SMike Smith */ 3259c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3260c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 326135863739SMike Smith return error; 326235863739SMike Smith } 326335863739SMike Smith 3264914da7d0SScott Long debug(2, "Userland revision= %d\n", 3265914da7d0SScott Long rev_check.callingRevision.buildNumber); 326635863739SMike Smith 326735863739SMike Smith /* 326835863739SMike Smith * Doctor up the response struct. 326935863739SMike Smith */ 327035863739SMike Smith rev_check_resp.possiblyCompatible = 1; 3271914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 3272914da7d0SScott Long sc->aac_revision.external.ul; 3273914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 3274914da7d0SScott Long sc->aac_revision.buildNumber; 327535863739SMike Smith 3276c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3277c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 327835863739SMike Smith } 327935863739SMike Smith 3280914da7d0SScott Long /* 328135863739SMike Smith * Pass the caller the next AIF in their queue 328235863739SMike Smith */ 328335863739SMike Smith static int 3284fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 328535863739SMike Smith { 328635863739SMike Smith struct get_adapter_fib_ioctl agf; 32879e2e96d8SScott Long int error; 328835863739SMike Smith 328935863739SMike Smith debug_called(2); 329035863739SMike Smith 329135863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 329235863739SMike Smith 329335863739SMike Smith /* 329435863739SMike Smith * Check the magic number that we gave the caller. 329535863739SMike Smith */ 3296b88ffdc8SScott Long if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) { 329735863739SMike Smith error = EFAULT; 329835863739SMike Smith } else { 3299fb0c27d7SScott Long error = aac_return_aif(sc, agf.AifFib); 330035863739SMike Smith if ((error == EAGAIN) && (agf.Wait)) { 330135863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 330235863739SMike Smith while (error == EAGAIN) { 3303914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3304914da7d0SScott Long PCATCH, "aacaif", 0); 330535863739SMike Smith if (error == 0) 3306914da7d0SScott Long error = aac_return_aif(sc, 3307914da7d0SScott Long agf.AifFib); 330835863739SMike Smith } 330935863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 331035863739SMike Smith } 331135863739SMike Smith } 331235863739SMike Smith } 331335863739SMike Smith return(error); 331435863739SMike Smith } 331535863739SMike Smith 3316914da7d0SScott Long /* 33170b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 33180b94a66eSMike Smith */ 33190b94a66eSMike Smith static int 3320fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr) 33210b94a66eSMike Smith { 33223df780cfSScott Long int next, error; 33230b94a66eSMike Smith 33240b94a66eSMike Smith debug_called(2); 33250b94a66eSMike Smith 3326bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 33270b94a66eSMike Smith if (sc->aac_aifq_tail == sc->aac_aifq_head) { 3328bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 33293df780cfSScott Long return (EAGAIN); 33303df780cfSScott Long } 33313df780cfSScott Long 33323df780cfSScott Long next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH; 33333df780cfSScott Long error = copyout(&sc->aac_aifq[next], uptr, 3334c6eafcf2SScott Long sizeof(struct aac_aif_command)); 333536e0bf6eSScott Long if (error) 333670545d1aSScott Long device_printf(sc->aac_dev, 333770545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 33383df780cfSScott Long else 33393df780cfSScott Long sc->aac_aifq_tail = next; 33403df780cfSScott Long 3341bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 33420b94a66eSMike Smith return(error); 33430b94a66eSMike Smith } 334436e0bf6eSScott Long 33457cb209f5SScott Long static int 33467cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 33477cb209f5SScott Long { 33487cb209f5SScott Long struct aac_pci_info { 33497cb209f5SScott Long u_int32_t bus; 33507cb209f5SScott Long u_int32_t slot; 33517cb209f5SScott Long } pciinf; 33527cb209f5SScott Long int error; 33537cb209f5SScott Long 33547cb209f5SScott Long debug_called(2); 33557cb209f5SScott Long 33567cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 33577cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 33587cb209f5SScott Long 33597cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 33607cb209f5SScott Long sizeof(struct aac_pci_info)); 33617cb209f5SScott Long 33627cb209f5SScott Long return (error); 33637cb209f5SScott Long } 33647cb209f5SScott Long 3365914da7d0SScott Long /* 336636e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 336736e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 336836e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 336936e0bf6eSScott Long */ 337036e0bf6eSScott Long static int 337136e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 337236e0bf6eSScott Long { 337336e0bf6eSScott Long struct aac_query_disk query_disk; 337436e0bf6eSScott Long struct aac_container *co; 3375914da7d0SScott Long struct aac_disk *disk; 337636e0bf6eSScott Long int error, id; 337736e0bf6eSScott Long 337836e0bf6eSScott Long debug_called(2); 337936e0bf6eSScott Long 3380914da7d0SScott Long disk = NULL; 3381914da7d0SScott Long 3382914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3383914da7d0SScott Long sizeof(struct aac_query_disk)); 338436e0bf6eSScott Long if (error) 338536e0bf6eSScott Long return (error); 338636e0bf6eSScott Long 338736e0bf6eSScott Long id = query_disk.ContainerNumber; 338836e0bf6eSScott Long if (id == -1) 338936e0bf6eSScott Long return (EINVAL); 339036e0bf6eSScott Long 3391bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 339236e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 339336e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 339436e0bf6eSScott Long break; 339536e0bf6eSScott Long } 339636e0bf6eSScott Long 339736e0bf6eSScott Long if (co == NULL) { 339836e0bf6eSScott Long query_disk.Valid = 0; 339936e0bf6eSScott Long query_disk.Locked = 0; 340036e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 340136e0bf6eSScott Long } else { 340236e0bf6eSScott Long disk = device_get_softc(co->co_disk); 340336e0bf6eSScott Long query_disk.Valid = 1; 3404914da7d0SScott Long query_disk.Locked = 3405914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 340636e0bf6eSScott Long query_disk.Deleted = 0; 3407b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 340836e0bf6eSScott Long query_disk.Target = disk->unit; 340936e0bf6eSScott Long query_disk.Lun = 0; 341036e0bf6eSScott Long query_disk.UnMapped = 0; 34117540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 34120b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 341336e0bf6eSScott Long } 3414bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 341536e0bf6eSScott Long 3416914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3417914da7d0SScott Long sizeof(struct aac_query_disk)); 341836e0bf6eSScott Long 341936e0bf6eSScott Long return (error); 342036e0bf6eSScott Long } 342136e0bf6eSScott Long 3422fe3cb0e1SScott Long static void 3423fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3424fe3cb0e1SScott Long { 3425fe3cb0e1SScott Long struct aac_fib *fib; 3426fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3427fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3428fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3429fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3430fe3cb0e1SScott Long struct aac_getbusinf businfo; 343170545d1aSScott Long struct aac_sim *caminf; 3432fe3cb0e1SScott Long device_t child; 3433fe3cb0e1SScott Long int i, found, error; 3434fe3cb0e1SScott Long 34351ffe41c1SChristian S.J. Peron mtx_lock(&sc->aac_io_lock); 343603b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3437fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 343839ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3439fe3cb0e1SScott Long 3440fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3441fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3442fe3cb0e1SScott Long c_cmd->param = 0; 3443fe3cb0e1SScott Long 3444fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3445fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3446fe3cb0e1SScott Long if (error) { 3447fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3448fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3449fe3cb0e1SScott Long aac_release_sync_fib(sc); 34501ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3451fe3cb0e1SScott Long return; 3452fe3cb0e1SScott Long } 3453fe3cb0e1SScott Long 3454fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3455fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3456fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3457fe3cb0e1SScott Long c_resp->Status); 3458fe3cb0e1SScott Long aac_release_sync_fib(sc); 34591ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3460fe3cb0e1SScott Long return; 3461fe3cb0e1SScott Long } 3462fe3cb0e1SScott Long 3463fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3464fe3cb0e1SScott Long 3465fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 346639ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 346739ee03c3SScott Long 3468fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3469fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3470fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3471fe3cb0e1SScott Long vmi->ObjId = 0; 3472fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3473fe3cb0e1SScott Long 3474fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3475fe3cb0e1SScott Long sizeof(struct aac_vmioctl)); 3476fe3cb0e1SScott Long if (error) { 3477fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3478fe3cb0e1SScott Long error); 3479fe3cb0e1SScott Long aac_release_sync_fib(sc); 34801ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3481fe3cb0e1SScott Long return; 3482fe3cb0e1SScott Long } 3483fe3cb0e1SScott Long 3484fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3485fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3486fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3487fe3cb0e1SScott Long vmi_resp->Status); 3488fe3cb0e1SScott Long aac_release_sync_fib(sc); 34891ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3490fe3cb0e1SScott Long return; 3491fe3cb0e1SScott Long } 3492fe3cb0e1SScott Long 3493fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3494fe3cb0e1SScott Long aac_release_sync_fib(sc); 34951ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3496fe3cb0e1SScott Long 3497fe3cb0e1SScott Long found = 0; 3498fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3499fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3500fe3cb0e1SScott Long continue; 3501fe3cb0e1SScott Long 3502a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3503a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3504b5f516cdSScott Long if (caminf == NULL) { 3505b5f516cdSScott Long device_printf(sc->aac_dev, 3506b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3507b5f516cdSScott Long break; 35087cb209f5SScott Long }; 3509fe3cb0e1SScott Long 3510fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3511fe3cb0e1SScott Long if (child == NULL) { 3512b5f516cdSScott Long device_printf(sc->aac_dev, 3513b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3514b5f516cdSScott Long i); 3515b5f516cdSScott Long free(caminf, M_AACBUF); 3516b5f516cdSScott Long break; 3517fe3cb0e1SScott Long } 3518fe3cb0e1SScott Long 3519fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3520fe3cb0e1SScott Long caminf->BusNumber = i; 3521fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3522fe3cb0e1SScott Long caminf->aac_sc = sc; 3523ddb8683eSScott Long caminf->sim_dev = child; 3524fe3cb0e1SScott Long 3525fe3cb0e1SScott Long device_set_ivars(child, caminf); 3526fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 352770545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3528fe3cb0e1SScott Long 3529fe3cb0e1SScott Long found = 1; 3530fe3cb0e1SScott Long } 3531fe3cb0e1SScott Long 3532fe3cb0e1SScott Long if (found) 3533fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3534fe3cb0e1SScott Long 3535fe3cb0e1SScott Long return; 3536fe3cb0e1SScott Long } 3537