xref: /freebsd/sys/dev/aac/aac.c (revision 157fbb2e83600e3047201ac8428af61d3c08bd2e)
135863739SMike Smith /*-
235863739SMike Smith  * Copyright (c) 2000 Michael Smith
335863739SMike Smith  * Copyright (c) 2000 BSDi
435863739SMike Smith  * All rights reserved.
535863739SMike Smith  *
635863739SMike Smith  * Redistribution and use in source and binary forms, with or without
735863739SMike Smith  * modification, are permitted provided that the following conditions
835863739SMike Smith  * are met:
935863739SMike Smith  * 1. Redistributions of source code must retain the above copyright
1035863739SMike Smith  *    notice, this list of conditions and the following disclaimer.
1135863739SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1235863739SMike Smith  *    notice, this list of conditions and the following disclaimer in the
1335863739SMike Smith  *    documentation and/or other materials provided with the distribution.
1435863739SMike Smith  *
1535863739SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1635863739SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1735863739SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1835863739SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1935863739SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2035863739SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2135863739SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2235863739SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2335863739SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2435863739SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2535863739SMike Smith  * SUCH DAMAGE.
2635863739SMike Smith  *
2735863739SMike Smith  *	$FreeBSD$
2835863739SMike Smith  */
2935863739SMike Smith 
3035863739SMike Smith /*
3135863739SMike Smith  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3235863739SMike Smith  */
3335863739SMike Smith 
3435863739SMike Smith #include <sys/param.h>
3535863739SMike Smith #include <sys/systm.h>
3635863739SMike Smith #include <sys/malloc.h>
3735863739SMike Smith #include <sys/kernel.h>
3835863739SMike Smith 
3935863739SMike Smith #include <dev/aac/aac_compat.h>
4035863739SMike Smith 
4135863739SMike Smith #include <sys/bus.h>
4235863739SMike Smith #include <sys/conf.h>
4335863739SMike Smith #include <sys/devicestat.h>
4435863739SMike Smith #include <sys/disk.h>
4535863739SMike Smith #include <sys/file.h>
4635863739SMike Smith #include <sys/signalvar.h>
470b94a66eSMike Smith #include <sys/time.h>
4835863739SMike Smith 
4935863739SMike Smith #include <machine/bus_memio.h>
5035863739SMike Smith #include <machine/bus.h>
5135863739SMike Smith #include <machine/resource.h>
5235863739SMike Smith 
5335863739SMike Smith #include <dev/aac/aacreg.h>
540b94a66eSMike Smith #include <dev/aac/aac_ioctl.h>
5535863739SMike Smith #include <dev/aac/aacvar.h>
5635863739SMike Smith #include <dev/aac/aac_tables.h>
5735863739SMike Smith 
5835863739SMike Smith devclass_t	aac_devclass;
5935863739SMike Smith 
6035863739SMike Smith static void	aac_startup(void *arg);
6135863739SMike Smith 
6235863739SMike Smith /* Command Processing */
6335863739SMike Smith static void	aac_startio(struct aac_softc *sc);
640b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
6535863739SMike Smith static int	aac_start(struct aac_command *cm);
6635863739SMike Smith static void	aac_complete(void *context, int pending);
6735863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
6835863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
6935863739SMike Smith static int	aac_wait_command(struct aac_command *cm, int timeout);
7035863739SMike Smith static void	aac_host_command(struct aac_softc *sc);
7135863739SMike Smith static void	aac_host_response(struct aac_softc *sc);
7235863739SMike Smith 
7335863739SMike Smith /* Command Buffer Management */
7435863739SMike Smith static int	aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp);
7535863739SMike Smith static void	aac_release_command(struct aac_command *cm);
760b94a66eSMike Smith static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
770b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
780b94a66eSMike Smith static void	aac_free_commands(struct aac_softc *sc);
7935863739SMike Smith static void	aac_map_command(struct aac_command *cm);
8035863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
8135863739SMike Smith 
8235863739SMike Smith /* Hardware Interface */
8335863739SMike Smith static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error);
8435863739SMike Smith static int	aac_init(struct aac_softc *sc);
8535863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
8635863739SMike Smith 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
8735863739SMike Smith 				 u_int32_t *sp);
8835863739SMike Smith static int	aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
8935863739SMike Smith 			     void *data, u_int16_t datasize,
9035863739SMike Smith 			     void *result, u_int16_t *resultsize);
9135863739SMike Smith static int	aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size, u_int32_t fib_addr);
9235863739SMike Smith static int	aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, struct aac_fib **fib_addr);
9335863739SMike Smith 
9435863739SMike Smith /* StrongARM interface */
9535863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
9635863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
9735863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
9835863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
9935863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
10035863739SMike Smith 				   u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3);
10135863739SMike Smith static int	aac_sa_get_mailboxstatus(struct aac_softc *sc);
10235863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
10335863739SMike Smith 
10435863739SMike Smith struct aac_interface aac_sa_interface = {
10535863739SMike Smith     aac_sa_get_fwstatus,
10635863739SMike Smith     aac_sa_qnotify,
10735863739SMike Smith     aac_sa_get_istatus,
10835863739SMike Smith     aac_sa_clear_istatus,
10935863739SMike Smith     aac_sa_set_mailbox,
11035863739SMike Smith     aac_sa_get_mailboxstatus,
11135863739SMike Smith     aac_sa_set_interrupts
11235863739SMike Smith };
11335863739SMike Smith 
11435863739SMike Smith /* i960Rx interface */
11535863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
11635863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
11735863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
11835863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
11935863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
12035863739SMike Smith 				   u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3);
12135863739SMike Smith static int	aac_rx_get_mailboxstatus(struct aac_softc *sc);
12235863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
12335863739SMike Smith 
12435863739SMike Smith struct aac_interface aac_rx_interface = {
12535863739SMike Smith     aac_rx_get_fwstatus,
12635863739SMike Smith     aac_rx_qnotify,
12735863739SMike Smith     aac_rx_get_istatus,
12835863739SMike Smith     aac_rx_clear_istatus,
12935863739SMike Smith     aac_rx_set_mailbox,
13035863739SMike Smith     aac_rx_get_mailboxstatus,
13135863739SMike Smith     aac_rx_set_interrupts
13235863739SMike Smith };
13335863739SMike Smith 
13435863739SMike Smith /* Debugging and Diagnostics */
13535863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
13635863739SMike Smith static char	*aac_describe_code(struct aac_code_lookup *table, u_int32_t code);
13735863739SMike Smith 
13835863739SMike Smith /* Management Interface */
13935863739SMike Smith static d_open_t		aac_open;
14035863739SMike Smith static d_close_t	aac_close;
14135863739SMike Smith static d_ioctl_t	aac_ioctl;
14265baa27cSJohn Baldwin static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) __unused;
14335863739SMike Smith static void		aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif);
14435863739SMike Smith #ifdef AAC_COMPAT_LINUX
14535863739SMike Smith static int		aac_linux_rev_check(struct aac_softc *sc, caddr_t udata);
14635863739SMike Smith static int		aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg);
1470b94a66eSMike Smith static int		aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr);
14835863739SMike Smith #endif
14935863739SMike Smith 
15035863739SMike Smith #define AAC_CDEV_MAJOR	150
15135863739SMike Smith 
15235863739SMike Smith static struct cdevsw aac_cdevsw = {
15335863739SMike Smith     aac_open,		/* open */
15435863739SMike Smith     aac_close,		/* close */
15535863739SMike Smith     noread,		/* read */
15635863739SMike Smith     nowrite,		/* write */
15735863739SMike Smith     aac_ioctl,		/* ioctl */
15835863739SMike Smith     nopoll,		/* poll */
15935863739SMike Smith     nommap,		/* mmap */
16035863739SMike Smith     nostrategy,		/* strategy */
16135863739SMike Smith     "aac",		/* name */
16235863739SMike Smith     AAC_CDEV_MAJOR,	/* major */
16335863739SMike Smith     nodump,		/* dump */
16435863739SMike Smith     nopsize,		/* psize */
16535863739SMike Smith     0,			/* flags */
16635863739SMike Smith     -1,			/* bmaj */
16735863739SMike Smith };
16835863739SMike Smith 
16935863739SMike Smith /********************************************************************************
17035863739SMike Smith  ********************************************************************************
17135863739SMike Smith                                                                  Device Interface
17235863739SMike Smith  ********************************************************************************
17335863739SMike Smith  ********************************************************************************/
17435863739SMike Smith 
17535863739SMike Smith /********************************************************************************
17635863739SMike Smith  * Initialise the controller and softc
17735863739SMike Smith  */
17835863739SMike Smith int
17935863739SMike Smith aac_attach(struct aac_softc *sc)
18035863739SMike Smith {
18135863739SMike Smith     int		error, unit;
18235863739SMike Smith 
18335863739SMike Smith     debug_called(1);
18435863739SMike Smith 
18535863739SMike Smith     /*
18635863739SMike Smith      * Initialise per-controller queues.
18735863739SMike Smith      */
1880b94a66eSMike Smith     aac_initq_free(sc);
1890b94a66eSMike Smith     aac_initq_ready(sc);
1900b94a66eSMike Smith     aac_initq_busy(sc);
1910b94a66eSMike Smith     aac_initq_complete(sc);
1920b94a66eSMike Smith     aac_initq_bio(sc);
19335863739SMike Smith 
19435863739SMike Smith #if __FreeBSD_version >= 500005
19535863739SMike Smith     /*
19635863739SMike Smith      * Initialise command-completion task.
19735863739SMike Smith      */
19835863739SMike Smith     TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
19935863739SMike Smith #endif
20035863739SMike Smith 
20135863739SMike Smith     /* disable interrupts before we enable anything */
20235863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
20335863739SMike Smith 
20435863739SMike Smith     /* mark controller as suspended until we get ourselves organised */
20535863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
20635863739SMike Smith 
20735863739SMike Smith     /*
2080b94a66eSMike Smith      * Allocate command structures.
2090b94a66eSMike Smith      */
2100b94a66eSMike Smith     if ((error = aac_alloc_commands(sc)) != 0)
2110b94a66eSMike Smith 	return(error);
2120b94a66eSMike Smith 
2130b94a66eSMike Smith     /*
21435863739SMike Smith      * Initialise the adapter.
21535863739SMike Smith      */
2160b94a66eSMike Smith     if ((error = aac_init(sc)) != 0)
21735863739SMike Smith 	return(error);
21835863739SMike Smith 
21935863739SMike Smith     /*
22035863739SMike Smith      * Print a little information about the controller.
22135863739SMike Smith      */
22235863739SMike Smith     aac_describe_controller(sc);
22335863739SMike Smith 
22435863739SMike Smith     /*
22535863739SMike Smith      * Register to probe our containers later.
22635863739SMike Smith      */
22735863739SMike Smith     sc->aac_ich.ich_func = aac_startup;
22835863739SMike Smith     sc->aac_ich.ich_arg = sc;
22935863739SMike Smith     if (config_intrhook_establish(&sc->aac_ich) != 0) {
23035863739SMike Smith         device_printf(sc->aac_dev, "can't establish configuration hook\n");
23135863739SMike Smith         return(ENXIO);
23235863739SMike Smith     }
23335863739SMike Smith 
23435863739SMike Smith     /*
23535863739SMike Smith      * Make the control device.
23635863739SMike Smith      */
23735863739SMike Smith     unit = device_get_unit(sc->aac_dev);
23835863739SMike Smith     sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644, "aac%d", unit);
239157fbb2eSScott Long     (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
240157fbb2eSScott Long 
24135863739SMike Smith     sc->aac_dev_t->si_drv1 = sc;
24235863739SMike Smith 
24335863739SMike Smith     return(0);
24435863739SMike Smith }
24535863739SMike Smith 
24635863739SMike Smith /********************************************************************************
24735863739SMike Smith  * Probe for containers, create disks.
24835863739SMike Smith  */
24935863739SMike Smith static void
25035863739SMike Smith aac_startup(void *arg)
25135863739SMike Smith {
25235863739SMike Smith     struct aac_softc		*sc = (struct aac_softc *)arg;
25335863739SMike Smith     struct aac_mntinfo		mi;
25435863739SMike Smith     struct aac_mntinforesponse	mir;
25535863739SMike Smith     device_t			child;
25635863739SMike Smith     u_int16_t			rsize;
25735863739SMike Smith     int				i;
25835863739SMike Smith 
25935863739SMike Smith     debug_called(1);
26035863739SMike Smith 
26135863739SMike Smith     /* disconnect ourselves from the intrhook chain */
26235863739SMike Smith     config_intrhook_disestablish(&sc->aac_ich);
26335863739SMike Smith 
26435863739SMike Smith     /* loop over possible containers */
26535863739SMike Smith     mi.Command = VM_NameServe;
26635863739SMike Smith     mi.MntType = FT_FILESYS;
26735863739SMike Smith     for (i = 0; i < AAC_MAX_CONTAINERS; i++) {
26835863739SMike Smith 	/* request information on this container */
26935863739SMike Smith 	mi.MntCount = i;
27035863739SMike Smith 	if (aac_sync_fib(sc, ContainerCommand, 0, &mi, sizeof(struct aac_mntinfo), &mir, &rsize)) {
27135863739SMike Smith 	    debug(2, "error probing container %d", i);
27235863739SMike Smith 	    continue;
27335863739SMike Smith 	}
27435863739SMike Smith 	/* check response size */
27535863739SMike Smith 	if (rsize != sizeof(mir)) {
276bb9f4664SScott Long 	    debug(2, "container info response wrong size (%d should be %d)", rsize, sizeof(mir));
27735863739SMike Smith 	    continue;
27835863739SMike Smith 	}
27935863739SMike Smith 	/*
28035863739SMike Smith 	 * Check container volume type for validity.  Note that many of the possible types
28135863739SMike Smith 	 * may never show up.
28235863739SMike Smith 	 */
28335863739SMike Smith 	if ((mir.Status == ST_OK) && (mir.MntTable[0].VolType != CT_NONE)) {
28435863739SMike Smith 	    debug(1, "%d: id %x  name '%.16s'  size %u  type %d",
28535863739SMike Smith 		  i, mir.MntTable[0].ObjectId,
28635863739SMike Smith 		  mir.MntTable[0].FileSystemName, mir.MntTable[0].Capacity,
28735863739SMike Smith 		  mir.MntTable[0].VolType);
28835863739SMike Smith 
28935863739SMike Smith 	    if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL) {
29035863739SMike Smith 		device_printf(sc->aac_dev, "device_add_child failed\n");
29135863739SMike Smith 	    } else {
29235863739SMike Smith 		device_set_ivars(child, &sc->aac_container[i]);
29335863739SMike Smith 	    }
29435863739SMike Smith 	    device_set_desc(child, aac_describe_code(aac_container_types, mir.MntTable[0].VolType));
29535863739SMike Smith 	    sc->aac_container[i].co_disk = child;
29635863739SMike Smith 	    sc->aac_container[i].co_mntobj = mir.MntTable[0];
29735863739SMike Smith 	}
29835863739SMike Smith     }
29935863739SMike Smith 
30035863739SMike Smith     /* poke the bus to actually attach the child devices */
30135863739SMike Smith     if (bus_generic_attach(sc->aac_dev))
30235863739SMike Smith 	device_printf(sc->aac_dev, "bus_generic_attach failed\n");
30335863739SMike Smith 
30435863739SMike Smith     /* mark the controller up */
30535863739SMike Smith     sc->aac_state &= ~AAC_STATE_SUSPEND;
30635863739SMike Smith 
30735863739SMike Smith     /* enable interrupts now */
30835863739SMike Smith     AAC_UNMASK_INTERRUPTS(sc);
3090b94a66eSMike Smith 
3100b94a66eSMike Smith     /* enable the timeout watchdog */
3110b94a66eSMike Smith     timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
31235863739SMike Smith }
31335863739SMike Smith 
31435863739SMike Smith /********************************************************************************
31535863739SMike Smith  * Free all of the resources associated with (sc)
31635863739SMike Smith  *
31735863739SMike Smith  * Should not be called if the controller is active.
31835863739SMike Smith  */
31935863739SMike Smith void
32035863739SMike Smith aac_free(struct aac_softc *sc)
32135863739SMike Smith {
32235863739SMike Smith     debug_called(1);
32335863739SMike Smith 
32435863739SMike Smith     /* remove the control device */
32535863739SMike Smith     if (sc->aac_dev_t != NULL)
32635863739SMike Smith 	destroy_dev(sc->aac_dev_t);
32735863739SMike Smith 
3280b94a66eSMike Smith     /* throw away any FIB buffers, discard the FIB DMA tag */
3290b94a66eSMike Smith     if (sc->aac_fibs != NULL)
3300b94a66eSMike Smith 	aac_free_commands(sc);
3310b94a66eSMike Smith     if (sc->aac_fib_dmat)
3320b94a66eSMike Smith 	bus_dma_tag_destroy(sc->aac_fib_dmat);
33335863739SMike Smith 
33435863739SMike Smith     /* destroy the common area */
33535863739SMike Smith     if (sc->aac_common) {
33635863739SMike Smith 	bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
33735863739SMike Smith 	bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, sc->aac_common_dmamap);
33835863739SMike Smith     }
3390b94a66eSMike Smith     if (sc->aac_common_dmat)
3400b94a66eSMike Smith 	bus_dma_tag_destroy(sc->aac_common_dmat);
34135863739SMike Smith 
34235863739SMike Smith     /* disconnect the interrupt handler */
34335863739SMike Smith     if (sc->aac_intr)
34435863739SMike Smith 	bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
34535863739SMike Smith     if (sc->aac_irq != NULL)
34635863739SMike Smith 	bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, sc->aac_irq);
34735863739SMike Smith 
34835863739SMike Smith     /* destroy data-transfer DMA tag */
34935863739SMike Smith     if (sc->aac_buffer_dmat)
35035863739SMike Smith 	bus_dma_tag_destroy(sc->aac_buffer_dmat);
35135863739SMike Smith 
35235863739SMike Smith     /* destroy the parent DMA tag */
35335863739SMike Smith     if (sc->aac_parent_dmat)
35435863739SMike Smith 	bus_dma_tag_destroy(sc->aac_parent_dmat);
35535863739SMike Smith 
35635863739SMike Smith     /* release the register window mapping */
35735863739SMike Smith     if (sc->aac_regs_resource != NULL)
35835863739SMike Smith 	bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, sc->aac_regs_rid, sc->aac_regs_resource);
35935863739SMike Smith }
36035863739SMike Smith 
36135863739SMike Smith /********************************************************************************
36235863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
36335863739SMike Smith  */
36435863739SMike Smith int
36535863739SMike Smith aac_detach(device_t dev)
36635863739SMike Smith {
36735863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
36835863739SMike Smith     int			error;
36935863739SMike Smith 
37035863739SMike Smith     debug_called(1);
37135863739SMike Smith 
37235863739SMike Smith     if (sc->aac_state & AAC_STATE_OPEN)
37335863739SMike Smith 	return(EBUSY);
37435863739SMike Smith 
37535863739SMike Smith     if ((error = aac_shutdown(dev)))
37635863739SMike Smith 	return(error);
37735863739SMike Smith 
37835863739SMike Smith     aac_free(sc);
37935863739SMike Smith 
38035863739SMike Smith     return(0);
38135863739SMike Smith }
38235863739SMike Smith 
38335863739SMike Smith /********************************************************************************
38435863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
38535863739SMike Smith  *
38635863739SMike Smith  * This function is called before detach or system shutdown.
38735863739SMike Smith  *
3880b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
38935863739SMike Smith  * allow shutdown if any device is open.
39035863739SMike Smith  */
39135863739SMike Smith int
39235863739SMike Smith aac_shutdown(device_t dev)
39335863739SMike Smith {
39435863739SMike Smith     struct aac_softc		*sc = device_get_softc(dev);
39535863739SMike Smith     struct aac_close_command	cc;
39635863739SMike Smith     int				s, i;
39735863739SMike Smith 
39835863739SMike Smith     debug_called(1);
39935863739SMike Smith 
40035863739SMike Smith     s = splbio();
40135863739SMike Smith 
40235863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
40335863739SMike Smith 
40435863739SMike Smith     /*
40535863739SMike Smith      * Send a Container shutdown followed by a HostShutdown FIB to the
40635863739SMike Smith      * controller to convince it that we don't want to talk to it anymore.
40735863739SMike Smith      * We've been closed and all I/O completed already
40835863739SMike Smith      */
40935863739SMike Smith     device_printf(sc->aac_dev, "shutting down controller...");
41035863739SMike Smith 
41135863739SMike Smith     cc.Command = VM_CloseAll;
41235863739SMike Smith     cc.ContainerId = 0xffffffff;
41335863739SMike Smith     if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL)) {
41435863739SMike Smith 	printf("FAILED.\n");
41535863739SMike Smith     } else {
41635863739SMike Smith 	i = 0;
41735863739SMike Smith 	if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i, sizeof(i), NULL, NULL)) {
41835863739SMike Smith 	    printf("FAILED.\n");
41935863739SMike Smith 	} else {
42035863739SMike Smith 	    printf("done.\n");
42135863739SMike Smith 	}
42235863739SMike Smith     }
42335863739SMike Smith 
42435863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
42535863739SMike Smith 
42635863739SMike Smith     splx(s);
42735863739SMike Smith     return(0);
42835863739SMike Smith }
42935863739SMike Smith 
43035863739SMike Smith /********************************************************************************
43135863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
43235863739SMike Smith  */
43335863739SMike Smith int
43435863739SMike Smith aac_suspend(device_t dev)
43535863739SMike Smith {
43635863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
43735863739SMike Smith     int			s;
43835863739SMike Smith 
43935863739SMike Smith     debug_called(1);
44035863739SMike Smith     s = splbio();
44135863739SMike Smith 
44235863739SMike Smith     sc->aac_state |= AAC_STATE_SUSPEND;
44335863739SMike Smith 
44435863739SMike Smith     AAC_MASK_INTERRUPTS(sc);
44535863739SMike Smith     splx(s);
44635863739SMike Smith     return(0);
44735863739SMike Smith }
44835863739SMike Smith 
44935863739SMike Smith /********************************************************************************
45035863739SMike Smith  * Bring the controller back to a state ready for operation.
45135863739SMike Smith  */
45235863739SMike Smith int
45335863739SMike Smith aac_resume(device_t dev)
45435863739SMike Smith {
45535863739SMike Smith     struct aac_softc	*sc = device_get_softc(dev);
45635863739SMike Smith 
45735863739SMike Smith     debug_called(1);
45835863739SMike Smith     sc->aac_state &= ~AAC_STATE_SUSPEND;
45935863739SMike Smith     AAC_UNMASK_INTERRUPTS(sc);
46035863739SMike Smith     return(0);
46135863739SMike Smith }
46235863739SMike Smith 
46335863739SMike Smith /*******************************************************************************
46435863739SMike Smith  * Take an interrupt.
46535863739SMike Smith  */
46635863739SMike Smith void
46735863739SMike Smith aac_intr(void *arg)
46835863739SMike Smith {
46935863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
47035863739SMike Smith     u_int16_t		reason;
47135863739SMike Smith 
47235863739SMike Smith     debug_called(2);
47335863739SMike Smith 
47435863739SMike Smith     reason = AAC_GET_ISTATUS(sc);
47535863739SMike Smith 
47635863739SMike Smith     /* controller wants to talk to the log?  XXX should we defer this? */
47735863739SMike Smith     if (reason & AAC_DB_PRINTF) {
47835863739SMike Smith 	if (sc->aac_common->ac_printf[0]) {
47935863739SMike Smith 	    device_printf(sc->aac_dev, "** %.*s", AAC_PRINTF_BUFSIZE, sc->aac_common->ac_printf);
48035863739SMike Smith 	    sc->aac_common->ac_printf[0] = 0;
48135863739SMike Smith 	}
48235863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
48335863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_PRINTF);
48435863739SMike Smith     }
48535863739SMike Smith 
48635863739SMike Smith     /* controller has a message for us? */
48735863739SMike Smith     if (reason & AAC_DB_COMMAND_READY) {
48835863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
489da4c1ce3SJustin T. Gibbs 	aac_host_command(sc);
49035863739SMike Smith     }
49135863739SMike Smith 
49235863739SMike Smith     /* controller has a response for us? */
49335863739SMike Smith     if (reason & AAC_DB_RESPONSE_READY) {
49435863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
495da4c1ce3SJustin T. Gibbs 	aac_host_response(sc);
49635863739SMike Smith     }
49735863739SMike Smith 
49835863739SMike Smith     /* spurious interrupts that we don't use - reset the mask and clear the interrupts */
49935863739SMike Smith     if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
50035863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
50135863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL);
50235863739SMike Smith     }
50335863739SMike Smith };
50435863739SMike Smith 
50535863739SMike Smith /********************************************************************************
50635863739SMike Smith  ********************************************************************************
50735863739SMike Smith                                                                Command Processing
50835863739SMike Smith  ********************************************************************************
50935863739SMike Smith  ********************************************************************************/
51035863739SMike Smith 
51135863739SMike Smith /********************************************************************************
51235863739SMike Smith  * Start as much queued I/O as possible on the controller
51335863739SMike Smith  */
51435863739SMike Smith static void
51535863739SMike Smith aac_startio(struct aac_softc *sc)
51635863739SMike Smith {
51735863739SMike Smith     struct aac_command	*cm;
51835863739SMike Smith 
51935863739SMike Smith     debug_called(2);
52035863739SMike Smith 
52135863739SMike Smith     for(;;) {
52235863739SMike Smith 	/* try to get a command that's been put off for lack of resources */
52335863739SMike Smith 	cm = aac_dequeue_ready(sc);
52435863739SMike Smith 
52535863739SMike Smith 	/* try to build a command off the bio queue (ignore error return) */
5260b94a66eSMike Smith 	if (cm == NULL)
52735863739SMike Smith 	    aac_bio_command(sc, &cm);
52835863739SMike Smith 
52935863739SMike Smith 	/* nothing to do? */
53035863739SMike Smith 	if (cm == NULL)
53135863739SMike Smith 	    break;
53235863739SMike Smith 
53335863739SMike Smith 	/* try to give the command to the controller */
53435863739SMike Smith 	if (aac_start(cm) == EBUSY) {
53535863739SMike Smith 	    /* put it on the ready queue for later */
53635863739SMike Smith 	    aac_requeue_ready(cm);
53735863739SMike Smith 	    break;
53835863739SMike Smith 	}
53935863739SMike Smith     }
54035863739SMike Smith }
54135863739SMike Smith 
54235863739SMike Smith /********************************************************************************
54335863739SMike Smith  * Deliver a command to the controller; allocate controller resources at the
54435863739SMike Smith  * last moment when possible.
54535863739SMike Smith  */
54635863739SMike Smith static int
54735863739SMike Smith aac_start(struct aac_command *cm)
54835863739SMike Smith {
54935863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
550ed5c5fb4SMike Smith     int			error;
55135863739SMike Smith 
55235863739SMike Smith     debug_called(2);
55335863739SMike Smith 
55435863739SMike Smith     /* get the command mapped */
55535863739SMike Smith     aac_map_command(cm);
55635863739SMike Smith 
5570b94a66eSMike Smith     /* fix up the address values in the FIB */
55835863739SMike Smith     cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
55935863739SMike Smith     cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
56035863739SMike Smith 
56135863739SMike Smith     /* save a pointer to the command for speedy reverse-lookup */
5620b94a66eSMike Smith     cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical address issue */
56335863739SMike Smith 
56435863739SMike Smith     /* put the FIB on the outbound queue */
56535863739SMike Smith     if (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, cm->cm_fib->Header.Size,
5660b94a66eSMike Smith 			cm->cm_fib->Header.ReceiverFibAddress)) {
5670b94a66eSMike Smith 	error = EBUSY;
5680b94a66eSMike Smith     } else {
5690b94a66eSMike Smith 	aac_enqueue_busy(cm);
5700b94a66eSMike Smith 	error = 0;
5710b94a66eSMike Smith     }
5720b94a66eSMike Smith     return(error);
57335863739SMike Smith }
57435863739SMike Smith 
57535863739SMike Smith /********************************************************************************
57635863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
57735863739SMike Smith  */
57835863739SMike Smith static void
57935863739SMike Smith aac_host_command(struct aac_softc *sc)
58035863739SMike Smith {
58135863739SMike Smith     struct aac_fib	*fib;
58235863739SMike Smith     u_int32_t		fib_size;
58335863739SMike Smith 
58435863739SMike Smith     debug_called(1);
58535863739SMike Smith 
58635863739SMike Smith     for (;;) {
58735863739SMike Smith 	if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size, &fib))
58835863739SMike Smith 	    break;	/* nothing to do */
58935863739SMike Smith 
59035863739SMike Smith 	switch(fib->Header.Command) {
59135863739SMike Smith 	case AifRequest:
59235863739SMike Smith 	    aac_handle_aif(sc, (struct aac_aif_command *)&fib->data[0]);
59335863739SMike Smith 	    break;
59435863739SMike Smith 	default:
59535863739SMike Smith 	    device_printf(sc->aac_dev, "unknown command from controller\n");
59635863739SMike Smith 	    AAC_PRINT_FIB(sc, fib);
59735863739SMike Smith 	    break;
59835863739SMike Smith 	}
59935863739SMike Smith 
60035863739SMike Smith 	/* XXX reply to FIBs requesting responses ?? */
60135863739SMike Smith 	/* XXX how do we return these FIBs to the controller? */
60235863739SMike Smith     }
60335863739SMike Smith }
60435863739SMike Smith 
60535863739SMike Smith /********************************************************************************
60635863739SMike Smith  * Handle notification of one or more FIBs completed by the controller
60735863739SMike Smith  */
60835863739SMike Smith static void
60935863739SMike Smith aac_host_response(struct aac_softc *sc)
61035863739SMike Smith {
61135863739SMike Smith     struct aac_command	*cm;
61235863739SMike Smith     struct aac_fib	*fib;
61335863739SMike Smith     u_int32_t		fib_size;
61435863739SMike Smith 
61535863739SMike Smith     debug_called(2);
61635863739SMike Smith 
61735863739SMike Smith     for (;;) {
61835863739SMike Smith 	/* look for completed FIBs on our queue */
61935863739SMike Smith 	if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, &fib))
62035863739SMike Smith 	    break;	/* nothing to do */
62135863739SMike Smith 
62235863739SMike Smith 	/* get the command, unmap and queue for later processing */
62335863739SMike Smith 	cm = (struct aac_command *)fib->Header.SenderData;
62435863739SMike Smith 	if (cm == NULL) {
62535863739SMike Smith 	    AAC_PRINT_FIB(sc, fib);
62635863739SMike Smith 	} else {
6270b94a66eSMike Smith 	    aac_remove_busy(cm);
62835863739SMike Smith 	    aac_unmap_command(cm);		/* XXX defer? */
6290b94a66eSMike Smith 	    aac_enqueue_complete(cm);
63035863739SMike Smith 	}
63135863739SMike Smith     }
63235863739SMike Smith 
63335863739SMike Smith     /* handle completion processing */
63435863739SMike Smith #if __FreeBSD_version >= 500005
63535863739SMike Smith     taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
63635863739SMike Smith #else
63735863739SMike Smith     aac_complete(sc, 0);
63835863739SMike Smith #endif
63935863739SMike Smith }
64035863739SMike Smith 
64135863739SMike Smith /********************************************************************************
64235863739SMike Smith  * Process completed commands.
64335863739SMike Smith  */
64435863739SMike Smith static void
64535863739SMike Smith aac_complete(void *context, int pending)
64635863739SMike Smith {
64735863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)context;
64835863739SMike Smith     struct aac_command	*cm;
64935863739SMike Smith 
65035863739SMike Smith     debug_called(2);
65135863739SMike Smith 
65235863739SMike Smith     /* pull completed commands off the queue */
65335863739SMike Smith     for (;;) {
6540b94a66eSMike Smith 	cm = aac_dequeue_complete(sc);
65535863739SMike Smith 	if (cm == NULL)
6560b94a66eSMike Smith 	    break;
65735863739SMike Smith 	cm->cm_flags |= AAC_CMD_COMPLETED;
65835863739SMike Smith 
65935863739SMike Smith 	/* is there a completion handler? */
66035863739SMike Smith 	if (cm->cm_complete != NULL) {
66135863739SMike Smith 	    cm->cm_complete(cm);
66235863739SMike Smith 	} else {
66335863739SMike Smith 	    /* assume that someone is sleeping on this command */
66435863739SMike Smith 	    wakeup(cm);
66535863739SMike Smith 	}
66635863739SMike Smith     }
6670b94a66eSMike Smith 
6680b94a66eSMike Smith     /* see if we can start some more I/O */
6690b94a66eSMike Smith     aac_startio(sc);
67035863739SMike Smith }
67135863739SMike Smith 
67235863739SMike Smith /********************************************************************************
67335863739SMike Smith  * Handle a bio submitted from a disk device.
67435863739SMike Smith  */
67535863739SMike Smith void
67635863739SMike Smith aac_submit_bio(struct bio *bp)
67735863739SMike Smith {
67835863739SMike Smith     struct aac_disk	*ad = (struct aac_disk *)bp->bio_dev->si_drv1;
67935863739SMike Smith     struct aac_softc	*sc = ad->ad_controller;
68035863739SMike Smith 
68135863739SMike Smith     debug_called(2);
68235863739SMike Smith 
68335863739SMike Smith     /* queue the BIO and try to get some work done */
6840b94a66eSMike Smith     aac_enqueue_bio(sc, bp);
68535863739SMike Smith     aac_startio(sc);
68635863739SMike Smith }
68735863739SMike Smith 
68835863739SMike Smith /********************************************************************************
68935863739SMike Smith  * Get a bio and build a command to go with it.
69035863739SMike Smith  */
69135863739SMike Smith static int
69235863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
69335863739SMike Smith {
69435863739SMike Smith     struct aac_command		*cm;
69535863739SMike Smith     struct aac_fib		*fib;
69635863739SMike Smith     struct aac_blockread	*br;
69735863739SMike Smith     struct aac_blockwrite	*bw;
69835863739SMike Smith     struct aac_disk		*ad;
69935863739SMike Smith     struct bio			*bp;
70035863739SMike Smith 
70135863739SMike Smith     debug_called(2);
70235863739SMike Smith 
70335863739SMike Smith     /* get the resources we will need */
70435863739SMike Smith     cm = NULL;
7050b94a66eSMike Smith     if ((bp = aac_dequeue_bio(sc)) == NULL)
70635863739SMike Smith 	goto fail;
70735863739SMike Smith     if (aac_alloc_command(sc, &cm))	/* get a command */
70835863739SMike Smith 	goto fail;
70935863739SMike Smith 
71035863739SMike Smith     /* fill out the command */
7110b94a66eSMike Smith     cm->cm_data = (void *)bp->bio_data;
7120b94a66eSMike Smith     cm->cm_datalen = bp->bio_bcount;
7130b94a66eSMike Smith     cm->cm_complete = aac_bio_complete;
71435863739SMike Smith     cm->cm_private = bp;
7150b94a66eSMike Smith     cm->cm_timestamp = time_second;
71635863739SMike Smith 
71735863739SMike Smith     /* build the FIB */
71835863739SMike Smith     fib = cm->cm_fib;
71935863739SMike Smith     fib->Header.XferState =
72035863739SMike Smith 	AAC_FIBSTATE_HOSTOWNED   |
72135863739SMike Smith 	AAC_FIBSTATE_INITIALISED |
72235863739SMike Smith 	AAC_FIBSTATE_FROMHOST    |
72335863739SMike Smith 	AAC_FIBSTATE_REXPECTED   |
72435863739SMike Smith 	AAC_FIBSTATE_NORM;
72535863739SMike Smith     fib->Header.Command = ContainerCommand;
72635863739SMike Smith     fib->Header.Size = sizeof(struct aac_fib_header);
72735863739SMike Smith 
72835863739SMike Smith     /* build the read/write request */
72935863739SMike Smith     ad = (struct aac_disk *)bp->bio_dev->si_drv1;
73035863739SMike Smith     if (BIO_IS_READ(bp)) {
73135863739SMike Smith 	br = (struct aac_blockread *)&fib->data[0];
73235863739SMike Smith 	br->Command = VM_CtBlockRead;
73335863739SMike Smith 	br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
73435863739SMike Smith 	br->BlockNumber = bp->bio_pblkno;
73535863739SMike Smith 	br->ByteCount = bp->bio_bcount;
73635863739SMike Smith 	fib->Header.Size += sizeof(struct aac_blockread);
73735863739SMike Smith 	cm->cm_sgtable = &br->SgMap;
73835863739SMike Smith 	cm->cm_flags |= AAC_CMD_DATAIN;
73935863739SMike Smith     } else {
74035863739SMike Smith 	bw = (struct aac_blockwrite *)&fib->data[0];
74135863739SMike Smith 	bw->Command = VM_CtBlockWrite;
74235863739SMike Smith 	bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
74335863739SMike Smith 	bw->BlockNumber = bp->bio_pblkno;
74435863739SMike Smith 	bw->ByteCount = bp->bio_bcount;
74535863739SMike Smith 	bw->Stable = CUNSTABLE;		/* XXX what's appropriate here? */
74635863739SMike Smith 	fib->Header.Size += sizeof(struct aac_blockwrite);
74735863739SMike Smith 	cm->cm_flags |= AAC_CMD_DATAOUT;
74835863739SMike Smith 	cm->cm_sgtable = &bw->SgMap;
74935863739SMike Smith     }
75035863739SMike Smith 
75135863739SMike Smith     *cmp = cm;
75235863739SMike Smith     return(0);
75335863739SMike Smith 
75435863739SMike Smith fail:
75535863739SMike Smith     if (bp != NULL)
7560b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
75735863739SMike Smith     if (cm != NULL)
75835863739SMike Smith 	aac_release_command(cm);
75935863739SMike Smith     return(ENOMEM);
76035863739SMike Smith }
76135863739SMike Smith 
76235863739SMike Smith /********************************************************************************
76335863739SMike Smith  * Handle a bio-instigated command that has been completed.
76435863739SMike Smith  */
76535863739SMike Smith static void
76635863739SMike Smith aac_bio_complete(struct aac_command *cm)
76735863739SMike Smith {
76835863739SMike Smith     struct aac_blockread_response	*brr;
76935863739SMike Smith     struct aac_blockwrite_response	*bwr;
77035863739SMike Smith     struct bio				*bp;
77135863739SMike Smith     AAC_FSAStatus			status;
77235863739SMike Smith 
77335863739SMike Smith     /* fetch relevant status and then release the command */
77435863739SMike Smith     bp = (struct bio *)cm->cm_private;
77535863739SMike Smith     if (BIO_IS_READ(bp)) {
77635863739SMike Smith 	brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
77735863739SMike Smith 	status = brr->Status;
77835863739SMike Smith     } else {
77935863739SMike Smith 	bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
78035863739SMike Smith 	status = bwr->Status;
78135863739SMike Smith     }
78235863739SMike Smith     aac_release_command(cm);
78335863739SMike Smith 
78435863739SMike Smith     /* fix up the bio based on status */
78535863739SMike Smith     if (status == ST_OK) {
78635863739SMike Smith 	bp->bio_resid = 0;
78735863739SMike Smith     } else {
78835863739SMike Smith 	bp->bio_error = EIO;
78935863739SMike Smith 	bp->bio_flags |= BIO_ERROR;
7900b94a66eSMike Smith 	/* pass an error string out to the disk layer */
7910b94a66eSMike Smith 	bp->bio_driver1 = aac_describe_code(aac_command_status_table, status);
79235863739SMike Smith     }
7930b94a66eSMike Smith     aac_biodone(bp);
79435863739SMike Smith }
79535863739SMike Smith 
79635863739SMike Smith /********************************************************************************
79735863739SMike Smith  * Submit a command to the controller, return when it completes.
79835863739SMike Smith  */
79935863739SMike Smith static int
80035863739SMike Smith aac_wait_command(struct aac_command *cm, int timeout)
80135863739SMike Smith {
80235863739SMike Smith     int s, error = 0;
80335863739SMike Smith 
80435863739SMike Smith     debug_called(2);
80535863739SMike Smith 
80635863739SMike Smith     /* Put the command on the ready queue and get things going */
80735863739SMike Smith     aac_enqueue_ready(cm);
80835863739SMike Smith     aac_startio(cm->cm_sc);
80935863739SMike Smith     s = splbio();
81035863739SMike Smith     while(!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
81135863739SMike Smith         error = tsleep(cm, PRIBIO, "aacwait", timeout * hz);
81235863739SMike Smith     }
81335863739SMike Smith     splx(s);
81435863739SMike Smith     return(error);
81535863739SMike Smith }
81635863739SMike Smith 
81735863739SMike Smith /********************************************************************************
81835863739SMike Smith  ********************************************************************************
81935863739SMike Smith                                                         Command Buffer Management
82035863739SMike Smith  ********************************************************************************
82135863739SMike Smith  ********************************************************************************/
82235863739SMike Smith 
82335863739SMike Smith /********************************************************************************
82435863739SMike Smith  * Allocate a command.
82535863739SMike Smith  */
82635863739SMike Smith static int
82735863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
82835863739SMike Smith {
82935863739SMike Smith     struct aac_command	*cm;
83035863739SMike Smith 
83135863739SMike Smith     debug_called(3);
83235863739SMike Smith 
8330b94a66eSMike Smith     if ((cm = aac_dequeue_free(sc)) == NULL)
83435863739SMike Smith 	return(ENOMEM);
83535863739SMike Smith 
8360b94a66eSMike Smith     *cmp = cm;
8370b94a66eSMike Smith     return(0);
8380b94a66eSMike Smith }
8390b94a66eSMike Smith 
8400b94a66eSMike Smith /********************************************************************************
8410b94a66eSMike Smith  * Release a command back to the freelist.
8420b94a66eSMike Smith  */
8430b94a66eSMike Smith static void
8440b94a66eSMike Smith aac_release_command(struct aac_command *cm)
8450b94a66eSMike Smith {
8460b94a66eSMike Smith     debug_called(3);
8470b94a66eSMike Smith 
8480b94a66eSMike Smith     /* (re)initialise the command/FIB */
84935863739SMike Smith     cm->cm_sgtable = NULL;
85035863739SMike Smith     cm->cm_flags = 0;
85135863739SMike Smith     cm->cm_complete = NULL;
85235863739SMike Smith     cm->cm_private = NULL;
85335863739SMike Smith     cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
85435863739SMike Smith     cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
85535863739SMike Smith     cm->cm_fib->Header.Flags = 0;
85635863739SMike Smith     cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
85735863739SMike Smith 
85835863739SMike Smith     /*
85935863739SMike Smith      * These are duplicated in aac_start to cover the case where an
86035863739SMike Smith      * intermediate stage may have destroyed them.  They're left
86135863739SMike Smith      * initialised here for debugging purposes only.
86235863739SMike Smith      */
86335863739SMike Smith     cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
86435863739SMike Smith     cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
86535863739SMike Smith 
86635863739SMike Smith     aac_enqueue_free(cm);
86735863739SMike Smith }
86835863739SMike Smith 
86935863739SMike Smith /********************************************************************************
8700b94a66eSMike Smith  * Map helper for command/FIB allocation.
87135863739SMike Smith  */
87235863739SMike Smith static void
8730b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
87435863739SMike Smith {
8750b94a66eSMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
87635863739SMike Smith 
87735863739SMike Smith     debug_called(3);
87835863739SMike Smith 
8790b94a66eSMike Smith     sc->aac_fibphys = segs[0].ds_addr;
88035863739SMike Smith }
88135863739SMike Smith 
88235863739SMike Smith /********************************************************************************
8830b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
88435863739SMike Smith  */
8850b94a66eSMike Smith static int
8860b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
88735863739SMike Smith {
88835863739SMike Smith     struct aac_command		*cm;
88935863739SMike Smith     int				i;
89035863739SMike Smith 
89135863739SMike Smith     debug_called(1);
89235863739SMike Smith 
8930b94a66eSMike Smith     /* allocate the FIBs in DMAable memory and load them */
8940b94a66eSMike Smith     if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs, BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
8950b94a66eSMike Smith 	return(ENOMEM);
89635863739SMike Smith     }
8970b94a66eSMike Smith     bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
8980b94a66eSMike Smith 		    AAC_FIB_COUNT * sizeof(struct aac_fib), aac_map_command_helper, sc, 0);
89935863739SMike Smith 
9000b94a66eSMike Smith     /* initialise constant fields in the command structure */
9010b94a66eSMike Smith     for (i = 0; i < AAC_FIB_COUNT; i++) {
9020b94a66eSMike Smith 	cm = &sc->aac_command[i];
90335863739SMike Smith 	cm->cm_sc = sc;
9040b94a66eSMike Smith 	cm->cm_fib = sc->aac_fibs + i;
9050b94a66eSMike Smith 	cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
90635863739SMike Smith 
90735863739SMike Smith 	if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
90835863739SMike Smith 	    aac_release_command(cm);
90935863739SMike Smith     }
9100b94a66eSMike Smith     return(0);
91135863739SMike Smith }
91235863739SMike Smith 
91335863739SMike Smith /********************************************************************************
9140b94a66eSMike Smith  * Free FIBs owned by this adapter.
91535863739SMike Smith  */
91635863739SMike Smith static void
9170b94a66eSMike Smith aac_free_commands(struct aac_softc *sc)
91835863739SMike Smith {
91935863739SMike Smith     int			i;
92035863739SMike Smith 
92135863739SMike Smith     debug_called(1);
92235863739SMike Smith 
9230b94a66eSMike Smith     for (i = 0; i < AAC_FIB_COUNT; i++)
9240b94a66eSMike Smith 	bus_dmamap_destroy(sc->aac_buffer_dmat, sc->aac_command[i].cm_datamap);
9250b94a66eSMike Smith     bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
9260b94a66eSMike Smith     bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
92735863739SMike Smith }
92835863739SMike Smith 
92935863739SMike Smith /********************************************************************************
93035863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
93135863739SMike Smith  */
93235863739SMike Smith static void
93335863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
93435863739SMike Smith {
93535863739SMike Smith     struct aac_command		*cm = (struct aac_command *)arg;
93635863739SMike Smith     struct aac_fib		*fib = cm->cm_fib;
93735863739SMike Smith     struct aac_sg_table		*sg;
93835863739SMike Smith     int				i;
93935863739SMike Smith 
94035863739SMike Smith     debug_called(3);
94135863739SMike Smith 
94235863739SMike Smith     /* find the s/g table */
94335863739SMike Smith     sg = cm->cm_sgtable;
94435863739SMike Smith 
94535863739SMike Smith     /* copy into the FIB */
94635863739SMike Smith     if (sg != NULL) {
94735863739SMike Smith 	sg->SgCount = nseg;
94835863739SMike Smith 	for (i = 0; i < nseg; i++) {
94935863739SMike Smith 	    sg->SgEntry[i].SgAddress = segs[i].ds_addr;
95035863739SMike Smith 	    sg->SgEntry[i].SgByteCount = segs[i].ds_len;
95135863739SMike Smith 	}
95235863739SMike Smith 	/* update the FIB size for the s/g count */
95335863739SMike Smith 	fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
95435863739SMike Smith     }
95535863739SMike Smith 
95635863739SMike Smith }
95735863739SMike Smith 
95835863739SMike Smith /********************************************************************************
95935863739SMike Smith  * Map a command into controller-visible space.
96035863739SMike Smith  */
96135863739SMike Smith static void
96235863739SMike Smith aac_map_command(struct aac_command *cm)
96335863739SMike Smith {
96435863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
96535863739SMike Smith 
96635863739SMike Smith     debug_called(2);
96735863739SMike Smith 
96835863739SMike Smith     /* don't map more than once */
96935863739SMike Smith     if (cm->cm_flags & AAC_CMD_MAPPED)
97035863739SMike Smith 	return;
97135863739SMike Smith 
97235863739SMike Smith     if (cm->cm_datalen != 0) {
97335863739SMike Smith 	bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap, cm->cm_data,
97435863739SMike Smith 			cm->cm_datalen, aac_map_command_sg, cm, 0);
97535863739SMike Smith 
97635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
97735863739SMike Smith 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_PREREAD);
97835863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
97935863739SMike Smith 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_PREWRITE);
98035863739SMike Smith     }
98135863739SMike Smith     cm->cm_flags |= AAC_CMD_MAPPED;
98235863739SMike Smith }
98335863739SMike Smith 
98435863739SMike Smith /********************************************************************************
98535863739SMike Smith  * Unmap a command from controller-visible space.
98635863739SMike Smith  */
98735863739SMike Smith static void
98835863739SMike Smith aac_unmap_command(struct aac_command *cm)
98935863739SMike Smith {
99035863739SMike Smith     struct aac_softc	*sc = cm->cm_sc;
99135863739SMike Smith 
99235863739SMike Smith     debug_called(2);
99335863739SMike Smith 
99435863739SMike Smith     if (!(cm->cm_flags & AAC_CMD_MAPPED))
99535863739SMike Smith 	return;
99635863739SMike Smith 
99735863739SMike Smith     if (cm->cm_datalen != 0) {
99835863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
99935863739SMike Smith 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_POSTREAD);
100035863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
100135863739SMike Smith 	    bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, BUS_DMASYNC_POSTWRITE);
100235863739SMike Smith 
100335863739SMike Smith 	bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
100435863739SMike Smith     }
100535863739SMike Smith     cm->cm_flags &= ~AAC_CMD_MAPPED;
100635863739SMike Smith }
100735863739SMike Smith 
100835863739SMike Smith /********************************************************************************
100935863739SMike Smith  ********************************************************************************
101035863739SMike Smith                                                                Hardware Interface
101135863739SMike Smith  ********************************************************************************
101235863739SMike Smith  ********************************************************************************/
101335863739SMike Smith 
101435863739SMike Smith /********************************************************************************
101535863739SMike Smith  * Initialise the adapter.
101635863739SMike Smith  */
101735863739SMike Smith static void
101835863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
101935863739SMike Smith {
102035863739SMike Smith     struct aac_softc	*sc = (struct aac_softc *)arg;
102135863739SMike Smith 
102235863739SMike Smith     debug_called(1);
102335863739SMike Smith 
102435863739SMike Smith     sc->aac_common_busaddr = segs[0].ds_addr;
102535863739SMike Smith }
102635863739SMike Smith 
102735863739SMike Smith static int
102835863739SMike Smith aac_init(struct aac_softc *sc)
102935863739SMike Smith {
103035863739SMike Smith     struct aac_adapter_init	*ip;
103135863739SMike Smith     time_t			then;
103235863739SMike Smith     u_int32_t			code;
103335863739SMike Smith     u_int8_t			*qaddr;
103435863739SMike Smith 
103535863739SMike Smith     debug_called(1);
103635863739SMike Smith 
103735863739SMike Smith     /*
103835863739SMike Smith      * First wait for the adapter to come ready.
103935863739SMike Smith      */
104035863739SMike Smith     then = time_second;
104135863739SMike Smith     do {
104235863739SMike Smith 	code = AAC_GET_FWSTATUS(sc);
104335863739SMike Smith 	if (code & AAC_SELF_TEST_FAILED) {
104435863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: selftest failed\n");
104535863739SMike Smith 	    return(ENXIO);
104635863739SMike Smith 	}
104735863739SMike Smith 	if (code & AAC_KERNEL_PANIC) {
104835863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: controller kernel panic\n");
104935863739SMike Smith 	    return(ENXIO);
105035863739SMike Smith 	}
105135863739SMike Smith 	if (time_second > (then + AAC_BOOT_TIMEOUT)) {
105235863739SMike Smith 	    device_printf(sc->aac_dev, "FATAL: controller not coming ready, status %x\n", code);
105335863739SMike Smith 	    return(ENXIO);
105435863739SMike Smith 	}
105535863739SMike Smith     } while (!(code & AAC_UP_AND_RUNNING));
105635863739SMike Smith 
105735863739SMike Smith     /*
105835863739SMike Smith      * Create DMA tag for the common structure and allocate it.
105935863739SMike Smith      */
106035863739SMike Smith     if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
106135863739SMike Smith 			   1, 0, 			/* alignment, boundary */
106235863739SMike Smith 			   BUS_SPACE_MAXADDR,		/* lowaddr */
106335863739SMike Smith 			   BUS_SPACE_MAXADDR, 		/* highaddr */
106435863739SMike Smith 			   NULL, NULL, 			/* filter, filterarg */
106535863739SMike Smith 			   sizeof(struct aac_common), 1,/* maxsize, nsegments */
106635863739SMike Smith 			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
106735863739SMike Smith 			   0,				/* flags */
106835863739SMike Smith 			   &sc->aac_common_dmat)) {
106935863739SMike Smith 	device_printf(sc->aac_dev, "can't allocate common structure DMA tag\n");
107035863739SMike Smith 	return(ENOMEM);
107135863739SMike Smith     }
107235863739SMike Smith     if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
107335863739SMike Smith 	device_printf(sc->aac_dev, "can't allocate common structure\n");
107435863739SMike Smith 	return(ENOMEM);
107535863739SMike Smith     }
107635863739SMike Smith     bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, sc->aac_common, sizeof(*sc->aac_common),
107735863739SMike Smith 		    aac_common_map, sc, 0);
107835863739SMike Smith     bzero(sc->aac_common, sizeof(*sc->aac_common));
107935863739SMike Smith 
108035863739SMike Smith     /*
108135863739SMike Smith      * Fill in the init structure.  This tells the adapter about the physical location
108235863739SMike Smith      * of various important shared data structures.
108335863739SMike Smith      */
108435863739SMike Smith     ip = &sc->aac_common->ac_init;
108535863739SMike Smith     ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
108635863739SMike Smith 
108746aa3347SPoul-Henning Kamp     ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_fibs);
108835863739SMike Smith     ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
108935863739SMike Smith     ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
109035863739SMike Smith     ip->AdapterFibAlign = sizeof(struct aac_fib);
109135863739SMike Smith 
109246aa3347SPoul-Henning Kamp     ip->PrintfBufferAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_printf);
109335863739SMike Smith     ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
109435863739SMike Smith 
109535863739SMike Smith     ip->HostPhysMemPages = 0;			/* not used? */
109635863739SMike Smith     ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
109735863739SMike Smith 
109835863739SMike Smith     /*
109935863739SMike Smith      * Initialise FIB queues.  Note that it appears that the layout of the indexes
11000b94a66eSMike Smith      * and the segmentation of the entries may be mandated by the adapter, which is
110135863739SMike Smith      * only told about the base of the queue index fields.
110235863739SMike Smith      *
110335863739SMike Smith      * The initial values of the indices are assumed to inform the adapter
11040b94a66eSMike Smith      * of the sizes of the respective queues, and theoretically it could work out
11050b94a66eSMike Smith      * the entire layout of the queue structures from this.  We take the easy
11060b94a66eSMike Smith      * route and just lay this area out like everyone else does.
110735863739SMike Smith      *
110835863739SMike Smith      * The Linux driver uses a much more complex scheme whereby several header
110935863739SMike Smith      * records are kept for each queue.  We use a couple of generic list manipulation
111035863739SMike Smith      * functions which 'know' the size of each list by virtue of a table.
111135863739SMike Smith      */
111235863739SMike Smith     qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
111335863739SMike Smith     qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
111435863739SMike Smith     sc->aac_queues = (struct aac_queue_table *)qaddr;
111535863739SMike Smith     ip->CommHeaderAddress = sc->aac_common_busaddr + ((u_int32_t)sc->aac_queues - (u_int32_t)sc->aac_common);
111635863739SMike Smith     bzero(sc->aac_queues, sizeof(struct aac_queue_table));
111735863739SMike Smith 
111835863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX]  = AAC_HOST_NORM_CMD_ENTRIES;
111935863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX]  = AAC_HOST_NORM_CMD_ENTRIES;
112035863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX]  = AAC_HOST_HIGH_CMD_ENTRIES;
112135863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX]  = AAC_HOST_HIGH_CMD_ENTRIES;
112235863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX]  = AAC_ADAP_NORM_CMD_ENTRIES;
112335863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX]  = AAC_ADAP_NORM_CMD_ENTRIES;
112435863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX]  = AAC_ADAP_HIGH_CMD_ENTRIES;
112535863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX]  = AAC_ADAP_HIGH_CMD_ENTRIES;
112635863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_NORM_RESP_ENTRIES;
112735863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_HOST_NORM_RESP_ENTRIES;
112835863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_HOST_HIGH_RESP_ENTRIES;
112935863739SMike Smith     sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_HOST_HIGH_RESP_ENTRIES;
113035863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_ADAP_NORM_RESP_ENTRIES;
113135863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_ADAP_NORM_RESP_ENTRIES;
113235863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = AAC_ADAP_HIGH_RESP_ENTRIES;
113335863739SMike Smith     sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = AAC_ADAP_HIGH_RESP_ENTRIES;
113435863739SMike Smith     sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = &sc->aac_queues->qt_HostNormCmdQueue[0];
113535863739SMike Smith     sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = &sc->aac_queues->qt_HostHighCmdQueue[0];
113635863739SMike Smith     sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = &sc->aac_queues->qt_AdapNormCmdQueue[0];
113735863739SMike Smith     sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = &sc->aac_queues->qt_AdapHighCmdQueue[0];
113835863739SMike Smith     sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = &sc->aac_queues->qt_HostNormRespQueue[0];
113935863739SMike Smith     sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = &sc->aac_queues->qt_HostHighRespQueue[0];
114035863739SMike Smith     sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = &sc->aac_queues->qt_AdapNormRespQueue[0];
114135863739SMike Smith     sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = &sc->aac_queues->qt_AdapHighRespQueue[0];
114235863739SMike Smith 
114335863739SMike Smith     /*
114435863739SMike Smith      * Do controller-type-specific initialisation
114535863739SMike Smith      */
114635863739SMike Smith     switch (sc->aac_hwif) {
114735863739SMike Smith     case AAC_HWIF_I960RX:
114835863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
114935863739SMike Smith 	break;
115035863739SMike Smith     }
115135863739SMike Smith 
115235863739SMike Smith     /*
115335863739SMike Smith      * Give the init structure to the controller.
115435863739SMike Smith      */
115535863739SMike Smith     if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
115646aa3347SPoul-Henning Kamp 			 sc->aac_common_busaddr + offsetof(struct aac_common, ac_init),
115735863739SMike Smith 			 0, 0, 0, NULL)) {
115835863739SMike Smith 	device_printf(sc->aac_dev, "error establishing init structure\n");
115935863739SMike Smith 	return(EIO);
116035863739SMike Smith     }
116135863739SMike Smith 
116235863739SMike Smith     return(0);
116335863739SMike Smith }
116435863739SMike Smith 
116535863739SMike Smith /********************************************************************************
116635863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
116735863739SMike Smith  */
116835863739SMike Smith static int
116935863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
117035863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
117135863739SMike Smith 		 u_int32_t *sp)
117235863739SMike Smith {
117335863739SMike Smith     time_t	then;
117435863739SMike Smith     u_int32_t	status;
117535863739SMike Smith 
117635863739SMike Smith     debug_called(3);
117735863739SMike Smith 
117835863739SMike Smith     /* populate the mailbox */
117935863739SMike Smith     AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
118035863739SMike Smith 
118135863739SMike Smith     /* ensure the sync command doorbell flag is cleared */
118235863739SMike Smith     AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
118335863739SMike Smith 
118435863739SMike Smith     /* then set it to signal the adapter */
118535863739SMike Smith     AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
118635863739SMike Smith 
118735863739SMike Smith     /* spin waiting for the command to complete */
118835863739SMike Smith     then = time_second;
118935863739SMike Smith     do {
119035863739SMike Smith 	if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
119135863739SMike Smith 	    debug(2, "timed out");
119235863739SMike Smith 	    return(EIO);
119335863739SMike Smith 	}
119435863739SMike Smith     } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
119535863739SMike Smith 
119635863739SMike Smith     /* clear the completion flag */
119735863739SMike Smith     AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
119835863739SMike Smith 
119935863739SMike Smith     /* get the command status */
120035863739SMike Smith     status = AAC_GET_MAILBOXSTATUS(sc);
120135863739SMike Smith     if (sp != NULL)
120235863739SMike Smith 	*sp = status;
12030b94a66eSMike Smith     return(0);
120435863739SMike Smith }
120535863739SMike Smith 
120635863739SMike Smith /********************************************************************************
120735863739SMike Smith  * Send a synchronous FIB to the controller and wait for a result.
120835863739SMike Smith  */
120935863739SMike Smith static int
121035863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
121135863739SMike Smith 	     void *data, u_int16_t datasize,
121235863739SMike Smith 	     void *result, u_int16_t *resultsize)
121335863739SMike Smith {
121435863739SMike Smith     struct aac_fib	*fib = &sc->aac_common->ac_sync_fib;
121535863739SMike Smith 
121635863739SMike Smith     debug_called(3);
121735863739SMike Smith 
121835863739SMike Smith     if (datasize > AAC_FIB_DATASIZE)
121935863739SMike Smith 	return(EINVAL);
122035863739SMike Smith 
122135863739SMike Smith     /*
122235863739SMike Smith      * Set up the sync FIB
122335863739SMike Smith      */
122435863739SMike Smith     fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_EMPTY;
122535863739SMike Smith     fib->Header.XferState |= xferstate;
122635863739SMike Smith     fib->Header.Command = command;
122735863739SMike Smith     fib->Header.StructType = AAC_FIBTYPE_TFIB;
122835863739SMike Smith     fib->Header.Size = sizeof(struct aac_fib) + datasize;
122935863739SMike Smith     fib->Header.SenderSize = sizeof(struct aac_fib);
123035863739SMike Smith     fib->Header.SenderFibAddress = (u_int32_t)fib;
123146aa3347SPoul-Henning Kamp     fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + offsetof(struct aac_common, ac_sync_fib);
123235863739SMike Smith 
123335863739SMike Smith     /*
123435863739SMike Smith      * Copy in data.
123535863739SMike Smith      */
123635863739SMike Smith     if (data != NULL) {
123735863739SMike Smith 	bcopy(data, fib->data, datasize);
123835863739SMike Smith 	fib->Header.XferState |= AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM;
123935863739SMike Smith     }
124035863739SMike Smith 
124135863739SMike Smith     /*
124235863739SMike Smith      * Give the FIB to the controller, wait for a response.
124335863739SMike Smith      */
124435863739SMike Smith     if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fib->Header.ReceiverFibAddress,
124535863739SMike Smith 			 0, 0, 0, NULL)) {
124635863739SMike Smith 	debug(2, "IO error");
124735863739SMike Smith 	return(EIO);
124835863739SMike Smith     }
124935863739SMike Smith 
125035863739SMike Smith     /*
125135863739SMike Smith      * Copy out the result
125235863739SMike Smith      */
125335863739SMike Smith     if (result != NULL) {
125435863739SMike Smith 	*resultsize = fib->Header.Size - sizeof(struct aac_fib_header);
125535863739SMike Smith 	bcopy(fib->data, result, *resultsize);
125635863739SMike Smith     }
125735863739SMike Smith     return(0);
125835863739SMike Smith }
125935863739SMike Smith 
126035863739SMike Smith /********************************************************************************
126135863739SMike Smith  * Adapter-space FIB queue manipulation
126235863739SMike Smith  *
126335863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
126435863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
126535863739SMike Smith  */
126635863739SMike Smith static struct {
126735863739SMike Smith     int		size;
126835863739SMike Smith     int		notify;
126935863739SMike Smith } aac_qinfo[] = {
127035863739SMike Smith     {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
127135863739SMike Smith     {AAC_HOST_HIGH_CMD_ENTRIES, 0},
127235863739SMike Smith     {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
127335863739SMike Smith     {AAC_ADAP_HIGH_CMD_ENTRIES, 0},
127435863739SMike Smith     {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
127535863739SMike Smith     {AAC_HOST_HIGH_RESP_ENTRIES, 0},
127635863739SMike Smith     {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
127735863739SMike Smith     {AAC_ADAP_HIGH_RESP_ENTRIES, 0}
127835863739SMike Smith };
127935863739SMike Smith 
128035863739SMike Smith /*
128135863739SMike Smith  * Atomically insert an entry into the nominated queue, returns 0 on success or EBUSY
128235863739SMike Smith  * if the queue is full.
128335863739SMike Smith  *
12840b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
128535863739SMike Smith  *       the case where we may be inserting several entries in rapid succession, but
12860b94a66eSMike Smith  *       implementing this usefully may be difficult (it would involve a separate
12870b94a66eSMike Smith  *       queue/notify interface).
128835863739SMike Smith  */
128935863739SMike Smith static int
129035863739SMike Smith aac_enqueue_fib(struct aac_softc *sc, int queue, u_int32_t fib_size, u_int32_t fib_addr)
129135863739SMike Smith {
129235863739SMike Smith     u_int32_t	pi, ci;
129335863739SMike Smith     int		s, error;
129435863739SMike Smith 
129535863739SMike Smith     debug_called(3);
129635863739SMike Smith 
129735863739SMike Smith     s = splbio();
129835863739SMike Smith 
129935863739SMike Smith     /* get the producer/consumer indices */
130035863739SMike Smith     pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
130135863739SMike Smith     ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
130235863739SMike Smith 
130335863739SMike Smith     /* wrap the queue? */
130435863739SMike Smith     if (pi >= aac_qinfo[queue].size)
130535863739SMike Smith 	pi = 0;
130635863739SMike Smith 
130735863739SMike Smith     /* check for queue full */
130835863739SMike Smith     if ((pi + 1) == ci) {
130935863739SMike Smith 	error = EBUSY;
131035863739SMike Smith 	goto out;
131135863739SMike Smith     }
131235863739SMike Smith 
131335863739SMike Smith     /* populate queue entry */
131435863739SMike Smith     (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
131535863739SMike Smith     (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
131635863739SMike Smith 
131735863739SMike Smith     /* update producer index */
131835863739SMike Smith     sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
131935863739SMike Smith 
132035863739SMike Smith     /* notify the adapter if we know how */
132135863739SMike Smith     if (aac_qinfo[queue].notify != 0)
132235863739SMike Smith 	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
132335863739SMike Smith 
132435863739SMike Smith     error = 0;
132535863739SMike Smith 
132635863739SMike Smith out:
132735863739SMike Smith     splx(s);
132835863739SMike Smith     return(error);
132935863739SMike Smith }
133035863739SMike Smith 
133135863739SMike Smith /*
133235863739SMike Smith  * Atomically remove one entry from the nominated queue, returns 0 on success or ENOENT
133335863739SMike Smith  * if the queue is empty.
133435863739SMike Smith  */
133535863739SMike Smith static int
133635863739SMike Smith aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, struct aac_fib **fib_addr)
133735863739SMike Smith {
133835863739SMike Smith     u_int32_t	pi, ci;
133935863739SMike Smith     int		s, error;
134035863739SMike Smith 
134135863739SMike Smith     debug_called(3);
134235863739SMike Smith 
134335863739SMike Smith     s = splbio();
134435863739SMike Smith 
134535863739SMike Smith     /* get the producer/consumer indices */
134635863739SMike Smith     pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
134735863739SMike Smith     ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
134835863739SMike Smith 
134935863739SMike Smith     /* check for queue empty */
135035863739SMike Smith     if (ci == pi) {
135135863739SMike Smith 	error = ENOENT;
135235863739SMike Smith 	goto out;
135335863739SMike Smith     }
135435863739SMike Smith 
135535863739SMike Smith     /* wrap the queue? */
135635863739SMike Smith     if (ci >= aac_qinfo[queue].size)
135735863739SMike Smith 	ci = 0;
135835863739SMike Smith 
135935863739SMike Smith     /* fetch the entry */
136035863739SMike Smith     *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
136135863739SMike Smith     *fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] + ci)->aq_fib_addr;
136235863739SMike Smith 
136335863739SMike Smith     /* update consumer index */
136435863739SMike Smith     sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
136535863739SMike Smith 
136635863739SMike Smith     /* if we have made the queue un-full, notify the adapter */
136735863739SMike Smith     if (((pi + 1) == ci) && (aac_qinfo[queue].notify != 0))
136835863739SMike Smith 	AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
136935863739SMike Smith     error = 0;
137035863739SMike Smith 
137135863739SMike Smith out:
137235863739SMike Smith     splx(s);
137335863739SMike Smith     return(error);
137435863739SMike Smith }
137535863739SMike Smith 
137635863739SMike Smith /********************************************************************************
13770b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
13780b94a66eSMike Smith  * and complain about them.
13790b94a66eSMike Smith  */
13800b94a66eSMike Smith static void
13810b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
13820b94a66eSMike Smith {
13830b94a66eSMike Smith     int		s;
13840b94a66eSMike Smith     struct	aac_command *cm;
13850b94a66eSMike Smith     time_t	deadline;
13860b94a66eSMike Smith 
13870b94a66eSMike Smith     /* simulate an interrupt to handle possibly-missed interrupts */
13880b94a66eSMike Smith     aac_intr(sc);
13890b94a66eSMike Smith 
13900b94a66eSMike Smith     /* kick the I/O queue to restart it in the case of deadlock */
13910b94a66eSMike Smith     aac_startio(sc);
13920b94a66eSMike Smith 
13930b94a66eSMike Smith     /* traverse the busy command list, bitch about late commands once only */
13940b94a66eSMike Smith     deadline = time_second - AAC_CMD_TIMEOUT;
13950b94a66eSMike Smith     s = splbio();
13960b94a66eSMike Smith     TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
13970b94a66eSMike Smith 	if ((cm->cm_timestamp  < deadline) && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) {
13980b94a66eSMike Smith 	    cm->cm_flags |= AAC_CMD_TIMEDOUT;
13990b94a66eSMike Smith 	    device_printf(sc->aac_dev, "COMMAND TIMED OUT AFTER %d SECONDS\n",
14000b94a66eSMike Smith 			  (int)(time_second - cm->cm_timestamp));
14010b94a66eSMike Smith 	    AAC_PRINT_FIB(sc, cm->cm_fib);
14020b94a66eSMike Smith 	}
14030b94a66eSMike Smith     }
14040b94a66eSMike Smith     splx(s);
14050b94a66eSMike Smith 
14060b94a66eSMike Smith     /* reset the timer for next time */
14070b94a66eSMike Smith     timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
14080b94a66eSMike Smith     return;
14090b94a66eSMike Smith }
14100b94a66eSMike Smith 
14110b94a66eSMike Smith /********************************************************************************
141235863739SMike Smith  ********************************************************************************
141335863739SMike Smith                                                        Interface Function Vectors
141435863739SMike Smith  ********************************************************************************
141535863739SMike Smith  ********************************************************************************/
141635863739SMike Smith 
141735863739SMike Smith /********************************************************************************
141835863739SMike Smith  * Read the current firmware status word.
141935863739SMike Smith  */
142035863739SMike Smith static int
142135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
142235863739SMike Smith {
142335863739SMike Smith     debug_called(3);
142435863739SMike Smith 
142535863739SMike Smith     return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
142635863739SMike Smith }
142735863739SMike Smith 
142835863739SMike Smith static int
142935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
143035863739SMike Smith {
143135863739SMike Smith     debug_called(3);
143235863739SMike Smith 
143335863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
143435863739SMike Smith }
143535863739SMike Smith 
143635863739SMike Smith /********************************************************************************
143735863739SMike Smith  * Notify the controller of a change in a given queue
143835863739SMike Smith  */
143935863739SMike Smith 
144035863739SMike Smith static void
144135863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
144235863739SMike Smith {
144335863739SMike Smith     debug_called(3);
144435863739SMike Smith 
144535863739SMike Smith     AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
144635863739SMike Smith }
144735863739SMike Smith 
144835863739SMike Smith static void
144935863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
145035863739SMike Smith {
145135863739SMike Smith     debug_called(3);
145235863739SMike Smith 
145335863739SMike Smith     AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
145435863739SMike Smith }
145535863739SMike Smith 
145635863739SMike Smith /********************************************************************************
145735863739SMike Smith  * Get the interrupt reason bits
145835863739SMike Smith  */
145935863739SMike Smith static int
146035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
146135863739SMike Smith {
146235863739SMike Smith     debug_called(3);
146335863739SMike Smith 
146435863739SMike Smith     return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
146535863739SMike Smith }
146635863739SMike Smith 
146735863739SMike Smith static int
146835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
146935863739SMike Smith {
147035863739SMike Smith     debug_called(3);
147135863739SMike Smith 
147235863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_ODBR));
147335863739SMike Smith }
147435863739SMike Smith 
147535863739SMike Smith /********************************************************************************
147635863739SMike Smith  * Clear some interrupt reason bits
147735863739SMike Smith  */
147835863739SMike Smith static void
147935863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
148035863739SMike Smith {
148135863739SMike Smith     debug_called(3);
148235863739SMike Smith 
148335863739SMike Smith     AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
148435863739SMike Smith }
148535863739SMike Smith 
148635863739SMike Smith static void
148735863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
148835863739SMike Smith {
148935863739SMike Smith     debug_called(3);
149035863739SMike Smith 
149135863739SMike Smith     AAC_SETREG4(sc, AAC_RX_ODBR, mask);
149235863739SMike Smith }
149335863739SMike Smith 
149435863739SMike Smith /********************************************************************************
149535863739SMike Smith  * Populate the mailbox and set the command word
149635863739SMike Smith  */
149735863739SMike Smith static void
149835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
149935863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
150035863739SMike Smith {
150135863739SMike Smith     debug_called(4);
150235863739SMike Smith 
150335863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
150435863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
150535863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
150635863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
150735863739SMike Smith     AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
150835863739SMike Smith }
150935863739SMike Smith 
151035863739SMike Smith static void
151135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
151235863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
151335863739SMike Smith {
151435863739SMike Smith     debug_called(4);
151535863739SMike Smith 
151635863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
151735863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
151835863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
151935863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
152035863739SMike Smith     AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
152135863739SMike Smith }
152235863739SMike Smith 
152335863739SMike Smith /********************************************************************************
152435863739SMike Smith  * Fetch the immediate command status word
152535863739SMike Smith  */
152635863739SMike Smith static int
152735863739SMike Smith aac_sa_get_mailboxstatus(struct aac_softc *sc)
152835863739SMike Smith {
152935863739SMike Smith     debug_called(4);
153035863739SMike Smith 
153135863739SMike Smith     return(AAC_GETREG4(sc, AAC_SA_MAILBOX));
153235863739SMike Smith }
153335863739SMike Smith 
153435863739SMike Smith static int
153535863739SMike Smith aac_rx_get_mailboxstatus(struct aac_softc *sc)
153635863739SMike Smith {
153735863739SMike Smith     debug_called(4);
153835863739SMike Smith 
153935863739SMike Smith     return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
154035863739SMike Smith }
154135863739SMike Smith 
154235863739SMike Smith /********************************************************************************
154335863739SMike Smith  * Set/clear interrupt masks
154435863739SMike Smith  */
154535863739SMike Smith static void
154635863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
154735863739SMike Smith {
154835863739SMike Smith     debug(2, "%sable interrupts", enable ? "en" : "dis");
154935863739SMike Smith 
155035863739SMike Smith     if (enable) {
155135863739SMike Smith 	AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
155235863739SMike Smith     } else {
155335863739SMike Smith 	AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
155435863739SMike Smith     }
155535863739SMike Smith }
155635863739SMike Smith 
155735863739SMike Smith static void
155835863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
155935863739SMike Smith {
156035863739SMike Smith     debug(2, "%sable interrupts", enable ? "en" : "dis");
156135863739SMike Smith 
156235863739SMike Smith     if (enable) {
156335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
156435863739SMike Smith     } else {
156535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
156635863739SMike Smith     }
156735863739SMike Smith }
156835863739SMike Smith 
156935863739SMike Smith /********************************************************************************
157035863739SMike Smith  ********************************************************************************
157135863739SMike Smith                                                         Debugging and Diagnostics
157235863739SMike Smith  ********************************************************************************
157335863739SMike Smith  ********************************************************************************/
157435863739SMike Smith 
157535863739SMike Smith /********************************************************************************
157635863739SMike Smith  * Print some information about the controller.
157735863739SMike Smith  */
157835863739SMike Smith static void
157935863739SMike Smith aac_describe_controller(struct aac_softc *sc)
158035863739SMike Smith {
158135863739SMike Smith     u_int8_t			buf[AAC_FIB_DATASIZE];	/* XXX really a bit big for the stack */
158235863739SMike Smith     u_int16_t			bufsize;
158335863739SMike Smith     struct aac_adapter_info	*info;
158435863739SMike Smith     u_int8_t			arg;
158535863739SMike Smith 
158635863739SMike Smith     debug_called(2);
158735863739SMike Smith 
158835863739SMike Smith     arg = 0;
158935863739SMike Smith     if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf, &bufsize)) {
159035863739SMike Smith 	device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
159135863739SMike Smith 	return;
159235863739SMike Smith     }
159335863739SMike Smith     if (bufsize != sizeof(*info)) {
159435863739SMike Smith 	device_printf(sc->aac_dev, "RequestAdapterInfo returned wrong data size (%d != %d)\n",
159535863739SMike Smith 		      bufsize, sizeof(*info));
15960b94a66eSMike Smith 	/*return;*/
159735863739SMike Smith     }
159835863739SMike Smith     info = (struct aac_adapter_info *)&buf[0];
159935863739SMike Smith 
160035863739SMike Smith     device_printf(sc->aac_dev, "%s %dMHz, %dMB total memory, %s (%d)\n",
160135863739SMike Smith 		  aac_describe_code(aac_cpu_variant, info->CpuVariant), info->ClockSpeed,
160235863739SMike Smith 		  info->TotalMem / (1024 * 1024),
160335863739SMike Smith 		  aac_describe_code(aac_battery_platform, info->batteryPlatform), info->batteryPlatform);
160435863739SMike Smith 
160535863739SMike Smith     /* save the kernel revision structure for later use */
160635863739SMike Smith     sc->aac_revision = info->KernelRevision;
160735863739SMike Smith     device_printf(sc->aac_dev, "Kernel %d.%d-%d, S/N %llx\n",
160835863739SMike Smith 		  info->KernelRevision.external.comp.major,
160935863739SMike Smith 		  info->KernelRevision.external.comp.minor,
161035863739SMike Smith 		  info->KernelRevision.external.comp.dash,
161135863739SMike Smith 		  info->SerialNumber);	/* XXX how is this meant to be formatted? */
161235863739SMike Smith }
161335863739SMike Smith 
161435863739SMike Smith /********************************************************************************
161535863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
161635863739SMike Smith  * same.
161735863739SMike Smith  */
161835863739SMike Smith static char *
161935863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
162035863739SMike Smith {
162135863739SMike Smith     int		i;
162235863739SMike Smith 
162335863739SMike Smith     for (i = 0; table[i].string != NULL; i++)
162435863739SMike Smith 	if (table[i].code == code)
162535863739SMike Smith 	    return(table[i].string);
162635863739SMike Smith     return(table[i + 1].string);
162735863739SMike Smith }
162835863739SMike Smith 
162935863739SMike Smith /*****************************************************************************
163035863739SMike Smith  *****************************************************************************
163135863739SMike Smith                                                     Management Interface
163235863739SMike Smith  *****************************************************************************
163335863739SMike Smith  *****************************************************************************/
163435863739SMike Smith 
163535863739SMike Smith static int
163635863739SMike Smith aac_open(dev_t dev, int flags, int fmt, struct proc *p)
163735863739SMike Smith {
163835863739SMike Smith     struct aac_softc	*sc = dev->si_drv1;
163935863739SMike Smith 
164035863739SMike Smith     debug_called(2);
164135863739SMike Smith 
164235863739SMike Smith     /* Check to make sure the device isn't already open */
164335863739SMike Smith     if (sc->aac_state & AAC_STATE_OPEN) {
164435863739SMike Smith         return EBUSY;
164535863739SMike Smith     }
164635863739SMike Smith     sc->aac_state |= AAC_STATE_OPEN;
164735863739SMike Smith 
164835863739SMike Smith     return 0;
164935863739SMike Smith }
165035863739SMike Smith 
165135863739SMike Smith static int
165235863739SMike Smith aac_close(dev_t dev, int flags, int fmt, struct proc *p)
165335863739SMike Smith {
165435863739SMike Smith     struct aac_softc	*sc = dev->si_drv1;
165535863739SMike Smith 
165635863739SMike Smith     debug_called(2);
165735863739SMike Smith 
165835863739SMike Smith     /* Mark this unit as no longer open  */
165935863739SMike Smith     sc->aac_state &= ~AAC_STATE_OPEN;
166035863739SMike Smith 
166135863739SMike Smith     return 0;
166235863739SMike Smith }
166335863739SMike Smith 
166435863739SMike Smith static int
166535863739SMike Smith aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
166635863739SMike Smith {
16670b94a66eSMike Smith     union aac_statrequest	*as = (union aac_statrequest *)arg;
166835863739SMike Smith     struct aac_softc		*sc = dev->si_drv1;
16690b94a66eSMike Smith     int				error = 0;
16700b94a66eSMike Smith #ifdef AAC_COMPAT_LINUX
16710b94a66eSMike Smith     int				i;
16720b94a66eSMike Smith #endif
167335863739SMike Smith 
167435863739SMike Smith     debug_called(2);
167535863739SMike Smith 
167635863739SMike Smith     switch (cmd) {
16770b94a66eSMike Smith     case AACIO_STATS:
16780b94a66eSMike Smith 	switch (as->as_item) {
16790b94a66eSMike Smith 	case AACQ_FREE:
16800b94a66eSMike Smith 	case AACQ_BIO:
16810b94a66eSMike Smith 	case AACQ_READY:
16820b94a66eSMike Smith 	case AACQ_BUSY:
16830b94a66eSMike Smith 	case AACQ_COMPLETE:
16840b94a66eSMike Smith 	    bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, sizeof(struct aac_qstat));
16850b94a66eSMike Smith 	    break;
16860b94a66eSMike Smith 	default:
16870b94a66eSMike Smith 	    error = ENOENT;
16880b94a66eSMike Smith 	    break;
16890b94a66eSMike Smith 	}
16900b94a66eSMike Smith 	break;
16910b94a66eSMike Smith 
169235863739SMike Smith #ifdef AAC_COMPAT_LINUX
169335863739SMike Smith     case FSACTL_SENDFIB:
16940b94a66eSMike Smith 	debug(1, "FSACTL_SENDFIB");
169535863739SMike Smith 	error = aac_ioctl_sendfib(sc, arg);
169635863739SMike Smith 	break;
169735863739SMike Smith     case FSACTL_AIF_THREAD:
16980b94a66eSMike Smith 	debug(1, "FSACTL_AIF_THREAD");
169935863739SMike Smith 	error = EINVAL;
170035863739SMike Smith 	break;
170135863739SMike Smith     case FSACTL_OPEN_GET_ADAPTER_FIB:
17020b94a66eSMike Smith 	debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
170335863739SMike Smith 	/*
170435863739SMike Smith 	 * Pass the caller out an AdapterFibContext.
170535863739SMike Smith 	 *
170635863739SMike Smith 	 * Note that because we only support one opener, we
170735863739SMike Smith 	 * basically ignore this.  Set the caller's context to a magic
170835863739SMike Smith 	 * number just in case.
17090b94a66eSMike Smith 	 *
17100b94a66eSMike Smith 	 * The Linux code hands the driver a pointer into kernel space,
17110b94a66eSMike Smith 	 * and then trusts it when the caller hands it back.  Aiee!
171235863739SMike Smith 	 */
171335863739SMike Smith 	i = AAC_AIF_SILLYMAGIC;
171435863739SMike Smith 	error = copyout(&i, arg, sizeof(i));
171535863739SMike Smith 	break;
171635863739SMike Smith     case FSACTL_GET_NEXT_ADAPTER_FIB:
17170b94a66eSMike Smith 	debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
171835863739SMike Smith 	error = aac_linux_getnext_aif(sc, arg);
171935863739SMike Smith 	break;
172035863739SMike Smith     case FSACTL_CLOSE_GET_ADAPTER_FIB:
17210b94a66eSMike Smith 	debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
172235863739SMike Smith 	/* don't do anything here */
172335863739SMike Smith 	break;
172435863739SMike Smith     case FSACTL_MINIPORT_REV_CHECK:
17250b94a66eSMike Smith 	debug(1, "FSACTL_MINIPORT_REV_CHECK");
172635863739SMike Smith 	error = aac_linux_rev_check(sc, arg);
172735863739SMike Smith 	break;
172835863739SMike Smith #endif
172935863739SMike Smith     default:
173035863739SMike Smith 	device_printf(sc->aac_dev, "unsupported cmd 0x%lx\n", cmd);
173135863739SMike Smith 	error = EINVAL;
173235863739SMike Smith 	break;
173335863739SMike Smith     }
173435863739SMike Smith     return(error);
173535863739SMike Smith }
173635863739SMike Smith 
173735863739SMike Smith /********************************************************************************
173835863739SMike Smith  * Send a FIB supplied from userspace
173935863739SMike Smith  */
174035863739SMike Smith static int
174135863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
174235863739SMike Smith {
174335863739SMike Smith     struct aac_command 	*cm;
174435863739SMike Smith     int			size, error;
174535863739SMike Smith 
174635863739SMike Smith     debug_called(2);
174735863739SMike Smith 
174835863739SMike Smith     cm = NULL;
174935863739SMike Smith 
175035863739SMike Smith     /*
175135863739SMike Smith      * Get a command
175235863739SMike Smith      */
175335863739SMike Smith     if (aac_alloc_command(sc, &cm)) {
175435863739SMike Smith 	error = EBUSY;
175535863739SMike Smith 	goto out;
175635863739SMike Smith     }
175735863739SMike Smith 
175835863739SMike Smith     /*
175935863739SMike Smith      * Fetch the FIB header, then re-copy to get data as well.
176035863739SMike Smith      */
176135863739SMike Smith     if ((error = copyin(ufib, cm->cm_fib, sizeof(struct aac_fib_header))) != 0)
176235863739SMike Smith 	goto out;
176335863739SMike Smith     size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
176435863739SMike Smith     if (size > sizeof(struct aac_fib)) {
176535863739SMike Smith 	device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", size, sizeof(struct aac_fib));
176635863739SMike Smith 	size = sizeof(struct aac_fib);
176735863739SMike Smith     }
176835863739SMike Smith     if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
176935863739SMike Smith 	goto out;
177035863739SMike Smith     cm->cm_fib->Header.Size = size;
177135863739SMike Smith 
177235863739SMike Smith     /*
177335863739SMike Smith      * Pass the FIB to the controller, wait for it to complete.
177435863739SMike Smith      */
177535863739SMike Smith     if ((error = aac_wait_command(cm, 30)) != 0)	/* XXX user timeout? */
177635863739SMike Smith 	goto out;
177735863739SMike Smith 
177835863739SMike Smith     /*
177935863739SMike Smith      * Copy the FIB and data back out to the caller.
178035863739SMike Smith      */
178135863739SMike Smith     size = cm->cm_fib->Header.Size;
178235863739SMike Smith     if (size > sizeof(struct aac_fib)) {
178335863739SMike Smith 	device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", size, sizeof(struct aac_fib));
178435863739SMike Smith 	size = sizeof(struct aac_fib);
178535863739SMike Smith     }
178635863739SMike Smith     error = copyout(cm->cm_fib, ufib, size);
178735863739SMike Smith 
178835863739SMike Smith out:
178935863739SMike Smith     if (cm != NULL)
179035863739SMike Smith 	aac_release_command(cm);
179135863739SMike Smith     return(error);
179235863739SMike Smith }
179335863739SMike Smith 
179435863739SMike Smith /********************************************************************************
179535863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
179635863739SMike Smith  *
179735863739SMike Smith  * XXX what's the right thing to do here when the queue is full?  Drop the older
179835863739SMike Smith  * or newer entries?
179935863739SMike Smith  */
180035863739SMike Smith static void
180135863739SMike Smith aac_handle_aif(struct aac_softc *sc, struct aac_aif_command *aif)
180235863739SMike Smith {
180335863739SMike Smith     int		next, s;
180435863739SMike Smith 
180535863739SMike Smith     debug_called(2);
180635863739SMike Smith 
180735863739SMike Smith     s = splbio();
180835863739SMike Smith     next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
180935863739SMike Smith     if (next != sc->aac_aifq_tail) {
181035863739SMike Smith 	bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
181135863739SMike Smith 	sc->aac_aifq_head = next;
181235863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
181335863739SMike Smith 	    wakeup(sc->aac_aifq);
181435863739SMike Smith     }
181535863739SMike Smith     splx(s);
181635863739SMike Smith     aac_print_aif(sc, aif);
181735863739SMike Smith }
181835863739SMike Smith 
181935863739SMike Smith /********************************************************************************
182035863739SMike Smith  ********************************************************************************
182135863739SMike Smith                                                        Linux Management Interface
182235863739SMike Smith  ********************************************************************************
182335863739SMike Smith  ********************************************************************************/
182435863739SMike Smith 
182535863739SMike Smith #ifdef AAC_COMPAT_LINUX
182635863739SMike Smith 
182730d57611SMike Smith #include <sys/proc.h>
182835863739SMike Smith #include <machine/../linux/linux.h>
182935863739SMike Smith #include <machine/../linux/linux_proto.h>
183035863739SMike Smith #include <compat/linux/linux_ioctl.h>
183135863739SMike Smith 
183235863739SMike Smith #define AAC_LINUX_IOCTL_MIN  0x2000
183335863739SMike Smith #define AAC_LINUX_IOCTL_MAX  0x21ff
183435863739SMike Smith 
183535863739SMike Smith static linux_ioctl_function_t aac_linux_ioctl;
183635863739SMike Smith static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl, AAC_LINUX_IOCTL_MIN, AAC_LINUX_IOCTL_MAX};
183735863739SMike Smith 
183835863739SMike Smith SYSINIT  (aac_register,   SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_register_handler, &aac_handler);
183935863739SMike Smith SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_unregister_handler, &aac_handler);
184035863739SMike Smith 
184135863739SMike Smith MODULE_DEPEND(aac, linux, 1, 1, 1);
184235863739SMike Smith 
184335863739SMike Smith static int
184435863739SMike Smith aac_linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
184535863739SMike Smith {
184635863739SMike Smith     struct file		*fp = p->p_fd->fd_ofiles[args->fd];
184735863739SMike Smith     u_long		cmd = args->cmd;
184835863739SMike Smith 
184935863739SMike Smith     /*
185035863739SMike Smith      * Pass the ioctl off to our standard handler.
185135863739SMike Smith      */
185235863739SMike Smith     return(fo_ioctl(fp, cmd, (caddr_t)args->arg, p));
185335863739SMike Smith }
185435863739SMike Smith 
185535863739SMike Smith /********************************************************************************
18560b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
185735863739SMike Smith  * userspace app is possibly compatible.  This is extremely bogus right now
185835863739SMike Smith  * because I have no idea how to handle the versioning of this driver.  It is
185935863739SMike Smith  * needed, though, to get aaccli working.
186035863739SMike Smith  */
186135863739SMike Smith static int
186235863739SMike Smith aac_linux_rev_check(struct aac_softc *sc, caddr_t udata)
186335863739SMike Smith {
186435863739SMike Smith     struct aac_rev_check	rev_check;
186535863739SMike Smith     struct aac_rev_check_resp	rev_check_resp;
186635863739SMike Smith     int				error = 0;
186735863739SMike Smith 
186835863739SMike Smith     debug_called(2);
186935863739SMike Smith 
187035863739SMike Smith     /*
187135863739SMike Smith      * Copyin the revision struct from userspace
187235863739SMike Smith      */
187335863739SMike Smith     if ((error = copyin(udata, (caddr_t)&rev_check, sizeof(struct aac_rev_check))) != 0) {
187435863739SMike Smith 	return error;
187535863739SMike Smith     }
187635863739SMike Smith 
187735863739SMike Smith     debug(2, "Userland revision= %d\n", rev_check.callingRevision.buildNumber);
187835863739SMike Smith 
187935863739SMike Smith     /*
188035863739SMike Smith      * Doctor up the response struct.
188135863739SMike Smith      */
188235863739SMike Smith     rev_check_resp.possiblyCompatible = 1;
188335863739SMike Smith     rev_check_resp.adapterSWRevision.external.ul = sc->aac_revision.external.ul;
188435863739SMike Smith     rev_check_resp.adapterSWRevision.buildNumber = sc->aac_revision.buildNumber;
188535863739SMike Smith 
188635863739SMike Smith     return(copyout((caddr_t)&rev_check_resp, udata, sizeof(struct aac_rev_check_resp)));
188735863739SMike Smith }
188835863739SMike Smith 
188935863739SMike Smith /********************************************************************************
189035863739SMike Smith  * Pass the caller the next AIF in their queue
189135863739SMike Smith  */
189235863739SMike Smith static int
189335863739SMike Smith aac_linux_getnext_aif(struct aac_softc *sc, caddr_t arg)
189435863739SMike Smith {
189535863739SMike Smith     struct get_adapter_fib_ioctl	agf;
189635863739SMike Smith     int					error, s;
189735863739SMike Smith 
189835863739SMike Smith     debug_called(2);
189935863739SMike Smith 
190035863739SMike Smith     if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
190135863739SMike Smith 
190235863739SMike Smith 	/*
190335863739SMike Smith 	 * Check the magic number that we gave the caller.
190435863739SMike Smith 	 */
190535863739SMike Smith 	if (agf.AdapterFibContext != AAC_AIF_SILLYMAGIC) {
190635863739SMike Smith 	    error = EFAULT;
190735863739SMike Smith 	} else {
190835863739SMike Smith 
190935863739SMike Smith 	    s = splbio();
19100b94a66eSMike Smith 	    error = aac_linux_return_aif(sc, agf.AifFib);
191135863739SMike Smith 
191235863739SMike Smith 	    if ((error == EAGAIN) && (agf.Wait)) {
191335863739SMike Smith 		sc->aac_state |= AAC_STATE_AIF_SLEEPER;
191435863739SMike Smith 		while (error == EAGAIN) {
191535863739SMike Smith 		    error = tsleep(sc->aac_aifq, PRIBIO | PCATCH, "aacaif", 0);
191635863739SMike Smith 		    if (error == 0)
19170b94a66eSMike Smith 			error = aac_linux_return_aif(sc, agf.AifFib);
191835863739SMike Smith 		}
191935863739SMike Smith 		sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
192035863739SMike Smith 	    }
192135863739SMike Smith 	    splx(s);
192235863739SMike Smith 	}
192335863739SMike Smith     }
192435863739SMike Smith     return(error);
192535863739SMike Smith }
192635863739SMike Smith 
19270b94a66eSMike Smith /********************************************************************************
19280b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
19290b94a66eSMike Smith  */
19300b94a66eSMike Smith static int
19310b94a66eSMike Smith aac_linux_return_aif(struct aac_softc *sc, caddr_t uptr)
19320b94a66eSMike Smith {
19330b94a66eSMike Smith     int		error, s;
19340b94a66eSMike Smith 
19350b94a66eSMike Smith     debug_called(2);
19360b94a66eSMike Smith 
19370b94a66eSMike Smith     s = splbio();
19380b94a66eSMike Smith     if (sc->aac_aifq_tail == sc->aac_aifq_head) {
19390b94a66eSMike Smith 	error = EAGAIN;
19400b94a66eSMike Smith     } else {
19410b94a66eSMike Smith 	error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr, sizeof(struct aac_aif_command));
19420b94a66eSMike Smith 	if (!error)
19430b94a66eSMike Smith 	    sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
19440b94a66eSMike Smith     }
19450b94a66eSMike Smith     splx(s);
19460b94a66eSMike Smith     return(error);
19470b94a66eSMike Smith }
19480b94a66eSMike Smith 
19490b94a66eSMike Smith 
195035863739SMike Smith #endif /* AAC_COMPAT_LINUX */
1951