xref: /freebsd/sys/dev/aac/aac.c (revision f6c4dd3f48a503debb165c4cd30b4bf1aa2a73c2)
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  *	$FreeBSD$
3035863739SMike Smith  */
3135863739SMike Smith 
3235863739SMike Smith /*
3335863739SMike Smith  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3435863739SMike Smith  */
3535863739SMike Smith 
36f6c4dd3fSScott Long #include "opt_aac.h"
37f6c4dd3fSScott Long 
38f6c4dd3fSScott Long /* include <stddef.h> */
3935863739SMike Smith #include <sys/param.h>
4035863739SMike Smith #include <sys/systm.h>
4135863739SMike Smith #include <sys/malloc.h>
4235863739SMike Smith #include <sys/kernel.h>
4335863739SMike Smith 
4435863739SMike Smith #include <dev/aac/aac_compat.h>
4535863739SMike Smith 
4635863739SMike Smith #include <sys/bus.h>
4735863739SMike Smith #include <sys/conf.h>
4835863739SMike Smith #include <sys/devicestat.h>
4935863739SMike Smith #include <sys/disk.h>
5035863739SMike Smith #include <sys/file.h>
5135863739SMike Smith #include <sys/signalvar.h>
520b94a66eSMike Smith #include <sys/time.h>
5335863739SMike Smith 
5435863739SMike Smith #include <machine/bus_memio.h>
5535863739SMike Smith #include <machine/bus.h>
5635863739SMike Smith #include <machine/resource.h>
5735863739SMike Smith 
5835863739SMike Smith #include <dev/aac/aacreg.h>
590b94a66eSMike Smith #include <dev/aac/aac_ioctl.h>
6035863739SMike Smith #include <dev/aac/aacvar.h>
6135863739SMike Smith #include <dev/aac/aac_tables.h>
6235863739SMike Smith 
6335863739SMike Smith devclass_t	aac_devclass;
6435863739SMike Smith 
6535863739SMike Smith static void	aac_startup(void *arg);
6635863739SMike Smith 
6735863739SMike Smith /* Command Processing */
6835863739SMike Smith static void	aac_startio(struct aac_softc *sc);
690b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7035863739SMike Smith static int	aac_start(struct aac_command *cm);
7135863739SMike Smith static void	aac_complete(void *context, int pending);
7235863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7335863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
7435863739SMike Smith static int	aac_wait_command(struct aac_command *cm, int timeout);
7535863739SMike Smith static void	aac_host_command(struct aac_softc *sc);
7635863739SMike Smith static void	aac_host_response(struct aac_softc *sc);
7735863739SMike Smith 
7835863739SMike Smith /* Command Buffer Management */
79fadfef89SScott Long static int	aac_alloc_command(struct aac_softc *sc,
80fadfef89SScott Long 				  struct aac_command **cmp);
8135863739SMike Smith static void	aac_release_command(struct aac_command *cm);
82c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
83c6eafcf2SScott Long 				       int nseg, int error);
840b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
850b94a66eSMike Smith static void	aac_free_commands(struct aac_softc *sc);
8635863739SMike Smith static void	aac_map_command(struct aac_command *cm);
8735863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
8835863739SMike Smith 
8935863739SMike Smith /* Hardware Interface */
90c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
91c6eafcf2SScott Long 			       int error);
9235863739SMike Smith static int	aac_init(struct aac_softc *sc);
9335863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
94c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
95c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
96c6eafcf2SScott Long static int	aac_sync_fib(struct aac_softc *sc, u_int32_t command,
97c6eafcf2SScott Long 			     u_int32_t xferstate, void *data,
98c6eafcf2SScott Long 			     u_int16_t datasize, void *result,
99c6eafcf2SScott Long 			     u_int16_t *resultsize);
100c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
101f6c4dd3fSScott Long 				struct aac_command *cm);
102c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
103c6eafcf2SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10435863739SMike Smith 
10535863739SMike Smith /* StrongARM interface */
10635863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
10735863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
10835863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
10935863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
11035863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
111c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
112c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
11335863739SMike Smith static int	aac_sa_get_mailboxstatus(struct aac_softc *sc);
11435863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
11535863739SMike Smith 
11635863739SMike Smith struct aac_interface aac_sa_interface = {
11735863739SMike Smith     aac_sa_get_fwstatus,
11835863739SMike Smith     aac_sa_qnotify,
11935863739SMike Smith     aac_sa_get_istatus,
12035863739SMike Smith     aac_sa_clear_istatus,
12135863739SMike Smith     aac_sa_set_mailbox,
12235863739SMike Smith     aac_sa_get_mailboxstatus,
12335863739SMike Smith     aac_sa_set_interrupts
12435863739SMike Smith };
12535863739SMike Smith 
12635863739SMike Smith /* i960Rx interface */
12735863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
12835863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
12935863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
13035863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
13135863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
132c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
133c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
13435863739SMike Smith static int	aac_rx_get_mailboxstatus(struct aac_softc *sc);
13535863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
13635863739SMike Smith 
13735863739SMike Smith struct aac_interface aac_rx_interface = {
13835863739SMike Smith     aac_rx_get_fwstatus,
13935863739SMike Smith     aac_rx_qnotify,
14035863739SMike Smith     aac_rx_get_istatus,
14135863739SMike Smith     aac_rx_clear_istatus,
14235863739SMike Smith     aac_rx_set_mailbox,
14335863739SMike Smith     aac_rx_get_mailboxstatus,
14435863739SMike Smith     aac_rx_set_interrupts
14535863739SMike Smith };
14635863739SMike Smith 
14735863739SMike Smith /* Debugging and Diagnostics */
14835863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
149c6eafcf2SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
150c6eafcf2SScott Long 				   u_int32_t code);
15135863739SMike Smith 
15235863739SMike Smith /* Management Interface */
15335863739SMike Smith static d_open_t		aac_open;
15435863739SMike Smith static d_close_t	aac_close;
15535863739SMike Smith static d_ioctl_t	aac_ioctl;
156c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
157c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
158c6eafcf2SScott Long 				       struct aac_aif_command *aif);
15935863739SMike Smith #ifdef AAC_COMPAT_LINUX
160c6eafcf2SScott Long static int		aac_linux_rev_check(struct aac_softc *sc,
161c6eafcf2SScott Long 					    caddr_t udata);
162c6eafcf2SScott Long static int		aac_linux_getnext_aif(struct aac_softc *sc,
163c6eafcf2SScott Long 					    caddr_t arg);
164c6eafcf2SScott Long static int		aac_linux_return_aif(struct aac_softc *sc,
165c6eafcf2SScott Long 					    caddr_t uptr);
16635863739SMike Smith #endif
16735863739SMike Smith 
16835863739SMike Smith #define AAC_CDEV_MAJOR	150
16935863739SMike Smith 
17035863739SMike Smith static struct cdevsw aac_cdevsw = {
17135863739SMike Smith     aac_open,		/* open */
17235863739SMike Smith     aac_close,		/* close */
17335863739SMike Smith     noread,		/* read */
17435863739SMike Smith     nowrite,		/* write */
17535863739SMike Smith     aac_ioctl,		/* ioctl */
17635863739SMike Smith     nopoll,		/* poll */
17735863739SMike Smith     nommap,		/* mmap */
17835863739SMike Smith     nostrategy,		/* strategy */
17935863739SMike Smith     "aac",		/* name */
18035863739SMike Smith     AAC_CDEV_MAJOR,	/* major */
18135863739SMike Smith     nodump,		/* dump */
18235863739SMike Smith     nopsize,		/* psize */
18335863739SMike Smith     0,			/* flags */
18435863739SMike Smith };
18535863739SMike Smith 
186c6eafcf2SScott Long /******************************************************************************
187c6eafcf2SScott Long  ******************************************************************************
18835863739SMike Smith 				Device Interface
189c6eafcf2SScott Long  ******************************************************************************
190c6eafcf2SScott Long  ******************************************************************************/
19135863739SMike Smith 
192c6eafcf2SScott Long /******************************************************************************
19335863739SMike Smith  * Initialise the controller and softc
19435863739SMike Smith  */
19535863739SMike Smith int
19635863739SMike Smith aac_attach(struct aac_softc *sc)
19735863739SMike Smith {
19835863739SMike Smith     int		error, unit;
19935863739SMike Smith 
20035863739SMike Smith     debug_called(1);
20135863739SMike Smith 
20235863739SMike Smith     /*
20335863739SMike Smith      * Initialise per-controller queues.
20435863739SMike Smith      */
2050b94a66eSMike Smith     aac_initq_free(sc);
2060b94a66eSMike Smith     aac_initq_ready(sc);
2070b94a66eSMike Smith     aac_initq_busy(sc);
2080b94a66eSMike Smith     aac_initq_complete(sc);
2090b94a66eSMike Smith     aac_initq_bio(sc);
21035863739SMike Smith 
21135863739SMike Smith #if __FreeBSD_version >= 500005
21235863739SMike Smith     /*
21335863739SMike Smith      * Initialise command-completion task.
21435863739SMike Smith      */
21535863739SMike Smith     TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
21635863739SMike Smith #endif
21735863739SMike Smith 
21835863739SMike Smith     /* disable interrupts before we enable anything */
21935863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
22035863739SMike Smith 
22135863739SMike Smith     /* mark controller as suspended until we get ourselves organised */
22235863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
22335863739SMike Smith 
22435863739SMike Smith     /*
2250b94a66eSMike Smith      * Allocate command structures.
2260b94a66eSMike Smith      */
2270b94a66eSMike Smith     if ((error = aac_alloc_commands(sc)) != 0)
2280b94a66eSMike Smith 	return(error);
2290b94a66eSMike Smith 
2300b94a66eSMike Smith     /*
23135863739SMike Smith      * Initialise the adapter.
23235863739SMike Smith      */
2330b94a66eSMike Smith     if ((error = aac_init(sc)) != 0)
23435863739SMike Smith 	return(error);
23535863739SMike Smith 
23635863739SMike Smith     /*
23735863739SMike Smith      * Print a little information about the controller.
23835863739SMike Smith      */
23935863739SMike Smith     aac_describe_controller(sc);
24035863739SMike Smith 
24135863739SMike Smith     /*
24235863739SMike Smith      * Register to probe our containers later.
24335863739SMike Smith      */
24435863739SMike Smith     sc->aac_ich.ich_func = aac_startup;
24535863739SMike Smith     sc->aac_ich.ich_arg = sc;
24635863739SMike Smith     if (config_intrhook_establish(&sc->aac_ich) != 0) {
24735863739SMike Smith         device_printf(sc->aac_dev, "can't establish configuration hook\n");
24835863739SMike Smith         return(ENXIO);
24935863739SMike Smith     }
25035863739SMike Smith 
25135863739SMike Smith     /*
25235863739SMike Smith      * Make the control device.
25335863739SMike Smith      */
25435863739SMike Smith     unit = device_get_unit(sc->aac_dev);
255c6eafcf2SScott Long     sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644,
256c6eafcf2SScott Long 			     "aac%d", unit);
257157fbb2eSScott Long     (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
2584aa620cdSScott Long     (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
259157fbb2eSScott Long 
26035863739SMike Smith     sc->aac_dev_t->si_drv1 = sc;
26135863739SMike Smith 
26235863739SMike Smith     return(0);
26335863739SMike Smith }
26435863739SMike Smith 
265c6eafcf2SScott Long /******************************************************************************
26635863739SMike Smith  * Probe for containers, create disks.
26735863739SMike Smith  */
26835863739SMike Smith static void
26935863739SMike Smith aac_startup(void *arg)
27035863739SMike Smith {
27135863739SMike Smith     struct aac_softc		*sc = (struct aac_softc *)arg;
27235863739SMike Smith     struct aac_mntinfo		mi;
27335863739SMike Smith     struct aac_mntinforesponse	mir;
27435863739SMike Smith     device_t			child;
27535863739SMike Smith     u_int16_t			rsize;
27635863739SMike Smith     int				i;
27735863739SMike Smith 
27835863739SMike Smith     debug_called(1);
27935863739SMike Smith 
28035863739SMike Smith     /* disconnect ourselves from the intrhook chain */
28135863739SMike Smith     config_intrhook_disestablish(&sc->aac_ich);
28235863739SMike Smith 
28335863739SMike Smith     /* loop over possible containers */
28435863739SMike Smith     mi.Command = VM_NameServe;
28535863739SMike Smith     mi.MntType = FT_FILESYS;
28635863739SMike Smith     for (i = 0; i < AAC_MAX_CONTAINERS; i++) {
28735863739SMike Smith 	/* request information on this container */
28835863739SMike Smith 	mi.MntCount = i;
289f6c4dd3fSScott Long 	rsize = sizeof(mir);
290c6eafcf2SScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
291c6eafcf2SScott Long 			 sizeof(struct aac_mntinfo), &mir, &rsize)) {
29235863739SMike Smith 	    debug(2, "error probing container %d", i);
29335863739SMike Smith 	    continue;
29435863739SMike Smith 	}
29535863739SMike Smith 	/* check response size */
29635863739SMike Smith 	if (rsize != sizeof(mir)) {
297c6eafcf2SScott Long 	    debug(2, "container info response wrong size (%d should be %d)",
298c6eafcf2SScott Long 		  rsize, sizeof(mir));
29935863739SMike Smith 	    continue;
30035863739SMike Smith 	}
30135863739SMike Smith 	/*
302c6eafcf2SScott Long 	 * Check container volume type for validity.  Note that many of the
303c6eafcf2SScott Long 	 * possible types may never show up.
30435863739SMike Smith 	 */
30535863739SMike Smith 	if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) {
30635863739SMike Smith 	    debug(1, "%d: id %x  name '%.16s'  size %u  type %d",
30735863739SMike Smith 		  i, mir.MntTable[0].ObjectId,
30835863739SMike Smith 		  mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity,
30935863739SMike Smith 		  mir.MntTable[0].VolType);
31035863739SMike Smith 
31135863739SMike Smith 	    if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) {
31235863739SMike Smith 		device_printf(sc->aac_dev, "device_add_child failed\n");
31335863739SMike Smith 	    } else {
31435863739SMike Smith 		device_set_ivars(child, &sc->aac_container[i]);
31535863739SMike Smith 	    }
316c6eafcf2SScott Long 	    device_set_desc(child, aac_describe_code(aac_container_types,
317c6eafcf2SScott Long 			    mir.MntTable[0].VolType));
31835863739SMike Smith 	    sc->aac_container[i].co_disk = child;
31935863739SMike Smith 	    sc->aac_container[i].co_mntobj = mir.MntTable[0];
32035863739SMike Smith 	}
32135863739SMike Smith     }
32235863739SMike Smith 
32335863739SMike Smith     /* poke the bus to actually attach the child devices */
32435863739SMike Smith     if (bus_generic_attach(sc->aac_dev))
32535863739SMike Smith 	device_printf(sc->aac_dev, "bus_generic_attach failed\n");
32635863739SMike Smith 
32735863739SMike Smith     /* mark the controller up */
32835863739SMike Smith     sc->aac_state &= ~AAC_STATE_SUSPEND;
32935863739SMike Smith 
33035863739SMike Smith     /* enable interrupts now */
33135863739SMike Smith     AAC_UNMASK_INTERRUPTS(sc);
3320b94a66eSMike Smith 
3330b94a66eSMike Smith     /* enable the timeout watchdog */
3340b94a66eSMike Smith     timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
33535863739SMike Smith }
33635863739SMike Smith 
337c6eafcf2SScott Long /******************************************************************************
33835863739SMike Smith  * Free all of the resources associated with (sc)
33935863739SMike Smith  *
34035863739SMike Smith  * Should not be called if the controller is active.
34135863739SMike Smith  */
34235863739SMike Smith void
34335863739SMike Smith aac_free(struct aac_softc *sc)
34435863739SMike Smith {
34535863739SMike Smith     debug_called(1);
34635863739SMike Smith 
34735863739SMike Smith     /* remove the control device */
34835863739SMike Smith     if (sc->aac_dev_t != NULL)
34935863739SMike Smith 	destroy_dev(sc->aac_dev_t);
35035863739SMike Smith 
3510b94a66eSMike Smith     /* throw away any FIB buffers, discard the FIB DMA tag */
3520b94a66eSMike Smith     if (sc->aac_fibs != NULL)
3530b94a66eSMike Smith 	aac_free_commands(sc);
3540b94a66eSMike Smith     if (sc->aac_fib_dmat)
3550b94a66eSMike Smith 	bus_dma_tag_destroy(sc->aac_fib_dmat);
35635863739SMike Smith 
35735863739SMike Smith     /* destroy the common area */
35835863739SMike Smith     if (sc->aac_common) {
35935863739SMike Smith 	bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
360c6eafcf2SScott Long 	bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
361c6eafcf2SScott Long 			sc->aac_common_dmamap);
36235863739SMike Smith     }
3630b94a66eSMike Smith     if (sc->aac_common_dmat)
3640b94a66eSMike Smith 	bus_dma_tag_destroy(sc->aac_common_dmat);
36535863739SMike Smith 
36635863739SMike Smith     /* disconnect the interrupt handler */
36735863739SMike Smith     if (sc->aac_intr)
36835863739SMike Smith 	bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
36935863739SMike Smith     if (sc->aac_irq != NULL)
370c6eafcf2SScott Long 	bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
371c6eafcf2SScott Long 			     sc->aac_irq);
37235863739SMike Smith 
37335863739SMike Smith     /* destroy data-transfer DMA tag */
37435863739SMike Smith     if (sc->aac_buffer_dmat)
37535863739SMike Smith 	bus_dma_tag_destroy(sc->aac_buffer_dmat);
37635863739SMike Smith 
37735863739SMike Smith     /* destroy the parent DMA tag */
37835863739SMike Smith     if (sc->aac_parent_dmat)
37935863739SMike Smith 	bus_dma_tag_destroy(sc->aac_parent_dmat);
38035863739SMike Smith 
38135863739SMike Smith     /* release the register window mapping */
38235863739SMike Smith     if (sc->aac_regs_resource != NULL)
383c6eafcf2SScott Long 	bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid,
384c6eafcf2SScott Long 			     sc->aac_regs_resource);
38535863739SMike Smith }
38635863739SMike Smith 
387c6eafcf2SScott Long /******************************************************************************
38835863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
38935863739SMike Smith  */
39035863739SMike Smith int
39135863739SMike Smith aac_detach(device_t dev)
39235863739SMike Smith {
39335863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
39435863739SMike Smith     int			error;
39535863739SMike Smith 
39635863739SMike Smith     debug_called(1);
39735863739SMike Smith 
39835863739SMike Smith     if (sc->aac_state & AAC_STATE_OPEN)
39935863739SMike Smith 	return(EBUSY);
40035863739SMike Smith 
40135863739SMike Smith     if ((error = aac_shutdown(dev)))
40235863739SMike Smith 	return(error);
40335863739SMike Smith 
40435863739SMike Smith     aac_free(sc);
40535863739SMike Smith 
40635863739SMike Smith     return(0);
40735863739SMike Smith }
40835863739SMike Smith 
409c6eafcf2SScott Long /******************************************************************************
41035863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
41135863739SMike Smith  *
41235863739SMike Smith  * This function is called before detach or system shutdown.
41335863739SMike Smith  *
4140b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
41535863739SMike Smith  * allow shutdown if any device is open.
41635863739SMike Smith  */
41735863739SMike Smith int
41835863739SMike Smith aac_shutdown(device_t dev)
41935863739SMike Smith {
42035863739SMike Smith     struct aac_softc		*sc = device_get_softc(dev);
42135863739SMike Smith     struct aac_close_command	cc;
42235863739SMike Smith     int				s, i;
42335863739SMike Smith 
42435863739SMike Smith     debug_called(1);
42535863739SMike Smith 
42635863739SMike Smith     s = splbio();
42735863739SMike Smith 
42835863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
42935863739SMike Smith 
43035863739SMike Smith     /*
43135863739SMike Smith      * Send a Container shutdown followed by a HostShutdown FIB to the
43235863739SMike Smith      * controller to convince it that we don't want to talk to it anymore.
43335863739SMike Smith      * We've been closed and all I/O completed already
43435863739SMike Smith      */
43535863739SMike Smith     device_printf(sc->aac_dev, "shutting down controller...");
43635863739SMike Smith 
43735863739SMike Smith     cc.Command = VM_CloseAll;
43835863739SMike Smith     cc.ContainerId = 0xffffffff;
43935863739SMike Smith     if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) {
44035863739SMike Smith 	printf("FAILED.\n");
44135863739SMike Smith     } else {
44235863739SMike Smith 	i = 0;
443c6eafcf2SScott Long 	if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i,
444c6eafcf2SScott Long 			 sizeof(i), NULL, NULL)) {
44535863739SMike Smith 	    printf("FAILED.\n");
44635863739SMike Smith 	} else {
44735863739SMike Smith 	    printf("done.\n");
44835863739SMike Smith 	}
44935863739SMike Smith     }
45035863739SMike Smith 
45135863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
45235863739SMike Smith 
45335863739SMike Smith     splx(s);
45435863739SMike Smith     return(0);
45535863739SMike Smith }
45635863739SMike Smith 
457c6eafcf2SScott Long /******************************************************************************
45835863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
45935863739SMike Smith  */
46035863739SMike Smith int
46135863739SMike Smith aac_suspend(device_t dev)
46235863739SMike Smith {
46335863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
46435863739SMike Smith     int			s;
46535863739SMike Smith 
46635863739SMike Smith     debug_called(1);
46735863739SMike Smith     s = splbio();
46835863739SMike Smith 
46935863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
47035863739SMike Smith 
47135863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
47235863739SMike Smith     splx(s);
47335863739SMike Smith     return(0);
47435863739SMike Smith }
47535863739SMike Smith 
476c6eafcf2SScott Long /******************************************************************************
47735863739SMike Smith  * Bring the controller back to a state ready for operation.
47835863739SMike Smith  */
47935863739SMike Smith int
48035863739SMike Smith aac_resume(device_t dev)
48135863739SMike Smith {
48235863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
48335863739SMike Smith 
48435863739SMike Smith     debug_called(1);
48535863739SMike Smith     sc->aac_state &= ~AAC_STATE_SUSPEND;
48635863739SMike Smith     AAC_UNMASK_INTERRUPTS(sc);
48735863739SMike Smith     return(0);
48835863739SMike Smith }
48935863739SMike Smith 
490c6eafcf2SScott Long /******************************************************************************
49135863739SMike Smith  * Take an interrupt.
49235863739SMike Smith  */
49335863739SMike Smith void
49435863739SMike Smith aac_intr(void *arg)
49535863739SMike Smith {
49635863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
49735863739SMike Smith     u_int16_t		reason;
49835863739SMike Smith 
49935863739SMike Smith     debug_called(2);
50035863739SMike Smith 
50135863739SMike Smith     reason = AAC_GET_ISTATUS(sc);
50235863739SMike Smith 
50335863739SMike Smith     /* controller wants to talk to the log?  XXX should we defer this? */
50435863739SMike Smith     if (reason & AAC_DB_PRINTF) {
50535863739SMike Smith 	if (sc->aac_common->ac_printf[0]) {
506c6eafcf2SScott Long 	    device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE,
507c6eafcf2SScott Long 			  sc->aac_common->ac_printf);
50835863739SMike Smith 	    sc->aac_common->ac_printf[0] = 0;
50935863739SMike Smith 	}
51035863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
51135863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_PRINTF);
51235863739SMike Smith     }
51335863739SMike Smith 
51435863739SMike Smith     /* controller has a message for us? */
51535863739SMike Smith     if (reason & AAC_DB_COMMAND_READY) {
51635863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
517da4c1ce3SJustin T. Gibbs 	aac_host_command(sc);
51835863739SMike Smith     }
51935863739SMike Smith 
52035863739SMike Smith     /* controller has a response for us? */
52135863739SMike Smith     if (reason & AAC_DB_RESPONSE_READY) {
52235863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
523da4c1ce3SJustin T. Gibbs 	aac_host_response(sc);
52435863739SMike Smith     }
52535863739SMike Smith 
526c6eafcf2SScott Long     /*
527c6eafcf2SScott Long      * spurious interrupts that we don't use - reset the mask and clear the
528c6eafcf2SScott Long      * interrupts
529c6eafcf2SScott Long      */
53035863739SMike Smith     if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
53135863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
532c6eafcf2SScott Long 	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL |
533c6eafcf2SScott Long 			  AAC_DB_RESPONSE_NOT_FULL);
53435863739SMike Smith     }
53535863739SMike Smith };
53635863739SMike Smith 
537c6eafcf2SScott Long /******************************************************************************
538c6eafcf2SScott Long  ******************************************************************************
53935863739SMike Smith 				Command Processing
540c6eafcf2SScott Long  ******************************************************************************
541c6eafcf2SScott Long  ******************************************************************************/
54235863739SMike Smith 
543c6eafcf2SScott Long /******************************************************************************
54435863739SMike Smith  * Start as much queued I/O as possible on the controller
54535863739SMike Smith  */
54635863739SMike Smith static void
54735863739SMike Smith aac_startio(struct aac_softc *sc)
54835863739SMike Smith {
54935863739SMike Smith     struct aac_command	*cm;
55035863739SMike Smith 
55135863739SMike Smith     debug_called(2);
55235863739SMike Smith 
55335863739SMike Smith     for(;;) {
55435863739SMike Smith 	/* try to get a command that's been put off for lack of resources */
55535863739SMike Smith 	cm = aac_dequeue_ready(sc);
55635863739SMike Smith 
55735863739SMike Smith 	/* try to build a command off the bio queue (ignore error return) */
5580b94a66eSMike Smith 	if (cm == NULL)
55935863739SMike Smith 	    aac_bio_command(sc, &cm);
56035863739SMike Smith 
56135863739SMike Smith 	/* nothing to do? */
56235863739SMike Smith 	if (cm == NULL)
56335863739SMike Smith 	    break;
56435863739SMike Smith 
56535863739SMike Smith 	/* try to give the command to the controller */
56635863739SMike Smith 	if (aac_start(cm) == EBUSY) {
56735863739SMike Smith 	    /* put it on the ready queue for later */
56835863739SMike Smith 	    aac_requeue_ready(cm);
56935863739SMike Smith 	    break;
57035863739SMike Smith 	}
57135863739SMike Smith     }
57235863739SMike Smith }
57335863739SMike Smith 
574c6eafcf2SScott Long /******************************************************************************
57535863739SMike Smith  * Deliver a command to the controller; allocate controller resources at the
57635863739SMike Smith  * last moment when possible.
57735863739SMike Smith  */
57835863739SMike Smith static int
57935863739SMike Smith aac_start(struct aac_command *cm)
58035863739SMike Smith {
58135863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
582ed5c5fb4SMike Smith     int			error;
58335863739SMike Smith 
58435863739SMike Smith     debug_called(2);
58535863739SMike Smith 
58635863739SMike Smith     /* get the command mapped */
58735863739SMike Smith     aac_map_command(cm);
58835863739SMike Smith 
5890b94a66eSMike Smith     /* fix up the address values in the FIB */
59035863739SMike Smith     cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
59135863739SMike Smith     cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
59235863739SMike Smith 
59335863739SMike Smith     /* save a pointer to the command for speedy reverse-lookup */
594c6eafcf2SScott Long     cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical
595c6eafcf2SScott Long 							 * address issue */
59635863739SMike Smith 
59735863739SMike Smith     /* put the FIB on the outbound queue */
598f6c4dd3fSScott Long     error = aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm);
5990b94a66eSMike Smith     return(error);
60035863739SMike Smith }
60135863739SMike Smith 
602c6eafcf2SScott Long /******************************************************************************
60335863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
60435863739SMike Smith  */
60535863739SMike Smith static void
60635863739SMike Smith aac_host_command(struct aac_softc *sc)
60735863739SMike Smith {
60835863739SMike Smith     struct aac_fib	*fib;
60935863739SMike Smith     u_int32_t		fib_size;
61035863739SMike Smith 
61135863739SMike Smith     debug_called(1);
61235863739SMike Smith 
61335863739SMike Smith     for (;;) {
61435863739SMike Smith 	if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib))
61535863739SMike Smith 	    break;	/* nothing to do */
61635863739SMike Smith 
61735863739SMike Smith 	switch(fib->Header.Command) {
61835863739SMike Smith 	case AifRequest:
61935863739SMike Smith 	    aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]);
62035863739SMike Smith 	    break;
62135863739SMike Smith 	default:
62235863739SMike Smith 	    device_printf(sc->aac_dev, "unknown command from controller\n");
62335863739SMike Smith 	    AAC_PRINT_FIB(sc, fib);
62435863739SMike Smith 	    break;
62535863739SMike Smith 	}
62635863739SMike Smith 
62735863739SMike Smith 	/* XXX reply to FIBs requesting responses ?? */
62835863739SMike Smith 	/* XXX how do we return these FIBs to the controller? */
62935863739SMike Smith     }
63035863739SMike Smith }
63135863739SMike Smith 
632c6eafcf2SScott Long /******************************************************************************
63335863739SMike Smith  * Handle notification of one or more FIBs completed by the controller
63435863739SMike Smith  */
63535863739SMike Smith static void
63635863739SMike Smith aac_host_response(struct aac_softc *sc)
63735863739SMike Smith {
63835863739SMike Smith     struct aac_command	*cm;
63935863739SMike Smith     struct aac_fib	*fib;
64035863739SMike Smith     u_int32_t		fib_size;
64135863739SMike Smith 
64235863739SMike Smith     debug_called(2);
64335863739SMike Smith 
64435863739SMike Smith     for (;;) {
64535863739SMike Smith 	/* look for completed FIBs on our queue */
64635863739SMike Smith 	if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib))
64735863739SMike Smith 	    break;	/* nothing to do */
64835863739SMike Smith 
64935863739SMike Smith 	/* get the command, unmap and queue for later processing */
65035863739SMike Smith 	cm = (struct aac_command *)fib->Header.SenderData;
65135863739SMike Smith 	if (cm == NULL) {
65235863739SMike Smith 	    AAC_PRINT_FIB(sc, fib);
65335863739SMike Smith 	} else {
6540b94a66eSMike Smith 	    aac_remove_busy(cm);
65535863739SMike Smith 	    aac_unmap_command(cm);		/* XXX defer? */
6560b94a66eSMike Smith 	    aac_enqueue_complete(cm);
65735863739SMike Smith 	}
65835863739SMike Smith     }
65935863739SMike Smith 
66035863739SMike Smith     /* handle completion processing */
66135863739SMike Smith #if __FreeBSD_version >= 500005
66235863739SMike Smith     taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
66335863739SMike Smith #else
66435863739SMike Smith     aac_complete(sc, 0);
66535863739SMike Smith #endif
66635863739SMike Smith }
66735863739SMike Smith 
668c6eafcf2SScott Long /******************************************************************************
66935863739SMike Smith  * Process completed commands.
67035863739SMike Smith  */
67135863739SMike Smith static void
67235863739SMike Smith aac_complete(void *context, int pending)
67335863739SMike Smith {
67435863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)context;
67535863739SMike Smith     struct aac_command	*cm;
67635863739SMike Smith 
67735863739SMike Smith     debug_called(2);
67835863739SMike Smith 
67935863739SMike Smith     /* pull completed commands off the queue */
68035863739SMike Smith     for (;;) {
6810b94a66eSMike Smith 	cm = aac_dequeue_complete(sc);
68235863739SMike Smith 	if (cm == NULL)
6830b94a66eSMike Smith 	    break;
68435863739SMike Smith 	cm->cm_flags |= AAC_CMD_COMPLETED;
68535863739SMike Smith 
68635863739SMike Smith 	/* is there a completion handler? */
68735863739SMike Smith 	if (cm->cm_complete != NULL) {
68835863739SMike Smith 	    cm->cm_complete(cm);
68935863739SMike Smith 	} else {
69035863739SMike Smith 	    /* assume that someone is sleeping on this command */
69135863739SMike Smith 	    wakeup(cm);
69235863739SMike Smith 	}
69335863739SMike Smith     }
6940b94a66eSMike Smith 
6950b94a66eSMike Smith     /* see if we can start some more I/O */
6960b94a66eSMike Smith     aac_startio(sc);
69735863739SMike Smith }
69835863739SMike Smith 
699c6eafcf2SScott Long /******************************************************************************
70035863739SMike Smith  * Handle a bio submitted from a disk device.
70135863739SMike Smith  */
70235863739SMike Smith void
70335863739SMike Smith aac_submit_bio(struct bio *bp)
70435863739SMike Smith {
70535863739SMike Smith     struct aac_disk	*ad = (struct aac_disk *)bp->bio_dev->si_drv1;
70635863739SMike Smith     struct aac_softc	*sc = ad->ad_controller;
70735863739SMike Smith 
70835863739SMike Smith     debug_called(2);
70935863739SMike Smith 
71035863739SMike Smith     /* queue the BIO and try to get some work done */
7110b94a66eSMike Smith     aac_enqueue_bio(sc, bp);
71235863739SMike Smith     aac_startio(sc);
71335863739SMike Smith }
71435863739SMike Smith 
715c6eafcf2SScott Long /******************************************************************************
71635863739SMike Smith  * Get a bio and build a command to go with it.
71735863739SMike Smith  */
71835863739SMike Smith static int
71935863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
72035863739SMike Smith {
72135863739SMike Smith     struct aac_command		*cm;
72235863739SMike Smith     struct aac_fib		*fib;
72335863739SMike Smith     struct aac_blockread	*br;
72435863739SMike Smith     struct aac_blockwrite	*bw;
72535863739SMike Smith     struct aac_disk		*ad;
72635863739SMike Smith     struct bio			*bp;
72735863739SMike Smith 
72835863739SMike Smith     debug_called(2);
72935863739SMike Smith 
73035863739SMike Smith     /* get the resources we will need */
73135863739SMike Smith     cm = NULL;
7320b94a66eSMike Smith     if ((bp = aac_dequeue_bio(sc)) == NULL)
73335863739SMike Smith 	goto fail;
73435863739SMike Smith     if (aac_alloc_command(sc, &cm))	/* get a command */
73535863739SMike Smith 	goto fail;
73635863739SMike Smith 
73735863739SMike Smith     /* fill out the command */
7380b94a66eSMike Smith     cm->cm_data = (void *)bp->bio_data;
7390b94a66eSMike Smith     cm->cm_datalen = bp->bio_bcount;
7400b94a66eSMike Smith     cm->cm_complete = aac_bio_complete;
74135863739SMike Smith     cm->cm_private = bp;
7420b94a66eSMike Smith     cm->cm_timestamp = time_second;
74335863739SMike Smith 
74435863739SMike Smith     /* build the FIB */
74535863739SMike Smith     fib = cm->cm_fib;
74635863739SMike Smith     fib->Header.XferState =
74735863739SMike Smith 	AAC_FIBSTATE_HOSTOWNED   |
74835863739SMike Smith 	AAC_FIBSTATE_INITIALISED |
74935863739SMike Smith 	AAC_FIBSTATE_FROMHOST    |
75035863739SMike Smith 	AAC_FIBSTATE_REXPECTED   |
75135863739SMike Smith 	AAC_FIBSTATE_NORM;
75235863739SMike Smith     fib->Header.Command = ContainerCommand;
75335863739SMike Smith     fib->Header.Size = sizeof(struct aac_fib_header);
75435863739SMike Smith 
75535863739SMike Smith     /* build the read/write request */
75635863739SMike Smith     ad = (struct aac_disk *)bp->bio_dev->si_drv1;
75735863739SMike Smith     if (BIO_IS_READ(bp)) {
75835863739SMike Smith 	br = (struct aac_blockread *)&fib->data[0];
75935863739SMike Smith 	br->Command = VM_CtBlockRead;
76035863739SMike Smith 	br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
76135863739SMike Smith 	br->BlockNumber = bp->bio_pblkno;
76235863739SMike Smith 	br->ByteCount = bp->bio_bcount;
76335863739SMike Smith 	fib->Header.Size += sizeof(struct aac_blockread);
76435863739SMike Smith 	cm->cm_sgtable = &br->SgMap;
76535863739SMike Smith 	cm->cm_flags |= AAC_CMD_DATAIN;
76635863739SMike Smith     } else {
76735863739SMike Smith 	bw = (struct aac_blockwrite *)&fib->data[0];
76835863739SMike Smith 	bw->Command = VM_CtBlockWrite;
76935863739SMike Smith 	bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
77035863739SMike Smith 	bw->BlockNumber = bp->bio_pblkno;
77135863739SMike Smith 	bw->ByteCount = bp->bio_bcount;
77235863739SMike Smith 	bw->Stable = CUNSTABLE;		/* XXX what's appropriate here? */
77335863739SMike Smith 	fib->Header.Size += sizeof(struct aac_blockwrite);
77435863739SMike Smith 	cm->cm_flags |= AAC_CMD_DATAOUT;
77535863739SMike Smith 	cm->cm_sgtable = &bw->SgMap;
77635863739SMike Smith     }
77735863739SMike Smith 
77835863739SMike Smith     *cmp = cm;
77935863739SMike Smith     return(0);
78035863739SMike Smith 
78135863739SMike Smith fail:
78235863739SMike Smith     if (bp != NULL)
7830b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
78435863739SMike Smith     if (cm != NULL)
78535863739SMike Smith 	aac_release_command(cm);
78635863739SMike Smith     return(ENOMEM);
78735863739SMike Smith }
78835863739SMike Smith 
789c6eafcf2SScott Long /******************************************************************************
79035863739SMike Smith  * Handle a bio-instigated command that has been completed.
79135863739SMike Smith  */
79235863739SMike Smith static void
79335863739SMike Smith aac_bio_complete(struct aac_command *cm)
79435863739SMike Smith {
79535863739SMike Smith     struct aac_blockread_response	*brr;
79635863739SMike Smith     struct aac_blockwrite_response	*bwr;
79735863739SMike Smith     struct bio				*bp;
79835863739SMike Smith     AAC_FSAStatus			status;
79935863739SMike Smith 
80035863739SMike Smith     /* fetch relevant status and then release the command */
80135863739SMike Smith     bp = (struct bio *)cm->cm_private;
80235863739SMike Smith     if (BIO_IS_READ(bp)) {
80335863739SMike Smith 	brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
80435863739SMike Smith 	status = brr->Status;
80535863739SMike Smith     } else {
80635863739SMike Smith 	bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
80735863739SMike Smith 	status = bwr->Status;
80835863739SMike Smith     }
80935863739SMike Smith     aac_release_command(cm);
81035863739SMike Smith 
81135863739SMike Smith     /* fix up the bio based on status */
81235863739SMike Smith     if (status == ST_OK) {
81335863739SMike Smith 	bp->bio_resid = 0;
81435863739SMike Smith     } else {
81535863739SMike Smith 	bp->bio_error = EIO;
81635863739SMike Smith 	bp->bio_flags |= BIO_ERROR;
8170b94a66eSMike Smith 	/* pass an error string out to the disk layer */
8180b94a66eSMike Smith 	bp->bio_driver1 = aac_describe_code(aac_command_status_table, status);
81935863739SMike Smith     }
8200b94a66eSMike Smith     aac_biodone(bp);
82135863739SMike Smith }
82235863739SMike Smith 
823c6eafcf2SScott Long /******************************************************************************
82435863739SMike Smith  * Submit a command to the controller, return when it completes.
82535863739SMike Smith  */
82635863739SMike Smith static int
82735863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout)
82835863739SMike Smith {
82935863739SMike Smith     int s, error = 0;
83035863739SMike Smith 
83135863739SMike Smith     debug_called(2);
83235863739SMike Smith 
83335863739SMike Smith     /* Put the command on the ready queue and get things going */
83435863739SMike Smith     aac_enqueue_ready(cm);
83535863739SMike Smith     aac_startio(cm->cm_sc);
83635863739SMike Smith     s = splbio();
83735863739SMike Smith     while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
838f6c4dd3fSScott Long         error = tsleep(cm, PRIBIO, "aacwait", 0);
83935863739SMike Smith     }
84035863739SMike Smith     splx(s);
84135863739SMike Smith     return(error);
84235863739SMike Smith }
84335863739SMike Smith 
844c6eafcf2SScott Long /******************************************************************************
845c6eafcf2SScott Long  ******************************************************************************
84635863739SMike Smith 			Command Buffer Management
847c6eafcf2SScott Long  ******************************************************************************
848c6eafcf2SScott Long  ******************************************************************************/
84935863739SMike Smith 
850c6eafcf2SScott Long /******************************************************************************
85135863739SMike Smith  * Allocate a command.
85235863739SMike Smith  */
85335863739SMike Smith static int
85435863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
85535863739SMike Smith {
85635863739SMike Smith     struct aac_command	*cm;
85735863739SMike Smith 
85835863739SMike Smith     debug_called(3);
85935863739SMike Smith 
8600b94a66eSMike Smith     if ((cm = aac_dequeue_free(sc)) == NULL)
86135863739SMike Smith 	return(ENOMEM);
86235863739SMike Smith 
8630b94a66eSMike Smith     *cmp = cm;
8640b94a66eSMike Smith     return(0);
8650b94a66eSMike Smith }
8660b94a66eSMike Smith 
867c6eafcf2SScott Long /******************************************************************************
8680b94a66eSMike Smith  * Release a command back to the freelist.
8690b94a66eSMike Smith  */
8700b94a66eSMike Smith static void
8710b94a66eSMike Smith aac_release_command(struct aac_command *cm)
8720b94a66eSMike Smith {
8730b94a66eSMike Smith     debug_called(3);
8740b94a66eSMike Smith 
8750b94a66eSMike Smith     /* (re)initialise the command/FIB */
87635863739SMike Smith     cm->cm_sgtable = NULL;
87735863739SMike Smith     cm->cm_flags = 0;
87835863739SMike Smith     cm->cm_complete = NULL;
87935863739SMike Smith     cm->cm_private = NULL;
88035863739SMike Smith     cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
88135863739SMike Smith     cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
88235863739SMike Smith     cm->cm_fib->Header.Flags = 0;
88335863739SMike Smith     cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
88435863739SMike Smith 
88535863739SMike Smith     /*
88635863739SMike Smith      * These are duplicated in aac_start to cover the case where an
88735863739SMike Smith      * intermediate stage may have destroyed them.  They're left
88835863739SMike Smith      * initialised here for debugging purposes only.
88935863739SMike Smith      */
89035863739SMike Smith     cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
89135863739SMike Smith     cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
89235863739SMike Smith 
89335863739SMike Smith     aac_enqueue_free(cm);
89435863739SMike Smith }
89535863739SMike Smith 
896c6eafcf2SScott Long /******************************************************************************
8970b94a66eSMike Smith  * Map helper for command/FIB allocation.
89835863739SMike Smith  */
89935863739SMike Smith static void
9000b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
90135863739SMike Smith {
9020b94a66eSMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
90335863739SMike Smith 
90435863739SMike Smith     debug_called(3);
90535863739SMike Smith 
9060b94a66eSMike Smith     sc->aac_fibphys = segs[0].ds_addr;
90735863739SMike Smith }
90835863739SMike Smith 
909c6eafcf2SScott Long /******************************************************************************
9100b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
91135863739SMike Smith  */
9120b94a66eSMike Smith static int
9130b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
91435863739SMike Smith {
91535863739SMike Smith     struct aac_command		*cm;
91635863739SMike Smith     int				i;
91735863739SMike Smith 
91835863739SMike Smith     debug_called(1);
91935863739SMike Smith 
9200b94a66eSMike Smith     /* allocate the FIBs in DMAable memory and load them */
921c6eafcf2SScott Long     if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs,
922c6eafcf2SScott Long 			 BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
9230b94a66eSMike Smith 	return(ENOMEM);
92435863739SMike Smith     }
9250b94a66eSMike Smith     bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
926c6eafcf2SScott Long 		    AAC_FIB_COUNT * sizeof(struct aac_fib),
927c6eafcf2SScott Long 		    aac_map_command_helper, sc, 0);
92835863739SMike Smith 
9290b94a66eSMike Smith     /* initialise constant fields in the command structure */
9300b94a66eSMike Smith     for (i = 0; i < AAC_FIB_COUNT; i++) {
9310b94a66eSMike Smith 	cm = &sc->aac_command[i];
93235863739SMike Smith 	cm->cm_sc = sc;
9330b94a66eSMike Smith 	cm->cm_fib = sc->aac_fibs + i;
9340b94a66eSMike Smith 	cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
93535863739SMike Smith 
93635863739SMike Smith 	if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
93735863739SMike Smith 	    aac_release_command(cm);
93835863739SMike Smith     }
9390b94a66eSMike Smith     return(0);
94035863739SMike Smith }
94135863739SMike Smith 
942c6eafcf2SScott Long /******************************************************************************
9430b94a66eSMike Smith  * Free FIBs owned by this adapter.
94435863739SMike Smith  */
94535863739SMike Smith static void
9460b94a66eSMike Smith aac_free_commands(struct aac_softc *sc)
94735863739SMike Smith {
94835863739SMike Smith     int			i;
94935863739SMike Smith 
95035863739SMike Smith     debug_called(1);
95135863739SMike Smith 
9520b94a66eSMike Smith     for (i = 0; i < AAC_FIB_COUNT; i++)
9530b94a66eSMike Smith 	bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap);
9540b94a66eSMike Smith     bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
9550b94a66eSMike Smith     bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
95635863739SMike Smith }
95735863739SMike Smith 
958c6eafcf2SScott Long /******************************************************************************
95935863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
96035863739SMike Smith  */
96135863739SMike Smith static void
96235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
96335863739SMike Smith {
96435863739SMike Smith     struct aac_command		*cm = (struct aac_command *)arg;
96535863739SMike Smith     struct aac_fib		*fib = cm->cm_fib;
96635863739SMike Smith     struct aac_sg_table		*sg;
96735863739SMike Smith     int				i;
96835863739SMike Smith 
96935863739SMike Smith     debug_called(3);
97035863739SMike Smith 
97135863739SMike Smith     /* find the s/g table */
97235863739SMike Smith     sg = cm->cm_sgtable;
97335863739SMike Smith 
97435863739SMike Smith     /* copy into the FIB */
97535863739SMike Smith     if (sg != NULL) {
97635863739SMike Smith 	sg->SgCount = nseg;
97735863739SMike Smith 	for (i = 0; i < nseg; i++) {
97835863739SMike Smith 	    sg->SgEntry[i].SgAddress = segs[i].ds_addr;
97935863739SMike Smith 	    sg->SgEntry[i].SgByteCount = segs[i].ds_len;
98035863739SMike Smith 	}
98135863739SMike Smith 	/* update the FIB size for the s/g count */
98235863739SMike Smith 	fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
98335863739SMike Smith     }
98435863739SMike Smith 
98535863739SMike Smith }
98635863739SMike Smith 
987c6eafcf2SScott Long /******************************************************************************
98835863739SMike Smith  * Map a command into controller-visible space.
98935863739SMike Smith  */
99035863739SMike Smith static void
99135863739SMike Smith aac_map_command(struct aac_command *cm)
99235863739SMike Smith {
99335863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
99435863739SMike Smith 
99535863739SMike Smith     debug_called(2);
99635863739SMike Smith 
99735863739SMike Smith     /* don't map more than once */
99835863739SMike Smith     if (cm->cm_flags & AAC_CMD_MAPPED)
99935863739SMike Smith 	return;
100035863739SMike Smith 
100135863739SMike Smith     if (cm->cm_datalen != 0) {
100235863739SMike Smith 	bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data,
100335863739SMike Smith 			cm->cm_datalen, aac_map_command_sg, cm, 0);
100435863739SMike Smith 
100535863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1006c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1007c6eafcf2SScott Long 			    BUS_DMASYNC_PREREAD);
100835863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1009c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1010c6eafcf2SScott Long 			    BUS_DMASYNC_PREWRITE);
101135863739SMike Smith     }
101235863739SMike Smith     cm->cm_flags |= AAC_CMD_MAPPED;
101335863739SMike Smith }
101435863739SMike Smith 
1015c6eafcf2SScott Long /******************************************************************************
101635863739SMike Smith  * Unmap a command from controller-visible space.
101735863739SMike Smith  */
101835863739SMike Smith static void
101935863739SMike Smith aac_unmap_command(struct aac_command *cm)
102035863739SMike Smith {
102135863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
102235863739SMike Smith 
102335863739SMike Smith     debug_called(2);
102435863739SMike Smith 
102535863739SMike Smith     if (!(cm->cm_flags & AAC_CMD_MAPPED))
102635863739SMike Smith 	return;
102735863739SMike Smith 
102835863739SMike Smith     if (cm->cm_datalen != 0) {
102935863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1030c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1031c6eafcf2SScott Long 			    BUS_DMASYNC_POSTREAD);
103235863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1033c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1034c6eafcf2SScott Long 			    BUS_DMASYNC_POSTWRITE);
103535863739SMike Smith 
103635863739SMike Smith 	bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
103735863739SMike Smith     }
103835863739SMike Smith     cm->cm_flags &= ~AAC_CMD_MAPPED;
103935863739SMike Smith }
104035863739SMike Smith 
1041c6eafcf2SScott Long /******************************************************************************
1042c6eafcf2SScott Long  ******************************************************************************
104335863739SMike Smith 				Hardware Interface
1044c6eafcf2SScott Long  ******************************************************************************
1045c6eafcf2SScott Long  ******************************************************************************/
104635863739SMike Smith 
1047c6eafcf2SScott Long /******************************************************************************
104835863739SMike Smith  * Initialise the adapter.
104935863739SMike Smith  */
105035863739SMike Smith static void
105135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
105235863739SMike Smith {
105335863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
105435863739SMike Smith 
105535863739SMike Smith     debug_called(1);
105635863739SMike Smith 
105735863739SMike Smith     sc->aac_common_busaddr = segs[0].ds_addr;
105835863739SMike Smith }
105935863739SMike Smith 
106035863739SMike Smith static int
106135863739SMike Smith aac_init(struct aac_softc *sc)
106235863739SMike Smith {
106335863739SMike Smith     struct aac_adapter_init	*ip;
106435863739SMike Smith     time_t			then;
106535863739SMike Smith     u_int32_t			code;
106635863739SMike Smith     u_int8_t			*qaddr;
106735863739SMike Smith 
106835863739SMike Smith     debug_called(1);
106935863739SMike Smith 
107035863739SMike Smith     /*
107135863739SMike Smith      * First wait for the adapter to come ready.
107235863739SMike Smith      */
107335863739SMike Smith     then = time_second;
107435863739SMike Smith     do {
107535863739SMike Smith 	code = AAC_GET_FWSTATUS(sc);
107635863739SMike Smith 	if (code & AAC_SELF_TEST_FAILED) {
107735863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: selftest failed\n");
107835863739SMike Smith 	    return(ENXIO);
107935863739SMike Smith 	}
108035863739SMike Smith 	if (code & AAC_KERNEL_PANIC) {
108135863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: controller kernel panic\n");
108235863739SMike Smith 	    return(ENXIO);
108335863739SMike Smith 	}
108435863739SMike Smith 	if (time_second > (then + AAC_BOOT_TIMEOUT)) {
1085c6eafcf2SScott Long 	    device_printf(sc->aac_dev, "FATAL: controller not coming ready, "
1086c6eafcf2SScott Long 			  "status %x\n", code);
108735863739SMike Smith 	    return(ENXIO);
108835863739SMike Smith 	}
108935863739SMike Smith     } while (!(code & AAC_UP_AND_RUNNING));
109035863739SMike Smith 
109135863739SMike Smith     /*
109235863739SMike Smith      * Create DMA tag for the common structure and allocate it.
109335863739SMike Smith      */
109435863739SMike Smith     if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1095c6eafcf2SScott Long 			   1, 0, 			/* algnmnt, boundary */
109635863739SMike Smith 			   BUS_SPACE_MAXADDR,		/* lowaddr */
109735863739SMike Smith 			   BUS_SPACE_MAXADDR, 		/* highaddr */
109835863739SMike Smith 			   NULL, NULL, 			/* filter, filterarg */
109935863739SMike Smith 			   sizeof(struct aac_common), 1,/* maxsize, nsegments */
110035863739SMike Smith 			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
110135863739SMike Smith 			   0,				/* flags */
110235863739SMike Smith 			   &sc->aac_common_dmat)) {
110335863739SMike Smith 	device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n");
110435863739SMike Smith 	return(ENOMEM);
110535863739SMike Smith     }
1106c6eafcf2SScott Long     if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1107c6eafcf2SScott Long 			 BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
110835863739SMike Smith 	device_printf(sc->aac_dev, "can't allocate common structure\n");
110935863739SMike Smith 	return(ENOMEM);
111035863739SMike Smith     }
1111c6eafcf2SScott Long     bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common,
1112c6eafcf2SScott Long 		    sizeof(*sc->aac_common), aac_common_map, sc, 0);
111335863739SMike Smith     bzero(sc->aac_common, sizeof(*sc->aac_common));
111435863739SMike Smith 
111535863739SMike Smith     /*
1116c6eafcf2SScott Long      * Fill in the init structure.  This tells the adapter about the physical
1117c6eafcf2SScott Long      * location of various important shared data structures.
111835863739SMike Smith      */
111935863739SMike Smith     ip = &sc->aac_common->ac_init;
112035863739SMike Smith     ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
112135863739SMike Smith 
1122c6eafcf2SScott Long     ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1123c6eafcf2SScott Long 				     offsetof(struct aac_common, ac_fibs);
112435863739SMike Smith     ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
112535863739SMike Smith     ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
112635863739SMike Smith     ip->AdapterFibAlign = sizeof(struct aac_fib);
112735863739SMike Smith 
1128c6eafcf2SScott Long     ip->PrintfBufferAddress = sc->aac_common_busaddr +
1129c6eafcf2SScott Long 			      offsetof(struct aac_common, ac_printf);
113035863739SMike Smith     ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
113135863739SMike Smith 
113235863739SMike Smith     ip->HostPhysMemPages = 0;			/* not used? */
113335863739SMike Smith     ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
113435863739SMike Smith 
113535863739SMike Smith     /*
1136c6eafcf2SScott Long      * Initialise FIB queues.  Note that it appears that the layout of the
1137c6eafcf2SScott Long      * indexes and the segmentation of the entries may be mandated by the
1138c6eafcf2SScott Long      * adapter, which is only told about the base of the queue index fields.
113935863739SMike Smith      *
114035863739SMike Smith      * The initial values of the indices are assumed to inform the adapter
1141c6eafcf2SScott Long      * of the sizes of the respective queues, and theoretically it could work
1142c6eafcf2SScott Long      * out the entire layout of the queue structures from this.  We take the
1143c6eafcf2SScott Long      * easy route and just lay this area out like everyone else does.
114435863739SMike Smith      *
114535863739SMike Smith      * The Linux driver uses a much more complex scheme whereby several header
1146c6eafcf2SScott Long      * records are kept for each queue.  We use a couple of generic list
1147c6eafcf2SScott Long      * manipulation functions which 'know' the size of each list by virtue of a
1148c6eafcf2SScott Long      * table.
114935863739SMike Smith      */
115035863739SMike Smith     qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
115135863739SMike Smith     qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
115235863739SMike Smith     sc->aac_queues = (struct aac_queue_table *)qaddr;
1153c6eafcf2SScott Long     ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues
1154c6eafcf2SScott Long 			    - (u_int32_t)sc->aac_common);
115535863739SMike Smith     bzero(sc->aac_queues, sizeof(struct aac_queue_table));
115635863739SMike Smith 
1157c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1158c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1159c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1160c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1161c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1162c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1163c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1164c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1165c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1166c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1167c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1168c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1169c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1170c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1171c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1172c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1173c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1174c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1175c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1176c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1177c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1178c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1179c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1180c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1181c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1182c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1183c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1184c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1185c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1186c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1187c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1188c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1189c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1190c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1191c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1192c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1193c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1194c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1195c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1196c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1197c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1198c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1199c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1200c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1201c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1202c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1203c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1204c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
120535863739SMike Smith 
120635863739SMike Smith     /*
120735863739SMike Smith      * Do controller-type-specific initialisation
120835863739SMike Smith      */
120935863739SMike Smith     switch (sc->aac_hwif) {
121035863739SMike Smith     case AAC_HWIF_I960RX:
121135863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
121235863739SMike Smith 	break;
121335863739SMike Smith     }
121435863739SMike Smith 
121535863739SMike Smith     /*
121635863739SMike Smith      * Give the init structure to the controller.
121735863739SMike Smith      */
121835863739SMike Smith     if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1219c6eafcf2SScott Long 			 sc->aac_common_busaddr + offsetof(struct aac_common,
1220c6eafcf2SScott Long 			 ac_init), 0, 0, 0, NULL)) {
122135863739SMike Smith 	device_printf(sc->aac_dev, "error establishing init structure\n");
122235863739SMike Smith 	return(EIO);
122335863739SMike Smith     }
122435863739SMike Smith 
122535863739SMike Smith     return(0);
122635863739SMike Smith }
122735863739SMike Smith 
1228c6eafcf2SScott Long /******************************************************************************
122935863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
123035863739SMike Smith  */
123135863739SMike Smith static int
123235863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
123335863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
123435863739SMike Smith 		 u_int32_t *sp)
123535863739SMike Smith {
123635863739SMike Smith     time_t	then;
123735863739SMike Smith     u_int32_t	status;
123835863739SMike Smith 
123935863739SMike Smith     debug_called(3);
124035863739SMike Smith 
124135863739SMike Smith     /* populate the mailbox */
124235863739SMike Smith     AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
124335863739SMike Smith 
124435863739SMike Smith     /* ensure the sync command doorbell flag is cleared */
124535863739SMike Smith     AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
124635863739SMike Smith 
124735863739SMike Smith     /* then set it to signal the adapter */
124835863739SMike Smith     AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
124935863739SMike Smith 
125035863739SMike Smith     /* spin waiting for the command to complete */
125135863739SMike Smith     then = time_second;
125235863739SMike Smith     do {
125335863739SMike Smith 	if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
125435863739SMike Smith 	    debug(2, "timed out");
125535863739SMike Smith 	    return(EIO);
125635863739SMike Smith 	}
125735863739SMike Smith     } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
125835863739SMike Smith 
125935863739SMike Smith     /* clear the completion flag */
126035863739SMike Smith     AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
126135863739SMike Smith 
126235863739SMike Smith     /* get the command status */
126335863739SMike Smith     status = AAC_GET_MAILBOXSTATUS(sc);
126435863739SMike Smith     if (sp != NULL)
126535863739SMike Smith 	*sp = status;
12660b94a66eSMike Smith     return(0);
126735863739SMike Smith }
126835863739SMike Smith 
1269c6eafcf2SScott Long /******************************************************************************
127035863739SMike Smith  * Send a synchronous FIB to the controller and wait for a result.
127135863739SMike Smith  */
127235863739SMike Smith static int
127335863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
127435863739SMike Smith 	     void *data, u_int16_t datasize,
127535863739SMike Smith 	     void *result, u_int16_t *resultsize)
127635863739SMike Smith {
127735863739SMike Smith     struct aac_fib	*fib = &sc->aac_common->ac_sync_fib;
127835863739SMike Smith 
127935863739SMike Smith     debug_called(3);
128035863739SMike Smith 
128135863739SMike Smith     if (datasize > AAC_FIB_DATASIZE)
128235863739SMike Smith 	return(EINVAL);
128335863739SMike Smith 
128435863739SMike Smith     /*
128535863739SMike Smith      * Set up the sync FIB
128635863739SMike Smith      */
1287c6eafcf2SScott Long     fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED |
1288c6eafcf2SScott Long 			    AAC_FIBSTATE_EMPTY;
128935863739SMike Smith     fib->Header.XferState |= xferstate;
129035863739SMike Smith     fib->Header.Command = command;
129135863739SMike Smith     fib->Header.StructType = AAC_FIBTYPE_TFIB;
129235863739SMike Smith     fib->Header.Size = sizeof(struct aac_fib) + datasize;
129335863739SMike Smith     fib->Header.SenderSize = sizeof(struct aac_fib);
129435863739SMike Smith     fib->Header.SenderFibAddress = (u_int32_t)fib;
1295c6eafcf2SScott Long     fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
1296c6eafcf2SScott Long 				     offsetof(struct aac_common, ac_sync_fib);
129735863739SMike Smith 
129835863739SMike Smith     /*
129935863739SMike Smith      * Copy in data.
130035863739SMike Smith      */
130135863739SMike Smith     if (data != NULL) {
1302f6c4dd3fSScott Long 	KASSERT(datasize <= sizeof(fib->data),
1303f6c4dd3fSScott Long 		"aac_sync_fib: datasize to large");
130435863739SMike Smith 	bcopy(data, fib->data, datasize);
130535863739SMike Smith 	fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM;
130635863739SMike Smith     }
130735863739SMike Smith 
130835863739SMike Smith     /*
130935863739SMike Smith      * Give the FIB to the controller, wait for a response.
131035863739SMike Smith      */
131135863739SMike Smith     if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress,
131235863739SMike Smith 			 0, 0, 0, NULL)) {
131335863739SMike Smith 	debug(2, "IO error");
131435863739SMike Smith 	return(EIO);
131535863739SMike Smith     }
131635863739SMike Smith 
131735863739SMike Smith     /*
131835863739SMike Smith      * Copy out the result
131935863739SMike Smith      */
132035863739SMike Smith     if (result != NULL) {
1321f6c4dd3fSScott Long 	u_int copysize;
1322f6c4dd3fSScott Long 
1323f6c4dd3fSScott Long 	copysize = fib->Header.Size - sizeof(struct aac_fib_header);
1324f6c4dd3fSScott Long 	if (copysize > *resultsize)
1325f6c4dd3fSScott Long 		copysize = *resultsize;
132635863739SMike Smith 	*resultsize = fib->Header.Size - sizeof(struct aac_fib_header);
1327f6c4dd3fSScott Long 	bcopy(fib->data, result, copysize);
132835863739SMike Smith     }
132935863739SMike Smith     return(0);
133035863739SMike Smith }
133135863739SMike Smith 
133235863739SMike Smith /********************************************************************************
133335863739SMike Smith  * Adapter-space FIB queue manipulation
133435863739SMike Smith  *
133535863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
133635863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
133735863739SMike Smith  */
133835863739SMike Smith static struct {
133935863739SMike Smith     int		size;
134035863739SMike Smith     int		notify;
134135863739SMike Smith } aac_qinfo[] = {
134235863739SMike Smith     {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
134335863739SMike Smith     {AAC_HOST_HIGH_CMD_ENTRIES, 0},
134435863739SMike Smith     {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
134535863739SMike Smith     {AAC_ADAP_HIGH_CMD_ENTRIES, 0},
134635863739SMike Smith     {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
134735863739SMike Smith     {AAC_HOST_HIGH_RESP_ENTRIES, 0},
134835863739SMike Smith     {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
134935863739SMike Smith     {AAC_ADAP_HIGH_RESP_ENTRIES, 0}
135035863739SMike Smith };
135135863739SMike Smith 
135235863739SMike Smith /*
1353c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
1354c6eafcf2SScott Long  * EBUSY if the queue is full.
135535863739SMike Smith  *
13560b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
1357c6eafcf2SScott Long  *       the case where we may be inserting several entries in rapid succession,
1358c6eafcf2SScott Long  *       but implementing this usefully may be difficult (it would involve a
1359c6eafcf2SScott Long  *       separate queue/notify interface).
136035863739SMike Smith  */
136135863739SMike Smith static int
1362f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
136335863739SMike Smith {
136435863739SMike Smith     u_int32_t	pi, ci;
136535863739SMike Smith     int		s, error;
1366f6c4dd3fSScott Long     u_int32_t	fib_size;
1367f6c4dd3fSScott Long     u_int32_t	fib_addr;
1368f6c4dd3fSScott Long 
1369f6c4dd3fSScott Long     fib_size = cm->cm_fib->Header.Size;
1370f6c4dd3fSScott Long     fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
137135863739SMike Smith 
137235863739SMike Smith     debug_called(3);
137335863739SMike Smith 
137435863739SMike Smith     s = splbio();
137535863739SMike Smith 
137635863739SMike Smith     /* get the producer/consumer indices */
137735863739SMike Smith     pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
137835863739SMike Smith     ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
137935863739SMike Smith 
138035863739SMike Smith     /* wrap the queue? */
138135863739SMike Smith     if (pi >= aac_qinfo[queue].size)
138235863739SMike Smith 	pi = 0;
138335863739SMike Smith 
138435863739SMike Smith     /* check for queue full */
138535863739SMike Smith     if ((pi + 1) == ci) {
138635863739SMike Smith 	error = EBUSY;
138735863739SMike Smith 	goto out;
138835863739SMike Smith     }
138935863739SMike Smith 
139035863739SMike Smith     /* populate queue entry */
139135863739SMike Smith     (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
139235863739SMike Smith     (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
139335863739SMike Smith 
139435863739SMike Smith     /* update producer index */
139535863739SMike Smith     sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
139635863739SMike Smith 
1397f6c4dd3fSScott Long     /*
1398f6c4dd3fSScott Long      * To avoid a race with its completion interrupt, place this command on the
1399f6c4dd3fSScott Long      * busy queue prior to advertising it to the controller.
1400f6c4dd3fSScott Long      */
1401f6c4dd3fSScott Long     aac_enqueue_busy(cm);
1402f6c4dd3fSScott Long 
140335863739SMike Smith     /* notify the adapter if we know how */
140435863739SMike Smith     if (aac_qinfo[queue].notify != 0)
140535863739SMike Smith 	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
140635863739SMike Smith 
140735863739SMike Smith     error = 0;
140835863739SMike Smith 
140935863739SMike Smith out:
141035863739SMike Smith     splx(s);
141135863739SMike Smith     return(error);
141235863739SMike Smith }
141335863739SMike Smith 
141435863739SMike Smith /*
1415c6eafcf2SScott Long  * Atomically remove one entry from the nominated queue, returns 0 on success or
1416c6eafcf2SScott Long  * ENOENT if the queue is empty.
141735863739SMike Smith  */
141835863739SMike Smith static int
1419c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1420c6eafcf2SScott Long 		struct aac_fib **fib_addr)
142135863739SMike Smith {
142235863739SMike Smith     u_int32_t	pi, ci;
142335863739SMike Smith     int		s, error;
1424f6c4dd3fSScott Long     int		notify;
142535863739SMike Smith 
142635863739SMike Smith     debug_called(3);
142735863739SMike Smith 
142835863739SMike Smith     s = splbio();
142935863739SMike Smith 
143035863739SMike Smith     /* get the producer/consumer indices */
143135863739SMike Smith     pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
143235863739SMike Smith     ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
143335863739SMike Smith 
143435863739SMike Smith     /* check for queue empty */
143535863739SMike Smith     if (ci == pi) {
143635863739SMike Smith 	error = ENOENT;
143735863739SMike Smith 	goto out;
143835863739SMike Smith     }
143935863739SMike Smith 
1440f6c4dd3fSScott Long     notify = 0;
1441f6c4dd3fSScott Long     if (ci == pi + 1)
1442f6c4dd3fSScott Long 	notify++;
1443f6c4dd3fSScott Long 
144435863739SMike Smith     /* wrap the queue? */
144535863739SMike Smith     if (ci >= aac_qinfo[queue].size)
144635863739SMike Smith 	ci = 0;
144735863739SMike Smith 
144835863739SMike Smith     /* fetch the entry */
144935863739SMike Smith     *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
145035863739SMike Smith     *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr;
145135863739SMike Smith 
145235863739SMike Smith     /* update consumer index */
145335863739SMike Smith     sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
145435863739SMike Smith 
145535863739SMike Smith     /* if we have made the queue un-full, notify the adapter */
1456f6c4dd3fSScott Long     if (notify && (aac_qinfo[queue].notify != 0))
145735863739SMike Smith 	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
145835863739SMike Smith     error = 0;
145935863739SMike Smith 
146035863739SMike Smith out:
146135863739SMike Smith     splx(s);
146235863739SMike Smith     return(error);
146335863739SMike Smith }
146435863739SMike Smith 
1465c6eafcf2SScott Long /******************************************************************************
14660b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
14670b94a66eSMike Smith  * and complain about them.
14680b94a66eSMike Smith  */
14690b94a66eSMike Smith static void
14700b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
14710b94a66eSMike Smith {
14720b94a66eSMike Smith     int		s;
14730b94a66eSMike Smith     struct	aac_command *cm;
14740b94a66eSMike Smith     time_t	deadline;
14750b94a66eSMike Smith 
1476f6c4dd3fSScott Long #if 0
14770b94a66eSMike Smith     /* simulate an interrupt to handle possibly-missed interrupts */
1478f6c4dd3fSScott Long     /*
1479f6c4dd3fSScott Long      * XXX This was done to work around another bug which has since been
1480f6c4dd3fSScott Long      * fixed.  It is dangerous anyways because you don't want multiple
1481f6c4dd3fSScott Long      * threads in the interrupt handler at the same time!  If calling
1482f6c4dd3fSScott Long      * is deamed neccesary in the future, proper mutexes must be used.
1483f6c4dd3fSScott Long      */
1484f6c4dd3fSScott Long     s = splbio();
14850b94a66eSMike Smith     aac_intr(sc);
1486f6c4dd3fSScott Long     splx(s);
1487f6c4dd3fSScott Long #endif
14880b94a66eSMike Smith 
14890b94a66eSMike Smith     /* kick the I/O queue to restart it in the case of deadlock */
14900b94a66eSMike Smith     aac_startio(sc);
14910b94a66eSMike Smith 
14920b94a66eSMike Smith     /* traverse the busy command list, bitch about late commands once only */
14930b94a66eSMike Smith     deadline = time_second - AAC_CMD_TIMEOUT;
14940b94a66eSMike Smith     s = splbio();
14950b94a66eSMike Smith     TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
1496f6c4dd3fSScott Long 	if ((cm->cm_timestamp < deadline)
1497f6c4dd3fSScott Long 	    /*  && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
14980b94a66eSMike Smith 	    cm->cm_flags |= AAC_CMD_TIMEDOUT;
1499f6c4dd3fSScott Long 	    device_printf(sc->aac_dev, "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
1500f6c4dd3fSScott Long 			  cm, (int)(time_second - cm->cm_timestamp));
15010b94a66eSMike Smith 	    AAC_PRINT_FIB(sc, cm->cm_fib);
15020b94a66eSMike Smith 	}
15030b94a66eSMike Smith     }
15040b94a66eSMike Smith     splx(s);
15050b94a66eSMike Smith 
15060b94a66eSMike Smith     /* reset the timer for next time */
15070b94a66eSMike Smith     timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
15080b94a66eSMike Smith     return;
15090b94a66eSMike Smith }
15100b94a66eSMike Smith 
1511c6eafcf2SScott Long /******************************************************************************
1512c6eafcf2SScott Long  ******************************************************************************
151335863739SMike Smith 			Interface Function Vectors
1514c6eafcf2SScott Long  ******************************************************************************
1515c6eafcf2SScott Long  ******************************************************************************/
151635863739SMike Smith 
1517c6eafcf2SScott Long /******************************************************************************
151835863739SMike Smith  * Read the current firmware status word.
151935863739SMike Smith  */
152035863739SMike Smith static int
152135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
152235863739SMike Smith {
152335863739SMike Smith     debug_called(3);
152435863739SMike Smith 
152535863739SMike Smith     return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
152635863739SMike Smith }
152735863739SMike Smith 
152835863739SMike Smith static int
152935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
153035863739SMike Smith {
153135863739SMike Smith     debug_called(3);
153235863739SMike Smith 
153335863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
153435863739SMike Smith }
153535863739SMike Smith 
1536c6eafcf2SScott Long /******************************************************************************
153735863739SMike Smith  * Notify the controller of a change in a given queue
153835863739SMike Smith  */
153935863739SMike Smith 
154035863739SMike Smith static void
154135863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
154235863739SMike Smith {
154335863739SMike Smith     debug_called(3);
154435863739SMike Smith 
154535863739SMike Smith     AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
154635863739SMike Smith }
154735863739SMike Smith 
154835863739SMike Smith static void
154935863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
155035863739SMike Smith {
155135863739SMike Smith     debug_called(3);
155235863739SMike Smith 
155335863739SMike Smith     AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
155435863739SMike Smith }
155535863739SMike Smith 
1556c6eafcf2SScott Long /******************************************************************************
155735863739SMike Smith  * Get the interrupt reason bits
155835863739SMike Smith  */
155935863739SMike Smith static int
156035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
156135863739SMike Smith {
156235863739SMike Smith     debug_called(3);
156335863739SMike Smith 
156435863739SMike Smith     return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
156535863739SMike Smith }
156635863739SMike Smith 
156735863739SMike Smith static int
156835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
156935863739SMike Smith {
157035863739SMike Smith     debug_called(3);
157135863739SMike Smith 
157235863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_ODBR));
157335863739SMike Smith }
157435863739SMike Smith 
1575c6eafcf2SScott Long /******************************************************************************
157635863739SMike Smith  * Clear some interrupt reason bits
157735863739SMike Smith  */
157835863739SMike Smith static void
157935863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
158035863739SMike Smith {
158135863739SMike Smith     debug_called(3);
158235863739SMike Smith 
158335863739SMike Smith     AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
158435863739SMike Smith }
158535863739SMike Smith 
158635863739SMike Smith static void
158735863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
158835863739SMike Smith {
158935863739SMike Smith     debug_called(3);
159035863739SMike Smith 
159135863739SMike Smith     AAC_SETREG4(sc, AAC_RX_ODBR, mask);
159235863739SMike Smith }
159335863739SMike Smith 
1594c6eafcf2SScott Long /******************************************************************************
159535863739SMike Smith  * Populate the mailbox and set the command word
159635863739SMike Smith  */
159735863739SMike Smith static void
159835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
159935863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
160035863739SMike Smith {
160135863739SMike Smith     debug_called(4);
160235863739SMike Smith 
160335863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
160435863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
160535863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
160635863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
160735863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
160835863739SMike Smith }
160935863739SMike Smith 
161035863739SMike Smith static void
161135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
161235863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
161335863739SMike Smith {
161435863739SMike Smith     debug_called(4);
161535863739SMike Smith 
161635863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
161735863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
161835863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
161935863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
162035863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
162135863739SMike Smith }
162235863739SMike Smith 
1623c6eafcf2SScott Long /******************************************************************************
162435863739SMike Smith  * Fetch the immediate command status word
162535863739SMike Smith  */
162635863739SMike Smith static int
162735863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc)
162835863739SMike Smith {
162935863739SMike Smith     debug_called(4);
163035863739SMike Smith 
163135863739SMike Smith     return(AAC_GETREG4(sc, AAC_SA_MAILBOX));
163235863739SMike Smith }
163335863739SMike Smith 
163435863739SMike Smith static int
163535863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc)
163635863739SMike Smith {
163735863739SMike Smith     debug_called(4);
163835863739SMike Smith 
163935863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
164035863739SMike Smith }
164135863739SMike Smith 
1642c6eafcf2SScott Long /******************************************************************************
164335863739SMike Smith  * Set/clear interrupt masks
164435863739SMike Smith  */
164535863739SMike Smith static void
164635863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
164735863739SMike Smith {
164835863739SMike Smith     debug(2, "%sable interrupts", enable ? "en" : "dis");
164935863739SMike Smith 
165035863739SMike Smith     if (enable) {
165135863739SMike Smith 	AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
165235863739SMike Smith     } else {
165335863739SMike Smith 	AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
165435863739SMike Smith     }
165535863739SMike Smith }
165635863739SMike Smith 
165735863739SMike Smith static void
165835863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
165935863739SMike Smith {
166035863739SMike Smith     debug(2, "%sable interrupts", enable ? "en" : "dis");
166135863739SMike Smith 
166235863739SMike Smith     if (enable) {
166335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
166435863739SMike Smith     } else {
166535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
166635863739SMike Smith     }
166735863739SMike Smith }
166835863739SMike Smith 
1669c6eafcf2SScott Long /******************************************************************************
1670c6eafcf2SScott Long  ******************************************************************************
167135863739SMike Smith 			Debugging and Diagnostics
1672c6eafcf2SScott Long  ******************************************************************************
1673c6eafcf2SScott Long  ******************************************************************************/
167435863739SMike Smith 
1675c6eafcf2SScott Long /******************************************************************************
167635863739SMike Smith  * Print some information about the controller.
167735863739SMike Smith  */
167835863739SMike Smith static void
167935863739SMike Smith aac_describe_controller(struct aac_softc *sc)
168035863739SMike Smith {
1681c6eafcf2SScott Long     u_int8_t			buf[AAC_FIB_DATASIZE];	/* XXX really a bit big
1682c6eafcf2SScott Long 							 * for the stack */
168335863739SMike Smith     u_int16_t			bufsize;
168435863739SMike Smith     struct aac_adapter_info	*info;
168535863739SMike Smith     u_int8_t			arg;
168635863739SMike Smith 
168735863739SMike Smith     debug_called(2);
168835863739SMike Smith 
168935863739SMike Smith     arg = 0;
1690f6c4dd3fSScott Long     bufsize = sizeof(buf);
1691c6eafcf2SScott Long     if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf,
1692c6eafcf2SScott Long 		     &bufsize)) {
169335863739SMike Smith 	device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
169435863739SMike Smith 	return;
169535863739SMike Smith     }
169635863739SMike Smith     if (bufsize != sizeof(*info)) {
1697c6eafcf2SScott Long 	device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data "
1698c6eafcf2SScott Long 		      "size (%d != %d)\n", bufsize, sizeof(*info));
16990b94a66eSMike Smith 	/*return;*/
170035863739SMike Smith     }
170135863739SMike Smith     info = (struct aac_adapter_info *)&buf[0];
170235863739SMike Smith 
170335863739SMike Smith     device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n",
1704c6eafcf2SScott Long 		  aac_describe_code(aac_cpu_variant, info->CpuVariant),
1705c6eafcf2SScott Long 		  info->ClockSpeed, info->TotalMem / (1024 * 1024),
1706c6eafcf2SScott Long 		  aac_describe_code(aac_battery_platform,
1707c6eafcf2SScott Long 		  info->batteryPlatform), info->batteryPlatform);
170835863739SMike Smith 
170935863739SMike Smith     /* save the kernel revision structure for later use */
171035863739SMike Smith     sc->aac_revision = info->KernelRevision;
171135863739SMike Smith     device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n",
171235863739SMike Smith 		  info->KernelRevision.external.comp.major,
171335863739SMike Smith 		  info->KernelRevision.external.comp.minor,
171435863739SMike Smith 		  info->KernelRevision.external.comp.dash,
1715c6eafcf2SScott Long 		  info->SerialNumber);	/* XXX format? */
171635863739SMike Smith }
171735863739SMike Smith 
1718c6eafcf2SScott Long /******************************************************************************
171935863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
172035863739SMike Smith  * same.
172135863739SMike Smith  */
172235863739SMike Smith static char *
172335863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
172435863739SMike Smith {
172535863739SMike Smith     int		i;
172635863739SMike Smith 
172735863739SMike Smith     for (i = 0; table[i].string != NULL; i++)
172835863739SMike Smith 	if (table[i].code == code)
172935863739SMike Smith 	    return(table[i].string);
173035863739SMike Smith     return(table[i + 1].string);
173135863739SMike Smith }
173235863739SMike Smith 
173335863739SMike Smith /*****************************************************************************
173435863739SMike Smith  *****************************************************************************
173535863739SMike Smith 				Management Interface
173635863739SMike Smith  *****************************************************************************
173735863739SMike Smith  *****************************************************************************/
173835863739SMike Smith 
173935863739SMike Smith static int
174035863739SMike Smith aac_open(dev_t dev, int flags, int fmt, struct proc *p)
174135863739SMike Smith {
174235863739SMike Smith     struct aac_softc	*sc = dev->si_drv1;
174335863739SMike Smith 
174435863739SMike Smith     debug_called(2);
174535863739SMike Smith 
174635863739SMike Smith     /* Check to make sure the device isn't already open */
174735863739SMike Smith     if (sc->aac_state & AAC_STATE_OPEN) {
174835863739SMike Smith         return EBUSY;
174935863739SMike Smith     }
175035863739SMike Smith     sc->aac_state |= AAC_STATE_OPEN;
175135863739SMike Smith 
175235863739SMike Smith     return 0;
175335863739SMike Smith }
175435863739SMike Smith 
175535863739SMike Smith static int
175635863739SMike Smith aac_close(dev_t dev, int flags, int fmt, struct proc *p)
175735863739SMike Smith {
175835863739SMike Smith     struct aac_softc	*sc = dev->si_drv1;
175935863739SMike Smith 
176035863739SMike Smith     debug_called(2);
176135863739SMike Smith 
176235863739SMike Smith     /* Mark this unit as no longer open  */
176335863739SMike Smith     sc->aac_state &= ~AAC_STATE_OPEN;
176435863739SMike Smith 
176535863739SMike Smith     return 0;
176635863739SMike Smith }
176735863739SMike Smith 
176835863739SMike Smith static int
176935863739SMike Smith aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
177035863739SMike Smith {
17710b94a66eSMike Smith     union aac_statrequest	*as = (union aac_statrequest *)arg;
177235863739SMike Smith     struct aac_softc		*sc = dev->si_drv1;
17730b94a66eSMike Smith     int				error = 0;
17740b94a66eSMike Smith #ifdef AAC_COMPAT_LINUX
17750b94a66eSMike Smith     int				i;
17760b94a66eSMike Smith #endif
177735863739SMike Smith 
177835863739SMike Smith     debug_called(2);
177935863739SMike Smith 
178035863739SMike Smith     switch (cmd) {
17810b94a66eSMike Smith     case AACIO_STATS:
17820b94a66eSMike Smith 	switch (as->as_item) {
17830b94a66eSMike Smith 	case AACQ_FREE:
17840b94a66eSMike Smith 	case AACQ_BIO:
17850b94a66eSMike Smith 	case AACQ_READY:
17860b94a66eSMike Smith 	case AACQ_BUSY:
17870b94a66eSMike Smith 	case AACQ_COMPLETE:
1788c6eafcf2SScott Long 	    bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
1789c6eafcf2SScott Long 		  sizeof(struct aac_qstat));
17900b94a66eSMike Smith 	    break;
17910b94a66eSMike Smith 	default:
17920b94a66eSMike Smith 	    error = ENOENT;
17930b94a66eSMike Smith 	    break;
17940b94a66eSMike Smith 	}
17950b94a66eSMike Smith 	break;
17960b94a66eSMike Smith 
179735863739SMike Smith #ifdef AAC_COMPAT_LINUX
179835863739SMike Smith     case FSACTL_SENDFIB:
17990b94a66eSMike Smith 	debug(1, "FSACTL_SENDFIB");
180035863739SMike Smith 	error = aac_ioctl_sendfib(sc, arg);
180135863739SMike Smith 	break;
180235863739SMike Smith     case FSACTL_AIF_THREAD:
18030b94a66eSMike Smith 	debug(1, "FSACTL_AIF_THREAD");
180435863739SMike Smith 	error = EINVAL;
180535863739SMike Smith 	break;
180635863739SMike Smith     case FSACTL_OPEN_GET_ADAPTER_FIB:
18070b94a66eSMike Smith 	debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
180835863739SMike Smith 	/*
180935863739SMike Smith 	 * Pass the caller out an AdapterFibContext.
181035863739SMike Smith 	 *
181135863739SMike Smith 	 * Note that because we only support one opener, we
181235863739SMike Smith 	 * basically ignore this.  Set the caller's context to a magic
181335863739SMike Smith 	 * number just in case.
18140b94a66eSMike Smith 	 *
18150b94a66eSMike Smith 	 * The Linux code hands the driver a pointer into kernel space,
18160b94a66eSMike Smith 	 * and then trusts it when the caller hands it back.  Aiee!
181735863739SMike Smith 	 */
181835863739SMike Smith 	i = AAC_AIF_SILLYMAGIC;
181935863739SMike Smith 	error = copyout(&i, arg, sizeof(i));
182035863739SMike Smith 	break;
182135863739SMike Smith     case FSACTL_GET_NEXT_ADAPTER_FIB:
18220b94a66eSMike Smith 	debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
182335863739SMike Smith 	error = aac_linux_getnext_aif(sc, arg);
182435863739SMike Smith 	break;
182535863739SMike Smith     case FSACTL_CLOSE_GET_ADAPTER_FIB:
18260b94a66eSMike Smith 	debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
182735863739SMike Smith 	/* don't do anything here */
182835863739SMike Smith 	break;
182935863739SMike Smith     case FSACTL_MINIPORT_REV_CHECK:
18300b94a66eSMike Smith 	debug(1, "FSACTL_MINIPORT_REV_CHECK");
183135863739SMike Smith 	error = aac_linux_rev_check(sc, arg);
183235863739SMike Smith 	break;
183335863739SMike Smith #endif
183435863739SMike Smith     default:
183535863739SMike Smith 	device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd);
183635863739SMike Smith 	error = EINVAL;
183735863739SMike Smith 	break;
183835863739SMike Smith     }
183935863739SMike Smith     return(error);
184035863739SMike Smith }
184135863739SMike Smith 
1842c6eafcf2SScott Long /******************************************************************************
184335863739SMike Smith  * Send a FIB supplied from userspace
184435863739SMike Smith  */
184535863739SMike Smith static int
184635863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
184735863739SMike Smith {
184835863739SMike Smith     struct aac_command 	*cm;
184935863739SMike Smith     int			size, error;
185035863739SMike Smith 
185135863739SMike Smith     debug_called(2);
185235863739SMike Smith 
185335863739SMike Smith     cm = NULL;
185435863739SMike Smith 
185535863739SMike Smith     /*
185635863739SMike Smith      * Get a command
185735863739SMike Smith      */
185835863739SMike Smith     if (aac_alloc_command(sc, &cm)) {
185935863739SMike Smith 	error = EBUSY;
186035863739SMike Smith 	goto out;
186135863739SMike Smith     }
186235863739SMike Smith 
186335863739SMike Smith     /*
186435863739SMike Smith      * Fetch the FIB header, then re-copy to get data as well.
186535863739SMike Smith      */
186635863739SMike Smith     if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0)
186735863739SMike Smith 	goto out;
186835863739SMike Smith     size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
186935863739SMike Smith     if (size > sizeof(struct aac_fib)) {
1870c6eafcf2SScott Long 	device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size,
1871c6eafcf2SScott Long 		      sizeof(struct aac_fib));
187235863739SMike Smith 	size = sizeof(struct aac_fib);
187335863739SMike Smith     }
187435863739SMike Smith     if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
187535863739SMike Smith 	goto out;
187635863739SMike Smith     cm->cm_fib->Header.Size = size;
1877f6c4dd3fSScott Long     cm->cm_timestamp = time_second;
187835863739SMike Smith 
187935863739SMike Smith     /*
188035863739SMike Smith      * Pass the FIB to the controller, wait for it to complete.
188135863739SMike Smith      */
188235863739SMike Smith     if ((error = aac_wait_command(cm, 30)) != 0)	/* XXX user timeout? */
188335863739SMike Smith 	goto out;
188435863739SMike Smith 
188535863739SMike Smith     /*
188635863739SMike Smith      * Copy the FIB and data back out to the caller.
188735863739SMike Smith      */
188835863739SMike Smith     size = cm->cm_fib->Header.Size;
188935863739SMike Smith     if (size > sizeof(struct aac_fib)) {
1890c6eafcf2SScott Long 	device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size,
1891c6eafcf2SScott Long 		      sizeof(struct aac_fib));
189235863739SMike Smith 	size = sizeof(struct aac_fib);
189335863739SMike Smith     }
189435863739SMike Smith     error = copyout(cm->cm_fib, ufib, size);
189535863739SMike Smith 
189635863739SMike Smith out:
1897f6c4dd3fSScott Long     if (cm != NULL) {
189835863739SMike Smith 	aac_release_command(cm);
1899f6c4dd3fSScott Long     }
190035863739SMike Smith     return(error);
190135863739SMike Smith }
190235863739SMike Smith 
1903c6eafcf2SScott Long /******************************************************************************
190435863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
190535863739SMike Smith  *
190635863739SMike Smith  * XXX what's the right thing to do here when the queue is full?  Drop the older
190735863739SMike Smith  * or newer entries?
190835863739SMike Smith  */
190935863739SMike Smith static void
191035863739SMike Smith aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif)
191135863739SMike Smith {
191235863739SMike Smith     int		next, s;
191335863739SMike Smith 
191435863739SMike Smith     debug_called(2);
191535863739SMike Smith 
191635863739SMike Smith     s = splbio();
191735863739SMike Smith     next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
191835863739SMike Smith     if (next != sc->aac_aifq_tail) {
191935863739SMike Smith 	bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
192035863739SMike Smith 	sc->aac_aifq_head = next;
192135863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
192235863739SMike Smith 	    wakeup(sc->aac_aifq);
192335863739SMike Smith     }
192435863739SMike Smith     splx(s);
192535863739SMike Smith     aac_print_aif(sc, aif);
192635863739SMike Smith }
192735863739SMike Smith 
1928c6eafcf2SScott Long /******************************************************************************
1929c6eafcf2SScott Long  ******************************************************************************
193035863739SMike Smith 			Linux Management Interface
1931c6eafcf2SScott Long  ******************************************************************************
1932c6eafcf2SScott Long  ******************************************************************************/
193335863739SMike Smith 
193435863739SMike Smith #ifdef AAC_COMPAT_LINUX
193535863739SMike Smith 
193630d57611SMike Smith #include <sys/proc.h>
193735863739SMike Smith #include <machine/../linux/linux.h>
193835863739SMike Smith #include <machine/../linux/linux_proto.h>
193935863739SMike Smith #include <compat/linux/linux_ioctl.h>
194035863739SMike Smith 
194135863739SMike Smith #define AAC_LINUX_IOCTL_MIN  0x2000
194235863739SMike Smith #define AAC_LINUX_IOCTL_MAX  0x21ff
194335863739SMike Smith 
194435863739SMike Smith static linux_ioctl_function_t aac_linux_ioctl;
1945c6eafcf2SScott Long static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl,
1946c6eafcf2SScott Long 						AAC_LINUX_IOCTL_MIN,
1947c6eafcf2SScott Long 						AAC_LINUX_IOCTL_MAX};
194835863739SMike Smith 
1949c6eafcf2SScott Long SYSINIT  (aac_register,   SI_SUB_KLD, SI_ORDER_MIDDLE,
1950c6eafcf2SScott Long 	  linux_ioctl_register_handler, &aac_handler);
1951c6eafcf2SScott Long SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
1952c6eafcf2SScott Long 	  linux_ioctl_unregister_handler, &aac_handler);
195335863739SMike Smith 
195435863739SMike Smith MODULE_DEPEND(aac, linux, 1, 1, 1);
195535863739SMike Smith 
195635863739SMike Smith static int
195735863739SMike Smith aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
195835863739SMike Smith {
195935863739SMike Smith     struct file		*fp = p->p_fd->fd_ofiles[args->fd];
196035863739SMike Smith     u_long		cmd = args->cmd;
196135863739SMike Smith 
196235863739SMike Smith     /*
196335863739SMike Smith      * Pass the ioctl off to our standard handler.
196435863739SMike Smith      */
196535863739SMike Smith     return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p));
196635863739SMike Smith }
196735863739SMike Smith 
1968c6eafcf2SScott Long /******************************************************************************
19690b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
197035863739SMike Smith  * userspace app is possibly compatible.  This is extremely bogus right now
197135863739SMike Smith  * because I have no idea how to handle the versioning of this driver.  It is
197235863739SMike Smith  * needed, though, to get aaccli working.
197335863739SMike Smith  */
197435863739SMike Smith static int
197535863739SMike Smith aac_linux_rev_check(struct aac_softc *sc, caddr_t udata)
197635863739SMike Smith {
197735863739SMike Smith     struct aac_rev_check	rev_check;
197835863739SMike Smith     struct aac_rev_check_resp	rev_check_resp;
197935863739SMike Smith     int				error = 0;
198035863739SMike Smith 
198135863739SMike Smith     debug_called(2);
198235863739SMike Smith 
198335863739SMike Smith     /*
198435863739SMike Smith      * Copyin the revision struct from userspace
198535863739SMike Smith      */
1986c6eafcf2SScott Long     if ((error = copyin(udata, (caddr_t)&rev_check,
1987c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
198835863739SMike Smith 	return error;
198935863739SMike Smith     }
199035863739SMike Smith 
199135863739SMike Smith     debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber);
199235863739SMike Smith 
199335863739SMike Smith     /*
199435863739SMike Smith      * Doctor up the response struct.
199535863739SMike Smith      */
199635863739SMike Smith     rev_check_resp.possiblyCompatible = 1;
199735863739SMike Smith     rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul;
199835863739SMike Smith     rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber;
199935863739SMike Smith 
2000c6eafcf2SScott Long     return(copyout((caddr_t)&rev_check_resp, udata,
2001c6eafcf2SScott Long 		   sizeof(struct aac_rev_check_resp)));
200235863739SMike Smith }
200335863739SMike Smith 
2004c6eafcf2SScott Long /******************************************************************************
200535863739SMike Smith  * Pass the caller the next AIF in their queue
200635863739SMike Smith  */
200735863739SMike Smith static int
200835863739SMike Smith aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg)
200935863739SMike Smith {
201035863739SMike Smith     struct get_adapter_fib_ioctl	agf;
201135863739SMike Smith     int					error, s;
201235863739SMike Smith 
201335863739SMike Smith     debug_called(2);
201435863739SMike Smith 
201535863739SMike Smith     if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
201635863739SMike Smith 
201735863739SMike Smith 	/*
201835863739SMike Smith 	 * Check the magic number that we gave the caller.
201935863739SMike Smith 	 */
202035863739SMike Smith 	if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) {
202135863739SMike Smith 	    error = EFAULT;
202235863739SMike Smith 	} else {
202335863739SMike Smith 
202435863739SMike Smith 	    s = splbio();
20250b94a66eSMike Smith 	    error = aac_linux_return_aif(sc, agf.AifFib);
202635863739SMike Smith 
202735863739SMike Smith 	    if ((error == EAGAIN) && (agf.Wait)) {
202835863739SMike Smith 		sc->aac_state |= AAC_STATE_AIF_SLEEPER;
202935863739SMike Smith 		while (error == EAGAIN) {
203035863739SMike Smith 		    error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0);
203135863739SMike Smith 		    if (error == 0)
20320b94a66eSMike Smith 			error = aac_linux_return_aif(sc, agf.AifFib);
203335863739SMike Smith 		}
203435863739SMike Smith 		sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
203535863739SMike Smith 	    }
203635863739SMike Smith 	    splx(s);
203735863739SMike Smith 	}
203835863739SMike Smith     }
203935863739SMike Smith     return(error);
204035863739SMike Smith }
204135863739SMike Smith 
2042c6eafcf2SScott Long /******************************************************************************
20430b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
20440b94a66eSMike Smith  */
20450b94a66eSMike Smith static int
20460b94a66eSMike Smith aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr)
20470b94a66eSMike Smith {
20480b94a66eSMike Smith     int		error, s;
20490b94a66eSMike Smith 
20500b94a66eSMike Smith     debug_called(2);
20510b94a66eSMike Smith 
20520b94a66eSMike Smith     s = splbio();
20530b94a66eSMike Smith     if (sc->aac_aifq_tail == sc->aac_aifq_head) {
20540b94a66eSMike Smith 	error = EAGAIN;
20550b94a66eSMike Smith     } else {
2056c6eafcf2SScott Long 	error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
2057c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
20580b94a66eSMike Smith 	if (!error)
20590b94a66eSMike Smith 	    sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
20600b94a66eSMike Smith     }
20610b94a66eSMike Smith     splx(s);
20620b94a66eSMike Smith     return(error);
20630b94a66eSMike Smith }
20640b94a66eSMike Smith 
20650b94a66eSMike Smith 
206635863739SMike Smith #endif /* AAC_COMPAT_LINUX */
2067