xref: /freebsd/sys/dev/aac/aac.c (revision 4afedc314e8e6ded5fb719708bcc78deba2eadcb)
135863739SMike Smith /*-
235863739SMike Smith  * Copyright (c) 2000 Michael Smith
3c6eafcf2SScott Long  * Copyright (c) 2001 Scott Long
435863739SMike Smith  * Copyright (c) 2000 BSDi
5c6eafcf2SScott Long  * Copyright (c) 2001 Adaptec, Inc.
635863739SMike Smith  * All rights reserved.
735863739SMike Smith  *
835863739SMike Smith  * Redistribution and use in source and binary forms, with or without
935863739SMike Smith  * modification, are permitted provided that the following conditions
1035863739SMike Smith  * are met:
1135863739SMike Smith  * 1. Redistributions of source code must retain the above copyright
1235863739SMike Smith  *    notice, this list of conditions and the following disclaimer.
1335863739SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1435863739SMike Smith  *    notice, this list of conditions and the following disclaimer in the
1535863739SMike Smith  *    documentation and/or other materials provided with the distribution.
1635863739SMike Smith  *
1735863739SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1835863739SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1935863739SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2035863739SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2135863739SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2235863739SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2335863739SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2435863739SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2535863739SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2635863739SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2735863739SMike Smith  * SUCH DAMAGE.
2835863739SMike Smith  */
2935863739SMike Smith 
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
32aad970f1SDavid E. O'Brien 
3335863739SMike Smith /*
3435863739SMike Smith  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3535863739SMike Smith  */
3635863739SMike Smith 
37f6c4dd3fSScott Long #include "opt_aac.h"
38f6c4dd3fSScott Long 
3936e0bf6eSScott Long /* #include <stddef.h> */
4035863739SMike Smith #include <sys/param.h>
4135863739SMike Smith #include <sys/systm.h>
4235863739SMike Smith #include <sys/malloc.h>
4335863739SMike Smith #include <sys/kernel.h>
4436e0bf6eSScott Long #include <sys/kthread.h>
453d04a9d7SScott Long #include <sys/sysctl.h>
46b3457b51SScott Long #include <sys/poll.h>
47891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
4835863739SMike Smith 
4935863739SMike Smith #include <sys/bus.h>
5035863739SMike Smith #include <sys/conf.h>
5135863739SMike Smith #include <sys/signalvar.h>
520b94a66eSMike Smith #include <sys/time.h>
5336e0bf6eSScott Long #include <sys/eventhandler.h>
5435863739SMike Smith 
5535863739SMike Smith #include <machine/bus_memio.h>
5635863739SMike Smith #include <machine/bus.h>
5735863739SMike Smith #include <machine/resource.h>
5835863739SMike Smith 
5935863739SMike Smith #include <dev/aac/aacreg.h>
600b94a66eSMike Smith #include <dev/aac/aac_ioctl.h>
6135863739SMike Smith #include <dev/aac/aacvar.h>
6235863739SMike Smith #include <dev/aac/aac_tables.h>
6335863739SMike Smith 
6435863739SMike Smith static void	aac_startup(void *arg);
65914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
66cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
67fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
6835863739SMike Smith 
6935863739SMike Smith /* Command Processing */
700b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7135863739SMike Smith static void	aac_complete(void *context, int pending);
7235863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7335863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
74d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
7570545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
7635863739SMike Smith 
7735863739SMike Smith /* Command Buffer Management */
78cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
79cd481291SScott Long 				   int nseg, int error);
80c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
81c6eafcf2SScott Long 				       int nseg, int error);
820b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
838480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
8435863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
8535863739SMike Smith 
8635863739SMike Smith /* Hardware Interface */
87c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
88c6eafcf2SScott Long 			       int error);
89fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9035863739SMike Smith static int	aac_init(struct aac_softc *sc);
9135863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
92c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
93c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
94c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
95f6c4dd3fSScott Long 				struct aac_command *cm);
96c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
97914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
9836e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
9936e0bf6eSScott Long 				     struct aac_fib *fib);
10035863739SMike Smith 
101b3457b51SScott Long /* Falcon/PPC interface */
102b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
103b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
104b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
105b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
106b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
107b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
108b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
109a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
110b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
111b3457b51SScott Long 
112b3457b51SScott Long struct aac_interface aac_fa_interface = {
113b3457b51SScott Long 	aac_fa_get_fwstatus,
114b3457b51SScott Long 	aac_fa_qnotify,
115b3457b51SScott Long 	aac_fa_get_istatus,
116b3457b51SScott Long 	aac_fa_clear_istatus,
117b3457b51SScott Long 	aac_fa_set_mailbox,
118a6d35632SScott Long 	aac_fa_get_mailbox,
119b3457b51SScott Long 	aac_fa_set_interrupts
120b3457b51SScott Long };
121b3457b51SScott Long 
12235863739SMike Smith /* StrongARM interface */
12335863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
12435863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
12535863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
12635863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
12735863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
128c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
129c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
130a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13135863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13235863739SMike Smith 
13335863739SMike Smith struct aac_interface aac_sa_interface = {
13435863739SMike Smith 	aac_sa_get_fwstatus,
13535863739SMike Smith 	aac_sa_qnotify,
13635863739SMike Smith 	aac_sa_get_istatus,
13735863739SMike Smith 	aac_sa_clear_istatus,
13835863739SMike Smith 	aac_sa_set_mailbox,
139a6d35632SScott Long 	aac_sa_get_mailbox,
14035863739SMike Smith 	aac_sa_set_interrupts
14135863739SMike Smith };
14235863739SMike Smith 
14335863739SMike Smith /* i960Rx interface */
14435863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
14535863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
14635863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
14735863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
14835863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
149c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
150c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
151a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
15235863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
15335863739SMike Smith 
15435863739SMike Smith struct aac_interface aac_rx_interface = {
15535863739SMike Smith 	aac_rx_get_fwstatus,
15635863739SMike Smith 	aac_rx_qnotify,
15735863739SMike Smith 	aac_rx_get_istatus,
15835863739SMike Smith 	aac_rx_clear_istatus,
15935863739SMike Smith 	aac_rx_set_mailbox,
160a6d35632SScott Long 	aac_rx_get_mailbox,
16135863739SMike Smith 	aac_rx_set_interrupts
16235863739SMike Smith };
16335863739SMike Smith 
1644afedc31SScott Long /* Rocket/MIPS interface */
1654afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1664afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1674afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1684afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1694afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1704afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1714afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1724afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1734afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1744afedc31SScott Long 
1754afedc31SScott Long struct aac_interface aac_rkt_interface = {
1764afedc31SScott Long 	aac_rkt_get_fwstatus,
1774afedc31SScott Long 	aac_rkt_qnotify,
1784afedc31SScott Long 	aac_rkt_get_istatus,
1794afedc31SScott Long 	aac_rkt_clear_istatus,
1804afedc31SScott Long 	aac_rkt_set_mailbox,
1814afedc31SScott Long 	aac_rkt_get_mailbox,
1824afedc31SScott Long 	aac_rkt_set_interrupts
1834afedc31SScott Long };
1844afedc31SScott Long 
18535863739SMike Smith /* Debugging and Diagnostics */
18635863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
1876965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
188c6eafcf2SScott Long 				   u_int32_t code);
18935863739SMike Smith 
19035863739SMike Smith /* Management Interface */
19135863739SMike Smith static d_open_t		aac_open;
19235863739SMike Smith static d_close_t	aac_close;
19335863739SMike Smith static d_ioctl_t	aac_ioctl;
194b3457b51SScott Long static d_poll_t		aac_poll;
195c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
196c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
19736e0bf6eSScott Long 					   struct aac_fib *fib);
198fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
199fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
200fb0c27d7SScott Long static int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
20136e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
20235863739SMike Smith 
20335863739SMike Smith static struct cdevsw aac_cdevsw = {
204dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
205dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2067ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2077ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2087ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2097ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2107ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
21135863739SMike Smith };
21235863739SMike Smith 
21336e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
21436e0bf6eSScott Long 
2153d04a9d7SScott Long /* sysctl node */
2163d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2173d04a9d7SScott Long 
218914da7d0SScott Long /*
219914da7d0SScott Long  * Device Interface
220914da7d0SScott Long  */
22135863739SMike Smith 
222914da7d0SScott Long /*
22335863739SMike Smith  * Initialise the controller and softc
22435863739SMike Smith  */
22535863739SMike Smith int
22635863739SMike Smith aac_attach(struct aac_softc *sc)
22735863739SMike Smith {
22835863739SMike Smith 	int error, unit;
22935863739SMike Smith 
23035863739SMike Smith 	debug_called(1);
23135863739SMike Smith 
23235863739SMike Smith 	/*
23335863739SMike Smith 	 * Initialise per-controller queues.
23435863739SMike Smith 	 */
2350b94a66eSMike Smith 	aac_initq_free(sc);
2360b94a66eSMike Smith 	aac_initq_ready(sc);
2370b94a66eSMike Smith 	aac_initq_busy(sc);
2380b94a66eSMike Smith 	aac_initq_bio(sc);
23935863739SMike Smith 
24035863739SMike Smith 	/*
24135863739SMike Smith 	 * Initialise command-completion task.
24235863739SMike Smith 	 */
24335863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
24435863739SMike Smith 
24535863739SMike Smith 	/* disable interrupts before we enable anything */
24635863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
24735863739SMike Smith 
24835863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
24935863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
25035863739SMike Smith 
25135863739SMike Smith 	/*
252fe94b852SScott Long 	 * Check that the firmware on the card is supported.
253fe94b852SScott Long 	 */
254fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
255fe94b852SScott Long 		return(error);
256fe94b852SScott Long 
257f6b1c44dSScott Long 	/*
258f6b1c44dSScott Long 	 * Initialize locks
259f6b1c44dSScott Long 	 */
260bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
261bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
262bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
263f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
264f6b1c44dSScott Long 
2653df780cfSScott Long 	/* Initialize the local AIF queue pointers */
2663df780cfSScott Long 	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
267cbfd045bSScott Long 
2680b94a66eSMike Smith 	/*
26935863739SMike Smith 	 * Initialise the adapter.
27035863739SMike Smith 	 */
2710b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
27235863739SMike Smith 		return(error);
27335863739SMike Smith 
27435863739SMike Smith 	/*
27535863739SMike Smith 	 * Print a little information about the controller.
27635863739SMike Smith 	 */
27735863739SMike Smith 	aac_describe_controller(sc);
27835863739SMike Smith 
27935863739SMike Smith 	/*
280ae543596SScott Long 	 * Register to probe our containers later.
281ae543596SScott Long 	 */
28235863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
28335863739SMike Smith 	sc->aac_ich.ich_arg = sc;
28435863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
285914da7d0SScott Long 		device_printf(sc->aac_dev,
286914da7d0SScott Long 			      "can't establish configuration hook\n");
28735863739SMike Smith 		return(ENXIO);
28835863739SMike Smith 	}
28935863739SMike Smith 
29035863739SMike Smith 	/*
29135863739SMike Smith 	 * Make the control device.
29235863739SMike Smith 	 */
29335863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
2949e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
2959e9466baSRobert Watson 				 0640, "aac%d", unit);
296157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
2974aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
29835863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
29935863739SMike Smith 
30036e0bf6eSScott Long 	/* Create the AIF thread */
30170545d1aSScott Long 	if (kthread_create((void(*)(void *))aac_command_thread, sc,
302316ec49aSScott Long 			   &sc->aifthread, 0, 0, "aac%daif", unit))
30336e0bf6eSScott Long 		panic("Could not create AIF thread\n");
30436e0bf6eSScott Long 
30536e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3065f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3075f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3085f54d522SScott Long 		device_printf(sc->aac_dev,
3095f54d522SScott Long 			      "shutdown event registration failed\n");
31036e0bf6eSScott Long 
311fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
312a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
31370545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
314fe3cb0e1SScott Long 		aac_get_bus_info(sc);
31570545d1aSScott Long 	}
316fe3cb0e1SScott Long 
31735863739SMike Smith 	return(0);
31835863739SMike Smith }
31935863739SMike Smith 
320914da7d0SScott Long /*
32135863739SMike Smith  * Probe for containers, create disks.
32235863739SMike Smith  */
32335863739SMike Smith static void
32435863739SMike Smith aac_startup(void *arg)
32535863739SMike Smith {
326914da7d0SScott Long 	struct aac_softc *sc;
327cbfd045bSScott Long 	struct aac_fib *fib;
328cbfd045bSScott Long 	struct aac_mntinfo *mi;
329cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
330795d7dc0SScott Long 	int count = 0, i = 0;
33135863739SMike Smith 
33235863739SMike Smith 	debug_called(1);
33335863739SMike Smith 
334914da7d0SScott Long 	sc = (struct aac_softc *)arg;
335914da7d0SScott Long 
33635863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
33735863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
33835863739SMike Smith 
33903b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
340cbfd045bSScott Long 	mi = (struct aac_mntinfo *)&fib->data[0];
341cbfd045bSScott Long 
34235863739SMike Smith 	/* loop over possible containers */
34336e0bf6eSScott Long 	do {
34435863739SMike Smith 		/* request information on this container */
34539ee03c3SScott Long 		bzero(mi, sizeof(struct aac_mntinfo));
34639ee03c3SScott Long 		mi->Command = VM_NameServe;
34739ee03c3SScott Long 		mi->MntType = FT_FILESYS;
348cbfd045bSScott Long 		mi->MntCount = i;
349cbfd045bSScott Long 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
350cbfd045bSScott Long 				 sizeof(struct aac_mntinfo))) {
351795d7dc0SScott Long 			printf("error probing container %d", i);
35235863739SMike Smith 			continue;
35335863739SMike Smith 		}
35435863739SMike Smith 
355cbfd045bSScott Long 		mir = (struct aac_mntinforesp *)&fib->data[0];
356795d7dc0SScott Long 		/* XXX Need to check if count changed */
357795d7dc0SScott Long 		count = mir->MntRespCount;
358cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
35936e0bf6eSScott Long 		i++;
360795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
361cbfd045bSScott Long 
362cbfd045bSScott Long 	aac_release_sync_fib(sc);
36335863739SMike Smith 
36435863739SMike Smith 	/* poke the bus to actually attach the child devices */
36535863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
36635863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
36735863739SMike Smith 
36835863739SMike Smith 	/* mark the controller up */
36935863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
37035863739SMike Smith 
37135863739SMike Smith 	/* enable interrupts now */
37235863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
37335863739SMike Smith }
37435863739SMike Smith 
375914da7d0SScott Long /*
376914da7d0SScott Long  * Create a device to respresent a new container
377914da7d0SScott Long  */
378914da7d0SScott Long static void
379cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
380914da7d0SScott Long {
381914da7d0SScott Long 	struct aac_container *co;
382914da7d0SScott Long 	device_t child;
383914da7d0SScott Long 
384914da7d0SScott Long 	/*
385914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
386914da7d0SScott Long 	 * the possible types may never show up.
387914da7d0SScott Long 	 */
388914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
389a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
390a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
391914da7d0SScott Long 		if (co == NULL)
392914da7d0SScott Long 			panic("Out of memory?!\n");
393914da7d0SScott Long 		debug(1, "id %x  name '%.16s'  size %u  type %d",
394914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
395914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
396914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
397914da7d0SScott Long 
398fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
399914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
400914da7d0SScott Long 		else
401914da7d0SScott Long 			device_set_ivars(child, co);
402914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
403914da7d0SScott Long 				mir->MntTable[0].VolType));
404914da7d0SScott Long 		co->co_disk = child;
405914da7d0SScott Long 		co->co_found = f;
406914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
407914da7d0SScott Long 		      sizeof(struct aac_mntobj));
408bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
409914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
410bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
411914da7d0SScott Long 	}
412914da7d0SScott Long }
413914da7d0SScott Long 
414914da7d0SScott Long /*
41535863739SMike Smith  * Free all of the resources associated with (sc)
41635863739SMike Smith  *
41735863739SMike Smith  * Should not be called if the controller is active.
41835863739SMike Smith  */
41935863739SMike Smith void
42035863739SMike Smith aac_free(struct aac_softc *sc)
42135863739SMike Smith {
422ffb37f33SScott Long 
42335863739SMike Smith 	debug_called(1);
42435863739SMike Smith 
42535863739SMike Smith 	/* remove the control device */
42635863739SMike Smith 	if (sc->aac_dev_t != NULL)
42735863739SMike Smith 		destroy_dev(sc->aac_dev_t);
42835863739SMike Smith 
4290b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
4308480cc63SScott Long 	aac_free_commands(sc);
4310b94a66eSMike Smith 	if (sc->aac_fib_dmat)
4320b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
43335863739SMike Smith 
434ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
435ffb37f33SScott Long 
43635863739SMike Smith 	/* destroy the common area */
43735863739SMike Smith 	if (sc->aac_common) {
43835863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
439c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
440c6eafcf2SScott Long 				sc->aac_common_dmamap);
44135863739SMike Smith 	}
4420b94a66eSMike Smith 	if (sc->aac_common_dmat)
4430b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
44435863739SMike Smith 
44535863739SMike Smith 	/* disconnect the interrupt handler */
44635863739SMike Smith 	if (sc->aac_intr)
44735863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
44835863739SMike Smith 	if (sc->aac_irq != NULL)
449c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
450c6eafcf2SScott Long 				     sc->aac_irq);
45135863739SMike Smith 
45235863739SMike Smith 	/* destroy data-transfer DMA tag */
45335863739SMike Smith 	if (sc->aac_buffer_dmat)
45435863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
45535863739SMike Smith 
45635863739SMike Smith 	/* destroy the parent DMA tag */
45735863739SMike Smith 	if (sc->aac_parent_dmat)
45835863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
45935863739SMike Smith 
46035863739SMike Smith 	/* release the register window mapping */
46135863739SMike Smith 	if (sc->aac_regs_resource != NULL)
462914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
463914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
46435863739SMike Smith }
46535863739SMike Smith 
466914da7d0SScott Long /*
46735863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
46835863739SMike Smith  */
46935863739SMike Smith int
47035863739SMike Smith aac_detach(device_t dev)
47135863739SMike Smith {
472914da7d0SScott Long 	struct aac_softc *sc;
47370545d1aSScott Long 	struct aac_container *co;
47470545d1aSScott Long 	struct aac_sim	*sim;
47535863739SMike Smith 	int error;
47635863739SMike Smith 
47735863739SMike Smith 	debug_called(1);
47835863739SMike Smith 
479914da7d0SScott Long 	sc = device_get_softc(dev);
480914da7d0SScott Long 
48135863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
48235863739SMike Smith 		return(EBUSY);
48335863739SMike Smith 
48470545d1aSScott Long 	/* Remove the child containers */
485a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
48670545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
48770545d1aSScott Long 		if (error)
48870545d1aSScott Long 			return (error);
48965ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
490a761a1caSScott Long 		free(co, M_AACBUF);
49170545d1aSScott Long 	}
49270545d1aSScott Long 
49370545d1aSScott Long 	/* Remove the CAM SIMs */
494a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
495a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
49670545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
49770545d1aSScott Long 		if (error)
49870545d1aSScott Long 			return (error);
499a761a1caSScott Long 		free(sim, M_AACBUF);
50070545d1aSScott Long 	}
50170545d1aSScott Long 
50236e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
50336e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
50436e0bf6eSScott Long 		wakeup(sc->aifthread);
50536e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
50636e0bf6eSScott Long 	}
50736e0bf6eSScott Long 
50836e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
50936e0bf6eSScott Long 		panic("Cannot shutdown AIF thread\n");
51036e0bf6eSScott Long 
51135863739SMike Smith 	if ((error = aac_shutdown(dev)))
51235863739SMike Smith 		return(error);
51335863739SMike Smith 
5145f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
5155f54d522SScott Long 
51635863739SMike Smith 	aac_free(sc);
51735863739SMike Smith 
518dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
519dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
520dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
521dc9efde5SScott Long 
52235863739SMike Smith 	return(0);
52335863739SMike Smith }
52435863739SMike Smith 
525914da7d0SScott Long /*
52635863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
52735863739SMike Smith  *
52835863739SMike Smith  * This function is called before detach or system shutdown.
52935863739SMike Smith  *
5300b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
53135863739SMike Smith  * allow shutdown if any device is open.
53235863739SMike Smith  */
53335863739SMike Smith int
53435863739SMike Smith aac_shutdown(device_t dev)
53535863739SMike Smith {
536914da7d0SScott Long 	struct aac_softc *sc;
537cbfd045bSScott Long 	struct aac_fib *fib;
538cbfd045bSScott Long 	struct aac_close_command *cc;
53935863739SMike Smith 
54035863739SMike Smith 	debug_called(1);
54135863739SMike Smith 
542914da7d0SScott Long 	sc = device_get_softc(dev);
543914da7d0SScott Long 
54435863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
54535863739SMike Smith 
54635863739SMike Smith 	/*
54735863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
54835863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
54935863739SMike Smith 	 * We've been closed and all I/O completed already
55035863739SMike Smith 	 */
55135863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
55235863739SMike Smith 
55303b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
554cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
555cbfd045bSScott Long 
55639ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
557cbfd045bSScott Long 	cc->Command = VM_CloseAll;
558cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
559cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
560cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
56135863739SMike Smith 		printf("FAILED.\n");
56270545d1aSScott Long 	else
56370545d1aSScott Long 		printf("done\n");
56470545d1aSScott Long #if 0
565914da7d0SScott Long 	else {
566cbfd045bSScott Long 		fib->data[0] = 0;
56736e0bf6eSScott Long 		/*
568914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
56936e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
57036e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
57136e0bf6eSScott Long 		 * driver module with the intent to reload it later.
57236e0bf6eSScott Long 		 */
573cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
574cbfd045bSScott Long 		    fib, 1)) {
57535863739SMike Smith 			printf("FAILED.\n");
57635863739SMike Smith 		} else {
57735863739SMike Smith 			printf("done.\n");
57835863739SMike Smith 		}
57935863739SMike Smith 	}
58070545d1aSScott Long #endif
58135863739SMike Smith 
58235863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
5833576af8fSScott Long 	aac_release_sync_fib(sc);
58435863739SMike Smith 
58535863739SMike Smith 	return(0);
58635863739SMike Smith }
58735863739SMike Smith 
588914da7d0SScott Long /*
58935863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
59035863739SMike Smith  */
59135863739SMike Smith int
59235863739SMike Smith aac_suspend(device_t dev)
59335863739SMike Smith {
594914da7d0SScott Long 	struct aac_softc *sc;
59535863739SMike Smith 
59635863739SMike Smith 	debug_called(1);
597914da7d0SScott Long 
598914da7d0SScott Long 	sc = device_get_softc(dev);
599914da7d0SScott Long 
60035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
60135863739SMike Smith 
60235863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
60335863739SMike Smith 	return(0);
60435863739SMike Smith }
60535863739SMike Smith 
606914da7d0SScott Long /*
60735863739SMike Smith  * Bring the controller back to a state ready for operation.
60835863739SMike Smith  */
60935863739SMike Smith int
61035863739SMike Smith aac_resume(device_t dev)
61135863739SMike Smith {
612914da7d0SScott Long 	struct aac_softc *sc;
61335863739SMike Smith 
61435863739SMike Smith 	debug_called(1);
615914da7d0SScott Long 
616914da7d0SScott Long 	sc = device_get_softc(dev);
617914da7d0SScott Long 
61835863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
61935863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
62035863739SMike Smith 	return(0);
62135863739SMike Smith }
62235863739SMike Smith 
623914da7d0SScott Long /*
62435863739SMike Smith  * Take an interrupt.
62535863739SMike Smith  */
62635863739SMike Smith void
62735863739SMike Smith aac_intr(void *arg)
62835863739SMike Smith {
629914da7d0SScott Long 	struct aac_softc *sc;
63070545d1aSScott Long 	u_int16_t reason;
63135863739SMike Smith 
63235863739SMike Smith 	debug_called(2);
63335863739SMike Smith 
634914da7d0SScott Long 	sc = (struct aac_softc *)arg;
635914da7d0SScott Long 
636f30ac74cSScott Long 	/*
6379148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
6389148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
6399148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
6409148fa21SScott Long 	 * ugly.
641f30ac74cSScott Long 	 */
64235863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
643f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
644f30ac74cSScott Long 
6459c3a7fceSScott Long 	/* handle completion processing */
6469148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
6479148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
64835863739SMike Smith 
6499148fa21SScott Long 	/* controller wants to talk to us */
6509148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
65170545d1aSScott Long 		/*
6529148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
6539148fa21SScott Long 		 * that start with a NULL.
65470545d1aSScott Long 		 */
6559148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
6569148fa21SScott Long 		    (sc->aac_common->ac_printf[0] == 0))
6579148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
65870545d1aSScott Long 
6599148fa21SScott Long 		/*
6609148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
661a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
6629148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
6639148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
6649148fa21SScott Long 		 * if needed.
6659148fa21SScott Long 		 */
66636e0bf6eSScott Long 		wakeup(sc->aifthread);
66736e0bf6eSScott Long 	}
6689148fa21SScott Long }
66935863739SMike Smith 
670c6eafcf2SScott Long /*
671914da7d0SScott Long  * Command Processing
672914da7d0SScott Long  */
67335863739SMike Smith 
674914da7d0SScott Long /*
67535863739SMike Smith  * Start as much queued I/O as possible on the controller
67635863739SMike Smith  */
677fe3cb0e1SScott Long void
67835863739SMike Smith aac_startio(struct aac_softc *sc)
67935863739SMike Smith {
68035863739SMike Smith 	struct aac_command *cm;
681397fa34fSScott Long 	int error;
68235863739SMike Smith 
68335863739SMike Smith 	debug_called(2);
68435863739SMike Smith 
68535863739SMike Smith 	for (;;) {
686914da7d0SScott Long 		/*
687397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
688397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
689397fa34fSScott Long 		 */
690397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
691397fa34fSScott Long 			break;
692397fa34fSScott Long 
693397fa34fSScott Long 		/*
694914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
695914da7d0SScott Long 		 * resources
696914da7d0SScott Long 		 */
69735863739SMike Smith 		cm = aac_dequeue_ready(sc);
69835863739SMike Smith 
699914da7d0SScott Long 		/*
700914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
701914da7d0SScott Long 		 * return)
702914da7d0SScott Long 		 */
7030b94a66eSMike Smith 		if (cm == NULL)
70435863739SMike Smith 			aac_bio_command(sc, &cm);
70535863739SMike Smith 
70635863739SMike Smith 		/* nothing to do? */
70735863739SMike Smith 		if (cm == NULL)
70835863739SMike Smith 			break;
70935863739SMike Smith 
710cd481291SScott Long 		/* don't map more than once */
711cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
7124102d44bSScott Long 			panic("aac: command %p already mapped", cm);
71335863739SMike Smith 
714397fa34fSScott Long 		/*
715397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
716397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
717397fa34fSScott Long 		 * busdma.
718397fa34fSScott Long 		 */
719cd481291SScott Long 		if (cm->cm_datalen != 0) {
720397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
721397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
722397fa34fSScott Long 						cm->cm_datalen,
723cd481291SScott Long 						aac_map_command_sg, cm, 0);
724cd481291SScott Long 			if (error == EINPROGRESS) {
725cd481291SScott Long 				debug(1, "freezing queue\n");
726cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
727cd481291SScott Long 				error = 0;
728614c22b2SScott Long 			} else if (error != 0)
729397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
730397fa34fSScott Long 				      "busdma\n", error);
731397fa34fSScott Long 		} else
7328778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
733cd481291SScott Long 	}
73435863739SMike Smith }
73535863739SMike Smith 
736914da7d0SScott Long /*
73735863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
73835863739SMike Smith  */
73935863739SMike Smith static void
74070545d1aSScott Long aac_command_thread(struct aac_softc *sc)
74135863739SMike Smith {
74235863739SMike Smith 	struct aac_fib *fib;
74335863739SMike Smith 	u_int32_t fib_size;
7449148fa21SScott Long 	int size, retval;
74535863739SMike Smith 
74636e0bf6eSScott Long 	debug_called(2);
74735863739SMike Smith 
748bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
749a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
75036e0bf6eSScott Long 
751a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
752a32a982dSScott Long 
753a32a982dSScott Long 		retval = 0;
754a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
755a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
756a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
75736e0bf6eSScott Long 
7589148fa21SScott Long 		/*
7599148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
7609148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
7619148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
7629148fa21SScott Long 		 */
7639148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
764bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
765a32a982dSScott Long 			aac_alloc_commands(sc);
766bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
7674102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
768a32a982dSScott Long 			aac_startio(sc);
769a32a982dSScott Long 		}
7709148fa21SScott Long 
7719148fa21SScott Long 		/*
7729148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
7739148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
7749148fa21SScott Long 		 * always fire.
7759148fa21SScott Long 		 */
7769148fa21SScott Long 		if (retval == EWOULDBLOCK)
77770545d1aSScott Long 			aac_timeout(sc);
77870545d1aSScott Long 
77970545d1aSScott Long 		/* Check the hardware printf message buffer */
7809148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
78170545d1aSScott Long 			aac_print_printf(sc);
78270545d1aSScott Long 
7839148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
7849148fa21SScott Long 		while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
7859148fa21SScott Long 				       &fib_size, &fib) == 0) {
78635863739SMike Smith 
78736e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
78836e0bf6eSScott Long 
78935863739SMike Smith 			switch (fib->Header.Command) {
79035863739SMike Smith 			case AifRequest:
79136e0bf6eSScott Long 				aac_handle_aif(sc, fib);
79235863739SMike Smith 				break;
79335863739SMike Smith 			default:
794914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
795914da7d0SScott Long 					      "from controller\n");
79635863739SMike Smith 				break;
79735863739SMike Smith 			}
79835863739SMike Smith 
79936e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
80036e0bf6eSScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
80136e0bf6eSScott Long 				break;
80236e0bf6eSScott Long 
80370545d1aSScott Long 			/* Return the AIF to the controller. */
80436e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
80536e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
80636e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
80736e0bf6eSScott Long 
80836e0bf6eSScott Long 				/* XXX Compute the Size field? */
80936e0bf6eSScott Long 				size = fib->Header.Size;
81036e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
81136e0bf6eSScott Long 					size = sizeof(struct aac_fib);
81236e0bf6eSScott Long 					fib->Header.Size = size;
81336e0bf6eSScott Long 				}
81436e0bf6eSScott Long 				/*
815914da7d0SScott Long 				 * Since we did not generate this command, it
816914da7d0SScott Long 				 * cannot go through the normal
817914da7d0SScott Long 				 * enqueue->startio chain.
81836e0bf6eSScott Long 				 */
819914da7d0SScott Long 				aac_enqueue_response(sc,
820914da7d0SScott Long 						     AAC_ADAP_NORM_RESP_QUEUE,
821914da7d0SScott Long 						     fib);
82236e0bf6eSScott Long 			}
82336e0bf6eSScott Long 		}
82436e0bf6eSScott Long 	}
82536e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
826bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
82736e0bf6eSScott Long 	wakeup(sc->aac_dev);
82836e0bf6eSScott Long 
82936e0bf6eSScott Long 	kthread_exit(0);
83035863739SMike Smith }
83135863739SMike Smith 
832914da7d0SScott Long /*
8339c3a7fceSScott Long  * Process completed commands.
83435863739SMike Smith  */
83535863739SMike Smith static void
8369c3a7fceSScott Long aac_complete(void *context, int pending)
83735863739SMike Smith {
8389c3a7fceSScott Long 	struct aac_softc *sc;
83935863739SMike Smith 	struct aac_command *cm;
84035863739SMike Smith 	struct aac_fib *fib;
84135863739SMike Smith 	u_int32_t fib_size;
84235863739SMike Smith 
84335863739SMike Smith 	debug_called(2);
84435863739SMike Smith 
8459c3a7fceSScott Long 	sc = (struct aac_softc *)context;
8469c3a7fceSScott Long 
847bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
848ae543596SScott Long 
8499c3a7fceSScott Long 	/* pull completed commands off the queue */
85035863739SMike Smith 	for (;;) {
85135863739SMike Smith 		/* look for completed FIBs on our queue */
852914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
853914da7d0SScott Long 				    &fib))
85435863739SMike Smith 			break;	/* nothing to do */
85535863739SMike Smith 
856ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
857cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
85835863739SMike Smith 		if (cm == NULL) {
85935863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
8609c3a7fceSScott Long 			break;
8619c3a7fceSScott Long 		}
8629c3a7fceSScott Long 
8630b94a66eSMike Smith 		aac_remove_busy(cm);
864ecd1c51fSScott Long 		aac_unmap_command(cm);
86535863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
86635863739SMike Smith 
86735863739SMike Smith 		/* is there a completion handler? */
86835863739SMike Smith 		if (cm->cm_complete != NULL) {
86935863739SMike Smith 			cm->cm_complete(cm);
87035863739SMike Smith 		} else {
87135863739SMike Smith 			/* assume that someone is sleeping on this command */
87235863739SMike Smith 			wakeup(cm);
87335863739SMike Smith 		}
87435863739SMike Smith 	}
8750b94a66eSMike Smith 
8760b94a66eSMike Smith 	/* see if we can start some more I/O */
877cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
8780b94a66eSMike Smith 	aac_startio(sc);
879ae543596SScott Long 
880bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
88135863739SMike Smith }
88235863739SMike Smith 
883914da7d0SScott Long /*
88435863739SMike Smith  * Handle a bio submitted from a disk device.
88535863739SMike Smith  */
88635863739SMike Smith void
88735863739SMike Smith aac_submit_bio(struct bio *bp)
88835863739SMike Smith {
889914da7d0SScott Long 	struct aac_disk *ad;
890914da7d0SScott Long 	struct aac_softc *sc;
89135863739SMike Smith 
89235863739SMike Smith 	debug_called(2);
89335863739SMike Smith 
8947540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
895914da7d0SScott Long 	sc = ad->ad_controller;
896914da7d0SScott Long 
89735863739SMike Smith 	/* queue the BIO and try to get some work done */
8980b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
89935863739SMike Smith 	aac_startio(sc);
90035863739SMike Smith }
90135863739SMike Smith 
902914da7d0SScott Long /*
90335863739SMike Smith  * Get a bio and build a command to go with it.
90435863739SMike Smith  */
90535863739SMike Smith static int
90635863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
90735863739SMike Smith {
90835863739SMike Smith 	struct aac_command *cm;
90935863739SMike Smith 	struct aac_fib *fib;
91035863739SMike Smith 	struct aac_disk *ad;
91135863739SMike Smith 	struct bio *bp;
91235863739SMike Smith 
91335863739SMike Smith 	debug_called(2);
91435863739SMike Smith 
91535863739SMike Smith 	/* get the resources we will need */
91635863739SMike Smith 	cm = NULL;
917a32a982dSScott Long 	bp = NULL;
91835863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
91935863739SMike Smith 		goto fail;
920a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
921a32a982dSScott Long 		goto fail;
92235863739SMike Smith 
92335863739SMike Smith 	/* fill out the command */
9240b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
9250b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
9260b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
92735863739SMike Smith 	cm->cm_private = bp;
9280b94a66eSMike Smith 	cm->cm_timestamp = time_second;
92936e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
93035863739SMike Smith 
93135863739SMike Smith 	/* build the FIB */
93235863739SMike Smith 	fib = cm->cm_fib;
933b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
93435863739SMike Smith 	fib->Header.XferState =
93535863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
93635863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
937f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
93835863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
93935863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
940f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
941f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
942f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
94335863739SMike Smith 
94435863739SMike Smith 	/* build the read/write request */
9457540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
946b85f5808SScott Long 
947b85f5808SScott Long 	if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
948b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
9499e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
950b85f5808SScott Long 			struct aac_blockread *br;
95135863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
95235863739SMike Smith 			br->Command = VM_CtBlockRead;
95335863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
95435863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
95535863739SMike Smith 			br->ByteCount = bp->bio_bcount;
95635863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
95735863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
95835863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
95935863739SMike Smith 		} else {
960b85f5808SScott Long 			struct aac_blockwrite *bw;
96135863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
96235863739SMike Smith 			bw->Command = VM_CtBlockWrite;
96335863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
96435863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
96535863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
966b85f5808SScott Long 			bw->Stable = CUNSTABLE;
96735863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
96835863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
96935863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
97035863739SMike Smith 		}
971b85f5808SScott Long 	} else {
972b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
973b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
974b85f5808SScott Long 			struct aac_blockread64 *br;
975b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
976b85f5808SScott Long 			br->Command = VM_CtHostRead64;
977b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
978b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
979b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
980b85f5808SScott Long 			br->Pad = 0;
981b85f5808SScott Long 			br->Flags = 0;
982b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
983b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
984eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
985b85f5808SScott Long 		} else {
986b85f5808SScott Long 			struct aac_blockwrite64 *bw;
987b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
988b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
989b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
990b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
991b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
992b85f5808SScott Long 			bw->Pad = 0;
993b85f5808SScott Long 			bw->Flags = 0;
994b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
995b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
996eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
997b85f5808SScott Long 		}
998b85f5808SScott Long 	}
99935863739SMike Smith 
100035863739SMike Smith 	*cmp = cm;
100135863739SMike Smith 	return(0);
100235863739SMike Smith 
100335863739SMike Smith fail:
100435863739SMike Smith 	if (bp != NULL)
10050b94a66eSMike Smith 		aac_enqueue_bio(sc, bp);
100635863739SMike Smith 	if (cm != NULL)
100735863739SMike Smith 		aac_release_command(cm);
100835863739SMike Smith 	return(ENOMEM);
100935863739SMike Smith }
101035863739SMike Smith 
1011914da7d0SScott Long /*
101235863739SMike Smith  * Handle a bio-instigated command that has been completed.
101335863739SMike Smith  */
101435863739SMike Smith static void
101535863739SMike Smith aac_bio_complete(struct aac_command *cm)
101635863739SMike Smith {
101735863739SMike Smith 	struct aac_blockread_response *brr;
101835863739SMike Smith 	struct aac_blockwrite_response *bwr;
101935863739SMike Smith 	struct bio *bp;
102035863739SMike Smith 	AAC_FSAStatus status;
102135863739SMike Smith 
102235863739SMike Smith 	/* fetch relevant status and then release the command */
102335863739SMike Smith 	bp = (struct bio *)cm->cm_private;
10249e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
102535863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
102635863739SMike Smith 		status = brr->Status;
102735863739SMike Smith 	} else {
102835863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
102935863739SMike Smith 		status = bwr->Status;
103035863739SMike Smith 	}
103135863739SMike Smith 	aac_release_command(cm);
103235863739SMike Smith 
103335863739SMike Smith 	/* fix up the bio based on status */
103435863739SMike Smith 	if (status == ST_OK) {
103535863739SMike Smith 		bp->bio_resid = 0;
103635863739SMike Smith 	} else {
103735863739SMike Smith 		bp->bio_error = EIO;
103835863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
10390b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1040914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1041914da7d0SScott Long 						    status);
104235863739SMike Smith 	}
10430b94a66eSMike Smith 	aac_biodone(bp);
104435863739SMike Smith }
104535863739SMike Smith 
1046914da7d0SScott Long /*
104735863739SMike Smith  * Submit a command to the controller, return when it completes.
1048b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1049b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1050d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1051d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1052d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1053d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1054d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
105535863739SMike Smith  */
105635863739SMike Smith static int
1057d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
105835863739SMike Smith {
1059ae543596SScott Long 	struct aac_softc *sc;
1060d8a0a473SScott Long 	int error;
106135863739SMike Smith 
106235863739SMike Smith 	debug_called(2);
106335863739SMike Smith 
1064ae543596SScott Long 	sc = cm->cm_sc;
1065ae543596SScott Long 
106635863739SMike Smith 	/* Put the command on the ready queue and get things going */
106736e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
106835863739SMike Smith 	aac_enqueue_ready(cm);
1069ae543596SScott Long 	aac_startio(sc);
1070ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
107135863739SMike Smith 	return(error);
107235863739SMike Smith }
107335863739SMike Smith 
1074914da7d0SScott Long /*
1075914da7d0SScott Long  *Command Buffer Management
1076914da7d0SScott Long  */
107735863739SMike Smith 
1078914da7d0SScott Long /*
107935863739SMike Smith  * Allocate a command.
108035863739SMike Smith  */
1081fe3cb0e1SScott Long int
108235863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
108335863739SMike Smith {
108435863739SMike Smith 	struct aac_command *cm;
108535863739SMike Smith 
108635863739SMike Smith 	debug_called(3);
108735863739SMike Smith 
1088ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1089b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1090ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1091ae543596SScott Long 			wakeup(sc->aifthread);
1092b85f5808SScott Long 		}
1093ae543596SScott Long 		return (EBUSY);
1094ffb37f33SScott Long 	}
109535863739SMike Smith 
10960b94a66eSMike Smith 	*cmp = cm;
10970b94a66eSMike Smith 	return(0);
10980b94a66eSMike Smith }
10990b94a66eSMike Smith 
1100914da7d0SScott Long /*
11010b94a66eSMike Smith  * Release a command back to the freelist.
11020b94a66eSMike Smith  */
1103fe3cb0e1SScott Long void
11040b94a66eSMike Smith aac_release_command(struct aac_command *cm)
11050b94a66eSMike Smith {
11060b94a66eSMike Smith 	debug_called(3);
11070b94a66eSMike Smith 
11080b94a66eSMike Smith 	/* (re)initialise the command/FIB */
110935863739SMike Smith 	cm->cm_sgtable = NULL;
111035863739SMike Smith 	cm->cm_flags = 0;
111135863739SMike Smith 	cm->cm_complete = NULL;
111235863739SMike Smith 	cm->cm_private = NULL;
111335863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
111435863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
111535863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
111635863739SMike Smith 	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
111735863739SMike Smith 
111835863739SMike Smith 	/*
111935863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
112035863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
112135863739SMike Smith 	 * initialised here for debugging purposes only.
112235863739SMike Smith 	 */
1123f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1124f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
112535863739SMike Smith 
112635863739SMike Smith 	aac_enqueue_free(cm);
112735863739SMike Smith }
112835863739SMike Smith 
1129914da7d0SScott Long /*
11300b94a66eSMike Smith  * Map helper for command/FIB allocation.
113135863739SMike Smith  */
113235863739SMike Smith static void
11330b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
113435863739SMike Smith {
11358480cc63SScott Long 	uint32_t	*fibphys;
1136914da7d0SScott Long 
11378480cc63SScott Long 	fibphys = (uint32_t *)arg;
113835863739SMike Smith 
113935863739SMike Smith 	debug_called(3);
114035863739SMike Smith 
1141ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
114235863739SMike Smith }
114335863739SMike Smith 
1144914da7d0SScott Long /*
11450b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
114635863739SMike Smith  */
11470b94a66eSMike Smith static int
11480b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
114935863739SMike Smith {
115035863739SMike Smith 	struct aac_command *cm;
1151ffb37f33SScott Long 	struct aac_fibmap *fm;
11528480cc63SScott Long 	uint32_t fibphys;
1153ffb37f33SScott Long 	int i, error;
115435863739SMike Smith 
1155a6d35632SScott Long 	debug_called(2);
115635863739SMike Smith 
1157a6d35632SScott Long 	if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
1158ffb37f33SScott Long 		return (ENOMEM);
1159ffb37f33SScott Long 
11608480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1161a6d35632SScott Long 	if (fm == NULL)
1162a6d35632SScott Long 		return (ENOMEM);
1163ffb37f33SScott Long 
11640b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1165ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1166ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
116770545d1aSScott Long 		device_printf(sc->aac_dev,
116870545d1aSScott Long 			      "Not enough contiguous memory available.\n");
11698480cc63SScott Long 		free(fm, M_AACBUF);
11700b94a66eSMike Smith 		return (ENOMEM);
117135863739SMike Smith 	}
1172128aa5a0SScott Long 
1173cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1174cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1175ffb37f33SScott Long 			      AAC_FIB_COUNT * sizeof(struct aac_fib),
1176ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1177128aa5a0SScott Long 
11780b94a66eSMike Smith 	/* initialise constant fields in the command structure */
1179bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1180ffb37f33SScott Long 	bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
11810b94a66eSMike Smith 	for (i = 0; i < AAC_FIB_COUNT; i++) {
11828480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1183ffb37f33SScott Long 		fm->aac_commands = cm;
118435863739SMike Smith 		cm->cm_sc = sc;
1185ffb37f33SScott Long 		cm->cm_fib = fm->aac_fibs + i;
11868480cc63SScott Long 		cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib));
1187cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
118835863739SMike Smith 
1189ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1190ffb37f33SScott Long 					       &cm->cm_datamap)) == 0)
119135863739SMike Smith 			aac_release_command(cm);
1192ffb37f33SScott Long 		else
11938480cc63SScott Long 			break;
11948480cc63SScott Long 		sc->total_fibs++;
119535863739SMike Smith 	}
1196ffb37f33SScott Long 
11978480cc63SScott Long 	if (i > 0) {
1198ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1199a6d35632SScott Long 		debug(1, "total_fibs= %d\n", sc->total_fibs);
1200bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
12010b94a66eSMike Smith 		return (0);
120235863739SMike Smith 	}
120335863739SMike Smith 
1204bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
12058480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
12068480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
12078480cc63SScott Long 	free(fm, M_AACBUF);
12088480cc63SScott Long 	return (ENOMEM);
12098480cc63SScott Long }
12108480cc63SScott Long 
1211914da7d0SScott Long /*
12120b94a66eSMike Smith  * Free FIBs owned by this adapter.
121335863739SMike Smith  */
121435863739SMike Smith static void
12158480cc63SScott Long aac_free_commands(struct aac_softc *sc)
121635863739SMike Smith {
12178480cc63SScott Long 	struct aac_fibmap *fm;
1218ffb37f33SScott Long 	struct aac_command *cm;
121935863739SMike Smith 	int i;
122035863739SMike Smith 
122135863739SMike Smith 	debug_called(1);
122235863739SMike Smith 
12238480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
12248480cc63SScott Long 
12258480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
12268480cc63SScott Long 		/*
12278480cc63SScott Long 		 * We check against total_fibs to handle partially
12288480cc63SScott Long 		 * allocated blocks.
12298480cc63SScott Long 		 */
12308480cc63SScott Long 		for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
1231ffb37f33SScott Long 			cm = fm->aac_commands + i;
1232ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1233ffb37f33SScott Long 		}
1234ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1235ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
12368480cc63SScott Long 		free(fm, M_AACBUF);
12378480cc63SScott Long 	}
123835863739SMike Smith }
123935863739SMike Smith 
1240914da7d0SScott Long /*
124135863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
124235863739SMike Smith  */
124335863739SMike Smith static void
124435863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
124535863739SMike Smith {
1246cd481291SScott Long 	struct aac_softc *sc;
1247914da7d0SScott Long 	struct aac_command *cm;
1248914da7d0SScott Long 	struct aac_fib *fib;
124935863739SMike Smith 	int i;
125035863739SMike Smith 
125135863739SMike Smith 	debug_called(3);
125235863739SMike Smith 
1253914da7d0SScott Long 	cm = (struct aac_command *)arg;
1254cd481291SScott Long 	sc = cm->cm_sc;
1255914da7d0SScott Long 	fib = cm->cm_fib;
1256914da7d0SScott Long 
125735863739SMike Smith 	/* copy into the FIB */
1258b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
1259b85f5808SScott Long 		if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1260b85f5808SScott Long 			struct aac_sg_table *sg;
1261b85f5808SScott Long 			sg = cm->cm_sgtable;
126235863739SMike Smith 			sg->SgCount = nseg;
126335863739SMike Smith 			for (i = 0; i < nseg; i++) {
126435863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
126535863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
126635863739SMike Smith 			}
126735863739SMike Smith 			/* update the FIB size for the s/g count */
126835863739SMike Smith 			fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
1269b85f5808SScott Long 		} else {
1270b85f5808SScott Long 			struct aac_sg_table64 *sg;
1271b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1272b85f5808SScott Long 			sg->SgCount = nseg;
1273b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1274b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1275b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
127635863739SMike Smith 			}
1277b85f5808SScott Long 			/* update the FIB size for the s/g count */
1278b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1279b85f5808SScott Long 		}
1280b85f5808SScott Long 	}
128135863739SMike Smith 
1282cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1283cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
1284cd481291SScott Long 	 * the SenderFibAddress over to make room for the fast response bit.
128535863739SMike Smith 	 */
1286cd481291SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
1287cd481291SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
128835863739SMike Smith 
1289cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1290cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
129135863739SMike Smith 
129235863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1293c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1294c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
129535863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1296c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1297c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
129835863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1299cd481291SScott Long 
1300397fa34fSScott Long 	/* Put the FIB on the outbound queue */
13014102d44bSScott Long 	if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
13024102d44bSScott Long 		aac_unmap_command(cm);
1303397fa34fSScott Long 		sc->flags |= AAC_QUEUE_FRZN;
1304cd481291SScott Long 		aac_requeue_ready(cm);
13054102d44bSScott Long 	}
1306cd481291SScott Long 
1307cd481291SScott Long 	return;
130835863739SMike Smith }
130935863739SMike Smith 
1310914da7d0SScott Long /*
131135863739SMike Smith  * Unmap a command from controller-visible space.
131235863739SMike Smith  */
131335863739SMike Smith static void
131435863739SMike Smith aac_unmap_command(struct aac_command *cm)
131535863739SMike Smith {
1316914da7d0SScott Long 	struct aac_softc *sc;
131735863739SMike Smith 
131835863739SMike Smith 	debug_called(2);
131935863739SMike Smith 
1320914da7d0SScott Long 	sc = cm->cm_sc;
1321914da7d0SScott Long 
132235863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
132335863739SMike Smith 		return;
132435863739SMike Smith 
132535863739SMike Smith 	if (cm->cm_datalen != 0) {
132635863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1327c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1328c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
132935863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1330c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1331c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
133235863739SMike Smith 
133335863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
133435863739SMike Smith 	}
133535863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
133635863739SMike Smith }
133735863739SMike Smith 
1338914da7d0SScott Long /*
1339914da7d0SScott Long  * Hardware Interface
1340914da7d0SScott Long  */
134135863739SMike Smith 
1342914da7d0SScott Long /*
134335863739SMike Smith  * Initialise the adapter.
134435863739SMike Smith  */
134535863739SMike Smith static void
134635863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
134735863739SMike Smith {
1348914da7d0SScott Long 	struct aac_softc *sc;
134935863739SMike Smith 
135035863739SMike Smith 	debug_called(1);
135135863739SMike Smith 
1352914da7d0SScott Long 	sc = (struct aac_softc *)arg;
1353914da7d0SScott Long 
135435863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
135535863739SMike Smith }
135635863739SMike Smith 
1357a6d35632SScott Long static int
1358a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1359a6d35632SScott Long {
1360a6d35632SScott Long 	u_int32_t major, minor, options;
1361a6d35632SScott Long 
1362a6d35632SScott Long 	debug_called(1);
1363a6d35632SScott Long 
1364fe94b852SScott Long 	/*
1365fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1366fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1367fe94b852SScott Long 	 */
1368a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1369fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1370fe94b852SScott Long 				     NULL)) {
1371fe94b852SScott Long 			device_printf(sc->aac_dev,
1372fe94b852SScott Long 				      "Error reading firmware version\n");
1373fe94b852SScott Long 			return (EIO);
1374fe94b852SScott Long 		}
1375fe94b852SScott Long 
1376fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1377a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1378a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1379fe94b852SScott Long 		if (major == 1) {
1380fe94b852SScott Long 			device_printf(sc->aac_dev,
1381fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1382fe94b852SScott Long 			    major, minor);
1383fe94b852SScott Long 			return (EINVAL);
1384fe94b852SScott Long 		}
1385fe94b852SScott Long 	}
1386fe94b852SScott Long 
1387a6d35632SScott Long 	/*
1388a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1389a6d35632SScott Long 	 * work-arounds to enable.
1390a6d35632SScott Long 	 */
1391a6d35632SScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1392a6d35632SScott Long 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1393a6d35632SScott Long 		return (EIO);
1394a6d35632SScott Long 	}
1395a6d35632SScott Long 	options = AAC_GET_MAILBOX(sc, 1);
1396a6d35632SScott Long 	sc->supported_options = options;
1397a6d35632SScott Long 
1398a6d35632SScott Long 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1399a6d35632SScott Long 	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1400a6d35632SScott Long 		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1401a6d35632SScott Long 	if (options & AAC_SUPPORTED_NONDASD)
1402a6d35632SScott Long 		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1403cd481291SScott Long 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1404cd481291SScott Long 	     && (sizeof(bus_addr_t) > 4)) {
1405a6d35632SScott Long 		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1406a6d35632SScott Long 		sc->flags |= AAC_FLAGS_SG_64BIT;
1407a6d35632SScott Long 	}
1408a6d35632SScott Long 
1409a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
1410a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
1411a6d35632SScott Long 		sc->aac_max_fibs = AAC_MAX_FIBS;
1412a6d35632SScott Long 	else
1413a6d35632SScott Long 		sc->aac_max_fibs = 256;
1414a6d35632SScott Long 
1415fe94b852SScott Long 	return (0);
1416fe94b852SScott Long }
1417fe94b852SScott Long 
141835863739SMike Smith static int
141935863739SMike Smith aac_init(struct aac_softc *sc)
142035863739SMike Smith {
142135863739SMike Smith 	struct aac_adapter_init	*ip;
142235863739SMike Smith 	time_t then;
1423b88ffdc8SScott Long 	u_int32_t code, qoffset;
1424a6d35632SScott Long 	int error;
142535863739SMike Smith 
142635863739SMike Smith 	debug_called(1);
142735863739SMike Smith 
142835863739SMike Smith 	/*
142935863739SMike Smith 	 * First wait for the adapter to come ready.
143035863739SMike Smith 	 */
143135863739SMike Smith 	then = time_second;
143235863739SMike Smith 	do {
143335863739SMike Smith 		code = AAC_GET_FWSTATUS(sc);
143435863739SMike Smith 		if (code & AAC_SELF_TEST_FAILED) {
143535863739SMike Smith 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
143635863739SMike Smith 			return(ENXIO);
143735863739SMike Smith 		}
143835863739SMike Smith 		if (code & AAC_KERNEL_PANIC) {
1439914da7d0SScott Long 			device_printf(sc->aac_dev,
1440914da7d0SScott Long 				      "FATAL: controller kernel panic\n");
144135863739SMike Smith 			return(ENXIO);
144235863739SMike Smith 		}
144335863739SMike Smith 		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
1444914da7d0SScott Long 			device_printf(sc->aac_dev,
1445914da7d0SScott Long 				      "FATAL: controller not coming ready, "
1446c6eafcf2SScott Long 					   "status %x\n", code);
144735863739SMike Smith 			return(ENXIO);
144835863739SMike Smith 		}
144935863739SMike Smith 	} while (!(code & AAC_UP_AND_RUNNING));
145035863739SMike Smith 
1451a6d35632SScott Long 	error = ENOMEM;
1452a6d35632SScott Long 	/*
1453a6d35632SScott Long 	 * Create DMA tag for mapping buffers into controller-addressable space.
1454a6d35632SScott Long 	 */
1455a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1456a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1457a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1458a6d35632SScott Long 			       BUS_SPACE_MAXADDR :
1459a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1460a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1461a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1462a6d35632SScott Long 			       MAXBSIZE,		/* maxsize */
1463a6d35632SScott Long 			       AAC_MAXSGENTRIES,	/* nsegments */
1464a6d35632SScott Long 			       MAXBSIZE,		/* maxsegsize */
1465a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1466f6b1c44dSScott Long 			       busdma_lock_mutex,	/* lockfunc */
1467f6b1c44dSScott Long 			       &sc->aac_io_lock,	/* lockfuncarg */
1468a6d35632SScott Long 			       &sc->aac_buffer_dmat)) {
1469a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1470a6d35632SScott Long 		goto out;
1471a6d35632SScott Long 	}
1472a6d35632SScott Long 
1473a6d35632SScott Long 	/*
1474a6d35632SScott Long 	 * Create DMA tag for mapping FIBs into controller-addressable space..
1475a6d35632SScott Long 	 */
1476a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1477a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1478a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1479a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1480a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
1481a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1482a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1483a6d35632SScott Long 			       AAC_FIB_COUNT *
1484a6d35632SScott Long 			       sizeof(struct aac_fib),  /* maxsize */
1485a6d35632SScott Long 			       1,			/* nsegments */
1486a6d35632SScott Long 			       AAC_FIB_COUNT *
1487a6d35632SScott Long 			       sizeof(struct aac_fib),	/* maxsegsize */
1488a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1489f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
1490a6d35632SScott Long 			       &sc->aac_fib_dmat)) {
1491a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1492a6d35632SScott Long 		goto out;
1493a6d35632SScott Long 	}
1494a6d35632SScott Long 
149535863739SMike Smith 	/*
149635863739SMike Smith 	 * Create DMA tag for the common structure and allocate it.
149735863739SMike Smith 	 */
149835863739SMike Smith 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1499c6eafcf2SScott Long 			       1, 0,			/* algnmnt, boundary */
1500a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1501a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1502a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
150335863739SMike Smith 			       BUS_SPACE_MAXADDR, 	/* highaddr */
150435863739SMike Smith 			       NULL, NULL, 		/* filter, filterarg */
1505ffb37f33SScott Long 			       8192 + sizeof(struct aac_common), /* maxsize */
1506914da7d0SScott Long 			       1,			/* nsegments */
150735863739SMike Smith 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1508a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1509f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
151035863739SMike Smith 			       &sc->aac_common_dmat)) {
1511914da7d0SScott Long 		device_printf(sc->aac_dev,
1512914da7d0SScott Long 			      "can't allocate common structure DMA tag\n");
1513a6d35632SScott Long 		goto out;
151435863739SMike Smith 	}
1515c6eafcf2SScott Long 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1516c6eafcf2SScott Long 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
151735863739SMike Smith 		device_printf(sc->aac_dev, "can't allocate common structure\n");
1518a6d35632SScott Long 		goto out;
151935863739SMike Smith 	}
1520ffb37f33SScott Long 
1521ffb37f33SScott Long 	/*
1522ffb37f33SScott Long 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1523ffb37f33SScott Long 	 * below address 8192 in physical memory.
1524ffb37f33SScott Long 	 * XXX If the padding is not needed, can it be put to use instead
1525ffb37f33SScott Long 	 * of ignored?
1526ffb37f33SScott Long 	 */
1527cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1528ffb37f33SScott Long 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1529ffb37f33SScott Long 			aac_common_map, sc, 0);
1530ffb37f33SScott Long 
1531ffb37f33SScott Long 	if (sc->aac_common_busaddr < 8192) {
1532eec256deSAlexander Kabaev 		sc->aac_common = (struct aac_common *)
1533eec256deSAlexander Kabaev 		    ((uint8_t *)sc->aac_common + 8192);
1534ffb37f33SScott Long 		sc->aac_common_busaddr += 8192;
1535ffb37f33SScott Long 	}
153635863739SMike Smith 	bzero(sc->aac_common, sizeof(*sc->aac_common));
153735863739SMike Smith 
1538ffb37f33SScott Long 	/* Allocate some FIBs and associated command structs */
1539ffb37f33SScott Long 	TAILQ_INIT(&sc->aac_fibmap_tqh);
1540ffb37f33SScott Long 	sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
15418480cc63SScott Long 				  M_AACBUF, M_WAITOK|M_ZERO);
15428480cc63SScott Long 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1543ffb37f33SScott Long 		if (aac_alloc_commands(sc) != 0)
1544ffb37f33SScott Long 			break;
1545ffb37f33SScott Long 	}
1546ffb37f33SScott Long 	if (sc->total_fibs == 0)
1547a6d35632SScott Long 		goto out;
1548ffb37f33SScott Long 
154935863739SMike Smith 	/*
1550914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1551914da7d0SScott Long 	 * physical location of various important shared data structures.
155235863739SMike Smith 	 */
155335863739SMike Smith 	ip = &sc->aac_common->ac_init;
155435863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1555f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
155635863739SMike Smith 
1557c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1558c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1559149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
156035863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
156135863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
156235863739SMike Smith 
1563c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1564c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
156535863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
156635863739SMike Smith 
15674b00f859SScott Long 	/*
15684b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
15694b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
15704b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
15714b00f859SScott Long 	 * Round up since the granularity is so high.
15724b00f859SScott Long 	 */
1573f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
15744b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
15754b00f859SScott Long 		ip->HostPhysMemPages =
15764b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1577204c0befSScott Long 	}
157835863739SMike Smith 	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
157935863739SMike Smith 
158035863739SMike Smith 	/*
1581c6eafcf2SScott Long 	 * Initialise FIB queues.  Note that it appears that the layout of the
1582c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1583c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
158435863739SMike Smith 	 *
158535863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1586914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1587914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1588914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1589914da7d0SScott Long 	 * does.
159035863739SMike Smith 	 *
1591914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1592914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1593914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1594914da7d0SScott Long 	 * virtue of a table.
159535863739SMike Smith 	 */
1596b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
15970bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
15980bcbebd6SScott Long 	sc->aac_queues =
15990bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1600b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
160135863739SMike Smith 
1602c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1603c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1604c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1605c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1606c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1607c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1608c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1609c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1610c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1611c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1612c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1613c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1614c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1615c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1616c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1617c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1618c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1619c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1620c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1621c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1622c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1623c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1624c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1625c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1626c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1627c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1628c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1629c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1630c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1631c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1632c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1633c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1634c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1635c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1636c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1637c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1638c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1639c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1640c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1641c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1642c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1643c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1644c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1645c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1646c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1647c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1648c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1649c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
165035863739SMike Smith 
165135863739SMike Smith 	/*
165235863739SMike Smith 	 * Do controller-type-specific initialisation
165335863739SMike Smith 	 */
165435863739SMike Smith 	switch (sc->aac_hwif) {
165535863739SMike Smith 	case AAC_HWIF_I960RX:
165635863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
165735863739SMike Smith 		break;
16584afedc31SScott Long 	case AAC_HWIF_RKT:
16594afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
16604afedc31SScott Long 		break;
16614afedc31SScott Long 	default:
16624afedc31SScott Long 		break;
166335863739SMike Smith 	}
166435863739SMike Smith 
166535863739SMike Smith 	/*
166635863739SMike Smith 	 * Give the init structure to the controller.
166735863739SMike Smith 	 */
166835863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1669914da7d0SScott Long 			     sc->aac_common_busaddr +
1670914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1671914da7d0SScott Long 			     NULL)) {
1672914da7d0SScott Long 		device_printf(sc->aac_dev,
1673914da7d0SScott Long 			      "error establishing init structure\n");
1674a6d35632SScott Long 		error = EIO;
1675a6d35632SScott Long 		goto out;
167635863739SMike Smith 	}
167735863739SMike Smith 
1678a6d35632SScott Long 	error = 0;
1679a6d35632SScott Long out:
1680a6d35632SScott Long 	return(error);
168135863739SMike Smith }
168235863739SMike Smith 
1683914da7d0SScott Long /*
168435863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
168535863739SMike Smith  */
168635863739SMike Smith static int
168735863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
168835863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
168935863739SMike Smith 		 u_int32_t *sp)
169035863739SMike Smith {
169135863739SMike Smith 	time_t then;
169235863739SMike Smith 	u_int32_t status;
169335863739SMike Smith 
169435863739SMike Smith 	debug_called(3);
169535863739SMike Smith 
169635863739SMike Smith 	/* populate the mailbox */
169735863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
169835863739SMike Smith 
169935863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
170035863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
170135863739SMike Smith 
170235863739SMike Smith 	/* then set it to signal the adapter */
170335863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
170435863739SMike Smith 
170535863739SMike Smith 	/* spin waiting for the command to complete */
170635863739SMike Smith 	then = time_second;
170735863739SMike Smith 	do {
170835863739SMike Smith 		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1709a6d35632SScott Long 			debug(1, "timed out");
171035863739SMike Smith 			return(EIO);
171135863739SMike Smith 		}
171235863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
171335863739SMike Smith 
171435863739SMike Smith 	/* clear the completion flag */
171535863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
171635863739SMike Smith 
171735863739SMike Smith 	/* get the command status */
1718a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
171935863739SMike Smith 	if (sp != NULL)
172035863739SMike Smith 		*sp = status;
17210b94a66eSMike Smith 	return(0);
172235863739SMike Smith }
172335863739SMike Smith 
1724cbfd045bSScott Long int
172535863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
1726cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
172735863739SMike Smith {
172835863739SMike Smith 	debug_called(3);
172935863739SMike Smith 
173035863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
173135863739SMike Smith 		return(EINVAL);
173235863739SMike Smith 
173335863739SMike Smith 	/*
173435863739SMike Smith 	 * Set up the sync FIB
173535863739SMike Smith 	 */
1736914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
1737914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
1738c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
173935863739SMike Smith 	fib->Header.XferState |= xferstate;
174035863739SMike Smith 	fib->Header.Command = command;
174135863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
174235863739SMike Smith 	fib->Header.Size = sizeof(struct aac_fib) + datasize;
174335863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
1744b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
1745c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
1746914da7d0SScott Long 					 offsetof(struct aac_common,
1747914da7d0SScott Long 						  ac_sync_fib);
174835863739SMike Smith 
174935863739SMike Smith 	/*
175035863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
175135863739SMike Smith 	 */
1752914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
1753914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
175435863739SMike Smith 		debug(2, "IO error");
175535863739SMike Smith 		return(EIO);
175635863739SMike Smith 	}
175735863739SMike Smith 
175835863739SMike Smith 	return (0);
175935863739SMike Smith }
176035863739SMike Smith 
1761914da7d0SScott Long /*
176235863739SMike Smith  * Adapter-space FIB queue manipulation
176335863739SMike Smith  *
176435863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
176535863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
176635863739SMike Smith  */
176735863739SMike Smith static struct {
176835863739SMike Smith 	int		size;
176935863739SMike Smith 	int		notify;
177035863739SMike Smith } aac_qinfo[] = {
177135863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
177235863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
177335863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
177435863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
177535863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
177635863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
177735863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
177835863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
177935863739SMike Smith };
178035863739SMike Smith 
178135863739SMike Smith /*
1782c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
1783c6eafcf2SScott Long  * EBUSY if the queue is full.
178435863739SMike Smith  *
17850b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
1786914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
1787914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
1788c6eafcf2SScott Long  *	 separate queue/notify interface).
178935863739SMike Smith  */
179035863739SMike Smith static int
1791f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
179235863739SMike Smith {
179335863739SMike Smith 	u_int32_t pi, ci;
17949e2e96d8SScott Long 	int error;
1795f6c4dd3fSScott Long 	u_int32_t fib_size;
1796f6c4dd3fSScott Long 	u_int32_t fib_addr;
1797f6c4dd3fSScott Long 
179836e0bf6eSScott Long 	debug_called(3);
179936e0bf6eSScott Long 
1800f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
1801f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
180235863739SMike Smith 
180335863739SMike Smith 	/* get the producer/consumer indices */
180435863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
180535863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
180635863739SMike Smith 
180735863739SMike Smith 	/* wrap the queue? */
180835863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
180935863739SMike Smith 		pi = 0;
181035863739SMike Smith 
181135863739SMike Smith 	/* check for queue full */
181235863739SMike Smith 	if ((pi + 1) == ci) {
181335863739SMike Smith 		error = EBUSY;
181435863739SMike Smith 		goto out;
181535863739SMike Smith 	}
181635863739SMike Smith 
1817614c22b2SScott Long 	/*
1818614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
1819614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
1820614c22b2SScott Long 	 */
1821614c22b2SScott Long 	aac_enqueue_busy(cm);
1822614c22b2SScott Long 
182335863739SMike Smith 	/* populate queue entry */
182435863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
182535863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
182635863739SMike Smith 
182735863739SMike Smith 	/* update producer index */
182835863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
182935863739SMike Smith 
183035863739SMike Smith 	/* notify the adapter if we know how */
183135863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
183235863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
183335863739SMike Smith 
183435863739SMike Smith 	error = 0;
183535863739SMike Smith 
183635863739SMike Smith out:
183735863739SMike Smith 	return(error);
183835863739SMike Smith }
183935863739SMike Smith 
184035863739SMike Smith /*
184136e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
184236e0bf6eSScott Long  * success or ENOENT if the queue is empty.
184335863739SMike Smith  */
184435863739SMike Smith static int
1845c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1846c6eafcf2SScott Long 		struct aac_fib **fib_addr)
184735863739SMike Smith {
184835863739SMike Smith 	u_int32_t pi, ci;
1849149af931SScott Long 	u_int32_t fib_index;
18509e2e96d8SScott Long 	int error;
1851f6c4dd3fSScott Long 	int notify;
185235863739SMike Smith 
185335863739SMike Smith 	debug_called(3);
185435863739SMike Smith 
185535863739SMike Smith 	/* get the producer/consumer indices */
185635863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
185735863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
185835863739SMike Smith 
185935863739SMike Smith 	/* check for queue empty */
186035863739SMike Smith 	if (ci == pi) {
186135863739SMike Smith 		error = ENOENT;
186235863739SMike Smith 		goto out;
186335863739SMike Smith 	}
186435863739SMike Smith 
18657753acd2SScott Long 	/* wrap the pi so the following test works */
18667753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
18677753acd2SScott Long 		pi = 0;
18687753acd2SScott Long 
1869f6c4dd3fSScott Long 	notify = 0;
1870f6c4dd3fSScott Long 	if (ci == pi + 1)
1871f6c4dd3fSScott Long 		notify++;
1872f6c4dd3fSScott Long 
187335863739SMike Smith 	/* wrap the queue? */
187435863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
187535863739SMike Smith 		ci = 0;
187635863739SMike Smith 
187735863739SMike Smith 	/* fetch the entry */
187835863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
1879149af931SScott Long 
1880149af931SScott Long 	switch (queue) {
1881149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
1882149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
1883149af931SScott Long 		/*
1884149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
1885149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
1886149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
1887149af931SScott Long 		 * Therefore, we have to convert it to an index.
1888149af931SScott Long 		 */
1889149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
1890149af931SScott Long 			sizeof(struct aac_fib);
1891149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
1892149af931SScott Long 		break;
1893149af931SScott Long 
1894149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
1895149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
1896149af931SScott Long 	{
1897149af931SScott Long 		struct aac_command *cm;
1898149af931SScott Long 
1899149af931SScott Long 		/*
1900149af931SScott Long 		 * As above, an index is used instead of an actual address.
1901149af931SScott Long 		 * Gotta shift the index to account for the fast response
1902149af931SScott Long 		 * bit.  No other correction is needed since this value was
1903149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
1904149af931SScott Long 		 * field.
1905149af931SScott Long 		 */
1906149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
1907149af931SScott Long 		cm = sc->aac_commands + (fib_index >> 1);
1908149af931SScott Long 		*fib_addr = cm->cm_fib;
190935863739SMike Smith 
1910f30ac74cSScott Long 		/*
1911f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
1912149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
1913f30ac74cSScott Long 		 */
1914149af931SScott Long 		if (fib_index & 0x01) {
1915f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
1916f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
1917f30ac74cSScott Long 		}
1918149af931SScott Long 		break;
1919149af931SScott Long 	}
1920149af931SScott Long 	default:
1921149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
1922149af931SScott Long 		break;
1923149af931SScott Long 	}
1924149af931SScott Long 
192535863739SMike Smith 	/* update consumer index */
192635863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
192735863739SMike Smith 
192835863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
1929f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
193035863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
193135863739SMike Smith 	error = 0;
193235863739SMike Smith 
193335863739SMike Smith out:
193435863739SMike Smith 	return(error);
193535863739SMike Smith }
193635863739SMike Smith 
1937914da7d0SScott Long /*
193836e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
193936e0bf6eSScott Long  */
194036e0bf6eSScott Long static int
194136e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
194236e0bf6eSScott Long {
194336e0bf6eSScott Long 	u_int32_t pi, ci;
19449e2e96d8SScott Long 	int error;
194536e0bf6eSScott Long 	u_int32_t fib_size;
194636e0bf6eSScott Long 	u_int32_t fib_addr;
194736e0bf6eSScott Long 
194836e0bf6eSScott Long 	debug_called(1);
194936e0bf6eSScott Long 
195036e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
195136e0bf6eSScott Long 	fib_size = fib->Header.Size;
195236e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
195336e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
195436e0bf6eSScott Long 
195536e0bf6eSScott Long 	/* get the producer/consumer indices */
195636e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
195736e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
195836e0bf6eSScott Long 
195936e0bf6eSScott Long 	/* wrap the queue? */
196036e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
196136e0bf6eSScott Long 		pi = 0;
196236e0bf6eSScott Long 
196336e0bf6eSScott Long 	/* check for queue full */
196436e0bf6eSScott Long 	if ((pi + 1) == ci) {
196536e0bf6eSScott Long 		error = EBUSY;
196636e0bf6eSScott Long 		goto out;
196736e0bf6eSScott Long 	}
196836e0bf6eSScott Long 
196936e0bf6eSScott Long 	/* populate queue entry */
197036e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
197136e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
197236e0bf6eSScott Long 
197336e0bf6eSScott Long 	/* update producer index */
197436e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
197536e0bf6eSScott Long 
197636e0bf6eSScott Long 	/* notify the adapter if we know how */
197736e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
197836e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
197936e0bf6eSScott Long 
198036e0bf6eSScott Long 	error = 0;
198136e0bf6eSScott Long 
198236e0bf6eSScott Long out:
198336e0bf6eSScott Long 	return(error);
198436e0bf6eSScott Long }
198536e0bf6eSScott Long 
1986914da7d0SScott Long /*
19870b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
19880b94a66eSMike Smith  * and complain about them.
19890b94a66eSMike Smith  */
19900b94a66eSMike Smith static void
19910b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
19920b94a66eSMike Smith {
19930b94a66eSMike Smith 	struct aac_command *cm;
19940b94a66eSMike Smith 	time_t deadline;
19950b94a66eSMike Smith 
1996f6c4dd3fSScott Long 	/*
199770545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
1998914da7d0SScott Long 	 * only.
1999914da7d0SScott Long 	 */
20000b94a66eSMike Smith 	deadline = time_second - AAC_CMD_TIMEOUT;
20010b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2002f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2003f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
20040b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2005914da7d0SScott Long 			device_printf(sc->aac_dev,
2006914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2007f6c4dd3fSScott Long 				      cm, (int)(time_second-cm->cm_timestamp));
20080b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
20090b94a66eSMike Smith 		}
20100b94a66eSMike Smith 	}
20110b94a66eSMike Smith 
20120b94a66eSMike Smith 	return;
20130b94a66eSMike Smith }
20140b94a66eSMike Smith 
2015914da7d0SScott Long /*
2016914da7d0SScott Long  * Interface Function Vectors
2017914da7d0SScott Long  */
201835863739SMike Smith 
2019914da7d0SScott Long /*
202035863739SMike Smith  * Read the current firmware status word.
202135863739SMike Smith  */
202235863739SMike Smith static int
202335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
202435863739SMike Smith {
202535863739SMike Smith 	debug_called(3);
202635863739SMike Smith 
202735863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
202835863739SMike Smith }
202935863739SMike Smith 
203035863739SMike Smith static int
203135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
203235863739SMike Smith {
203335863739SMike Smith 	debug_called(3);
203435863739SMike Smith 
203535863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
203635863739SMike Smith }
203735863739SMike Smith 
2038b3457b51SScott Long static int
2039b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2040b3457b51SScott Long {
2041b3457b51SScott Long 	int val;
2042b3457b51SScott Long 
2043b3457b51SScott Long 	debug_called(3);
2044b3457b51SScott Long 
2045b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2046b3457b51SScott Long 	return (val);
2047b3457b51SScott Long }
2048b3457b51SScott Long 
20494afedc31SScott Long static int
20504afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
20514afedc31SScott Long {
20524afedc31SScott Long 	debug_called(3);
20534afedc31SScott Long 
20544afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
20554afedc31SScott Long }
20564afedc31SScott Long 
2057914da7d0SScott Long /*
205835863739SMike Smith  * Notify the controller of a change in a given queue
205935863739SMike Smith  */
206035863739SMike Smith 
206135863739SMike Smith static void
206235863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
206335863739SMike Smith {
206435863739SMike Smith 	debug_called(3);
206535863739SMike Smith 
206635863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
206735863739SMike Smith }
206835863739SMike Smith 
206935863739SMike Smith static void
207035863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
207135863739SMike Smith {
207235863739SMike Smith 	debug_called(3);
207335863739SMike Smith 
207435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
207535863739SMike Smith }
207635863739SMike Smith 
2077b3457b51SScott Long static void
2078b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2079b3457b51SScott Long {
2080b3457b51SScott Long 	debug_called(3);
2081b3457b51SScott Long 
2082b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2083b3457b51SScott Long 	AAC_FA_HACK(sc);
2084b3457b51SScott Long }
2085b3457b51SScott Long 
20864afedc31SScott Long static void
20874afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
20884afedc31SScott Long {
20894afedc31SScott Long 	debug_called(3);
20904afedc31SScott Long 
20914afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
20924afedc31SScott Long }
20934afedc31SScott Long 
2094914da7d0SScott Long /*
209535863739SMike Smith  * Get the interrupt reason bits
209635863739SMike Smith  */
209735863739SMike Smith static int
209835863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
209935863739SMike Smith {
210035863739SMike Smith 	debug_called(3);
210135863739SMike Smith 
210235863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
210335863739SMike Smith }
210435863739SMike Smith 
210535863739SMike Smith static int
210635863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
210735863739SMike Smith {
210835863739SMike Smith 	debug_called(3);
210935863739SMike Smith 
211035863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
211135863739SMike Smith }
211235863739SMike Smith 
2113b3457b51SScott Long static int
2114b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2115b3457b51SScott Long {
2116b3457b51SScott Long 	int val;
2117b3457b51SScott Long 
2118b3457b51SScott Long 	debug_called(3);
2119b3457b51SScott Long 
2120b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2121b3457b51SScott Long 	return (val);
2122b3457b51SScott Long }
2123b3457b51SScott Long 
21244afedc31SScott Long static int
21254afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
21264afedc31SScott Long {
21274afedc31SScott Long 	debug_called(3);
21284afedc31SScott Long 
21294afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
21304afedc31SScott Long }
21314afedc31SScott Long 
2132914da7d0SScott Long /*
213335863739SMike Smith  * Clear some interrupt reason bits
213435863739SMike Smith  */
213535863739SMike Smith static void
213635863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
213735863739SMike Smith {
213835863739SMike Smith 	debug_called(3);
213935863739SMike Smith 
214035863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
214135863739SMike Smith }
214235863739SMike Smith 
214335863739SMike Smith static void
214435863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
214535863739SMike Smith {
214635863739SMike Smith 	debug_called(3);
214735863739SMike Smith 
214835863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
214935863739SMike Smith }
215035863739SMike Smith 
2151b3457b51SScott Long static void
2152b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2153b3457b51SScott Long {
2154b3457b51SScott Long 	debug_called(3);
2155b3457b51SScott Long 
2156b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2157b3457b51SScott Long 	AAC_FA_HACK(sc);
2158b3457b51SScott Long }
2159b3457b51SScott Long 
21604afedc31SScott Long static void
21614afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
21624afedc31SScott Long {
21634afedc31SScott Long 	debug_called(3);
21644afedc31SScott Long 
21654afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
21664afedc31SScott Long }
21674afedc31SScott Long 
2168914da7d0SScott Long /*
216935863739SMike Smith  * Populate the mailbox and set the command word
217035863739SMike Smith  */
217135863739SMike Smith static void
217235863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
217335863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
217435863739SMike Smith {
217535863739SMike Smith 	debug_called(4);
217635863739SMike Smith 
217735863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
217835863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
217935863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
218035863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
218135863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
218235863739SMike Smith }
218335863739SMike Smith 
218435863739SMike Smith static void
218535863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
218635863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
218735863739SMike Smith {
218835863739SMike Smith 	debug_called(4);
218935863739SMike Smith 
219035863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
219135863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
219235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
219335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
219435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
219535863739SMike Smith }
219635863739SMike Smith 
2197b3457b51SScott Long static void
2198b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2199b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2200b3457b51SScott Long {
2201b3457b51SScott Long 	debug_called(4);
2202b3457b51SScott Long 
2203b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2204b3457b51SScott Long 	AAC_FA_HACK(sc);
2205b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2206b3457b51SScott Long 	AAC_FA_HACK(sc);
2207b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2208b3457b51SScott Long 	AAC_FA_HACK(sc);
2209b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2210b3457b51SScott Long 	AAC_FA_HACK(sc);
2211b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2212b3457b51SScott Long 	AAC_FA_HACK(sc);
2213b3457b51SScott Long }
2214b3457b51SScott Long 
22154afedc31SScott Long static void
22164afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
22174afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
22184afedc31SScott Long {
22194afedc31SScott Long 	debug_called(4);
22204afedc31SScott Long 
22214afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
22224afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
22234afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
22244afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
22254afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
22264afedc31SScott Long }
22274afedc31SScott Long 
2228914da7d0SScott Long /*
222935863739SMike Smith  * Fetch the immediate command status word
223035863739SMike Smith  */
223135863739SMike Smith static int
2232a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
223335863739SMike Smith {
223435863739SMike Smith 	debug_called(4);
223535863739SMike Smith 
2236a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
223735863739SMike Smith }
223835863739SMike Smith 
223935863739SMike Smith static int
2240a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
224135863739SMike Smith {
224235863739SMike Smith 	debug_called(4);
224335863739SMike Smith 
2244a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
224535863739SMike Smith }
224635863739SMike Smith 
2247b3457b51SScott Long static int
2248a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2249b3457b51SScott Long {
2250b3457b51SScott Long 	int val;
2251b3457b51SScott Long 
2252b3457b51SScott Long 	debug_called(4);
2253b3457b51SScott Long 
2254a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2255b3457b51SScott Long 	return (val);
2256b3457b51SScott Long }
2257b3457b51SScott Long 
22584afedc31SScott Long static int
22594afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
22604afedc31SScott Long {
22614afedc31SScott Long 	debug_called(4);
22624afedc31SScott Long 
22634afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
22644afedc31SScott Long }
22654afedc31SScott Long 
2266914da7d0SScott Long /*
226735863739SMike Smith  * Set/clear interrupt masks
226835863739SMike Smith  */
226935863739SMike Smith static void
227035863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
227135863739SMike Smith {
227235863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
227335863739SMike Smith 
227435863739SMike Smith 	if (enable) {
227535863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
227635863739SMike Smith 	} else {
227735863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
227835863739SMike Smith 	}
227935863739SMike Smith }
228035863739SMike Smith 
228135863739SMike Smith static void
228235863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
228335863739SMike Smith {
228435863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
228535863739SMike Smith 
228635863739SMike Smith 	if (enable) {
228735863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
228835863739SMike Smith 	} else {
228935863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
229035863739SMike Smith 	}
229135863739SMike Smith }
229235863739SMike Smith 
2293b3457b51SScott Long static void
2294b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2295b3457b51SScott Long {
2296b3457b51SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
2297b3457b51SScott Long 
2298b3457b51SScott Long 	if (enable) {
2299b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2300b3457b51SScott Long 		AAC_FA_HACK(sc);
2301b3457b51SScott Long 	} else {
2302b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2303b3457b51SScott Long 		AAC_FA_HACK(sc);
2304b3457b51SScott Long 	}
2305b3457b51SScott Long }
2306b3457b51SScott Long 
23074afedc31SScott Long static void
23084afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
23094afedc31SScott Long {
23104afedc31SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
23114afedc31SScott Long 
23124afedc31SScott Long 	if (enable) {
23134afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
23144afedc31SScott Long 	} else {
23154afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
23164afedc31SScott Long 	}
23174afedc31SScott Long }
23184afedc31SScott Long 
2319914da7d0SScott Long /*
2320914da7d0SScott Long  * Debugging and Diagnostics
2321914da7d0SScott Long  */
232235863739SMike Smith 
2323914da7d0SScott Long /*
232435863739SMike Smith  * Print some information about the controller.
232535863739SMike Smith  */
232635863739SMike Smith static void
232735863739SMike Smith aac_describe_controller(struct aac_softc *sc)
232835863739SMike Smith {
2329cbfd045bSScott Long 	struct aac_fib *fib;
233035863739SMike Smith 	struct aac_adapter_info	*info;
233135863739SMike Smith 
233235863739SMike Smith 	debug_called(2);
233335863739SMike Smith 
233403b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2335cbfd045bSScott Long 
2336cbfd045bSScott Long 	fib->data[0] = 0;
2337cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
233835863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2339fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
234035863739SMike Smith 		return;
234135863739SMike Smith 	}
2342cbfd045bSScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
234335863739SMike Smith 
234436e0bf6eSScott Long 	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
2345c6eafcf2SScott Long 		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
234636e0bf6eSScott Long 		      info->ClockSpeed, info->BufferMem / (1024 * 1024),
2347914da7d0SScott Long 		      aac_describe_code(aac_battery_platform,
2348914da7d0SScott Long 					info->batteryPlatform));
234935863739SMike Smith 
235035863739SMike Smith 	/* save the kernel revision structure for later use */
235135863739SMike Smith 	sc->aac_revision = info->KernelRevision;
235236e0bf6eSScott Long 	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
235335863739SMike Smith 		      info->KernelRevision.external.comp.major,
235435863739SMike Smith 		      info->KernelRevision.external.comp.minor,
235535863739SMike Smith 		      info->KernelRevision.external.comp.dash,
235636e0bf6eSScott Long 		      info->KernelRevision.buildNumber,
235736e0bf6eSScott Long 		      (u_int32_t)(info->SerialNumber & 0xffffff));
2358fe3cb0e1SScott Long 
2359fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
2360a6d35632SScott Long 
2361a6d35632SScott Long 	if (1 || bootverbose) {
2362a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2363a6d35632SScott Long 			      sc->supported_options,
2364a6d35632SScott Long 			      "\20"
2365a6d35632SScott Long 			      "\1SNAPSHOT"
2366a6d35632SScott Long 			      "\2CLUSTERS"
2367a6d35632SScott Long 			      "\3WCACHE"
2368a6d35632SScott Long 			      "\4DATA64"
2369a6d35632SScott Long 			      "\5HOSTTIME"
2370a6d35632SScott Long 			      "\6RAID50"
2371a6d35632SScott Long 			      "\7WINDOW4GB"
2372a6d35632SScott Long 			      "\10SCSIUPGD"
2373a6d35632SScott Long 			      "\11SOFTERR"
2374a6d35632SScott Long 			      "\12NORECOND"
2375a6d35632SScott Long 			      "\13SGMAP64"
2376a6d35632SScott Long 			      "\14ALARM"
2377a6d35632SScott Long 			      "\15NONDASD");
2378a6d35632SScott Long 	}
237935863739SMike Smith }
238035863739SMike Smith 
2381914da7d0SScott Long /*
238235863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
238335863739SMike Smith  * same.
238435863739SMike Smith  */
238535863739SMike Smith static char *
238635863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
238735863739SMike Smith {
238835863739SMike Smith 	int i;
238935863739SMike Smith 
239035863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
239135863739SMike Smith 		if (table[i].code == code)
239235863739SMike Smith 			return(table[i].string);
239335863739SMike Smith 	return(table[i + 1].string);
239435863739SMike Smith }
239535863739SMike Smith 
2396914da7d0SScott Long /*
2397914da7d0SScott Long  * Management Interface
2398914da7d0SScott Long  */
239935863739SMike Smith 
240035863739SMike Smith static int
240189c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
240235863739SMike Smith {
2403914da7d0SScott Long 	struct aac_softc *sc;
240435863739SMike Smith 
240535863739SMike Smith 	debug_called(2);
240635863739SMike Smith 
2407914da7d0SScott Long 	sc = dev->si_drv1;
2408914da7d0SScott Long 
240935863739SMike Smith 	/* Check to make sure the device isn't already open */
241035863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN) {
241135863739SMike Smith 		return EBUSY;
241235863739SMike Smith 	}
241335863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
241435863739SMike Smith 
241535863739SMike Smith 	return 0;
241635863739SMike Smith }
241735863739SMike Smith 
241835863739SMike Smith static int
241989c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
242035863739SMike Smith {
2421914da7d0SScott Long 	struct aac_softc *sc;
242235863739SMike Smith 
242335863739SMike Smith 	debug_called(2);
242435863739SMike Smith 
2425914da7d0SScott Long 	sc = dev->si_drv1;
2426914da7d0SScott Long 
242735863739SMike Smith 	/* Mark this unit as no longer open  */
242835863739SMike Smith 	sc->aac_state &= ~AAC_STATE_OPEN;
242935863739SMike Smith 
243035863739SMike Smith 	return 0;
243135863739SMike Smith }
243235863739SMike Smith 
243335863739SMike Smith static int
243489c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
243535863739SMike Smith {
2436914da7d0SScott Long 	union aac_statrequest *as;
2437914da7d0SScott Long 	struct aac_softc *sc;
24380b94a66eSMike Smith 	int error = 0;
2439b88ffdc8SScott Long 	uint32_t cookie;
244035863739SMike Smith 
244135863739SMike Smith 	debug_called(2);
244235863739SMike Smith 
2443914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2444914da7d0SScott Long 	sc = dev->si_drv1;
2445914da7d0SScott Long 
244635863739SMike Smith 	switch (cmd) {
24470b94a66eSMike Smith 	case AACIO_STATS:
24480b94a66eSMike Smith 		switch (as->as_item) {
24490b94a66eSMike Smith 		case AACQ_FREE:
24500b94a66eSMike Smith 		case AACQ_BIO:
24510b94a66eSMike Smith 		case AACQ_READY:
24520b94a66eSMike Smith 		case AACQ_BUSY:
2453c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2454c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
24550b94a66eSMike Smith 			break;
24560b94a66eSMike Smith 		default:
24570b94a66eSMike Smith 			error = ENOENT;
24580b94a66eSMike Smith 			break;
24590b94a66eSMike Smith 		}
24600b94a66eSMike Smith 	break;
24610b94a66eSMike Smith 
246235863739SMike Smith 	case FSACTL_SENDFIB:
2463fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2464fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
24650b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
246635863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
246735863739SMike Smith 		break;
246835863739SMike Smith 	case FSACTL_AIF_THREAD:
2469fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
24700b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
247135863739SMike Smith 		error = EINVAL;
247235863739SMike Smith 		break;
247335863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2474fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2475fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
24760b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
247735863739SMike Smith 		/*
247835863739SMike Smith 		 * Pass the caller out an AdapterFibContext.
247935863739SMike Smith 		 *
248035863739SMike Smith 		 * Note that because we only support one opener, we
248135863739SMike Smith 		 * basically ignore this.  Set the caller's context to a magic
248235863739SMike Smith 		 * number just in case.
24830b94a66eSMike Smith 		 *
24840b94a66eSMike Smith 		 * The Linux code hands the driver a pointer into kernel space,
24850b94a66eSMike Smith 		 * and then trusts it when the caller hands it back.  Aiee!
2486914da7d0SScott Long 		 * Here, we give it the proc pointer of the per-adapter aif
2487914da7d0SScott Long 		 * thread. It's only used as a sanity check in other calls.
248835863739SMike Smith 		 */
2489b88ffdc8SScott Long 		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2490b88ffdc8SScott Long 		error = copyout(&cookie, arg, sizeof(cookie));
249135863739SMike Smith 		break;
249235863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2493fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2494fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
24950b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2496fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
249735863739SMike Smith 		break;
249835863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2499fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
25000b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
250135863739SMike Smith 		/* don't do anything here */
250235863739SMike Smith 		break;
250335863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2504fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2505fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
25060b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2507fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
250835863739SMike Smith 		break;
250936e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
251036e0bf6eSScott Long 		arg = *(caddr_t*)arg;
251136e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
251236e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
251336e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
251436e0bf6eSScott Long 			break;
251536e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
251636e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2517914da7d0SScott Long 		/*
2518914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2519914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2520914da7d0SScott Long 		 * controller
2521914da7d0SScott Long 		 */
252236e0bf6eSScott Long 		error = 0;
252336e0bf6eSScott Long 		break;
252435863739SMike Smith 	default:
2525b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
252635863739SMike Smith 		error = EINVAL;
252735863739SMike Smith 		break;
252835863739SMike Smith 	}
252935863739SMike Smith 	return(error);
253035863739SMike Smith }
253135863739SMike Smith 
2532b3457b51SScott Long static int
253389c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2534b3457b51SScott Long {
2535b3457b51SScott Long 	struct aac_softc *sc;
2536b3457b51SScott Long 	int revents;
2537b3457b51SScott Long 
2538b3457b51SScott Long 	sc = dev->si_drv1;
2539b3457b51SScott Long 	revents = 0;
2540b3457b51SScott Long 
2541bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2542b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2543b3457b51SScott Long 		if (sc->aac_aifq_tail != sc->aac_aifq_head)
2544b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2545b3457b51SScott Long 	}
2546bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2547b3457b51SScott Long 
2548b3457b51SScott Long 	if (revents == 0) {
2549b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2550b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2551b3457b51SScott Long 	}
2552b3457b51SScott Long 
2553b3457b51SScott Long 	return (revents);
2554b3457b51SScott Long }
2555b3457b51SScott Long 
2556914da7d0SScott Long /*
255735863739SMike Smith  * Send a FIB supplied from userspace
255835863739SMike Smith  */
255935863739SMike Smith static int
256035863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
256135863739SMike Smith {
256235863739SMike Smith 	struct aac_command *cm;
256335863739SMike Smith 	int size, error;
256435863739SMike Smith 
256535863739SMike Smith 	debug_called(2);
256635863739SMike Smith 
256735863739SMike Smith 	cm = NULL;
256835863739SMike Smith 
256935863739SMike Smith 	/*
257035863739SMike Smith 	 * Get a command
257135863739SMike Smith 	 */
2572bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
257335863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
257435863739SMike Smith 		error = EBUSY;
257535863739SMike Smith 		goto out;
257635863739SMike Smith 	}
257735863739SMike Smith 
257835863739SMike Smith 	/*
257935863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
258035863739SMike Smith 	 */
2581914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
2582914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
258335863739SMike Smith 		goto out;
258435863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
258535863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
2586b88ffdc8SScott Long 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
2587914da7d0SScott Long 			      size, sizeof(struct aac_fib));
258835863739SMike Smith 		size = sizeof(struct aac_fib);
258935863739SMike Smith 	}
259035863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
259135863739SMike Smith 		goto out;
259235863739SMike Smith 	cm->cm_fib->Header.Size = size;
2593f6c4dd3fSScott Long 	cm->cm_timestamp = time_second;
259435863739SMike Smith 
259535863739SMike Smith 	/*
259635863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
259735863739SMike Smith 	 */
2598d8a0a473SScott Long 	if ((error = aac_wait_command(cm)) != 0) {
259970545d1aSScott Long 		device_printf(sc->aac_dev,
260070545d1aSScott Long 			      "aac_wait_command return %d\n", error);
260135863739SMike Smith 		goto out;
2602b3457b51SScott Long 	}
260335863739SMike Smith 
260435863739SMike Smith 	/*
260535863739SMike Smith 	 * Copy the FIB and data back out to the caller.
260635863739SMike Smith 	 */
260735863739SMike Smith 	size = cm->cm_fib->Header.Size;
260835863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
2609b88ffdc8SScott Long 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
2610914da7d0SScott Long 			      size, sizeof(struct aac_fib));
261135863739SMike Smith 		size = sizeof(struct aac_fib);
261235863739SMike Smith 	}
261335863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
261435863739SMike Smith 
261535863739SMike Smith out:
2616f6c4dd3fSScott Long 	if (cm != NULL) {
261735863739SMike Smith 		aac_release_command(cm);
2618f6c4dd3fSScott Long 	}
2619ae543596SScott Long 
2620bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
262135863739SMike Smith 	return(error);
262235863739SMike Smith }
262335863739SMike Smith 
2624914da7d0SScott Long /*
262535863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
262636e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
262735863739SMike Smith  */
262835863739SMike Smith static void
262936e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
263035863739SMike Smith {
263136e0bf6eSScott Long 	struct aac_aif_command *aif;
263236e0bf6eSScott Long 	struct aac_container *co, *co_next;
2633cbfd045bSScott Long 	struct aac_mntinfo *mi;
2634cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
263536e0bf6eSScott Long 	u_int16_t rsize;
2636b3457b51SScott Long 	int next, found;
2637795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
263835863739SMike Smith 
263935863739SMike Smith 	debug_called(2);
264035863739SMike Smith 
264136e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
264236e0bf6eSScott Long 	aac_print_aif(sc, aif);
264336e0bf6eSScott Long 
264436e0bf6eSScott Long 	/* Is it an event that we should care about? */
264536e0bf6eSScott Long 	switch (aif->command) {
264636e0bf6eSScott Long 	case AifCmdEventNotify:
264736e0bf6eSScott Long 		switch (aif->data.EN.type) {
264836e0bf6eSScott Long 		case AifEnAddContainer:
264936e0bf6eSScott Long 		case AifEnDeleteContainer:
265036e0bf6eSScott Long 			/*
2651914da7d0SScott Long 			 * A container was added or deleted, but the message
2652914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
2653914da7d0SScott Long 			 * containers and sort things out.
265436e0bf6eSScott Long 			 */
265503b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
2656cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
265736e0bf6eSScott Long 			do {
265836e0bf6eSScott Long 				/*
2659914da7d0SScott Long 				 * Ask the controller for its containers one at
2660914da7d0SScott Long 				 * a time.
2661914da7d0SScott Long 				 * XXX What if the controller's list changes
2662914da7d0SScott Long 				 * midway through this enumaration?
266336e0bf6eSScott Long 				 * XXX This should be done async.
266436e0bf6eSScott Long 				 */
266539ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
266639ee03c3SScott Long 				mi->Command = VM_NameServe;
266739ee03c3SScott Long 				mi->MntType = FT_FILESYS;
2668cbfd045bSScott Long 				mi->MntCount = i;
266936e0bf6eSScott Long 				rsize = sizeof(mir);
2670cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
2671cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
2672795d7dc0SScott Long 					printf("Error probing container %d\n",
2673914da7d0SScott Long 					      i);
267436e0bf6eSScott Long 					continue;
267536e0bf6eSScott Long 				}
2676cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
2677795d7dc0SScott Long 				/* XXX Need to check if count changed */
2678795d7dc0SScott Long 				count = mir->MntRespCount;
267936e0bf6eSScott Long 				/*
2680914da7d0SScott Long 				 * Check the container against our list.
2681914da7d0SScott Long 				 * co->co_found was already set to 0 in a
2682914da7d0SScott Long 				 * previous run.
268336e0bf6eSScott Long 				 */
2684cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
2685cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
268636e0bf6eSScott Long 					found = 0;
2687914da7d0SScott Long 					TAILQ_FOREACH(co,
2688914da7d0SScott Long 						      &sc->aac_container_tqh,
2689914da7d0SScott Long 						      co_link) {
269036e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
2691cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
269236e0bf6eSScott Long 							co->co_found = 1;
269336e0bf6eSScott Long 							found = 1;
269436e0bf6eSScott Long 							break;
269536e0bf6eSScott Long 						}
269636e0bf6eSScott Long 					}
2697914da7d0SScott Long 					/*
2698914da7d0SScott Long 					 * If the container matched, continue
2699914da7d0SScott Long 					 * in the list.
2700914da7d0SScott Long 					 */
270136e0bf6eSScott Long 					if (found) {
270236e0bf6eSScott Long 						i++;
270336e0bf6eSScott Long 						continue;
270436e0bf6eSScott Long 					}
270536e0bf6eSScott Long 
270636e0bf6eSScott Long 					/*
2707914da7d0SScott Long 					 * This is a new container.  Do all the
270870545d1aSScott Long 					 * appropriate things to set it up.
270970545d1aSScott Long 					 */
2710cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
271136e0bf6eSScott Long 					added = 1;
271236e0bf6eSScott Long 				}
271336e0bf6eSScott Long 				i++;
2714795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
2715cbfd045bSScott Long 			aac_release_sync_fib(sc);
271636e0bf6eSScott Long 
271736e0bf6eSScott Long 			/*
2718914da7d0SScott Long 			 * Go through our list of containers and see which ones
2719914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
2720914da7d0SScott Long 			 * list them they must have been deleted.  Do the
2721914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
2722914da7d0SScott Long 			 * the co->co_found field.
272336e0bf6eSScott Long 			 */
272436e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
272536e0bf6eSScott Long 			while (co != NULL) {
272636e0bf6eSScott Long 				if (co->co_found == 0) {
2727914da7d0SScott Long 					device_delete_child(sc->aac_dev,
2728914da7d0SScott Long 							    co->co_disk);
272936e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
2730bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
2731914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
2732914da7d0SScott Long 						     co_link);
2733bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
2734ba1d57e7SScott Long 					free(co, M_AACBUF);
273536e0bf6eSScott Long 					co = co_next;
273636e0bf6eSScott Long 				} else {
273736e0bf6eSScott Long 					co->co_found = 0;
273836e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
273936e0bf6eSScott Long 				}
274036e0bf6eSScott Long 			}
274136e0bf6eSScott Long 
274236e0bf6eSScott Long 			/* Attach the newly created containers */
274336e0bf6eSScott Long 			if (added)
274436e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
274536e0bf6eSScott Long 
274636e0bf6eSScott Long 			break;
274736e0bf6eSScott Long 
274836e0bf6eSScott Long 		default:
274936e0bf6eSScott Long 			break;
275036e0bf6eSScott Long 		}
275136e0bf6eSScott Long 
275236e0bf6eSScott Long 	default:
275336e0bf6eSScott Long 		break;
275436e0bf6eSScott Long 	}
275536e0bf6eSScott Long 
275636e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
2757bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
275835863739SMike Smith 	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
275935863739SMike Smith 	if (next != sc->aac_aifq_tail) {
276035863739SMike Smith 		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
276135863739SMike Smith 		sc->aac_aifq_head = next;
2762b3457b51SScott Long 
2763b3457b51SScott Long 		/* On the off chance that someone is sleeping for an aif... */
276435863739SMike Smith 		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
276535863739SMike Smith 			wakeup(sc->aac_aifq);
2766b3457b51SScott Long 		/* Wakeup any poll()ers */
2767512824f8SSeigo Tanimura 		selwakeuppri(&sc->rcv_select, PRIBIO);
276835863739SMike Smith 	}
2769bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
277036e0bf6eSScott Long 
277136e0bf6eSScott Long 	return;
277235863739SMike Smith }
277335863739SMike Smith 
2774914da7d0SScott Long /*
27750b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
277636e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
277736e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
277836e0bf6eSScott Long  * returning what the card reported.
277935863739SMike Smith  */
278035863739SMike Smith static int
2781fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
278235863739SMike Smith {
278335863739SMike Smith 	struct aac_rev_check rev_check;
278435863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
278535863739SMike Smith 	int error = 0;
278635863739SMike Smith 
278735863739SMike Smith 	debug_called(2);
278835863739SMike Smith 
278935863739SMike Smith 	/*
279035863739SMike Smith 	 * Copyin the revision struct from userspace
279135863739SMike Smith 	 */
2792c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
2793c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
279435863739SMike Smith 		return error;
279535863739SMike Smith 	}
279635863739SMike Smith 
2797914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
2798914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
279935863739SMike Smith 
280035863739SMike Smith 	/*
280135863739SMike Smith 	 * Doctor up the response struct.
280235863739SMike Smith 	 */
280335863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
2804914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
2805914da7d0SScott Long 	    sc->aac_revision.external.ul;
2806914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
2807914da7d0SScott Long 	    sc->aac_revision.buildNumber;
280835863739SMike Smith 
2809c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
2810c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
281135863739SMike Smith }
281235863739SMike Smith 
2813914da7d0SScott Long /*
281435863739SMike Smith  * Pass the caller the next AIF in their queue
281535863739SMike Smith  */
281635863739SMike Smith static int
2817fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
281835863739SMike Smith {
281935863739SMike Smith 	struct get_adapter_fib_ioctl agf;
28209e2e96d8SScott Long 	int error;
282135863739SMike Smith 
282235863739SMike Smith 	debug_called(2);
282335863739SMike Smith 
282435863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
282535863739SMike Smith 
282635863739SMike Smith 		/*
282735863739SMike Smith 		 * Check the magic number that we gave the caller.
282835863739SMike Smith 		 */
2829b88ffdc8SScott Long 		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
283035863739SMike Smith 			error = EFAULT;
283135863739SMike Smith 		} else {
2832fb0c27d7SScott Long 			error = aac_return_aif(sc, agf.AifFib);
283335863739SMike Smith 			if ((error == EAGAIN) && (agf.Wait)) {
283435863739SMike Smith 				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
283535863739SMike Smith 				while (error == EAGAIN) {
2836914da7d0SScott Long 					error = tsleep(sc->aac_aifq, PRIBIO |
2837914da7d0SScott Long 						       PCATCH, "aacaif", 0);
283835863739SMike Smith 					if (error == 0)
2839914da7d0SScott Long 						error = aac_return_aif(sc,
2840914da7d0SScott Long 						    agf.AifFib);
284135863739SMike Smith 				}
284235863739SMike Smith 				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
284335863739SMike Smith 			}
284435863739SMike Smith 		}
284535863739SMike Smith 	}
284635863739SMike Smith 	return(error);
284735863739SMike Smith }
284835863739SMike Smith 
2849914da7d0SScott Long /*
28500b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
28510b94a66eSMike Smith  */
28520b94a66eSMike Smith static int
2853fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr)
28540b94a66eSMike Smith {
28553df780cfSScott Long 	int next, error;
28560b94a66eSMike Smith 
28570b94a66eSMike Smith 	debug_called(2);
28580b94a66eSMike Smith 
2859bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
28600b94a66eSMike Smith 	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
2861bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
28623df780cfSScott Long 		return (EAGAIN);
28633df780cfSScott Long 	}
28643df780cfSScott Long 
28653df780cfSScott Long 	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
28663df780cfSScott Long 	error = copyout(&sc->aac_aifq[next], uptr,
2867c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
286836e0bf6eSScott Long 	if (error)
286970545d1aSScott Long 		device_printf(sc->aac_dev,
287070545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
28713df780cfSScott Long 	else
28723df780cfSScott Long 		sc->aac_aifq_tail = next;
28733df780cfSScott Long 
2874bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
28750b94a66eSMike Smith 	return(error);
28760b94a66eSMike Smith }
287736e0bf6eSScott Long 
2878914da7d0SScott Long /*
287936e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
288036e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
288136e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
288236e0bf6eSScott Long  */
288336e0bf6eSScott Long static int
288436e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
288536e0bf6eSScott Long {
288636e0bf6eSScott Long 	struct aac_query_disk query_disk;
288736e0bf6eSScott Long 	struct aac_container *co;
2888914da7d0SScott Long 	struct aac_disk	*disk;
288936e0bf6eSScott Long 	int error, id;
289036e0bf6eSScott Long 
289136e0bf6eSScott Long 	debug_called(2);
289236e0bf6eSScott Long 
2893914da7d0SScott Long 	disk = NULL;
2894914da7d0SScott Long 
2895914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
2896914da7d0SScott Long 		       sizeof(struct aac_query_disk));
289736e0bf6eSScott Long 	if (error)
289836e0bf6eSScott Long 		return (error);
289936e0bf6eSScott Long 
290036e0bf6eSScott Long 	id = query_disk.ContainerNumber;
290136e0bf6eSScott Long 	if (id == -1)
290236e0bf6eSScott Long 		return (EINVAL);
290336e0bf6eSScott Long 
2904bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
290536e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
290636e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
290736e0bf6eSScott Long 			break;
290836e0bf6eSScott Long 		}
290936e0bf6eSScott Long 
291036e0bf6eSScott Long 	if (co == NULL) {
291136e0bf6eSScott Long 			query_disk.Valid = 0;
291236e0bf6eSScott Long 			query_disk.Locked = 0;
291336e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
291436e0bf6eSScott Long 	} else {
291536e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
291636e0bf6eSScott Long 		query_disk.Valid = 1;
2917914da7d0SScott Long 		query_disk.Locked =
2918914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
291936e0bf6eSScott Long 		query_disk.Deleted = 0;
2920b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
292136e0bf6eSScott Long 		query_disk.Target = disk->unit;
292236e0bf6eSScott Long 		query_disk.Lun = 0;
292336e0bf6eSScott Long 		query_disk.UnMapped = 0;
29247540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
29250b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
292636e0bf6eSScott Long 	}
2927bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
292836e0bf6eSScott Long 
2929914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
2930914da7d0SScott Long 			sizeof(struct aac_query_disk));
293136e0bf6eSScott Long 
293236e0bf6eSScott Long 	return (error);
293336e0bf6eSScott Long }
293436e0bf6eSScott Long 
2935fe3cb0e1SScott Long static void
2936fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
2937fe3cb0e1SScott Long {
2938fe3cb0e1SScott Long 	struct aac_fib *fib;
2939fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
2940fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
2941fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
2942fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
2943fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
294470545d1aSScott Long 	struct aac_sim *caminf;
2945fe3cb0e1SScott Long 	device_t child;
2946fe3cb0e1SScott Long 	int i, found, error;
2947fe3cb0e1SScott Long 
294803b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2949fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
295039ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
2951fe3cb0e1SScott Long 
2952fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
2953fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
2954fe3cb0e1SScott Long 	c_cmd->param = 0;
2955fe3cb0e1SScott Long 
2956fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
2957fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
2958fe3cb0e1SScott Long 	if (error) {
2959fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
2960fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
2961fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2962fe3cb0e1SScott Long 		return;
2963fe3cb0e1SScott Long 	}
2964fe3cb0e1SScott Long 
2965fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
2966fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
2967fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
2968fe3cb0e1SScott Long 		    c_resp->Status);
2969fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2970fe3cb0e1SScott Long 		return;
2971fe3cb0e1SScott Long 	}
2972fe3cb0e1SScott Long 
2973fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
2974fe3cb0e1SScott Long 
2975fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
297639ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
297739ee03c3SScott Long 
2978fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
2979fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
2980fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
2981fe3cb0e1SScott Long 	vmi->ObjId = 0;
2982fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
2983fe3cb0e1SScott Long 
2984fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
2985fe3cb0e1SScott Long 	    sizeof(struct aac_vmioctl));
2986fe3cb0e1SScott Long 	if (error) {
2987fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
2988fe3cb0e1SScott Long 		    error);
2989fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2990fe3cb0e1SScott Long 		return;
2991fe3cb0e1SScott Long 	}
2992fe3cb0e1SScott Long 
2993fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
2994fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
2995fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
2996fe3cb0e1SScott Long 		    vmi_resp->Status);
2997fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2998fe3cb0e1SScott Long 		return;
2999fe3cb0e1SScott Long 	}
3000fe3cb0e1SScott Long 
3001fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3002fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
3003fe3cb0e1SScott Long 
3004fe3cb0e1SScott Long 	found = 0;
3005fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3006fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3007fe3cb0e1SScott Long 			continue;
3008fe3cb0e1SScott Long 
3009a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3010a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3011fe3cb0e1SScott Long 		if (caminf == NULL)
3012fe3cb0e1SScott Long 			continue;
3013fe3cb0e1SScott Long 
3014fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3015fe3cb0e1SScott Long 		if (child == NULL) {
3016fe3cb0e1SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
3017fe3cb0e1SScott Long 			continue;
3018fe3cb0e1SScott Long 		}
3019fe3cb0e1SScott Long 
3020fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3021fe3cb0e1SScott Long 		caminf->BusNumber = i;
3022fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3023fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3024ddb8683eSScott Long 		caminf->sim_dev = child;
3025fe3cb0e1SScott Long 
3026fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3027fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
302870545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3029fe3cb0e1SScott Long 
3030fe3cb0e1SScott Long 		found = 1;
3031fe3cb0e1SScott Long 	}
3032fe3cb0e1SScott Long 
3033fe3cb0e1SScott Long 	if (found)
3034fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3035fe3cb0e1SScott Long 
3036fe3cb0e1SScott Long 	return;
3037fe3cb0e1SScott Long }
3038