xref: /freebsd/sys/dev/aac/aac.c (revision c6eafcf2c5aa739b9f1ec6fe01caf82dbb6cf90f)
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 
3635863739SMike Smith #include <sys/param.h>
3735863739SMike Smith #include <sys/systm.h>
3835863739SMike Smith #include <sys/malloc.h>
3935863739SMike Smith #include <sys/kernel.h>
4035863739SMike Smith 
4135863739SMike Smith #include <dev/aac/aac_compat.h>
4235863739SMike Smith 
4335863739SMike Smith #include <sys/bus.h>
4435863739SMike Smith #include <sys/conf.h>
4535863739SMike Smith #include <sys/devicestat.h>
4635863739SMike Smith #include <sys/disk.h>
4735863739SMike Smith #include <sys/file.h>
4835863739SMike Smith #include <sys/signalvar.h>
490b94a66eSMike Smith #include <sys/time.h>
5035863739SMike Smith 
5135863739SMike Smith #include <machine/bus_memio.h>
5235863739SMike Smith #include <machine/bus.h>
5335863739SMike Smith #include <machine/resource.h>
5435863739SMike Smith 
5535863739SMike Smith #include <dev/aac/aacreg.h>
560b94a66eSMike Smith #include <dev/aac/aac_ioctl.h>
5735863739SMike Smith #include <dev/aac/aacvar.h>
5835863739SMike Smith #include <dev/aac/aac_tables.h>
5935863739SMike Smith 
6035863739SMike Smith devclass_t	aac_devclass;
6135863739SMike Smith 
6235863739SMike Smith static void	aac_startup(void *arg);
6335863739SMike Smith 
6435863739SMike Smith /* Command Processing */
6535863739SMike Smith static void	aac_startio(struct aac_softc *sc);
660b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
6735863739SMike Smith static int	aac_start(struct aac_command *cm);
6835863739SMike Smith static void	aac_complete(void *context, int pending);
6935863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7035863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
7135863739SMike Smith static int	aac_wait_command(struct aac_command *cm, int timeout);
7235863739SMike Smith static void	aac_host_command(struct aac_softc *sc);
7335863739SMike Smith static void	aac_host_response(struct aac_softc *sc);
7435863739SMike Smith 
7535863739SMike Smith /* Command Buffer Management */
7635863739SMike Smith static int	aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp);
7735863739SMike Smith static void	aac_release_command(struct aac_command *cm);
78c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
79c6eafcf2SScott Long 				       int nseg, int error);
800b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
810b94a66eSMike Smith static void	aac_free_commands(struct aac_softc *sc);
8235863739SMike Smith static void	aac_map_command(struct aac_command *cm);
8335863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
8435863739SMike Smith 
8535863739SMike Smith /* Hardware Interface */
86c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
87c6eafcf2SScott Long 			       int error);
8835863739SMike Smith static int	aac_init(struct aac_softc *sc);
8935863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
90c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
91c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
92c6eafcf2SScott Long static int	aac_sync_fib(struct aac_softc *sc, u_int32_t command,
93c6eafcf2SScott Long 			     u_int32_t xferstate, void *data,
94c6eafcf2SScott Long 			     u_int16_t datasize, void *result,
95c6eafcf2SScott Long 			     u_int16_t *resultsize);
96c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
97c6eafcf2SScott Long 				u_int32_t fib_size, u_int32_t fib_addr);
98c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
99c6eafcf2SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10035863739SMike Smith 
10135863739SMike Smith /* StrongARM interface */
10235863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
10335863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
10435863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
10535863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
10635863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
107c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
108c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
10935863739SMike Smith static int	aac_sa_get_mailboxstatus(struct aac_softc *sc);
11035863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
11135863739SMike Smith 
11235863739SMike Smith struct aac_interface aac_sa_interface = {
11335863739SMike Smith     aac_sa_get_fwstatus,
11435863739SMike Smith     aac_sa_qnotify,
11535863739SMike Smith     aac_sa_get_istatus,
11635863739SMike Smith     aac_sa_clear_istatus,
11735863739SMike Smith     aac_sa_set_mailbox,
11835863739SMike Smith     aac_sa_get_mailboxstatus,
11935863739SMike Smith     aac_sa_set_interrupts
12035863739SMike Smith };
12135863739SMike Smith 
12235863739SMike Smith /* i960Rx interface */
12335863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
12435863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
12535863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
12635863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
12735863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
128c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
129c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
13035863739SMike Smith static int	aac_rx_get_mailboxstatus(struct aac_softc *sc);
13135863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
13235863739SMike Smith 
13335863739SMike Smith struct aac_interface aac_rx_interface = {
13435863739SMike Smith     aac_rx_get_fwstatus,
13535863739SMike Smith     aac_rx_qnotify,
13635863739SMike Smith     aac_rx_get_istatus,
13735863739SMike Smith     aac_rx_clear_istatus,
13835863739SMike Smith     aac_rx_set_mailbox,
13935863739SMike Smith     aac_rx_get_mailboxstatus,
14035863739SMike Smith     aac_rx_set_interrupts
14135863739SMike Smith };
14235863739SMike Smith 
14335863739SMike Smith /* Debugging and Diagnostics */
14435863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
145c6eafcf2SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
146c6eafcf2SScott Long 				   u_int32_t code);
14735863739SMike Smith 
14835863739SMike Smith /* Management Interface */
14935863739SMike Smith static d_open_t		aac_open;
15035863739SMike Smith static d_close_t	aac_close;
15135863739SMike Smith static d_ioctl_t	aac_ioctl;
152c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
153c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
154c6eafcf2SScott Long 				       struct aac_aif_command *aif);
15535863739SMike Smith #ifdef AAC_COMPAT_LINUX
156c6eafcf2SScott Long static int		aac_linux_rev_check(struct aac_softc *sc,
157c6eafcf2SScott Long 					    caddr_t udata);
158c6eafcf2SScott Long static int		aac_linux_getnext_aif(struct aac_softc *sc,
159c6eafcf2SScott Long 					    caddr_t arg);
160c6eafcf2SScott Long static int		aac_linux_return_aif(struct aac_softc *sc,
161c6eafcf2SScott Long 					    caddr_t uptr);
16235863739SMike Smith #endif
16335863739SMike Smith 
16435863739SMike Smith #define AAC_CDEV_MAJOR	150
16535863739SMike Smith 
16635863739SMike Smith static struct cdevsw aac_cdevsw = {
16735863739SMike Smith     aac_open,		/* open */
16835863739SMike Smith     aac_close,		/* close */
16935863739SMike Smith     noread,		/* read */
17035863739SMike Smith     nowrite,		/* write */
17135863739SMike Smith     aac_ioctl,		/* ioctl */
17235863739SMike Smith     nopoll,		/* poll */
17335863739SMike Smith     nommap,		/* mmap */
17435863739SMike Smith     nostrategy,		/* strategy */
17535863739SMike Smith     "aac",		/* name */
17635863739SMike Smith     AAC_CDEV_MAJOR,	/* major */
17735863739SMike Smith     nodump,		/* dump */
17835863739SMike Smith     nopsize,		/* psize */
17935863739SMike Smith     0,			/* flags */
18035863739SMike Smith };
18135863739SMike Smith 
182c6eafcf2SScott Long /******************************************************************************
183c6eafcf2SScott Long  ******************************************************************************
18435863739SMike Smith 				Device Interface
185c6eafcf2SScott Long  ******************************************************************************
186c6eafcf2SScott Long  ******************************************************************************/
18735863739SMike Smith 
188c6eafcf2SScott Long /******************************************************************************
18935863739SMike Smith  * Initialise the controller and softc
19035863739SMike Smith  */
19135863739SMike Smith int
19235863739SMike Smith aac_attach(struct aac_softc *sc)
19335863739SMike Smith {
19435863739SMike Smith     int		error, unit;
19535863739SMike Smith 
19635863739SMike Smith     debug_called(1);
19735863739SMike Smith 
19835863739SMike Smith     /*
19935863739SMike Smith      * Initialise per-controller queues.
20035863739SMike Smith      */
2010b94a66eSMike Smith     aac_initq_free(sc);
2020b94a66eSMike Smith     aac_initq_ready(sc);
2030b94a66eSMike Smith     aac_initq_busy(sc);
2040b94a66eSMike Smith     aac_initq_complete(sc);
2050b94a66eSMike Smith     aac_initq_bio(sc);
20635863739SMike Smith 
20735863739SMike Smith #if __FreeBSD_version >= 500005
20835863739SMike Smith     /*
20935863739SMike Smith      * Initialise command-completion task.
21035863739SMike Smith      */
21135863739SMike Smith     TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
21235863739SMike Smith #endif
21335863739SMike Smith 
21435863739SMike Smith     /* disable interrupts before we enable anything */
21535863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
21635863739SMike Smith 
21735863739SMike Smith     /* mark controller as suspended until we get ourselves organised */
21835863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
21935863739SMike Smith 
22035863739SMike Smith     /*
2210b94a66eSMike Smith      * Allocate command structures.
2220b94a66eSMike Smith      */
2230b94a66eSMike Smith     if ((error = aac_alloc_commands(sc)) != 0)
2240b94a66eSMike Smith 	return(error);
2250b94a66eSMike Smith 
2260b94a66eSMike Smith     /*
22735863739SMike Smith      * Initialise the adapter.
22835863739SMike Smith      */
2290b94a66eSMike Smith     if ((error = aac_init(sc)) != 0)
23035863739SMike Smith 	return(error);
23135863739SMike Smith 
23235863739SMike Smith     /*
23335863739SMike Smith      * Print a little information about the controller.
23435863739SMike Smith      */
23535863739SMike Smith     aac_describe_controller(sc);
23635863739SMike Smith 
23735863739SMike Smith     /*
23835863739SMike Smith      * Register to probe our containers later.
23935863739SMike Smith      */
24035863739SMike Smith     sc->aac_ich.ich_func = aac_startup;
24135863739SMike Smith     sc->aac_ich.ich_arg = sc;
24235863739SMike Smith     if (config_intrhook_establish(&sc->aac_ich) != 0) {
24335863739SMike Smith         device_printf(sc->aac_dev, "can't establish configuration hook\n");
24435863739SMike Smith         return(ENXIO);
24535863739SMike Smith     }
24635863739SMike Smith 
24735863739SMike Smith     /*
24835863739SMike Smith      * Make the control device.
24935863739SMike Smith      */
25035863739SMike Smith     unit = device_get_unit(sc->aac_dev);
251c6eafcf2SScott Long     sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644,
252c6eafcf2SScott Long 			     "aac%d", unit);
253157fbb2eSScott Long     (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
2544aa620cdSScott Long     (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
255157fbb2eSScott Long 
25635863739SMike Smith     sc->aac_dev_t->si_drv1 = sc;
25735863739SMike Smith 
25835863739SMike Smith     return(0);
25935863739SMike Smith }
26035863739SMike Smith 
261c6eafcf2SScott Long /******************************************************************************
26235863739SMike Smith  * Probe for containers, create disks.
26335863739SMike Smith  */
26435863739SMike Smith static void
26535863739SMike Smith aac_startup(void *arg)
26635863739SMike Smith {
26735863739SMike Smith     struct aac_softc		*sc = (struct aac_softc *)arg;
26835863739SMike Smith     struct aac_mntinfo		mi;
26935863739SMike Smith     struct aac_mntinforesponse	mir;
27035863739SMike Smith     device_t			child;
27135863739SMike Smith     u_int16_t			rsize;
27235863739SMike Smith     int				i;
27335863739SMike Smith 
27435863739SMike Smith     debug_called(1);
27535863739SMike Smith 
27635863739SMike Smith     /* disconnect ourselves from the intrhook chain */
27735863739SMike Smith     config_intrhook_disestablish(&sc->aac_ich);
27835863739SMike Smith 
27935863739SMike Smith     /* loop over possible containers */
28035863739SMike Smith     mi.Command = VM_NameServe;
28135863739SMike Smith     mi.MntType = FT_FILESYS;
28235863739SMike Smith     for (i = 0; i < AAC_MAX_CONTAINERS; i++) {
28335863739SMike Smith 	/* request information on this container */
28435863739SMike Smith 	mi.MntCount = i;
285c6eafcf2SScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
286c6eafcf2SScott Long 			 sizeof(struct aac_mntinfo), &mir, &rsize)) {
28735863739SMike Smith 	    debug(2, "error probing container %d", i);
28835863739SMike Smith 	    continue;
28935863739SMike Smith 	}
29035863739SMike Smith 	/* check response size */
29135863739SMike Smith 	if (rsize != sizeof(mir)) {
292c6eafcf2SScott Long 	    debug(2, "container info response wrong size (%d should be %d)",
293c6eafcf2SScott Long 		  rsize, sizeof(mir));
29435863739SMike Smith 	    continue;
29535863739SMike Smith 	}
29635863739SMike Smith 	/*
297c6eafcf2SScott Long 	 * Check container volume type for validity.  Note that many of the
298c6eafcf2SScott Long 	 * possible types may never show up.
29935863739SMike Smith 	 */
30035863739SMike Smith 	if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) {
30135863739SMike Smith 	    debug(1, "%d: id %x  name '%.16s'  size %u  type %d",
30235863739SMike Smith 		  i, mir.MntTable[0].ObjectId,
30335863739SMike Smith 		  mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity,
30435863739SMike Smith 		  mir.MntTable[0].VolType);
30535863739SMike Smith 
30635863739SMike Smith 	    if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) {
30735863739SMike Smith 		device_printf(sc->aac_dev, "device_add_child failed\n");
30835863739SMike Smith 	    } else {
30935863739SMike Smith 		device_set_ivars(child, &sc->aac_container[i]);
31035863739SMike Smith 	    }
311c6eafcf2SScott Long 	    device_set_desc(child, aac_describe_code(aac_container_types,
312c6eafcf2SScott Long 			    mir.MntTable[0].VolType));
31335863739SMike Smith 	    sc->aac_container[i].co_disk = child;
31435863739SMike Smith 	    sc->aac_container[i].co_mntobj = mir.MntTable[0];
31535863739SMike Smith 	}
31635863739SMike Smith     }
31735863739SMike Smith 
31835863739SMike Smith     /* poke the bus to actually attach the child devices */
31935863739SMike Smith     if (bus_generic_attach(sc->aac_dev))
32035863739SMike Smith 	device_printf(sc->aac_dev, "bus_generic_attach failed\n");
32135863739SMike Smith 
32235863739SMike Smith     /* mark the controller up */
32335863739SMike Smith     sc->aac_state &= ~AAC_STATE_SUSPEND;
32435863739SMike Smith 
32535863739SMike Smith     /* enable interrupts now */
32635863739SMike Smith     AAC_UNMASK_INTERRUPTS(sc);
3270b94a66eSMike Smith 
3280b94a66eSMike Smith     /* enable the timeout watchdog */
3290b94a66eSMike Smith     timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
33035863739SMike Smith }
33135863739SMike Smith 
332c6eafcf2SScott Long /******************************************************************************
33335863739SMike Smith  * Free all of the resources associated with (sc)
33435863739SMike Smith  *
33535863739SMike Smith  * Should not be called if the controller is active.
33635863739SMike Smith  */
33735863739SMike Smith void
33835863739SMike Smith aac_free(struct aac_softc *sc)
33935863739SMike Smith {
34035863739SMike Smith     debug_called(1);
34135863739SMike Smith 
34235863739SMike Smith     /* remove the control device */
34335863739SMike Smith     if (sc->aac_dev_t != NULL)
34435863739SMike Smith 	destroy_dev(sc->aac_dev_t);
34535863739SMike Smith 
3460b94a66eSMike Smith     /* throw away any FIB buffers, discard the FIB DMA tag */
3470b94a66eSMike Smith     if (sc->aac_fibs != NULL)
3480b94a66eSMike Smith 	aac_free_commands(sc);
3490b94a66eSMike Smith     if (sc->aac_fib_dmat)
3500b94a66eSMike Smith 	bus_dma_tag_destroy(sc->aac_fib_dmat);
35135863739SMike Smith 
35235863739SMike Smith     /* destroy the common area */
35335863739SMike Smith     if (sc->aac_common) {
35435863739SMike Smith 	bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
355c6eafcf2SScott Long 	bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
356c6eafcf2SScott Long 			sc->aac_common_dmamap);
35735863739SMike Smith     }
3580b94a66eSMike Smith     if (sc->aac_common_dmat)
3590b94a66eSMike Smith 	bus_dma_tag_destroy(sc->aac_common_dmat);
36035863739SMike Smith 
36135863739SMike Smith     /* disconnect the interrupt handler */
36235863739SMike Smith     if (sc->aac_intr)
36335863739SMike Smith 	bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
36435863739SMike Smith     if (sc->aac_irq != NULL)
365c6eafcf2SScott Long 	bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
366c6eafcf2SScott Long 			     sc->aac_irq);
36735863739SMike Smith 
36835863739SMike Smith     /* destroy data-transfer DMA tag */
36935863739SMike Smith     if (sc->aac_buffer_dmat)
37035863739SMike Smith 	bus_dma_tag_destroy(sc->aac_buffer_dmat);
37135863739SMike Smith 
37235863739SMike Smith     /* destroy the parent DMA tag */
37335863739SMike Smith     if (sc->aac_parent_dmat)
37435863739SMike Smith 	bus_dma_tag_destroy(sc->aac_parent_dmat);
37535863739SMike Smith 
37635863739SMike Smith     /* release the register window mapping */
37735863739SMike Smith     if (sc->aac_regs_resource != NULL)
378c6eafcf2SScott Long 	bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid,
379c6eafcf2SScott Long 			     sc->aac_regs_resource);
38035863739SMike Smith }
38135863739SMike Smith 
382c6eafcf2SScott Long /******************************************************************************
38335863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
38435863739SMike Smith  */
38535863739SMike Smith int
38635863739SMike Smith aac_detach(device_t dev)
38735863739SMike Smith {
38835863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
38935863739SMike Smith     int			error;
39035863739SMike Smith 
39135863739SMike Smith     debug_called(1);
39235863739SMike Smith 
39335863739SMike Smith     if (sc->aac_state & AAC_STATE_OPEN)
39435863739SMike Smith 	return(EBUSY);
39535863739SMike Smith 
39635863739SMike Smith     if ((error = aac_shutdown(dev)))
39735863739SMike Smith 	return(error);
39835863739SMike Smith 
39935863739SMike Smith     aac_free(sc);
40035863739SMike Smith 
40135863739SMike Smith     return(0);
40235863739SMike Smith }
40335863739SMike Smith 
404c6eafcf2SScott Long /******************************************************************************
40535863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
40635863739SMike Smith  *
40735863739SMike Smith  * This function is called before detach or system shutdown.
40835863739SMike Smith  *
4090b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
41035863739SMike Smith  * allow shutdown if any device is open.
41135863739SMike Smith  */
41235863739SMike Smith int
41335863739SMike Smith aac_shutdown(device_t dev)
41435863739SMike Smith {
41535863739SMike Smith     struct aac_softc		*sc = device_get_softc(dev);
41635863739SMike Smith     struct aac_close_command	cc;
41735863739SMike Smith     int				s, i;
41835863739SMike Smith 
41935863739SMike Smith     debug_called(1);
42035863739SMike Smith 
42135863739SMike Smith     s = splbio();
42235863739SMike Smith 
42335863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
42435863739SMike Smith 
42535863739SMike Smith     /*
42635863739SMike Smith      * Send a Container shutdown followed by a HostShutdown FIB to the
42735863739SMike Smith      * controller to convince it that we don't want to talk to it anymore.
42835863739SMike Smith      * We've been closed and all I/O completed already
42935863739SMike Smith      */
43035863739SMike Smith     device_printf(sc->aac_dev, "shutting down controller...");
43135863739SMike Smith 
43235863739SMike Smith     cc.Command = VM_CloseAll;
43335863739SMike Smith     cc.ContainerId = 0xffffffff;
43435863739SMike Smith     if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) {
43535863739SMike Smith 	printf("FAILED.\n");
43635863739SMike Smith     } else {
43735863739SMike Smith 	i = 0;
438c6eafcf2SScott Long 	if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i,
439c6eafcf2SScott Long 			 sizeof(i), NULL, NULL)) {
44035863739SMike Smith 	    printf("FAILED.\n");
44135863739SMike Smith 	} else {
44235863739SMike Smith 	    printf("done.\n");
44335863739SMike Smith 	}
44435863739SMike Smith     }
44535863739SMike Smith 
44635863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
44735863739SMike Smith 
44835863739SMike Smith     splx(s);
44935863739SMike Smith     return(0);
45035863739SMike Smith }
45135863739SMike Smith 
452c6eafcf2SScott Long /******************************************************************************
45335863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
45435863739SMike Smith  */
45535863739SMike Smith int
45635863739SMike Smith aac_suspend(device_t dev)
45735863739SMike Smith {
45835863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
45935863739SMike Smith     int			s;
46035863739SMike Smith 
46135863739SMike Smith     debug_called(1);
46235863739SMike Smith     s = splbio();
46335863739SMike Smith 
46435863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
46535863739SMike Smith 
46635863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
46735863739SMike Smith     splx(s);
46835863739SMike Smith     return(0);
46935863739SMike Smith }
47035863739SMike Smith 
471c6eafcf2SScott Long /******************************************************************************
47235863739SMike Smith  * Bring the controller back to a state ready for operation.
47335863739SMike Smith  */
47435863739SMike Smith int
47535863739SMike Smith aac_resume(device_t dev)
47635863739SMike Smith {
47735863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
47835863739SMike Smith 
47935863739SMike Smith     debug_called(1);
48035863739SMike Smith     sc->aac_state &= ~AAC_STATE_SUSPEND;
48135863739SMike Smith     AAC_UNMASK_INTERRUPTS(sc);
48235863739SMike Smith     return(0);
48335863739SMike Smith }
48435863739SMike Smith 
485c6eafcf2SScott Long /******************************************************************************
48635863739SMike Smith  * Take an interrupt.
48735863739SMike Smith  */
48835863739SMike Smith void
48935863739SMike Smith aac_intr(void *arg)
49035863739SMike Smith {
49135863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
49235863739SMike Smith     u_int16_t		reason;
49335863739SMike Smith 
49435863739SMike Smith     debug_called(2);
49535863739SMike Smith 
49635863739SMike Smith     reason = AAC_GET_ISTATUS(sc);
49735863739SMike Smith 
49835863739SMike Smith     /* controller wants to talk to the log?  XXX should we defer this? */
49935863739SMike Smith     if (reason & AAC_DB_PRINTF) {
50035863739SMike Smith 	if (sc->aac_common->ac_printf[0]) {
501c6eafcf2SScott Long 	    device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE,
502c6eafcf2SScott Long 			  sc->aac_common->ac_printf);
50335863739SMike Smith 	    sc->aac_common->ac_printf[0] = 0;
50435863739SMike Smith 	}
50535863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
50635863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_PRINTF);
50735863739SMike Smith     }
50835863739SMike Smith 
50935863739SMike Smith     /* controller has a message for us? */
51035863739SMike Smith     if (reason & AAC_DB_COMMAND_READY) {
51135863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
512da4c1ce3SJustin T. Gibbs 	aac_host_command(sc);
51335863739SMike Smith     }
51435863739SMike Smith 
51535863739SMike Smith     /* controller has a response for us? */
51635863739SMike Smith     if (reason & AAC_DB_RESPONSE_READY) {
51735863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
518da4c1ce3SJustin T. Gibbs 	aac_host_response(sc);
51935863739SMike Smith     }
52035863739SMike Smith 
521c6eafcf2SScott Long     /*
522c6eafcf2SScott Long      * spurious interrupts that we don't use - reset the mask and clear the
523c6eafcf2SScott Long      * interrupts
524c6eafcf2SScott Long      */
52535863739SMike Smith     if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
52635863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
527c6eafcf2SScott Long 	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL |
528c6eafcf2SScott Long 			  AAC_DB_RESPONSE_NOT_FULL);
52935863739SMike Smith     }
53035863739SMike Smith };
53135863739SMike Smith 
532c6eafcf2SScott Long /******************************************************************************
533c6eafcf2SScott Long  ******************************************************************************
53435863739SMike Smith 				Command Processing
535c6eafcf2SScott Long  ******************************************************************************
536c6eafcf2SScott Long  ******************************************************************************/
53735863739SMike Smith 
538c6eafcf2SScott Long /******************************************************************************
53935863739SMike Smith  * Start as much queued I/O as possible on the controller
54035863739SMike Smith  */
54135863739SMike Smith static void
54235863739SMike Smith aac_startio(struct aac_softc *sc)
54335863739SMike Smith {
54435863739SMike Smith     struct aac_command	*cm;
54535863739SMike Smith 
54635863739SMike Smith     debug_called(2);
54735863739SMike Smith 
54835863739SMike Smith     for(;;) {
54935863739SMike Smith 	/* try to get a command that's been put off for lack of resources */
55035863739SMike Smith 	cm = aac_dequeue_ready(sc);
55135863739SMike Smith 
55235863739SMike Smith 	/* try to build a command off the bio queue (ignore error return) */
5530b94a66eSMike Smith 	if (cm == NULL)
55435863739SMike Smith 	    aac_bio_command(sc, &cm);
55535863739SMike Smith 
55635863739SMike Smith 	/* nothing to do? */
55735863739SMike Smith 	if (cm == NULL)
55835863739SMike Smith 	    break;
55935863739SMike Smith 
56035863739SMike Smith 	/* try to give the command to the controller */
56135863739SMike Smith 	if (aac_start(cm) == EBUSY) {
56235863739SMike Smith 	    /* put it on the ready queue for later */
56335863739SMike Smith 	    aac_requeue_ready(cm);
56435863739SMike Smith 	    break;
56535863739SMike Smith 	}
56635863739SMike Smith     }
56735863739SMike Smith }
56835863739SMike Smith 
569c6eafcf2SScott Long /******************************************************************************
57035863739SMike Smith  * Deliver a command to the controller; allocate controller resources at the
57135863739SMike Smith  * last moment when possible.
57235863739SMike Smith  */
57335863739SMike Smith static int
57435863739SMike Smith aac_start(struct aac_command *cm)
57535863739SMike Smith {
57635863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
577ed5c5fb4SMike Smith     int			error;
57835863739SMike Smith 
57935863739SMike Smith     debug_called(2);
58035863739SMike Smith 
58135863739SMike Smith     /* get the command mapped */
58235863739SMike Smith     aac_map_command(cm);
58335863739SMike Smith 
5840b94a66eSMike Smith     /* fix up the address values in the FIB */
58535863739SMike Smith     cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
58635863739SMike Smith     cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
58735863739SMike Smith 
58835863739SMike Smith     /* save a pointer to the command for speedy reverse-lookup */
589c6eafcf2SScott Long     cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical
590c6eafcf2SScott Long 							 * address issue */
59135863739SMike Smith 
59235863739SMike Smith     /* put the FIB on the outbound queue */
59335863739SMike Smith     if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm->cm_fib->Header.Size,
5940b94a66eSMike Smith 			cm->cm_fib->Header.ReceiverFibAddress)) {
5950b94a66eSMike Smith 	error = EBUSY;
5960b94a66eSMike Smith     } else {
5970b94a66eSMike Smith 	aac_enqueue_busy(cm);
5980b94a66eSMike Smith 	error = 0;
5990b94a66eSMike Smith     }
6000b94a66eSMike Smith     return(error);
60135863739SMike Smith }
60235863739SMike Smith 
603c6eafcf2SScott Long /******************************************************************************
60435863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
60535863739SMike Smith  */
60635863739SMike Smith static void
60735863739SMike Smith aac_host_command(struct aac_softc *sc)
60835863739SMike Smith {
60935863739SMike Smith     struct aac_fib	*fib;
61035863739SMike Smith     u_int32_t		fib_size;
61135863739SMike Smith 
61235863739SMike Smith     debug_called(1);
61335863739SMike Smith 
61435863739SMike Smith     for (;;) {
61535863739SMike Smith 	if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib))
61635863739SMike Smith 	    break;	/* nothing to do */
61735863739SMike Smith 
61835863739SMike Smith 	switch(fib->Header.Command) {
61935863739SMike Smith 	case AifRequest:
62035863739SMike Smith 	    aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]);
62135863739SMike Smith 	    break;
62235863739SMike Smith 	default:
62335863739SMike Smith 	    device_printf(sc->aac_dev, "unknown command from controller\n");
62435863739SMike Smith 	    AAC_PRINT_FIB(sc, fib);
62535863739SMike Smith 	    break;
62635863739SMike Smith 	}
62735863739SMike Smith 
62835863739SMike Smith 	/* XXX reply to FIBs requesting responses ?? */
62935863739SMike Smith 	/* XXX how do we return these FIBs to the controller? */
63035863739SMike Smith     }
63135863739SMike Smith }
63235863739SMike Smith 
633c6eafcf2SScott Long /******************************************************************************
63435863739SMike Smith  * Handle notification of one or more FIBs completed by the controller
63535863739SMike Smith  */
63635863739SMike Smith static void
63735863739SMike Smith aac_host_response(struct aac_softc *sc)
63835863739SMike Smith {
63935863739SMike Smith     struct aac_command	*cm;
64035863739SMike Smith     struct aac_fib	*fib;
64135863739SMike Smith     u_int32_t		fib_size;
64235863739SMike Smith 
64335863739SMike Smith     debug_called(2);
64435863739SMike Smith 
64535863739SMike Smith     for (;;) {
64635863739SMike Smith 	/* look for completed FIBs on our queue */
64735863739SMike Smith 	if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib))
64835863739SMike Smith 	    break;	/* nothing to do */
64935863739SMike Smith 
65035863739SMike Smith 	/* get the command, unmap and queue for later processing */
65135863739SMike Smith 	cm = (struct aac_command *)fib->Header.SenderData;
65235863739SMike Smith 	if (cm == NULL) {
65335863739SMike Smith 	    AAC_PRINT_FIB(sc, fib);
65435863739SMike Smith 	} else {
6550b94a66eSMike Smith 	    aac_remove_busy(cm);
65635863739SMike Smith 	    aac_unmap_command(cm);		/* XXX defer? */
6570b94a66eSMike Smith 	    aac_enqueue_complete(cm);
65835863739SMike Smith 	}
65935863739SMike Smith     }
66035863739SMike Smith 
66135863739SMike Smith     /* handle completion processing */
66235863739SMike Smith #if __FreeBSD_version >= 500005
66335863739SMike Smith     taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
66435863739SMike Smith #else
66535863739SMike Smith     aac_complete(sc, 0);
66635863739SMike Smith #endif
66735863739SMike Smith }
66835863739SMike Smith 
669c6eafcf2SScott Long /******************************************************************************
67035863739SMike Smith  * Process completed commands.
67135863739SMike Smith  */
67235863739SMike Smith static void
67335863739SMike Smith aac_complete(void *context, int pending)
67435863739SMike Smith {
67535863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)context;
67635863739SMike Smith     struct aac_command	*cm;
67735863739SMike Smith 
67835863739SMike Smith     debug_called(2);
67935863739SMike Smith 
68035863739SMike Smith     /* pull completed commands off the queue */
68135863739SMike Smith     for (;;) {
6820b94a66eSMike Smith 	cm = aac_dequeue_complete(sc);
68335863739SMike Smith 	if (cm == NULL)
6840b94a66eSMike Smith 	    break;
68535863739SMike Smith 	cm->cm_flags |= AAC_CMD_COMPLETED;
68635863739SMike Smith 
68735863739SMike Smith 	/* is there a completion handler? */
68835863739SMike Smith 	if (cm->cm_complete != NULL) {
68935863739SMike Smith 	    cm->cm_complete(cm);
69035863739SMike Smith 	} else {
69135863739SMike Smith 	    /* assume that someone is sleeping on this command */
69235863739SMike Smith 	    wakeup(cm);
69335863739SMike Smith 	}
69435863739SMike Smith     }
6950b94a66eSMike Smith 
6960b94a66eSMike Smith     /* see if we can start some more I/O */
6970b94a66eSMike Smith     aac_startio(sc);
69835863739SMike Smith }
69935863739SMike Smith 
700c6eafcf2SScott Long /******************************************************************************
70135863739SMike Smith  * Handle a bio submitted from a disk device.
70235863739SMike Smith  */
70335863739SMike Smith void
70435863739SMike Smith aac_submit_bio(struct bio *bp)
70535863739SMike Smith {
70635863739SMike Smith     struct aac_disk	*ad = (struct aac_disk *)bp->bio_dev->si_drv1;
70735863739SMike Smith     struct aac_softc	*sc = ad->ad_controller;
70835863739SMike Smith 
70935863739SMike Smith     debug_called(2);
71035863739SMike Smith 
71135863739SMike Smith     /* queue the BIO and try to get some work done */
7120b94a66eSMike Smith     aac_enqueue_bio(sc, bp);
71335863739SMike Smith     aac_startio(sc);
71435863739SMike Smith }
71535863739SMike Smith 
716c6eafcf2SScott Long /******************************************************************************
71735863739SMike Smith  * Get a bio and build a command to go with it.
71835863739SMike Smith  */
71935863739SMike Smith static int
72035863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
72135863739SMike Smith {
72235863739SMike Smith     struct aac_command		*cm;
72335863739SMike Smith     struct aac_fib		*fib;
72435863739SMike Smith     struct aac_blockread	*br;
72535863739SMike Smith     struct aac_blockwrite	*bw;
72635863739SMike Smith     struct aac_disk		*ad;
72735863739SMike Smith     struct bio			*bp;
72835863739SMike Smith 
72935863739SMike Smith     debug_called(2);
73035863739SMike Smith 
73135863739SMike Smith     /* get the resources we will need */
73235863739SMike Smith     cm = NULL;
7330b94a66eSMike Smith     if ((bp = aac_dequeue_bio(sc)) == NULL)
73435863739SMike Smith 	goto fail;
73535863739SMike Smith     if (aac_alloc_command(sc, &cm))	/* get a command */
73635863739SMike Smith 	goto fail;
73735863739SMike Smith 
73835863739SMike Smith     /* fill out the command */
7390b94a66eSMike Smith     cm->cm_data = (void *)bp->bio_data;
7400b94a66eSMike Smith     cm->cm_datalen = bp->bio_bcount;
7410b94a66eSMike Smith     cm->cm_complete = aac_bio_complete;
74235863739SMike Smith     cm->cm_private = bp;
7430b94a66eSMike Smith     cm->cm_timestamp = time_second;
74435863739SMike Smith 
74535863739SMike Smith     /* build the FIB */
74635863739SMike Smith     fib = cm->cm_fib;
74735863739SMike Smith     fib->Header.XferState =
74835863739SMike Smith 	AAC_FIBSTATE_HOSTOWNED   |
74935863739SMike Smith 	AAC_FIBSTATE_INITIALISED |
75035863739SMike Smith 	AAC_FIBSTATE_FROMHOST    |
75135863739SMike Smith 	AAC_FIBSTATE_REXPECTED   |
75235863739SMike Smith 	AAC_FIBSTATE_NORM;
75335863739SMike Smith     fib->Header.Command = ContainerCommand;
75435863739SMike Smith     fib->Header.Size = sizeof(struct aac_fib_header);
75535863739SMike Smith 
75635863739SMike Smith     /* build the read/write request */
75735863739SMike Smith     ad = (struct aac_disk *)bp->bio_dev->si_drv1;
75835863739SMike Smith     if (BIO_IS_READ(bp)) {
75935863739SMike Smith 	br = (struct aac_blockread *)&fib->data[0];
76035863739SMike Smith 	br->Command = VM_CtBlockRead;
76135863739SMike Smith 	br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
76235863739SMike Smith 	br->BlockNumber = bp->bio_pblkno;
76335863739SMike Smith 	br->ByteCount = bp->bio_bcount;
76435863739SMike Smith 	fib->Header.Size += sizeof(struct aac_blockread);
76535863739SMike Smith 	cm->cm_sgtable = &br->SgMap;
76635863739SMike Smith 	cm->cm_flags |= AAC_CMD_DATAIN;
76735863739SMike Smith     } else {
76835863739SMike Smith 	bw = (struct aac_blockwrite *)&fib->data[0];
76935863739SMike Smith 	bw->Command = VM_CtBlockWrite;
77035863739SMike Smith 	bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
77135863739SMike Smith 	bw->BlockNumber = bp->bio_pblkno;
77235863739SMike Smith 	bw->ByteCount = bp->bio_bcount;
77335863739SMike Smith 	bw->Stable = CUNSTABLE;		/* XXX what's appropriate here? */
77435863739SMike Smith 	fib->Header.Size += sizeof(struct aac_blockwrite);
77535863739SMike Smith 	cm->cm_flags |= AAC_CMD_DATAOUT;
77635863739SMike Smith 	cm->cm_sgtable = &bw->SgMap;
77735863739SMike Smith     }
77835863739SMike Smith 
77935863739SMike Smith     *cmp = cm;
78035863739SMike Smith     return(0);
78135863739SMike Smith 
78235863739SMike Smith fail:
78335863739SMike Smith     if (bp != NULL)
7840b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
78535863739SMike Smith     if (cm != NULL)
78635863739SMike Smith 	aac_release_command(cm);
78735863739SMike Smith     return(ENOMEM);
78835863739SMike Smith }
78935863739SMike Smith 
790c6eafcf2SScott Long /******************************************************************************
79135863739SMike Smith  * Handle a bio-instigated command that has been completed.
79235863739SMike Smith  */
79335863739SMike Smith static void
79435863739SMike Smith aac_bio_complete(struct aac_command *cm)
79535863739SMike Smith {
79635863739SMike Smith     struct aac_blockread_response	*brr;
79735863739SMike Smith     struct aac_blockwrite_response	*bwr;
79835863739SMike Smith     struct bio				*bp;
79935863739SMike Smith     AAC_FSAStatus			status;
80035863739SMike Smith 
80135863739SMike Smith     /* fetch relevant status and then release the command */
80235863739SMike Smith     bp = (struct bio *)cm->cm_private;
80335863739SMike Smith     if (BIO_IS_READ(bp)) {
80435863739SMike Smith 	brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
80535863739SMike Smith 	status = brr->Status;
80635863739SMike Smith     } else {
80735863739SMike Smith 	bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
80835863739SMike Smith 	status = bwr->Status;
80935863739SMike Smith     }
81035863739SMike Smith     aac_release_command(cm);
81135863739SMike Smith 
81235863739SMike Smith     /* fix up the bio based on status */
81335863739SMike Smith     if (status == ST_OK) {
81435863739SMike Smith 	bp->bio_resid = 0;
81535863739SMike Smith     } else {
81635863739SMike Smith 	bp->bio_error = EIO;
81735863739SMike Smith 	bp->bio_flags |= BIO_ERROR;
8180b94a66eSMike Smith 	/* pass an error string out to the disk layer */
8190b94a66eSMike Smith 	bp->bio_driver1 = aac_describe_code(aac_command_status_table, status);
82035863739SMike Smith     }
8210b94a66eSMike Smith     aac_biodone(bp);
82235863739SMike Smith }
82335863739SMike Smith 
824c6eafcf2SScott Long /******************************************************************************
82535863739SMike Smith  * Submit a command to the controller, return when it completes.
82635863739SMike Smith  */
82735863739SMike Smith static int
82835863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout)
82935863739SMike Smith {
83035863739SMike Smith     int s, error = 0;
83135863739SMike Smith 
83235863739SMike Smith     debug_called(2);
83335863739SMike Smith 
83435863739SMike Smith     /* Put the command on the ready queue and get things going */
83535863739SMike Smith     aac_enqueue_ready(cm);
83635863739SMike Smith     aac_startio(cm->cm_sc);
83735863739SMike Smith     s = splbio();
83835863739SMike Smith     while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
83935863739SMike Smith         error = tsleep(cm, PRIBIO, "aacwait", timeout * hz);
84035863739SMike Smith     }
84135863739SMike Smith     splx(s);
84235863739SMike Smith     return(error);
84335863739SMike Smith }
84435863739SMike Smith 
845c6eafcf2SScott Long /******************************************************************************
846c6eafcf2SScott Long  ******************************************************************************
84735863739SMike Smith 			Command Buffer Management
848c6eafcf2SScott Long  ******************************************************************************
849c6eafcf2SScott Long  ******************************************************************************/
85035863739SMike Smith 
851c6eafcf2SScott Long /******************************************************************************
85235863739SMike Smith  * Allocate a command.
85335863739SMike Smith  */
85435863739SMike Smith static int
85535863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
85635863739SMike Smith {
85735863739SMike Smith     struct aac_command	*cm;
85835863739SMike Smith 
85935863739SMike Smith     debug_called(3);
86035863739SMike Smith 
8610b94a66eSMike Smith     if ((cm = aac_dequeue_free(sc)) == NULL)
86235863739SMike Smith 	return(ENOMEM);
86335863739SMike Smith 
8640b94a66eSMike Smith     *cmp = cm;
8650b94a66eSMike Smith     return(0);
8660b94a66eSMike Smith }
8670b94a66eSMike Smith 
868c6eafcf2SScott Long /******************************************************************************
8690b94a66eSMike Smith  * Release a command back to the freelist.
8700b94a66eSMike Smith  */
8710b94a66eSMike Smith static void
8720b94a66eSMike Smith aac_release_command(struct aac_command *cm)
8730b94a66eSMike Smith {
8740b94a66eSMike Smith     debug_called(3);
8750b94a66eSMike Smith 
8760b94a66eSMike Smith     /* (re)initialise the command/FIB */
87735863739SMike Smith     cm->cm_sgtable = NULL;
87835863739SMike Smith     cm->cm_flags = 0;
87935863739SMike Smith     cm->cm_complete = NULL;
88035863739SMike Smith     cm->cm_private = NULL;
88135863739SMike Smith     cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
88235863739SMike Smith     cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
88335863739SMike Smith     cm->cm_fib->Header.Flags = 0;
88435863739SMike Smith     cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
88535863739SMike Smith 
88635863739SMike Smith     /*
88735863739SMike Smith      * These are duplicated in aac_start to cover the case where an
88835863739SMike Smith      * intermediate stage may have destroyed them.  They're left
88935863739SMike Smith      * initialised here for debugging purposes only.
89035863739SMike Smith      */
89135863739SMike Smith     cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
89235863739SMike Smith     cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
89335863739SMike Smith 
89435863739SMike Smith     aac_enqueue_free(cm);
89535863739SMike Smith }
89635863739SMike Smith 
897c6eafcf2SScott Long /******************************************************************************
8980b94a66eSMike Smith  * Map helper for command/FIB allocation.
89935863739SMike Smith  */
90035863739SMike Smith static void
9010b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
90235863739SMike Smith {
9030b94a66eSMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
90435863739SMike Smith 
90535863739SMike Smith     debug_called(3);
90635863739SMike Smith 
9070b94a66eSMike Smith     sc->aac_fibphys = segs[0].ds_addr;
90835863739SMike Smith }
90935863739SMike Smith 
910c6eafcf2SScott Long /******************************************************************************
9110b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
91235863739SMike Smith  */
9130b94a66eSMike Smith static int
9140b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
91535863739SMike Smith {
91635863739SMike Smith     struct aac_command		*cm;
91735863739SMike Smith     int				i;
91835863739SMike Smith 
91935863739SMike Smith     debug_called(1);
92035863739SMike Smith 
9210b94a66eSMike Smith     /* allocate the FIBs in DMAable memory and load them */
922c6eafcf2SScott Long     if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs,
923c6eafcf2SScott Long 			 BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
9240b94a66eSMike Smith 	return(ENOMEM);
92535863739SMike Smith     }
9260b94a66eSMike Smith     bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
927c6eafcf2SScott Long 		    AAC_FIB_COUNT * sizeof(struct aac_fib),
928c6eafcf2SScott Long 		    aac_map_command_helper, sc, 0);
92935863739SMike Smith 
9300b94a66eSMike Smith     /* initialise constant fields in the command structure */
9310b94a66eSMike Smith     for (i = 0; i < AAC_FIB_COUNT; i++) {
9320b94a66eSMike Smith 	cm = &sc->aac_command[i];
93335863739SMike Smith 	cm->cm_sc = sc;
9340b94a66eSMike Smith 	cm->cm_fib = sc->aac_fibs + i;
9350b94a66eSMike Smith 	cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
93635863739SMike Smith 
93735863739SMike Smith 	if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
93835863739SMike Smith 	    aac_release_command(cm);
93935863739SMike Smith     }
9400b94a66eSMike Smith     return(0);
94135863739SMike Smith }
94235863739SMike Smith 
943c6eafcf2SScott Long /******************************************************************************
9440b94a66eSMike Smith  * Free FIBs owned by this adapter.
94535863739SMike Smith  */
94635863739SMike Smith static void
9470b94a66eSMike Smith aac_free_commands(struct aac_softc *sc)
94835863739SMike Smith {
94935863739SMike Smith     int			i;
95035863739SMike Smith 
95135863739SMike Smith     debug_called(1);
95235863739SMike Smith 
9530b94a66eSMike Smith     for (i = 0; i < AAC_FIB_COUNT; i++)
9540b94a66eSMike Smith 	bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap);
9550b94a66eSMike Smith     bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
9560b94a66eSMike Smith     bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
95735863739SMike Smith }
95835863739SMike Smith 
959c6eafcf2SScott Long /******************************************************************************
96035863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
96135863739SMike Smith  */
96235863739SMike Smith static void
96335863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
96435863739SMike Smith {
96535863739SMike Smith     struct aac_command		*cm = (struct aac_command *)arg;
96635863739SMike Smith     struct aac_fib		*fib = cm->cm_fib;
96735863739SMike Smith     struct aac_sg_table		*sg;
96835863739SMike Smith     int				i;
96935863739SMike Smith 
97035863739SMike Smith     debug_called(3);
97135863739SMike Smith 
97235863739SMike Smith     /* find the s/g table */
97335863739SMike Smith     sg = cm->cm_sgtable;
97435863739SMike Smith 
97535863739SMike Smith     /* copy into the FIB */
97635863739SMike Smith     if (sg != NULL) {
97735863739SMike Smith 	sg->SgCount = nseg;
97835863739SMike Smith 	for (i = 0; i < nseg; i++) {
97935863739SMike Smith 	    sg->SgEntry[i].SgAddress = segs[i].ds_addr;
98035863739SMike Smith 	    sg->SgEntry[i].SgByteCount = segs[i].ds_len;
98135863739SMike Smith 	}
98235863739SMike Smith 	/* update the FIB size for the s/g count */
98335863739SMike Smith 	fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
98435863739SMike Smith     }
98535863739SMike Smith 
98635863739SMike Smith }
98735863739SMike Smith 
988c6eafcf2SScott Long /******************************************************************************
98935863739SMike Smith  * Map a command into controller-visible space.
99035863739SMike Smith  */
99135863739SMike Smith static void
99235863739SMike Smith aac_map_command(struct aac_command *cm)
99335863739SMike Smith {
99435863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
99535863739SMike Smith 
99635863739SMike Smith     debug_called(2);
99735863739SMike Smith 
99835863739SMike Smith     /* don't map more than once */
99935863739SMike Smith     if (cm->cm_flags & AAC_CMD_MAPPED)
100035863739SMike Smith 	return;
100135863739SMike Smith 
100235863739SMike Smith     if (cm->cm_datalen != 0) {
100335863739SMike Smith 	bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data,
100435863739SMike Smith 			cm->cm_datalen, aac_map_command_sg, cm, 0);
100535863739SMike Smith 
100635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1007c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1008c6eafcf2SScott Long 			    BUS_DMASYNC_PREREAD);
100935863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1010c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1011c6eafcf2SScott Long 			    BUS_DMASYNC_PREWRITE);
101235863739SMike Smith     }
101335863739SMike Smith     cm->cm_flags |= AAC_CMD_MAPPED;
101435863739SMike Smith }
101535863739SMike Smith 
1016c6eafcf2SScott Long /******************************************************************************
101735863739SMike Smith  * Unmap a command from controller-visible space.
101835863739SMike Smith  */
101935863739SMike Smith static void
102035863739SMike Smith aac_unmap_command(struct aac_command *cm)
102135863739SMike Smith {
102235863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
102335863739SMike Smith 
102435863739SMike Smith     debug_called(2);
102535863739SMike Smith 
102635863739SMike Smith     if (!(cm->cm_flags & AAC_CMD_MAPPED))
102735863739SMike Smith 	return;
102835863739SMike Smith 
102935863739SMike Smith     if (cm->cm_datalen != 0) {
103035863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1031c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1032c6eafcf2SScott Long 			    BUS_DMASYNC_POSTREAD);
103335863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1034c6eafcf2SScott Long 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1035c6eafcf2SScott Long 			    BUS_DMASYNC_POSTWRITE);
103635863739SMike Smith 
103735863739SMike Smith 	bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
103835863739SMike Smith     }
103935863739SMike Smith     cm->cm_flags &= ~AAC_CMD_MAPPED;
104035863739SMike Smith }
104135863739SMike Smith 
1042c6eafcf2SScott Long /******************************************************************************
1043c6eafcf2SScott Long  ******************************************************************************
104435863739SMike Smith 				Hardware Interface
1045c6eafcf2SScott Long  ******************************************************************************
1046c6eafcf2SScott Long  ******************************************************************************/
104735863739SMike Smith 
1048c6eafcf2SScott Long /******************************************************************************
104935863739SMike Smith  * Initialise the adapter.
105035863739SMike Smith  */
105135863739SMike Smith static void
105235863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
105335863739SMike Smith {
105435863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
105535863739SMike Smith 
105635863739SMike Smith     debug_called(1);
105735863739SMike Smith 
105835863739SMike Smith     sc->aac_common_busaddr = segs[0].ds_addr;
105935863739SMike Smith }
106035863739SMike Smith 
106135863739SMike Smith static int
106235863739SMike Smith aac_init(struct aac_softc *sc)
106335863739SMike Smith {
106435863739SMike Smith     struct aac_adapter_init	*ip;
106535863739SMike Smith     time_t			then;
106635863739SMike Smith     u_int32_t			code;
106735863739SMike Smith     u_int8_t			*qaddr;
106835863739SMike Smith 
106935863739SMike Smith     debug_called(1);
107035863739SMike Smith 
107135863739SMike Smith     /*
107235863739SMike Smith      * First wait for the adapter to come ready.
107335863739SMike Smith      */
107435863739SMike Smith     then = time_second;
107535863739SMike Smith     do {
107635863739SMike Smith 	code = AAC_GET_FWSTATUS(sc);
107735863739SMike Smith 	if (code & AAC_SELF_TEST_FAILED) {
107835863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: selftest failed\n");
107935863739SMike Smith 	    return(ENXIO);
108035863739SMike Smith 	}
108135863739SMike Smith 	if (code & AAC_KERNEL_PANIC) {
108235863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: controller kernel panic\n");
108335863739SMike Smith 	    return(ENXIO);
108435863739SMike Smith 	}
108535863739SMike Smith 	if (time_second > (then + AAC_BOOT_TIMEOUT)) {
1086c6eafcf2SScott Long 	    device_printf(sc->aac_dev, "FATAL: controller not coming ready, "
1087c6eafcf2SScott Long 			  "status %x\n", code);
108835863739SMike Smith 	    return(ENXIO);
108935863739SMike Smith 	}
109035863739SMike Smith     } while (!(code & AAC_UP_AND_RUNNING));
109135863739SMike Smith 
109235863739SMike Smith     /*
109335863739SMike Smith      * Create DMA tag for the common structure and allocate it.
109435863739SMike Smith      */
109535863739SMike Smith     if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1096c6eafcf2SScott Long 			   1, 0, 			/* algnmnt, boundary */
109735863739SMike Smith 			   BUS_SPACE_MAXADDR,		/* lowaddr */
109835863739SMike Smith 			   BUS_SPACE_MAXADDR, 		/* highaddr */
109935863739SMike Smith 			   NULL, NULL, 			/* filter, filterarg */
110035863739SMike Smith 			   sizeof(struct aac_common), 1,/* maxsize, nsegments */
110135863739SMike Smith 			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
110235863739SMike Smith 			   0,				/* flags */
110335863739SMike Smith 			   &sc->aac_common_dmat)) {
110435863739SMike Smith 	device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n");
110535863739SMike Smith 	return(ENOMEM);
110635863739SMike Smith     }
1107c6eafcf2SScott Long     if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1108c6eafcf2SScott Long 			 BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
110935863739SMike Smith 	device_printf(sc->aac_dev, "can't allocate common structure\n");
111035863739SMike Smith 	return(ENOMEM);
111135863739SMike Smith     }
1112c6eafcf2SScott Long     bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common,
1113c6eafcf2SScott Long 		    sizeof(*sc->aac_common), aac_common_map, sc, 0);
111435863739SMike Smith     bzero(sc->aac_common, sizeof(*sc->aac_common));
111535863739SMike Smith 
111635863739SMike Smith     /*
1117c6eafcf2SScott Long      * Fill in the init structure.  This tells the adapter about the physical
1118c6eafcf2SScott Long      * location of various important shared data structures.
111935863739SMike Smith      */
112035863739SMike Smith     ip = &sc->aac_common->ac_init;
112135863739SMike Smith     ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
112235863739SMike Smith 
1123c6eafcf2SScott Long     ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1124c6eafcf2SScott Long 				     offsetof(struct aac_common, ac_fibs);
112535863739SMike Smith     ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
112635863739SMike Smith     ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
112735863739SMike Smith     ip->AdapterFibAlign = sizeof(struct aac_fib);
112835863739SMike Smith 
1129c6eafcf2SScott Long     ip->PrintfBufferAddress = sc->aac_common_busaddr +
1130c6eafcf2SScott Long 			      offsetof(struct aac_common, ac_printf);
113135863739SMike Smith     ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
113235863739SMike Smith 
113335863739SMike Smith     ip->HostPhysMemPages = 0;			/* not used? */
113435863739SMike Smith     ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
113535863739SMike Smith 
113635863739SMike Smith     /*
1137c6eafcf2SScott Long      * Initialise FIB queues.  Note that it appears that the layout of the
1138c6eafcf2SScott Long      * indexes and the segmentation of the entries may be mandated by the
1139c6eafcf2SScott Long      * adapter, which is only told about the base of the queue index fields.
114035863739SMike Smith      *
114135863739SMike Smith      * The initial values of the indices are assumed to inform the adapter
1142c6eafcf2SScott Long      * of the sizes of the respective queues, and theoretically it could work
1143c6eafcf2SScott Long      * out the entire layout of the queue structures from this.  We take the
1144c6eafcf2SScott Long      * easy route and just lay this area out like everyone else does.
114535863739SMike Smith      *
114635863739SMike Smith      * The Linux driver uses a much more complex scheme whereby several header
1147c6eafcf2SScott Long      * records are kept for each queue.  We use a couple of generic list
1148c6eafcf2SScott Long      * manipulation functions which 'know' the size of each list by virtue of a
1149c6eafcf2SScott Long      * table.
115035863739SMike Smith      */
115135863739SMike Smith     qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
115235863739SMike Smith     qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
115335863739SMike Smith     sc->aac_queues = (struct aac_queue_table *)qaddr;
1154c6eafcf2SScott Long     ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues
1155c6eafcf2SScott Long 			    - (u_int32_t)sc->aac_common);
115635863739SMike Smith     bzero(sc->aac_queues, sizeof(struct aac_queue_table));
115735863739SMike Smith 
1158c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1159c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1160c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1161c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1162c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1163c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1164c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1165c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1166c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1167c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1168c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1169c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1170c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1171c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1172c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1173c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1174c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1175c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1176c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1177c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1178c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1179c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1180c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1181c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1182c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1183c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1184c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1185c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1186c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] =
1187c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1188c6eafcf2SScott Long     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] =
1189c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1190c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1191c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1192c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1193c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1194c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1195c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1196c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1197c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1198c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1199c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1200c6eafcf2SScott Long     sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1201c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1202c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1203c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1204c6eafcf2SScott Long     sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1205c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
120635863739SMike Smith 
120735863739SMike Smith     /*
120835863739SMike Smith      * Do controller-type-specific initialisation
120935863739SMike Smith      */
121035863739SMike Smith     switch (sc->aac_hwif) {
121135863739SMike Smith     case AAC_HWIF_I960RX:
121235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
121335863739SMike Smith 	break;
121435863739SMike Smith     }
121535863739SMike Smith 
121635863739SMike Smith     /*
121735863739SMike Smith      * Give the init structure to the controller.
121835863739SMike Smith      */
121935863739SMike Smith     if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1220c6eafcf2SScott Long 			 sc->aac_common_busaddr + offsetof(struct aac_common,
1221c6eafcf2SScott Long 			 ac_init), 0, 0, 0, NULL)) {
122235863739SMike Smith 	device_printf(sc->aac_dev, "error establishing init structure\n");
122335863739SMike Smith 	return(EIO);
122435863739SMike Smith     }
122535863739SMike Smith 
122635863739SMike Smith     return(0);
122735863739SMike Smith }
122835863739SMike Smith 
1229c6eafcf2SScott Long /******************************************************************************
123035863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
123135863739SMike Smith  */
123235863739SMike Smith static int
123335863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
123435863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
123535863739SMike Smith 		 u_int32_t *sp)
123635863739SMike Smith {
123735863739SMike Smith     time_t	then;
123835863739SMike Smith     u_int32_t	status;
123935863739SMike Smith 
124035863739SMike Smith     debug_called(3);
124135863739SMike Smith 
124235863739SMike Smith     /* populate the mailbox */
124335863739SMike Smith     AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
124435863739SMike Smith 
124535863739SMike Smith     /* ensure the sync command doorbell flag is cleared */
124635863739SMike Smith     AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
124735863739SMike Smith 
124835863739SMike Smith     /* then set it to signal the adapter */
124935863739SMike Smith     AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
125035863739SMike Smith 
125135863739SMike Smith     /* spin waiting for the command to complete */
125235863739SMike Smith     then = time_second;
125335863739SMike Smith     do {
125435863739SMike Smith 	if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
125535863739SMike Smith 	    debug(2, "timed out");
125635863739SMike Smith 	    return(EIO);
125735863739SMike Smith 	}
125835863739SMike Smith     } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
125935863739SMike Smith 
126035863739SMike Smith     /* clear the completion flag */
126135863739SMike Smith     AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
126235863739SMike Smith 
126335863739SMike Smith     /* get the command status */
126435863739SMike Smith     status = AAC_GET_MAILBOXSTATUS(sc);
126535863739SMike Smith     if (sp != NULL)
126635863739SMike Smith 	*sp = status;
12670b94a66eSMike Smith     return(0);
126835863739SMike Smith }
126935863739SMike Smith 
1270c6eafcf2SScott Long /******************************************************************************
127135863739SMike Smith  * Send a synchronous FIB to the controller and wait for a result.
127235863739SMike Smith  */
127335863739SMike Smith static int
127435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
127535863739SMike Smith 	     void *data, u_int16_t datasize,
127635863739SMike Smith 	     void *result, u_int16_t *resultsize)
127735863739SMike Smith {
127835863739SMike Smith     struct aac_fib	*fib = &sc->aac_common->ac_sync_fib;
127935863739SMike Smith 
128035863739SMike Smith     debug_called(3);
128135863739SMike Smith 
128235863739SMike Smith     if (datasize > AAC_FIB_DATASIZE)
128335863739SMike Smith 	return(EINVAL);
128435863739SMike Smith 
128535863739SMike Smith     /*
128635863739SMike Smith      * Set up the sync FIB
128735863739SMike Smith      */
1288c6eafcf2SScott Long     fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED |
1289c6eafcf2SScott Long 			    AAC_FIBSTATE_EMPTY;
129035863739SMike Smith     fib->Header.XferState |= xferstate;
129135863739SMike Smith     fib->Header.Command = command;
129235863739SMike Smith     fib->Header.StructType = AAC_FIBTYPE_TFIB;
129335863739SMike Smith     fib->Header.Size = sizeof(struct aac_fib) + datasize;
129435863739SMike Smith     fib->Header.SenderSize = sizeof(struct aac_fib);
129535863739SMike Smith     fib->Header.SenderFibAddress = (u_int32_t)fib;
1296c6eafcf2SScott Long     fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
1297c6eafcf2SScott Long 				     offsetof(struct aac_common, ac_sync_fib);
129835863739SMike Smith 
129935863739SMike Smith     /*
130035863739SMike Smith      * Copy in data.
130135863739SMike Smith      */
130235863739SMike Smith     if (data != NULL) {
130335863739SMike Smith 	bcopy(data, fib->data, datasize);
130435863739SMike Smith 	fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM;
130535863739SMike Smith     }
130635863739SMike Smith 
130735863739SMike Smith     /*
130835863739SMike Smith      * Give the FIB to the controller, wait for a response.
130935863739SMike Smith      */
131035863739SMike Smith     if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress,
131135863739SMike Smith 			 0, 0, 0, NULL)) {
131235863739SMike Smith 	debug(2, "IO error");
131335863739SMike Smith 	return(EIO);
131435863739SMike Smith     }
131535863739SMike Smith 
131635863739SMike Smith     /*
131735863739SMike Smith      * Copy out the result
131835863739SMike Smith      */
131935863739SMike Smith     if (result != NULL) {
132035863739SMike Smith 	*resultsize = fib->Header.Size - sizeof(struct aac_fib_header);
132135863739SMike Smith 	bcopy(fib->data, result, *resultsize);
132235863739SMike Smith     }
132335863739SMike Smith     return(0);
132435863739SMike Smith }
132535863739SMike Smith 
132635863739SMike Smith /********************************************************************************
132735863739SMike Smith  * Adapter-space FIB queue manipulation
132835863739SMike Smith  *
132935863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
133035863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
133135863739SMike Smith  */
133235863739SMike Smith static struct {
133335863739SMike Smith     int		size;
133435863739SMike Smith     int		notify;
133535863739SMike Smith } aac_qinfo[] = {
133635863739SMike Smith     {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
133735863739SMike Smith     {AAC_HOST_HIGH_CMD_ENTRIES, 0},
133835863739SMike Smith     {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
133935863739SMike Smith     {AAC_ADAP_HIGH_CMD_ENTRIES, 0},
134035863739SMike Smith     {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
134135863739SMike Smith     {AAC_HOST_HIGH_RESP_ENTRIES, 0},
134235863739SMike Smith     {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
134335863739SMike Smith     {AAC_ADAP_HIGH_RESP_ENTRIES, 0}
134435863739SMike Smith };
134535863739SMike Smith 
134635863739SMike Smith /*
1347c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
1348c6eafcf2SScott Long  * EBUSY if the queue is full.
134935863739SMike Smith  *
13500b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
1351c6eafcf2SScott Long  *       the case where we may be inserting several entries in rapid succession,
1352c6eafcf2SScott Long  *       but implementing this usefully may be difficult (it would involve a
1353c6eafcf2SScott Long  *       separate queue/notify interface).
135435863739SMike Smith  */
135535863739SMike Smith static int
1356c6eafcf2SScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size,
1357c6eafcf2SScott Long 		u_int32_t fib_addr)
135835863739SMike Smith {
135935863739SMike Smith     u_int32_t	pi, ci;
136035863739SMike Smith     int		s, error;
136135863739SMike Smith 
136235863739SMike Smith     debug_called(3);
136335863739SMike Smith 
136435863739SMike Smith     s = splbio();
136535863739SMike Smith 
136635863739SMike Smith     /* get the producer/consumer indices */
136735863739SMike Smith     pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
136835863739SMike Smith     ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
136935863739SMike Smith 
137035863739SMike Smith     /* wrap the queue? */
137135863739SMike Smith     if (pi >= aac_qinfo[queue].size)
137235863739SMike Smith 	pi = 0;
137335863739SMike Smith 
137435863739SMike Smith     /* check for queue full */
137535863739SMike Smith     if ((pi + 1) == ci) {
137635863739SMike Smith 	error = EBUSY;
137735863739SMike Smith 	goto out;
137835863739SMike Smith     }
137935863739SMike Smith 
138035863739SMike Smith     /* populate queue entry */
138135863739SMike Smith     (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
138235863739SMike Smith     (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
138335863739SMike Smith 
138435863739SMike Smith     /* update producer index */
138535863739SMike Smith     sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
138635863739SMike Smith 
138735863739SMike Smith     /* notify the adapter if we know how */
138835863739SMike Smith     if (aac_qinfo[queue].notify != 0)
138935863739SMike Smith 	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
139035863739SMike Smith 
139135863739SMike Smith     error = 0;
139235863739SMike Smith 
139335863739SMike Smith out:
139435863739SMike Smith     splx(s);
139535863739SMike Smith     return(error);
139635863739SMike Smith }
139735863739SMike Smith 
139835863739SMike Smith /*
1399c6eafcf2SScott Long  * Atomically remove one entry from the nominated queue, returns 0 on success or
1400c6eafcf2SScott Long  * ENOENT if the queue is empty.
140135863739SMike Smith  */
140235863739SMike Smith static int
1403c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1404c6eafcf2SScott Long 		struct aac_fib **fib_addr)
140535863739SMike Smith {
140635863739SMike Smith     u_int32_t	pi, ci;
140735863739SMike Smith     int		s, error;
140835863739SMike Smith 
140935863739SMike Smith     debug_called(3);
141035863739SMike Smith 
141135863739SMike Smith     s = splbio();
141235863739SMike Smith 
141335863739SMike Smith     /* get the producer/consumer indices */
141435863739SMike Smith     pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
141535863739SMike Smith     ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
141635863739SMike Smith 
141735863739SMike Smith     /* check for queue empty */
141835863739SMike Smith     if (ci == pi) {
141935863739SMike Smith 	error = ENOENT;
142035863739SMike Smith 	goto out;
142135863739SMike Smith     }
142235863739SMike Smith 
142335863739SMike Smith     /* wrap the queue? */
142435863739SMike Smith     if (ci >= aac_qinfo[queue].size)
142535863739SMike Smith 	ci = 0;
142635863739SMike Smith 
142735863739SMike Smith     /* fetch the entry */
142835863739SMike Smith     *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
142935863739SMike Smith     *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr;
143035863739SMike Smith 
143135863739SMike Smith     /* update consumer index */
143235863739SMike Smith     sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
143335863739SMike Smith 
143435863739SMike Smith     /* if we have made the queue un-full, notify the adapter */
143535863739SMike Smith     if (((pi + 1) == ci) && (aac_qinfo[queue].notify != 0))
143635863739SMike Smith 	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
143735863739SMike Smith     error = 0;
143835863739SMike Smith 
143935863739SMike Smith out:
144035863739SMike Smith     splx(s);
144135863739SMike Smith     return(error);
144235863739SMike Smith }
144335863739SMike Smith 
1444c6eafcf2SScott Long /******************************************************************************
14450b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
14460b94a66eSMike Smith  * and complain about them.
14470b94a66eSMike Smith  */
14480b94a66eSMike Smith static void
14490b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
14500b94a66eSMike Smith {
14510b94a66eSMike Smith     int		s;
14520b94a66eSMike Smith     struct	aac_command *cm;
14530b94a66eSMike Smith     time_t	deadline;
14540b94a66eSMike Smith 
14550b94a66eSMike Smith     /* simulate an interrupt to handle possibly-missed interrupts */
14560b94a66eSMike Smith     aac_intr(sc);
14570b94a66eSMike Smith 
14580b94a66eSMike Smith     /* kick the I/O queue to restart it in the case of deadlock */
14590b94a66eSMike Smith     aac_startio(sc);
14600b94a66eSMike Smith 
14610b94a66eSMike Smith     /* traverse the busy command list, bitch about late commands once only */
14620b94a66eSMike Smith     deadline = time_second - AAC_CMD_TIMEOUT;
14630b94a66eSMike Smith     s = splbio();
14640b94a66eSMike Smith     TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
1465c6eafcf2SScott Long 	if ((cm->cm_timestamp < deadline) &&
1466c6eafcf2SScott Long 	    !(cm->cm_flags & AAC_CMD_TIMEDOUT)) {
14670b94a66eSMike Smith 	    cm->cm_flags |= AAC_CMD_TIMEDOUT;
14680b94a66eSMike Smith 	    device_printf(sc->aac_dev, "COMMAND TIMED OUT AFTER %d SECONDS\n",
14690b94a66eSMike Smith 			  (int)(time_second - cm->cm_timestamp));
14700b94a66eSMike Smith 	    AAC_PRINT_FIB(sc, cm->cm_fib);
14710b94a66eSMike Smith 	}
14720b94a66eSMike Smith     }
14730b94a66eSMike Smith     splx(s);
14740b94a66eSMike Smith 
14750b94a66eSMike Smith     /* reset the timer for next time */
14760b94a66eSMike Smith     timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
14770b94a66eSMike Smith     return;
14780b94a66eSMike Smith }
14790b94a66eSMike Smith 
1480c6eafcf2SScott Long /******************************************************************************
1481c6eafcf2SScott Long  ******************************************************************************
148235863739SMike Smith 			Interface Function Vectors
1483c6eafcf2SScott Long  ******************************************************************************
1484c6eafcf2SScott Long  ******************************************************************************/
148535863739SMike Smith 
1486c6eafcf2SScott Long /******************************************************************************
148735863739SMike Smith  * Read the current firmware status word.
148835863739SMike Smith  */
148935863739SMike Smith static int
149035863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
149135863739SMike Smith {
149235863739SMike Smith     debug_called(3);
149335863739SMike Smith 
149435863739SMike Smith     return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
149535863739SMike Smith }
149635863739SMike Smith 
149735863739SMike Smith static int
149835863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
149935863739SMike Smith {
150035863739SMike Smith     debug_called(3);
150135863739SMike Smith 
150235863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
150335863739SMike Smith }
150435863739SMike Smith 
1505c6eafcf2SScott Long /******************************************************************************
150635863739SMike Smith  * Notify the controller of a change in a given queue
150735863739SMike Smith  */
150835863739SMike Smith 
150935863739SMike Smith static void
151035863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
151135863739SMike Smith {
151235863739SMike Smith     debug_called(3);
151335863739SMike Smith 
151435863739SMike Smith     AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
151535863739SMike Smith }
151635863739SMike Smith 
151735863739SMike Smith static void
151835863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
151935863739SMike Smith {
152035863739SMike Smith     debug_called(3);
152135863739SMike Smith 
152235863739SMike Smith     AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
152335863739SMike Smith }
152435863739SMike Smith 
1525c6eafcf2SScott Long /******************************************************************************
152635863739SMike Smith  * Get the interrupt reason bits
152735863739SMike Smith  */
152835863739SMike Smith static int
152935863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
153035863739SMike Smith {
153135863739SMike Smith     debug_called(3);
153235863739SMike Smith 
153335863739SMike Smith     return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
153435863739SMike Smith }
153535863739SMike Smith 
153635863739SMike Smith static int
153735863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
153835863739SMike Smith {
153935863739SMike Smith     debug_called(3);
154035863739SMike Smith 
154135863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_ODBR));
154235863739SMike Smith }
154335863739SMike Smith 
1544c6eafcf2SScott Long /******************************************************************************
154535863739SMike Smith  * Clear some interrupt reason bits
154635863739SMike Smith  */
154735863739SMike Smith static void
154835863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
154935863739SMike Smith {
155035863739SMike Smith     debug_called(3);
155135863739SMike Smith 
155235863739SMike Smith     AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
155335863739SMike Smith }
155435863739SMike Smith 
155535863739SMike Smith static void
155635863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
155735863739SMike Smith {
155835863739SMike Smith     debug_called(3);
155935863739SMike Smith 
156035863739SMike Smith     AAC_SETREG4(sc, AAC_RX_ODBR, mask);
156135863739SMike Smith }
156235863739SMike Smith 
1563c6eafcf2SScott Long /******************************************************************************
156435863739SMike Smith  * Populate the mailbox and set the command word
156535863739SMike Smith  */
156635863739SMike Smith static void
156735863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
156835863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
156935863739SMike Smith {
157035863739SMike Smith     debug_called(4);
157135863739SMike Smith 
157235863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
157335863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
157435863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
157535863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
157635863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
157735863739SMike Smith }
157835863739SMike Smith 
157935863739SMike Smith static void
158035863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
158135863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
158235863739SMike Smith {
158335863739SMike Smith     debug_called(4);
158435863739SMike Smith 
158535863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
158635863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
158735863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
158835863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
158935863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
159035863739SMike Smith }
159135863739SMike Smith 
1592c6eafcf2SScott Long /******************************************************************************
159335863739SMike Smith  * Fetch the immediate command status word
159435863739SMike Smith  */
159535863739SMike Smith static int
159635863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc)
159735863739SMike Smith {
159835863739SMike Smith     debug_called(4);
159935863739SMike Smith 
160035863739SMike Smith     return(AAC_GETREG4(sc, AAC_SA_MAILBOX));
160135863739SMike Smith }
160235863739SMike Smith 
160335863739SMike Smith static int
160435863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc)
160535863739SMike Smith {
160635863739SMike Smith     debug_called(4);
160735863739SMike Smith 
160835863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
160935863739SMike Smith }
161035863739SMike Smith 
1611c6eafcf2SScott Long /******************************************************************************
161235863739SMike Smith  * Set/clear interrupt masks
161335863739SMike Smith  */
161435863739SMike Smith static void
161535863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
161635863739SMike Smith {
161735863739SMike Smith     debug(2, "%sable interrupts", enable ? "en" : "dis");
161835863739SMike Smith 
161935863739SMike Smith     if (enable) {
162035863739SMike Smith 	AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
162135863739SMike Smith     } else {
162235863739SMike Smith 	AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
162335863739SMike Smith     }
162435863739SMike Smith }
162535863739SMike Smith 
162635863739SMike Smith static void
162735863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
162835863739SMike Smith {
162935863739SMike Smith     debug(2, "%sable interrupts", enable ? "en" : "dis");
163035863739SMike Smith 
163135863739SMike Smith     if (enable) {
163235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
163335863739SMike Smith     } else {
163435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
163535863739SMike Smith     }
163635863739SMike Smith }
163735863739SMike Smith 
1638c6eafcf2SScott Long /******************************************************************************
1639c6eafcf2SScott Long  ******************************************************************************
164035863739SMike Smith 			Debugging and Diagnostics
1641c6eafcf2SScott Long  ******************************************************************************
1642c6eafcf2SScott Long  ******************************************************************************/
164335863739SMike Smith 
1644c6eafcf2SScott Long /******************************************************************************
164535863739SMike Smith  * Print some information about the controller.
164635863739SMike Smith  */
164735863739SMike Smith static void
164835863739SMike Smith aac_describe_controller(struct aac_softc *sc)
164935863739SMike Smith {
1650c6eafcf2SScott Long     u_int8_t			buf[AAC_FIB_DATASIZE];	/* XXX really a bit big
1651c6eafcf2SScott Long 							 * for the stack */
165235863739SMike Smith     u_int16_t			bufsize;
165335863739SMike Smith     struct aac_adapter_info	*info;
165435863739SMike Smith     u_int8_t			arg;
165535863739SMike Smith 
165635863739SMike Smith     debug_called(2);
165735863739SMike Smith 
165835863739SMike Smith     arg = 0;
1659c6eafcf2SScott Long     if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf,
1660c6eafcf2SScott Long 		     &bufsize)) {
166135863739SMike Smith 	device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
166235863739SMike Smith 	return;
166335863739SMike Smith     }
166435863739SMike Smith     if (bufsize != sizeof(*info)) {
1665c6eafcf2SScott Long 	device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data "
1666c6eafcf2SScott Long 		      "size (%d != %d)\n", bufsize, sizeof(*info));
16670b94a66eSMike Smith 	/*return;*/
166835863739SMike Smith     }
166935863739SMike Smith     info = (struct aac_adapter_info *)&buf[0];
167035863739SMike Smith 
167135863739SMike Smith     device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n",
1672c6eafcf2SScott Long 		  aac_describe_code(aac_cpu_variant, info->CpuVariant),
1673c6eafcf2SScott Long 		  info->ClockSpeed, info->TotalMem / (1024 * 1024),
1674c6eafcf2SScott Long 		  aac_describe_code(aac_battery_platform,
1675c6eafcf2SScott Long 		  info->batteryPlatform), info->batteryPlatform);
167635863739SMike Smith 
167735863739SMike Smith     /* save the kernel revision structure for later use */
167835863739SMike Smith     sc->aac_revision = info->KernelRevision;
167935863739SMike Smith     device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n",
168035863739SMike Smith 		  info->KernelRevision.external.comp.major,
168135863739SMike Smith 		  info->KernelRevision.external.comp.minor,
168235863739SMike Smith 		  info->KernelRevision.external.comp.dash,
1683c6eafcf2SScott Long 		  info->SerialNumber);	/* XXX format? */
168435863739SMike Smith }
168535863739SMike Smith 
1686c6eafcf2SScott Long /******************************************************************************
168735863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
168835863739SMike Smith  * same.
168935863739SMike Smith  */
169035863739SMike Smith static char *
169135863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
169235863739SMike Smith {
169335863739SMike Smith     int		i;
169435863739SMike Smith 
169535863739SMike Smith     for (i = 0; table[i].string != NULL; i++)
169635863739SMike Smith 	if (table[i].code == code)
169735863739SMike Smith 	    return(table[i].string);
169835863739SMike Smith     return(table[i + 1].string);
169935863739SMike Smith }
170035863739SMike Smith 
170135863739SMike Smith /*****************************************************************************
170235863739SMike Smith  *****************************************************************************
170335863739SMike Smith 				Management Interface
170435863739SMike Smith  *****************************************************************************
170535863739SMike Smith  *****************************************************************************/
170635863739SMike Smith 
170735863739SMike Smith static int
170835863739SMike Smith aac_open(dev_t dev, int flags, int fmt, struct proc *p)
170935863739SMike Smith {
171035863739SMike Smith     struct aac_softc	*sc = dev->si_drv1;
171135863739SMike Smith 
171235863739SMike Smith     debug_called(2);
171335863739SMike Smith 
171435863739SMike Smith     /* Check to make sure the device isn't already open */
171535863739SMike Smith     if (sc->aac_state & AAC_STATE_OPEN) {
171635863739SMike Smith         return EBUSY;
171735863739SMike Smith     }
171835863739SMike Smith     sc->aac_state |= AAC_STATE_OPEN;
171935863739SMike Smith 
172035863739SMike Smith     return 0;
172135863739SMike Smith }
172235863739SMike Smith 
172335863739SMike Smith static int
172435863739SMike Smith aac_close(dev_t dev, int flags, int fmt, struct proc *p)
172535863739SMike Smith {
172635863739SMike Smith     struct aac_softc	*sc = dev->si_drv1;
172735863739SMike Smith 
172835863739SMike Smith     debug_called(2);
172935863739SMike Smith 
173035863739SMike Smith     /* Mark this unit as no longer open  */
173135863739SMike Smith     sc->aac_state &= ~AAC_STATE_OPEN;
173235863739SMike Smith 
173335863739SMike Smith     return 0;
173435863739SMike Smith }
173535863739SMike Smith 
173635863739SMike Smith static int
173735863739SMike Smith aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
173835863739SMike Smith {
17390b94a66eSMike Smith     union aac_statrequest	*as = (union aac_statrequest *)arg;
174035863739SMike Smith     struct aac_softc		*sc = dev->si_drv1;
17410b94a66eSMike Smith     int				error = 0;
17420b94a66eSMike Smith #ifdef AAC_COMPAT_LINUX
17430b94a66eSMike Smith     int				i;
17440b94a66eSMike Smith #endif
174535863739SMike Smith 
174635863739SMike Smith     debug_called(2);
174735863739SMike Smith 
174835863739SMike Smith     switch (cmd) {
17490b94a66eSMike Smith     case AACIO_STATS:
17500b94a66eSMike Smith 	switch (as->as_item) {
17510b94a66eSMike Smith 	case AACQ_FREE:
17520b94a66eSMike Smith 	case AACQ_BIO:
17530b94a66eSMike Smith 	case AACQ_READY:
17540b94a66eSMike Smith 	case AACQ_BUSY:
17550b94a66eSMike Smith 	case AACQ_COMPLETE:
1756c6eafcf2SScott Long 	    bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
1757c6eafcf2SScott Long 		  sizeof(struct aac_qstat));
17580b94a66eSMike Smith 	    break;
17590b94a66eSMike Smith 	default:
17600b94a66eSMike Smith 	    error = ENOENT;
17610b94a66eSMike Smith 	    break;
17620b94a66eSMike Smith 	}
17630b94a66eSMike Smith 	break;
17640b94a66eSMike Smith 
176535863739SMike Smith #ifdef AAC_COMPAT_LINUX
176635863739SMike Smith     case FSACTL_SENDFIB:
17670b94a66eSMike Smith 	debug(1, "FSACTL_SENDFIB");
176835863739SMike Smith 	error = aac_ioctl_sendfib(sc, arg);
176935863739SMike Smith 	break;
177035863739SMike Smith     case FSACTL_AIF_THREAD:
17710b94a66eSMike Smith 	debug(1, "FSACTL_AIF_THREAD");
177235863739SMike Smith 	error = EINVAL;
177335863739SMike Smith 	break;
177435863739SMike Smith     case FSACTL_OPEN_GET_ADAPTER_FIB:
17750b94a66eSMike Smith 	debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
177635863739SMike Smith 	/*
177735863739SMike Smith 	 * Pass the caller out an AdapterFibContext.
177835863739SMike Smith 	 *
177935863739SMike Smith 	 * Note that because we only support one opener, we
178035863739SMike Smith 	 * basically ignore this.  Set the caller's context to a magic
178135863739SMike Smith 	 * number just in case.
17820b94a66eSMike Smith 	 *
17830b94a66eSMike Smith 	 * The Linux code hands the driver a pointer into kernel space,
17840b94a66eSMike Smith 	 * and then trusts it when the caller hands it back.  Aiee!
178535863739SMike Smith 	 */
178635863739SMike Smith 	i = AAC_AIF_SILLYMAGIC;
178735863739SMike Smith 	error = copyout(&i, arg, sizeof(i));
178835863739SMike Smith 	break;
178935863739SMike Smith     case FSACTL_GET_NEXT_ADAPTER_FIB:
17900b94a66eSMike Smith 	debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
179135863739SMike Smith 	error = aac_linux_getnext_aif(sc, arg);
179235863739SMike Smith 	break;
179335863739SMike Smith     case FSACTL_CLOSE_GET_ADAPTER_FIB:
17940b94a66eSMike Smith 	debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
179535863739SMike Smith 	/* don't do anything here */
179635863739SMike Smith 	break;
179735863739SMike Smith     case FSACTL_MINIPORT_REV_CHECK:
17980b94a66eSMike Smith 	debug(1, "FSACTL_MINIPORT_REV_CHECK");
179935863739SMike Smith 	error = aac_linux_rev_check(sc, arg);
180035863739SMike Smith 	break;
180135863739SMike Smith #endif
180235863739SMike Smith     default:
180335863739SMike Smith 	device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd);
180435863739SMike Smith 	error = EINVAL;
180535863739SMike Smith 	break;
180635863739SMike Smith     }
180735863739SMike Smith     return(error);
180835863739SMike Smith }
180935863739SMike Smith 
1810c6eafcf2SScott Long /******************************************************************************
181135863739SMike Smith  * Send a FIB supplied from userspace
181235863739SMike Smith  */
181335863739SMike Smith static int
181435863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
181535863739SMike Smith {
181635863739SMike Smith     struct aac_command 	*cm;
181735863739SMike Smith     int			size, error;
181835863739SMike Smith 
181935863739SMike Smith     debug_called(2);
182035863739SMike Smith 
182135863739SMike Smith     cm = NULL;
182235863739SMike Smith 
182335863739SMike Smith     /*
182435863739SMike Smith      * Get a command
182535863739SMike Smith      */
182635863739SMike Smith     if (aac_alloc_command(sc, &cm)) {
182735863739SMike Smith 	error = EBUSY;
182835863739SMike Smith 	goto out;
182935863739SMike Smith     }
183035863739SMike Smith 
183135863739SMike Smith     /*
183235863739SMike Smith      * Fetch the FIB header, then re-copy to get data as well.
183335863739SMike Smith      */
183435863739SMike Smith     if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0)
183535863739SMike Smith 	goto out;
183635863739SMike Smith     size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
183735863739SMike Smith     if (size > sizeof(struct aac_fib)) {
1838c6eafcf2SScott Long 	device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size,
1839c6eafcf2SScott Long 		      sizeof(struct aac_fib));
184035863739SMike Smith 	size = sizeof(struct aac_fib);
184135863739SMike Smith     }
184235863739SMike Smith     if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
184335863739SMike Smith 	goto out;
184435863739SMike Smith     cm->cm_fib->Header.Size = size;
184535863739SMike Smith 
184635863739SMike Smith     /*
184735863739SMike Smith      * Pass the FIB to the controller, wait for it to complete.
184835863739SMike Smith      */
184935863739SMike Smith     if ((error = aac_wait_command(cm, 30)) != 0)	/* XXX user timeout? */
185035863739SMike Smith 	goto out;
185135863739SMike Smith 
185235863739SMike Smith     /*
185335863739SMike Smith      * Copy the FIB and data back out to the caller.
185435863739SMike Smith      */
185535863739SMike Smith     size = cm->cm_fib->Header.Size;
185635863739SMike Smith     if (size > sizeof(struct aac_fib)) {
1857c6eafcf2SScott Long 	device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size,
1858c6eafcf2SScott Long 		      sizeof(struct aac_fib));
185935863739SMike Smith 	size = sizeof(struct aac_fib);
186035863739SMike Smith     }
186135863739SMike Smith     error = copyout(cm->cm_fib, ufib, size);
186235863739SMike Smith 
186335863739SMike Smith out:
186435863739SMike Smith     if (cm != NULL)
186535863739SMike Smith 	aac_release_command(cm);
186635863739SMike Smith     return(error);
186735863739SMike Smith }
186835863739SMike Smith 
1869c6eafcf2SScott Long /******************************************************************************
187035863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
187135863739SMike Smith  *
187235863739SMike Smith  * XXX what's the right thing to do here when the queue is full?  Drop the older
187335863739SMike Smith  * or newer entries?
187435863739SMike Smith  */
187535863739SMike Smith static void
187635863739SMike Smith aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif)
187735863739SMike Smith {
187835863739SMike Smith     int		next, s;
187935863739SMike Smith 
188035863739SMike Smith     debug_called(2);
188135863739SMike Smith 
188235863739SMike Smith     s = splbio();
188335863739SMike Smith     next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
188435863739SMike Smith     if (next != sc->aac_aifq_tail) {
188535863739SMike Smith 	bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
188635863739SMike Smith 	sc->aac_aifq_head = next;
188735863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
188835863739SMike Smith 	    wakeup(sc->aac_aifq);
188935863739SMike Smith     }
189035863739SMike Smith     splx(s);
189135863739SMike Smith     aac_print_aif(sc, aif);
189235863739SMike Smith }
189335863739SMike Smith 
1894c6eafcf2SScott Long /******************************************************************************
1895c6eafcf2SScott Long  ******************************************************************************
189635863739SMike Smith 			Linux Management Interface
1897c6eafcf2SScott Long  ******************************************************************************
1898c6eafcf2SScott Long  ******************************************************************************/
189935863739SMike Smith 
190035863739SMike Smith #ifdef AAC_COMPAT_LINUX
190135863739SMike Smith 
190230d57611SMike Smith #include <sys/proc.h>
190335863739SMike Smith #include <machine/../linux/linux.h>
190435863739SMike Smith #include <machine/../linux/linux_proto.h>
190535863739SMike Smith #include <compat/linux/linux_ioctl.h>
190635863739SMike Smith 
190735863739SMike Smith #define AAC_LINUX_IOCTL_MIN  0x2000
190835863739SMike Smith #define AAC_LINUX_IOCTL_MAX  0x21ff
190935863739SMike Smith 
191035863739SMike Smith static linux_ioctl_function_t aac_linux_ioctl;
1911c6eafcf2SScott Long static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl,
1912c6eafcf2SScott Long 						AAC_LINUX_IOCTL_MIN,
1913c6eafcf2SScott Long 						AAC_LINUX_IOCTL_MAX};
191435863739SMike Smith 
1915c6eafcf2SScott Long SYSINIT  (aac_register,   SI_SUB_KLD, SI_ORDER_MIDDLE,
1916c6eafcf2SScott Long 	  linux_ioctl_register_handler, &aac_handler);
1917c6eafcf2SScott Long SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
1918c6eafcf2SScott Long 	  linux_ioctl_unregister_handler, &aac_handler);
191935863739SMike Smith 
192035863739SMike Smith MODULE_DEPEND(aac, linux, 1, 1, 1);
192135863739SMike Smith 
192235863739SMike Smith static int
192335863739SMike Smith aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
192435863739SMike Smith {
192535863739SMike Smith     struct file		*fp = p->p_fd->fd_ofiles[args->fd];
192635863739SMike Smith     u_long		cmd = args->cmd;
192735863739SMike Smith 
192835863739SMike Smith     /*
192935863739SMike Smith      * Pass the ioctl off to our standard handler.
193035863739SMike Smith      */
193135863739SMike Smith     return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p));
193235863739SMike Smith }
193335863739SMike Smith 
1934c6eafcf2SScott Long /******************************************************************************
19350b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
193635863739SMike Smith  * userspace app is possibly compatible.  This is extremely bogus right now
193735863739SMike Smith  * because I have no idea how to handle the versioning of this driver.  It is
193835863739SMike Smith  * needed, though, to get aaccli working.
193935863739SMike Smith  */
194035863739SMike Smith static int
194135863739SMike Smith aac_linux_rev_check(struct aac_softc *sc, caddr_t udata)
194235863739SMike Smith {
194335863739SMike Smith     struct aac_rev_check	rev_check;
194435863739SMike Smith     struct aac_rev_check_resp	rev_check_resp;
194535863739SMike Smith     int				error = 0;
194635863739SMike Smith 
194735863739SMike Smith     debug_called(2);
194835863739SMike Smith 
194935863739SMike Smith     /*
195035863739SMike Smith      * Copyin the revision struct from userspace
195135863739SMike Smith      */
1952c6eafcf2SScott Long     if ((error = copyin(udata, (caddr_t)&rev_check,
1953c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
195435863739SMike Smith 	return error;
195535863739SMike Smith     }
195635863739SMike Smith 
195735863739SMike Smith     debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber);
195835863739SMike Smith 
195935863739SMike Smith     /*
196035863739SMike Smith      * Doctor up the response struct.
196135863739SMike Smith      */
196235863739SMike Smith     rev_check_resp.possiblyCompatible = 1;
196335863739SMike Smith     rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul;
196435863739SMike Smith     rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber;
196535863739SMike Smith 
1966c6eafcf2SScott Long     return(copyout((caddr_t)&rev_check_resp, udata,
1967c6eafcf2SScott Long 		   sizeof(struct aac_rev_check_resp)));
196835863739SMike Smith }
196935863739SMike Smith 
1970c6eafcf2SScott Long /******************************************************************************
197135863739SMike Smith  * Pass the caller the next AIF in their queue
197235863739SMike Smith  */
197335863739SMike Smith static int
197435863739SMike Smith aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg)
197535863739SMike Smith {
197635863739SMike Smith     struct get_adapter_fib_ioctl	agf;
197735863739SMike Smith     int					error, s;
197835863739SMike Smith 
197935863739SMike Smith     debug_called(2);
198035863739SMike Smith 
198135863739SMike Smith     if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
198235863739SMike Smith 
198335863739SMike Smith 	/*
198435863739SMike Smith 	 * Check the magic number that we gave the caller.
198535863739SMike Smith 	 */
198635863739SMike Smith 	if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) {
198735863739SMike Smith 	    error = EFAULT;
198835863739SMike Smith 	} else {
198935863739SMike Smith 
199035863739SMike Smith 	    s = splbio();
19910b94a66eSMike Smith 	    error = aac_linux_return_aif(sc, agf.AifFib);
199235863739SMike Smith 
199335863739SMike Smith 	    if ((error == EAGAIN) && (agf.Wait)) {
199435863739SMike Smith 		sc->aac_state |= AAC_STATE_AIF_SLEEPER;
199535863739SMike Smith 		while (error == EAGAIN) {
199635863739SMike Smith 		    error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0);
199735863739SMike Smith 		    if (error == 0)
19980b94a66eSMike Smith 			error = aac_linux_return_aif(sc, agf.AifFib);
199935863739SMike Smith 		}
200035863739SMike Smith 		sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
200135863739SMike Smith 	    }
200235863739SMike Smith 	    splx(s);
200335863739SMike Smith 	}
200435863739SMike Smith     }
200535863739SMike Smith     return(error);
200635863739SMike Smith }
200735863739SMike Smith 
2008c6eafcf2SScott Long /******************************************************************************
20090b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
20100b94a66eSMike Smith  */
20110b94a66eSMike Smith static int
20120b94a66eSMike Smith aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr)
20130b94a66eSMike Smith {
20140b94a66eSMike Smith     int		error, s;
20150b94a66eSMike Smith 
20160b94a66eSMike Smith     debug_called(2);
20170b94a66eSMike Smith 
20180b94a66eSMike Smith     s = splbio();
20190b94a66eSMike Smith     if (sc->aac_aifq_tail == sc->aac_aifq_head) {
20200b94a66eSMike Smith 	error = EAGAIN;
20210b94a66eSMike Smith     } else {
2022c6eafcf2SScott Long 	error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
2023c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
20240b94a66eSMike Smith 	if (!error)
20250b94a66eSMike Smith 	    sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
20260b94a66eSMike Smith     }
20270b94a66eSMike Smith     splx(s);
20280b94a66eSMike Smith     return(error);
20290b94a66eSMike Smith }
20300b94a66eSMike Smith 
20310b94a66eSMike Smith 
203235863739SMike Smith #endif /* AAC_COMPAT_LINUX */
2033