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); 74ff0991c4SAttilio Rao static void aac_daemon(void *arg); 7535863739SMike Smith 7635863739SMike Smith /* Command Processing */ 770b94a66eSMike Smith static void aac_timeout(struct aac_softc *sc); 7835863739SMike Smith static void aac_complete(void *context, int pending); 7935863739SMike Smith static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); 8035863739SMike Smith static void aac_bio_complete(struct aac_command *cm); 81d8a0a473SScott Long static int aac_wait_command(struct aac_command *cm); 8270545d1aSScott Long static void aac_command_thread(struct aac_softc *sc); 8335863739SMike Smith 8435863739SMike Smith /* Command Buffer Management */ 85cd481291SScott Long static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, 86cd481291SScott Long int nseg, int error); 87c6eafcf2SScott Long static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, 88c6eafcf2SScott Long int nseg, int error); 890b94a66eSMike Smith static int aac_alloc_commands(struct aac_softc *sc); 908480cc63SScott Long static void aac_free_commands(struct aac_softc *sc); 9135863739SMike Smith static void aac_unmap_command(struct aac_command *cm); 9235863739SMike Smith 9335863739SMike Smith /* Hardware Interface */ 9404f4d586SEd Maste static int aac_alloc(struct aac_softc *sc); 95c6eafcf2SScott Long static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, 96c6eafcf2SScott Long int error); 97fe94b852SScott Long static int aac_check_firmware(struct aac_softc *sc); 9835863739SMike Smith static int aac_init(struct aac_softc *sc); 9935863739SMike Smith static int aac_sync_command(struct aac_softc *sc, u_int32_t command, 100c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 101c6eafcf2SScott Long u_int32_t arg3, u_int32_t *sp); 10204f4d586SEd Maste static int aac_setup_intr(struct aac_softc *sc); 103c6eafcf2SScott Long static int aac_enqueue_fib(struct aac_softc *sc, int queue, 104f6c4dd3fSScott Long struct aac_command *cm); 105c6eafcf2SScott Long static int aac_dequeue_fib(struct aac_softc *sc, int queue, 106914da7d0SScott Long u_int32_t *fib_size, struct aac_fib **fib_addr); 10736e0bf6eSScott Long static int aac_enqueue_response(struct aac_softc *sc, int queue, 10836e0bf6eSScott Long struct aac_fib *fib); 10935863739SMike Smith 110b3457b51SScott Long /* Falcon/PPC interface */ 111b3457b51SScott Long static int aac_fa_get_fwstatus(struct aac_softc *sc); 112b3457b51SScott Long static void aac_fa_qnotify(struct aac_softc *sc, int qbit); 113b3457b51SScott Long static int aac_fa_get_istatus(struct aac_softc *sc); 114b3457b51SScott Long static void aac_fa_clear_istatus(struct aac_softc *sc, int mask); 115b3457b51SScott Long static void aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 116b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, 117b3457b51SScott Long u_int32_t arg2, u_int32_t arg3); 118a6d35632SScott Long static int aac_fa_get_mailbox(struct aac_softc *sc, int mb); 119b3457b51SScott Long static void aac_fa_set_interrupts(struct aac_softc *sc, int enable); 120b3457b51SScott Long 121b3457b51SScott Long struct aac_interface aac_fa_interface = { 122b3457b51SScott Long aac_fa_get_fwstatus, 123b3457b51SScott Long aac_fa_qnotify, 124b3457b51SScott Long aac_fa_get_istatus, 125b3457b51SScott Long aac_fa_clear_istatus, 126b3457b51SScott Long aac_fa_set_mailbox, 127a6d35632SScott Long aac_fa_get_mailbox, 1287cb209f5SScott Long aac_fa_set_interrupts, 1297cb209f5SScott Long NULL, NULL, NULL 130b3457b51SScott Long }; 131b3457b51SScott Long 13235863739SMike Smith /* StrongARM interface */ 13335863739SMike Smith static int aac_sa_get_fwstatus(struct aac_softc *sc); 13435863739SMike Smith static void aac_sa_qnotify(struct aac_softc *sc, int qbit); 13535863739SMike Smith static int aac_sa_get_istatus(struct aac_softc *sc); 13635863739SMike Smith static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); 13735863739SMike Smith static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 138c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 139c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 140a6d35632SScott Long static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); 14135863739SMike Smith static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); 14235863739SMike Smith 14335863739SMike Smith struct aac_interface aac_sa_interface = { 14435863739SMike Smith aac_sa_get_fwstatus, 14535863739SMike Smith aac_sa_qnotify, 14635863739SMike Smith aac_sa_get_istatus, 14735863739SMike Smith aac_sa_clear_istatus, 14835863739SMike Smith aac_sa_set_mailbox, 149a6d35632SScott Long aac_sa_get_mailbox, 1507cb209f5SScott Long aac_sa_set_interrupts, 1517cb209f5SScott Long NULL, NULL, NULL 15235863739SMike Smith }; 15335863739SMike Smith 15435863739SMike Smith /* i960Rx interface */ 15535863739SMike Smith static int aac_rx_get_fwstatus(struct aac_softc *sc); 15635863739SMike Smith static void aac_rx_qnotify(struct aac_softc *sc, int qbit); 15735863739SMike Smith static int aac_rx_get_istatus(struct aac_softc *sc); 15835863739SMike Smith static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); 15935863739SMike Smith static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 160c6eafcf2SScott Long u_int32_t arg0, u_int32_t arg1, 161c6eafcf2SScott Long u_int32_t arg2, u_int32_t arg3); 162a6d35632SScott Long static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); 16335863739SMike Smith static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); 1647cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); 1657cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc); 1667cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); 16735863739SMike Smith 16835863739SMike Smith struct aac_interface aac_rx_interface = { 16935863739SMike Smith aac_rx_get_fwstatus, 17035863739SMike Smith aac_rx_qnotify, 17135863739SMike Smith aac_rx_get_istatus, 17235863739SMike Smith aac_rx_clear_istatus, 17335863739SMike Smith aac_rx_set_mailbox, 174a6d35632SScott Long aac_rx_get_mailbox, 1757cb209f5SScott Long aac_rx_set_interrupts, 1767cb209f5SScott Long aac_rx_send_command, 1777cb209f5SScott Long aac_rx_get_outb_queue, 1787cb209f5SScott Long aac_rx_set_outb_queue 17935863739SMike Smith }; 18035863739SMike Smith 1814afedc31SScott Long /* Rocket/MIPS interface */ 1824afedc31SScott Long static int aac_rkt_get_fwstatus(struct aac_softc *sc); 1834afedc31SScott Long static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); 1844afedc31SScott Long static int aac_rkt_get_istatus(struct aac_softc *sc); 1854afedc31SScott Long static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); 1864afedc31SScott Long static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, 1874afedc31SScott Long u_int32_t arg0, u_int32_t arg1, 1884afedc31SScott Long u_int32_t arg2, u_int32_t arg3); 1894afedc31SScott Long static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); 1904afedc31SScott Long static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); 1917cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); 1927cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc); 1937cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); 1944afedc31SScott Long 1954afedc31SScott Long struct aac_interface aac_rkt_interface = { 1964afedc31SScott Long aac_rkt_get_fwstatus, 1974afedc31SScott Long aac_rkt_qnotify, 1984afedc31SScott Long aac_rkt_get_istatus, 1994afedc31SScott Long aac_rkt_clear_istatus, 2004afedc31SScott Long aac_rkt_set_mailbox, 2014afedc31SScott Long aac_rkt_get_mailbox, 2027cb209f5SScott Long aac_rkt_set_interrupts, 2037cb209f5SScott Long aac_rkt_send_command, 2047cb209f5SScott Long aac_rkt_get_outb_queue, 2057cb209f5SScott Long aac_rkt_set_outb_queue 2064afedc31SScott Long }; 2074afedc31SScott Long 20835863739SMike Smith /* Debugging and Diagnostics */ 20935863739SMike Smith static void aac_describe_controller(struct aac_softc *sc); 2106965a493SScott Long static char *aac_describe_code(struct aac_code_lookup *table, 211c6eafcf2SScott Long u_int32_t code); 21235863739SMike Smith 21335863739SMike Smith /* Management Interface */ 21435863739SMike Smith static d_open_t aac_open; 21535863739SMike Smith static d_close_t aac_close; 21635863739SMike Smith static d_ioctl_t aac_ioctl; 217b3457b51SScott Long static d_poll_t aac_poll; 218c6eafcf2SScott Long static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); 219f355c0e0SEd Maste static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); 220c6eafcf2SScott Long static void aac_handle_aif(struct aac_softc *sc, 22136e0bf6eSScott Long struct aac_fib *fib); 222fb0c27d7SScott Long static int aac_rev_check(struct aac_softc *sc, caddr_t udata); 223a723a548SEd Maste static int aac_open_aif(struct aac_softc *sc, caddr_t arg); 224a723a548SEd Maste static int aac_close_aif(struct aac_softc *sc, caddr_t arg); 225fb0c27d7SScott Long static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); 226a723a548SEd Maste static int aac_return_aif(struct aac_softc *sc, 227a723a548SEd Maste struct aac_fib_context *ctx, caddr_t uptr); 22836e0bf6eSScott Long static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); 2297cb209f5SScott Long static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); 2306d307336SEd Maste static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); 2317cb209f5SScott Long static void aac_ioctl_event(struct aac_softc *sc, 2327cb209f5SScott Long struct aac_event *event, void *arg); 23304f4d586SEd Maste static struct aac_mntinforesp * 23404f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); 23535863739SMike Smith 23635863739SMike Smith static struct cdevsw aac_cdevsw = { 237dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 238dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 2397ac40f5fSPoul-Henning Kamp .d_open = aac_open, 2407ac40f5fSPoul-Henning Kamp .d_close = aac_close, 2417ac40f5fSPoul-Henning Kamp .d_ioctl = aac_ioctl, 2427ac40f5fSPoul-Henning Kamp .d_poll = aac_poll, 2437ac40f5fSPoul-Henning Kamp .d_name = "aac", 24435863739SMike Smith }; 24535863739SMike Smith 24636e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); 24736e0bf6eSScott Long 2483d04a9d7SScott Long /* sysctl node */ 2493d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); 2503d04a9d7SScott Long 251914da7d0SScott Long /* 252914da7d0SScott Long * Device Interface 253914da7d0SScott Long */ 25435863739SMike Smith 255914da7d0SScott Long /* 2564109ba51SEd Maste * Initialize the controller and softc 25735863739SMike Smith */ 25835863739SMike Smith int 25935863739SMike Smith aac_attach(struct aac_softc *sc) 26035863739SMike Smith { 26135863739SMike Smith int error, unit; 26235863739SMike Smith 26331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26435863739SMike Smith 26535863739SMike Smith /* 2664109ba51SEd Maste * Initialize per-controller queues. 26735863739SMike Smith */ 2680b94a66eSMike Smith aac_initq_free(sc); 2690b94a66eSMike Smith aac_initq_ready(sc); 2700b94a66eSMike Smith aac_initq_busy(sc); 2710b94a66eSMike Smith aac_initq_bio(sc); 27235863739SMike Smith 27335863739SMike Smith /* 2744109ba51SEd Maste * Initialize command-completion task. 27535863739SMike Smith */ 27635863739SMike Smith TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); 27735863739SMike Smith 27835863739SMike Smith /* mark controller as suspended until we get ourselves organised */ 27935863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 28035863739SMike Smith 28135863739SMike Smith /* 282fe94b852SScott Long * Check that the firmware on the card is supported. 283fe94b852SScott Long */ 284fe94b852SScott Long if ((error = aac_check_firmware(sc)) != 0) 285fe94b852SScott Long return(error); 286fe94b852SScott Long 287f6b1c44dSScott Long /* 288f6b1c44dSScott Long * Initialize locks 289f6b1c44dSScott Long */ 290bb6fe253SScott Long mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF); 291bb6fe253SScott Long mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF); 292bb6fe253SScott Long mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF); 293f6b1c44dSScott Long TAILQ_INIT(&sc->aac_container_tqh); 294065dd78cSScott Long TAILQ_INIT(&sc->aac_ev_cmfree); 295f6b1c44dSScott Long 296ff0991c4SAttilio Rao /* Initialize the clock daemon callout. */ 297ff0991c4SAttilio Rao callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0); 298ff0991c4SAttilio Rao 2990b94a66eSMike Smith /* 3004109ba51SEd Maste * Initialize the adapter. 30135863739SMike Smith */ 30204f4d586SEd Maste if ((error = aac_alloc(sc)) != 0) 30304f4d586SEd Maste return(error); 3040b94a66eSMike Smith if ((error = aac_init(sc)) != 0) 30535863739SMike Smith return(error); 30635863739SMike Smith 30735863739SMike Smith /* 3087cb209f5SScott Long * Allocate and connect our interrupt. 3097cb209f5SScott Long */ 31004f4d586SEd Maste if ((error = aac_setup_intr(sc)) != 0) 31104f4d586SEd Maste return(error); 3127cb209f5SScott Long 3137cb209f5SScott Long /* 31435863739SMike Smith * Print a little information about the controller. 31535863739SMike Smith */ 31635863739SMike Smith aac_describe_controller(sc); 31735863739SMike Smith 31835863739SMike Smith /* 319ae543596SScott Long * Register to probe our containers later. 320ae543596SScott Long */ 32135863739SMike Smith sc->aac_ich.ich_func = aac_startup; 32235863739SMike Smith sc->aac_ich.ich_arg = sc; 32335863739SMike Smith if (config_intrhook_establish(&sc->aac_ich) != 0) { 324914da7d0SScott Long device_printf(sc->aac_dev, 325914da7d0SScott Long "can't establish configuration hook\n"); 32635863739SMike Smith return(ENXIO); 32735863739SMike Smith } 32835863739SMike Smith 32935863739SMike Smith /* 33035863739SMike Smith * Make the control device. 33135863739SMike Smith */ 33235863739SMike Smith unit = device_get_unit(sc->aac_dev); 3339e9466baSRobert Watson sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR, 3349e9466baSRobert Watson 0640, "aac%d", unit); 335157fbb2eSScott Long (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); 3364aa620cdSScott Long (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); 33735863739SMike Smith sc->aac_dev_t->si_drv1 = sc; 33835863739SMike Smith 33936e0bf6eSScott Long /* Create the AIF thread */ 3403745c395SJulian Elischer if (kproc_create((void(*)(void *))aac_command_thread, sc, 341316ec49aSScott Long &sc->aifthread, 0, 0, "aac%daif", unit)) 342a620bad0SEd Maste panic("Could not create AIF thread"); 34336e0bf6eSScott Long 34436e0bf6eSScott Long /* Register the shutdown method to only be called post-dump */ 3455f54d522SScott Long if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, 3465f54d522SScott Long sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) 3475f54d522SScott Long device_printf(sc->aac_dev, 3485f54d522SScott Long "shutdown event registration failed\n"); 34936e0bf6eSScott Long 350fe3cb0e1SScott Long /* Register with CAM for the non-DASD devices */ 351a6d35632SScott Long if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { 35270545d1aSScott Long TAILQ_INIT(&sc->aac_sim_tqh); 353fe3cb0e1SScott Long aac_get_bus_info(sc); 35470545d1aSScott Long } 355fe3cb0e1SScott Long 356ff0991c4SAttilio Rao mtx_lock(&sc->aac_io_lock); 357867b1d34SEd Maste callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); 358ff0991c4SAttilio Rao mtx_unlock(&sc->aac_io_lock); 359ff0991c4SAttilio Rao 36035863739SMike Smith return(0); 36135863739SMike Smith } 36235863739SMike Smith 363ff0991c4SAttilio Rao static void 364ff0991c4SAttilio Rao aac_daemon(void *arg) 365ff0991c4SAttilio Rao { 366ff0991c4SAttilio Rao struct timeval tv; 367ff0991c4SAttilio Rao struct aac_softc *sc; 368ff0991c4SAttilio Rao struct aac_fib *fib; 369ff0991c4SAttilio Rao 370ff0991c4SAttilio Rao sc = arg; 371ff0991c4SAttilio Rao mtx_assert(&sc->aac_io_lock, MA_OWNED); 372ff0991c4SAttilio Rao 373ff0991c4SAttilio Rao if (callout_pending(&sc->aac_daemontime) || 374ff0991c4SAttilio Rao callout_active(&sc->aac_daemontime) == 0) 375ff0991c4SAttilio Rao return; 376ff0991c4SAttilio Rao getmicrotime(&tv); 377ff0991c4SAttilio Rao aac_alloc_sync_fib(sc, &fib); 378ff0991c4SAttilio Rao *(uint32_t *)fib->data = tv.tv_sec; 379ff0991c4SAttilio Rao aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); 380ff0991c4SAttilio Rao aac_release_sync_fib(sc); 381ff0991c4SAttilio Rao callout_schedule(&sc->aac_daemontime, 30 * 60 * hz); 382ff0991c4SAttilio Rao } 383ff0991c4SAttilio Rao 3847cb209f5SScott Long void 3857cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event) 3867cb209f5SScott Long { 3877cb209f5SScott Long 3887cb209f5SScott Long switch (event->ev_type & AAC_EVENT_MASK) { 3897cb209f5SScott Long case AAC_EVENT_CMFREE: 3907cb209f5SScott Long TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); 3917cb209f5SScott Long break; 3927cb209f5SScott Long default: 3937cb209f5SScott Long device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", 3947cb209f5SScott Long event->ev_type); 3957cb209f5SScott Long break; 3967cb209f5SScott Long } 3977cb209f5SScott Long 3987cb209f5SScott Long return; 3997cb209f5SScott Long } 4007cb209f5SScott Long 401914da7d0SScott Long /* 40204f4d586SEd Maste * Request information of container #cid 40304f4d586SEd Maste */ 40404f4d586SEd Maste static struct aac_mntinforesp * 40504f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) 40604f4d586SEd Maste { 40704f4d586SEd Maste struct aac_mntinfo *mi; 40804f4d586SEd Maste 40904f4d586SEd Maste mi = (struct aac_mntinfo *)&fib->data[0]; 410523da39bSEd Maste /* use 64-bit LBA if enabled */ 411523da39bSEd Maste mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? 412523da39bSEd Maste VM_NameServe64 : VM_NameServe; 41304f4d586SEd Maste mi->MntType = FT_FILESYS; 41404f4d586SEd Maste mi->MntCount = cid; 41504f4d586SEd Maste 41604f4d586SEd Maste if (aac_sync_fib(sc, ContainerCommand, 0, fib, 41704f4d586SEd Maste sizeof(struct aac_mntinfo))) { 418a620bad0SEd Maste printf("Error probing container %d\n", cid); 41904f4d586SEd Maste return (NULL); 42004f4d586SEd Maste } 42104f4d586SEd Maste 42204f4d586SEd Maste return ((struct aac_mntinforesp *)&fib->data[0]); 42304f4d586SEd Maste } 42404f4d586SEd Maste 42504f4d586SEd Maste /* 42635863739SMike Smith * Probe for containers, create disks. 42735863739SMike Smith */ 42835863739SMike Smith static void 42935863739SMike Smith aac_startup(void *arg) 43035863739SMike Smith { 431914da7d0SScott Long struct aac_softc *sc; 432cbfd045bSScott Long struct aac_fib *fib; 43304f4d586SEd Maste struct aac_mntinforesp *mir; 434795d7dc0SScott Long int count = 0, i = 0; 43535863739SMike Smith 436914da7d0SScott Long sc = (struct aac_softc *)arg; 43731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 438914da7d0SScott Long 43935863739SMike Smith /* disconnect ourselves from the intrhook chain */ 44035863739SMike Smith config_intrhook_disestablish(&sc->aac_ich); 44135863739SMike Smith 4427cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 44303b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 444cbfd045bSScott Long 44535863739SMike Smith /* loop over possible containers */ 44636e0bf6eSScott Long do { 44704f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 44835863739SMike Smith continue; 44904f4d586SEd Maste if (i == 0) 450795d7dc0SScott Long count = mir->MntRespCount; 451cbfd045bSScott Long aac_add_container(sc, mir, 0); 45236e0bf6eSScott Long i++; 453795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 454cbfd045bSScott Long 455cbfd045bSScott Long aac_release_sync_fib(sc); 4567cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 45735863739SMike Smith 45835863739SMike Smith /* poke the bus to actually attach the child devices */ 45935863739SMike Smith if (bus_generic_attach(sc->aac_dev)) 46035863739SMike Smith device_printf(sc->aac_dev, "bus_generic_attach failed\n"); 46135863739SMike Smith 46235863739SMike Smith /* mark the controller up */ 46335863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 46435863739SMike Smith 46535863739SMike Smith /* enable interrupts now */ 46635863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 46735863739SMike Smith } 46835863739SMike Smith 469914da7d0SScott Long /* 4704109ba51SEd Maste * Create a device to represent a new container 471914da7d0SScott Long */ 472914da7d0SScott Long static void 473cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) 474914da7d0SScott Long { 475914da7d0SScott Long struct aac_container *co; 476914da7d0SScott Long device_t child; 477914da7d0SScott Long 478914da7d0SScott Long /* 479914da7d0SScott Long * Check container volume type for validity. Note that many of 480914da7d0SScott Long * the possible types may never show up. 481914da7d0SScott Long */ 482914da7d0SScott Long if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { 483a761a1caSScott Long co = (struct aac_container *)malloc(sizeof *co, M_AACBUF, 484a761a1caSScott Long M_NOWAIT | M_ZERO); 485914da7d0SScott Long if (co == NULL) 486a620bad0SEd Maste panic("Out of memory?!"); 48731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", 488914da7d0SScott Long mir->MntTable[0].ObjectId, 489914da7d0SScott Long mir->MntTable[0].FileSystemName, 490914da7d0SScott Long mir->MntTable[0].Capacity, mir->MntTable[0].VolType); 491914da7d0SScott Long 492fe3cb0e1SScott Long if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) 493914da7d0SScott Long device_printf(sc->aac_dev, "device_add_child failed\n"); 494914da7d0SScott Long else 495914da7d0SScott Long device_set_ivars(child, co); 496914da7d0SScott Long device_set_desc(child, aac_describe_code(aac_container_types, 497914da7d0SScott Long mir->MntTable[0].VolType)); 498914da7d0SScott Long co->co_disk = child; 499914da7d0SScott Long co->co_found = f; 500914da7d0SScott Long bcopy(&mir->MntTable[0], &co->co_mntobj, 501914da7d0SScott Long sizeof(struct aac_mntobj)); 502bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 503914da7d0SScott Long TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); 504bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 505914da7d0SScott Long } 506914da7d0SScott Long } 507914da7d0SScott Long 508914da7d0SScott Long /* 50904f4d586SEd Maste * Allocate resources associated with (sc) 51004f4d586SEd Maste */ 51104f4d586SEd Maste static int 51204f4d586SEd Maste aac_alloc(struct aac_softc *sc) 51304f4d586SEd Maste { 51431a0399eSEd Maste 51531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 51631a0399eSEd Maste 51704f4d586SEd Maste /* 51804f4d586SEd Maste * Create DMA tag for mapping buffers into controller-addressable space. 51904f4d586SEd Maste */ 52004f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 52104f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 52204f4d586SEd Maste (sc->flags & AAC_FLAGS_SG_64BIT) ? 52304f4d586SEd Maste BUS_SPACE_MAXADDR : 52404f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 52504f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 52604f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 52704f4d586SEd Maste MAXBSIZE, /* maxsize */ 52804f4d586SEd Maste sc->aac_sg_tablesize, /* nsegments */ 52904f4d586SEd Maste MAXBSIZE, /* maxsegsize */ 53004f4d586SEd Maste BUS_DMA_ALLOCNOW, /* flags */ 53104f4d586SEd Maste busdma_lock_mutex, /* lockfunc */ 53204f4d586SEd Maste &sc->aac_io_lock, /* lockfuncarg */ 53304f4d586SEd Maste &sc->aac_buffer_dmat)) { 53404f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); 53504f4d586SEd Maste return (ENOMEM); 53604f4d586SEd Maste } 53704f4d586SEd Maste 53804f4d586SEd Maste /* 53904f4d586SEd Maste * Create DMA tag for mapping FIBs into controller-addressable space.. 54004f4d586SEd Maste */ 54104f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 54204f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 54304f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 54404f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 54504f4d586SEd Maste 0x7fffffff, /* lowaddr */ 54604f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 54704f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 54804f4d586SEd Maste sc->aac_max_fibs_alloc * 54904f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 55004f4d586SEd Maste 1, /* nsegments */ 55104f4d586SEd Maste sc->aac_max_fibs_alloc * 55204f4d586SEd Maste sc->aac_max_fib_size, /* maxsize */ 55304f4d586SEd Maste 0, /* flags */ 55404f4d586SEd Maste NULL, NULL, /* No locking needed */ 55504f4d586SEd Maste &sc->aac_fib_dmat)) { 55604f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");; 55704f4d586SEd Maste return (ENOMEM); 55804f4d586SEd Maste } 55904f4d586SEd Maste 56004f4d586SEd Maste /* 56104f4d586SEd Maste * Create DMA tag for the common structure and allocate it. 56204f4d586SEd Maste */ 56304f4d586SEd Maste if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ 56404f4d586SEd Maste 1, 0, /* algnmnt, boundary */ 56504f4d586SEd Maste (sc->flags & AAC_FLAGS_4GB_WINDOW) ? 56604f4d586SEd Maste BUS_SPACE_MAXADDR_32BIT : 56704f4d586SEd Maste 0x7fffffff, /* lowaddr */ 56804f4d586SEd Maste BUS_SPACE_MAXADDR, /* highaddr */ 56904f4d586SEd Maste NULL, NULL, /* filter, filterarg */ 57004f4d586SEd Maste 8192 + sizeof(struct aac_common), /* maxsize */ 57104f4d586SEd Maste 1, /* nsegments */ 57204f4d586SEd Maste BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 57304f4d586SEd Maste 0, /* flags */ 57404f4d586SEd Maste NULL, NULL, /* No locking needed */ 57504f4d586SEd Maste &sc->aac_common_dmat)) { 57604f4d586SEd Maste device_printf(sc->aac_dev, 57704f4d586SEd Maste "can't allocate common structure DMA tag\n"); 57804f4d586SEd Maste return (ENOMEM); 57904f4d586SEd Maste } 58004f4d586SEd Maste if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, 58104f4d586SEd Maste BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { 58204f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate common structure\n"); 58304f4d586SEd Maste return (ENOMEM); 58404f4d586SEd Maste } 58504f4d586SEd Maste 58604f4d586SEd Maste /* 58704f4d586SEd Maste * Work around a bug in the 2120 and 2200 that cannot DMA commands 58804f4d586SEd Maste * below address 8192 in physical memory. 58904f4d586SEd Maste * XXX If the padding is not needed, can it be put to use instead 59004f4d586SEd Maste * of ignored? 59104f4d586SEd Maste */ 59204f4d586SEd Maste (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, 59304f4d586SEd Maste sc->aac_common, 8192 + sizeof(*sc->aac_common), 59404f4d586SEd Maste aac_common_map, sc, 0); 59504f4d586SEd Maste 59604f4d586SEd Maste if (sc->aac_common_busaddr < 8192) { 59704f4d586SEd Maste sc->aac_common = (struct aac_common *) 59804f4d586SEd Maste ((uint8_t *)sc->aac_common + 8192); 59904f4d586SEd Maste sc->aac_common_busaddr += 8192; 60004f4d586SEd Maste } 60104f4d586SEd Maste bzero(sc->aac_common, sizeof(*sc->aac_common)); 60204f4d586SEd Maste 60304f4d586SEd Maste /* Allocate some FIBs and associated command structs */ 60404f4d586SEd Maste TAILQ_INIT(&sc->aac_fibmap_tqh); 60504f4d586SEd Maste sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command), 60604f4d586SEd Maste M_AACBUF, M_WAITOK|M_ZERO); 60704f4d586SEd Maste while (sc->total_fibs < AAC_PREALLOCATE_FIBS) { 60804f4d586SEd Maste if (aac_alloc_commands(sc) != 0) 60904f4d586SEd Maste break; 61004f4d586SEd Maste } 61104f4d586SEd Maste if (sc->total_fibs == 0) 61204f4d586SEd Maste return (ENOMEM); 61304f4d586SEd Maste 61404f4d586SEd Maste return (0); 61504f4d586SEd Maste } 61604f4d586SEd Maste 61704f4d586SEd Maste /* 61835863739SMike Smith * Free all of the resources associated with (sc) 61935863739SMike Smith * 62035863739SMike Smith * Should not be called if the controller is active. 62135863739SMike Smith */ 62235863739SMike Smith void 62335863739SMike Smith aac_free(struct aac_softc *sc) 62435863739SMike Smith { 625ffb37f33SScott Long 62631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 62735863739SMike Smith 62835863739SMike Smith /* remove the control device */ 62935863739SMike Smith if (sc->aac_dev_t != NULL) 63035863739SMike Smith destroy_dev(sc->aac_dev_t); 63135863739SMike Smith 6320b94a66eSMike Smith /* throw away any FIB buffers, discard the FIB DMA tag */ 6338480cc63SScott Long aac_free_commands(sc); 6340b94a66eSMike Smith if (sc->aac_fib_dmat) 6350b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_fib_dmat); 63635863739SMike Smith 637ffb37f33SScott Long free(sc->aac_commands, M_AACBUF); 638ffb37f33SScott Long 63935863739SMike Smith /* destroy the common area */ 64035863739SMike Smith if (sc->aac_common) { 64135863739SMike Smith bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); 642c6eafcf2SScott Long bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, 643c6eafcf2SScott Long sc->aac_common_dmamap); 64435863739SMike Smith } 6450b94a66eSMike Smith if (sc->aac_common_dmat) 6460b94a66eSMike Smith bus_dma_tag_destroy(sc->aac_common_dmat); 64735863739SMike Smith 64835863739SMike Smith /* disconnect the interrupt handler */ 64935863739SMike Smith if (sc->aac_intr) 65035863739SMike Smith bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); 65135863739SMike Smith if (sc->aac_irq != NULL) 652c6eafcf2SScott Long bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, 653c6eafcf2SScott Long sc->aac_irq); 65435863739SMike Smith 65535863739SMike Smith /* destroy data-transfer DMA tag */ 65635863739SMike Smith if (sc->aac_buffer_dmat) 65735863739SMike Smith bus_dma_tag_destroy(sc->aac_buffer_dmat); 65835863739SMike Smith 65935863739SMike Smith /* destroy the parent DMA tag */ 66035863739SMike Smith if (sc->aac_parent_dmat) 66135863739SMike Smith bus_dma_tag_destroy(sc->aac_parent_dmat); 66235863739SMike Smith 66335863739SMike Smith /* release the register window mapping */ 664ff0991c4SAttilio Rao if (sc->aac_regs_res0 != NULL) 665914da7d0SScott Long bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 666ff0991c4SAttilio Rao sc->aac_regs_rid0, sc->aac_regs_res0); 667ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) 668ff0991c4SAttilio Rao bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, 669ff0991c4SAttilio Rao sc->aac_regs_rid1, sc->aac_regs_res1); 67035863739SMike Smith } 67135863739SMike Smith 672914da7d0SScott Long /* 67335863739SMike Smith * Disconnect from the controller completely, in preparation for unload. 67435863739SMike Smith */ 67535863739SMike Smith int 67635863739SMike Smith aac_detach(device_t dev) 67735863739SMike Smith { 678914da7d0SScott Long struct aac_softc *sc; 67970545d1aSScott Long struct aac_container *co; 68070545d1aSScott Long struct aac_sim *sim; 68135863739SMike Smith int error; 68235863739SMike Smith 683914da7d0SScott Long sc = device_get_softc(dev); 68431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 685914da7d0SScott Long 68635863739SMike Smith if (sc->aac_state & AAC_STATE_OPEN) 68735863739SMike Smith return(EBUSY); 68835863739SMike Smith 689ff0991c4SAttilio Rao callout_drain(&sc->aac_daemontime); 690ff0991c4SAttilio Rao 69170545d1aSScott Long /* Remove the child containers */ 692a761a1caSScott Long while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { 69370545d1aSScott Long error = device_delete_child(dev, co->co_disk); 69470545d1aSScott Long if (error) 69570545d1aSScott Long return (error); 69665ac4ed6SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); 697a761a1caSScott Long free(co, M_AACBUF); 69870545d1aSScott Long } 69970545d1aSScott Long 70070545d1aSScott Long /* Remove the CAM SIMs */ 701a761a1caSScott Long while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { 702a761a1caSScott Long TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); 70370545d1aSScott Long error = device_delete_child(dev, sim->sim_dev); 70470545d1aSScott Long if (error) 70570545d1aSScott Long return (error); 706a761a1caSScott Long free(sim, M_AACBUF); 70770545d1aSScott Long } 70870545d1aSScott Long 70936e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { 71036e0bf6eSScott Long sc->aifflags |= AAC_AIFFLAGS_EXIT; 71136e0bf6eSScott Long wakeup(sc->aifthread); 71236e0bf6eSScott Long tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz); 71336e0bf6eSScott Long } 71436e0bf6eSScott Long 71536e0bf6eSScott Long if (sc->aifflags & AAC_AIFFLAGS_RUNNING) 716a620bad0SEd Maste panic("Cannot shutdown AIF thread"); 71736e0bf6eSScott Long 71835863739SMike Smith if ((error = aac_shutdown(dev))) 71935863739SMike Smith return(error); 72035863739SMike Smith 7215f54d522SScott Long EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); 7225f54d522SScott Long 72335863739SMike Smith aac_free(sc); 72435863739SMike Smith 725dc9efde5SScott Long mtx_destroy(&sc->aac_aifq_lock); 726dc9efde5SScott Long mtx_destroy(&sc->aac_io_lock); 727dc9efde5SScott Long mtx_destroy(&sc->aac_container_lock); 728dc9efde5SScott Long 72935863739SMike Smith return(0); 73035863739SMike Smith } 73135863739SMike Smith 732914da7d0SScott Long /* 73335863739SMike Smith * Bring the controller down to a dormant state and detach all child devices. 73435863739SMike Smith * 73535863739SMike Smith * This function is called before detach or system shutdown. 73635863739SMike Smith * 7370b94a66eSMike Smith * Note that we can assume that the bioq on the controller is empty, as we won't 73835863739SMike Smith * allow shutdown if any device is open. 73935863739SMike Smith */ 74035863739SMike Smith int 74135863739SMike Smith aac_shutdown(device_t dev) 74235863739SMike Smith { 743914da7d0SScott Long struct aac_softc *sc; 744cbfd045bSScott Long struct aac_fib *fib; 745cbfd045bSScott Long struct aac_close_command *cc; 74635863739SMike Smith 747914da7d0SScott Long sc = device_get_softc(dev); 74831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 749914da7d0SScott Long 75035863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 75135863739SMike Smith 75235863739SMike Smith /* 75335863739SMike Smith * Send a Container shutdown followed by a HostShutdown FIB to the 75435863739SMike Smith * controller to convince it that we don't want to talk to it anymore. 75535863739SMike Smith * We've been closed and all I/O completed already 75635863739SMike Smith */ 75735863739SMike Smith device_printf(sc->aac_dev, "shutting down controller..."); 75835863739SMike Smith 7597cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 76003b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 761cbfd045bSScott Long cc = (struct aac_close_command *)&fib->data[0]; 762cbfd045bSScott Long 76339ee03c3SScott Long bzero(cc, sizeof(struct aac_close_command)); 764cbfd045bSScott Long cc->Command = VM_CloseAll; 765cbfd045bSScott Long cc->ContainerId = 0xffffffff; 766cbfd045bSScott Long if (aac_sync_fib(sc, ContainerCommand, 0, fib, 767cbfd045bSScott Long sizeof(struct aac_close_command))) 76835863739SMike Smith printf("FAILED.\n"); 76970545d1aSScott Long else 77070545d1aSScott Long printf("done\n"); 77170545d1aSScott Long #if 0 772914da7d0SScott Long else { 773cbfd045bSScott Long fib->data[0] = 0; 77436e0bf6eSScott Long /* 775914da7d0SScott Long * XXX Issuing this command to the controller makes it shut down 77636e0bf6eSScott Long * but also keeps it from coming back up without a reset of the 77736e0bf6eSScott Long * PCI bus. This is not desirable if you are just unloading the 77836e0bf6eSScott Long * driver module with the intent to reload it later. 77936e0bf6eSScott Long */ 780cbfd045bSScott Long if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, 781cbfd045bSScott Long fib, 1)) { 78235863739SMike Smith printf("FAILED.\n"); 78335863739SMike Smith } else { 78435863739SMike Smith printf("done.\n"); 78535863739SMike Smith } 78635863739SMike Smith } 78770545d1aSScott Long #endif 78835863739SMike Smith 78935863739SMike Smith AAC_MASK_INTERRUPTS(sc); 7903576af8fSScott Long aac_release_sync_fib(sc); 7917cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 79235863739SMike Smith 79335863739SMike Smith return(0); 79435863739SMike Smith } 79535863739SMike Smith 796914da7d0SScott Long /* 79735863739SMike Smith * Bring the controller to a quiescent state, ready for system suspend. 79835863739SMike Smith */ 79935863739SMike Smith int 80035863739SMike Smith aac_suspend(device_t dev) 80135863739SMike Smith { 802914da7d0SScott Long struct aac_softc *sc; 80335863739SMike Smith 804914da7d0SScott Long sc = device_get_softc(dev); 805914da7d0SScott Long 80631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 80735863739SMike Smith sc->aac_state |= AAC_STATE_SUSPEND; 80835863739SMike Smith 80935863739SMike Smith AAC_MASK_INTERRUPTS(sc); 81035863739SMike Smith return(0); 81135863739SMike Smith } 81235863739SMike Smith 813914da7d0SScott Long /* 81435863739SMike Smith * Bring the controller back to a state ready for operation. 81535863739SMike Smith */ 81635863739SMike Smith int 81735863739SMike Smith aac_resume(device_t dev) 81835863739SMike Smith { 819914da7d0SScott Long struct aac_softc *sc; 82035863739SMike Smith 821914da7d0SScott Long sc = device_get_softc(dev); 822914da7d0SScott Long 82331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 82435863739SMike Smith sc->aac_state &= ~AAC_STATE_SUSPEND; 82535863739SMike Smith AAC_UNMASK_INTERRUPTS(sc); 82635863739SMike Smith return(0); 82735863739SMike Smith } 82835863739SMike Smith 829914da7d0SScott Long /* 8307cb209f5SScott Long * Interrupt handler for NEW_COMM interface. 83135863739SMike Smith */ 83235863739SMike Smith void 8337cb209f5SScott Long aac_new_intr(void *arg) 8347cb209f5SScott Long { 8357cb209f5SScott Long struct aac_softc *sc; 8367cb209f5SScott Long u_int32_t index, fast; 8377cb209f5SScott Long struct aac_command *cm; 8387cb209f5SScott Long struct aac_fib *fib; 8397cb209f5SScott Long int i; 8407cb209f5SScott Long 8417cb209f5SScott Long sc = (struct aac_softc *)arg; 8427cb209f5SScott Long 84331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 8447cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 8457cb209f5SScott Long while (1) { 8467cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8477cb209f5SScott Long if (index == 0xffffffff) 8487cb209f5SScott Long index = AAC_GET_OUTB_QUEUE(sc); 8497cb209f5SScott Long if (index == 0xffffffff) 8507cb209f5SScott Long break; 8517cb209f5SScott Long if (index & 2) { 8527cb209f5SScott Long if (index == 0xfffffffe) { 8537cb209f5SScott Long /* XXX This means that the controller wants 8547cb209f5SScott Long * more work. Ignore it for now. 8557cb209f5SScott Long */ 8567cb209f5SScott Long continue; 8577cb209f5SScott Long } 8587cb209f5SScott Long /* AIF */ 8597cb209f5SScott Long fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF, 8607cb209f5SScott Long M_NOWAIT | M_ZERO); 8617cb209f5SScott Long if (fib == NULL) { 8627cb209f5SScott Long /* If we're really this short on memory, 8637cb209f5SScott Long * hopefully breaking out of the handler will 8647cb209f5SScott Long * allow something to get freed. This 8657cb209f5SScott Long * actually sucks a whole lot. 8667cb209f5SScott Long */ 8677cb209f5SScott Long break; 8687cb209f5SScott Long } 8697cb209f5SScott Long index &= ~2; 8707cb209f5SScott Long for (i = 0; i < sizeof(struct aac_fib)/4; ++i) 871ff0991c4SAttilio Rao ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); 8727cb209f5SScott Long aac_handle_aif(sc, fib); 8737cb209f5SScott Long free(fib, M_AACBUF); 8747cb209f5SScott Long 8757cb209f5SScott Long /* 8767cb209f5SScott Long * AIF memory is owned by the adapter, so let it 8777cb209f5SScott Long * know that we are done with it. 8787cb209f5SScott Long */ 8797cb209f5SScott Long AAC_SET_OUTB_QUEUE(sc, index); 8807cb209f5SScott Long AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); 8817cb209f5SScott Long } else { 8827cb209f5SScott Long fast = index & 1; 8837cb209f5SScott Long cm = sc->aac_commands + (index >> 2); 8847cb209f5SScott Long fib = cm->cm_fib; 8857cb209f5SScott Long if (fast) { 8867cb209f5SScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; 8877cb209f5SScott Long *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; 8887cb209f5SScott Long } 8897cb209f5SScott Long aac_remove_busy(cm); 8907cb209f5SScott Long aac_unmap_command(cm); 8917cb209f5SScott Long cm->cm_flags |= AAC_CMD_COMPLETED; 8927cb209f5SScott Long 8937cb209f5SScott Long /* is there a completion handler? */ 8947cb209f5SScott Long if (cm->cm_complete != NULL) { 8957cb209f5SScott Long cm->cm_complete(cm); 8967cb209f5SScott Long } else { 8977cb209f5SScott Long /* assume that someone is sleeping on this 8987cb209f5SScott Long * command 8997cb209f5SScott Long */ 9007cb209f5SScott Long wakeup(cm); 9017cb209f5SScott Long } 9027cb209f5SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 9037cb209f5SScott Long } 9047cb209f5SScott Long } 9057cb209f5SScott Long /* see if we can start some more I/O */ 9067cb209f5SScott Long if ((sc->flags & AAC_QUEUE_FRZN) == 0) 9077cb209f5SScott Long aac_startio(sc); 9087cb209f5SScott Long 9097cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 9107cb209f5SScott Long } 9117cb209f5SScott Long 912e46b9eeaSEd Maste /* 913e46b9eeaSEd Maste * Interrupt filter for !NEW_COMM interface. 914e46b9eeaSEd Maste */ 915ef544f63SPaolo Pisati int 916e46b9eeaSEd Maste aac_filter(void *arg) 91735863739SMike Smith { 918914da7d0SScott Long struct aac_softc *sc; 91970545d1aSScott Long u_int16_t reason; 92035863739SMike Smith 921914da7d0SScott Long sc = (struct aac_softc *)arg; 922914da7d0SScott Long 92331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 924f30ac74cSScott Long /* 9259148fa21SScott Long * Read the status register directly. This is faster than taking the 9269148fa21SScott Long * driver lock and reading the queues directly. It also saves having 9279148fa21SScott Long * to turn parts of the driver lock into a spin mutex, which would be 9289148fa21SScott Long * ugly. 929f30ac74cSScott Long */ 93035863739SMike Smith reason = AAC_GET_ISTATUS(sc); 931f30ac74cSScott Long AAC_CLEAR_ISTATUS(sc, reason); 932f30ac74cSScott Long 9339c3a7fceSScott Long /* handle completion processing */ 9349148fa21SScott Long if (reason & AAC_DB_RESPONSE_READY) 9359148fa21SScott Long taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete); 93635863739SMike Smith 9379148fa21SScott Long /* controller wants to talk to us */ 9389148fa21SScott Long if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { 93970545d1aSScott Long /* 9409148fa21SScott Long * XXX Make sure that we don't get fooled by strange messages 9419148fa21SScott Long * that start with a NULL. 94270545d1aSScott Long */ 9439148fa21SScott Long if ((reason & AAC_DB_PRINTF) && 9449148fa21SScott Long (sc->aac_common->ac_printf[0] == 0)) 9459148fa21SScott Long sc->aac_common->ac_printf[0] = 32; 94670545d1aSScott Long 9479148fa21SScott Long /* 9489148fa21SScott Long * This might miss doing the actual wakeup. However, the 949a32a982dSScott Long * msleep that this is waking up has a timeout, so it will 9509148fa21SScott Long * wake up eventually. AIFs and printfs are low enough 9519148fa21SScott Long * priority that they can handle hanging out for a few seconds 9529148fa21SScott Long * if needed. 9539148fa21SScott Long */ 95436e0bf6eSScott Long wakeup(sc->aifthread); 95536e0bf6eSScott Long } 956ef544f63SPaolo Pisati return (FILTER_HANDLED); 9579148fa21SScott Long } 95835863739SMike Smith 959c6eafcf2SScott Long /* 960914da7d0SScott Long * Command Processing 961914da7d0SScott Long */ 96235863739SMike Smith 963914da7d0SScott Long /* 96435863739SMike Smith * Start as much queued I/O as possible on the controller 96535863739SMike Smith */ 966fe3cb0e1SScott Long void 96735863739SMike Smith aac_startio(struct aac_softc *sc) 96835863739SMike Smith { 96935863739SMike Smith struct aac_command *cm; 970397fa34fSScott Long int error; 97135863739SMike Smith 97231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 97335863739SMike Smith 97435863739SMike Smith for (;;) { 975914da7d0SScott Long /* 976397fa34fSScott Long * This flag might be set if the card is out of resources. 977397fa34fSScott Long * Checking it here prevents an infinite loop of deferrals. 978397fa34fSScott Long */ 979397fa34fSScott Long if (sc->flags & AAC_QUEUE_FRZN) 980397fa34fSScott Long break; 981397fa34fSScott Long 982397fa34fSScott Long /* 983914da7d0SScott Long * Try to get a command that's been put off for lack of 984914da7d0SScott Long * resources 985914da7d0SScott Long */ 98635863739SMike Smith cm = aac_dequeue_ready(sc); 98735863739SMike Smith 988914da7d0SScott Long /* 989914da7d0SScott Long * Try to build a command off the bio queue (ignore error 990914da7d0SScott Long * return) 991914da7d0SScott Long */ 9920b94a66eSMike Smith if (cm == NULL) 99335863739SMike Smith aac_bio_command(sc, &cm); 99435863739SMike Smith 99535863739SMike Smith /* nothing to do? */ 99635863739SMike Smith if (cm == NULL) 99735863739SMike Smith break; 99835863739SMike Smith 999cd481291SScott Long /* don't map more than once */ 1000cd481291SScott Long if (cm->cm_flags & AAC_CMD_MAPPED) 10014102d44bSScott Long panic("aac: command %p already mapped", cm); 100235863739SMike Smith 1003397fa34fSScott Long /* 1004397fa34fSScott Long * Set up the command to go to the controller. If there are no 1005397fa34fSScott Long * data buffers associated with the command then it can bypass 1006397fa34fSScott Long * busdma. 1007397fa34fSScott Long */ 1008cd481291SScott Long if (cm->cm_datalen != 0) { 1009397fa34fSScott Long error = bus_dmamap_load(sc->aac_buffer_dmat, 1010397fa34fSScott Long cm->cm_datamap, cm->cm_data, 1011397fa34fSScott Long cm->cm_datalen, 1012cd481291SScott Long aac_map_command_sg, cm, 0); 1013cd481291SScott Long if (error == EINPROGRESS) { 101431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); 1015cd481291SScott Long sc->flags |= AAC_QUEUE_FRZN; 1016cd481291SScott Long error = 0; 1017614c22b2SScott Long } else if (error != 0) 1018397fa34fSScott Long panic("aac_startio: unexpected error %d from " 1019a620bad0SEd Maste "busdma", error); 1020397fa34fSScott Long } else 10218778f63dSScott Long aac_map_command_sg(cm, NULL, 0, 0); 1022cd481291SScott Long } 102335863739SMike Smith } 102435863739SMike Smith 1025914da7d0SScott Long /* 102635863739SMike Smith * Handle notification of one or more FIBs coming from the controller. 102735863739SMike Smith */ 102835863739SMike Smith static void 102970545d1aSScott Long aac_command_thread(struct aac_softc *sc) 103035863739SMike Smith { 103135863739SMike Smith struct aac_fib *fib; 103235863739SMike Smith u_int32_t fib_size; 10339148fa21SScott Long int size, retval; 103435863739SMike Smith 103531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 103635863739SMike Smith 1037bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1038a32a982dSScott Long sc->aifflags = AAC_AIFFLAGS_RUNNING; 103936e0bf6eSScott Long 1040a32a982dSScott Long while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { 1041a32a982dSScott Long 1042a32a982dSScott Long retval = 0; 1043a32a982dSScott Long if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) 1044a32a982dSScott Long retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO, 1045a32a982dSScott Long "aifthd", AAC_PERIODIC_INTERVAL * hz); 104636e0bf6eSScott Long 10479148fa21SScott Long /* 10489148fa21SScott Long * First see if any FIBs need to be allocated. This needs 10499148fa21SScott Long * to be called without the driver lock because contigmalloc 10509148fa21SScott Long * will grab Giant, and would result in an LOR. 10519148fa21SScott Long */ 10529148fa21SScott Long if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { 1053bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 1054a32a982dSScott Long aac_alloc_commands(sc); 1055bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 10564102d44bSScott Long sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; 1057a32a982dSScott Long aac_startio(sc); 1058a32a982dSScott Long } 10599148fa21SScott Long 10609148fa21SScott Long /* 10619148fa21SScott Long * While we're here, check to see if any commands are stuck. 10629148fa21SScott Long * This is pretty low-priority, so it's ok if it doesn't 10639148fa21SScott Long * always fire. 10649148fa21SScott Long */ 10659148fa21SScott Long if (retval == EWOULDBLOCK) 106670545d1aSScott Long aac_timeout(sc); 106770545d1aSScott Long 106870545d1aSScott Long /* Check the hardware printf message buffer */ 10699148fa21SScott Long if (sc->aac_common->ac_printf[0] != 0) 107070545d1aSScott Long aac_print_printf(sc); 107170545d1aSScott Long 10729148fa21SScott Long /* Also check to see if the adapter has a command for us. */ 10737cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 10747cb209f5SScott Long continue; 10757cb209f5SScott Long for (;;) { 10767cb209f5SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, 10777cb209f5SScott Long &fib_size, &fib)) 10787cb209f5SScott Long break; 107935863739SMike Smith 108036e0bf6eSScott Long AAC_PRINT_FIB(sc, fib); 108136e0bf6eSScott Long 108235863739SMike Smith switch (fib->Header.Command) { 108335863739SMike Smith case AifRequest: 108436e0bf6eSScott Long aac_handle_aif(sc, fib); 108535863739SMike Smith break; 108635863739SMike Smith default: 1087914da7d0SScott Long device_printf(sc->aac_dev, "unknown command " 1088914da7d0SScott Long "from controller\n"); 108935863739SMike Smith break; 109035863739SMike Smith } 109135863739SMike Smith 109236e0bf6eSScott Long if ((fib->Header.XferState == 0) || 10937cb209f5SScott Long (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { 109436e0bf6eSScott Long break; 10957cb209f5SScott Long } 109636e0bf6eSScott Long 109770545d1aSScott Long /* Return the AIF to the controller. */ 109836e0bf6eSScott Long if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { 109936e0bf6eSScott Long fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; 110036e0bf6eSScott Long *(AAC_FSAStatus*)fib->data = ST_OK; 110136e0bf6eSScott Long 110236e0bf6eSScott Long /* XXX Compute the Size field? */ 110336e0bf6eSScott Long size = fib->Header.Size; 110436e0bf6eSScott Long if (size > sizeof(struct aac_fib)) { 110536e0bf6eSScott Long size = sizeof(struct aac_fib); 110636e0bf6eSScott Long fib->Header.Size = size; 110736e0bf6eSScott Long } 110836e0bf6eSScott Long /* 1109914da7d0SScott Long * Since we did not generate this command, it 1110914da7d0SScott Long * cannot go through the normal 1111914da7d0SScott Long * enqueue->startio chain. 111236e0bf6eSScott Long */ 1113914da7d0SScott Long aac_enqueue_response(sc, 1114914da7d0SScott Long AAC_ADAP_NORM_RESP_QUEUE, 1115914da7d0SScott Long fib); 111636e0bf6eSScott Long } 111736e0bf6eSScott Long } 111836e0bf6eSScott Long } 111936e0bf6eSScott Long sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; 1120bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 112136e0bf6eSScott Long wakeup(sc->aac_dev); 112236e0bf6eSScott Long 11233745c395SJulian Elischer kproc_exit(0); 112435863739SMike Smith } 112535863739SMike Smith 1126914da7d0SScott Long /* 11279c3a7fceSScott Long * Process completed commands. 112835863739SMike Smith */ 112935863739SMike Smith static void 11309c3a7fceSScott Long aac_complete(void *context, int pending) 113135863739SMike Smith { 11329c3a7fceSScott Long struct aac_softc *sc; 113335863739SMike Smith struct aac_command *cm; 113435863739SMike Smith struct aac_fib *fib; 113535863739SMike Smith u_int32_t fib_size; 113635863739SMike Smith 11379c3a7fceSScott Long sc = (struct aac_softc *)context; 113831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 11399c3a7fceSScott Long 1140bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 1141ae543596SScott Long 11429c3a7fceSScott Long /* pull completed commands off the queue */ 114335863739SMike Smith for (;;) { 114435863739SMike Smith /* look for completed FIBs on our queue */ 1145914da7d0SScott Long if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, 1146914da7d0SScott Long &fib)) 114735863739SMike Smith break; /* nothing to do */ 114835863739SMike Smith 1149ecd1c51fSScott Long /* get the command, unmap and hand off for processing */ 1150cb0d64b9SScott Long cm = sc->aac_commands + fib->Header.SenderData; 115135863739SMike Smith if (cm == NULL) { 115235863739SMike Smith AAC_PRINT_FIB(sc, fib); 11539c3a7fceSScott Long break; 11549c3a7fceSScott Long } 11550b94a66eSMike Smith aac_remove_busy(cm); 11567cb209f5SScott Long 1157ecd1c51fSScott Long aac_unmap_command(cm); 115835863739SMike Smith cm->cm_flags |= AAC_CMD_COMPLETED; 115935863739SMike Smith 116035863739SMike Smith /* is there a completion handler? */ 116135863739SMike Smith if (cm->cm_complete != NULL) { 116235863739SMike Smith cm->cm_complete(cm); 116335863739SMike Smith } else { 116435863739SMike Smith /* assume that someone is sleeping on this command */ 116535863739SMike Smith wakeup(cm); 116635863739SMike Smith } 116735863739SMike Smith } 11680b94a66eSMike Smith 11690b94a66eSMike Smith /* see if we can start some more I/O */ 1170cd481291SScott Long sc->flags &= ~AAC_QUEUE_FRZN; 11710b94a66eSMike Smith aac_startio(sc); 1172ae543596SScott Long 1173bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 117435863739SMike Smith } 117535863739SMike Smith 1176914da7d0SScott Long /* 117735863739SMike Smith * Handle a bio submitted from a disk device. 117835863739SMike Smith */ 117935863739SMike Smith void 118035863739SMike Smith aac_submit_bio(struct bio *bp) 118135863739SMike Smith { 1182914da7d0SScott Long struct aac_disk *ad; 1183914da7d0SScott Long struct aac_softc *sc; 118435863739SMike Smith 11857540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1186914da7d0SScott Long sc = ad->ad_controller; 118731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1188914da7d0SScott Long 118935863739SMike Smith /* queue the BIO and try to get some work done */ 11900b94a66eSMike Smith aac_enqueue_bio(sc, bp); 119135863739SMike Smith aac_startio(sc); 119235863739SMike Smith } 119335863739SMike Smith 1194914da7d0SScott Long /* 119535863739SMike Smith * Get a bio and build a command to go with it. 119635863739SMike Smith */ 119735863739SMike Smith static int 119835863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) 119935863739SMike Smith { 120035863739SMike Smith struct aac_command *cm; 120135863739SMike Smith struct aac_fib *fib; 120235863739SMike Smith struct aac_disk *ad; 120335863739SMike Smith struct bio *bp; 120435863739SMike Smith 120531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 120635863739SMike Smith 120735863739SMike Smith /* get the resources we will need */ 120835863739SMike Smith cm = NULL; 1209a32a982dSScott Long bp = NULL; 121035863739SMike Smith if (aac_alloc_command(sc, &cm)) /* get a command */ 121135863739SMike Smith goto fail; 1212a32a982dSScott Long if ((bp = aac_dequeue_bio(sc)) == NULL) 1213a32a982dSScott Long goto fail; 121435863739SMike Smith 121535863739SMike Smith /* fill out the command */ 12160b94a66eSMike Smith cm->cm_data = (void *)bp->bio_data; 12170b94a66eSMike Smith cm->cm_datalen = bp->bio_bcount; 12180b94a66eSMike Smith cm->cm_complete = aac_bio_complete; 121935863739SMike Smith cm->cm_private = bp; 12202b3b0f17SScott Long cm->cm_timestamp = time_uptime; 122136e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 122235863739SMike Smith 122335863739SMike Smith /* build the FIB */ 122435863739SMike Smith fib = cm->cm_fib; 1225b85f5808SScott Long fib->Header.Size = sizeof(struct aac_fib_header); 122635863739SMike Smith fib->Header.XferState = 122735863739SMike Smith AAC_FIBSTATE_HOSTOWNED | 122835863739SMike Smith AAC_FIBSTATE_INITIALISED | 1229f30ac74cSScott Long AAC_FIBSTATE_EMPTY | 123035863739SMike Smith AAC_FIBSTATE_FROMHOST | 123135863739SMike Smith AAC_FIBSTATE_REXPECTED | 1232f30ac74cSScott Long AAC_FIBSTATE_NORM | 1233f30ac74cSScott Long AAC_FIBSTATE_ASYNC | 1234f30ac74cSScott Long AAC_FIBSTATE_FAST_RESPONSE; 123535863739SMike Smith 123635863739SMike Smith /* build the read/write request */ 12377540e65eSScott Long ad = (struct aac_disk *)bp->bio_disk->d_drv1; 1238b85f5808SScott Long 12397cb209f5SScott Long if (sc->flags & AAC_FLAGS_RAW_IO) { 12407cb209f5SScott Long struct aac_raw_io *raw; 12417cb209f5SScott Long raw = (struct aac_raw_io *)&fib->data[0]; 12427cb209f5SScott Long fib->Header.Command = RawIo; 12437cb209f5SScott Long raw->BlockNumber = (u_int64_t)bp->bio_pblkno; 12447cb209f5SScott Long raw->ByteCount = bp->bio_bcount; 12457cb209f5SScott Long raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 12467cb209f5SScott Long raw->BpTotal = 0; 12477cb209f5SScott Long raw->BpComplete = 0; 12487cb209f5SScott Long fib->Header.Size += sizeof(struct aac_raw_io); 12497cb209f5SScott Long cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; 12507cb209f5SScott Long if (bp->bio_cmd == BIO_READ) { 12517cb209f5SScott Long raw->Flags = 1; 12527cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAIN; 12537cb209f5SScott Long } else { 12547cb209f5SScott Long raw->Flags = 0; 12557cb209f5SScott Long cm->cm_flags |= AAC_CMD_DATAOUT; 12567cb209f5SScott Long } 12577cb209f5SScott Long } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1258b85f5808SScott Long fib->Header.Command = ContainerCommand; 12599e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 1260b85f5808SScott Long struct aac_blockread *br; 126135863739SMike Smith br = (struct aac_blockread *)&fib->data[0]; 126235863739SMike Smith br->Command = VM_CtBlockRead; 126335863739SMike Smith br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 126435863739SMike Smith br->BlockNumber = bp->bio_pblkno; 126535863739SMike Smith br->ByteCount = bp->bio_bcount; 126635863739SMike Smith fib->Header.Size += sizeof(struct aac_blockread); 126735863739SMike Smith cm->cm_sgtable = &br->SgMap; 126835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAIN; 126935863739SMike Smith } else { 1270b85f5808SScott Long struct aac_blockwrite *bw; 127135863739SMike Smith bw = (struct aac_blockwrite *)&fib->data[0]; 127235863739SMike Smith bw->Command = VM_CtBlockWrite; 127335863739SMike Smith bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 127435863739SMike Smith bw->BlockNumber = bp->bio_pblkno; 127535863739SMike Smith bw->ByteCount = bp->bio_bcount; 1276b85f5808SScott Long bw->Stable = CUNSTABLE; 127735863739SMike Smith fib->Header.Size += sizeof(struct aac_blockwrite); 127835863739SMike Smith cm->cm_flags |= AAC_CMD_DATAOUT; 127935863739SMike Smith cm->cm_sgtable = &bw->SgMap; 128035863739SMike Smith } 1281b85f5808SScott Long } else { 1282b85f5808SScott Long fib->Header.Command = ContainerCommand64; 1283b85f5808SScott Long if (bp->bio_cmd == BIO_READ) { 1284b85f5808SScott Long struct aac_blockread64 *br; 1285b85f5808SScott Long br = (struct aac_blockread64 *)&fib->data[0]; 1286b85f5808SScott Long br->Command = VM_CtHostRead64; 1287b85f5808SScott Long br->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1288b85f5808SScott Long br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1289b85f5808SScott Long br->BlockNumber = bp->bio_pblkno; 1290b85f5808SScott Long br->Pad = 0; 1291b85f5808SScott Long br->Flags = 0; 1292b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockread64); 129354e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAIN; 1294eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 1295b85f5808SScott Long } else { 1296b85f5808SScott Long struct aac_blockwrite64 *bw; 1297b85f5808SScott Long bw = (struct aac_blockwrite64 *)&fib->data[0]; 1298b85f5808SScott Long bw->Command = VM_CtHostWrite64; 1299b85f5808SScott Long bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; 1300b85f5808SScott Long bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE; 1301b85f5808SScott Long bw->BlockNumber = bp->bio_pblkno; 1302b85f5808SScott Long bw->Pad = 0; 1303b85f5808SScott Long bw->Flags = 0; 1304b85f5808SScott Long fib->Header.Size += sizeof(struct aac_blockwrite64); 130554e2ebdfSEd Maste cm->cm_flags |= AAC_CMD_DATAOUT; 1306eec256deSAlexander Kabaev cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 1307b85f5808SScott Long } 1308b85f5808SScott Long } 130935863739SMike Smith 131035863739SMike Smith *cmp = cm; 131135863739SMike Smith return(0); 131235863739SMike Smith 131335863739SMike Smith fail: 13147cb209f5SScott Long if (bp != NULL) 13157cb209f5SScott Long aac_enqueue_bio(sc, bp); 131635863739SMike Smith if (cm != NULL) 131735863739SMike Smith aac_release_command(cm); 131835863739SMike Smith return(ENOMEM); 131935863739SMike Smith } 132035863739SMike Smith 1321914da7d0SScott Long /* 132235863739SMike Smith * Handle a bio-instigated command that has been completed. 132335863739SMike Smith */ 132435863739SMike Smith static void 132535863739SMike Smith aac_bio_complete(struct aac_command *cm) 132635863739SMike Smith { 132735863739SMike Smith struct aac_blockread_response *brr; 132835863739SMike Smith struct aac_blockwrite_response *bwr; 132935863739SMike Smith struct bio *bp; 133035863739SMike Smith AAC_FSAStatus status; 133135863739SMike Smith 133235863739SMike Smith /* fetch relevant status and then release the command */ 133335863739SMike Smith bp = (struct bio *)cm->cm_private; 13349e2e96d8SScott Long if (bp->bio_cmd == BIO_READ) { 133535863739SMike Smith brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; 133635863739SMike Smith status = brr->Status; 133735863739SMike Smith } else { 133835863739SMike Smith bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; 133935863739SMike Smith status = bwr->Status; 134035863739SMike Smith } 134135863739SMike Smith aac_release_command(cm); 134235863739SMike Smith 134335863739SMike Smith /* fix up the bio based on status */ 134435863739SMike Smith if (status == ST_OK) { 134535863739SMike Smith bp->bio_resid = 0; 134635863739SMike Smith } else { 134735863739SMike Smith bp->bio_error = EIO; 134835863739SMike Smith bp->bio_flags |= BIO_ERROR; 13490b94a66eSMike Smith /* pass an error string out to the disk layer */ 1350914da7d0SScott Long bp->bio_driver1 = aac_describe_code(aac_command_status_table, 1351914da7d0SScott Long status); 135235863739SMike Smith } 13530b94a66eSMike Smith aac_biodone(bp); 135435863739SMike Smith } 135535863739SMike Smith 1356914da7d0SScott Long /* 135735863739SMike Smith * Submit a command to the controller, return when it completes. 1358b3457b51SScott Long * XXX This is very dangerous! If the card has gone out to lunch, we could 1359b3457b51SScott Long * be stuck here forever. At the same time, signals are not caught 1360d8a0a473SScott Long * because there is a risk that a signal could wakeup the sleep before 1361d8a0a473SScott Long * the card has a chance to complete the command. Since there is no way 1362d8a0a473SScott Long * to cancel a command that is in progress, we can't protect against the 1363d8a0a473SScott Long * card completing a command late and spamming the command and data 1364d8a0a473SScott Long * memory. So, we are held hostage until the command completes. 136535863739SMike Smith */ 136635863739SMike Smith static int 1367d8a0a473SScott Long aac_wait_command(struct aac_command *cm) 136835863739SMike Smith { 1369ae543596SScott Long struct aac_softc *sc; 1370d8a0a473SScott Long int error; 137135863739SMike Smith 1372ae543596SScott Long sc = cm->cm_sc; 137331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1374ae543596SScott Long 137535863739SMike Smith /* Put the command on the ready queue and get things going */ 137636e0bf6eSScott Long cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; 137735863739SMike Smith aac_enqueue_ready(cm); 1378ae543596SScott Long aac_startio(sc); 1379ae543596SScott Long error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0); 138035863739SMike Smith return(error); 138135863739SMike Smith } 138235863739SMike Smith 1383914da7d0SScott Long /* 1384914da7d0SScott Long *Command Buffer Management 1385914da7d0SScott Long */ 138635863739SMike Smith 1387914da7d0SScott Long /* 138835863739SMike Smith * Allocate a command. 138935863739SMike Smith */ 1390fe3cb0e1SScott Long int 139135863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) 139235863739SMike Smith { 139335863739SMike Smith struct aac_command *cm; 139435863739SMike Smith 139531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 139635863739SMike Smith 1397ffb37f33SScott Long if ((cm = aac_dequeue_free(sc)) == NULL) { 1398b85f5808SScott Long if (sc->total_fibs < sc->aac_max_fibs) { 1399ae543596SScott Long sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; 1400ae543596SScott Long wakeup(sc->aifthread); 1401b85f5808SScott Long } 1402ae543596SScott Long return (EBUSY); 1403ffb37f33SScott Long } 140435863739SMike Smith 14050b94a66eSMike Smith *cmp = cm; 14060b94a66eSMike Smith return(0); 14070b94a66eSMike Smith } 14080b94a66eSMike Smith 1409914da7d0SScott Long /* 14100b94a66eSMike Smith * Release a command back to the freelist. 14110b94a66eSMike Smith */ 1412fe3cb0e1SScott Long void 14130b94a66eSMike Smith aac_release_command(struct aac_command *cm) 14140b94a66eSMike Smith { 14157cb209f5SScott Long struct aac_event *event; 14167cb209f5SScott Long struct aac_softc *sc; 14177cb209f5SScott Long 141831a0399eSEd Maste sc = cm->cm_sc; 141931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 14200b94a66eSMike Smith 14214109ba51SEd Maste /* (re)initialize the command/FIB */ 142235863739SMike Smith cm->cm_sgtable = NULL; 142335863739SMike Smith cm->cm_flags = 0; 142435863739SMike Smith cm->cm_complete = NULL; 142535863739SMike Smith cm->cm_private = NULL; 142635863739SMike Smith cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; 142735863739SMike Smith cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; 142835863739SMike Smith cm->cm_fib->Header.Flags = 0; 14297cb209f5SScott Long cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; 143035863739SMike Smith 143135863739SMike Smith /* 143235863739SMike Smith * These are duplicated in aac_start to cover the case where an 143335863739SMike Smith * intermediate stage may have destroyed them. They're left 14344109ba51SEd Maste * initialized here for debugging purposes only. 143535863739SMike Smith */ 1436f30ac74cSScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 1437f30ac74cSScott Long cm->cm_fib->Header.SenderData = 0; 143835863739SMike Smith 143935863739SMike Smith aac_enqueue_free(cm); 14407cb209f5SScott Long 1441eb5cbaa0SEd Maste /* 1442eb5cbaa0SEd Maste * Dequeue all events so that there's no risk of events getting 1443eb5cbaa0SEd Maste * stranded. 1444eb5cbaa0SEd Maste */ 1445eb5cbaa0SEd Maste while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { 14467cb209f5SScott Long TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); 14477cb209f5SScott Long event->ev_callback(sc, event, event->ev_arg); 14487cb209f5SScott Long } 144935863739SMike Smith } 145035863739SMike Smith 1451914da7d0SScott Long /* 14520b94a66eSMike Smith * Map helper for command/FIB allocation. 145335863739SMike Smith */ 145435863739SMike Smith static void 14550b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) 145635863739SMike Smith { 14577cb209f5SScott Long uint64_t *fibphys; 1458914da7d0SScott Long 14597cb209f5SScott Long fibphys = (uint64_t *)arg; 146035863739SMike Smith 1461ffb37f33SScott Long *fibphys = segs[0].ds_addr; 146235863739SMike Smith } 146335863739SMike Smith 1464914da7d0SScott Long /* 14654109ba51SEd Maste * Allocate and initialize commands/FIBs for this adapter. 146635863739SMike Smith */ 14670b94a66eSMike Smith static int 14680b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc) 146935863739SMike Smith { 147035863739SMike Smith struct aac_command *cm; 1471ffb37f33SScott Long struct aac_fibmap *fm; 14727cb209f5SScott Long uint64_t fibphys; 1473ffb37f33SScott Long int i, error; 147435863739SMike Smith 147531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 147635863739SMike Smith 14777cb209f5SScott Long if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) 1478ffb37f33SScott Long return (ENOMEM); 1479ffb37f33SScott Long 14808480cc63SScott Long fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO); 1481a6d35632SScott Long if (fm == NULL) 1482a6d35632SScott Long return (ENOMEM); 1483ffb37f33SScott Long 14840b94a66eSMike Smith /* allocate the FIBs in DMAable memory and load them */ 1485ffb37f33SScott Long if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, 1486ffb37f33SScott Long BUS_DMA_NOWAIT, &fm->aac_fibmap)) { 148770545d1aSScott Long device_printf(sc->aac_dev, 148870545d1aSScott Long "Not enough contiguous memory available.\n"); 14898480cc63SScott Long free(fm, M_AACBUF); 14900b94a66eSMike Smith return (ENOMEM); 149135863739SMike Smith } 1492128aa5a0SScott Long 1493cd481291SScott Long /* Ignore errors since this doesn't bounce */ 1494cd481291SScott Long (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, 14957cb209f5SScott Long sc->aac_max_fibs_alloc * sc->aac_max_fib_size, 1496ffb37f33SScott Long aac_map_command_helper, &fibphys, 0); 1497128aa5a0SScott Long 14984109ba51SEd Maste /* initialize constant fields in the command structure */ 14997cb209f5SScott Long bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); 15007cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc; i++) { 15018480cc63SScott Long cm = sc->aac_commands + sc->total_fibs; 1502ffb37f33SScott Long fm->aac_commands = cm; 150335863739SMike Smith cm->cm_sc = sc; 15047cb209f5SScott Long cm->cm_fib = (struct aac_fib *) 15057cb209f5SScott Long ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); 15067cb209f5SScott Long cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; 1507cb0d64b9SScott Long cm->cm_index = sc->total_fibs; 150835863739SMike Smith 1509ffb37f33SScott Long if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, 151093cfca22SScott Long &cm->cm_datamap)) != 0) 15118480cc63SScott Long break; 151293cfca22SScott Long mtx_lock(&sc->aac_io_lock); 151393cfca22SScott Long aac_release_command(cm); 15148480cc63SScott Long sc->total_fibs++; 151593cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 151635863739SMike Smith } 1517ffb37f33SScott Long 15188480cc63SScott Long if (i > 0) { 151993cfca22SScott Long mtx_lock(&sc->aac_io_lock); 1520ffb37f33SScott Long TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); 152131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); 1522bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 15230b94a66eSMike Smith return (0); 152435863739SMike Smith } 152535863739SMike Smith 15268480cc63SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 15278480cc63SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15288480cc63SScott Long free(fm, M_AACBUF); 15298480cc63SScott Long return (ENOMEM); 15308480cc63SScott Long } 15318480cc63SScott Long 1532914da7d0SScott Long /* 15330b94a66eSMike Smith * Free FIBs owned by this adapter. 153435863739SMike Smith */ 153535863739SMike Smith static void 15368480cc63SScott Long aac_free_commands(struct aac_softc *sc) 153735863739SMike Smith { 15388480cc63SScott Long struct aac_fibmap *fm; 1539ffb37f33SScott Long struct aac_command *cm; 154035863739SMike Smith int i; 154135863739SMike Smith 154231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 154335863739SMike Smith 15448480cc63SScott Long while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { 15458480cc63SScott Long 15468480cc63SScott Long TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); 15478480cc63SScott Long /* 15488480cc63SScott Long * We check against total_fibs to handle partially 15498480cc63SScott Long * allocated blocks. 15508480cc63SScott Long */ 15517cb209f5SScott Long for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { 1552ffb37f33SScott Long cm = fm->aac_commands + i; 1553ffb37f33SScott Long bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); 1554ffb37f33SScott Long } 1555ffb37f33SScott Long bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); 1556ffb37f33SScott Long bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); 15578480cc63SScott Long free(fm, M_AACBUF); 15588480cc63SScott Long } 155935863739SMike Smith } 156035863739SMike Smith 1561914da7d0SScott Long /* 156235863739SMike Smith * Command-mapping helper function - populate this command's s/g table. 156335863739SMike Smith */ 156435863739SMike Smith static void 156535863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) 156635863739SMike Smith { 1567cd481291SScott Long struct aac_softc *sc; 1568914da7d0SScott Long struct aac_command *cm; 1569914da7d0SScott Long struct aac_fib *fib; 157035863739SMike Smith int i; 157135863739SMike Smith 1572914da7d0SScott Long cm = (struct aac_command *)arg; 1573cd481291SScott Long sc = cm->cm_sc; 1574914da7d0SScott Long fib = cm->cm_fib; 157531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1576914da7d0SScott Long 157735863739SMike Smith /* copy into the FIB */ 1578b85f5808SScott Long if (cm->cm_sgtable != NULL) { 15797cb209f5SScott Long if (fib->Header.Command == RawIo) { 15807cb209f5SScott Long struct aac_sg_tableraw *sg; 15817cb209f5SScott Long sg = (struct aac_sg_tableraw *)cm->cm_sgtable; 15827cb209f5SScott Long sg->SgCount = nseg; 15837cb209f5SScott Long for (i = 0; i < nseg; i++) { 15847cb209f5SScott Long sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; 15857cb209f5SScott Long sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; 15867cb209f5SScott Long sg->SgEntryRaw[i].Next = 0; 15877cb209f5SScott Long sg->SgEntryRaw[i].Prev = 0; 15887cb209f5SScott Long sg->SgEntryRaw[i].Flags = 0; 15897cb209f5SScott Long } 15907cb209f5SScott Long /* update the FIB size for the s/g count */ 15917cb209f5SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); 15927cb209f5SScott Long } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 1593b85f5808SScott Long struct aac_sg_table *sg; 1594b85f5808SScott Long sg = cm->cm_sgtable; 159535863739SMike Smith sg->SgCount = nseg; 159635863739SMike Smith for (i = 0; i < nseg; i++) { 159735863739SMike Smith sg->SgEntry[i].SgAddress = segs[i].ds_addr; 159835863739SMike Smith sg->SgEntry[i].SgByteCount = segs[i].ds_len; 159935863739SMike Smith } 160035863739SMike Smith /* update the FIB size for the s/g count */ 160135863739SMike Smith fib->Header.Size += nseg*sizeof(struct aac_sg_entry); 1602b85f5808SScott Long } else { 1603b85f5808SScott Long struct aac_sg_table64 *sg; 1604b85f5808SScott Long sg = (struct aac_sg_table64 *)cm->cm_sgtable; 1605b85f5808SScott Long sg->SgCount = nseg; 1606b85f5808SScott Long for (i = 0; i < nseg; i++) { 1607b85f5808SScott Long sg->SgEntry64[i].SgAddress = segs[i].ds_addr; 1608b85f5808SScott Long sg->SgEntry64[i].SgByteCount = segs[i].ds_len; 160935863739SMike Smith } 1610b85f5808SScott Long /* update the FIB size for the s/g count */ 1611b85f5808SScott Long fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); 1612b85f5808SScott Long } 1613b85f5808SScott Long } 161435863739SMike Smith 1615cd481291SScott Long /* Fix up the address values in the FIB. Use the command array index 1616cd481291SScott Long * instead of a pointer since these fields are only 32 bits. Shift 16177cb209f5SScott Long * the SenderFibAddress over to make room for the fast response bit 16187cb209f5SScott Long * and for the AIF bit 161935863739SMike Smith */ 16207cb209f5SScott Long cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); 16217cb209f5SScott Long cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; 162235863739SMike Smith 1623cd481291SScott Long /* save a pointer to the command for speedy reverse-lookup */ 1624cd481291SScott Long cm->cm_fib->Header.SenderData = cm->cm_index; 162535863739SMike Smith 162635863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1627c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1628c6eafcf2SScott Long BUS_DMASYNC_PREREAD); 162935863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1630c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1631c6eafcf2SScott Long BUS_DMASYNC_PREWRITE); 163235863739SMike Smith cm->cm_flags |= AAC_CMD_MAPPED; 1633cd481291SScott Long 16347cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 16357cb209f5SScott Long int count = 10000000L; 16367cb209f5SScott Long while (AAC_SEND_COMMAND(sc, cm) != 0) { 16377cb209f5SScott Long if (--count == 0) { 16387cb209f5SScott Long aac_unmap_command(cm); 16397cb209f5SScott Long sc->flags |= AAC_QUEUE_FRZN; 16407cb209f5SScott Long aac_requeue_ready(cm); 16417cb209f5SScott Long } 16427cb209f5SScott Long DELAY(5); /* wait 5 usec. */ 16437cb209f5SScott Long } 16447cb209f5SScott Long } else { 1645397fa34fSScott Long /* Put the FIB on the outbound queue */ 16464102d44bSScott Long if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { 16474102d44bSScott Long aac_unmap_command(cm); 1648397fa34fSScott Long sc->flags |= AAC_QUEUE_FRZN; 1649cd481291SScott Long aac_requeue_ready(cm); 16504102d44bSScott Long } 16517cb209f5SScott Long } 1652cd481291SScott Long 1653cd481291SScott Long return; 165435863739SMike Smith } 165535863739SMike Smith 1656914da7d0SScott Long /* 165735863739SMike Smith * Unmap a command from controller-visible space. 165835863739SMike Smith */ 165935863739SMike Smith static void 166035863739SMike Smith aac_unmap_command(struct aac_command *cm) 166135863739SMike Smith { 1662914da7d0SScott Long struct aac_softc *sc; 166335863739SMike Smith 1664914da7d0SScott Long sc = cm->cm_sc; 166531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1666914da7d0SScott Long 166735863739SMike Smith if (!(cm->cm_flags & AAC_CMD_MAPPED)) 166835863739SMike Smith return; 166935863739SMike Smith 167035863739SMike Smith if (cm->cm_datalen != 0) { 167135863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAIN) 1672c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1673c6eafcf2SScott Long BUS_DMASYNC_POSTREAD); 167435863739SMike Smith if (cm->cm_flags & AAC_CMD_DATAOUT) 1675c6eafcf2SScott Long bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, 1676c6eafcf2SScott Long BUS_DMASYNC_POSTWRITE); 167735863739SMike Smith 167835863739SMike Smith bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); 167935863739SMike Smith } 168035863739SMike Smith cm->cm_flags &= ~AAC_CMD_MAPPED; 168135863739SMike Smith } 168235863739SMike Smith 1683914da7d0SScott Long /* 1684914da7d0SScott Long * Hardware Interface 1685914da7d0SScott Long */ 168635863739SMike Smith 1687914da7d0SScott Long /* 16884109ba51SEd Maste * Initialize the adapter. 168935863739SMike Smith */ 169035863739SMike Smith static void 169135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 169235863739SMike Smith { 1693914da7d0SScott Long struct aac_softc *sc; 169435863739SMike Smith 1695914da7d0SScott Long sc = (struct aac_softc *)arg; 169631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1697914da7d0SScott Long 169835863739SMike Smith sc->aac_common_busaddr = segs[0].ds_addr; 169935863739SMike Smith } 170035863739SMike Smith 1701a6d35632SScott Long static int 1702a6d35632SScott Long aac_check_firmware(struct aac_softc *sc) 1703a6d35632SScott Long { 170404f4d586SEd Maste u_int32_t code, major, minor, options = 0, atu_size = 0; 1705a441b3fcSScott Long int status; 170604f4d586SEd Maste time_t then; 1707a6d35632SScott Long 170831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 170904f4d586SEd Maste /* 171004f4d586SEd Maste * Wait for the adapter to come ready. 171104f4d586SEd Maste */ 171204f4d586SEd Maste then = time_uptime; 171304f4d586SEd Maste do { 171404f4d586SEd Maste code = AAC_GET_FWSTATUS(sc); 171504f4d586SEd Maste if (code & AAC_SELF_TEST_FAILED) { 171604f4d586SEd Maste device_printf(sc->aac_dev, "FATAL: selftest failed\n"); 171704f4d586SEd Maste return(ENXIO); 171804f4d586SEd Maste } 171904f4d586SEd Maste if (code & AAC_KERNEL_PANIC) { 172004f4d586SEd Maste device_printf(sc->aac_dev, 1721a620bad0SEd Maste "FATAL: controller kernel panic"); 172204f4d586SEd Maste return(ENXIO); 172304f4d586SEd Maste } 172404f4d586SEd Maste if (time_uptime > (then + AAC_BOOT_TIMEOUT)) { 172504f4d586SEd Maste device_printf(sc->aac_dev, 172604f4d586SEd Maste "FATAL: controller not coming ready, " 172704f4d586SEd Maste "status %x\n", code); 172804f4d586SEd Maste return(ENXIO); 172904f4d586SEd Maste } 173004f4d586SEd Maste } while (!(code & AAC_UP_AND_RUNNING)); 1731a6d35632SScott Long 1732fe94b852SScott Long /* 1733fe94b852SScott Long * Retrieve the firmware version numbers. Dell PERC2/QC cards with 1734fe94b852SScott Long * firmware version 1.x are not compatible with this driver. 1735fe94b852SScott Long */ 1736a6d35632SScott Long if (sc->flags & AAC_FLAGS_PERC2QC) { 1737fe94b852SScott Long if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, 1738fe94b852SScott Long NULL)) { 1739fe94b852SScott Long device_printf(sc->aac_dev, 1740fe94b852SScott Long "Error reading firmware version\n"); 1741fe94b852SScott Long return (EIO); 1742fe94b852SScott Long } 1743fe94b852SScott Long 1744fe94b852SScott Long /* These numbers are stored as ASCII! */ 1745a6d35632SScott Long major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; 1746a6d35632SScott Long minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; 1747fe94b852SScott Long if (major == 1) { 1748fe94b852SScott Long device_printf(sc->aac_dev, 1749fe94b852SScott Long "Firmware version %d.%d is not supported.\n", 1750fe94b852SScott Long major, minor); 1751fe94b852SScott Long return (EINVAL); 1752fe94b852SScott Long } 1753fe94b852SScott Long } 1754fe94b852SScott Long 1755a6d35632SScott Long /* 1756a6d35632SScott Long * Retrieve the capabilities/supported options word so we know what 1757a441b3fcSScott Long * work-arounds to enable. Some firmware revs don't support this 1758a441b3fcSScott Long * command. 1759a6d35632SScott Long */ 1760a441b3fcSScott Long if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { 1761a441b3fcSScott Long if (status != AAC_SRB_STS_INVALID_REQUEST) { 1762a441b3fcSScott Long device_printf(sc->aac_dev, 1763a441b3fcSScott Long "RequestAdapterInfo failed\n"); 1764a6d35632SScott Long return (EIO); 1765a6d35632SScott Long } 1766a441b3fcSScott Long } else { 1767a6d35632SScott Long options = AAC_GET_MAILBOX(sc, 1); 17687cb209f5SScott Long atu_size = AAC_GET_MAILBOX(sc, 2); 1769a6d35632SScott Long sc->supported_options = options; 1770a6d35632SScott Long 1771a6d35632SScott Long if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && 1772a6d35632SScott Long (sc->flags & AAC_FLAGS_NO4GB) == 0) 1773a6d35632SScott Long sc->flags |= AAC_FLAGS_4GB_WINDOW; 1774a6d35632SScott Long if (options & AAC_SUPPORTED_NONDASD) 1775a6d35632SScott Long sc->flags |= AAC_FLAGS_ENABLE_CAM; 1776cd481291SScott Long if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 1777cd481291SScott Long && (sizeof(bus_addr_t) > 4)) { 1778a441b3fcSScott Long device_printf(sc->aac_dev, 1779a441b3fcSScott Long "Enabling 64-bit address support\n"); 1780a6d35632SScott Long sc->flags |= AAC_FLAGS_SG_64BIT; 1781a6d35632SScott Long } 1782a441b3fcSScott Long if ((options & AAC_SUPPORTED_NEW_COMM) 1783a441b3fcSScott Long && sc->aac_if.aif_send_command) 17847cb209f5SScott Long sc->flags |= AAC_FLAGS_NEW_COMM; 17857cb209f5SScott Long if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) 17867cb209f5SScott Long sc->flags |= AAC_FLAGS_ARRAY_64BIT; 1787a441b3fcSScott Long } 1788a6d35632SScott Long 1789a6d35632SScott Long /* Check for broken hardware that does a lower number of commands */ 17907cb209f5SScott Long sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); 17917cb209f5SScott Long 17927cb209f5SScott Long /* Remap mem. resource, if required */ 17937cb209f5SScott Long if ((sc->flags & AAC_FLAGS_NEW_COMM) && 1794ff0991c4SAttilio Rao atu_size > rman_get_size(sc->aac_regs_res1)) { 17957cb209f5SScott Long bus_release_resource( 17967cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 1797ff0991c4SAttilio Rao sc->aac_regs_rid1, sc->aac_regs_res1); 1798ff0991c4SAttilio Rao sc->aac_regs_res1 = bus_alloc_resource( 1799ff0991c4SAttilio Rao sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1, 18007cb209f5SScott Long 0ul, ~0ul, atu_size, RF_ACTIVE); 1801ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 1802ff0991c4SAttilio Rao sc->aac_regs_res1 = bus_alloc_resource_any( 18037cb209f5SScott Long sc->aac_dev, SYS_RES_MEMORY, 1804ff0991c4SAttilio Rao &sc->aac_regs_rid1, RF_ACTIVE); 1805ff0991c4SAttilio Rao if (sc->aac_regs_res1 == NULL) { 18067cb209f5SScott Long device_printf(sc->aac_dev, 18077cb209f5SScott Long "couldn't allocate register window\n"); 18087cb209f5SScott Long return (ENXIO); 18097cb209f5SScott Long } 18107cb209f5SScott Long sc->flags &= ~AAC_FLAGS_NEW_COMM; 18117cb209f5SScott Long } 1812ff0991c4SAttilio Rao sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 1813ff0991c4SAttilio Rao sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 1814ff0991c4SAttilio Rao 1815ff0991c4SAttilio Rao if (sc->aac_hwif == AAC_HWIF_NARK) { 1816ff0991c4SAttilio Rao sc->aac_regs_res0 = sc->aac_regs_res1; 1817ff0991c4SAttilio Rao sc->aac_regs_rid0 = sc->aac_regs_rid1; 1818ff0991c4SAttilio Rao sc->aac_btag0 = sc->aac_btag1; 1819ff0991c4SAttilio Rao sc->aac_bhandle0 = sc->aac_bhandle1; 1820ff0991c4SAttilio Rao } 18217cb209f5SScott Long } 18227cb209f5SScott Long 18237cb209f5SScott Long /* Read preferred settings */ 18247cb209f5SScott Long sc->aac_max_fib_size = sizeof(struct aac_fib); 18257cb209f5SScott Long sc->aac_max_sectors = 128; /* 64KB */ 18267cb209f5SScott Long if (sc->flags & AAC_FLAGS_SG_64BIT) 1827a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18287e7a458eSEd Maste - sizeof(struct aac_blockwrite64)) 18297e7a458eSEd Maste / sizeof(struct aac_sg_entry64); 1830a6d35632SScott Long else 1831a441b3fcSScott Long sc->aac_sg_tablesize = (AAC_FIB_DATASIZE 18327e7a458eSEd Maste - sizeof(struct aac_blockwrite)) 18337e7a458eSEd Maste / sizeof(struct aac_sg_entry); 1834a441b3fcSScott Long 18357cb209f5SScott Long if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { 18367cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 1); 18377cb209f5SScott Long sc->aac_max_fib_size = (options & 0xFFFF); 18387cb209f5SScott Long sc->aac_max_sectors = (options >> 16) << 1; 18397cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 2); 18407cb209f5SScott Long sc->aac_sg_tablesize = (options >> 16); 18417cb209f5SScott Long options = AAC_GET_MAILBOX(sc, 3); 18427cb209f5SScott Long sc->aac_max_fibs = (options & 0xFFFF); 18437cb209f5SScott Long } 18447cb209f5SScott Long if (sc->aac_max_fib_size > PAGE_SIZE) 18457cb209f5SScott Long sc->aac_max_fib_size = PAGE_SIZE; 18467cb209f5SScott Long sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; 1847a6d35632SScott Long 1848f355c0e0SEd Maste if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 1849f355c0e0SEd Maste sc->flags |= AAC_FLAGS_RAW_IO; 1850f355c0e0SEd Maste device_printf(sc->aac_dev, "Enable Raw I/O\n"); 1851f355c0e0SEd Maste } 1852523da39bSEd Maste if ((sc->flags & AAC_FLAGS_RAW_IO) && 1853523da39bSEd Maste (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { 1854523da39bSEd Maste sc->flags |= AAC_FLAGS_LBA_64BIT; 1855523da39bSEd Maste device_printf(sc->aac_dev, "Enable 64-bit array\n"); 1856523da39bSEd Maste } 1857f355c0e0SEd Maste 1858fe94b852SScott Long return (0); 1859fe94b852SScott Long } 1860fe94b852SScott Long 186135863739SMike Smith static int 186235863739SMike Smith aac_init(struct aac_softc *sc) 186335863739SMike Smith { 186435863739SMike Smith struct aac_adapter_init *ip; 186504f4d586SEd Maste u_int32_t qoffset; 1866a6d35632SScott Long int error; 186735863739SMike Smith 186831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1869ffb37f33SScott Long 187035863739SMike Smith /* 1871914da7d0SScott Long * Fill in the init structure. This tells the adapter about the 1872914da7d0SScott Long * physical location of various important shared data structures. 187335863739SMike Smith */ 187435863739SMike Smith ip = &sc->aac_common->ac_init; 187535863739SMike Smith ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; 18767cb209f5SScott Long if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { 18777cb209f5SScott Long ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; 18787cb209f5SScott Long sc->flags |= AAC_FLAGS_RAW_IO; 18797cb209f5SScott Long } 1880f30ac74cSScott Long ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; 188135863739SMike Smith 1882c6eafcf2SScott Long ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + 1883c6eafcf2SScott Long offsetof(struct aac_common, ac_fibs); 1884149af931SScott Long ip->AdapterFibsVirtualAddress = 0; 188535863739SMike Smith ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); 188635863739SMike Smith ip->AdapterFibAlign = sizeof(struct aac_fib); 188735863739SMike Smith 1888c6eafcf2SScott Long ip->PrintfBufferAddress = sc->aac_common_busaddr + 1889c6eafcf2SScott Long offsetof(struct aac_common, ac_printf); 189035863739SMike Smith ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; 189135863739SMike Smith 18924b00f859SScott Long /* 18934b00f859SScott Long * The adapter assumes that pages are 4K in size, except on some 18944b00f859SScott Long * broken firmware versions that do the page->byte conversion twice, 18954b00f859SScott Long * therefore 'assuming' that this value is in 16MB units (2^24). 18964b00f859SScott Long * Round up since the granularity is so high. 18974b00f859SScott Long */ 1898f30ac74cSScott Long ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; 18994b00f859SScott Long if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { 19004b00f859SScott Long ip->HostPhysMemPages = 19014b00f859SScott Long (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; 1902204c0befSScott Long } 19032b3b0f17SScott Long ip->HostElapsedSeconds = time_uptime; /* reset later if invalid */ 190435863739SMike Smith 19057cb209f5SScott Long ip->InitFlags = 0; 19067cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) { 19077cb209f5SScott Long ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED; 19087cb209f5SScott Long device_printf(sc->aac_dev, "New comm. interface enabled\n"); 19097cb209f5SScott Long } 19107cb209f5SScott Long 19117cb209f5SScott Long ip->MaxIoCommands = sc->aac_max_fibs; 19127cb209f5SScott Long ip->MaxIoSize = sc->aac_max_sectors << 9; 19137cb209f5SScott Long ip->MaxFibSize = sc->aac_max_fib_size; 19147cb209f5SScott Long 191535863739SMike Smith /* 19164109ba51SEd Maste * Initialize FIB queues. Note that it appears that the layout of the 1917c6eafcf2SScott Long * indexes and the segmentation of the entries may be mandated by the 1918c6eafcf2SScott Long * adapter, which is only told about the base of the queue index fields. 191935863739SMike Smith * 192035863739SMike Smith * The initial values of the indices are assumed to inform the adapter 1921914da7d0SScott Long * of the sizes of the respective queues, and theoretically it could 1922914da7d0SScott Long * work out the entire layout of the queue structures from this. We 1923914da7d0SScott Long * take the easy route and just lay this area out like everyone else 1924914da7d0SScott Long * does. 192535863739SMike Smith * 1926914da7d0SScott Long * The Linux driver uses a much more complex scheme whereby several 1927914da7d0SScott Long * header records are kept for each queue. We use a couple of generic 1928914da7d0SScott Long * list manipulation functions which 'know' the size of each list by 1929914da7d0SScott Long * virtue of a table. 193035863739SMike Smith */ 1931b88ffdc8SScott Long qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; 19320bcbebd6SScott Long qoffset &= ~(AAC_QUEUE_ALIGN - 1); 19330bcbebd6SScott Long sc->aac_queues = 19340bcbebd6SScott Long (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); 1935b88ffdc8SScott Long ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; 193635863739SMike Smith 1937c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1938c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1939c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1940c6eafcf2SScott Long AAC_HOST_NORM_CMD_ENTRIES; 1941c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1942c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1943c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1944c6eafcf2SScott Long AAC_HOST_HIGH_CMD_ENTRIES; 1945c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1946c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1947c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1948c6eafcf2SScott Long AAC_ADAP_NORM_CMD_ENTRIES; 1949c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = 1950c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1951c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = 1952c6eafcf2SScott Long AAC_ADAP_HIGH_CMD_ENTRIES; 1953c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1954c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1955c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1956c6eafcf2SScott Long AAC_HOST_NORM_RESP_ENTRIES; 1957c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1958c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1959c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1960c6eafcf2SScott Long AAC_HOST_HIGH_RESP_ENTRIES; 1961c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1962c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1963c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1964c6eafcf2SScott Long AAC_ADAP_NORM_RESP_ENTRIES; 1965c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= 1966c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1967c6eafcf2SScott Long sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= 1968c6eafcf2SScott Long AAC_ADAP_HIGH_RESP_ENTRIES; 1969c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = 1970c6eafcf2SScott Long &sc->aac_queues->qt_HostNormCmdQueue[0]; 1971c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = 1972c6eafcf2SScott Long &sc->aac_queues->qt_HostHighCmdQueue[0]; 1973c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = 1974c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormCmdQueue[0]; 1975c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = 1976c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighCmdQueue[0]; 1977c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = 1978c6eafcf2SScott Long &sc->aac_queues->qt_HostNormRespQueue[0]; 1979c6eafcf2SScott Long sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = 1980c6eafcf2SScott Long &sc->aac_queues->qt_HostHighRespQueue[0]; 1981c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = 1982c6eafcf2SScott Long &sc->aac_queues->qt_AdapNormRespQueue[0]; 1983c6eafcf2SScott Long sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = 1984c6eafcf2SScott Long &sc->aac_queues->qt_AdapHighRespQueue[0]; 198535863739SMike Smith 198635863739SMike Smith /* 198735863739SMike Smith * Do controller-type-specific initialisation 198835863739SMike Smith */ 198935863739SMike Smith switch (sc->aac_hwif) { 199035863739SMike Smith case AAC_HWIF_I960RX: 1991ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); 199235863739SMike Smith break; 19934afedc31SScott Long case AAC_HWIF_RKT: 1994ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); 19954afedc31SScott Long break; 19964afedc31SScott Long default: 19974afedc31SScott Long break; 199835863739SMike Smith } 199935863739SMike Smith 200035863739SMike Smith /* 200135863739SMike Smith * Give the init structure to the controller. 200235863739SMike Smith */ 200335863739SMike Smith if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, 2004914da7d0SScott Long sc->aac_common_busaddr + 2005914da7d0SScott Long offsetof(struct aac_common, ac_init), 0, 0, 0, 2006914da7d0SScott Long NULL)) { 2007914da7d0SScott Long device_printf(sc->aac_dev, 2008914da7d0SScott Long "error establishing init structure\n"); 2009a6d35632SScott Long error = EIO; 2010a6d35632SScott Long goto out; 201135863739SMike Smith } 201235863739SMike Smith 2013a6d35632SScott Long error = 0; 2014a6d35632SScott Long out: 2015a6d35632SScott Long return(error); 201635863739SMike Smith } 201735863739SMike Smith 201804f4d586SEd Maste static int 201904f4d586SEd Maste aac_setup_intr(struct aac_softc *sc) 202004f4d586SEd Maste { 202104f4d586SEd Maste sc->aac_irq_rid = 0; 202204f4d586SEd Maste if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, 202304f4d586SEd Maste &sc->aac_irq_rid, 202404f4d586SEd Maste RF_SHAREABLE | 202504f4d586SEd Maste RF_ACTIVE)) == NULL) { 202604f4d586SEd Maste device_printf(sc->aac_dev, "can't allocate interrupt\n"); 202704f4d586SEd Maste return (EINVAL); 202804f4d586SEd Maste } 202904f4d586SEd Maste if (sc->flags & AAC_FLAGS_NEW_COMM) { 203004f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 203104f4d586SEd Maste INTR_MPSAFE|INTR_TYPE_BIO, NULL, 203204f4d586SEd Maste aac_new_intr, sc, &sc->aac_intr)) { 203304f4d586SEd Maste device_printf(sc->aac_dev, "can't set up interrupt\n"); 203404f4d586SEd Maste return (EINVAL); 203504f4d586SEd Maste } 203604f4d586SEd Maste } else { 203704f4d586SEd Maste if (bus_setup_intr(sc->aac_dev, sc->aac_irq, 2038e46b9eeaSEd Maste INTR_TYPE_BIO, aac_filter, NULL, 203904f4d586SEd Maste sc, &sc->aac_intr)) { 204004f4d586SEd Maste device_printf(sc->aac_dev, 2041e46b9eeaSEd Maste "can't set up interrupt filter\n"); 204204f4d586SEd Maste return (EINVAL); 204304f4d586SEd Maste } 204404f4d586SEd Maste } 204504f4d586SEd Maste return (0); 204604f4d586SEd Maste } 204704f4d586SEd Maste 2048914da7d0SScott Long /* 204935863739SMike Smith * Send a synchronous command to the controller and wait for a result. 20507cb209f5SScott Long * Indicate if the controller completed the command with an error status. 205135863739SMike Smith */ 205235863739SMike Smith static int 205335863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command, 205435863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, 205535863739SMike Smith u_int32_t *sp) 205635863739SMike Smith { 205735863739SMike Smith time_t then; 205835863739SMike Smith u_int32_t status; 205935863739SMike Smith 206031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 206135863739SMike Smith 206235863739SMike Smith /* populate the mailbox */ 206335863739SMike Smith AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); 206435863739SMike Smith 206535863739SMike Smith /* ensure the sync command doorbell flag is cleared */ 206635863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 206735863739SMike Smith 206835863739SMike Smith /* then set it to signal the adapter */ 206935863739SMike Smith AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); 207035863739SMike Smith 207135863739SMike Smith /* spin waiting for the command to complete */ 20722b3b0f17SScott Long then = time_uptime; 207335863739SMike Smith do { 20742b3b0f17SScott Long if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) { 207531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); 207635863739SMike Smith return(EIO); 207735863739SMike Smith } 207835863739SMike Smith } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); 207935863739SMike Smith 208035863739SMike Smith /* clear the completion flag */ 208135863739SMike Smith AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); 208235863739SMike Smith 208335863739SMike Smith /* get the command status */ 2084a6d35632SScott Long status = AAC_GET_MAILBOX(sc, 0); 208535863739SMike Smith if (sp != NULL) 208635863739SMike Smith *sp = status; 20877cb209f5SScott Long 2088a441b3fcSScott Long if (status != AAC_SRB_STS_SUCCESS) 20897cb209f5SScott Long return (-1); 20900b94a66eSMike Smith return(0); 209135863739SMike Smith } 209235863739SMike Smith 2093cbfd045bSScott Long int 209435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, 2095cbfd045bSScott Long struct aac_fib *fib, u_int16_t datasize) 209635863739SMike Smith { 209731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 20987cb209f5SScott Long mtx_assert(&sc->aac_io_lock, MA_OWNED); 209935863739SMike Smith 210035863739SMike Smith if (datasize > AAC_FIB_DATASIZE) 210135863739SMike Smith return(EINVAL); 210235863739SMike Smith 210335863739SMike Smith /* 210435863739SMike Smith * Set up the sync FIB 210535863739SMike Smith */ 2106914da7d0SScott Long fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | 2107914da7d0SScott Long AAC_FIBSTATE_INITIALISED | 2108c6eafcf2SScott Long AAC_FIBSTATE_EMPTY; 210935863739SMike Smith fib->Header.XferState |= xferstate; 211035863739SMike Smith fib->Header.Command = command; 211135863739SMike Smith fib->Header.StructType = AAC_FIBTYPE_TFIB; 211242ef13a2SEd Maste fib->Header.Size = sizeof(struct aac_fib_header) + datasize; 211335863739SMike Smith fib->Header.SenderSize = sizeof(struct aac_fib); 2114b88ffdc8SScott Long fib->Header.SenderFibAddress = 0; /* Not needed */ 2115c6eafcf2SScott Long fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + 2116914da7d0SScott Long offsetof(struct aac_common, 2117914da7d0SScott Long ac_sync_fib); 211835863739SMike Smith 211935863739SMike Smith /* 212035863739SMike Smith * Give the FIB to the controller, wait for a response. 212135863739SMike Smith */ 2122914da7d0SScott Long if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, 2123914da7d0SScott Long fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { 212431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); 212535863739SMike Smith return(EIO); 212635863739SMike Smith } 212735863739SMike Smith 212835863739SMike Smith return (0); 212935863739SMike Smith } 213035863739SMike Smith 2131914da7d0SScott Long /* 213235863739SMike Smith * Adapter-space FIB queue manipulation 213335863739SMike Smith * 213435863739SMike Smith * Note that the queue implementation here is a little funky; neither the PI or 213535863739SMike Smith * CI will ever be zero. This behaviour is a controller feature. 213635863739SMike Smith */ 213735863739SMike Smith static struct { 213835863739SMike Smith int size; 213935863739SMike Smith int notify; 214035863739SMike Smith } aac_qinfo[] = { 214135863739SMike Smith {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, 214235863739SMike Smith {AAC_HOST_HIGH_CMD_ENTRIES, 0}, 214335863739SMike Smith {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, 214435863739SMike Smith {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, 214535863739SMike Smith {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, 214635863739SMike Smith {AAC_HOST_HIGH_RESP_ENTRIES, 0}, 214735863739SMike Smith {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, 214835863739SMike Smith {AAC_ADAP_HIGH_RESP_ENTRIES, 0} 214935863739SMike Smith }; 215035863739SMike Smith 215135863739SMike Smith /* 2152c6eafcf2SScott Long * Atomically insert an entry into the nominated queue, returns 0 on success or 2153c6eafcf2SScott Long * EBUSY if the queue is full. 215435863739SMike Smith * 21550b94a66eSMike Smith * Note: it would be more efficient to defer notifying the controller in 2156914da7d0SScott Long * the case where we may be inserting several entries in rapid succession, 2157914da7d0SScott Long * but implementing this usefully may be difficult (it would involve a 2158c6eafcf2SScott Long * separate queue/notify interface). 215935863739SMike Smith */ 216035863739SMike Smith static int 2161f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) 216235863739SMike Smith { 216335863739SMike Smith u_int32_t pi, ci; 21649e2e96d8SScott Long int error; 2165f6c4dd3fSScott Long u_int32_t fib_size; 2166f6c4dd3fSScott Long u_int32_t fib_addr; 2167f6c4dd3fSScott Long 216831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 216936e0bf6eSScott Long 2170f6c4dd3fSScott Long fib_size = cm->cm_fib->Header.Size; 2171f6c4dd3fSScott Long fib_addr = cm->cm_fib->Header.ReceiverFibAddress; 217235863739SMike Smith 217335863739SMike Smith /* get the producer/consumer indices */ 217435863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 217535863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 217635863739SMike Smith 217735863739SMike Smith /* wrap the queue? */ 217835863739SMike Smith if (pi >= aac_qinfo[queue].size) 217935863739SMike Smith pi = 0; 218035863739SMike Smith 218135863739SMike Smith /* check for queue full */ 218235863739SMike Smith if ((pi + 1) == ci) { 218335863739SMike Smith error = EBUSY; 218435863739SMike Smith goto out; 218535863739SMike Smith } 218635863739SMike Smith 2187614c22b2SScott Long /* 2188614c22b2SScott Long * To avoid a race with its completion interrupt, place this command on 2189614c22b2SScott Long * the busy queue prior to advertising it to the controller. 2190614c22b2SScott Long */ 2191614c22b2SScott Long aac_enqueue_busy(cm); 2192614c22b2SScott Long 219335863739SMike Smith /* populate queue entry */ 219435863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 219535863739SMike Smith (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 219635863739SMike Smith 219735863739SMike Smith /* update producer index */ 219835863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 219935863739SMike Smith 220035863739SMike Smith /* notify the adapter if we know how */ 220135863739SMike Smith if (aac_qinfo[queue].notify != 0) 220235863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 220335863739SMike Smith 220435863739SMike Smith error = 0; 220535863739SMike Smith 220635863739SMike Smith out: 220735863739SMike Smith return(error); 220835863739SMike Smith } 220935863739SMike Smith 221035863739SMike Smith /* 221136e0bf6eSScott Long * Atomically remove one entry from the nominated queue, returns 0 on 221236e0bf6eSScott Long * success or ENOENT if the queue is empty. 221335863739SMike Smith */ 221435863739SMike Smith static int 2215c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, 2216c6eafcf2SScott Long struct aac_fib **fib_addr) 221735863739SMike Smith { 221835863739SMike Smith u_int32_t pi, ci; 2219149af931SScott Long u_int32_t fib_index; 22209e2e96d8SScott Long int error; 2221f6c4dd3fSScott Long int notify; 222235863739SMike Smith 222331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 222435863739SMike Smith 222535863739SMike Smith /* get the producer/consumer indices */ 222635863739SMike Smith pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 222735863739SMike Smith ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 222835863739SMike Smith 222935863739SMike Smith /* check for queue empty */ 223035863739SMike Smith if (ci == pi) { 223135863739SMike Smith error = ENOENT; 223235863739SMike Smith goto out; 223335863739SMike Smith } 223435863739SMike Smith 22357753acd2SScott Long /* wrap the pi so the following test works */ 22367753acd2SScott Long if (pi >= aac_qinfo[queue].size) 22377753acd2SScott Long pi = 0; 22387753acd2SScott Long 2239f6c4dd3fSScott Long notify = 0; 2240f6c4dd3fSScott Long if (ci == pi + 1) 2241f6c4dd3fSScott Long notify++; 2242f6c4dd3fSScott Long 224335863739SMike Smith /* wrap the queue? */ 224435863739SMike Smith if (ci >= aac_qinfo[queue].size) 224535863739SMike Smith ci = 0; 224635863739SMike Smith 224735863739SMike Smith /* fetch the entry */ 224835863739SMike Smith *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; 2249149af931SScott Long 2250149af931SScott Long switch (queue) { 2251149af931SScott Long case AAC_HOST_NORM_CMD_QUEUE: 2252149af931SScott Long case AAC_HOST_HIGH_CMD_QUEUE: 2253149af931SScott Long /* 2254149af931SScott Long * The aq_fib_addr is only 32 bits wide so it can't be counted 2255149af931SScott Long * on to hold an address. For AIF's, the adapter assumes 2256149af931SScott Long * that it's giving us an address into the array of AIF fibs. 2257149af931SScott Long * Therefore, we have to convert it to an index. 2258149af931SScott Long */ 2259149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / 2260149af931SScott Long sizeof(struct aac_fib); 2261149af931SScott Long *fib_addr = &sc->aac_common->ac_fibs[fib_index]; 2262149af931SScott Long break; 2263149af931SScott Long 2264149af931SScott Long case AAC_HOST_NORM_RESP_QUEUE: 2265149af931SScott Long case AAC_HOST_HIGH_RESP_QUEUE: 2266149af931SScott Long { 2267149af931SScott Long struct aac_command *cm; 2268149af931SScott Long 2269149af931SScott Long /* 2270149af931SScott Long * As above, an index is used instead of an actual address. 2271149af931SScott Long * Gotta shift the index to account for the fast response 2272149af931SScott Long * bit. No other correction is needed since this value was 2273149af931SScott Long * originally provided by the driver via the SenderFibAddress 2274149af931SScott Long * field. 2275149af931SScott Long */ 2276149af931SScott Long fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; 22777cb209f5SScott Long cm = sc->aac_commands + (fib_index >> 2); 2278149af931SScott Long *fib_addr = cm->cm_fib; 227935863739SMike Smith 2280f30ac74cSScott Long /* 2281f30ac74cSScott Long * Is this a fast response? If it is, update the fib fields in 2282149af931SScott Long * local memory since the whole fib isn't DMA'd back up. 2283f30ac74cSScott Long */ 2284149af931SScott Long if (fib_index & 0x01) { 2285f30ac74cSScott Long (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; 2286f30ac74cSScott Long *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; 2287f30ac74cSScott Long } 2288149af931SScott Long break; 2289149af931SScott Long } 2290149af931SScott Long default: 2291149af931SScott Long panic("Invalid queue in aac_dequeue_fib()"); 2292149af931SScott Long break; 2293149af931SScott Long } 2294149af931SScott Long 229535863739SMike Smith /* update consumer index */ 229635863739SMike Smith sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; 229735863739SMike Smith 229835863739SMike Smith /* if we have made the queue un-full, notify the adapter */ 2299f6c4dd3fSScott Long if (notify && (aac_qinfo[queue].notify != 0)) 230035863739SMike Smith AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 230135863739SMike Smith error = 0; 230235863739SMike Smith 230335863739SMike Smith out: 230435863739SMike Smith return(error); 230535863739SMike Smith } 230635863739SMike Smith 2307914da7d0SScott Long /* 230836e0bf6eSScott Long * Put our response to an Adapter Initialed Fib on the response queue 230936e0bf6eSScott Long */ 231036e0bf6eSScott Long static int 231136e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) 231236e0bf6eSScott Long { 231336e0bf6eSScott Long u_int32_t pi, ci; 23149e2e96d8SScott Long int error; 231536e0bf6eSScott Long u_int32_t fib_size; 231636e0bf6eSScott Long u_int32_t fib_addr; 231736e0bf6eSScott Long 231831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 231936e0bf6eSScott Long 232036e0bf6eSScott Long /* Tell the adapter where the FIB is */ 232136e0bf6eSScott Long fib_size = fib->Header.Size; 232236e0bf6eSScott Long fib_addr = fib->Header.SenderFibAddress; 232336e0bf6eSScott Long fib->Header.ReceiverFibAddress = fib_addr; 232436e0bf6eSScott Long 232536e0bf6eSScott Long /* get the producer/consumer indices */ 232636e0bf6eSScott Long pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; 232736e0bf6eSScott Long ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; 232836e0bf6eSScott Long 232936e0bf6eSScott Long /* wrap the queue? */ 233036e0bf6eSScott Long if (pi >= aac_qinfo[queue].size) 233136e0bf6eSScott Long pi = 0; 233236e0bf6eSScott Long 233336e0bf6eSScott Long /* check for queue full */ 233436e0bf6eSScott Long if ((pi + 1) == ci) { 233536e0bf6eSScott Long error = EBUSY; 233636e0bf6eSScott Long goto out; 233736e0bf6eSScott Long } 233836e0bf6eSScott Long 233936e0bf6eSScott Long /* populate queue entry */ 234036e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; 234136e0bf6eSScott Long (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; 234236e0bf6eSScott Long 234336e0bf6eSScott Long /* update producer index */ 234436e0bf6eSScott Long sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; 234536e0bf6eSScott Long 234636e0bf6eSScott Long /* notify the adapter if we know how */ 234736e0bf6eSScott Long if (aac_qinfo[queue].notify != 0) 234836e0bf6eSScott Long AAC_QNOTIFY(sc, aac_qinfo[queue].notify); 234936e0bf6eSScott Long 235036e0bf6eSScott Long error = 0; 235136e0bf6eSScott Long 235236e0bf6eSScott Long out: 235336e0bf6eSScott Long return(error); 235436e0bf6eSScott Long } 235536e0bf6eSScott Long 2356914da7d0SScott Long /* 23570b94a66eSMike Smith * Check for commands that have been outstanding for a suspiciously long time, 23580b94a66eSMike Smith * and complain about them. 23590b94a66eSMike Smith */ 23600b94a66eSMike Smith static void 23610b94a66eSMike Smith aac_timeout(struct aac_softc *sc) 23620b94a66eSMike Smith { 23630b94a66eSMike Smith struct aac_command *cm; 23640b94a66eSMike Smith time_t deadline; 236515c37be0SScott Long int timedout, code; 23660b94a66eSMike Smith 2367f6c4dd3fSScott Long /* 236870545d1aSScott Long * Traverse the busy command list, bitch about late commands once 2369914da7d0SScott Long * only. 2370914da7d0SScott Long */ 237115c37be0SScott Long timedout = 0; 23722b3b0f17SScott Long deadline = time_uptime - AAC_CMD_TIMEOUT; 23730b94a66eSMike Smith TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { 2374f6c4dd3fSScott Long if ((cm->cm_timestamp < deadline) 2375f6c4dd3fSScott Long /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { 23760b94a66eSMike Smith cm->cm_flags |= AAC_CMD_TIMEDOUT; 2377914da7d0SScott Long device_printf(sc->aac_dev, 2378914da7d0SScott Long "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 23792b3b0f17SScott Long cm, (int)(time_uptime-cm->cm_timestamp)); 23800b94a66eSMike Smith AAC_PRINT_FIB(sc, cm->cm_fib); 238115c37be0SScott Long timedout++; 23820b94a66eSMike Smith } 23830b94a66eSMike Smith } 23840b94a66eSMike Smith 238515c37be0SScott Long if (timedout) { 238615c37be0SScott Long code = AAC_GET_FWSTATUS(sc); 238715c37be0SScott Long if (code != AAC_UP_AND_RUNNING) { 238815c37be0SScott Long device_printf(sc->aac_dev, "WARNING! Controller is no " 238915c37be0SScott Long "longer running! code= 0x%x\n", code); 239015c37be0SScott Long } 239115c37be0SScott Long } 23920b94a66eSMike Smith return; 23930b94a66eSMike Smith } 23940b94a66eSMike Smith 2395914da7d0SScott Long /* 2396914da7d0SScott Long * Interface Function Vectors 2397914da7d0SScott Long */ 239835863739SMike Smith 2399914da7d0SScott Long /* 240035863739SMike Smith * Read the current firmware status word. 240135863739SMike Smith */ 240235863739SMike Smith static int 240335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc) 240435863739SMike Smith { 240531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 240635863739SMike Smith 2407ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); 240835863739SMike Smith } 240935863739SMike Smith 241035863739SMike Smith static int 241135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc) 241235863739SMike Smith { 241331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 241435863739SMike Smith 24154824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 24164824be88SEd Maste AAC_RX_OMR0 : AAC_RX_FWSTATUS)); 241735863739SMike Smith } 241835863739SMike Smith 2419b3457b51SScott Long static int 2420b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc) 2421b3457b51SScott Long { 2422b3457b51SScott Long int val; 2423b3457b51SScott Long 242431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2425b3457b51SScott Long 2426ff0991c4SAttilio Rao val = AAC_MEM0_GETREG4(sc, AAC_FA_FWSTATUS); 2427b3457b51SScott Long return (val); 2428b3457b51SScott Long } 2429b3457b51SScott Long 24304afedc31SScott Long static int 24314afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc) 24324afedc31SScott Long { 243331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24344afedc31SScott Long 24354824be88SEd Maste return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? 24364824be88SEd Maste AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); 24374afedc31SScott Long } 24384afedc31SScott Long 2439914da7d0SScott Long /* 244035863739SMike Smith * Notify the controller of a change in a given queue 244135863739SMike Smith */ 244235863739SMike Smith 244335863739SMike Smith static void 244435863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit) 244535863739SMike Smith { 244631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 244735863739SMike Smith 2448ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 244935863739SMike Smith } 245035863739SMike Smith 245135863739SMike Smith static void 245235863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit) 245335863739SMike Smith { 245431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 245535863739SMike Smith 2456ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); 245735863739SMike Smith } 245835863739SMike Smith 2459b3457b51SScott Long static void 2460b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit) 2461b3457b51SScott Long { 246231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2463b3457b51SScott Long 2464ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL1, qbit); 2465b3457b51SScott Long AAC_FA_HACK(sc); 2466b3457b51SScott Long } 2467b3457b51SScott Long 24684afedc31SScott Long static void 24694afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit) 24704afedc31SScott Long { 247131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 24724afedc31SScott Long 2473ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); 24744afedc31SScott Long } 24754afedc31SScott Long 2476914da7d0SScott Long /* 247735863739SMike Smith * Get the interrupt reason bits 247835863739SMike Smith */ 247935863739SMike Smith static int 248035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc) 248135863739SMike Smith { 248231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 248335863739SMike Smith 2484ff0991c4SAttilio Rao return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); 248535863739SMike Smith } 248635863739SMike Smith 248735863739SMike Smith static int 248835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc) 248935863739SMike Smith { 249031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 249135863739SMike Smith 2492ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); 249335863739SMike Smith } 249435863739SMike Smith 2495b3457b51SScott Long static int 2496b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc) 2497b3457b51SScott Long { 2498b3457b51SScott Long int val; 2499b3457b51SScott Long 250031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2501b3457b51SScott Long 2502ff0991c4SAttilio Rao val = AAC_MEM0_GETREG2(sc, AAC_FA_DOORBELL0); 2503b3457b51SScott Long return (val); 2504b3457b51SScott Long } 2505b3457b51SScott Long 25064afedc31SScott Long static int 25074afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc) 25084afedc31SScott Long { 250931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25104afedc31SScott Long 2511ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); 25124afedc31SScott Long } 25134afedc31SScott Long 2514914da7d0SScott Long /* 251535863739SMike Smith * Clear some interrupt reason bits 251635863739SMike Smith */ 251735863739SMike Smith static void 251835863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask) 251935863739SMike Smith { 252031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 252135863739SMike Smith 2522ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 252335863739SMike Smith } 252435863739SMike Smith 252535863739SMike Smith static void 252635863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask) 252735863739SMike Smith { 252831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 252935863739SMike Smith 2530ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); 253135863739SMike Smith } 253235863739SMike Smith 2533b3457b51SScott Long static void 2534b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask) 2535b3457b51SScott Long { 253631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2537b3457b51SScott Long 2538ff0991c4SAttilio Rao AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask); 2539b3457b51SScott Long AAC_FA_HACK(sc); 2540b3457b51SScott Long } 2541b3457b51SScott Long 25424afedc31SScott Long static void 25434afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask) 25444afedc31SScott Long { 254531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 25464afedc31SScott Long 2547ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); 25484afedc31SScott Long } 25494afedc31SScott Long 2550914da7d0SScott Long /* 255135863739SMike Smith * Populate the mailbox and set the command word 255235863739SMike Smith */ 255335863739SMike Smith static void 255435863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 255535863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 255635863739SMike Smith { 255731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 255835863739SMike Smith 2559ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); 2560ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 2561ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 2562ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 2563ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 256435863739SMike Smith } 256535863739SMike Smith 256635863739SMike Smith static void 256735863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 256835863739SMike Smith u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 256935863739SMike Smith { 257031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 257135863739SMike Smith 2572ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); 2573ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 2574ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 2575ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 2576ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 257735863739SMike Smith } 257835863739SMike Smith 2579b3457b51SScott Long static void 2580b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command, 2581b3457b51SScott Long u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 2582b3457b51SScott Long { 258331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2584b3457b51SScott Long 2585ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX, command); 2586b3457b51SScott Long AAC_FA_HACK(sc); 2587ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0); 2588b3457b51SScott Long AAC_FA_HACK(sc); 2589ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1); 2590b3457b51SScott Long AAC_FA_HACK(sc); 2591ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2); 2592b3457b51SScott Long AAC_FA_HACK(sc); 2593ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3); 2594b3457b51SScott Long AAC_FA_HACK(sc); 2595b3457b51SScott Long } 2596b3457b51SScott Long 25974afedc31SScott Long static void 25984afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, 25994afedc31SScott Long u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 26004afedc31SScott Long { 260131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26024afedc31SScott Long 2603ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); 2604ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); 2605ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); 2606ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); 2607ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); 26084afedc31SScott Long } 26094afedc31SScott Long 2610914da7d0SScott Long /* 261135863739SMike Smith * Fetch the immediate command status word 261235863739SMike Smith */ 261335863739SMike Smith static int 2614a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb) 261535863739SMike Smith { 261631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 261735863739SMike Smith 2618ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); 261935863739SMike Smith } 262035863739SMike Smith 262135863739SMike Smith static int 2622a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb) 262335863739SMike Smith { 262431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 262535863739SMike Smith 2626ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); 262735863739SMike Smith } 262835863739SMike Smith 2629b3457b51SScott Long static int 2630a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb) 2631b3457b51SScott Long { 2632b3457b51SScott Long int val; 2633b3457b51SScott Long 263431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2635b3457b51SScott Long 2636ff0991c4SAttilio Rao val = AAC_MEM1_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4)); 2637b3457b51SScott Long return (val); 2638b3457b51SScott Long } 2639b3457b51SScott Long 26404afedc31SScott Long static int 26414afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb) 26424afedc31SScott Long { 264331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 26444afedc31SScott Long 2645ff0991c4SAttilio Rao return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); 26464afedc31SScott Long } 26474afedc31SScott Long 2648914da7d0SScott Long /* 264935863739SMike Smith * Set/clear interrupt masks 265035863739SMike Smith */ 265135863739SMike Smith static void 265235863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable) 265335863739SMike Smith { 265431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 265535863739SMike Smith 265635863739SMike Smith if (enable) { 2657ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 265835863739SMike Smith } else { 2659ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 266035863739SMike Smith } 266135863739SMike Smith } 266235863739SMike Smith 266335863739SMike Smith static void 266435863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable) 266535863739SMike Smith { 266631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 266735863739SMike Smith 266835863739SMike Smith if (enable) { 26697cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2670ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); 26717cb209f5SScott Long else 2672ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 267335863739SMike Smith } else { 2674ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); 267535863739SMike Smith } 267635863739SMike Smith } 267735863739SMike Smith 2678b3457b51SScott Long static void 2679b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable) 2680b3457b51SScott Long { 268131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 2682b3457b51SScott Long 2683b3457b51SScott Long if (enable) { 2684ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 2685b3457b51SScott Long AAC_FA_HACK(sc); 2686b3457b51SScott Long } else { 2687ff0991c4SAttilio Rao AAC_MEM0_SETREG2((sc), AAC_FA_MASK0, ~0); 2688b3457b51SScott Long AAC_FA_HACK(sc); 2689b3457b51SScott Long } 2690b3457b51SScott Long } 2691b3457b51SScott Long 26924afedc31SScott Long static void 26934afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable) 26944afedc31SScott Long { 269531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); 26964afedc31SScott Long 26974afedc31SScott Long if (enable) { 26987cb209f5SScott Long if (sc->flags & AAC_FLAGS_NEW_COMM) 2699ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); 27007cb209f5SScott Long else 2701ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); 27024afedc31SScott Long } else { 2703ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); 27044afedc31SScott Long } 27054afedc31SScott Long } 27064afedc31SScott Long 2707914da7d0SScott Long /* 27087cb209f5SScott Long * New comm. interface: Send command functions 27097cb209f5SScott Long */ 27107cb209f5SScott Long static int 27117cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) 27127cb209f5SScott Long { 27137cb209f5SScott Long u_int32_t index, device; 27147cb209f5SScott Long 271531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 27167cb209f5SScott Long 2717ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 27187cb209f5SScott Long if (index == 0xffffffffL) 2719ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); 27207cb209f5SScott Long if (index == 0xffffffffL) 27217cb209f5SScott Long return index; 27227cb209f5SScott Long aac_enqueue_busy(cm); 27237cb209f5SScott Long device = index; 2724ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 27257cb209f5SScott Long device += 4; 2726ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 27277cb209f5SScott Long device += 4; 2728ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2729ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); 27307cb209f5SScott Long return 0; 27317cb209f5SScott Long } 27327cb209f5SScott Long 27337cb209f5SScott Long static int 27347cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) 27357cb209f5SScott Long { 27367cb209f5SScott Long u_int32_t index, device; 27377cb209f5SScott Long 273831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); 27397cb209f5SScott Long 2740ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 27417cb209f5SScott Long if (index == 0xffffffffL) 2742ff0991c4SAttilio Rao index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); 27437cb209f5SScott Long if (index == 0xffffffffL) 27447cb209f5SScott Long return index; 27457cb209f5SScott Long aac_enqueue_busy(cm); 27467cb209f5SScott Long device = index; 2747ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); 27487cb209f5SScott Long device += 4; 2749ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); 27507cb209f5SScott Long device += 4; 2751ff0991c4SAttilio Rao AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); 2752ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); 27537cb209f5SScott Long return 0; 27547cb209f5SScott Long } 27557cb209f5SScott Long 27567cb209f5SScott Long /* 27577cb209f5SScott Long * New comm. interface: get, set outbound queue index 27587cb209f5SScott Long */ 27597cb209f5SScott Long static int 27607cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc) 27617cb209f5SScott Long { 276231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 27637cb209f5SScott Long 2764ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); 27657cb209f5SScott Long } 27667cb209f5SScott Long 27677cb209f5SScott Long static int 27687cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc) 27697cb209f5SScott Long { 277031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 27717cb209f5SScott Long 2772ff0991c4SAttilio Rao return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); 27737cb209f5SScott Long } 27747cb209f5SScott Long 27757cb209f5SScott Long static void 27767cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index) 27777cb209f5SScott Long { 277831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 27797cb209f5SScott Long 2780ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); 27817cb209f5SScott Long } 27827cb209f5SScott Long 27837cb209f5SScott Long static void 27847cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index) 27857cb209f5SScott Long { 278631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 27877cb209f5SScott Long 2788ff0991c4SAttilio Rao AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); 27897cb209f5SScott Long } 27907cb209f5SScott Long 27917cb209f5SScott Long /* 2792914da7d0SScott Long * Debugging and Diagnostics 2793914da7d0SScott Long */ 279435863739SMike Smith 2795914da7d0SScott Long /* 279635863739SMike Smith * Print some information about the controller. 279735863739SMike Smith */ 279835863739SMike Smith static void 279935863739SMike Smith aac_describe_controller(struct aac_softc *sc) 280035863739SMike Smith { 2801cbfd045bSScott Long struct aac_fib *fib; 280235863739SMike Smith struct aac_adapter_info *info; 28037ea2d558SEd Maste char *adapter_type = "Adaptec RAID controller"; 280435863739SMike Smith 280531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 280635863739SMike Smith 280781b3da08SScott Long mtx_lock(&sc->aac_io_lock); 280803b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 2809cbfd045bSScott Long 2810cbfd045bSScott Long fib->data[0] = 0; 2811cbfd045bSScott Long if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { 281235863739SMike Smith device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); 2813fe3cb0e1SScott Long aac_release_sync_fib(sc); 281481b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 281535863739SMike Smith return; 281635863739SMike Smith } 281735863739SMike Smith 2818bd971c49SScott Long /* save the kernel revision structure for later use */ 2819bd971c49SScott Long info = (struct aac_adapter_info *)&fib->data[0]; 2820bd971c49SScott Long sc->aac_revision = info->KernelRevision; 2821bd971c49SScott Long 2822bd971c49SScott Long if (bootverbose) { 2823b1c56c68SScott Long device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " 2824b1c56c68SScott Long "(%dMB cache, %dMB execution), %s\n", 2825c6eafcf2SScott Long aac_describe_code(aac_cpu_variant, info->CpuVariant), 2826b1c56c68SScott Long info->ClockSpeed, info->TotalMem / (1024 * 1024), 2827b1c56c68SScott Long info->BufferMem / (1024 * 1024), 2828b1c56c68SScott Long info->ExecutionMem / (1024 * 1024), 2829914da7d0SScott Long aac_describe_code(aac_battery_platform, 2830914da7d0SScott Long info->batteryPlatform)); 283135863739SMike Smith 2832bd971c49SScott Long device_printf(sc->aac_dev, 2833bd971c49SScott Long "Kernel %d.%d-%d, Build %d, S/N %6X\n", 283435863739SMike Smith info->KernelRevision.external.comp.major, 283535863739SMike Smith info->KernelRevision.external.comp.minor, 283635863739SMike Smith info->KernelRevision.external.comp.dash, 283736e0bf6eSScott Long info->KernelRevision.buildNumber, 283836e0bf6eSScott Long (u_int32_t)(info->SerialNumber & 0xffffff)); 2839fe3cb0e1SScott Long 2840a6d35632SScott Long device_printf(sc->aac_dev, "Supported Options=%b\n", 2841a6d35632SScott Long sc->supported_options, 2842a6d35632SScott Long "\20" 2843a6d35632SScott Long "\1SNAPSHOT" 2844a6d35632SScott Long "\2CLUSTERS" 2845a6d35632SScott Long "\3WCACHE" 2846a6d35632SScott Long "\4DATA64" 2847a6d35632SScott Long "\5HOSTTIME" 2848a6d35632SScott Long "\6RAID50" 2849a6d35632SScott Long "\7WINDOW4GB" 2850a6d35632SScott Long "\10SCSIUPGD" 2851a6d35632SScott Long "\11SOFTERR" 2852a6d35632SScott Long "\12NORECOND" 2853a6d35632SScott Long "\13SGMAP64" 2854a6d35632SScott Long "\14ALARM" 28557cb209f5SScott Long "\15NONDASD" 28567cb209f5SScott Long "\16SCSIMGT" 28577cb209f5SScott Long "\17RAIDSCSI" 28587cb209f5SScott Long "\21ADPTINFO" 28597cb209f5SScott Long "\22NEWCOMM" 28607cb209f5SScott Long "\23ARRAY64BIT" 28617cb209f5SScott Long "\24HEATSENSOR"); 2862a6d35632SScott Long } 286355aa1136SEd Maste 286455aa1136SEd Maste if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { 286555aa1136SEd Maste fib->data[0] = 0; 286655aa1136SEd Maste if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) 286755aa1136SEd Maste device_printf(sc->aac_dev, 286855aa1136SEd Maste "RequestSupplementAdapterInfo failed\n"); 286955aa1136SEd Maste else 287055aa1136SEd Maste adapter_type = ((struct aac_supplement_adapter_info *) 287155aa1136SEd Maste &fib->data[0])->AdapterTypeText; 287255aa1136SEd Maste } 287355aa1136SEd Maste device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", 287455aa1136SEd Maste adapter_type, 287555aa1136SEd Maste AAC_DRIVER_VERSION >> 24, 287655aa1136SEd Maste (AAC_DRIVER_VERSION >> 16) & 0xFF, 287755aa1136SEd Maste AAC_DRIVER_VERSION & 0xFF, 287855aa1136SEd Maste AAC_DRIVER_BUILD); 287955aa1136SEd Maste 2880bd971c49SScott Long aac_release_sync_fib(sc); 288181b3da08SScott Long mtx_unlock(&sc->aac_io_lock); 288235863739SMike Smith } 288335863739SMike Smith 2884914da7d0SScott Long /* 288535863739SMike Smith * Look up a text description of a numeric error code and return a pointer to 288635863739SMike Smith * same. 288735863739SMike Smith */ 288835863739SMike Smith static char * 288935863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code) 289035863739SMike Smith { 289135863739SMike Smith int i; 289235863739SMike Smith 289335863739SMike Smith for (i = 0; table[i].string != NULL; i++) 289435863739SMike Smith if (table[i].code == code) 289535863739SMike Smith return(table[i].string); 289635863739SMike Smith return(table[i + 1].string); 289735863739SMike Smith } 289835863739SMike Smith 2899914da7d0SScott Long /* 2900914da7d0SScott Long * Management Interface 2901914da7d0SScott Long */ 290235863739SMike Smith 290335863739SMike Smith static int 290400b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) 290535863739SMike Smith { 2906914da7d0SScott Long struct aac_softc *sc; 290735863739SMike Smith 2908914da7d0SScott Long sc = dev->si_drv1; 290931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2910a723a548SEd Maste sc->aac_open_cnt++; 291135863739SMike Smith sc->aac_state |= AAC_STATE_OPEN; 291235863739SMike Smith 291335863739SMike Smith return 0; 291435863739SMike Smith } 291535863739SMike Smith 291635863739SMike Smith static int 291700b4e54aSWarner Losh aac_close(struct cdev *dev, int flags, int fmt, struct thread *td) 291835863739SMike Smith { 2919914da7d0SScott Long struct aac_softc *sc; 292035863739SMike Smith 2921914da7d0SScott Long sc = dev->si_drv1; 292231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2923a723a548SEd Maste sc->aac_open_cnt--; 292435863739SMike Smith /* Mark this unit as no longer open */ 2925a723a548SEd Maste if (sc->aac_open_cnt == 0) 292635863739SMike Smith sc->aac_state &= ~AAC_STATE_OPEN; 292735863739SMike Smith 292835863739SMike Smith return 0; 292935863739SMike Smith } 293035863739SMike Smith 293135863739SMike Smith static int 293200b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 293335863739SMike Smith { 2934914da7d0SScott Long union aac_statrequest *as; 2935914da7d0SScott Long struct aac_softc *sc; 29360b94a66eSMike Smith int error = 0; 293735863739SMike Smith 2938914da7d0SScott Long as = (union aac_statrequest *)arg; 2939914da7d0SScott Long sc = dev->si_drv1; 294031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 2941914da7d0SScott Long 294235863739SMike Smith switch (cmd) { 29430b94a66eSMike Smith case AACIO_STATS: 29440b94a66eSMike Smith switch (as->as_item) { 29450b94a66eSMike Smith case AACQ_FREE: 29460b94a66eSMike Smith case AACQ_BIO: 29470b94a66eSMike Smith case AACQ_READY: 29480b94a66eSMike Smith case AACQ_BUSY: 2949c6eafcf2SScott Long bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, 2950c6eafcf2SScott Long sizeof(struct aac_qstat)); 29510b94a66eSMike Smith break; 29520b94a66eSMike Smith default: 29530b94a66eSMike Smith error = ENOENT; 29540b94a66eSMike Smith break; 29550b94a66eSMike Smith } 29560b94a66eSMike Smith break; 29570b94a66eSMike Smith 295835863739SMike Smith case FSACTL_SENDFIB: 2959f355c0e0SEd Maste case FSACTL_SEND_LARGE_FIB: 2960fb0c27d7SScott Long arg = *(caddr_t*)arg; 2961fb0c27d7SScott Long case FSACTL_LNX_SENDFIB: 2962f355c0e0SEd Maste case FSACTL_LNX_SEND_LARGE_FIB: 296331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); 296435863739SMike Smith error = aac_ioctl_sendfib(sc, arg); 296535863739SMike Smith break; 2966f355c0e0SEd Maste case FSACTL_SEND_RAW_SRB: 2967f355c0e0SEd Maste arg = *(caddr_t*)arg; 2968f355c0e0SEd Maste case FSACTL_LNX_SEND_RAW_SRB: 296931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); 2970f355c0e0SEd Maste error = aac_ioctl_send_raw_srb(sc, arg); 2971f355c0e0SEd Maste break; 297235863739SMike Smith case FSACTL_AIF_THREAD: 2973fb0c27d7SScott Long case FSACTL_LNX_AIF_THREAD: 297431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); 297535863739SMike Smith error = EINVAL; 297635863739SMike Smith break; 297735863739SMike Smith case FSACTL_OPEN_GET_ADAPTER_FIB: 2978fb0c27d7SScott Long arg = *(caddr_t*)arg; 2979fb0c27d7SScott Long case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: 298031a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); 2981a723a548SEd Maste error = aac_open_aif(sc, arg); 298235863739SMike Smith break; 298335863739SMike Smith case FSACTL_GET_NEXT_ADAPTER_FIB: 2984fb0c27d7SScott Long arg = *(caddr_t*)arg; 2985fb0c27d7SScott Long case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: 298631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); 2987fb0c27d7SScott Long error = aac_getnext_aif(sc, arg); 298835863739SMike Smith break; 298935863739SMike Smith case FSACTL_CLOSE_GET_ADAPTER_FIB: 2990a723a548SEd Maste arg = *(caddr_t*)arg; 2991fb0c27d7SScott Long case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: 299231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); 2993a723a548SEd Maste error = aac_close_aif(sc, arg); 299435863739SMike Smith break; 299535863739SMike Smith case FSACTL_MINIPORT_REV_CHECK: 2996fb0c27d7SScott Long arg = *(caddr_t*)arg; 2997fb0c27d7SScott Long case FSACTL_LNX_MINIPORT_REV_CHECK: 299831a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); 2999fb0c27d7SScott Long error = aac_rev_check(sc, arg); 300035863739SMike Smith break; 300136e0bf6eSScott Long case FSACTL_QUERY_DISK: 300236e0bf6eSScott Long arg = *(caddr_t*)arg; 300336e0bf6eSScott Long case FSACTL_LNX_QUERY_DISK: 300431a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); 300536e0bf6eSScott Long error = aac_query_disk(sc, arg); 300636e0bf6eSScott Long break; 300736e0bf6eSScott Long case FSACTL_DELETE_DISK: 300836e0bf6eSScott Long case FSACTL_LNX_DELETE_DISK: 3009914da7d0SScott Long /* 3010914da7d0SScott Long * We don't trust the underland to tell us when to delete a 3011914da7d0SScott Long * container, rather we rely on an AIF coming from the 3012914da7d0SScott Long * controller 3013914da7d0SScott Long */ 301436e0bf6eSScott Long error = 0; 301536e0bf6eSScott Long break; 30167cb209f5SScott Long case FSACTL_GET_PCI_INFO: 30177cb209f5SScott Long arg = *(caddr_t*)arg; 30187cb209f5SScott Long case FSACTL_LNX_GET_PCI_INFO: 301931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); 30207cb209f5SScott Long error = aac_get_pci_info(sc, arg); 30217cb209f5SScott Long break; 30226d307336SEd Maste case FSACTL_GET_FEATURES: 30236d307336SEd Maste arg = *(caddr_t*)arg; 30246d307336SEd Maste case FSACTL_LNX_GET_FEATURES: 30256d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); 30266d307336SEd Maste error = aac_supported_features(sc, arg); 30276d307336SEd Maste break; 302835863739SMike Smith default: 302931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); 303035863739SMike Smith error = EINVAL; 303135863739SMike Smith break; 303235863739SMike Smith } 303335863739SMike Smith return(error); 303435863739SMike Smith } 303535863739SMike Smith 3036b3457b51SScott Long static int 303700b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td) 3038b3457b51SScott Long { 3039b3457b51SScott Long struct aac_softc *sc; 3040ef0b687cSEd Maste struct aac_fib_context *ctx; 3041b3457b51SScott Long int revents; 3042b3457b51SScott Long 3043b3457b51SScott Long sc = dev->si_drv1; 3044b3457b51SScott Long revents = 0; 3045b3457b51SScott Long 3046bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3047b3457b51SScott Long if ((poll_events & (POLLRDNORM | POLLIN)) != 0) { 3048ef0b687cSEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3049ef0b687cSEd Maste if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) { 3050b3457b51SScott Long revents |= poll_events & (POLLIN | POLLRDNORM); 3051ef0b687cSEd Maste break; 3052ef0b687cSEd Maste } 3053ef0b687cSEd Maste } 3054b3457b51SScott Long } 3055bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 3056b3457b51SScott Long 3057b3457b51SScott Long if (revents == 0) { 3058b3457b51SScott Long if (poll_events & (POLLIN | POLLRDNORM)) 3059b3457b51SScott Long selrecord(td, &sc->rcv_select); 3060b3457b51SScott Long } 3061b3457b51SScott Long 3062b3457b51SScott Long return (revents); 3063b3457b51SScott Long } 3064b3457b51SScott Long 30657cb209f5SScott Long static void 30667cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) 30677cb209f5SScott Long { 30687cb209f5SScott Long 30697cb209f5SScott Long switch (event->ev_type) { 30707cb209f5SScott Long case AAC_EVENT_CMFREE: 30710c40d5beSEd Maste mtx_assert(&sc->aac_io_lock, MA_OWNED); 30721a681311SLuoqi Chen if (aac_alloc_command(sc, (struct aac_command **)arg)) { 30737cb209f5SScott Long aac_add_event(sc, event); 30747cb209f5SScott Long return; 30757cb209f5SScott Long } 30767cb209f5SScott Long free(event, M_AACBUF); 30778eeb2ca6SScott Long wakeup(arg); 30787cb209f5SScott Long break; 30797cb209f5SScott Long default: 30807cb209f5SScott Long break; 30817cb209f5SScott Long } 30827cb209f5SScott Long } 30837cb209f5SScott Long 3084914da7d0SScott Long /* 308535863739SMike Smith * Send a FIB supplied from userspace 308635863739SMike Smith */ 308735863739SMike Smith static int 308835863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) 308935863739SMike Smith { 309035863739SMike Smith struct aac_command *cm; 309135863739SMike Smith int size, error; 309235863739SMike Smith 309331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 309435863739SMike Smith 309535863739SMike Smith cm = NULL; 309635863739SMike Smith 309735863739SMike Smith /* 309835863739SMike Smith * Get a command 309935863739SMike Smith */ 3100bb6fe253SScott Long mtx_lock(&sc->aac_io_lock); 310135863739SMike Smith if (aac_alloc_command(sc, &cm)) { 31027cb209f5SScott Long struct aac_event *event; 31037cb209f5SScott Long 31047cb209f5SScott Long event = malloc(sizeof(struct aac_event), M_AACBUF, 31057cb209f5SScott Long M_NOWAIT | M_ZERO); 31067cb209f5SScott Long if (event == NULL) { 310735863739SMike Smith error = EBUSY; 3108f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 310935863739SMike Smith goto out; 311035863739SMike Smith } 31117cb209f5SScott Long event->ev_type = AAC_EVENT_CMFREE; 31127cb209f5SScott Long event->ev_callback = aac_ioctl_event; 31137cb209f5SScott Long event->ev_arg = &cm; 31147cb209f5SScott Long aac_add_event(sc, event); 31158eeb2ca6SScott Long msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); 31167cb209f5SScott Long } 311793cfca22SScott Long mtx_unlock(&sc->aac_io_lock); 311835863739SMike Smith 311935863739SMike Smith /* 312035863739SMike Smith * Fetch the FIB header, then re-copy to get data as well. 312135863739SMike Smith */ 3122914da7d0SScott Long if ((error = copyin(ufib, cm->cm_fib, 3123914da7d0SScott Long sizeof(struct aac_fib_header))) != 0) 312435863739SMike Smith goto out; 312535863739SMike Smith size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); 3126f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3127f355c0e0SEd Maste device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", 3128f355c0e0SEd Maste size, sc->aac_max_fib_size); 3129f355c0e0SEd Maste size = sc->aac_max_fib_size; 313035863739SMike Smith } 313135863739SMike Smith if ((error = copyin(ufib, cm->cm_fib, size)) != 0) 313235863739SMike Smith goto out; 313335863739SMike Smith cm->cm_fib->Header.Size = size; 31342b3b0f17SScott Long cm->cm_timestamp = time_uptime; 313535863739SMike Smith 313635863739SMike Smith /* 313735863739SMike Smith * Pass the FIB to the controller, wait for it to complete. 313835863739SMike Smith */ 313993cfca22SScott Long mtx_lock(&sc->aac_io_lock); 3140f16627aaSEd Maste error = aac_wait_command(cm); 3141f16627aaSEd Maste mtx_unlock(&sc->aac_io_lock); 3142f16627aaSEd Maste if (error != 0) { 314370545d1aSScott Long device_printf(sc->aac_dev, 314470545d1aSScott Long "aac_wait_command return %d\n", error); 314535863739SMike Smith goto out; 3146b3457b51SScott Long } 314735863739SMike Smith 314835863739SMike Smith /* 314935863739SMike Smith * Copy the FIB and data back out to the caller. 315035863739SMike Smith */ 315135863739SMike Smith size = cm->cm_fib->Header.Size; 3152f355c0e0SEd Maste if (size > sc->aac_max_fib_size) { 3153f355c0e0SEd Maste device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", 3154f355c0e0SEd Maste size, sc->aac_max_fib_size); 3155f355c0e0SEd Maste size = sc->aac_max_fib_size; 315635863739SMike Smith } 315735863739SMike Smith error = copyout(cm->cm_fib, ufib, size); 315835863739SMike Smith 315935863739SMike Smith out: 3160f6c4dd3fSScott Long if (cm != NULL) { 3161f16627aaSEd Maste mtx_lock(&sc->aac_io_lock); 316235863739SMike Smith aac_release_command(cm); 3163bb6fe253SScott Long mtx_unlock(&sc->aac_io_lock); 3164f16627aaSEd Maste } 316535863739SMike Smith return(error); 316635863739SMike Smith } 316735863739SMike Smith 3168914da7d0SScott Long /* 3169f355c0e0SEd Maste * Send a passthrough FIB supplied from userspace 3170f355c0e0SEd Maste */ 3171f355c0e0SEd Maste static int 3172f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) 3173f355c0e0SEd Maste { 3174f355c0e0SEd Maste return (EINVAL); 3175f355c0e0SEd Maste } 3176f355c0e0SEd Maste 3177f355c0e0SEd Maste /* 317835863739SMike Smith * Handle an AIF sent to us by the controller; queue it for later reference. 317936e0bf6eSScott Long * If the queue fills up, then drop the older entries. 318035863739SMike Smith */ 318135863739SMike Smith static void 318236e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) 318335863739SMike Smith { 318436e0bf6eSScott Long struct aac_aif_command *aif; 318536e0bf6eSScott Long struct aac_container *co, *co_next; 3186a723a548SEd Maste struct aac_fib_context *ctx; 318704f4d586SEd Maste struct aac_mntinforesp *mir; 3188a723a548SEd Maste int next, current, found; 3189795d7dc0SScott Long int count = 0, added = 0, i = 0; 319035863739SMike Smith 319131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 319235863739SMike Smith 319336e0bf6eSScott Long aif = (struct aac_aif_command*)&fib->data[0]; 319436e0bf6eSScott Long aac_print_aif(sc, aif); 319536e0bf6eSScott Long 319636e0bf6eSScott Long /* Is it an event that we should care about? */ 319736e0bf6eSScott Long switch (aif->command) { 319836e0bf6eSScott Long case AifCmdEventNotify: 319936e0bf6eSScott Long switch (aif->data.EN.type) { 320036e0bf6eSScott Long case AifEnAddContainer: 320136e0bf6eSScott Long case AifEnDeleteContainer: 320236e0bf6eSScott Long /* 3203914da7d0SScott Long * A container was added or deleted, but the message 3204914da7d0SScott Long * doesn't tell us anything else! Re-enumerate the 3205914da7d0SScott Long * containers and sort things out. 320636e0bf6eSScott Long */ 320703b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 320836e0bf6eSScott Long do { 320936e0bf6eSScott Long /* 3210914da7d0SScott Long * Ask the controller for its containers one at 3211914da7d0SScott Long * a time. 3212914da7d0SScott Long * XXX What if the controller's list changes 3213914da7d0SScott Long * midway through this enumaration? 321436e0bf6eSScott Long * XXX This should be done async. 321536e0bf6eSScott Long */ 321604f4d586SEd Maste if ((mir = aac_get_container_info(sc, fib, i)) == NULL) 321736e0bf6eSScott Long continue; 321804f4d586SEd Maste if (i == 0) 3219795d7dc0SScott Long count = mir->MntRespCount; 322036e0bf6eSScott Long /* 3221914da7d0SScott Long * Check the container against our list. 3222914da7d0SScott Long * co->co_found was already set to 0 in a 3223914da7d0SScott Long * previous run. 322436e0bf6eSScott Long */ 3225cbfd045bSScott Long if ((mir->Status == ST_OK) && 3226cbfd045bSScott Long (mir->MntTable[0].VolType != CT_NONE)) { 322736e0bf6eSScott Long found = 0; 3228914da7d0SScott Long TAILQ_FOREACH(co, 3229914da7d0SScott Long &sc->aac_container_tqh, 3230914da7d0SScott Long co_link) { 323136e0bf6eSScott Long if (co->co_mntobj.ObjectId == 3232cbfd045bSScott Long mir->MntTable[0].ObjectId) { 323336e0bf6eSScott Long co->co_found = 1; 323436e0bf6eSScott Long found = 1; 323536e0bf6eSScott Long break; 323636e0bf6eSScott Long } 323736e0bf6eSScott Long } 3238914da7d0SScott Long /* 3239914da7d0SScott Long * If the container matched, continue 3240914da7d0SScott Long * in the list. 3241914da7d0SScott Long */ 324236e0bf6eSScott Long if (found) { 324336e0bf6eSScott Long i++; 324436e0bf6eSScott Long continue; 324536e0bf6eSScott Long } 324636e0bf6eSScott Long 324736e0bf6eSScott Long /* 3248914da7d0SScott Long * This is a new container. Do all the 324970545d1aSScott Long * appropriate things to set it up. 325070545d1aSScott Long */ 3251cbfd045bSScott Long aac_add_container(sc, mir, 1); 325236e0bf6eSScott Long added = 1; 325336e0bf6eSScott Long } 325436e0bf6eSScott Long i++; 3255795d7dc0SScott Long } while ((i < count) && (i < AAC_MAX_CONTAINERS)); 3256cbfd045bSScott Long aac_release_sync_fib(sc); 325736e0bf6eSScott Long 325836e0bf6eSScott Long /* 3259914da7d0SScott Long * Go through our list of containers and see which ones 3260914da7d0SScott Long * were not marked 'found'. Since the controller didn't 3261914da7d0SScott Long * list them they must have been deleted. Do the 3262914da7d0SScott Long * appropriate steps to destroy the device. Also reset 3263914da7d0SScott Long * the co->co_found field. 326436e0bf6eSScott Long */ 326536e0bf6eSScott Long co = TAILQ_FIRST(&sc->aac_container_tqh); 326636e0bf6eSScott Long while (co != NULL) { 326736e0bf6eSScott Long if (co->co_found == 0) { 32687cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3269a56fe095SJohn Baldwin mtx_lock(&Giant); 3270914da7d0SScott Long device_delete_child(sc->aac_dev, 3271914da7d0SScott Long co->co_disk); 3272a56fe095SJohn Baldwin mtx_unlock(&Giant); 32737cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 327436e0bf6eSScott Long co_next = TAILQ_NEXT(co, co_link); 3275bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 3276914da7d0SScott Long TAILQ_REMOVE(&sc->aac_container_tqh, co, 3277914da7d0SScott Long co_link); 3278bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 3279ba1d57e7SScott Long free(co, M_AACBUF); 328036e0bf6eSScott Long co = co_next; 328136e0bf6eSScott Long } else { 328236e0bf6eSScott Long co->co_found = 0; 328336e0bf6eSScott Long co = TAILQ_NEXT(co, co_link); 328436e0bf6eSScott Long } 328536e0bf6eSScott Long } 328636e0bf6eSScott Long 328736e0bf6eSScott Long /* Attach the newly created containers */ 32887cb209f5SScott Long if (added) { 32897cb209f5SScott Long mtx_unlock(&sc->aac_io_lock); 3290a56fe095SJohn Baldwin mtx_lock(&Giant); 329136e0bf6eSScott Long bus_generic_attach(sc->aac_dev); 3292a56fe095SJohn Baldwin mtx_unlock(&Giant); 32937cb209f5SScott Long mtx_lock(&sc->aac_io_lock); 32947cb209f5SScott Long } 329536e0bf6eSScott Long 329636e0bf6eSScott Long break; 329736e0bf6eSScott Long 329836e0bf6eSScott Long default: 329936e0bf6eSScott Long break; 330036e0bf6eSScott Long } 330136e0bf6eSScott Long 330236e0bf6eSScott Long default: 330336e0bf6eSScott Long break; 330436e0bf6eSScott Long } 330536e0bf6eSScott Long 330636e0bf6eSScott Long /* Copy the AIF data to the AIF queue for ioctl retrieval */ 3307bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3308a723a548SEd Maste current = sc->aifq_idx; 3309a723a548SEd Maste next = (current + 1) % AAC_AIFQ_LENGTH; 3310a723a548SEd Maste if (next == 0) 3311a723a548SEd Maste sc->aifq_filled = 1; 3312a723a548SEd Maste bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); 3313a723a548SEd Maste /* modify AIF contexts */ 3314a723a548SEd Maste if (sc->aifq_filled) { 3315a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3316a723a548SEd Maste if (next == ctx->ctx_idx) 3317a723a548SEd Maste ctx->ctx_wrap = 1; 3318a723a548SEd Maste else if (current == ctx->ctx_idx && ctx->ctx_wrap) 3319a723a548SEd Maste ctx->ctx_idx = next; 3320a723a548SEd Maste } 3321a723a548SEd Maste } 3322a723a548SEd Maste sc->aifq_idx = next; 3323b3457b51SScott Long /* On the off chance that someone is sleeping for an aif... */ 332435863739SMike Smith if (sc->aac_state & AAC_STATE_AIF_SLEEPER) 332535863739SMike Smith wakeup(sc->aac_aifq); 3326b3457b51SScott Long /* Wakeup any poll()ers */ 3327512824f8SSeigo Tanimura selwakeuppri(&sc->rcv_select, PRIBIO); 3328bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 332936e0bf6eSScott Long 333036e0bf6eSScott Long return; 333135863739SMike Smith } 333235863739SMike Smith 3333914da7d0SScott Long /* 33340b94a66eSMike Smith * Return the Revision of the driver to userspace and check to see if the 333536e0bf6eSScott Long * userspace app is possibly compatible. This is extremely bogus since 333636e0bf6eSScott Long * our driver doesn't follow Adaptec's versioning system. Cheat by just 333736e0bf6eSScott Long * returning what the card reported. 333835863739SMike Smith */ 333935863739SMike Smith static int 3340fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata) 334135863739SMike Smith { 334235863739SMike Smith struct aac_rev_check rev_check; 334335863739SMike Smith struct aac_rev_check_resp rev_check_resp; 334435863739SMike Smith int error = 0; 334535863739SMike Smith 334631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 334735863739SMike Smith 334835863739SMike Smith /* 334935863739SMike Smith * Copyin the revision struct from userspace 335035863739SMike Smith */ 3351c6eafcf2SScott Long if ((error = copyin(udata, (caddr_t)&rev_check, 3352c6eafcf2SScott Long sizeof(struct aac_rev_check))) != 0) { 335335863739SMike Smith return error; 335435863739SMike Smith } 335535863739SMike Smith 335631a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", 3357914da7d0SScott Long rev_check.callingRevision.buildNumber); 335835863739SMike Smith 335935863739SMike Smith /* 336035863739SMike Smith * Doctor up the response struct. 336135863739SMike Smith */ 336235863739SMike Smith rev_check_resp.possiblyCompatible = 1; 3363914da7d0SScott Long rev_check_resp.adapterSWRevision.external.ul = 3364914da7d0SScott Long sc->aac_revision.external.ul; 3365914da7d0SScott Long rev_check_resp.adapterSWRevision.buildNumber = 3366914da7d0SScott Long sc->aac_revision.buildNumber; 336735863739SMike Smith 3368c6eafcf2SScott Long return(copyout((caddr_t)&rev_check_resp, udata, 3369c6eafcf2SScott Long sizeof(struct aac_rev_check_resp))); 337035863739SMike Smith } 337135863739SMike Smith 3372914da7d0SScott Long /* 3373a723a548SEd Maste * Pass the fib context to the caller 3374a723a548SEd Maste */ 3375a723a548SEd Maste static int 3376a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg) 3377a723a548SEd Maste { 3378a723a548SEd Maste struct aac_fib_context *fibctx, *ctx; 3379a723a548SEd Maste int error = 0; 3380a723a548SEd Maste 338131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3382a723a548SEd Maste 3383a723a548SEd Maste fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); 3384a723a548SEd Maste if (fibctx == NULL) 3385a723a548SEd Maste return (ENOMEM); 3386a723a548SEd Maste 3387a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3388a723a548SEd Maste /* all elements are already 0, add to queue */ 3389a723a548SEd Maste if (sc->fibctx == NULL) 3390a723a548SEd Maste sc->fibctx = fibctx; 3391a723a548SEd Maste else { 3392a723a548SEd Maste for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) 3393a723a548SEd Maste ; 3394a723a548SEd Maste ctx->next = fibctx; 3395a723a548SEd Maste fibctx->prev = ctx; 3396a723a548SEd Maste } 3397a723a548SEd Maste 3398a723a548SEd Maste /* evaluate unique value */ 3399a723a548SEd Maste fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); 3400a723a548SEd Maste ctx = sc->fibctx; 3401a723a548SEd Maste while (ctx != fibctx) { 3402a723a548SEd Maste if (ctx->unique == fibctx->unique) { 3403a723a548SEd Maste fibctx->unique++; 3404a723a548SEd Maste ctx = sc->fibctx; 3405a723a548SEd Maste } else { 3406a723a548SEd Maste ctx = ctx->next; 3407a723a548SEd Maste } 3408a723a548SEd Maste } 3409a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3410a723a548SEd Maste 3411a723a548SEd Maste error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); 3412a723a548SEd Maste if (error) 3413a723a548SEd Maste aac_close_aif(sc, (caddr_t)ctx); 3414a723a548SEd Maste return error; 3415a723a548SEd Maste } 3416a723a548SEd Maste 3417a723a548SEd Maste /* 3418a723a548SEd Maste * Close the caller's fib context 3419a723a548SEd Maste */ 3420a723a548SEd Maste static int 3421a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg) 3422a723a548SEd Maste { 3423a723a548SEd Maste struct aac_fib_context *ctx; 3424a723a548SEd Maste 342531a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 3426a723a548SEd Maste 3427a723a548SEd Maste mtx_lock(&sc->aac_aifq_lock); 3428a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3429a723a548SEd Maste if (ctx->unique == *(uint32_t *)&arg) { 3430a723a548SEd Maste if (ctx == sc->fibctx) 3431a723a548SEd Maste sc->fibctx = NULL; 3432a723a548SEd Maste else { 3433a723a548SEd Maste ctx->prev->next = ctx->next; 3434a723a548SEd Maste if (ctx->next) 3435a723a548SEd Maste ctx->next->prev = ctx->prev; 3436a723a548SEd Maste } 3437a723a548SEd Maste break; 3438a723a548SEd Maste } 3439a723a548SEd Maste } 3440a723a548SEd Maste mtx_unlock(&sc->aac_aifq_lock); 3441a723a548SEd Maste if (ctx) 3442a723a548SEd Maste free(ctx, M_AACBUF); 3443a723a548SEd Maste 3444a723a548SEd Maste return 0; 3445a723a548SEd Maste } 3446a723a548SEd Maste 3447a723a548SEd Maste /* 344835863739SMike Smith * Pass the caller the next AIF in their queue 344935863739SMike Smith */ 345035863739SMike Smith static int 3451fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg) 345235863739SMike Smith { 345335863739SMike Smith struct get_adapter_fib_ioctl agf; 3454a723a548SEd Maste struct aac_fib_context *ctx; 34559e2e96d8SScott Long int error; 345635863739SMike Smith 345731a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 345835863739SMike Smith 345935863739SMike Smith if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { 3460a723a548SEd Maste for (ctx = sc->fibctx; ctx; ctx = ctx->next) { 3461a723a548SEd Maste if (agf.AdapterFibContext == ctx->unique) 3462a723a548SEd Maste break; 3463a723a548SEd Maste } 3464a723a548SEd Maste if (!ctx) 3465a723a548SEd Maste return (EFAULT); 346635863739SMike Smith 3467a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 3468a723a548SEd Maste if (error == EAGAIN && agf.Wait) { 346931a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF"); 347035863739SMike Smith sc->aac_state |= AAC_STATE_AIF_SLEEPER; 347135863739SMike Smith while (error == EAGAIN) { 3472914da7d0SScott Long error = tsleep(sc->aac_aifq, PRIBIO | 3473914da7d0SScott Long PCATCH, "aacaif", 0); 347435863739SMike Smith if (error == 0) 3475a723a548SEd Maste error = aac_return_aif(sc, ctx, agf.AifFib); 347635863739SMike Smith } 347735863739SMike Smith sc->aac_state &= ~AAC_STATE_AIF_SLEEPER; 347835863739SMike Smith } 347935863739SMike Smith } 348035863739SMike Smith return(error); 348135863739SMike Smith } 348235863739SMike Smith 3483914da7d0SScott Long /* 34840b94a66eSMike Smith * Hand the next AIF off the top of the queue out to userspace. 34850b94a66eSMike Smith */ 34860b94a66eSMike Smith static int 3487a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr) 34880b94a66eSMike Smith { 3489a723a548SEd Maste int current, error; 34900b94a66eSMike Smith 349131a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 34920b94a66eSMike Smith 3493bb6fe253SScott Long mtx_lock(&sc->aac_aifq_lock); 3494a723a548SEd Maste current = ctx->ctx_idx; 3495a723a548SEd Maste if (current == sc->aifq_idx && !ctx->ctx_wrap) { 3496a723a548SEd Maste /* empty */ 3497bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 34983df780cfSScott Long return (EAGAIN); 34993df780cfSScott Long } 3500a723a548SEd Maste error = 3501a723a548SEd Maste copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib)); 350236e0bf6eSScott Long if (error) 350370545d1aSScott Long device_printf(sc->aac_dev, 350470545d1aSScott Long "aac_return_aif: copyout returned %d\n", error); 3505a723a548SEd Maste else { 3506a723a548SEd Maste ctx->ctx_wrap = 0; 3507a723a548SEd Maste ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH; 3508a723a548SEd Maste } 3509bb6fe253SScott Long mtx_unlock(&sc->aac_aifq_lock); 35100b94a66eSMike Smith return(error); 35110b94a66eSMike Smith } 351236e0bf6eSScott Long 35137cb209f5SScott Long static int 35147cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr) 35157cb209f5SScott Long { 35167cb209f5SScott Long struct aac_pci_info { 35177cb209f5SScott Long u_int32_t bus; 35187cb209f5SScott Long u_int32_t slot; 35197cb209f5SScott Long } pciinf; 35207cb209f5SScott Long int error; 35217cb209f5SScott Long 352231a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 35237cb209f5SScott Long 35247cb209f5SScott Long pciinf.bus = pci_get_bus(sc->aac_dev); 35257cb209f5SScott Long pciinf.slot = pci_get_slot(sc->aac_dev); 35267cb209f5SScott Long 35277cb209f5SScott Long error = copyout((caddr_t)&pciinf, uptr, 35287cb209f5SScott Long sizeof(struct aac_pci_info)); 35297cb209f5SScott Long 35307cb209f5SScott Long return (error); 35317cb209f5SScott Long } 35327cb209f5SScott Long 35336d307336SEd Maste static int 35346d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr) 35356d307336SEd Maste { 35366d307336SEd Maste struct aac_features f; 35376d307336SEd Maste int error; 35386d307336SEd Maste 35396d307336SEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 35406d307336SEd Maste 35416d307336SEd Maste if ((error = copyin(uptr, &f, sizeof (f))) != 0) 35426d307336SEd Maste return (error); 35436d307336SEd Maste 35446d307336SEd Maste /* 35456d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 35466d307336SEd Maste * ALL zero in the featuresState, the driver will return the current 35476d307336SEd Maste * state of all the supported features, the data field will not be 35486d307336SEd Maste * valid. 35496d307336SEd Maste * When the management driver receives FSACTL_GET_FEATURES ioctl with 35506d307336SEd Maste * a specific bit set in the featuresState, the driver will return the 35516d307336SEd Maste * current state of this specific feature and whatever data that are 35526d307336SEd Maste * associated with the feature in the data field or perform whatever 35536d307336SEd Maste * action needed indicates in the data field. 35546d307336SEd Maste */ 35556d307336SEd Maste if (f.feat.fValue == 0) { 35566d307336SEd Maste f.feat.fBits.largeLBA = 35576d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 35586d307336SEd Maste /* TODO: In the future, add other features state here as well */ 35596d307336SEd Maste } else { 35606d307336SEd Maste if (f.feat.fBits.largeLBA) 35616d307336SEd Maste f.feat.fBits.largeLBA = 35626d307336SEd Maste (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 35636d307336SEd Maste /* TODO: Add other features state and data in the future */ 35646d307336SEd Maste } 35656d307336SEd Maste 35666d307336SEd Maste error = copyout(&f, uptr, sizeof (f)); 35676d307336SEd Maste return (error); 35686d307336SEd Maste } 35696d307336SEd Maste 3570914da7d0SScott Long /* 357136e0bf6eSScott Long * Give the userland some information about the container. The AAC arch 357236e0bf6eSScott Long * expects the driver to be a SCSI passthrough type driver, so it expects 357336e0bf6eSScott Long * the containers to have b:t:l numbers. Fake it. 357436e0bf6eSScott Long */ 357536e0bf6eSScott Long static int 357636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr) 357736e0bf6eSScott Long { 357836e0bf6eSScott Long struct aac_query_disk query_disk; 357936e0bf6eSScott Long struct aac_container *co; 3580914da7d0SScott Long struct aac_disk *disk; 358136e0bf6eSScott Long int error, id; 358236e0bf6eSScott Long 358331a0399eSEd Maste fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 358436e0bf6eSScott Long 3585914da7d0SScott Long disk = NULL; 3586914da7d0SScott Long 3587914da7d0SScott Long error = copyin(uptr, (caddr_t)&query_disk, 3588914da7d0SScott Long sizeof(struct aac_query_disk)); 358936e0bf6eSScott Long if (error) 359036e0bf6eSScott Long return (error); 359136e0bf6eSScott Long 359236e0bf6eSScott Long id = query_disk.ContainerNumber; 359336e0bf6eSScott Long if (id == -1) 359436e0bf6eSScott Long return (EINVAL); 359536e0bf6eSScott Long 3596bb6fe253SScott Long mtx_lock(&sc->aac_container_lock); 359736e0bf6eSScott Long TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 359836e0bf6eSScott Long if (co->co_mntobj.ObjectId == id) 359936e0bf6eSScott Long break; 360036e0bf6eSScott Long } 360136e0bf6eSScott Long 360236e0bf6eSScott Long if (co == NULL) { 360336e0bf6eSScott Long query_disk.Valid = 0; 360436e0bf6eSScott Long query_disk.Locked = 0; 360536e0bf6eSScott Long query_disk.Deleted = 1; /* XXX is this right? */ 360636e0bf6eSScott Long } else { 360736e0bf6eSScott Long disk = device_get_softc(co->co_disk); 360836e0bf6eSScott Long query_disk.Valid = 1; 3609914da7d0SScott Long query_disk.Locked = 3610914da7d0SScott Long (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0; 361136e0bf6eSScott Long query_disk.Deleted = 0; 3612b3457b51SScott Long query_disk.Bus = device_get_unit(sc->aac_dev); 361336e0bf6eSScott Long query_disk.Target = disk->unit; 361436e0bf6eSScott Long query_disk.Lun = 0; 361536e0bf6eSScott Long query_disk.UnMapped = 0; 36167540e65eSScott Long sprintf(&query_disk.diskDeviceName[0], "%s%d", 36170b7ed341SPoul-Henning Kamp disk->ad_disk->d_name, disk->ad_disk->d_unit); 361836e0bf6eSScott Long } 3619bb6fe253SScott Long mtx_unlock(&sc->aac_container_lock); 362036e0bf6eSScott Long 3621914da7d0SScott Long error = copyout((caddr_t)&query_disk, uptr, 3622914da7d0SScott Long sizeof(struct aac_query_disk)); 362336e0bf6eSScott Long 362436e0bf6eSScott Long return (error); 362536e0bf6eSScott Long } 362636e0bf6eSScott Long 3627fe3cb0e1SScott Long static void 3628fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc) 3629fe3cb0e1SScott Long { 3630fe3cb0e1SScott Long struct aac_fib *fib; 3631fe3cb0e1SScott Long struct aac_ctcfg *c_cmd; 3632fe3cb0e1SScott Long struct aac_ctcfg_resp *c_resp; 3633fe3cb0e1SScott Long struct aac_vmioctl *vmi; 3634fe3cb0e1SScott Long struct aac_vmi_businf_resp *vmi_resp; 3635fe3cb0e1SScott Long struct aac_getbusinf businfo; 363670545d1aSScott Long struct aac_sim *caminf; 3637fe3cb0e1SScott Long device_t child; 3638fe3cb0e1SScott Long int i, found, error; 3639fe3cb0e1SScott Long 36401ffe41c1SChristian S.J. Peron mtx_lock(&sc->aac_io_lock); 364103b5fe51SScott Long aac_alloc_sync_fib(sc, &fib); 3642fe3cb0e1SScott Long c_cmd = (struct aac_ctcfg *)&fib->data[0]; 364339ee03c3SScott Long bzero(c_cmd, sizeof(struct aac_ctcfg)); 3644fe3cb0e1SScott Long 3645fe3cb0e1SScott Long c_cmd->Command = VM_ContainerConfig; 3646fe3cb0e1SScott Long c_cmd->cmd = CT_GET_SCSI_METHOD; 3647fe3cb0e1SScott Long c_cmd->param = 0; 3648fe3cb0e1SScott Long 3649fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 3650fe3cb0e1SScott Long sizeof(struct aac_ctcfg)); 3651fe3cb0e1SScott Long if (error) { 3652fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending " 3653fe3cb0e1SScott Long "VM_ContainerConfig command\n", error); 3654fe3cb0e1SScott Long aac_release_sync_fib(sc); 36551ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3656fe3cb0e1SScott Long return; 3657fe3cb0e1SScott Long } 3658fe3cb0e1SScott Long 3659fe3cb0e1SScott Long c_resp = (struct aac_ctcfg_resp *)&fib->data[0]; 3660fe3cb0e1SScott Long if (c_resp->Status != ST_OK) { 3661fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n", 3662fe3cb0e1SScott Long c_resp->Status); 3663fe3cb0e1SScott Long aac_release_sync_fib(sc); 36641ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3665fe3cb0e1SScott Long return; 3666fe3cb0e1SScott Long } 3667fe3cb0e1SScott Long 3668fe3cb0e1SScott Long sc->scsi_method_id = c_resp->param; 3669fe3cb0e1SScott Long 3670fe3cb0e1SScott Long vmi = (struct aac_vmioctl *)&fib->data[0]; 367139ee03c3SScott Long bzero(vmi, sizeof(struct aac_vmioctl)); 367239ee03c3SScott Long 3673fe3cb0e1SScott Long vmi->Command = VM_Ioctl; 3674fe3cb0e1SScott Long vmi->ObjType = FT_DRIVE; 3675fe3cb0e1SScott Long vmi->MethId = sc->scsi_method_id; 3676fe3cb0e1SScott Long vmi->ObjId = 0; 3677fe3cb0e1SScott Long vmi->IoctlCmd = GetBusInfo; 3678fe3cb0e1SScott Long 3679fe3cb0e1SScott Long error = aac_sync_fib(sc, ContainerCommand, 0, fib, 368042ef13a2SEd Maste sizeof(struct aac_vmi_businf_resp)); 3681fe3cb0e1SScott Long if (error) { 3682fe3cb0e1SScott Long device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n", 3683fe3cb0e1SScott Long error); 3684fe3cb0e1SScott Long aac_release_sync_fib(sc); 36851ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3686fe3cb0e1SScott Long return; 3687fe3cb0e1SScott Long } 3688fe3cb0e1SScott Long 3689fe3cb0e1SScott Long vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0]; 3690fe3cb0e1SScott Long if (vmi_resp->Status != ST_OK) { 3691fe3cb0e1SScott Long device_printf(sc->aac_dev, "VM_Ioctl returned %d\n", 3692fe3cb0e1SScott Long vmi_resp->Status); 3693fe3cb0e1SScott Long aac_release_sync_fib(sc); 36941ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3695fe3cb0e1SScott Long return; 3696fe3cb0e1SScott Long } 3697fe3cb0e1SScott Long 3698fe3cb0e1SScott Long bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf)); 3699fe3cb0e1SScott Long aac_release_sync_fib(sc); 37001ffe41c1SChristian S.J. Peron mtx_unlock(&sc->aac_io_lock); 3701fe3cb0e1SScott Long 3702fe3cb0e1SScott Long found = 0; 3703fe3cb0e1SScott Long for (i = 0; i < businfo.BusCount; i++) { 3704fe3cb0e1SScott Long if (businfo.BusValid[i] != AAC_BUS_VALID) 3705fe3cb0e1SScott Long continue; 3706fe3cb0e1SScott Long 3707a761a1caSScott Long caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim), 3708a761a1caSScott Long M_AACBUF, M_NOWAIT | M_ZERO); 3709b5f516cdSScott Long if (caminf == NULL) { 3710b5f516cdSScott Long device_printf(sc->aac_dev, 3711b5f516cdSScott Long "No memory to add passthrough bus %d\n", i); 3712b5f516cdSScott Long break; 37137cb209f5SScott Long }; 3714fe3cb0e1SScott Long 3715fe3cb0e1SScott Long child = device_add_child(sc->aac_dev, "aacp", -1); 3716fe3cb0e1SScott Long if (child == NULL) { 3717b5f516cdSScott Long device_printf(sc->aac_dev, 3718b5f516cdSScott Long "device_add_child failed for passthrough bus %d\n", 3719b5f516cdSScott Long i); 3720b5f516cdSScott Long free(caminf, M_AACBUF); 3721b5f516cdSScott Long break; 3722fe3cb0e1SScott Long } 3723fe3cb0e1SScott Long 3724fe3cb0e1SScott Long caminf->TargetsPerBus = businfo.TargetsPerBus; 3725fe3cb0e1SScott Long caminf->BusNumber = i; 3726fe3cb0e1SScott Long caminf->InitiatorBusId = businfo.InitiatorBusId[i]; 3727fe3cb0e1SScott Long caminf->aac_sc = sc; 3728ddb8683eSScott Long caminf->sim_dev = child; 3729fe3cb0e1SScott Long 3730fe3cb0e1SScott Long device_set_ivars(child, caminf); 3731fe3cb0e1SScott Long device_set_desc(child, "SCSI Passthrough Bus"); 373270545d1aSScott Long TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link); 3733fe3cb0e1SScott Long 3734fe3cb0e1SScott Long found = 1; 3735fe3cb0e1SScott Long } 3736fe3cb0e1SScott Long 3737fe3cb0e1SScott Long if (found) 3738fe3cb0e1SScott Long bus_generic_attach(sc->aac_dev); 3739fe3cb0e1SScott Long 3740fe3cb0e1SScott Long return; 3741fe3cb0e1SScott Long } 3742