xref: /freebsd/sys/dev/aac/aac.c (revision b5f516cdaf5da6ca16054283915e6426c66b135d)
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>
57b5f516cdSScott Long #include <sys/bus_dma.h>
5835863739SMike Smith #include <machine/resource.h>
5935863739SMike Smith 
6035863739SMike Smith #include <dev/aac/aacreg.h>
610b0594cdSScott Long #include <sys/aac_ioctl.h>
6235863739SMike Smith #include <dev/aac/aacvar.h>
6335863739SMike Smith #include <dev/aac/aac_tables.h>
6435863739SMike Smith 
6535863739SMike Smith static void	aac_startup(void *arg);
66914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
67cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
68fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
6935863739SMike Smith 
7035863739SMike Smith /* Command Processing */
710b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7235863739SMike Smith static void	aac_complete(void *context, int pending);
7335863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7435863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
75d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
7670545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
7735863739SMike Smith 
7835863739SMike Smith /* Command Buffer Management */
79cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
80cd481291SScott Long 				   int nseg, int error);
81c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
82c6eafcf2SScott Long 				       int nseg, int error);
830b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
848480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
8535863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
8635863739SMike Smith 
8735863739SMike Smith /* Hardware Interface */
88c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
89c6eafcf2SScott Long 			       int error);
90fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9135863739SMike Smith static int	aac_init(struct aac_softc *sc);
9235863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
93c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
94c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
95c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
96f6c4dd3fSScott Long 				struct aac_command *cm);
97c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
98914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
9936e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10036e0bf6eSScott Long 				     struct aac_fib *fib);
10135863739SMike Smith 
102b3457b51SScott Long /* Falcon/PPC interface */
103b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
104b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
105b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
106b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
107b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
108b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
109b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
110a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
111b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
112b3457b51SScott Long 
113b3457b51SScott Long struct aac_interface aac_fa_interface = {
114b3457b51SScott Long 	aac_fa_get_fwstatus,
115b3457b51SScott Long 	aac_fa_qnotify,
116b3457b51SScott Long 	aac_fa_get_istatus,
117b3457b51SScott Long 	aac_fa_clear_istatus,
118b3457b51SScott Long 	aac_fa_set_mailbox,
119a6d35632SScott Long 	aac_fa_get_mailbox,
120b3457b51SScott Long 	aac_fa_set_interrupts
121b3457b51SScott Long };
122b3457b51SScott Long 
12335863739SMike Smith /* StrongARM interface */
12435863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
12535863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
12635863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
12735863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
12835863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
129c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
130c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
131a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13235863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13335863739SMike Smith 
13435863739SMike Smith struct aac_interface aac_sa_interface = {
13535863739SMike Smith 	aac_sa_get_fwstatus,
13635863739SMike Smith 	aac_sa_qnotify,
13735863739SMike Smith 	aac_sa_get_istatus,
13835863739SMike Smith 	aac_sa_clear_istatus,
13935863739SMike Smith 	aac_sa_set_mailbox,
140a6d35632SScott Long 	aac_sa_get_mailbox,
14135863739SMike Smith 	aac_sa_set_interrupts
14235863739SMike Smith };
14335863739SMike Smith 
14435863739SMike Smith /* i960Rx interface */
14535863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
14635863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
14735863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
14835863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
14935863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
150c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
151c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
152a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
15335863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
15435863739SMike Smith 
15535863739SMike Smith struct aac_interface aac_rx_interface = {
15635863739SMike Smith 	aac_rx_get_fwstatus,
15735863739SMike Smith 	aac_rx_qnotify,
15835863739SMike Smith 	aac_rx_get_istatus,
15935863739SMike Smith 	aac_rx_clear_istatus,
16035863739SMike Smith 	aac_rx_set_mailbox,
161a6d35632SScott Long 	aac_rx_get_mailbox,
16235863739SMike Smith 	aac_rx_set_interrupts
16335863739SMike Smith };
16435863739SMike Smith 
1654afedc31SScott Long /* Rocket/MIPS interface */
1664afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1674afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1684afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1694afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1704afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1714afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1724afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1734afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1744afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1754afedc31SScott Long 
1764afedc31SScott Long struct aac_interface aac_rkt_interface = {
1774afedc31SScott Long 	aac_rkt_get_fwstatus,
1784afedc31SScott Long 	aac_rkt_qnotify,
1794afedc31SScott Long 	aac_rkt_get_istatus,
1804afedc31SScott Long 	aac_rkt_clear_istatus,
1814afedc31SScott Long 	aac_rkt_set_mailbox,
1824afedc31SScott Long 	aac_rkt_get_mailbox,
1834afedc31SScott Long 	aac_rkt_set_interrupts
1844afedc31SScott Long };
1854afedc31SScott Long 
18635863739SMike Smith /* Debugging and Diagnostics */
18735863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
1886965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
189c6eafcf2SScott Long 				   u_int32_t code);
19035863739SMike Smith 
19135863739SMike Smith /* Management Interface */
19235863739SMike Smith static d_open_t		aac_open;
19335863739SMike Smith static d_close_t	aac_close;
19435863739SMike Smith static d_ioctl_t	aac_ioctl;
195b3457b51SScott Long static d_poll_t		aac_poll;
196c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
197c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
19836e0bf6eSScott Long 					   struct aac_fib *fib);
199fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
200fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
201fb0c27d7SScott Long static int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
20236e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
20335863739SMike Smith 
20435863739SMike Smith static struct cdevsw aac_cdevsw = {
205dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
206dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2077ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2087ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2097ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2107ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2117ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
21235863739SMike Smith };
21335863739SMike Smith 
21436e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
21536e0bf6eSScott Long 
2163d04a9d7SScott Long /* sysctl node */
2173d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2183d04a9d7SScott Long 
219914da7d0SScott Long /*
220914da7d0SScott Long  * Device Interface
221914da7d0SScott Long  */
22235863739SMike Smith 
223914da7d0SScott Long /*
22435863739SMike Smith  * Initialise the controller and softc
22535863739SMike Smith  */
22635863739SMike Smith int
22735863739SMike Smith aac_attach(struct aac_softc *sc)
22835863739SMike Smith {
22935863739SMike Smith 	int error, unit;
23035863739SMike Smith 
23135863739SMike Smith 	debug_called(1);
23235863739SMike Smith 
23335863739SMike Smith 	/*
23435863739SMike Smith 	 * Initialise per-controller queues.
23535863739SMike Smith 	 */
2360b94a66eSMike Smith 	aac_initq_free(sc);
2370b94a66eSMike Smith 	aac_initq_ready(sc);
2380b94a66eSMike Smith 	aac_initq_busy(sc);
2390b94a66eSMike Smith 	aac_initq_bio(sc);
24035863739SMike Smith 
24135863739SMike Smith 	/*
24235863739SMike Smith 	 * Initialise command-completion task.
24335863739SMike Smith 	 */
24435863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
24535863739SMike Smith 
24635863739SMike Smith 	/* disable interrupts before we enable anything */
24735863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
24835863739SMike Smith 
24935863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
25035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
25135863739SMike Smith 
25235863739SMike Smith 	/*
253fe94b852SScott Long 	 * Check that the firmware on the card is supported.
254fe94b852SScott Long 	 */
255fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
256fe94b852SScott Long 		return(error);
257fe94b852SScott Long 
258f6b1c44dSScott Long 	/*
259f6b1c44dSScott Long 	 * Initialize locks
260f6b1c44dSScott Long 	 */
261bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
262bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
263bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
264f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
265f6b1c44dSScott Long 
2663df780cfSScott Long 	/* Initialize the local AIF queue pointers */
2673df780cfSScott Long 	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
268cbfd045bSScott Long 
2690b94a66eSMike Smith 	/*
27035863739SMike Smith 	 * Initialise the adapter.
27135863739SMike Smith 	 */
2720b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
27335863739SMike Smith 		return(error);
27435863739SMike Smith 
27535863739SMike Smith 	/*
27635863739SMike Smith 	 * Print a little information about the controller.
27735863739SMike Smith 	 */
27835863739SMike Smith 	aac_describe_controller(sc);
27935863739SMike Smith 
28035863739SMike Smith 	/*
281ae543596SScott Long 	 * Register to probe our containers later.
282ae543596SScott Long 	 */
28335863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
28435863739SMike Smith 	sc->aac_ich.ich_arg = sc;
28535863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
286914da7d0SScott Long 		device_printf(sc->aac_dev,
287914da7d0SScott Long 			      "can't establish configuration hook\n");
28835863739SMike Smith 		return(ENXIO);
28935863739SMike Smith 	}
29035863739SMike Smith 
29135863739SMike Smith 	/*
29235863739SMike Smith 	 * Make the control device.
29335863739SMike Smith 	 */
29435863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
2959e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
2969e9466baSRobert Watson 				 0640, "aac%d", unit);
297157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
2984aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
29935863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
30035863739SMike Smith 
30136e0bf6eSScott Long 	/* Create the AIF thread */
30270545d1aSScott Long 	if (kthread_create((void(*)(void *))aac_command_thread, sc,
303316ec49aSScott Long 			   &sc->aifthread, 0, 0, "aac%daif", unit))
30436e0bf6eSScott Long 		panic("Could not create AIF thread\n");
30536e0bf6eSScott Long 
30636e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3075f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3085f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3095f54d522SScott Long 		device_printf(sc->aac_dev,
3105f54d522SScott Long 			      "shutdown event registration failed\n");
31136e0bf6eSScott Long 
312fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
313a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
31470545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
315fe3cb0e1SScott Long 		aac_get_bus_info(sc);
31670545d1aSScott Long 	}
317fe3cb0e1SScott Long 
31835863739SMike Smith 	return(0);
31935863739SMike Smith }
32035863739SMike Smith 
321914da7d0SScott Long /*
32235863739SMike Smith  * Probe for containers, create disks.
32335863739SMike Smith  */
32435863739SMike Smith static void
32535863739SMike Smith aac_startup(void *arg)
32635863739SMike Smith {
327914da7d0SScott Long 	struct aac_softc *sc;
328cbfd045bSScott Long 	struct aac_fib *fib;
329cbfd045bSScott Long 	struct aac_mntinfo *mi;
330cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
331795d7dc0SScott Long 	int count = 0, i = 0;
33235863739SMike Smith 
33335863739SMike Smith 	debug_called(1);
33435863739SMike Smith 
335914da7d0SScott Long 	sc = (struct aac_softc *)arg;
336914da7d0SScott Long 
33735863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
33835863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
33935863739SMike Smith 
34003b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
341cbfd045bSScott Long 	mi = (struct aac_mntinfo *)&fib->data[0];
342cbfd045bSScott Long 
34335863739SMike Smith 	/* loop over possible containers */
34436e0bf6eSScott Long 	do {
34535863739SMike Smith 		/* request information on this container */
34639ee03c3SScott Long 		bzero(mi, sizeof(struct aac_mntinfo));
34739ee03c3SScott Long 		mi->Command = VM_NameServe;
34839ee03c3SScott Long 		mi->MntType = FT_FILESYS;
349cbfd045bSScott Long 		mi->MntCount = i;
350cbfd045bSScott Long 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
351cbfd045bSScott Long 				 sizeof(struct aac_mntinfo))) {
352795d7dc0SScott Long 			printf("error probing container %d", i);
35335863739SMike Smith 			continue;
35435863739SMike Smith 		}
35535863739SMike Smith 
356cbfd045bSScott Long 		mir = (struct aac_mntinforesp *)&fib->data[0];
357795d7dc0SScott Long 		/* XXX Need to check if count changed */
358795d7dc0SScott Long 		count = mir->MntRespCount;
359cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
36036e0bf6eSScott Long 		i++;
361795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
362cbfd045bSScott Long 
363cbfd045bSScott Long 	aac_release_sync_fib(sc);
36435863739SMike Smith 
36535863739SMike Smith 	/* poke the bus to actually attach the child devices */
36635863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
36735863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
36835863739SMike Smith 
36935863739SMike Smith 	/* mark the controller up */
37035863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
37135863739SMike Smith 
37235863739SMike Smith 	/* enable interrupts now */
37335863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
37435863739SMike Smith }
37535863739SMike Smith 
376914da7d0SScott Long /*
377914da7d0SScott Long  * Create a device to respresent a new container
378914da7d0SScott Long  */
379914da7d0SScott Long static void
380cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
381914da7d0SScott Long {
382914da7d0SScott Long 	struct aac_container *co;
383914da7d0SScott Long 	device_t child;
384914da7d0SScott Long 
385914da7d0SScott Long 	/*
386914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
387914da7d0SScott Long 	 * the possible types may never show up.
388914da7d0SScott Long 	 */
389914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
390a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
391a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
392914da7d0SScott Long 		if (co == NULL)
393914da7d0SScott Long 			panic("Out of memory?!\n");
394914da7d0SScott Long 		debug(1, "id %x  name '%.16s'  size %u  type %d",
395914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
396914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
397914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
398914da7d0SScott Long 
399fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
400914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
401914da7d0SScott Long 		else
402914da7d0SScott Long 			device_set_ivars(child, co);
403914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
404914da7d0SScott Long 				mir->MntTable[0].VolType));
405914da7d0SScott Long 		co->co_disk = child;
406914da7d0SScott Long 		co->co_found = f;
407914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
408914da7d0SScott Long 		      sizeof(struct aac_mntobj));
409bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
410914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
411bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
412914da7d0SScott Long 	}
413914da7d0SScott Long }
414914da7d0SScott Long 
415914da7d0SScott Long /*
41635863739SMike Smith  * Free all of the resources associated with (sc)
41735863739SMike Smith  *
41835863739SMike Smith  * Should not be called if the controller is active.
41935863739SMike Smith  */
42035863739SMike Smith void
42135863739SMike Smith aac_free(struct aac_softc *sc)
42235863739SMike Smith {
423ffb37f33SScott Long 
42435863739SMike Smith 	debug_called(1);
42535863739SMike Smith 
42635863739SMike Smith 	/* remove the control device */
42735863739SMike Smith 	if (sc->aac_dev_t != NULL)
42835863739SMike Smith 		destroy_dev(sc->aac_dev_t);
42935863739SMike Smith 
4300b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
4318480cc63SScott Long 	aac_free_commands(sc);
4320b94a66eSMike Smith 	if (sc->aac_fib_dmat)
4330b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
43435863739SMike Smith 
435ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
436ffb37f33SScott Long 
43735863739SMike Smith 	/* destroy the common area */
43835863739SMike Smith 	if (sc->aac_common) {
43935863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
440c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
441c6eafcf2SScott Long 				sc->aac_common_dmamap);
44235863739SMike Smith 	}
4430b94a66eSMike Smith 	if (sc->aac_common_dmat)
4440b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
44535863739SMike Smith 
44635863739SMike Smith 	/* disconnect the interrupt handler */
44735863739SMike Smith 	if (sc->aac_intr)
44835863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
44935863739SMike Smith 	if (sc->aac_irq != NULL)
450c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
451c6eafcf2SScott Long 				     sc->aac_irq);
45235863739SMike Smith 
45335863739SMike Smith 	/* destroy data-transfer DMA tag */
45435863739SMike Smith 	if (sc->aac_buffer_dmat)
45535863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
45635863739SMike Smith 
45735863739SMike Smith 	/* destroy the parent DMA tag */
45835863739SMike Smith 	if (sc->aac_parent_dmat)
45935863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
46035863739SMike Smith 
46135863739SMike Smith 	/* release the register window mapping */
46235863739SMike Smith 	if (sc->aac_regs_resource != NULL)
463914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
464914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
46535863739SMike Smith }
46635863739SMike Smith 
467914da7d0SScott Long /*
46835863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
46935863739SMike Smith  */
47035863739SMike Smith int
47135863739SMike Smith aac_detach(device_t dev)
47235863739SMike Smith {
473914da7d0SScott Long 	struct aac_softc *sc;
47470545d1aSScott Long 	struct aac_container *co;
47570545d1aSScott Long 	struct aac_sim	*sim;
47635863739SMike Smith 	int error;
47735863739SMike Smith 
47835863739SMike Smith 	debug_called(1);
47935863739SMike Smith 
480914da7d0SScott Long 	sc = device_get_softc(dev);
481914da7d0SScott Long 
48235863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
48335863739SMike Smith 		return(EBUSY);
48435863739SMike Smith 
48570545d1aSScott Long 	/* Remove the child containers */
486a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
48770545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
48870545d1aSScott Long 		if (error)
48970545d1aSScott Long 			return (error);
49065ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
491a761a1caSScott Long 		free(co, M_AACBUF);
49270545d1aSScott Long 	}
49370545d1aSScott Long 
49470545d1aSScott Long 	/* Remove the CAM SIMs */
495a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
496a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
49770545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
49870545d1aSScott Long 		if (error)
49970545d1aSScott Long 			return (error);
500a761a1caSScott Long 		free(sim, M_AACBUF);
50170545d1aSScott Long 	}
50270545d1aSScott Long 
50336e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
50436e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
50536e0bf6eSScott Long 		wakeup(sc->aifthread);
50636e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
50736e0bf6eSScott Long 	}
50836e0bf6eSScott Long 
50936e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
51036e0bf6eSScott Long 		panic("Cannot shutdown AIF thread\n");
51136e0bf6eSScott Long 
51235863739SMike Smith 	if ((error = aac_shutdown(dev)))
51335863739SMike Smith 		return(error);
51435863739SMike Smith 
5155f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
5165f54d522SScott Long 
51735863739SMike Smith 	aac_free(sc);
51835863739SMike Smith 
519dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
520dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
521dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
522dc9efde5SScott Long 
52335863739SMike Smith 	return(0);
52435863739SMike Smith }
52535863739SMike Smith 
526914da7d0SScott Long /*
52735863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
52835863739SMike Smith  *
52935863739SMike Smith  * This function is called before detach or system shutdown.
53035863739SMike Smith  *
5310b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
53235863739SMike Smith  * allow shutdown if any device is open.
53335863739SMike Smith  */
53435863739SMike Smith int
53535863739SMike Smith aac_shutdown(device_t dev)
53635863739SMike Smith {
537914da7d0SScott Long 	struct aac_softc *sc;
538cbfd045bSScott Long 	struct aac_fib *fib;
539cbfd045bSScott Long 	struct aac_close_command *cc;
54035863739SMike Smith 
54135863739SMike Smith 	debug_called(1);
54235863739SMike Smith 
543914da7d0SScott Long 	sc = device_get_softc(dev);
544914da7d0SScott Long 
54535863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
54635863739SMike Smith 
54735863739SMike Smith 	/*
54835863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
54935863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
55035863739SMike Smith 	 * We've been closed and all I/O completed already
55135863739SMike Smith 	 */
55235863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
55335863739SMike Smith 
55403b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
555cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
556cbfd045bSScott Long 
55739ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
558cbfd045bSScott Long 	cc->Command = VM_CloseAll;
559cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
560cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
561cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
56235863739SMike Smith 		printf("FAILED.\n");
56370545d1aSScott Long 	else
56470545d1aSScott Long 		printf("done\n");
56570545d1aSScott Long #if 0
566914da7d0SScott Long 	else {
567cbfd045bSScott Long 		fib->data[0] = 0;
56836e0bf6eSScott Long 		/*
569914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
57036e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
57136e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
57236e0bf6eSScott Long 		 * driver module with the intent to reload it later.
57336e0bf6eSScott Long 		 */
574cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
575cbfd045bSScott Long 		    fib, 1)) {
57635863739SMike Smith 			printf("FAILED.\n");
57735863739SMike Smith 		} else {
57835863739SMike Smith 			printf("done.\n");
57935863739SMike Smith 		}
58035863739SMike Smith 	}
58170545d1aSScott Long #endif
58235863739SMike Smith 
58335863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
5843576af8fSScott Long 	aac_release_sync_fib(sc);
58535863739SMike Smith 
58635863739SMike Smith 	return(0);
58735863739SMike Smith }
58835863739SMike Smith 
589914da7d0SScott Long /*
59035863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
59135863739SMike Smith  */
59235863739SMike Smith int
59335863739SMike Smith aac_suspend(device_t dev)
59435863739SMike Smith {
595914da7d0SScott Long 	struct aac_softc *sc;
59635863739SMike Smith 
59735863739SMike Smith 	debug_called(1);
598914da7d0SScott Long 
599914da7d0SScott Long 	sc = device_get_softc(dev);
600914da7d0SScott Long 
60135863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
60235863739SMike Smith 
60335863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
60435863739SMike Smith 	return(0);
60535863739SMike Smith }
60635863739SMike Smith 
607914da7d0SScott Long /*
60835863739SMike Smith  * Bring the controller back to a state ready for operation.
60935863739SMike Smith  */
61035863739SMike Smith int
61135863739SMike Smith aac_resume(device_t dev)
61235863739SMike Smith {
613914da7d0SScott Long 	struct aac_softc *sc;
61435863739SMike Smith 
61535863739SMike Smith 	debug_called(1);
616914da7d0SScott Long 
617914da7d0SScott Long 	sc = device_get_softc(dev);
618914da7d0SScott Long 
61935863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
62035863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
62135863739SMike Smith 	return(0);
62235863739SMike Smith }
62335863739SMike Smith 
624914da7d0SScott Long /*
62535863739SMike Smith  * Take an interrupt.
62635863739SMike Smith  */
62735863739SMike Smith void
62835863739SMike Smith aac_intr(void *arg)
62935863739SMike Smith {
630914da7d0SScott Long 	struct aac_softc *sc;
63170545d1aSScott Long 	u_int16_t reason;
63235863739SMike Smith 
63335863739SMike Smith 	debug_called(2);
63435863739SMike Smith 
635914da7d0SScott Long 	sc = (struct aac_softc *)arg;
636914da7d0SScott Long 
637f30ac74cSScott Long 	/*
6389148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
6399148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
6409148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
6419148fa21SScott Long 	 * ugly.
642f30ac74cSScott Long 	 */
64335863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
644f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
645f30ac74cSScott Long 
6469c3a7fceSScott Long 	/* handle completion processing */
6479148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
6489148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
64935863739SMike Smith 
6509148fa21SScott Long 	/* controller wants to talk to us */
6519148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
65270545d1aSScott Long 		/*
6539148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
6549148fa21SScott Long 		 * that start with a NULL.
65570545d1aSScott Long 		 */
6569148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
6579148fa21SScott Long 		    (sc->aac_common->ac_printf[0] == 0))
6589148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
65970545d1aSScott Long 
6609148fa21SScott Long 		/*
6619148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
662a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
6639148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
6649148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
6659148fa21SScott Long 		 * if needed.
6669148fa21SScott Long 		 */
66736e0bf6eSScott Long 		wakeup(sc->aifthread);
66836e0bf6eSScott Long 	}
6699148fa21SScott Long }
67035863739SMike Smith 
671c6eafcf2SScott Long /*
672914da7d0SScott Long  * Command Processing
673914da7d0SScott Long  */
67435863739SMike Smith 
675914da7d0SScott Long /*
67635863739SMike Smith  * Start as much queued I/O as possible on the controller
67735863739SMike Smith  */
678fe3cb0e1SScott Long void
67935863739SMike Smith aac_startio(struct aac_softc *sc)
68035863739SMike Smith {
68135863739SMike Smith 	struct aac_command *cm;
682397fa34fSScott Long 	int error;
68335863739SMike Smith 
68435863739SMike Smith 	debug_called(2);
68535863739SMike Smith 
68635863739SMike Smith 	for (;;) {
687914da7d0SScott Long 		/*
688397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
689397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
690397fa34fSScott Long 		 */
691397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
692397fa34fSScott Long 			break;
693397fa34fSScott Long 
694397fa34fSScott Long 		/*
695914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
696914da7d0SScott Long 		 * resources
697914da7d0SScott Long 		 */
69835863739SMike Smith 		cm = aac_dequeue_ready(sc);
69935863739SMike Smith 
700914da7d0SScott Long 		/*
701914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
702914da7d0SScott Long 		 * return)
703914da7d0SScott Long 		 */
7040b94a66eSMike Smith 		if (cm == NULL)
70535863739SMike Smith 			aac_bio_command(sc, &cm);
70635863739SMike Smith 
70735863739SMike Smith 		/* nothing to do? */
70835863739SMike Smith 		if (cm == NULL)
70935863739SMike Smith 			break;
71035863739SMike Smith 
711cd481291SScott Long 		/* don't map more than once */
712cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
7134102d44bSScott Long 			panic("aac: command %p already mapped", cm);
71435863739SMike Smith 
715397fa34fSScott Long 		/*
716397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
717397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
718397fa34fSScott Long 		 * busdma.
719397fa34fSScott Long 		 */
720cd481291SScott Long 		if (cm->cm_datalen != 0) {
721397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
722397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
723397fa34fSScott Long 						cm->cm_datalen,
724cd481291SScott Long 						aac_map_command_sg, cm, 0);
725cd481291SScott Long 			if (error == EINPROGRESS) {
726cd481291SScott Long 				debug(1, "freezing queue\n");
727cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
728cd481291SScott Long 				error = 0;
729614c22b2SScott Long 			} else if (error != 0)
730397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
731397fa34fSScott Long 				      "busdma\n", error);
732397fa34fSScott Long 		} else
7338778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
734cd481291SScott Long 	}
73535863739SMike Smith }
73635863739SMike Smith 
737914da7d0SScott Long /*
73835863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
73935863739SMike Smith  */
74035863739SMike Smith static void
74170545d1aSScott Long aac_command_thread(struct aac_softc *sc)
74235863739SMike Smith {
74335863739SMike Smith 	struct aac_fib *fib;
74435863739SMike Smith 	u_int32_t fib_size;
7459148fa21SScott Long 	int size, retval;
74635863739SMike Smith 
74736e0bf6eSScott Long 	debug_called(2);
74835863739SMike Smith 
749bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
750a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
75136e0bf6eSScott Long 
752a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
753a32a982dSScott Long 
754a32a982dSScott Long 		retval = 0;
755a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
756a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
757a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
75836e0bf6eSScott Long 
7599148fa21SScott Long 		/*
7609148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
7619148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
7629148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
7639148fa21SScott Long 		 */
7649148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
765bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
766a32a982dSScott Long 			aac_alloc_commands(sc);
767bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
7684102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
769a32a982dSScott Long 			aac_startio(sc);
770a32a982dSScott Long 		}
7719148fa21SScott Long 
7729148fa21SScott Long 		/*
7739148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
7749148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
7759148fa21SScott Long 		 * always fire.
7769148fa21SScott Long 		 */
7779148fa21SScott Long 		if (retval == EWOULDBLOCK)
77870545d1aSScott Long 			aac_timeout(sc);
77970545d1aSScott Long 
78070545d1aSScott Long 		/* Check the hardware printf message buffer */
7819148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
78270545d1aSScott Long 			aac_print_printf(sc);
78370545d1aSScott Long 
7849148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
7859148fa21SScott Long 		while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
7869148fa21SScott Long 				       &fib_size, &fib) == 0) {
78735863739SMike Smith 
78836e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
78936e0bf6eSScott Long 
79035863739SMike Smith 			switch (fib->Header.Command) {
79135863739SMike Smith 			case AifRequest:
79236e0bf6eSScott Long 				aac_handle_aif(sc, fib);
79335863739SMike Smith 				break;
79435863739SMike Smith 			default:
795914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
796914da7d0SScott Long 					      "from controller\n");
79735863739SMike Smith 				break;
79835863739SMike Smith 			}
79935863739SMike Smith 
80036e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
80136e0bf6eSScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
80236e0bf6eSScott Long 				break;
80336e0bf6eSScott Long 
80470545d1aSScott Long 			/* Return the AIF to the controller. */
80536e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
80636e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
80736e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
80836e0bf6eSScott Long 
80936e0bf6eSScott Long 				/* XXX Compute the Size field? */
81036e0bf6eSScott Long 				size = fib->Header.Size;
81136e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
81236e0bf6eSScott Long 					size = sizeof(struct aac_fib);
81336e0bf6eSScott Long 					fib->Header.Size = size;
81436e0bf6eSScott Long 				}
81536e0bf6eSScott Long 				/*
816914da7d0SScott Long 				 * Since we did not generate this command, it
817914da7d0SScott Long 				 * cannot go through the normal
818914da7d0SScott Long 				 * enqueue->startio chain.
81936e0bf6eSScott Long 				 */
820914da7d0SScott Long 				aac_enqueue_response(sc,
821914da7d0SScott Long 						     AAC_ADAP_NORM_RESP_QUEUE,
822914da7d0SScott Long 						     fib);
82336e0bf6eSScott Long 			}
82436e0bf6eSScott Long 		}
82536e0bf6eSScott Long 	}
82636e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
827bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
82836e0bf6eSScott Long 	wakeup(sc->aac_dev);
82936e0bf6eSScott Long 
83036e0bf6eSScott Long 	kthread_exit(0);
83135863739SMike Smith }
83235863739SMike Smith 
833914da7d0SScott Long /*
8349c3a7fceSScott Long  * Process completed commands.
83535863739SMike Smith  */
83635863739SMike Smith static void
8379c3a7fceSScott Long aac_complete(void *context, int pending)
83835863739SMike Smith {
8399c3a7fceSScott Long 	struct aac_softc *sc;
84035863739SMike Smith 	struct aac_command *cm;
84135863739SMike Smith 	struct aac_fib *fib;
84235863739SMike Smith 	u_int32_t fib_size;
84335863739SMike Smith 
84435863739SMike Smith 	debug_called(2);
84535863739SMike Smith 
8469c3a7fceSScott Long 	sc = (struct aac_softc *)context;
8479c3a7fceSScott Long 
848bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
849ae543596SScott Long 
8509c3a7fceSScott Long 	/* pull completed commands off the queue */
85135863739SMike Smith 	for (;;) {
85235863739SMike Smith 		/* look for completed FIBs on our queue */
853914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
854914da7d0SScott Long 				    &fib))
85535863739SMike Smith 			break;	/* nothing to do */
85635863739SMike Smith 
857ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
858cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
85935863739SMike Smith 		if (cm == NULL) {
86035863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
8619c3a7fceSScott Long 			break;
8629c3a7fceSScott Long 		}
8639c3a7fceSScott Long 
8640b94a66eSMike Smith 		aac_remove_busy(cm);
865ecd1c51fSScott Long 		aac_unmap_command(cm);
86635863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
86735863739SMike Smith 
86835863739SMike Smith 		/* is there a completion handler? */
86935863739SMike Smith 		if (cm->cm_complete != NULL) {
87035863739SMike Smith 			cm->cm_complete(cm);
87135863739SMike Smith 		} else {
87235863739SMike Smith 			/* assume that someone is sleeping on this command */
87335863739SMike Smith 			wakeup(cm);
87435863739SMike Smith 		}
87535863739SMike Smith 	}
8760b94a66eSMike Smith 
8770b94a66eSMike Smith 	/* see if we can start some more I/O */
878cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
8790b94a66eSMike Smith 	aac_startio(sc);
880ae543596SScott Long 
881bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
88235863739SMike Smith }
88335863739SMike Smith 
884914da7d0SScott Long /*
88535863739SMike Smith  * Handle a bio submitted from a disk device.
88635863739SMike Smith  */
88735863739SMike Smith void
88835863739SMike Smith aac_submit_bio(struct bio *bp)
88935863739SMike Smith {
890914da7d0SScott Long 	struct aac_disk *ad;
891914da7d0SScott Long 	struct aac_softc *sc;
89235863739SMike Smith 
89335863739SMike Smith 	debug_called(2);
89435863739SMike Smith 
8957540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
896914da7d0SScott Long 	sc = ad->ad_controller;
897914da7d0SScott Long 
89835863739SMike Smith 	/* queue the BIO and try to get some work done */
8990b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
90035863739SMike Smith 	aac_startio(sc);
90135863739SMike Smith }
90235863739SMike Smith 
903914da7d0SScott Long /*
90435863739SMike Smith  * Get a bio and build a command to go with it.
90535863739SMike Smith  */
90635863739SMike Smith static int
90735863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
90835863739SMike Smith {
90935863739SMike Smith 	struct aac_command *cm;
91035863739SMike Smith 	struct aac_fib *fib;
91135863739SMike Smith 	struct aac_disk *ad;
91235863739SMike Smith 	struct bio *bp;
91335863739SMike Smith 
91435863739SMike Smith 	debug_called(2);
91535863739SMike Smith 
91635863739SMike Smith 	/* get the resources we will need */
91735863739SMike Smith 	cm = NULL;
918a32a982dSScott Long 	bp = NULL;
91935863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
92035863739SMike Smith 		goto fail;
921a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
922a32a982dSScott Long 		goto fail;
92335863739SMike Smith 
92435863739SMike Smith 	/* fill out the command */
9250b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
9260b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
9270b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
92835863739SMike Smith 	cm->cm_private = bp;
9290b94a66eSMike Smith 	cm->cm_timestamp = time_second;
93036e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
93135863739SMike Smith 
93235863739SMike Smith 	/* build the FIB */
93335863739SMike Smith 	fib = cm->cm_fib;
934b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
93535863739SMike Smith 	fib->Header.XferState =
93635863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
93735863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
938f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
93935863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
94035863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
941f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
942f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
943f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
94435863739SMike Smith 
94535863739SMike Smith 	/* build the read/write request */
9467540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
947b85f5808SScott Long 
948b85f5808SScott Long 	if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
949b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
9509e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
951b85f5808SScott Long 			struct aac_blockread *br;
95235863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
95335863739SMike Smith 			br->Command = VM_CtBlockRead;
95435863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
95535863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
95635863739SMike Smith 			br->ByteCount = bp->bio_bcount;
95735863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
95835863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
95935863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
96035863739SMike Smith 		} else {
961b85f5808SScott Long 			struct aac_blockwrite *bw;
96235863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
96335863739SMike Smith 			bw->Command = VM_CtBlockWrite;
96435863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
96535863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
96635863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
967b85f5808SScott Long 			bw->Stable = CUNSTABLE;
96835863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
96935863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
97035863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
97135863739SMike Smith 		}
972b85f5808SScott Long 	} else {
973b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
974b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
975b85f5808SScott Long 			struct aac_blockread64 *br;
976b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
977b85f5808SScott Long 			br->Command = VM_CtHostRead64;
978b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
979b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
980b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
981b85f5808SScott Long 			br->Pad = 0;
982b85f5808SScott Long 			br->Flags = 0;
983b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
984b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
985eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
986b85f5808SScott Long 		} else {
987b85f5808SScott Long 			struct aac_blockwrite64 *bw;
988b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
989b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
990b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
991b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
992b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
993b85f5808SScott Long 			bw->Pad = 0;
994b85f5808SScott Long 			bw->Flags = 0;
995b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
996b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
997eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
998b85f5808SScott Long 		}
999b85f5808SScott Long 	}
100035863739SMike Smith 
100135863739SMike Smith 	*cmp = cm;
100235863739SMike Smith 	return(0);
100335863739SMike Smith 
100435863739SMike Smith fail:
100535863739SMike Smith 	if (bp != NULL)
10060b94a66eSMike Smith 		aac_enqueue_bio(sc, bp);
100735863739SMike Smith 	if (cm != NULL)
100835863739SMike Smith 		aac_release_command(cm);
100935863739SMike Smith 	return(ENOMEM);
101035863739SMike Smith }
101135863739SMike Smith 
1012914da7d0SScott Long /*
101335863739SMike Smith  * Handle a bio-instigated command that has been completed.
101435863739SMike Smith  */
101535863739SMike Smith static void
101635863739SMike Smith aac_bio_complete(struct aac_command *cm)
101735863739SMike Smith {
101835863739SMike Smith 	struct aac_blockread_response *brr;
101935863739SMike Smith 	struct aac_blockwrite_response *bwr;
102035863739SMike Smith 	struct bio *bp;
102135863739SMike Smith 	AAC_FSAStatus status;
102235863739SMike Smith 
102335863739SMike Smith 	/* fetch relevant status and then release the command */
102435863739SMike Smith 	bp = (struct bio *)cm->cm_private;
10259e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
102635863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
102735863739SMike Smith 		status = brr->Status;
102835863739SMike Smith 	} else {
102935863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
103035863739SMike Smith 		status = bwr->Status;
103135863739SMike Smith 	}
103235863739SMike Smith 	aac_release_command(cm);
103335863739SMike Smith 
103435863739SMike Smith 	/* fix up the bio based on status */
103535863739SMike Smith 	if (status == ST_OK) {
103635863739SMike Smith 		bp->bio_resid = 0;
103735863739SMike Smith 	} else {
103835863739SMike Smith 		bp->bio_error = EIO;
103935863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
10400b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1041914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1042914da7d0SScott Long 						    status);
104335863739SMike Smith 	}
10440b94a66eSMike Smith 	aac_biodone(bp);
104535863739SMike Smith }
104635863739SMike Smith 
1047914da7d0SScott Long /*
104835863739SMike Smith  * Submit a command to the controller, return when it completes.
1049b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1050b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1051d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1052d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1053d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1054d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1055d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
105635863739SMike Smith  */
105735863739SMike Smith static int
1058d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
105935863739SMike Smith {
1060ae543596SScott Long 	struct aac_softc *sc;
1061d8a0a473SScott Long 	int error;
106235863739SMike Smith 
106335863739SMike Smith 	debug_called(2);
106435863739SMike Smith 
1065ae543596SScott Long 	sc = cm->cm_sc;
1066ae543596SScott Long 
106735863739SMike Smith 	/* Put the command on the ready queue and get things going */
106836e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
106935863739SMike Smith 	aac_enqueue_ready(cm);
1070ae543596SScott Long 	aac_startio(sc);
1071ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
107235863739SMike Smith 	return(error);
107335863739SMike Smith }
107435863739SMike Smith 
1075914da7d0SScott Long /*
1076914da7d0SScott Long  *Command Buffer Management
1077914da7d0SScott Long  */
107835863739SMike Smith 
1079914da7d0SScott Long /*
108035863739SMike Smith  * Allocate a command.
108135863739SMike Smith  */
1082fe3cb0e1SScott Long int
108335863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
108435863739SMike Smith {
108535863739SMike Smith 	struct aac_command *cm;
108635863739SMike Smith 
108735863739SMike Smith 	debug_called(3);
108835863739SMike Smith 
1089ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1090b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1091ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1092ae543596SScott Long 			wakeup(sc->aifthread);
1093b85f5808SScott Long 		}
1094ae543596SScott Long 		return (EBUSY);
1095ffb37f33SScott Long 	}
109635863739SMike Smith 
10970b94a66eSMike Smith 	*cmp = cm;
10980b94a66eSMike Smith 	return(0);
10990b94a66eSMike Smith }
11000b94a66eSMike Smith 
1101914da7d0SScott Long /*
11020b94a66eSMike Smith  * Release a command back to the freelist.
11030b94a66eSMike Smith  */
1104fe3cb0e1SScott Long void
11050b94a66eSMike Smith aac_release_command(struct aac_command *cm)
11060b94a66eSMike Smith {
11070b94a66eSMike Smith 	debug_called(3);
11080b94a66eSMike Smith 
11090b94a66eSMike Smith 	/* (re)initialise the command/FIB */
111035863739SMike Smith 	cm->cm_sgtable = NULL;
111135863739SMike Smith 	cm->cm_flags = 0;
111235863739SMike Smith 	cm->cm_complete = NULL;
111335863739SMike Smith 	cm->cm_private = NULL;
111435863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
111535863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
111635863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
111735863739SMike Smith 	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
111835863739SMike Smith 
111935863739SMike Smith 	/*
112035863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
112135863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
112235863739SMike Smith 	 * initialised here for debugging purposes only.
112335863739SMike Smith 	 */
1124f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1125f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
112635863739SMike Smith 
112735863739SMike Smith 	aac_enqueue_free(cm);
112835863739SMike Smith }
112935863739SMike Smith 
1130914da7d0SScott Long /*
11310b94a66eSMike Smith  * Map helper for command/FIB allocation.
113235863739SMike Smith  */
113335863739SMike Smith static void
11340b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
113535863739SMike Smith {
11368480cc63SScott Long 	uint32_t	*fibphys;
1137914da7d0SScott Long 
11388480cc63SScott Long 	fibphys = (uint32_t *)arg;
113935863739SMike Smith 
114035863739SMike Smith 	debug_called(3);
114135863739SMike Smith 
1142ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
114335863739SMike Smith }
114435863739SMike Smith 
1145914da7d0SScott Long /*
11460b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
114735863739SMike Smith  */
11480b94a66eSMike Smith static int
11490b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
115035863739SMike Smith {
115135863739SMike Smith 	struct aac_command *cm;
1152ffb37f33SScott Long 	struct aac_fibmap *fm;
11538480cc63SScott Long 	uint32_t fibphys;
1154ffb37f33SScott Long 	int i, error;
115535863739SMike Smith 
1156a6d35632SScott Long 	debug_called(2);
115735863739SMike Smith 
1158a6d35632SScott Long 	if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
1159ffb37f33SScott Long 		return (ENOMEM);
1160ffb37f33SScott Long 
11618480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1162a6d35632SScott Long 	if (fm == NULL)
1163a6d35632SScott Long 		return (ENOMEM);
1164ffb37f33SScott Long 
11650b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1166ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1167ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
116870545d1aSScott Long 		device_printf(sc->aac_dev,
116970545d1aSScott Long 			      "Not enough contiguous memory available.\n");
11708480cc63SScott Long 		free(fm, M_AACBUF);
11710b94a66eSMike Smith 		return (ENOMEM);
117235863739SMike Smith 	}
1173128aa5a0SScott Long 
1174cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1175cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1176ffb37f33SScott Long 			      AAC_FIB_COUNT * sizeof(struct aac_fib),
1177ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1178128aa5a0SScott Long 
11790b94a66eSMike Smith 	/* initialise constant fields in the command structure */
1180bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1181ffb37f33SScott Long 	bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
11820b94a66eSMike Smith 	for (i = 0; i < AAC_FIB_COUNT; i++) {
11838480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1184ffb37f33SScott Long 		fm->aac_commands = cm;
118535863739SMike Smith 		cm->cm_sc = sc;
1186ffb37f33SScott Long 		cm->cm_fib = fm->aac_fibs + i;
11878480cc63SScott Long 		cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib));
1188cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
118935863739SMike Smith 
1190ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1191ffb37f33SScott Long 					       &cm->cm_datamap)) == 0)
119235863739SMike Smith 			aac_release_command(cm);
1193ffb37f33SScott Long 		else
11948480cc63SScott Long 			break;
11958480cc63SScott Long 		sc->total_fibs++;
119635863739SMike Smith 	}
1197ffb37f33SScott Long 
11988480cc63SScott Long 	if (i > 0) {
1199ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1200a6d35632SScott Long 		debug(1, "total_fibs= %d\n", sc->total_fibs);
1201bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
12020b94a66eSMike Smith 		return (0);
120335863739SMike Smith 	}
120435863739SMike Smith 
1205bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
12068480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
12078480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
12088480cc63SScott Long 	free(fm, M_AACBUF);
12098480cc63SScott Long 	return (ENOMEM);
12108480cc63SScott Long }
12118480cc63SScott Long 
1212914da7d0SScott Long /*
12130b94a66eSMike Smith  * Free FIBs owned by this adapter.
121435863739SMike Smith  */
121535863739SMike Smith static void
12168480cc63SScott Long aac_free_commands(struct aac_softc *sc)
121735863739SMike Smith {
12188480cc63SScott Long 	struct aac_fibmap *fm;
1219ffb37f33SScott Long 	struct aac_command *cm;
122035863739SMike Smith 	int i;
122135863739SMike Smith 
122235863739SMike Smith 	debug_called(1);
122335863739SMike Smith 
12248480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
12258480cc63SScott Long 
12268480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
12278480cc63SScott Long 		/*
12288480cc63SScott Long 		 * We check against total_fibs to handle partially
12298480cc63SScott Long 		 * allocated blocks.
12308480cc63SScott Long 		 */
12318480cc63SScott Long 		for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
1232ffb37f33SScott Long 			cm = fm->aac_commands + i;
1233ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1234ffb37f33SScott Long 		}
1235ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1236ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
12378480cc63SScott Long 		free(fm, M_AACBUF);
12388480cc63SScott Long 	}
123935863739SMike Smith }
124035863739SMike Smith 
1241914da7d0SScott Long /*
124235863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
124335863739SMike Smith  */
124435863739SMike Smith static void
124535863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
124635863739SMike Smith {
1247cd481291SScott Long 	struct aac_softc *sc;
1248914da7d0SScott Long 	struct aac_command *cm;
1249914da7d0SScott Long 	struct aac_fib *fib;
125035863739SMike Smith 	int i;
125135863739SMike Smith 
125235863739SMike Smith 	debug_called(3);
125335863739SMike Smith 
1254914da7d0SScott Long 	cm = (struct aac_command *)arg;
1255cd481291SScott Long 	sc = cm->cm_sc;
1256914da7d0SScott Long 	fib = cm->cm_fib;
1257914da7d0SScott Long 
125835863739SMike Smith 	/* copy into the FIB */
1259b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
1260b85f5808SScott Long 		if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1261b85f5808SScott Long 			struct aac_sg_table *sg;
1262b85f5808SScott Long 			sg = cm->cm_sgtable;
126335863739SMike Smith 			sg->SgCount = nseg;
126435863739SMike Smith 			for (i = 0; i < nseg; i++) {
126535863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
126635863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
126735863739SMike Smith 			}
126835863739SMike Smith 			/* update the FIB size for the s/g count */
126935863739SMike Smith 			fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
1270b85f5808SScott Long 		} else {
1271b85f5808SScott Long 			struct aac_sg_table64 *sg;
1272b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1273b85f5808SScott Long 			sg->SgCount = nseg;
1274b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1275b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1276b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
127735863739SMike Smith 			}
1278b85f5808SScott Long 			/* update the FIB size for the s/g count */
1279b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1280b85f5808SScott Long 		}
1281b85f5808SScott Long 	}
128235863739SMike Smith 
1283cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1284cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
1285cd481291SScott Long 	 * the SenderFibAddress over to make room for the fast response bit.
128635863739SMike Smith 	 */
1287cd481291SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
1288cd481291SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
128935863739SMike Smith 
1290cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1291cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
129235863739SMike Smith 
129335863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1294c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1295c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
129635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1297c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1298c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
129935863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1300cd481291SScott Long 
1301397fa34fSScott Long 	/* Put the FIB on the outbound queue */
13024102d44bSScott Long 	if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
13034102d44bSScott Long 		aac_unmap_command(cm);
1304397fa34fSScott Long 		sc->flags |= AAC_QUEUE_FRZN;
1305cd481291SScott Long 		aac_requeue_ready(cm);
13064102d44bSScott Long 	}
1307cd481291SScott Long 
1308cd481291SScott Long 	return;
130935863739SMike Smith }
131035863739SMike Smith 
1311914da7d0SScott Long /*
131235863739SMike Smith  * Unmap a command from controller-visible space.
131335863739SMike Smith  */
131435863739SMike Smith static void
131535863739SMike Smith aac_unmap_command(struct aac_command *cm)
131635863739SMike Smith {
1317914da7d0SScott Long 	struct aac_softc *sc;
131835863739SMike Smith 
131935863739SMike Smith 	debug_called(2);
132035863739SMike Smith 
1321914da7d0SScott Long 	sc = cm->cm_sc;
1322914da7d0SScott Long 
132335863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
132435863739SMike Smith 		return;
132535863739SMike Smith 
132635863739SMike Smith 	if (cm->cm_datalen != 0) {
132735863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1328c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1329c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
133035863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1331c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1332c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
133335863739SMike Smith 
133435863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
133535863739SMike Smith 	}
133635863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
133735863739SMike Smith }
133835863739SMike Smith 
1339914da7d0SScott Long /*
1340914da7d0SScott Long  * Hardware Interface
1341914da7d0SScott Long  */
134235863739SMike Smith 
1343914da7d0SScott Long /*
134435863739SMike Smith  * Initialise the adapter.
134535863739SMike Smith  */
134635863739SMike Smith static void
134735863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
134835863739SMike Smith {
1349914da7d0SScott Long 	struct aac_softc *sc;
135035863739SMike Smith 
135135863739SMike Smith 	debug_called(1);
135235863739SMike Smith 
1353914da7d0SScott Long 	sc = (struct aac_softc *)arg;
1354914da7d0SScott Long 
135535863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
135635863739SMike Smith }
135735863739SMike Smith 
1358a6d35632SScott Long static int
1359a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1360a6d35632SScott Long {
1361a6d35632SScott Long 	u_int32_t major, minor, options;
1362a6d35632SScott Long 
1363a6d35632SScott Long 	debug_called(1);
1364a6d35632SScott Long 
1365fe94b852SScott Long 	/*
1366fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1367fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1368fe94b852SScott Long 	 */
1369a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1370fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1371fe94b852SScott Long 				     NULL)) {
1372fe94b852SScott Long 			device_printf(sc->aac_dev,
1373fe94b852SScott Long 				      "Error reading firmware version\n");
1374fe94b852SScott Long 			return (EIO);
1375fe94b852SScott Long 		}
1376fe94b852SScott Long 
1377fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1378a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1379a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1380fe94b852SScott Long 		if (major == 1) {
1381fe94b852SScott Long 			device_printf(sc->aac_dev,
1382fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1383fe94b852SScott Long 			    major, minor);
1384fe94b852SScott Long 			return (EINVAL);
1385fe94b852SScott Long 		}
1386fe94b852SScott Long 	}
1387fe94b852SScott Long 
1388a6d35632SScott Long 	/*
1389a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1390a6d35632SScott Long 	 * work-arounds to enable.
1391a6d35632SScott Long 	 */
1392a6d35632SScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1393a6d35632SScott Long 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1394a6d35632SScott Long 		return (EIO);
1395a6d35632SScott Long 	}
1396a6d35632SScott Long 	options = AAC_GET_MAILBOX(sc, 1);
1397a6d35632SScott Long 	sc->supported_options = options;
1398a6d35632SScott Long 
1399a6d35632SScott Long 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1400a6d35632SScott Long 	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1401a6d35632SScott Long 		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1402a6d35632SScott Long 	if (options & AAC_SUPPORTED_NONDASD)
1403a6d35632SScott Long 		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1404cd481291SScott Long 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1405cd481291SScott Long 	     && (sizeof(bus_addr_t) > 4)) {
1406a6d35632SScott Long 		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1407a6d35632SScott Long 		sc->flags |= AAC_FLAGS_SG_64BIT;
1408a6d35632SScott Long 	}
1409a6d35632SScott Long 
1410a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
1411a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
1412a6d35632SScott Long 		sc->aac_max_fibs = AAC_MAX_FIBS;
1413a6d35632SScott Long 	else
1414a6d35632SScott Long 		sc->aac_max_fibs = 256;
1415a6d35632SScott Long 
1416fe94b852SScott Long 	return (0);
1417fe94b852SScott Long }
1418fe94b852SScott Long 
141935863739SMike Smith static int
142035863739SMike Smith aac_init(struct aac_softc *sc)
142135863739SMike Smith {
142235863739SMike Smith 	struct aac_adapter_init	*ip;
142335863739SMike Smith 	time_t then;
1424b88ffdc8SScott Long 	u_int32_t code, qoffset;
1425a6d35632SScott Long 	int error;
142635863739SMike Smith 
142735863739SMike Smith 	debug_called(1);
142835863739SMike Smith 
142935863739SMike Smith 	/*
143035863739SMike Smith 	 * First wait for the adapter to come ready.
143135863739SMike Smith 	 */
143235863739SMike Smith 	then = time_second;
143335863739SMike Smith 	do {
143435863739SMike Smith 		code = AAC_GET_FWSTATUS(sc);
143535863739SMike Smith 		if (code & AAC_SELF_TEST_FAILED) {
143635863739SMike Smith 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
143735863739SMike Smith 			return(ENXIO);
143835863739SMike Smith 		}
143935863739SMike Smith 		if (code & AAC_KERNEL_PANIC) {
1440914da7d0SScott Long 			device_printf(sc->aac_dev,
1441914da7d0SScott Long 				      "FATAL: controller kernel panic\n");
144235863739SMike Smith 			return(ENXIO);
144335863739SMike Smith 		}
144435863739SMike Smith 		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
1445914da7d0SScott Long 			device_printf(sc->aac_dev,
1446914da7d0SScott Long 				      "FATAL: controller not coming ready, "
1447c6eafcf2SScott Long 					   "status %x\n", code);
144835863739SMike Smith 			return(ENXIO);
144935863739SMike Smith 		}
145035863739SMike Smith 	} while (!(code & AAC_UP_AND_RUNNING));
145135863739SMike Smith 
1452a6d35632SScott Long 	error = ENOMEM;
1453a6d35632SScott Long 	/*
1454a6d35632SScott Long 	 * Create DMA tag for mapping buffers into controller-addressable space.
1455a6d35632SScott Long 	 */
1456a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1457a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1458a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1459a6d35632SScott Long 			       BUS_SPACE_MAXADDR :
1460a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1461a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1462a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1463a6d35632SScott Long 			       MAXBSIZE,		/* maxsize */
1464a6d35632SScott Long 			       AAC_MAXSGENTRIES,	/* nsegments */
1465a6d35632SScott Long 			       MAXBSIZE,		/* maxsegsize */
1466a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1467f6b1c44dSScott Long 			       busdma_lock_mutex,	/* lockfunc */
1468f6b1c44dSScott Long 			       &sc->aac_io_lock,	/* lockfuncarg */
1469a6d35632SScott Long 			       &sc->aac_buffer_dmat)) {
1470a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1471a6d35632SScott Long 		goto out;
1472a6d35632SScott Long 	}
1473a6d35632SScott Long 
1474a6d35632SScott Long 	/*
1475a6d35632SScott Long 	 * Create DMA tag for mapping FIBs into controller-addressable space..
1476a6d35632SScott Long 	 */
1477a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1478a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1479a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1480a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1481a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
1482a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1483a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1484a6d35632SScott Long 			       AAC_FIB_COUNT *
1485a6d35632SScott Long 			       sizeof(struct aac_fib),  /* maxsize */
1486a6d35632SScott Long 			       1,			/* nsegments */
1487a6d35632SScott Long 			       AAC_FIB_COUNT *
1488a6d35632SScott Long 			       sizeof(struct aac_fib),	/* maxsegsize */
14891248408dSScott Long 			       0,			/* flags */
1490f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
1491a6d35632SScott Long 			       &sc->aac_fib_dmat)) {
1492a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1493a6d35632SScott Long 		goto out;
1494a6d35632SScott Long 	}
1495a6d35632SScott Long 
149635863739SMike Smith 	/*
149735863739SMike Smith 	 * Create DMA tag for the common structure and allocate it.
149835863739SMike Smith 	 */
149935863739SMike Smith 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1500c6eafcf2SScott Long 			       1, 0,			/* algnmnt, boundary */
1501a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1502a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1503a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
150435863739SMike Smith 			       BUS_SPACE_MAXADDR, 	/* highaddr */
150535863739SMike Smith 			       NULL, NULL, 		/* filter, filterarg */
1506ffb37f33SScott Long 			       8192 + sizeof(struct aac_common), /* maxsize */
1507914da7d0SScott Long 			       1,			/* nsegments */
150835863739SMike Smith 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
15091248408dSScott Long 			       0,			/* flags */
1510f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
151135863739SMike Smith 			       &sc->aac_common_dmat)) {
1512914da7d0SScott Long 		device_printf(sc->aac_dev,
1513914da7d0SScott Long 			      "can't allocate common structure DMA tag\n");
1514a6d35632SScott Long 		goto out;
151535863739SMike Smith 	}
1516c6eafcf2SScott Long 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1517c6eafcf2SScott Long 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
151835863739SMike Smith 		device_printf(sc->aac_dev, "can't allocate common structure\n");
1519a6d35632SScott Long 		goto out;
152035863739SMike Smith 	}
1521ffb37f33SScott Long 
1522ffb37f33SScott Long 	/*
1523ffb37f33SScott Long 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1524ffb37f33SScott Long 	 * below address 8192 in physical memory.
1525ffb37f33SScott Long 	 * XXX If the padding is not needed, can it be put to use instead
1526ffb37f33SScott Long 	 * of ignored?
1527ffb37f33SScott Long 	 */
1528cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1529ffb37f33SScott Long 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1530ffb37f33SScott Long 			aac_common_map, sc, 0);
1531ffb37f33SScott Long 
1532ffb37f33SScott Long 	if (sc->aac_common_busaddr < 8192) {
1533eec256deSAlexander Kabaev 		sc->aac_common = (struct aac_common *)
1534eec256deSAlexander Kabaev 		    ((uint8_t *)sc->aac_common + 8192);
1535ffb37f33SScott Long 		sc->aac_common_busaddr += 8192;
1536ffb37f33SScott Long 	}
153735863739SMike Smith 	bzero(sc->aac_common, sizeof(*sc->aac_common));
153835863739SMike Smith 
1539ffb37f33SScott Long 	/* Allocate some FIBs and associated command structs */
1540ffb37f33SScott Long 	TAILQ_INIT(&sc->aac_fibmap_tqh);
1541ffb37f33SScott Long 	sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
15428480cc63SScott Long 				  M_AACBUF, M_WAITOK|M_ZERO);
15438480cc63SScott Long 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1544ffb37f33SScott Long 		if (aac_alloc_commands(sc) != 0)
1545ffb37f33SScott Long 			break;
1546ffb37f33SScott Long 	}
1547ffb37f33SScott Long 	if (sc->total_fibs == 0)
1548a6d35632SScott Long 		goto out;
1549ffb37f33SScott Long 
155035863739SMike Smith 	/*
1551914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1552914da7d0SScott Long 	 * physical location of various important shared data structures.
155335863739SMike Smith 	 */
155435863739SMike Smith 	ip = &sc->aac_common->ac_init;
155535863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1556f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
155735863739SMike Smith 
1558c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1559c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1560149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
156135863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
156235863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
156335863739SMike Smith 
1564c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1565c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
156635863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
156735863739SMike Smith 
15684b00f859SScott Long 	/*
15694b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
15704b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
15714b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
15724b00f859SScott Long 	 * Round up since the granularity is so high.
15734b00f859SScott Long 	 */
1574f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
15754b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
15764b00f859SScott Long 		ip->HostPhysMemPages =
15774b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1578204c0befSScott Long 	}
157935863739SMike Smith 	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
158035863739SMike Smith 
158135863739SMike Smith 	/*
1582c6eafcf2SScott Long 	 * Initialise FIB queues.  Note that it appears that the layout of the
1583c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1584c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
158535863739SMike Smith 	 *
158635863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1587914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1588914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1589914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1590914da7d0SScott Long 	 * does.
159135863739SMike Smith 	 *
1592914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1593914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1594914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1595914da7d0SScott Long 	 * virtue of a table.
159635863739SMike Smith 	 */
1597b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
15980bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
15990bcbebd6SScott Long 	sc->aac_queues =
16000bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1601b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
160235863739SMike Smith 
1603c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1604c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1605c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1606c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1607c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1608c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1609c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1610c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1611c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1612c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1613c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1614c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1615c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1616c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1617c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1618c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1619c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1620c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1621c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1622c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1623c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1624c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1625c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1626c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1627c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1628c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1629c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1630c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1631c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1632c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1633c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1634c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1635c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1636c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1637c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1638c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1639c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1640c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1641c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1642c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1643c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1644c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1645c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1646c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1647c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1648c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1649c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1650c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
165135863739SMike Smith 
165235863739SMike Smith 	/*
165335863739SMike Smith 	 * Do controller-type-specific initialisation
165435863739SMike Smith 	 */
165535863739SMike Smith 	switch (sc->aac_hwif) {
165635863739SMike Smith 	case AAC_HWIF_I960RX:
165735863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
165835863739SMike Smith 		break;
16594afedc31SScott Long 	case AAC_HWIF_RKT:
16604afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
16614afedc31SScott Long 		break;
16624afedc31SScott Long 	default:
16634afedc31SScott Long 		break;
166435863739SMike Smith 	}
166535863739SMike Smith 
166635863739SMike Smith 	/*
166735863739SMike Smith 	 * Give the init structure to the controller.
166835863739SMike Smith 	 */
166935863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1670914da7d0SScott Long 			     sc->aac_common_busaddr +
1671914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1672914da7d0SScott Long 			     NULL)) {
1673914da7d0SScott Long 		device_printf(sc->aac_dev,
1674914da7d0SScott Long 			      "error establishing init structure\n");
1675a6d35632SScott Long 		error = EIO;
1676a6d35632SScott Long 		goto out;
167735863739SMike Smith 	}
167835863739SMike Smith 
1679a6d35632SScott Long 	error = 0;
1680a6d35632SScott Long out:
1681a6d35632SScott Long 	return(error);
168235863739SMike Smith }
168335863739SMike Smith 
1684914da7d0SScott Long /*
168535863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
168635863739SMike Smith  */
168735863739SMike Smith static int
168835863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
168935863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
169035863739SMike Smith 		 u_int32_t *sp)
169135863739SMike Smith {
169235863739SMike Smith 	time_t then;
169335863739SMike Smith 	u_int32_t status;
169435863739SMike Smith 
169535863739SMike Smith 	debug_called(3);
169635863739SMike Smith 
169735863739SMike Smith 	/* populate the mailbox */
169835863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
169935863739SMike Smith 
170035863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
170135863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
170235863739SMike Smith 
170335863739SMike Smith 	/* then set it to signal the adapter */
170435863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
170535863739SMike Smith 
170635863739SMike Smith 	/* spin waiting for the command to complete */
170735863739SMike Smith 	then = time_second;
170835863739SMike Smith 	do {
170935863739SMike Smith 		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1710a6d35632SScott Long 			debug(1, "timed out");
171135863739SMike Smith 			return(EIO);
171235863739SMike Smith 		}
171335863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
171435863739SMike Smith 
171535863739SMike Smith 	/* clear the completion flag */
171635863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
171735863739SMike Smith 
171835863739SMike Smith 	/* get the command status */
1719a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
172035863739SMike Smith 	if (sp != NULL)
172135863739SMike Smith 		*sp = status;
17220b94a66eSMike Smith 	return(0);
172335863739SMike Smith }
172435863739SMike Smith 
1725cbfd045bSScott Long int
172635863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
1727cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
172835863739SMike Smith {
172935863739SMike Smith 	debug_called(3);
173035863739SMike Smith 
173135863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
173235863739SMike Smith 		return(EINVAL);
173335863739SMike Smith 
173435863739SMike Smith 	/*
173535863739SMike Smith 	 * Set up the sync FIB
173635863739SMike Smith 	 */
1737914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
1738914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
1739c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
174035863739SMike Smith 	fib->Header.XferState |= xferstate;
174135863739SMike Smith 	fib->Header.Command = command;
174235863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
174335863739SMike Smith 	fib->Header.Size = sizeof(struct aac_fib) + datasize;
174435863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
1745b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
1746c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
1747914da7d0SScott Long 					 offsetof(struct aac_common,
1748914da7d0SScott Long 						  ac_sync_fib);
174935863739SMike Smith 
175035863739SMike Smith 	/*
175135863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
175235863739SMike Smith 	 */
1753914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
1754914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
175535863739SMike Smith 		debug(2, "IO error");
175635863739SMike Smith 		return(EIO);
175735863739SMike Smith 	}
175835863739SMike Smith 
175935863739SMike Smith 	return (0);
176035863739SMike Smith }
176135863739SMike Smith 
1762914da7d0SScott Long /*
176335863739SMike Smith  * Adapter-space FIB queue manipulation
176435863739SMike Smith  *
176535863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
176635863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
176735863739SMike Smith  */
176835863739SMike Smith static struct {
176935863739SMike Smith 	int		size;
177035863739SMike Smith 	int		notify;
177135863739SMike Smith } aac_qinfo[] = {
177235863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
177335863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
177435863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
177535863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
177635863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
177735863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
177835863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
177935863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
178035863739SMike Smith };
178135863739SMike Smith 
178235863739SMike Smith /*
1783c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
1784c6eafcf2SScott Long  * EBUSY if the queue is full.
178535863739SMike Smith  *
17860b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
1787914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
1788914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
1789c6eafcf2SScott Long  *	 separate queue/notify interface).
179035863739SMike Smith  */
179135863739SMike Smith static int
1792f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
179335863739SMike Smith {
179435863739SMike Smith 	u_int32_t pi, ci;
17959e2e96d8SScott Long 	int error;
1796f6c4dd3fSScott Long 	u_int32_t fib_size;
1797f6c4dd3fSScott Long 	u_int32_t fib_addr;
1798f6c4dd3fSScott Long 
179936e0bf6eSScott Long 	debug_called(3);
180036e0bf6eSScott Long 
1801f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
1802f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
180335863739SMike Smith 
180435863739SMike Smith 	/* get the producer/consumer indices */
180535863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
180635863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
180735863739SMike Smith 
180835863739SMike Smith 	/* wrap the queue? */
180935863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
181035863739SMike Smith 		pi = 0;
181135863739SMike Smith 
181235863739SMike Smith 	/* check for queue full */
181335863739SMike Smith 	if ((pi + 1) == ci) {
181435863739SMike Smith 		error = EBUSY;
181535863739SMike Smith 		goto out;
181635863739SMike Smith 	}
181735863739SMike Smith 
1818614c22b2SScott Long 	/*
1819614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
1820614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
1821614c22b2SScott Long 	 */
1822614c22b2SScott Long 	aac_enqueue_busy(cm);
1823614c22b2SScott Long 
182435863739SMike Smith 	/* populate queue entry */
182535863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
182635863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
182735863739SMike Smith 
182835863739SMike Smith 	/* update producer index */
182935863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
183035863739SMike Smith 
183135863739SMike Smith 	/* notify the adapter if we know how */
183235863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
183335863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
183435863739SMike Smith 
183535863739SMike Smith 	error = 0;
183635863739SMike Smith 
183735863739SMike Smith out:
183835863739SMike Smith 	return(error);
183935863739SMike Smith }
184035863739SMike Smith 
184135863739SMike Smith /*
184236e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
184336e0bf6eSScott Long  * success or ENOENT if the queue is empty.
184435863739SMike Smith  */
184535863739SMike Smith static int
1846c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1847c6eafcf2SScott Long 		struct aac_fib **fib_addr)
184835863739SMike Smith {
184935863739SMike Smith 	u_int32_t pi, ci;
1850149af931SScott Long 	u_int32_t fib_index;
18519e2e96d8SScott Long 	int error;
1852f6c4dd3fSScott Long 	int notify;
185335863739SMike Smith 
185435863739SMike Smith 	debug_called(3);
185535863739SMike Smith 
185635863739SMike Smith 	/* get the producer/consumer indices */
185735863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
185835863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
185935863739SMike Smith 
186035863739SMike Smith 	/* check for queue empty */
186135863739SMike Smith 	if (ci == pi) {
186235863739SMike Smith 		error = ENOENT;
186335863739SMike Smith 		goto out;
186435863739SMike Smith 	}
186535863739SMike Smith 
18667753acd2SScott Long 	/* wrap the pi so the following test works */
18677753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
18687753acd2SScott Long 		pi = 0;
18697753acd2SScott Long 
1870f6c4dd3fSScott Long 	notify = 0;
1871f6c4dd3fSScott Long 	if (ci == pi + 1)
1872f6c4dd3fSScott Long 		notify++;
1873f6c4dd3fSScott Long 
187435863739SMike Smith 	/* wrap the queue? */
187535863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
187635863739SMike Smith 		ci = 0;
187735863739SMike Smith 
187835863739SMike Smith 	/* fetch the entry */
187935863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
1880149af931SScott Long 
1881149af931SScott Long 	switch (queue) {
1882149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
1883149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
1884149af931SScott Long 		/*
1885149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
1886149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
1887149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
1888149af931SScott Long 		 * Therefore, we have to convert it to an index.
1889149af931SScott Long 		 */
1890149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
1891149af931SScott Long 			sizeof(struct aac_fib);
1892149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
1893149af931SScott Long 		break;
1894149af931SScott Long 
1895149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
1896149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
1897149af931SScott Long 	{
1898149af931SScott Long 		struct aac_command *cm;
1899149af931SScott Long 
1900149af931SScott Long 		/*
1901149af931SScott Long 		 * As above, an index is used instead of an actual address.
1902149af931SScott Long 		 * Gotta shift the index to account for the fast response
1903149af931SScott Long 		 * bit.  No other correction is needed since this value was
1904149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
1905149af931SScott Long 		 * field.
1906149af931SScott Long 		 */
1907149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
1908149af931SScott Long 		cm = sc->aac_commands + (fib_index >> 1);
1909149af931SScott Long 		*fib_addr = cm->cm_fib;
191035863739SMike Smith 
1911f30ac74cSScott Long 		/*
1912f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
1913149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
1914f30ac74cSScott Long 		 */
1915149af931SScott Long 		if (fib_index & 0x01) {
1916f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
1917f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
1918f30ac74cSScott Long 		}
1919149af931SScott Long 		break;
1920149af931SScott Long 	}
1921149af931SScott Long 	default:
1922149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
1923149af931SScott Long 		break;
1924149af931SScott Long 	}
1925149af931SScott Long 
192635863739SMike Smith 	/* update consumer index */
192735863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
192835863739SMike Smith 
192935863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
1930f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
193135863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
193235863739SMike Smith 	error = 0;
193335863739SMike Smith 
193435863739SMike Smith out:
193535863739SMike Smith 	return(error);
193635863739SMike Smith }
193735863739SMike Smith 
1938914da7d0SScott Long /*
193936e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
194036e0bf6eSScott Long  */
194136e0bf6eSScott Long static int
194236e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
194336e0bf6eSScott Long {
194436e0bf6eSScott Long 	u_int32_t pi, ci;
19459e2e96d8SScott Long 	int error;
194636e0bf6eSScott Long 	u_int32_t fib_size;
194736e0bf6eSScott Long 	u_int32_t fib_addr;
194836e0bf6eSScott Long 
194936e0bf6eSScott Long 	debug_called(1);
195036e0bf6eSScott Long 
195136e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
195236e0bf6eSScott Long 	fib_size = fib->Header.Size;
195336e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
195436e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
195536e0bf6eSScott Long 
195636e0bf6eSScott Long 	/* get the producer/consumer indices */
195736e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
195836e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
195936e0bf6eSScott Long 
196036e0bf6eSScott Long 	/* wrap the queue? */
196136e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
196236e0bf6eSScott Long 		pi = 0;
196336e0bf6eSScott Long 
196436e0bf6eSScott Long 	/* check for queue full */
196536e0bf6eSScott Long 	if ((pi + 1) == ci) {
196636e0bf6eSScott Long 		error = EBUSY;
196736e0bf6eSScott Long 		goto out;
196836e0bf6eSScott Long 	}
196936e0bf6eSScott Long 
197036e0bf6eSScott Long 	/* populate queue entry */
197136e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
197236e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
197336e0bf6eSScott Long 
197436e0bf6eSScott Long 	/* update producer index */
197536e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
197636e0bf6eSScott Long 
197736e0bf6eSScott Long 	/* notify the adapter if we know how */
197836e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
197936e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
198036e0bf6eSScott Long 
198136e0bf6eSScott Long 	error = 0;
198236e0bf6eSScott Long 
198336e0bf6eSScott Long out:
198436e0bf6eSScott Long 	return(error);
198536e0bf6eSScott Long }
198636e0bf6eSScott Long 
1987914da7d0SScott Long /*
19880b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
19890b94a66eSMike Smith  * and complain about them.
19900b94a66eSMike Smith  */
19910b94a66eSMike Smith static void
19920b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
19930b94a66eSMike Smith {
19940b94a66eSMike Smith 	struct aac_command *cm;
19950b94a66eSMike Smith 	time_t deadline;
199615c37be0SScott Long 	int timedout, code;
19970b94a66eSMike Smith 
1998f6c4dd3fSScott Long 	/*
199970545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2000914da7d0SScott Long 	 * only.
2001914da7d0SScott Long 	 */
200215c37be0SScott Long 	timedout = 0;
20030b94a66eSMike Smith 	deadline = time_second - AAC_CMD_TIMEOUT;
20040b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2005f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2006f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
20070b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2008914da7d0SScott Long 			device_printf(sc->aac_dev,
2009914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2010f6c4dd3fSScott Long 				      cm, (int)(time_second-cm->cm_timestamp));
20110b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
201215c37be0SScott Long 			timedout++;
20130b94a66eSMike Smith 		}
20140b94a66eSMike Smith 	}
20150b94a66eSMike Smith 
201615c37be0SScott Long 	if (timedout) {
201715c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
201815c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
201915c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
202015c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
202115c37be0SScott Long 		}
202215c37be0SScott Long 	}
20230b94a66eSMike Smith 	return;
20240b94a66eSMike Smith }
20250b94a66eSMike Smith 
2026914da7d0SScott Long /*
2027914da7d0SScott Long  * Interface Function Vectors
2028914da7d0SScott Long  */
202935863739SMike Smith 
2030914da7d0SScott Long /*
203135863739SMike Smith  * Read the current firmware status word.
203235863739SMike Smith  */
203335863739SMike Smith static int
203435863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
203535863739SMike Smith {
203635863739SMike Smith 	debug_called(3);
203735863739SMike Smith 
203835863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
203935863739SMike Smith }
204035863739SMike Smith 
204135863739SMike Smith static int
204235863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
204335863739SMike Smith {
204435863739SMike Smith 	debug_called(3);
204535863739SMike Smith 
204635863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
204735863739SMike Smith }
204835863739SMike Smith 
2049b3457b51SScott Long static int
2050b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2051b3457b51SScott Long {
2052b3457b51SScott Long 	int val;
2053b3457b51SScott Long 
2054b3457b51SScott Long 	debug_called(3);
2055b3457b51SScott Long 
2056b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2057b3457b51SScott Long 	return (val);
2058b3457b51SScott Long }
2059b3457b51SScott Long 
20604afedc31SScott Long static int
20614afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
20624afedc31SScott Long {
20634afedc31SScott Long 	debug_called(3);
20644afedc31SScott Long 
20654afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
20664afedc31SScott Long }
20674afedc31SScott Long 
2068914da7d0SScott Long /*
206935863739SMike Smith  * Notify the controller of a change in a given queue
207035863739SMike Smith  */
207135863739SMike Smith 
207235863739SMike Smith static void
207335863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
207435863739SMike Smith {
207535863739SMike Smith 	debug_called(3);
207635863739SMike Smith 
207735863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
207835863739SMike Smith }
207935863739SMike Smith 
208035863739SMike Smith static void
208135863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
208235863739SMike Smith {
208335863739SMike Smith 	debug_called(3);
208435863739SMike Smith 
208535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
208635863739SMike Smith }
208735863739SMike Smith 
2088b3457b51SScott Long static void
2089b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2090b3457b51SScott Long {
2091b3457b51SScott Long 	debug_called(3);
2092b3457b51SScott Long 
2093b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2094b3457b51SScott Long 	AAC_FA_HACK(sc);
2095b3457b51SScott Long }
2096b3457b51SScott Long 
20974afedc31SScott Long static void
20984afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
20994afedc31SScott Long {
21004afedc31SScott Long 	debug_called(3);
21014afedc31SScott Long 
21024afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
21034afedc31SScott Long }
21044afedc31SScott Long 
2105914da7d0SScott Long /*
210635863739SMike Smith  * Get the interrupt reason bits
210735863739SMike Smith  */
210835863739SMike Smith static int
210935863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
211035863739SMike Smith {
211135863739SMike Smith 	debug_called(3);
211235863739SMike Smith 
211335863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
211435863739SMike Smith }
211535863739SMike Smith 
211635863739SMike Smith static int
211735863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
211835863739SMike Smith {
211935863739SMike Smith 	debug_called(3);
212035863739SMike Smith 
212135863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
212235863739SMike Smith }
212335863739SMike Smith 
2124b3457b51SScott Long static int
2125b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2126b3457b51SScott Long {
2127b3457b51SScott Long 	int val;
2128b3457b51SScott Long 
2129b3457b51SScott Long 	debug_called(3);
2130b3457b51SScott Long 
2131b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2132b3457b51SScott Long 	return (val);
2133b3457b51SScott Long }
2134b3457b51SScott Long 
21354afedc31SScott Long static int
21364afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
21374afedc31SScott Long {
21384afedc31SScott Long 	debug_called(3);
21394afedc31SScott Long 
21404afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
21414afedc31SScott Long }
21424afedc31SScott Long 
2143914da7d0SScott Long /*
214435863739SMike Smith  * Clear some interrupt reason bits
214535863739SMike Smith  */
214635863739SMike Smith static void
214735863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
214835863739SMike Smith {
214935863739SMike Smith 	debug_called(3);
215035863739SMike Smith 
215135863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
215235863739SMike Smith }
215335863739SMike Smith 
215435863739SMike Smith static void
215535863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
215635863739SMike Smith {
215735863739SMike Smith 	debug_called(3);
215835863739SMike Smith 
215935863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
216035863739SMike Smith }
216135863739SMike Smith 
2162b3457b51SScott Long static void
2163b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2164b3457b51SScott Long {
2165b3457b51SScott Long 	debug_called(3);
2166b3457b51SScott Long 
2167b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2168b3457b51SScott Long 	AAC_FA_HACK(sc);
2169b3457b51SScott Long }
2170b3457b51SScott Long 
21714afedc31SScott Long static void
21724afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
21734afedc31SScott Long {
21744afedc31SScott Long 	debug_called(3);
21754afedc31SScott Long 
21764afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
21774afedc31SScott Long }
21784afedc31SScott Long 
2179914da7d0SScott Long /*
218035863739SMike Smith  * Populate the mailbox and set the command word
218135863739SMike Smith  */
218235863739SMike Smith static void
218335863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
218435863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
218535863739SMike Smith {
218635863739SMike Smith 	debug_called(4);
218735863739SMike Smith 
218835863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
218935863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
219035863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
219135863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
219235863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
219335863739SMike Smith }
219435863739SMike Smith 
219535863739SMike Smith static void
219635863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
219735863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
219835863739SMike Smith {
219935863739SMike Smith 	debug_called(4);
220035863739SMike Smith 
220135863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
220235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
220335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
220435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
220535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
220635863739SMike Smith }
220735863739SMike Smith 
2208b3457b51SScott Long static void
2209b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2210b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2211b3457b51SScott Long {
2212b3457b51SScott Long 	debug_called(4);
2213b3457b51SScott Long 
2214b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2215b3457b51SScott Long 	AAC_FA_HACK(sc);
2216b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2217b3457b51SScott Long 	AAC_FA_HACK(sc);
2218b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2219b3457b51SScott Long 	AAC_FA_HACK(sc);
2220b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2221b3457b51SScott Long 	AAC_FA_HACK(sc);
2222b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2223b3457b51SScott Long 	AAC_FA_HACK(sc);
2224b3457b51SScott Long }
2225b3457b51SScott Long 
22264afedc31SScott Long static void
22274afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
22284afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
22294afedc31SScott Long {
22304afedc31SScott Long 	debug_called(4);
22314afedc31SScott Long 
22324afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
22334afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
22344afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
22354afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
22364afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
22374afedc31SScott Long }
22384afedc31SScott Long 
2239914da7d0SScott Long /*
224035863739SMike Smith  * Fetch the immediate command status word
224135863739SMike Smith  */
224235863739SMike Smith static int
2243a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
224435863739SMike Smith {
224535863739SMike Smith 	debug_called(4);
224635863739SMike Smith 
2247a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
224835863739SMike Smith }
224935863739SMike Smith 
225035863739SMike Smith static int
2251a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
225235863739SMike Smith {
225335863739SMike Smith 	debug_called(4);
225435863739SMike Smith 
2255a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
225635863739SMike Smith }
225735863739SMike Smith 
2258b3457b51SScott Long static int
2259a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2260b3457b51SScott Long {
2261b3457b51SScott Long 	int val;
2262b3457b51SScott Long 
2263b3457b51SScott Long 	debug_called(4);
2264b3457b51SScott Long 
2265a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2266b3457b51SScott Long 	return (val);
2267b3457b51SScott Long }
2268b3457b51SScott Long 
22694afedc31SScott Long static int
22704afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
22714afedc31SScott Long {
22724afedc31SScott Long 	debug_called(4);
22734afedc31SScott Long 
22744afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
22754afedc31SScott Long }
22764afedc31SScott Long 
2277914da7d0SScott Long /*
227835863739SMike Smith  * Set/clear interrupt masks
227935863739SMike Smith  */
228035863739SMike Smith static void
228135863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
228235863739SMike Smith {
228335863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
228435863739SMike Smith 
228535863739SMike Smith 	if (enable) {
228635863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
228735863739SMike Smith 	} else {
228835863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
228935863739SMike Smith 	}
229035863739SMike Smith }
229135863739SMike Smith 
229235863739SMike Smith static void
229335863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
229435863739SMike Smith {
229535863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
229635863739SMike Smith 
229735863739SMike Smith 	if (enable) {
229835863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
229935863739SMike Smith 	} else {
230035863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
230135863739SMike Smith 	}
230235863739SMike Smith }
230335863739SMike Smith 
2304b3457b51SScott Long static void
2305b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2306b3457b51SScott Long {
2307b3457b51SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
2308b3457b51SScott Long 
2309b3457b51SScott Long 	if (enable) {
2310b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2311b3457b51SScott Long 		AAC_FA_HACK(sc);
2312b3457b51SScott Long 	} else {
2313b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2314b3457b51SScott Long 		AAC_FA_HACK(sc);
2315b3457b51SScott Long 	}
2316b3457b51SScott Long }
2317b3457b51SScott Long 
23184afedc31SScott Long static void
23194afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
23204afedc31SScott Long {
23214afedc31SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
23224afedc31SScott Long 
23234afedc31SScott Long 	if (enable) {
23244afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
23254afedc31SScott Long 	} else {
23264afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
23274afedc31SScott Long 	}
23284afedc31SScott Long }
23294afedc31SScott Long 
2330914da7d0SScott Long /*
2331914da7d0SScott Long  * Debugging and Diagnostics
2332914da7d0SScott Long  */
233335863739SMike Smith 
2334914da7d0SScott Long /*
233535863739SMike Smith  * Print some information about the controller.
233635863739SMike Smith  */
233735863739SMike Smith static void
233835863739SMike Smith aac_describe_controller(struct aac_softc *sc)
233935863739SMike Smith {
2340cbfd045bSScott Long 	struct aac_fib *fib;
234135863739SMike Smith 	struct aac_adapter_info	*info;
234235863739SMike Smith 
234335863739SMike Smith 	debug_called(2);
234435863739SMike Smith 
234503b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2346cbfd045bSScott Long 
2347cbfd045bSScott Long 	fib->data[0] = 0;
2348cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
234935863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2350fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
235135863739SMike Smith 		return;
235235863739SMike Smith 	}
235335863739SMike Smith 
2354bd971c49SScott Long 	/* save the kernel revision structure for later use */
2355bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2356bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2357bd971c49SScott Long 
2358bd971c49SScott Long 	if (bootverbose) {
235936e0bf6eSScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
2360c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
236136e0bf6eSScott Long 		    info->ClockSpeed, info->BufferMem / (1024 * 1024),
2362914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2363914da7d0SScott Long 		    info->batteryPlatform));
236435863739SMike Smith 
2365bd971c49SScott Long 		device_printf(sc->aac_dev,
2366bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
236735863739SMike Smith 		    info->KernelRevision.external.comp.major,
236835863739SMike Smith 		    info->KernelRevision.external.comp.minor,
236935863739SMike Smith 		    info->KernelRevision.external.comp.dash,
237036e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
237136e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2372fe3cb0e1SScott Long 
2373a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2374a6d35632SScott Long 			      sc->supported_options,
2375a6d35632SScott Long 			      "\20"
2376a6d35632SScott Long 			      "\1SNAPSHOT"
2377a6d35632SScott Long 			      "\2CLUSTERS"
2378a6d35632SScott Long 			      "\3WCACHE"
2379a6d35632SScott Long 			      "\4DATA64"
2380a6d35632SScott Long 			      "\5HOSTTIME"
2381a6d35632SScott Long 			      "\6RAID50"
2382a6d35632SScott Long 			      "\7WINDOW4GB"
2383a6d35632SScott Long 			      "\10SCSIUPGD"
2384a6d35632SScott Long 			      "\11SOFTERR"
2385a6d35632SScott Long 			      "\12NORECOND"
2386a6d35632SScott Long 			      "\13SGMAP64"
2387a6d35632SScott Long 			      "\14ALARM"
2388a6d35632SScott Long 			      "\15NONDASD");
2389a6d35632SScott Long 	}
2390bd971c49SScott Long 	aac_release_sync_fib(sc);
239135863739SMike Smith }
239235863739SMike Smith 
2393914da7d0SScott Long /*
239435863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
239535863739SMike Smith  * same.
239635863739SMike Smith  */
239735863739SMike Smith static char *
239835863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
239935863739SMike Smith {
240035863739SMike Smith 	int i;
240135863739SMike Smith 
240235863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
240335863739SMike Smith 		if (table[i].code == code)
240435863739SMike Smith 			return(table[i].string);
240535863739SMike Smith 	return(table[i + 1].string);
240635863739SMike Smith }
240735863739SMike Smith 
2408914da7d0SScott Long /*
2409914da7d0SScott Long  * Management Interface
2410914da7d0SScott Long  */
241135863739SMike Smith 
241235863739SMike Smith static int
241389c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
241435863739SMike Smith {
2415914da7d0SScott Long 	struct aac_softc *sc;
241635863739SMike Smith 
241735863739SMike Smith 	debug_called(2);
241835863739SMike Smith 
2419914da7d0SScott Long 	sc = dev->si_drv1;
2420914da7d0SScott Long 
242135863739SMike Smith 	/* Check to make sure the device isn't already open */
242235863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN) {
242335863739SMike Smith 		return EBUSY;
242435863739SMike Smith 	}
242535863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
242635863739SMike Smith 
242735863739SMike Smith 	return 0;
242835863739SMike Smith }
242935863739SMike Smith 
243035863739SMike Smith static int
243189c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
243235863739SMike Smith {
2433914da7d0SScott Long 	struct aac_softc *sc;
243435863739SMike Smith 
243535863739SMike Smith 	debug_called(2);
243635863739SMike Smith 
2437914da7d0SScott Long 	sc = dev->si_drv1;
2438914da7d0SScott Long 
243935863739SMike Smith 	/* Mark this unit as no longer open  */
244035863739SMike Smith 	sc->aac_state &= ~AAC_STATE_OPEN;
244135863739SMike Smith 
244235863739SMike Smith 	return 0;
244335863739SMike Smith }
244435863739SMike Smith 
244535863739SMike Smith static int
244689c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
244735863739SMike Smith {
2448914da7d0SScott Long 	union aac_statrequest *as;
2449914da7d0SScott Long 	struct aac_softc *sc;
24500b94a66eSMike Smith 	int error = 0;
2451b88ffdc8SScott Long 	uint32_t cookie;
245235863739SMike Smith 
245335863739SMike Smith 	debug_called(2);
245435863739SMike Smith 
2455914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2456914da7d0SScott Long 	sc = dev->si_drv1;
2457914da7d0SScott Long 
245835863739SMike Smith 	switch (cmd) {
24590b94a66eSMike Smith 	case AACIO_STATS:
24600b94a66eSMike Smith 		switch (as->as_item) {
24610b94a66eSMike Smith 		case AACQ_FREE:
24620b94a66eSMike Smith 		case AACQ_BIO:
24630b94a66eSMike Smith 		case AACQ_READY:
24640b94a66eSMike Smith 		case AACQ_BUSY:
2465c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2466c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
24670b94a66eSMike Smith 			break;
24680b94a66eSMike Smith 		default:
24690b94a66eSMike Smith 			error = ENOENT;
24700b94a66eSMike Smith 			break;
24710b94a66eSMike Smith 		}
24720b94a66eSMike Smith 	break;
24730b94a66eSMike Smith 
247435863739SMike Smith 	case FSACTL_SENDFIB:
2475fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2476fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
24770b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
247835863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
247935863739SMike Smith 		break;
248035863739SMike Smith 	case FSACTL_AIF_THREAD:
2481fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
24820b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
248335863739SMike Smith 		error = EINVAL;
248435863739SMike Smith 		break;
248535863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2486fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2487fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
24880b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
248935863739SMike Smith 		/*
249035863739SMike Smith 		 * Pass the caller out an AdapterFibContext.
249135863739SMike Smith 		 *
249235863739SMike Smith 		 * Note that because we only support one opener, we
249335863739SMike Smith 		 * basically ignore this.  Set the caller's context to a magic
249435863739SMike Smith 		 * number just in case.
24950b94a66eSMike Smith 		 *
24960b94a66eSMike Smith 		 * The Linux code hands the driver a pointer into kernel space,
24970b94a66eSMike Smith 		 * and then trusts it when the caller hands it back.  Aiee!
2498914da7d0SScott Long 		 * Here, we give it the proc pointer of the per-adapter aif
2499914da7d0SScott Long 		 * thread. It's only used as a sanity check in other calls.
250035863739SMike Smith 		 */
2501b88ffdc8SScott Long 		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2502b88ffdc8SScott Long 		error = copyout(&cookie, arg, sizeof(cookie));
250335863739SMike Smith 		break;
250435863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2505fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2506fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
25070b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2508fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
250935863739SMike Smith 		break;
251035863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2511fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
25120b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
251335863739SMike Smith 		/* don't do anything here */
251435863739SMike Smith 		break;
251535863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2516fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2517fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
25180b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2519fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
252035863739SMike Smith 		break;
252136e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
252236e0bf6eSScott Long 		arg = *(caddr_t*)arg;
252336e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
252436e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
252536e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
252636e0bf6eSScott Long 			break;
252736e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
252836e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2529914da7d0SScott Long 		/*
2530914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2531914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2532914da7d0SScott Long 		 * controller
2533914da7d0SScott Long 		 */
253436e0bf6eSScott Long 		error = 0;
253536e0bf6eSScott Long 		break;
253635863739SMike Smith 	default:
2537b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
253835863739SMike Smith 		error = EINVAL;
253935863739SMike Smith 		break;
254035863739SMike Smith 	}
254135863739SMike Smith 	return(error);
254235863739SMike Smith }
254335863739SMike Smith 
2544b3457b51SScott Long static int
254589c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2546b3457b51SScott Long {
2547b3457b51SScott Long 	struct aac_softc *sc;
2548b3457b51SScott Long 	int revents;
2549b3457b51SScott Long 
2550b3457b51SScott Long 	sc = dev->si_drv1;
2551b3457b51SScott Long 	revents = 0;
2552b3457b51SScott Long 
2553bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2554b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2555b3457b51SScott Long 		if (sc->aac_aifq_tail != sc->aac_aifq_head)
2556b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2557b3457b51SScott Long 	}
2558bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2559b3457b51SScott Long 
2560b3457b51SScott Long 	if (revents == 0) {
2561b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2562b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2563b3457b51SScott Long 	}
2564b3457b51SScott Long 
2565b3457b51SScott Long 	return (revents);
2566b3457b51SScott Long }
2567b3457b51SScott Long 
2568914da7d0SScott Long /*
256935863739SMike Smith  * Send a FIB supplied from userspace
257035863739SMike Smith  */
257135863739SMike Smith static int
257235863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
257335863739SMike Smith {
257435863739SMike Smith 	struct aac_command *cm;
257535863739SMike Smith 	int size, error;
257635863739SMike Smith 
257735863739SMike Smith 	debug_called(2);
257835863739SMike Smith 
257935863739SMike Smith 	cm = NULL;
258035863739SMike Smith 
258135863739SMike Smith 	/*
258235863739SMike Smith 	 * Get a command
258335863739SMike Smith 	 */
2584bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
258535863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
258635863739SMike Smith 		error = EBUSY;
258735863739SMike Smith 		goto out;
258835863739SMike Smith 	}
258935863739SMike Smith 
259035863739SMike Smith 	/*
259135863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
259235863739SMike Smith 	 */
2593914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
2594914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
259535863739SMike Smith 		goto out;
259635863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
259735863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
2598b88ffdc8SScott Long 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
2599914da7d0SScott Long 			      size, sizeof(struct aac_fib));
260035863739SMike Smith 		size = sizeof(struct aac_fib);
260135863739SMike Smith 	}
260235863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
260335863739SMike Smith 		goto out;
260435863739SMike Smith 	cm->cm_fib->Header.Size = size;
2605f6c4dd3fSScott Long 	cm->cm_timestamp = time_second;
260635863739SMike Smith 
260735863739SMike Smith 	/*
260835863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
260935863739SMike Smith 	 */
2610d8a0a473SScott Long 	if ((error = aac_wait_command(cm)) != 0) {
261170545d1aSScott Long 		device_printf(sc->aac_dev,
261270545d1aSScott Long 			      "aac_wait_command return %d\n", error);
261335863739SMike Smith 		goto out;
2614b3457b51SScott Long 	}
261535863739SMike Smith 
261635863739SMike Smith 	/*
261735863739SMike Smith 	 * Copy the FIB and data back out to the caller.
261835863739SMike Smith 	 */
261935863739SMike Smith 	size = cm->cm_fib->Header.Size;
262035863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
2621b88ffdc8SScott Long 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
2622914da7d0SScott Long 			      size, sizeof(struct aac_fib));
262335863739SMike Smith 		size = sizeof(struct aac_fib);
262435863739SMike Smith 	}
262535863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
262635863739SMike Smith 
262735863739SMike Smith out:
2628f6c4dd3fSScott Long 	if (cm != NULL) {
262935863739SMike Smith 		aac_release_command(cm);
2630f6c4dd3fSScott Long 	}
2631ae543596SScott Long 
2632bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
263335863739SMike Smith 	return(error);
263435863739SMike Smith }
263535863739SMike Smith 
2636914da7d0SScott Long /*
263735863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
263836e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
263935863739SMike Smith  */
264035863739SMike Smith static void
264136e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
264235863739SMike Smith {
264336e0bf6eSScott Long 	struct aac_aif_command *aif;
264436e0bf6eSScott Long 	struct aac_container *co, *co_next;
2645cbfd045bSScott Long 	struct aac_mntinfo *mi;
2646cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
264736e0bf6eSScott Long 	u_int16_t rsize;
2648b3457b51SScott Long 	int next, found;
2649795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
265035863739SMike Smith 
265135863739SMike Smith 	debug_called(2);
265235863739SMike Smith 
265336e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
265436e0bf6eSScott Long 	aac_print_aif(sc, aif);
265536e0bf6eSScott Long 
265636e0bf6eSScott Long 	/* Is it an event that we should care about? */
265736e0bf6eSScott Long 	switch (aif->command) {
265836e0bf6eSScott Long 	case AifCmdEventNotify:
265936e0bf6eSScott Long 		switch (aif->data.EN.type) {
266036e0bf6eSScott Long 		case AifEnAddContainer:
266136e0bf6eSScott Long 		case AifEnDeleteContainer:
266236e0bf6eSScott Long 			/*
2663914da7d0SScott Long 			 * A container was added or deleted, but the message
2664914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
2665914da7d0SScott Long 			 * containers and sort things out.
266636e0bf6eSScott Long 			 */
266703b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
2668cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
266936e0bf6eSScott Long 			do {
267036e0bf6eSScott Long 				/*
2671914da7d0SScott Long 				 * Ask the controller for its containers one at
2672914da7d0SScott Long 				 * a time.
2673914da7d0SScott Long 				 * XXX What if the controller's list changes
2674914da7d0SScott Long 				 * midway through this enumaration?
267536e0bf6eSScott Long 				 * XXX This should be done async.
267636e0bf6eSScott Long 				 */
267739ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
267839ee03c3SScott Long 				mi->Command = VM_NameServe;
267939ee03c3SScott Long 				mi->MntType = FT_FILESYS;
2680cbfd045bSScott Long 				mi->MntCount = i;
268136e0bf6eSScott Long 				rsize = sizeof(mir);
2682cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
2683cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
2684795d7dc0SScott Long 					printf("Error probing container %d\n",
2685914da7d0SScott Long 					      i);
268636e0bf6eSScott Long 					continue;
268736e0bf6eSScott Long 				}
2688cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
2689795d7dc0SScott Long 				/* XXX Need to check if count changed */
2690795d7dc0SScott Long 				count = mir->MntRespCount;
269136e0bf6eSScott Long 				/*
2692914da7d0SScott Long 				 * Check the container against our list.
2693914da7d0SScott Long 				 * co->co_found was already set to 0 in a
2694914da7d0SScott Long 				 * previous run.
269536e0bf6eSScott Long 				 */
2696cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
2697cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
269836e0bf6eSScott Long 					found = 0;
2699914da7d0SScott Long 					TAILQ_FOREACH(co,
2700914da7d0SScott Long 						      &sc->aac_container_tqh,
2701914da7d0SScott Long 						      co_link) {
270236e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
2703cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
270436e0bf6eSScott Long 							co->co_found = 1;
270536e0bf6eSScott Long 							found = 1;
270636e0bf6eSScott Long 							break;
270736e0bf6eSScott Long 						}
270836e0bf6eSScott Long 					}
2709914da7d0SScott Long 					/*
2710914da7d0SScott Long 					 * If the container matched, continue
2711914da7d0SScott Long 					 * in the list.
2712914da7d0SScott Long 					 */
271336e0bf6eSScott Long 					if (found) {
271436e0bf6eSScott Long 						i++;
271536e0bf6eSScott Long 						continue;
271636e0bf6eSScott Long 					}
271736e0bf6eSScott Long 
271836e0bf6eSScott Long 					/*
2719914da7d0SScott Long 					 * This is a new container.  Do all the
272070545d1aSScott Long 					 * appropriate things to set it up.
272170545d1aSScott Long 					 */
2722cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
272336e0bf6eSScott Long 					added = 1;
272436e0bf6eSScott Long 				}
272536e0bf6eSScott Long 				i++;
2726795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
2727cbfd045bSScott Long 			aac_release_sync_fib(sc);
272836e0bf6eSScott Long 
272936e0bf6eSScott Long 			/*
2730914da7d0SScott Long 			 * Go through our list of containers and see which ones
2731914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
2732914da7d0SScott Long 			 * list them they must have been deleted.  Do the
2733914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
2734914da7d0SScott Long 			 * the co->co_found field.
273536e0bf6eSScott Long 			 */
273636e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
273736e0bf6eSScott Long 			while (co != NULL) {
273836e0bf6eSScott Long 				if (co->co_found == 0) {
2739914da7d0SScott Long 					device_delete_child(sc->aac_dev,
2740914da7d0SScott Long 							    co->co_disk);
274136e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
2742bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
2743914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
2744914da7d0SScott Long 						     co_link);
2745bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
2746ba1d57e7SScott Long 					free(co, M_AACBUF);
274736e0bf6eSScott Long 					co = co_next;
274836e0bf6eSScott Long 				} else {
274936e0bf6eSScott Long 					co->co_found = 0;
275036e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
275136e0bf6eSScott Long 				}
275236e0bf6eSScott Long 			}
275336e0bf6eSScott Long 
275436e0bf6eSScott Long 			/* Attach the newly created containers */
275536e0bf6eSScott Long 			if (added)
275636e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
275736e0bf6eSScott Long 
275836e0bf6eSScott Long 			break;
275936e0bf6eSScott Long 
276036e0bf6eSScott Long 		default:
276136e0bf6eSScott Long 			break;
276236e0bf6eSScott Long 		}
276336e0bf6eSScott Long 
276436e0bf6eSScott Long 	default:
276536e0bf6eSScott Long 		break;
276636e0bf6eSScott Long 	}
276736e0bf6eSScott Long 
276836e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
2769bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
277035863739SMike Smith 	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
277135863739SMike Smith 	if (next != sc->aac_aifq_tail) {
277235863739SMike Smith 		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
277335863739SMike Smith 		sc->aac_aifq_head = next;
2774b3457b51SScott Long 
2775b3457b51SScott Long 		/* On the off chance that someone is sleeping for an aif... */
277635863739SMike Smith 		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
277735863739SMike Smith 			wakeup(sc->aac_aifq);
2778b3457b51SScott Long 		/* Wakeup any poll()ers */
2779512824f8SSeigo Tanimura 		selwakeuppri(&sc->rcv_select, PRIBIO);
278035863739SMike Smith 	}
2781bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
278236e0bf6eSScott Long 
278336e0bf6eSScott Long 	return;
278435863739SMike Smith }
278535863739SMike Smith 
2786914da7d0SScott Long /*
27870b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
278836e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
278936e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
279036e0bf6eSScott Long  * returning what the card reported.
279135863739SMike Smith  */
279235863739SMike Smith static int
2793fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
279435863739SMike Smith {
279535863739SMike Smith 	struct aac_rev_check rev_check;
279635863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
279735863739SMike Smith 	int error = 0;
279835863739SMike Smith 
279935863739SMike Smith 	debug_called(2);
280035863739SMike Smith 
280135863739SMike Smith 	/*
280235863739SMike Smith 	 * Copyin the revision struct from userspace
280335863739SMike Smith 	 */
2804c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
2805c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
280635863739SMike Smith 		return error;
280735863739SMike Smith 	}
280835863739SMike Smith 
2809914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
2810914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
281135863739SMike Smith 
281235863739SMike Smith 	/*
281335863739SMike Smith 	 * Doctor up the response struct.
281435863739SMike Smith 	 */
281535863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
2816914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
2817914da7d0SScott Long 	    sc->aac_revision.external.ul;
2818914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
2819914da7d0SScott Long 	    sc->aac_revision.buildNumber;
282035863739SMike Smith 
2821c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
2822c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
282335863739SMike Smith }
282435863739SMike Smith 
2825914da7d0SScott Long /*
282635863739SMike Smith  * Pass the caller the next AIF in their queue
282735863739SMike Smith  */
282835863739SMike Smith static int
2829fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
283035863739SMike Smith {
283135863739SMike Smith 	struct get_adapter_fib_ioctl agf;
28329e2e96d8SScott Long 	int error;
283335863739SMike Smith 
283435863739SMike Smith 	debug_called(2);
283535863739SMike Smith 
283635863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
283735863739SMike Smith 
283835863739SMike Smith 		/*
283935863739SMike Smith 		 * Check the magic number that we gave the caller.
284035863739SMike Smith 		 */
2841b88ffdc8SScott Long 		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
284235863739SMike Smith 			error = EFAULT;
284335863739SMike Smith 		} else {
2844fb0c27d7SScott Long 			error = aac_return_aif(sc, agf.AifFib);
284535863739SMike Smith 			if ((error == EAGAIN) && (agf.Wait)) {
284635863739SMike Smith 				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
284735863739SMike Smith 				while (error == EAGAIN) {
2848914da7d0SScott Long 					error = tsleep(sc->aac_aifq, PRIBIO |
2849914da7d0SScott Long 						       PCATCH, "aacaif", 0);
285035863739SMike Smith 					if (error == 0)
2851914da7d0SScott Long 						error = aac_return_aif(sc,
2852914da7d0SScott Long 						    agf.AifFib);
285335863739SMike Smith 				}
285435863739SMike Smith 				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
285535863739SMike Smith 			}
285635863739SMike Smith 		}
285735863739SMike Smith 	}
285835863739SMike Smith 	return(error);
285935863739SMike Smith }
286035863739SMike Smith 
2861914da7d0SScott Long /*
28620b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
28630b94a66eSMike Smith  */
28640b94a66eSMike Smith static int
2865fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr)
28660b94a66eSMike Smith {
28673df780cfSScott Long 	int next, error;
28680b94a66eSMike Smith 
28690b94a66eSMike Smith 	debug_called(2);
28700b94a66eSMike Smith 
2871bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
28720b94a66eSMike Smith 	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
2873bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
28743df780cfSScott Long 		return (EAGAIN);
28753df780cfSScott Long 	}
28763df780cfSScott Long 
28773df780cfSScott Long 	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
28783df780cfSScott Long 	error = copyout(&sc->aac_aifq[next], uptr,
2879c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
288036e0bf6eSScott Long 	if (error)
288170545d1aSScott Long 		device_printf(sc->aac_dev,
288270545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
28833df780cfSScott Long 	else
28843df780cfSScott Long 		sc->aac_aifq_tail = next;
28853df780cfSScott Long 
2886bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
28870b94a66eSMike Smith 	return(error);
28880b94a66eSMike Smith }
288936e0bf6eSScott Long 
2890914da7d0SScott Long /*
289136e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
289236e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
289336e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
289436e0bf6eSScott Long  */
289536e0bf6eSScott Long static int
289636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
289736e0bf6eSScott Long {
289836e0bf6eSScott Long 	struct aac_query_disk query_disk;
289936e0bf6eSScott Long 	struct aac_container *co;
2900914da7d0SScott Long 	struct aac_disk	*disk;
290136e0bf6eSScott Long 	int error, id;
290236e0bf6eSScott Long 
290336e0bf6eSScott Long 	debug_called(2);
290436e0bf6eSScott Long 
2905914da7d0SScott Long 	disk = NULL;
2906914da7d0SScott Long 
2907914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
2908914da7d0SScott Long 		       sizeof(struct aac_query_disk));
290936e0bf6eSScott Long 	if (error)
291036e0bf6eSScott Long 		return (error);
291136e0bf6eSScott Long 
291236e0bf6eSScott Long 	id = query_disk.ContainerNumber;
291336e0bf6eSScott Long 	if (id == -1)
291436e0bf6eSScott Long 		return (EINVAL);
291536e0bf6eSScott Long 
2916bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
291736e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
291836e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
291936e0bf6eSScott Long 			break;
292036e0bf6eSScott Long 		}
292136e0bf6eSScott Long 
292236e0bf6eSScott Long 	if (co == NULL) {
292336e0bf6eSScott Long 			query_disk.Valid = 0;
292436e0bf6eSScott Long 			query_disk.Locked = 0;
292536e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
292636e0bf6eSScott Long 	} else {
292736e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
292836e0bf6eSScott Long 		query_disk.Valid = 1;
2929914da7d0SScott Long 		query_disk.Locked =
2930914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
293136e0bf6eSScott Long 		query_disk.Deleted = 0;
2932b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
293336e0bf6eSScott Long 		query_disk.Target = disk->unit;
293436e0bf6eSScott Long 		query_disk.Lun = 0;
293536e0bf6eSScott Long 		query_disk.UnMapped = 0;
29367540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
29370b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
293836e0bf6eSScott Long 	}
2939bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
294036e0bf6eSScott Long 
2941914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
2942914da7d0SScott Long 			sizeof(struct aac_query_disk));
294336e0bf6eSScott Long 
294436e0bf6eSScott Long 	return (error);
294536e0bf6eSScott Long }
294636e0bf6eSScott Long 
2947fe3cb0e1SScott Long static void
2948fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
2949fe3cb0e1SScott Long {
2950fe3cb0e1SScott Long 	struct aac_fib *fib;
2951fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
2952fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
2953fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
2954fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
2955fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
295670545d1aSScott Long 	struct aac_sim *caminf;
2957fe3cb0e1SScott Long 	device_t child;
2958fe3cb0e1SScott Long 	int i, found, error;
2959fe3cb0e1SScott Long 
296003b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2961fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
296239ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
2963fe3cb0e1SScott Long 
2964fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
2965fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
2966fe3cb0e1SScott Long 	c_cmd->param = 0;
2967fe3cb0e1SScott Long 
2968fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
2969fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
2970fe3cb0e1SScott Long 	if (error) {
2971fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
2972fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
2973fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2974fe3cb0e1SScott Long 		return;
2975fe3cb0e1SScott Long 	}
2976fe3cb0e1SScott Long 
2977fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
2978fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
2979fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
2980fe3cb0e1SScott Long 		    c_resp->Status);
2981fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2982fe3cb0e1SScott Long 		return;
2983fe3cb0e1SScott Long 	}
2984fe3cb0e1SScott Long 
2985fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
2986fe3cb0e1SScott Long 
2987fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
298839ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
298939ee03c3SScott Long 
2990fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
2991fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
2992fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
2993fe3cb0e1SScott Long 	vmi->ObjId = 0;
2994fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
2995fe3cb0e1SScott Long 
2996fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
2997fe3cb0e1SScott Long 	    sizeof(struct aac_vmioctl));
2998fe3cb0e1SScott Long 	if (error) {
2999fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3000fe3cb0e1SScott Long 		    error);
3001fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3002fe3cb0e1SScott Long 		return;
3003fe3cb0e1SScott Long 	}
3004fe3cb0e1SScott Long 
3005fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3006fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3007fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3008fe3cb0e1SScott Long 		    vmi_resp->Status);
3009fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3010fe3cb0e1SScott Long 		return;
3011fe3cb0e1SScott Long 	}
3012fe3cb0e1SScott Long 
3013fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3014fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
3015fe3cb0e1SScott Long 
3016fe3cb0e1SScott Long 	found = 0;
3017fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3018fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3019fe3cb0e1SScott Long 			continue;
3020fe3cb0e1SScott Long 
3021a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3022a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3023b5f516cdSScott Long 		if (caminf == NULL) {
3024b5f516cdSScott Long 			device_printf(sc->aac_dev,
3025b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3026b5f516cdSScott Long 			break;
3027b5f516cdSScott Long 		}
3028fe3cb0e1SScott Long 
3029fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3030fe3cb0e1SScott Long 		if (child == NULL) {
3031b5f516cdSScott Long 			device_printf(sc->aac_dev,
3032b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3033b5f516cdSScott Long 			    i);
3034b5f516cdSScott Long 			free(caminf, M_AACBUF);
3035b5f516cdSScott Long 			break;
3036fe3cb0e1SScott Long 		}
3037fe3cb0e1SScott Long 
3038fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3039fe3cb0e1SScott Long 		caminf->BusNumber = i;
3040fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3041fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3042ddb8683eSScott Long 		caminf->sim_dev = child;
3043fe3cb0e1SScott Long 
3044fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3045fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
304670545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3047fe3cb0e1SScott Long 
3048fe3cb0e1SScott Long 		found = 1;
3049fe3cb0e1SScott Long 	}
3050fe3cb0e1SScott Long 
3051fe3cb0e1SScott Long 	if (found)
3052fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3053fe3cb0e1SScott Long 
3054fe3cb0e1SScott Long 	return;
3055fe3cb0e1SScott Long }
3056