xref: /freebsd/sys/dev/aac/aac.c (revision 397fa34f51ad83c50e176bdb0343f0e96922b44c)
135863739SMike Smith /*-
235863739SMike Smith  * Copyright (c) 2000 Michael Smith
3c6eafcf2SScott Long  * Copyright (c) 2001 Scott Long
435863739SMike Smith  * Copyright (c) 2000 BSDi
5c6eafcf2SScott Long  * Copyright (c) 2001 Adaptec, Inc.
635863739SMike Smith  * All rights reserved.
735863739SMike Smith  *
835863739SMike Smith  * Redistribution and use in source and binary forms, with or without
935863739SMike Smith  * modification, are permitted provided that the following conditions
1035863739SMike Smith  * are met:
1135863739SMike Smith  * 1. Redistributions of source code must retain the above copyright
1235863739SMike Smith  *    notice, this list of conditions and the following disclaimer.
1335863739SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1435863739SMike Smith  *    notice, this list of conditions and the following disclaimer in the
1535863739SMike Smith  *    documentation and/or other materials provided with the distribution.
1635863739SMike Smith  *
1735863739SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1835863739SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1935863739SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2035863739SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2135863739SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2235863739SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2335863739SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2435863739SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2535863739SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2635863739SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2735863739SMike Smith  * SUCH DAMAGE.
2835863739SMike Smith  */
2935863739SMike Smith 
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
32aad970f1SDavid E. O'Brien 
3335863739SMike Smith /*
3435863739SMike Smith  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3535863739SMike Smith  */
3635863739SMike Smith 
37f6c4dd3fSScott Long #include "opt_aac.h"
38f6c4dd3fSScott Long 
3936e0bf6eSScott Long /* #include <stddef.h> */
4035863739SMike Smith #include <sys/param.h>
4135863739SMike Smith #include <sys/systm.h>
4235863739SMike Smith #include <sys/malloc.h>
4335863739SMike Smith #include <sys/kernel.h>
4436e0bf6eSScott Long #include <sys/kthread.h>
453d04a9d7SScott Long #include <sys/sysctl.h>
46b3457b51SScott Long #include <sys/poll.h>
47891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
4835863739SMike Smith 
4935863739SMike Smith #include <sys/bus.h>
5035863739SMike Smith #include <sys/conf.h>
5135863739SMike Smith #include <sys/signalvar.h>
520b94a66eSMike Smith #include <sys/time.h>
5336e0bf6eSScott Long #include <sys/eventhandler.h>
5435863739SMike Smith 
5535863739SMike Smith #include <machine/bus_memio.h>
5635863739SMike Smith #include <machine/bus.h>
5735863739SMike Smith #include <machine/resource.h>
5835863739SMike Smith 
5935863739SMike Smith #include <dev/aac/aacreg.h>
600b94a66eSMike Smith #include <dev/aac/aac_ioctl.h>
6135863739SMike Smith #include <dev/aac/aacvar.h>
6235863739SMike Smith #include <dev/aac/aac_tables.h>
6335863739SMike Smith 
6435863739SMike Smith static void	aac_startup(void *arg);
65914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
66cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
67fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
6835863739SMike Smith 
6935863739SMike Smith /* Command Processing */
700b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7135863739SMike Smith static void	aac_complete(void *context, int pending);
7235863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7335863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
74d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
7570545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
7635863739SMike Smith 
7735863739SMike Smith /* Command Buffer Management */
78cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
79cd481291SScott Long 				   int nseg, int error);
80c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
81c6eafcf2SScott Long 				       int nseg, int error);
820b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
838480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
8435863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
8535863739SMike Smith 
8635863739SMike Smith /* Hardware Interface */
87c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
88c6eafcf2SScott Long 			       int error);
89fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9035863739SMike Smith static int	aac_init(struct aac_softc *sc);
9135863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
92c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
93c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
94c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
95f6c4dd3fSScott Long 				struct aac_command *cm);
96c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
97914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
9836e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
9936e0bf6eSScott Long 				     struct aac_fib *fib);
10035863739SMike Smith 
101b3457b51SScott Long /* Falcon/PPC interface */
102b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
103b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
104b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
105b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
106b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
107b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
108b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
109a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
110b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
111b3457b51SScott Long 
112b3457b51SScott Long struct aac_interface aac_fa_interface = {
113b3457b51SScott Long 	aac_fa_get_fwstatus,
114b3457b51SScott Long 	aac_fa_qnotify,
115b3457b51SScott Long 	aac_fa_get_istatus,
116b3457b51SScott Long 	aac_fa_clear_istatus,
117b3457b51SScott Long 	aac_fa_set_mailbox,
118a6d35632SScott Long 	aac_fa_get_mailbox,
119b3457b51SScott Long 	aac_fa_set_interrupts
120b3457b51SScott Long };
121b3457b51SScott Long 
12235863739SMike Smith /* StrongARM interface */
12335863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
12435863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
12535863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
12635863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
12735863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
128c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
129c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
130a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13135863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13235863739SMike Smith 
13335863739SMike Smith struct aac_interface aac_sa_interface = {
13435863739SMike Smith 	aac_sa_get_fwstatus,
13535863739SMike Smith 	aac_sa_qnotify,
13635863739SMike Smith 	aac_sa_get_istatus,
13735863739SMike Smith 	aac_sa_clear_istatus,
13835863739SMike Smith 	aac_sa_set_mailbox,
139a6d35632SScott Long 	aac_sa_get_mailbox,
14035863739SMike Smith 	aac_sa_set_interrupts
14135863739SMike Smith };
14235863739SMike Smith 
14335863739SMike Smith /* i960Rx interface */
14435863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
14535863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
14635863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
14735863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
14835863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
149c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
150c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
151a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
15235863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
15335863739SMike Smith 
15435863739SMike Smith struct aac_interface aac_rx_interface = {
15535863739SMike Smith 	aac_rx_get_fwstatus,
15635863739SMike Smith 	aac_rx_qnotify,
15735863739SMike Smith 	aac_rx_get_istatus,
15835863739SMike Smith 	aac_rx_clear_istatus,
15935863739SMike Smith 	aac_rx_set_mailbox,
160a6d35632SScott Long 	aac_rx_get_mailbox,
16135863739SMike Smith 	aac_rx_set_interrupts
16235863739SMike Smith };
16335863739SMike Smith 
16435863739SMike Smith /* Debugging and Diagnostics */
16535863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
1666965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
167c6eafcf2SScott Long 				   u_int32_t code);
16835863739SMike Smith 
16935863739SMike Smith /* Management Interface */
17035863739SMike Smith static d_open_t		aac_open;
17135863739SMike Smith static d_close_t	aac_close;
17235863739SMike Smith static d_ioctl_t	aac_ioctl;
173b3457b51SScott Long static d_poll_t		aac_poll;
174c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
175c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
17636e0bf6eSScott Long 					   struct aac_fib *fib);
177fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
178fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
179fb0c27d7SScott Long static int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
18036e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
18135863739SMike Smith 
18235863739SMike Smith static struct cdevsw aac_cdevsw = {
183dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
184dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1857ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
1867ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
1877ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
1887ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
1897ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
19035863739SMike Smith };
19135863739SMike Smith 
19236e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
19336e0bf6eSScott Long 
1943d04a9d7SScott Long /* sysctl node */
1953d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
1963d04a9d7SScott Long 
197914da7d0SScott Long /*
198914da7d0SScott Long  * Device Interface
199914da7d0SScott Long  */
20035863739SMike Smith 
201914da7d0SScott Long /*
20235863739SMike Smith  * Initialise the controller and softc
20335863739SMike Smith  */
20435863739SMike Smith int
20535863739SMike Smith aac_attach(struct aac_softc *sc)
20635863739SMike Smith {
20735863739SMike Smith 	int error, unit;
20835863739SMike Smith 
20935863739SMike Smith 	debug_called(1);
21035863739SMike Smith 
21135863739SMike Smith 	/*
21235863739SMike Smith 	 * Initialise per-controller queues.
21335863739SMike Smith 	 */
2140b94a66eSMike Smith 	aac_initq_free(sc);
2150b94a66eSMike Smith 	aac_initq_ready(sc);
2160b94a66eSMike Smith 	aac_initq_busy(sc);
2170b94a66eSMike Smith 	aac_initq_bio(sc);
21835863739SMike Smith 
21935863739SMike Smith 	/*
22035863739SMike Smith 	 * Initialise command-completion task.
22135863739SMike Smith 	 */
22235863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
22335863739SMike Smith 
22435863739SMike Smith 	/* disable interrupts before we enable anything */
22535863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
22635863739SMike Smith 
22735863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
22835863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
22935863739SMike Smith 
23035863739SMike Smith 	/*
231fe94b852SScott Long 	 * Check that the firmware on the card is supported.
232fe94b852SScott Long 	 */
233fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
234fe94b852SScott Long 		return(error);
235fe94b852SScott Long 
236f6b1c44dSScott Long 	/*
237f6b1c44dSScott Long 	 * Initialize locks
238f6b1c44dSScott Long 	 */
239cbfd045bSScott Long 	AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock");
240f6b1c44dSScott Long 	AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
241f6b1c44dSScott Long 	AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock");
242f6b1c44dSScott Long 	AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
243f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
244f6b1c44dSScott Long 
2453df780cfSScott Long 	/* Initialize the local AIF queue pointers */
2463df780cfSScott Long 	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
247cbfd045bSScott Long 
2480b94a66eSMike Smith 	/*
24935863739SMike Smith 	 * Initialise the adapter.
25035863739SMike Smith 	 */
2510b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
25235863739SMike Smith 		return(error);
25335863739SMike Smith 
25435863739SMike Smith 	/*
25535863739SMike Smith 	 * Print a little information about the controller.
25635863739SMike Smith 	 */
25735863739SMike Smith 	aac_describe_controller(sc);
25835863739SMike Smith 
25935863739SMike Smith 	/*
260ae543596SScott Long 	 * Register to probe our containers later.
261ae543596SScott Long 	 */
26235863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
26335863739SMike Smith 	sc->aac_ich.ich_arg = sc;
26435863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
265914da7d0SScott Long 		device_printf(sc->aac_dev,
266914da7d0SScott Long 			      "can't establish configuration hook\n");
26735863739SMike Smith 		return(ENXIO);
26835863739SMike Smith 	}
26935863739SMike Smith 
27035863739SMike Smith 	/*
27135863739SMike Smith 	 * Make the control device.
27235863739SMike Smith 	 */
27335863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
2749e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
2759e9466baSRobert Watson 				 0640, "aac%d", unit);
276157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
2774aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
27835863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
27935863739SMike Smith 
28036e0bf6eSScott Long 	/* Create the AIF thread */
28170545d1aSScott Long 	if (kthread_create((void(*)(void *))aac_command_thread, sc,
282316ec49aSScott Long 			   &sc->aifthread, 0, 0, "aac%daif", unit))
28336e0bf6eSScott Long 		panic("Could not create AIF thread\n");
28436e0bf6eSScott Long 
28536e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
2865f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
2875f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
2885f54d522SScott Long 		device_printf(sc->aac_dev,
2895f54d522SScott Long 			      "shutdown event registration failed\n");
29036e0bf6eSScott Long 
291fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
292a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
29370545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
294fe3cb0e1SScott Long 		aac_get_bus_info(sc);
29570545d1aSScott Long 	}
296fe3cb0e1SScott Long 
29735863739SMike Smith 	return(0);
29835863739SMike Smith }
29935863739SMike Smith 
300914da7d0SScott Long /*
30135863739SMike Smith  * Probe for containers, create disks.
30235863739SMike Smith  */
30335863739SMike Smith static void
30435863739SMike Smith aac_startup(void *arg)
30535863739SMike Smith {
306914da7d0SScott Long 	struct aac_softc *sc;
307cbfd045bSScott Long 	struct aac_fib *fib;
308cbfd045bSScott Long 	struct aac_mntinfo *mi;
309cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
310795d7dc0SScott Long 	int count = 0, i = 0;
31135863739SMike Smith 
31235863739SMike Smith 	debug_called(1);
31335863739SMike Smith 
314914da7d0SScott Long 	sc = (struct aac_softc *)arg;
315914da7d0SScott Long 
31635863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
31735863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
31835863739SMike Smith 
319fe3cb0e1SScott Long 	aac_alloc_sync_fib(sc, &fib, 0);
320cbfd045bSScott Long 	mi = (struct aac_mntinfo *)&fib->data[0];
321cbfd045bSScott Long 
32235863739SMike Smith 	/* loop over possible containers */
32336e0bf6eSScott Long 	do {
32435863739SMike Smith 		/* request information on this container */
32539ee03c3SScott Long 		bzero(mi, sizeof(struct aac_mntinfo));
32639ee03c3SScott Long 		mi->Command = VM_NameServe;
32739ee03c3SScott Long 		mi->MntType = FT_FILESYS;
328cbfd045bSScott Long 		mi->MntCount = i;
329cbfd045bSScott Long 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
330cbfd045bSScott Long 				 sizeof(struct aac_mntinfo))) {
331795d7dc0SScott Long 			printf("error probing container %d", i);
33235863739SMike Smith 			continue;
33335863739SMike Smith 		}
33435863739SMike Smith 
335cbfd045bSScott Long 		mir = (struct aac_mntinforesp *)&fib->data[0];
336795d7dc0SScott Long 		/* XXX Need to check if count changed */
337795d7dc0SScott Long 		count = mir->MntRespCount;
338cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
33936e0bf6eSScott Long 		i++;
340795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
341cbfd045bSScott Long 
342cbfd045bSScott Long 	aac_release_sync_fib(sc);
34335863739SMike Smith 
34435863739SMike Smith 	/* poke the bus to actually attach the child devices */
34535863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
34635863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
34735863739SMike Smith 
34835863739SMike Smith 	/* mark the controller up */
34935863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
35035863739SMike Smith 
35135863739SMike Smith 	/* enable interrupts now */
35235863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
35335863739SMike Smith }
35435863739SMike Smith 
355914da7d0SScott Long /*
356914da7d0SScott Long  * Create a device to respresent a new container
357914da7d0SScott Long  */
358914da7d0SScott Long static void
359cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
360914da7d0SScott Long {
361914da7d0SScott Long 	struct aac_container *co;
362914da7d0SScott Long 	device_t child;
363914da7d0SScott Long 
364914da7d0SScott Long 	/*
365914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
366914da7d0SScott Long 	 * the possible types may never show up.
367914da7d0SScott Long 	 */
368914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
369a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
370a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
371914da7d0SScott Long 		if (co == NULL)
372914da7d0SScott Long 			panic("Out of memory?!\n");
373914da7d0SScott Long 		debug(1, "id %x  name '%.16s'  size %u  type %d",
374914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
375914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
376914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
377914da7d0SScott Long 
378fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
379914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
380914da7d0SScott Long 		else
381914da7d0SScott Long 			device_set_ivars(child, co);
382914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
383914da7d0SScott Long 				mir->MntTable[0].VolType));
384914da7d0SScott Long 		co->co_disk = child;
385914da7d0SScott Long 		co->co_found = f;
386914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
387914da7d0SScott Long 		      sizeof(struct aac_mntobj));
388c3d15322SScott Long 		AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
389914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
390914da7d0SScott Long 		AAC_LOCK_RELEASE(&sc->aac_container_lock);
391914da7d0SScott Long 	}
392914da7d0SScott Long }
393914da7d0SScott Long 
394914da7d0SScott Long /*
39535863739SMike Smith  * Free all of the resources associated with (sc)
39635863739SMike Smith  *
39735863739SMike Smith  * Should not be called if the controller is active.
39835863739SMike Smith  */
39935863739SMike Smith void
40035863739SMike Smith aac_free(struct aac_softc *sc)
40135863739SMike Smith {
402ffb37f33SScott Long 
40335863739SMike Smith 	debug_called(1);
40435863739SMike Smith 
40535863739SMike Smith 	/* remove the control device */
40635863739SMike Smith 	if (sc->aac_dev_t != NULL)
40735863739SMike Smith 		destroy_dev(sc->aac_dev_t);
40835863739SMike Smith 
4090b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
4108480cc63SScott Long 	aac_free_commands(sc);
4110b94a66eSMike Smith 	if (sc->aac_fib_dmat)
4120b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
41335863739SMike Smith 
414ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
415ffb37f33SScott Long 
41635863739SMike Smith 	/* destroy the common area */
41735863739SMike Smith 	if (sc->aac_common) {
41835863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
419c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
420c6eafcf2SScott Long 				sc->aac_common_dmamap);
42135863739SMike Smith 	}
4220b94a66eSMike Smith 	if (sc->aac_common_dmat)
4230b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
42435863739SMike Smith 
42535863739SMike Smith 	/* disconnect the interrupt handler */
42635863739SMike Smith 	if (sc->aac_intr)
42735863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
42835863739SMike Smith 	if (sc->aac_irq != NULL)
429c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
430c6eafcf2SScott Long 				     sc->aac_irq);
43135863739SMike Smith 
43235863739SMike Smith 	/* destroy data-transfer DMA tag */
43335863739SMike Smith 	if (sc->aac_buffer_dmat)
43435863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
43535863739SMike Smith 
43635863739SMike Smith 	/* destroy the parent DMA tag */
43735863739SMike Smith 	if (sc->aac_parent_dmat)
43835863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
43935863739SMike Smith 
44035863739SMike Smith 	/* release the register window mapping */
44135863739SMike Smith 	if (sc->aac_regs_resource != NULL)
442914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
443914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
44435863739SMike Smith }
44535863739SMike Smith 
446914da7d0SScott Long /*
44735863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
44835863739SMike Smith  */
44935863739SMike Smith int
45035863739SMike Smith aac_detach(device_t dev)
45135863739SMike Smith {
452914da7d0SScott Long 	struct aac_softc *sc;
45370545d1aSScott Long 	struct aac_container *co;
45470545d1aSScott Long 	struct aac_sim	*sim;
45535863739SMike Smith 	int error;
45635863739SMike Smith 
45735863739SMike Smith 	debug_called(1);
45835863739SMike Smith 
459914da7d0SScott Long 	sc = device_get_softc(dev);
460914da7d0SScott Long 
46135863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
46235863739SMike Smith 		return(EBUSY);
46335863739SMike Smith 
46470545d1aSScott Long 	/* Remove the child containers */
465a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
46670545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
46770545d1aSScott Long 		if (error)
46870545d1aSScott Long 			return (error);
46965ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
470a761a1caSScott Long 		free(co, M_AACBUF);
47170545d1aSScott Long 	}
47270545d1aSScott Long 
47370545d1aSScott Long 	/* Remove the CAM SIMs */
474a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
475a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
47670545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
47770545d1aSScott Long 		if (error)
47870545d1aSScott Long 			return (error);
479a761a1caSScott Long 		free(sim, M_AACBUF);
48070545d1aSScott Long 	}
48170545d1aSScott Long 
48236e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
48336e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
48436e0bf6eSScott Long 		wakeup(sc->aifthread);
48536e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
48636e0bf6eSScott Long 	}
48736e0bf6eSScott Long 
48836e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
48936e0bf6eSScott Long 		panic("Cannot shutdown AIF thread\n");
49036e0bf6eSScott Long 
49135863739SMike Smith 	if ((error = aac_shutdown(dev)))
49235863739SMike Smith 		return(error);
49335863739SMike Smith 
4945f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
4955f54d522SScott Long 
49635863739SMike Smith 	aac_free(sc);
49735863739SMike Smith 
49835863739SMike Smith 	return(0);
49935863739SMike Smith }
50035863739SMike Smith 
501914da7d0SScott Long /*
50235863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
50335863739SMike Smith  *
50435863739SMike Smith  * This function is called before detach or system shutdown.
50535863739SMike Smith  *
5060b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
50735863739SMike Smith  * allow shutdown if any device is open.
50835863739SMike Smith  */
50935863739SMike Smith int
51035863739SMike Smith aac_shutdown(device_t dev)
51135863739SMike Smith {
512914da7d0SScott Long 	struct aac_softc *sc;
513cbfd045bSScott Long 	struct aac_fib *fib;
514cbfd045bSScott Long 	struct aac_close_command *cc;
51535863739SMike Smith 
51635863739SMike Smith 	debug_called(1);
51735863739SMike Smith 
518914da7d0SScott Long 	sc = device_get_softc(dev);
519914da7d0SScott Long 
52035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
52135863739SMike Smith 
52235863739SMike Smith 	/*
52335863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
52435863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
52535863739SMike Smith 	 * We've been closed and all I/O completed already
52635863739SMike Smith 	 */
52735863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
52835863739SMike Smith 
529fe3cb0e1SScott Long 	aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
530cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
531cbfd045bSScott Long 
53239ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
533cbfd045bSScott Long 	cc->Command = VM_CloseAll;
534cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
535cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
536cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
53735863739SMike Smith 		printf("FAILED.\n");
53870545d1aSScott Long 	else
53970545d1aSScott Long 		printf("done\n");
54070545d1aSScott Long #if 0
541914da7d0SScott Long 	else {
542cbfd045bSScott Long 		fib->data[0] = 0;
54336e0bf6eSScott Long 		/*
544914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
54536e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
54636e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
54736e0bf6eSScott Long 		 * driver module with the intent to reload it later.
54836e0bf6eSScott Long 		 */
549cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
550cbfd045bSScott Long 		    fib, 1)) {
55135863739SMike Smith 			printf("FAILED.\n");
55235863739SMike Smith 		} else {
55335863739SMike Smith 			printf("done.\n");
55435863739SMike Smith 		}
55535863739SMike Smith 	}
55670545d1aSScott Long #endif
55735863739SMike Smith 
55835863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
55935863739SMike Smith 
56035863739SMike Smith 	return(0);
56135863739SMike Smith }
56235863739SMike Smith 
563914da7d0SScott Long /*
56435863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
56535863739SMike Smith  */
56635863739SMike Smith int
56735863739SMike Smith aac_suspend(device_t dev)
56835863739SMike Smith {
569914da7d0SScott Long 	struct aac_softc *sc;
57035863739SMike Smith 
57135863739SMike Smith 	debug_called(1);
572914da7d0SScott Long 
573914da7d0SScott Long 	sc = device_get_softc(dev);
574914da7d0SScott Long 
57535863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
57635863739SMike Smith 
57735863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
57835863739SMike Smith 	return(0);
57935863739SMike Smith }
58035863739SMike Smith 
581914da7d0SScott Long /*
58235863739SMike Smith  * Bring the controller back to a state ready for operation.
58335863739SMike Smith  */
58435863739SMike Smith int
58535863739SMike Smith aac_resume(device_t dev)
58635863739SMike Smith {
587914da7d0SScott Long 	struct aac_softc *sc;
58835863739SMike Smith 
58935863739SMike Smith 	debug_called(1);
590914da7d0SScott Long 
591914da7d0SScott Long 	sc = device_get_softc(dev);
592914da7d0SScott Long 
59335863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
59435863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
59535863739SMike Smith 	return(0);
59635863739SMike Smith }
59735863739SMike Smith 
598914da7d0SScott Long /*
59935863739SMike Smith  * Take an interrupt.
60035863739SMike Smith  */
60135863739SMike Smith void
60235863739SMike Smith aac_intr(void *arg)
60335863739SMike Smith {
604914da7d0SScott Long 	struct aac_softc *sc;
60570545d1aSScott Long 	u_int16_t reason;
60635863739SMike Smith 
60735863739SMike Smith 	debug_called(2);
60835863739SMike Smith 
609914da7d0SScott Long 	sc = (struct aac_softc *)arg;
610914da7d0SScott Long 
611f30ac74cSScott Long 	/*
6129148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
6139148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
6149148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
6159148fa21SScott Long 	 * ugly.
616f30ac74cSScott Long 	 */
61735863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
618f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
619f30ac74cSScott Long 
6209c3a7fceSScott Long 	/* handle completion processing */
6219148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
6229148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
62335863739SMike Smith 
6249148fa21SScott Long 	/* controller wants to talk to us */
6259148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
62670545d1aSScott Long 		/*
6279148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
6289148fa21SScott Long 		 * that start with a NULL.
62970545d1aSScott Long 		 */
6309148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
6319148fa21SScott Long 		    (sc->aac_common->ac_printf[0] == 0))
6329148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
63370545d1aSScott Long 
6349148fa21SScott Long 		/*
6359148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
636a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
6379148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
6389148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
6399148fa21SScott Long 		 * if needed.
6409148fa21SScott Long 		 */
64136e0bf6eSScott Long 		wakeup(sc->aifthread);
64236e0bf6eSScott Long 	}
6439148fa21SScott Long }
64435863739SMike Smith 
645c6eafcf2SScott Long /*
646914da7d0SScott Long  * Command Processing
647914da7d0SScott Long  */
64835863739SMike Smith 
649914da7d0SScott Long /*
65035863739SMike Smith  * Start as much queued I/O as possible on the controller
65135863739SMike Smith  */
652fe3cb0e1SScott Long void
65335863739SMike Smith aac_startio(struct aac_softc *sc)
65435863739SMike Smith {
65535863739SMike Smith 	struct aac_command *cm;
656397fa34fSScott Long 	int error;
65735863739SMike Smith 
65835863739SMike Smith 	debug_called(2);
65935863739SMike Smith 
66035863739SMike Smith 	for (;;) {
661914da7d0SScott Long 		/*
662397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
663397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
664397fa34fSScott Long 		 */
665397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
666397fa34fSScott Long 			break;
667397fa34fSScott Long 
668397fa34fSScott Long 		/*
669914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
670914da7d0SScott Long 		 * resources
671914da7d0SScott Long 		 */
67235863739SMike Smith 		cm = aac_dequeue_ready(sc);
67335863739SMike Smith 
674914da7d0SScott Long 		/*
675914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
676914da7d0SScott Long 		 * return)
677914da7d0SScott Long 		 */
6780b94a66eSMike Smith 		if (cm == NULL)
67935863739SMike Smith 			aac_bio_command(sc, &cm);
68035863739SMike Smith 
68135863739SMike Smith 		/* nothing to do? */
68235863739SMike Smith 		if (cm == NULL)
68335863739SMike Smith 			break;
68435863739SMike Smith 
685cd481291SScott Long 		/* don't map more than once */
686cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
6874102d44bSScott Long 			panic("aac: command %p already mapped", cm);
68835863739SMike Smith 
689397fa34fSScott Long 		/*
690397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
691397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
692397fa34fSScott Long 		 * busdma.
693397fa34fSScott Long 		 */
694cd481291SScott Long 		if (cm->cm_datalen != 0) {
695397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
696397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
697397fa34fSScott Long 						cm->cm_datalen,
698cd481291SScott Long 						aac_map_command_sg, cm, 0);
699cd481291SScott Long 			if (error == EINPROGRESS) {
700cd481291SScott Long 				debug(1, "freezing queue\n");
701cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
702cd481291SScott Long 				error = 0;
703397fa34fSScott Long 			} else
704397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
705397fa34fSScott Long 				      "busdma\n", error);
706397fa34fSScott Long 		} else
7078778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
708cd481291SScott Long 	}
70935863739SMike Smith }
71035863739SMike Smith 
711914da7d0SScott Long /*
71235863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
71335863739SMike Smith  */
71435863739SMike Smith static void
71570545d1aSScott Long aac_command_thread(struct aac_softc *sc)
71635863739SMike Smith {
71735863739SMike Smith 	struct aac_fib *fib;
71835863739SMike Smith 	u_int32_t fib_size;
7199148fa21SScott Long 	int size, retval;
72035863739SMike Smith 
72136e0bf6eSScott Long 	debug_called(2);
72235863739SMike Smith 
723a32a982dSScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
724a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
72536e0bf6eSScott Long 
726a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
727a32a982dSScott Long 
728a32a982dSScott Long 		retval = 0;
729a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
730a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
731a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
73236e0bf6eSScott Long 
7339148fa21SScott Long 		/*
7349148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
7359148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
7369148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
7379148fa21SScott Long 		 */
7389148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
739a32a982dSScott Long 			AAC_LOCK_RELEASE(&sc->aac_io_lock);
740a32a982dSScott Long 			aac_alloc_commands(sc);
7419148fa21SScott Long 			AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
7424102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
743a32a982dSScott Long 			aac_startio(sc);
744a32a982dSScott Long 		}
7459148fa21SScott Long 
7469148fa21SScott Long 		/*
7479148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
7489148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
7499148fa21SScott Long 		 * always fire.
7509148fa21SScott Long 		 */
7519148fa21SScott Long 		if (retval == EWOULDBLOCK)
75270545d1aSScott Long 			aac_timeout(sc);
75370545d1aSScott Long 
75470545d1aSScott Long 		/* Check the hardware printf message buffer */
7559148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
75670545d1aSScott Long 			aac_print_printf(sc);
75770545d1aSScott Long 
7589148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
7599148fa21SScott Long 		while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
7609148fa21SScott Long 				       &fib_size, &fib) == 0) {
76135863739SMike Smith 
76236e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
76336e0bf6eSScott Long 
76435863739SMike Smith 			switch (fib->Header.Command) {
76535863739SMike Smith 			case AifRequest:
76636e0bf6eSScott Long 				aac_handle_aif(sc, fib);
76735863739SMike Smith 				break;
76835863739SMike Smith 			default:
769914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
770914da7d0SScott Long 					      "from controller\n");
77135863739SMike Smith 				break;
77235863739SMike Smith 			}
77335863739SMike Smith 
77436e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
77536e0bf6eSScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
77636e0bf6eSScott Long 				break;
77736e0bf6eSScott Long 
77870545d1aSScott Long 			/* Return the AIF to the controller. */
77936e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
78036e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
78136e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
78236e0bf6eSScott Long 
78336e0bf6eSScott Long 				/* XXX Compute the Size field? */
78436e0bf6eSScott Long 				size = fib->Header.Size;
78536e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
78636e0bf6eSScott Long 					size = sizeof(struct aac_fib);
78736e0bf6eSScott Long 					fib->Header.Size = size;
78836e0bf6eSScott Long 				}
78936e0bf6eSScott Long 				/*
790914da7d0SScott Long 				 * Since we did not generate this command, it
791914da7d0SScott Long 				 * cannot go through the normal
792914da7d0SScott Long 				 * enqueue->startio chain.
79336e0bf6eSScott Long 				 */
794914da7d0SScott Long 				aac_enqueue_response(sc,
795914da7d0SScott Long 						     AAC_ADAP_NORM_RESP_QUEUE,
796914da7d0SScott Long 						     fib);
79736e0bf6eSScott Long 			}
79836e0bf6eSScott Long 		}
79936e0bf6eSScott Long 	}
80036e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
801a32a982dSScott Long 	AAC_LOCK_RELEASE(&sc->aac_io_lock);
80236e0bf6eSScott Long 	wakeup(sc->aac_dev);
80336e0bf6eSScott Long 
80436e0bf6eSScott Long 	kthread_exit(0);
80535863739SMike Smith }
80635863739SMike Smith 
807914da7d0SScott Long /*
8089c3a7fceSScott Long  * Process completed commands.
80935863739SMike Smith  */
81035863739SMike Smith static void
8119c3a7fceSScott Long aac_complete(void *context, int pending)
81235863739SMike Smith {
8139c3a7fceSScott Long 	struct aac_softc *sc;
81435863739SMike Smith 	struct aac_command *cm;
81535863739SMike Smith 	struct aac_fib *fib;
81635863739SMike Smith 	u_int32_t fib_size;
81735863739SMike Smith 
81835863739SMike Smith 	debug_called(2);
81935863739SMike Smith 
8209c3a7fceSScott Long 	sc = (struct aac_softc *)context;
8219c3a7fceSScott Long 
822ae543596SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
823ae543596SScott Long 
8249c3a7fceSScott Long 	/* pull completed commands off the queue */
82535863739SMike Smith 	for (;;) {
82635863739SMike Smith 		/* look for completed FIBs on our queue */
827914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
828914da7d0SScott Long 				    &fib))
82935863739SMike Smith 			break;	/* nothing to do */
83035863739SMike Smith 
831ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
832cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
83335863739SMike Smith 		if (cm == NULL) {
83435863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
8359c3a7fceSScott Long 			break;
8369c3a7fceSScott Long 		}
8379c3a7fceSScott Long 
8380b94a66eSMike Smith 		aac_remove_busy(cm);
839ecd1c51fSScott Long 		aac_unmap_command(cm);
84035863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
84135863739SMike Smith 
84235863739SMike Smith 		/* is there a completion handler? */
84335863739SMike Smith 		if (cm->cm_complete != NULL) {
84435863739SMike Smith 			cm->cm_complete(cm);
84535863739SMike Smith 		} else {
84635863739SMike Smith 			/* assume that someone is sleeping on this command */
84735863739SMike Smith 			wakeup(cm);
84835863739SMike Smith 		}
84935863739SMike Smith 	}
8500b94a66eSMike Smith 
8510b94a66eSMike Smith 	/* see if we can start some more I/O */
852cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
8530b94a66eSMike Smith 	aac_startio(sc);
854ae543596SScott Long 
855ae543596SScott Long 	AAC_LOCK_RELEASE(&sc->aac_io_lock);
85635863739SMike Smith }
85735863739SMike Smith 
858914da7d0SScott Long /*
85935863739SMike Smith  * Handle a bio submitted from a disk device.
86035863739SMike Smith  */
86135863739SMike Smith void
86235863739SMike Smith aac_submit_bio(struct bio *bp)
86335863739SMike Smith {
864914da7d0SScott Long 	struct aac_disk *ad;
865914da7d0SScott Long 	struct aac_softc *sc;
86635863739SMike Smith 
86735863739SMike Smith 	debug_called(2);
86835863739SMike Smith 
8697540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
870914da7d0SScott Long 	sc = ad->ad_controller;
871914da7d0SScott Long 
87235863739SMike Smith 	/* queue the BIO and try to get some work done */
8730b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
87435863739SMike Smith 	aac_startio(sc);
87535863739SMike Smith }
87635863739SMike Smith 
877914da7d0SScott Long /*
87835863739SMike Smith  * Get a bio and build a command to go with it.
87935863739SMike Smith  */
88035863739SMike Smith static int
88135863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
88235863739SMike Smith {
88335863739SMike Smith 	struct aac_command *cm;
88435863739SMike Smith 	struct aac_fib *fib;
88535863739SMike Smith 	struct aac_disk *ad;
88635863739SMike Smith 	struct bio *bp;
88735863739SMike Smith 
88835863739SMike Smith 	debug_called(2);
88935863739SMike Smith 
89035863739SMike Smith 	/* get the resources we will need */
89135863739SMike Smith 	cm = NULL;
892a32a982dSScott Long 	bp = NULL;
89335863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
89435863739SMike Smith 		goto fail;
895a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
896a32a982dSScott Long 		goto fail;
89735863739SMike Smith 
89835863739SMike Smith 	/* fill out the command */
8990b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
9000b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
9010b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
90235863739SMike Smith 	cm->cm_private = bp;
9030b94a66eSMike Smith 	cm->cm_timestamp = time_second;
90436e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
90535863739SMike Smith 
90635863739SMike Smith 	/* build the FIB */
90735863739SMike Smith 	fib = cm->cm_fib;
908b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
90935863739SMike Smith 	fib->Header.XferState =
91035863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
91135863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
912f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
91335863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
91435863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
915f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
916f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
917f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
91835863739SMike Smith 
91935863739SMike Smith 	/* build the read/write request */
9207540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
921b85f5808SScott Long 
922b85f5808SScott Long 	if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
923b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
9249e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
925b85f5808SScott Long 			struct aac_blockread *br;
92635863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
92735863739SMike Smith 			br->Command = VM_CtBlockRead;
92835863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
92935863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
93035863739SMike Smith 			br->ByteCount = bp->bio_bcount;
93135863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
93235863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
93335863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
93435863739SMike Smith 		} else {
935b85f5808SScott Long 			struct aac_blockwrite *bw;
93635863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
93735863739SMike Smith 			bw->Command = VM_CtBlockWrite;
93835863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
93935863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
94035863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
941b85f5808SScott Long 			bw->Stable = CUNSTABLE;
94235863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
94335863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
94435863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
94535863739SMike Smith 		}
946b85f5808SScott Long 	} else {
947b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
948b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
949b85f5808SScott Long 			struct aac_blockread64 *br;
950b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
951b85f5808SScott Long 			br->Command = VM_CtHostRead64;
952b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
953b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
954b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
955b85f5808SScott Long 			br->Pad = 0;
956b85f5808SScott Long 			br->Flags = 0;
957b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
958b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
959b85f5808SScott Long 			(struct aac_sg_table64 *)cm->cm_sgtable = &br->SgMap64;
960b85f5808SScott Long 		} else {
961b85f5808SScott Long 			struct aac_blockwrite64 *bw;
962b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
963b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
964b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
965b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
966b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
967b85f5808SScott Long 			bw->Pad = 0;
968b85f5808SScott Long 			bw->Flags = 0;
969b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
970b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
971b85f5808SScott Long 			(struct aac_sg_table64 *)cm->cm_sgtable = &bw->SgMap64;
972b85f5808SScott Long 		}
973b85f5808SScott Long 	}
97435863739SMike Smith 
97535863739SMike Smith 	*cmp = cm;
97635863739SMike Smith 	return(0);
97735863739SMike Smith 
97835863739SMike Smith fail:
97935863739SMike Smith 	if (bp != NULL)
9800b94a66eSMike Smith 		aac_enqueue_bio(sc, bp);
98135863739SMike Smith 	if (cm != NULL)
98235863739SMike Smith 		aac_release_command(cm);
98335863739SMike Smith 	return(ENOMEM);
98435863739SMike Smith }
98535863739SMike Smith 
986914da7d0SScott Long /*
98735863739SMike Smith  * Handle a bio-instigated command that has been completed.
98835863739SMike Smith  */
98935863739SMike Smith static void
99035863739SMike Smith aac_bio_complete(struct aac_command *cm)
99135863739SMike Smith {
99235863739SMike Smith 	struct aac_blockread_response *brr;
99335863739SMike Smith 	struct aac_blockwrite_response *bwr;
99435863739SMike Smith 	struct bio *bp;
99535863739SMike Smith 	AAC_FSAStatus status;
99635863739SMike Smith 
99735863739SMike Smith 	/* fetch relevant status and then release the command */
99835863739SMike Smith 	bp = (struct bio *)cm->cm_private;
9999e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
100035863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
100135863739SMike Smith 		status = brr->Status;
100235863739SMike Smith 	} else {
100335863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
100435863739SMike Smith 		status = bwr->Status;
100535863739SMike Smith 	}
100635863739SMike Smith 	aac_release_command(cm);
100735863739SMike Smith 
100835863739SMike Smith 	/* fix up the bio based on status */
100935863739SMike Smith 	if (status == ST_OK) {
101035863739SMike Smith 		bp->bio_resid = 0;
101135863739SMike Smith 	} else {
101235863739SMike Smith 		bp->bio_error = EIO;
101335863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
10140b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1015914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1016914da7d0SScott Long 						    status);
101735863739SMike Smith 	}
10180b94a66eSMike Smith 	aac_biodone(bp);
101935863739SMike Smith }
102035863739SMike Smith 
1021914da7d0SScott Long /*
102235863739SMike Smith  * Submit a command to the controller, return when it completes.
1023b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1024b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1025d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1026d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1027d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1028d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1029d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
103035863739SMike Smith  */
103135863739SMike Smith static int
1032d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
103335863739SMike Smith {
1034ae543596SScott Long 	struct aac_softc *sc;
1035d8a0a473SScott Long 	int error;
103635863739SMike Smith 
103735863739SMike Smith 	debug_called(2);
103835863739SMike Smith 
1039ae543596SScott Long 	sc = cm->cm_sc;
1040ae543596SScott Long 
104135863739SMike Smith 	/* Put the command on the ready queue and get things going */
104236e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
104335863739SMike Smith 	aac_enqueue_ready(cm);
1044ae543596SScott Long 	aac_startio(sc);
1045ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
104635863739SMike Smith 	return(error);
104735863739SMike Smith }
104835863739SMike Smith 
1049914da7d0SScott Long /*
1050914da7d0SScott Long  *Command Buffer Management
1051914da7d0SScott Long  */
105235863739SMike Smith 
1053914da7d0SScott Long /*
105435863739SMike Smith  * Allocate a command.
105535863739SMike Smith  */
1056fe3cb0e1SScott Long int
105735863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
105835863739SMike Smith {
105935863739SMike Smith 	struct aac_command *cm;
106035863739SMike Smith 
106135863739SMike Smith 	debug_called(3);
106235863739SMike Smith 
1063ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1064b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1065ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1066ae543596SScott Long 			wakeup(sc->aifthread);
1067b85f5808SScott Long 		}
1068ae543596SScott Long 		return (EBUSY);
1069ffb37f33SScott Long 	}
107035863739SMike Smith 
10710b94a66eSMike Smith 	*cmp = cm;
10720b94a66eSMike Smith 	return(0);
10730b94a66eSMike Smith }
10740b94a66eSMike Smith 
1075914da7d0SScott Long /*
10760b94a66eSMike Smith  * Release a command back to the freelist.
10770b94a66eSMike Smith  */
1078fe3cb0e1SScott Long void
10790b94a66eSMike Smith aac_release_command(struct aac_command *cm)
10800b94a66eSMike Smith {
10810b94a66eSMike Smith 	debug_called(3);
10820b94a66eSMike Smith 
10830b94a66eSMike Smith 	/* (re)initialise the command/FIB */
108435863739SMike Smith 	cm->cm_sgtable = NULL;
108535863739SMike Smith 	cm->cm_flags = 0;
108635863739SMike Smith 	cm->cm_complete = NULL;
108735863739SMike Smith 	cm->cm_private = NULL;
108835863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
108935863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
109035863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
109135863739SMike Smith 	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
109235863739SMike Smith 
109335863739SMike Smith 	/*
109435863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
109535863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
109635863739SMike Smith 	 * initialised here for debugging purposes only.
109735863739SMike Smith 	 */
1098f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1099f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
110035863739SMike Smith 
110135863739SMike Smith 	aac_enqueue_free(cm);
110235863739SMike Smith }
110335863739SMike Smith 
1104914da7d0SScott Long /*
11050b94a66eSMike Smith  * Map helper for command/FIB allocation.
110635863739SMike Smith  */
110735863739SMike Smith static void
11080b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
110935863739SMike Smith {
11108480cc63SScott Long 	uint32_t	*fibphys;
1111914da7d0SScott Long 
11128480cc63SScott Long 	fibphys = (uint32_t *)arg;
111335863739SMike Smith 
111435863739SMike Smith 	debug_called(3);
111535863739SMike Smith 
1116ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
111735863739SMike Smith }
111835863739SMike Smith 
1119914da7d0SScott Long /*
11200b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
112135863739SMike Smith  */
11220b94a66eSMike Smith static int
11230b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
112435863739SMike Smith {
112535863739SMike Smith 	struct aac_command *cm;
1126ffb37f33SScott Long 	struct aac_fibmap *fm;
11278480cc63SScott Long 	uint32_t fibphys;
1128ffb37f33SScott Long 	int i, error;
112935863739SMike Smith 
1130a6d35632SScott Long 	debug_called(2);
113135863739SMike Smith 
1132a6d35632SScott Long 	if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
1133ffb37f33SScott Long 		return (ENOMEM);
1134ffb37f33SScott Long 
11358480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1136a6d35632SScott Long 	if (fm == NULL)
1137a6d35632SScott Long 		return (ENOMEM);
1138ffb37f33SScott Long 
11390b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1140ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1141ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
114270545d1aSScott Long 		device_printf(sc->aac_dev,
114370545d1aSScott Long 			      "Not enough contiguous memory available.\n");
11448480cc63SScott Long 		free(fm, M_AACBUF);
11450b94a66eSMike Smith 		return (ENOMEM);
114635863739SMike Smith 	}
1147128aa5a0SScott Long 
1148cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1149cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1150ffb37f33SScott Long 			      AAC_FIB_COUNT * sizeof(struct aac_fib),
1151ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1152128aa5a0SScott Long 
11530b94a66eSMike Smith 	/* initialise constant fields in the command structure */
11549148fa21SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
1155ffb37f33SScott Long 	bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
11560b94a66eSMike Smith 	for (i = 0; i < AAC_FIB_COUNT; i++) {
11578480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1158ffb37f33SScott Long 		fm->aac_commands = cm;
115935863739SMike Smith 		cm->cm_sc = sc;
1160ffb37f33SScott Long 		cm->cm_fib = fm->aac_fibs + i;
11618480cc63SScott Long 		cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib));
1162cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
116335863739SMike Smith 
1164ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1165ffb37f33SScott Long 					       &cm->cm_datamap)) == 0)
116635863739SMike Smith 			aac_release_command(cm);
1167ffb37f33SScott Long 		else
11688480cc63SScott Long 			break;
11698480cc63SScott Long 		sc->total_fibs++;
117035863739SMike Smith 	}
1171ffb37f33SScott Long 
11728480cc63SScott Long 	if (i > 0) {
1173ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1174a6d35632SScott Long 		debug(1, "total_fibs= %d\n", sc->total_fibs);
11759148fa21SScott Long 		AAC_LOCK_RELEASE(&sc->aac_io_lock);
11760b94a66eSMike Smith 		return (0);
117735863739SMike Smith 	}
117835863739SMike Smith 
11799148fa21SScott Long 	AAC_LOCK_RELEASE(&sc->aac_io_lock);
11808480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
11818480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
11828480cc63SScott Long 	free(fm, M_AACBUF);
11838480cc63SScott Long 	return (ENOMEM);
11848480cc63SScott Long }
11858480cc63SScott Long 
1186914da7d0SScott Long /*
11870b94a66eSMike Smith  * Free FIBs owned by this adapter.
118835863739SMike Smith  */
118935863739SMike Smith static void
11908480cc63SScott Long aac_free_commands(struct aac_softc *sc)
119135863739SMike Smith {
11928480cc63SScott Long 	struct aac_fibmap *fm;
1193ffb37f33SScott Long 	struct aac_command *cm;
119435863739SMike Smith 	int i;
119535863739SMike Smith 
119635863739SMike Smith 	debug_called(1);
119735863739SMike Smith 
11988480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
11998480cc63SScott Long 
12008480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
12018480cc63SScott Long 		/*
12028480cc63SScott Long 		 * We check against total_fibs to handle partially
12038480cc63SScott Long 		 * allocated blocks.
12048480cc63SScott Long 		 */
12058480cc63SScott Long 		for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
1206ffb37f33SScott Long 			cm = fm->aac_commands + i;
1207ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1208ffb37f33SScott Long 		}
1209ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1210ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
12118480cc63SScott Long 		free(fm, M_AACBUF);
12128480cc63SScott Long 	}
121335863739SMike Smith }
121435863739SMike Smith 
1215914da7d0SScott Long /*
121635863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
121735863739SMike Smith  */
121835863739SMike Smith static void
121935863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
122035863739SMike Smith {
1221cd481291SScott Long 	struct aac_softc *sc;
1222914da7d0SScott Long 	struct aac_command *cm;
1223914da7d0SScott Long 	struct aac_fib *fib;
122435863739SMike Smith 	int i;
122535863739SMike Smith 
122635863739SMike Smith 	debug_called(3);
122735863739SMike Smith 
1228914da7d0SScott Long 	cm = (struct aac_command *)arg;
1229cd481291SScott Long 	sc = cm->cm_sc;
1230914da7d0SScott Long 	fib = cm->cm_fib;
1231914da7d0SScott Long 
123235863739SMike Smith 	/* copy into the FIB */
1233b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
1234b85f5808SScott Long 		if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1235b85f5808SScott Long 			struct aac_sg_table *sg;
1236b85f5808SScott Long 			sg = cm->cm_sgtable;
123735863739SMike Smith 			sg->SgCount = nseg;
123835863739SMike Smith 			for (i = 0; i < nseg; i++) {
123935863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
124035863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
124135863739SMike Smith 			}
124235863739SMike Smith 			/* update the FIB size for the s/g count */
124335863739SMike Smith 			fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
1244b85f5808SScott Long 		} else {
1245b85f5808SScott Long 			struct aac_sg_table64 *sg;
1246b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1247b85f5808SScott Long 			sg->SgCount = nseg;
1248b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1249b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1250b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
125135863739SMike Smith 			}
1252b85f5808SScott Long 			/* update the FIB size for the s/g count */
1253b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1254b85f5808SScott Long 		}
1255b85f5808SScott Long 	}
125635863739SMike Smith 
1257cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1258cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
1259cd481291SScott Long 	 * the SenderFibAddress over to make room for the fast response bit.
126035863739SMike Smith 	 */
1261cd481291SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
1262cd481291SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
126335863739SMike Smith 
1264cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1265cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
126635863739SMike Smith 
126735863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1268c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1269c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
127035863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1271c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1272c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
127335863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1274cd481291SScott Long 
1275397fa34fSScott Long 	/* Put the FIB on the outbound queue */
12764102d44bSScott Long 	if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
12774102d44bSScott Long 		aac_unmap_command(cm);
1278397fa34fSScott Long 		sc->flags |= AAC_QUEUE_FRZN;
1279cd481291SScott Long 		aac_requeue_ready(cm);
12804102d44bSScott Long 	}
1281cd481291SScott Long 
1282cd481291SScott Long 	return;
128335863739SMike Smith }
128435863739SMike Smith 
1285914da7d0SScott Long /*
128635863739SMike Smith  * Unmap a command from controller-visible space.
128735863739SMike Smith  */
128835863739SMike Smith static void
128935863739SMike Smith aac_unmap_command(struct aac_command *cm)
129035863739SMike Smith {
1291914da7d0SScott Long 	struct aac_softc *sc;
129235863739SMike Smith 
129335863739SMike Smith 	debug_called(2);
129435863739SMike Smith 
1295914da7d0SScott Long 	sc = cm->cm_sc;
1296914da7d0SScott Long 
129735863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
129835863739SMike Smith 		return;
129935863739SMike Smith 
130035863739SMike Smith 	if (cm->cm_datalen != 0) {
130135863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1302c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1303c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
130435863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1305c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1306c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
130735863739SMike Smith 
130835863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
130935863739SMike Smith 	}
131035863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
131135863739SMike Smith }
131235863739SMike Smith 
1313914da7d0SScott Long /*
1314914da7d0SScott Long  * Hardware Interface
1315914da7d0SScott Long  */
131635863739SMike Smith 
1317914da7d0SScott Long /*
131835863739SMike Smith  * Initialise the adapter.
131935863739SMike Smith  */
132035863739SMike Smith static void
132135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
132235863739SMike Smith {
1323914da7d0SScott Long 	struct aac_softc *sc;
132435863739SMike Smith 
132535863739SMike Smith 	debug_called(1);
132635863739SMike Smith 
1327914da7d0SScott Long 	sc = (struct aac_softc *)arg;
1328914da7d0SScott Long 
132935863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
133035863739SMike Smith }
133135863739SMike Smith 
1332a6d35632SScott Long static int
1333a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1334a6d35632SScott Long {
1335a6d35632SScott Long 	u_int32_t major, minor, options;
1336a6d35632SScott Long 
1337a6d35632SScott Long 	debug_called(1);
1338a6d35632SScott Long 
1339fe94b852SScott Long 	/*
1340fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1341fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1342fe94b852SScott Long 	 */
1343a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1344fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1345fe94b852SScott Long 				     NULL)) {
1346fe94b852SScott Long 			device_printf(sc->aac_dev,
1347fe94b852SScott Long 				      "Error reading firmware version\n");
1348fe94b852SScott Long 			return (EIO);
1349fe94b852SScott Long 		}
1350fe94b852SScott Long 
1351fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1352a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1353a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1354fe94b852SScott Long 		if (major == 1) {
1355fe94b852SScott Long 			device_printf(sc->aac_dev,
1356fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1357fe94b852SScott Long 			    major, minor);
1358fe94b852SScott Long 			return (EINVAL);
1359fe94b852SScott Long 		}
1360fe94b852SScott Long 	}
1361fe94b852SScott Long 
1362a6d35632SScott Long 	/*
1363a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1364a6d35632SScott Long 	 * work-arounds to enable.
1365a6d35632SScott Long 	 */
1366a6d35632SScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1367a6d35632SScott Long 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1368a6d35632SScott Long 		return (EIO);
1369a6d35632SScott Long 	}
1370a6d35632SScott Long 	options = AAC_GET_MAILBOX(sc, 1);
1371a6d35632SScott Long 	sc->supported_options = options;
1372a6d35632SScott Long 
1373a6d35632SScott Long 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1374a6d35632SScott Long 	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1375a6d35632SScott Long 		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1376a6d35632SScott Long 	if (options & AAC_SUPPORTED_NONDASD)
1377a6d35632SScott Long 		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1378cd481291SScott Long 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1379cd481291SScott Long 	     && (sizeof(bus_addr_t) > 4)) {
1380a6d35632SScott Long 		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1381a6d35632SScott Long 		sc->flags |= AAC_FLAGS_SG_64BIT;
1382a6d35632SScott Long 	}
1383a6d35632SScott Long 
1384a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
1385a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
1386a6d35632SScott Long 		sc->aac_max_fibs = AAC_MAX_FIBS;
1387a6d35632SScott Long 	else
1388a6d35632SScott Long 		sc->aac_max_fibs = 256;
1389a6d35632SScott Long 
1390fe94b852SScott Long 	return (0);
1391fe94b852SScott Long }
1392fe94b852SScott Long 
139335863739SMike Smith static int
139435863739SMike Smith aac_init(struct aac_softc *sc)
139535863739SMike Smith {
139635863739SMike Smith 	struct aac_adapter_init	*ip;
139735863739SMike Smith 	time_t then;
1398b88ffdc8SScott Long 	u_int32_t code, qoffset;
1399a6d35632SScott Long 	int error;
140035863739SMike Smith 
140135863739SMike Smith 	debug_called(1);
140235863739SMike Smith 
140335863739SMike Smith 	/*
140435863739SMike Smith 	 * First wait for the adapter to come ready.
140535863739SMike Smith 	 */
140635863739SMike Smith 	then = time_second;
140735863739SMike Smith 	do {
140835863739SMike Smith 		code = AAC_GET_FWSTATUS(sc);
140935863739SMike Smith 		if (code & AAC_SELF_TEST_FAILED) {
141035863739SMike Smith 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
141135863739SMike Smith 			return(ENXIO);
141235863739SMike Smith 		}
141335863739SMike Smith 		if (code & AAC_KERNEL_PANIC) {
1414914da7d0SScott Long 			device_printf(sc->aac_dev,
1415914da7d0SScott Long 				      "FATAL: controller kernel panic\n");
141635863739SMike Smith 			return(ENXIO);
141735863739SMike Smith 		}
141835863739SMike Smith 		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
1419914da7d0SScott Long 			device_printf(sc->aac_dev,
1420914da7d0SScott Long 				      "FATAL: controller not coming ready, "
1421c6eafcf2SScott Long 					   "status %x\n", code);
142235863739SMike Smith 			return(ENXIO);
142335863739SMike Smith 		}
142435863739SMike Smith 	} while (!(code & AAC_UP_AND_RUNNING));
142535863739SMike Smith 
1426a6d35632SScott Long 	error = ENOMEM;
1427a6d35632SScott Long 	/*
1428a6d35632SScott Long 	 * Create DMA tag for mapping buffers into controller-addressable space.
1429a6d35632SScott Long 	 */
1430a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1431a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1432a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1433a6d35632SScott Long 			       BUS_SPACE_MAXADDR :
1434a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1435a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1436a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1437a6d35632SScott Long 			       MAXBSIZE,		/* maxsize */
1438a6d35632SScott Long 			       AAC_MAXSGENTRIES,	/* nsegments */
1439a6d35632SScott Long 			       MAXBSIZE,		/* maxsegsize */
1440a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1441f6b1c44dSScott Long 			       busdma_lock_mutex,	/* lockfunc */
1442f6b1c44dSScott Long 			       &sc->aac_io_lock,	/* lockfuncarg */
1443a6d35632SScott Long 			       &sc->aac_buffer_dmat)) {
1444a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1445a6d35632SScott Long 		goto out;
1446a6d35632SScott Long 	}
1447a6d35632SScott Long 
1448a6d35632SScott Long 	/*
1449a6d35632SScott Long 	 * Create DMA tag for mapping FIBs into controller-addressable space..
1450a6d35632SScott Long 	 */
1451a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1452a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1453a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1454a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1455a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
1456a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1457a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1458a6d35632SScott Long 			       AAC_FIB_COUNT *
1459a6d35632SScott Long 			       sizeof(struct aac_fib),  /* maxsize */
1460a6d35632SScott Long 			       1,			/* nsegments */
1461a6d35632SScott Long 			       AAC_FIB_COUNT *
1462a6d35632SScott Long 			       sizeof(struct aac_fib),	/* maxsegsize */
1463a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1464f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
1465a6d35632SScott Long 			       &sc->aac_fib_dmat)) {
1466a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1467a6d35632SScott Long 		goto out;
1468a6d35632SScott Long 	}
1469a6d35632SScott Long 
147035863739SMike Smith 	/*
147135863739SMike Smith 	 * Create DMA tag for the common structure and allocate it.
147235863739SMike Smith 	 */
147335863739SMike Smith 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1474c6eafcf2SScott Long 			       1, 0,			/* algnmnt, boundary */
1475a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1476a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1477a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
147835863739SMike Smith 			       BUS_SPACE_MAXADDR, 	/* highaddr */
147935863739SMike Smith 			       NULL, NULL, 		/* filter, filterarg */
1480ffb37f33SScott Long 			       8192 + sizeof(struct aac_common), /* maxsize */
1481914da7d0SScott Long 			       1,			/* nsegments */
148235863739SMike Smith 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1483a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1484f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
148535863739SMike Smith 			       &sc->aac_common_dmat)) {
1486914da7d0SScott Long 		device_printf(sc->aac_dev,
1487914da7d0SScott Long 			      "can't allocate common structure DMA tag\n");
1488a6d35632SScott Long 		goto out;
148935863739SMike Smith 	}
1490c6eafcf2SScott Long 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1491c6eafcf2SScott Long 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
149235863739SMike Smith 		device_printf(sc->aac_dev, "can't allocate common structure\n");
1493a6d35632SScott Long 		goto out;
149435863739SMike Smith 	}
1495ffb37f33SScott Long 
1496ffb37f33SScott Long 	/*
1497ffb37f33SScott Long 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1498ffb37f33SScott Long 	 * below address 8192 in physical memory.
1499ffb37f33SScott Long 	 * XXX If the padding is not needed, can it be put to use instead
1500ffb37f33SScott Long 	 * of ignored?
1501ffb37f33SScott Long 	 */
1502cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1503ffb37f33SScott Long 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1504ffb37f33SScott Long 			aac_common_map, sc, 0);
1505ffb37f33SScott Long 
1506ffb37f33SScott Long 	if (sc->aac_common_busaddr < 8192) {
1507ffb37f33SScott Long 		(uint8_t *)sc->aac_common += 8192;
1508ffb37f33SScott Long 		sc->aac_common_busaddr += 8192;
1509ffb37f33SScott Long 	}
151035863739SMike Smith 	bzero(sc->aac_common, sizeof(*sc->aac_common));
151135863739SMike Smith 
1512ffb37f33SScott Long 	/* Allocate some FIBs and associated command structs */
1513ffb37f33SScott Long 	TAILQ_INIT(&sc->aac_fibmap_tqh);
1514ffb37f33SScott Long 	sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
15158480cc63SScott Long 				  M_AACBUF, M_WAITOK|M_ZERO);
15168480cc63SScott Long 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1517ffb37f33SScott Long 		if (aac_alloc_commands(sc) != 0)
1518ffb37f33SScott Long 			break;
1519ffb37f33SScott Long 	}
1520ffb37f33SScott Long 	if (sc->total_fibs == 0)
1521a6d35632SScott Long 		goto out;
1522ffb37f33SScott Long 
152335863739SMike Smith 	/*
1524914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1525914da7d0SScott Long 	 * physical location of various important shared data structures.
152635863739SMike Smith 	 */
152735863739SMike Smith 	ip = &sc->aac_common->ac_init;
152835863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1529f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
153035863739SMike Smith 
1531c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1532c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1533149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
153435863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
153535863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
153635863739SMike Smith 
1537c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1538c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
153935863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
154035863739SMike Smith 
15414b00f859SScott Long 	/*
15424b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
15434b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
15444b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
15454b00f859SScott Long 	 * Round up since the granularity is so high.
15464b00f859SScott Long 	 */
1547f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
15484b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
15494b00f859SScott Long 		ip->HostPhysMemPages =
15504b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1551204c0befSScott Long 	}
155235863739SMike Smith 	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
155335863739SMike Smith 
155435863739SMike Smith 	/*
1555c6eafcf2SScott Long 	 * Initialise FIB queues.  Note that it appears that the layout of the
1556c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1557c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
155835863739SMike Smith 	 *
155935863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1560914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1561914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1562914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1563914da7d0SScott Long 	 * does.
156435863739SMike Smith 	 *
1565914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1566914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1567914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1568914da7d0SScott Long 	 * virtue of a table.
156935863739SMike Smith 	 */
1570b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
15710bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
15720bcbebd6SScott Long 	sc->aac_queues =
15730bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1574b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
157535863739SMike Smith 
1576c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1577c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1578c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1579c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1580c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1581c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1582c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1583c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1584c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1585c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1586c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1587c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1588c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1589c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1590c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1591c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1592c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1593c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1594c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1595c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1596c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1597c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1598c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1599c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1600c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1601c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1602c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1603c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1604c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1605c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1606c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1607c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1608c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1609c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1610c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1611c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1612c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1613c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1614c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1615c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1616c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1617c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1618c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1619c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1620c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1621c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1622c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1623c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
162435863739SMike Smith 
162535863739SMike Smith 	/*
162635863739SMike Smith 	 * Do controller-type-specific initialisation
162735863739SMike Smith 	 */
162835863739SMike Smith 	switch (sc->aac_hwif) {
162935863739SMike Smith 	case AAC_HWIF_I960RX:
163035863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
163135863739SMike Smith 		break;
163235863739SMike Smith 	}
163335863739SMike Smith 
163435863739SMike Smith 	/*
163535863739SMike Smith 	 * Give the init structure to the controller.
163635863739SMike Smith 	 */
163735863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1638914da7d0SScott Long 			     sc->aac_common_busaddr +
1639914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1640914da7d0SScott Long 			     NULL)) {
1641914da7d0SScott Long 		device_printf(sc->aac_dev,
1642914da7d0SScott Long 			      "error establishing init structure\n");
1643a6d35632SScott Long 		error = EIO;
1644a6d35632SScott Long 		goto out;
164535863739SMike Smith 	}
164635863739SMike Smith 
1647a6d35632SScott Long 	error = 0;
1648a6d35632SScott Long out:
1649a6d35632SScott Long 	return(error);
165035863739SMike Smith }
165135863739SMike Smith 
1652914da7d0SScott Long /*
165335863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
165435863739SMike Smith  */
165535863739SMike Smith static int
165635863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
165735863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
165835863739SMike Smith 		 u_int32_t *sp)
165935863739SMike Smith {
166035863739SMike Smith 	time_t then;
166135863739SMike Smith 	u_int32_t status;
166235863739SMike Smith 
166335863739SMike Smith 	debug_called(3);
166435863739SMike Smith 
166535863739SMike Smith 	/* populate the mailbox */
166635863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
166735863739SMike Smith 
166835863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
166935863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
167035863739SMike Smith 
167135863739SMike Smith 	/* then set it to signal the adapter */
167235863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
167335863739SMike Smith 
167435863739SMike Smith 	/* spin waiting for the command to complete */
167535863739SMike Smith 	then = time_second;
167635863739SMike Smith 	do {
167735863739SMike Smith 		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1678a6d35632SScott Long 			debug(1, "timed out");
167935863739SMike Smith 			return(EIO);
168035863739SMike Smith 		}
168135863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
168235863739SMike Smith 
168335863739SMike Smith 	/* clear the completion flag */
168435863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
168535863739SMike Smith 
168635863739SMike Smith 	/* get the command status */
1687a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
168835863739SMike Smith 	if (sp != NULL)
168935863739SMike Smith 		*sp = status;
16900b94a66eSMike Smith 	return(0);
169135863739SMike Smith }
169235863739SMike Smith 
1693914da7d0SScott Long /*
1694cbfd045bSScott Long  * Grab the sync fib area.
1695cbfd045bSScott Long  */
1696cbfd045bSScott Long int
1697fe3cb0e1SScott Long aac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags)
1698cbfd045bSScott Long {
1699cbfd045bSScott Long 
1700cbfd045bSScott Long 	/*
1701cbfd045bSScott Long 	 * If the force flag is set, the system is shutting down, or in
1702cbfd045bSScott Long 	 * trouble.  Ignore the mutex.
1703cbfd045bSScott Long 	 */
1704cbfd045bSScott Long 	if (!(flags & AAC_SYNC_LOCK_FORCE))
1705cbfd045bSScott Long 		AAC_LOCK_ACQUIRE(&sc->aac_sync_lock);
1706cbfd045bSScott Long 
1707cbfd045bSScott Long 	*fib = &sc->aac_common->ac_sync_fib;
1708cbfd045bSScott Long 
1709cbfd045bSScott Long 	return (1);
1710cbfd045bSScott Long }
1711cbfd045bSScott Long 
1712cbfd045bSScott Long /*
1713cbfd045bSScott Long  * Release the sync fib area.
1714cbfd045bSScott Long  */
1715cbfd045bSScott Long void
1716cbfd045bSScott Long aac_release_sync_fib(struct aac_softc *sc)
1717cbfd045bSScott Long {
1718cbfd045bSScott Long 
1719cbfd045bSScott Long 	AAC_LOCK_RELEASE(&sc->aac_sync_lock);
1720cbfd045bSScott Long }
1721cbfd045bSScott Long 
1722cbfd045bSScott Long /*
172335863739SMike Smith  * Send a synchronous FIB to the controller and wait for a result.
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 
181835863739SMike Smith 	/* populate queue entry */
181935863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
182035863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
182135863739SMike Smith 
182235863739SMike Smith 	/* update producer index */
182335863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
182435863739SMike Smith 
1825f6c4dd3fSScott Long 	/*
1826914da7d0SScott Long 	 * To avoid a race with its completion interrupt, place this command on
1827914da7d0SScott Long 	 * the busy queue prior to advertising it to the controller.
1828f6c4dd3fSScott Long 	 */
1829f6c4dd3fSScott Long 	aac_enqueue_busy(cm);
1830f6c4dd3fSScott Long 
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;
19960b94a66eSMike Smith 
1997f6c4dd3fSScott Long 	/*
199870545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
1999914da7d0SScott Long 	 * only.
2000914da7d0SScott Long 	 */
20010b94a66eSMike Smith 	deadline = time_second - AAC_CMD_TIMEOUT;
20020b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2003f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2004f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
20050b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2006914da7d0SScott Long 			device_printf(sc->aac_dev,
2007914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2008f6c4dd3fSScott Long 				      cm, (int)(time_second-cm->cm_timestamp));
20090b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
20100b94a66eSMike Smith 		}
20110b94a66eSMike Smith 	}
20120b94a66eSMike Smith 
20130b94a66eSMike Smith 	return;
20140b94a66eSMike Smith }
20150b94a66eSMike Smith 
2016914da7d0SScott Long /*
2017914da7d0SScott Long  * Interface Function Vectors
2018914da7d0SScott Long  */
201935863739SMike Smith 
2020914da7d0SScott Long /*
202135863739SMike Smith  * Read the current firmware status word.
202235863739SMike Smith  */
202335863739SMike Smith static int
202435863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
202535863739SMike Smith {
202635863739SMike Smith 	debug_called(3);
202735863739SMike Smith 
202835863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
202935863739SMike Smith }
203035863739SMike Smith 
203135863739SMike Smith static int
203235863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
203335863739SMike Smith {
203435863739SMike Smith 	debug_called(3);
203535863739SMike Smith 
203635863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
203735863739SMike Smith }
203835863739SMike Smith 
2039b3457b51SScott Long static int
2040b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2041b3457b51SScott Long {
2042b3457b51SScott Long 	int val;
2043b3457b51SScott Long 
2044b3457b51SScott Long 	debug_called(3);
2045b3457b51SScott Long 
2046b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2047b3457b51SScott Long 	return (val);
2048b3457b51SScott Long }
2049b3457b51SScott Long 
2050914da7d0SScott Long /*
205135863739SMike Smith  * Notify the controller of a change in a given queue
205235863739SMike Smith  */
205335863739SMike Smith 
205435863739SMike Smith static void
205535863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
205635863739SMike Smith {
205735863739SMike Smith 	debug_called(3);
205835863739SMike Smith 
205935863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
206035863739SMike Smith }
206135863739SMike Smith 
206235863739SMike Smith static void
206335863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
206435863739SMike Smith {
206535863739SMike Smith 	debug_called(3);
206635863739SMike Smith 
206735863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
206835863739SMike Smith }
206935863739SMike Smith 
2070b3457b51SScott Long static void
2071b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2072b3457b51SScott Long {
2073b3457b51SScott Long 	debug_called(3);
2074b3457b51SScott Long 
2075b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2076b3457b51SScott Long 	AAC_FA_HACK(sc);
2077b3457b51SScott Long }
2078b3457b51SScott Long 
2079914da7d0SScott Long /*
208035863739SMike Smith  * Get the interrupt reason bits
208135863739SMike Smith  */
208235863739SMike Smith static int
208335863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
208435863739SMike Smith {
208535863739SMike Smith 	debug_called(3);
208635863739SMike Smith 
208735863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
208835863739SMike Smith }
208935863739SMike Smith 
209035863739SMike Smith static int
209135863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
209235863739SMike Smith {
209335863739SMike Smith 	debug_called(3);
209435863739SMike Smith 
209535863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
209635863739SMike Smith }
209735863739SMike Smith 
2098b3457b51SScott Long static int
2099b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2100b3457b51SScott Long {
2101b3457b51SScott Long 	int val;
2102b3457b51SScott Long 
2103b3457b51SScott Long 	debug_called(3);
2104b3457b51SScott Long 
2105b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2106b3457b51SScott Long 	return (val);
2107b3457b51SScott Long }
2108b3457b51SScott Long 
2109914da7d0SScott Long /*
211035863739SMike Smith  * Clear some interrupt reason bits
211135863739SMike Smith  */
211235863739SMike Smith static void
211335863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
211435863739SMike Smith {
211535863739SMike Smith 	debug_called(3);
211635863739SMike Smith 
211735863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
211835863739SMike Smith }
211935863739SMike Smith 
212035863739SMike Smith static void
212135863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
212235863739SMike Smith {
212335863739SMike Smith 	debug_called(3);
212435863739SMike Smith 
212535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
212635863739SMike Smith }
212735863739SMike Smith 
2128b3457b51SScott Long static void
2129b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2130b3457b51SScott Long {
2131b3457b51SScott Long 	debug_called(3);
2132b3457b51SScott Long 
2133b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2134b3457b51SScott Long 	AAC_FA_HACK(sc);
2135b3457b51SScott Long }
2136b3457b51SScott Long 
2137914da7d0SScott Long /*
213835863739SMike Smith  * Populate the mailbox and set the command word
213935863739SMike Smith  */
214035863739SMike Smith static void
214135863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
214235863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
214335863739SMike Smith {
214435863739SMike Smith 	debug_called(4);
214535863739SMike Smith 
214635863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
214735863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
214835863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
214935863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
215035863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
215135863739SMike Smith }
215235863739SMike Smith 
215335863739SMike Smith static void
215435863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
215535863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
215635863739SMike Smith {
215735863739SMike Smith 	debug_called(4);
215835863739SMike Smith 
215935863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
216035863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
216135863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
216235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
216335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
216435863739SMike Smith }
216535863739SMike Smith 
2166b3457b51SScott Long static void
2167b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2168b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2169b3457b51SScott Long {
2170b3457b51SScott Long 	debug_called(4);
2171b3457b51SScott Long 
2172b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2173b3457b51SScott Long 	AAC_FA_HACK(sc);
2174b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2175b3457b51SScott Long 	AAC_FA_HACK(sc);
2176b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2177b3457b51SScott Long 	AAC_FA_HACK(sc);
2178b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2179b3457b51SScott Long 	AAC_FA_HACK(sc);
2180b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2181b3457b51SScott Long 	AAC_FA_HACK(sc);
2182b3457b51SScott Long }
2183b3457b51SScott Long 
2184914da7d0SScott Long /*
218535863739SMike Smith  * Fetch the immediate command status word
218635863739SMike Smith  */
218735863739SMike Smith static int
2188a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
218935863739SMike Smith {
219035863739SMike Smith 	debug_called(4);
219135863739SMike Smith 
2192a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
219335863739SMike Smith }
219435863739SMike Smith 
219535863739SMike Smith static int
2196a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
219735863739SMike Smith {
219835863739SMike Smith 	debug_called(4);
219935863739SMike Smith 
2200a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
220135863739SMike Smith }
220235863739SMike Smith 
2203b3457b51SScott Long static int
2204a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2205b3457b51SScott Long {
2206b3457b51SScott Long 	int val;
2207b3457b51SScott Long 
2208b3457b51SScott Long 	debug_called(4);
2209b3457b51SScott Long 
2210a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2211b3457b51SScott Long 	return (val);
2212b3457b51SScott Long }
2213b3457b51SScott Long 
2214914da7d0SScott Long /*
221535863739SMike Smith  * Set/clear interrupt masks
221635863739SMike Smith  */
221735863739SMike Smith static void
221835863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
221935863739SMike Smith {
222035863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
222135863739SMike Smith 
222235863739SMike Smith 	if (enable) {
222335863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
222435863739SMike Smith 	} else {
222535863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
222635863739SMike Smith 	}
222735863739SMike Smith }
222835863739SMike Smith 
222935863739SMike Smith static void
223035863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
223135863739SMike Smith {
223235863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
223335863739SMike Smith 
223435863739SMike Smith 	if (enable) {
223535863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
223635863739SMike Smith 	} else {
223735863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
223835863739SMike Smith 	}
223935863739SMike Smith }
224035863739SMike Smith 
2241b3457b51SScott Long static void
2242b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2243b3457b51SScott Long {
2244b3457b51SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
2245b3457b51SScott Long 
2246b3457b51SScott Long 	if (enable) {
2247b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2248b3457b51SScott Long 		AAC_FA_HACK(sc);
2249b3457b51SScott Long 	} else {
2250b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2251b3457b51SScott Long 		AAC_FA_HACK(sc);
2252b3457b51SScott Long 	}
2253b3457b51SScott Long }
2254b3457b51SScott Long 
2255914da7d0SScott Long /*
2256914da7d0SScott Long  * Debugging and Diagnostics
2257914da7d0SScott Long  */
225835863739SMike Smith 
2259914da7d0SScott Long /*
226035863739SMike Smith  * Print some information about the controller.
226135863739SMike Smith  */
226235863739SMike Smith static void
226335863739SMike Smith aac_describe_controller(struct aac_softc *sc)
226435863739SMike Smith {
2265cbfd045bSScott Long 	struct aac_fib *fib;
226635863739SMike Smith 	struct aac_adapter_info	*info;
226735863739SMike Smith 
226835863739SMike Smith 	debug_called(2);
226935863739SMike Smith 
2270fe3cb0e1SScott Long 	aac_alloc_sync_fib(sc, &fib, 0);
2271cbfd045bSScott Long 
2272cbfd045bSScott Long 	fib->data[0] = 0;
2273cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
227435863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2275fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
227635863739SMike Smith 		return;
227735863739SMike Smith 	}
2278cbfd045bSScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
227935863739SMike Smith 
228036e0bf6eSScott Long 	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
2281c6eafcf2SScott Long 		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
228236e0bf6eSScott Long 		      info->ClockSpeed, info->BufferMem / (1024 * 1024),
2283914da7d0SScott Long 		      aac_describe_code(aac_battery_platform,
2284914da7d0SScott Long 					info->batteryPlatform));
228535863739SMike Smith 
228635863739SMike Smith 	/* save the kernel revision structure for later use */
228735863739SMike Smith 	sc->aac_revision = info->KernelRevision;
228836e0bf6eSScott Long 	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
228935863739SMike Smith 		      info->KernelRevision.external.comp.major,
229035863739SMike Smith 		      info->KernelRevision.external.comp.minor,
229135863739SMike Smith 		      info->KernelRevision.external.comp.dash,
229236e0bf6eSScott Long 		      info->KernelRevision.buildNumber,
229336e0bf6eSScott Long 		      (u_int32_t)(info->SerialNumber & 0xffffff));
2294fe3cb0e1SScott Long 
2295fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
2296a6d35632SScott Long 
2297a6d35632SScott Long 	if (1 || bootverbose) {
2298a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2299a6d35632SScott Long 			      sc->supported_options,
2300a6d35632SScott Long 			      "\20"
2301a6d35632SScott Long 			      "\1SNAPSHOT"
2302a6d35632SScott Long 			      "\2CLUSTERS"
2303a6d35632SScott Long 			      "\3WCACHE"
2304a6d35632SScott Long 			      "\4DATA64"
2305a6d35632SScott Long 			      "\5HOSTTIME"
2306a6d35632SScott Long 			      "\6RAID50"
2307a6d35632SScott Long 			      "\7WINDOW4GB"
2308a6d35632SScott Long 			      "\10SCSIUPGD"
2309a6d35632SScott Long 			      "\11SOFTERR"
2310a6d35632SScott Long 			      "\12NORECOND"
2311a6d35632SScott Long 			      "\13SGMAP64"
2312a6d35632SScott Long 			      "\14ALARM"
2313a6d35632SScott Long 			      "\15NONDASD");
2314a6d35632SScott Long 	}
231535863739SMike Smith }
231635863739SMike Smith 
2317914da7d0SScott Long /*
231835863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
231935863739SMike Smith  * same.
232035863739SMike Smith  */
232135863739SMike Smith static char *
232235863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
232335863739SMike Smith {
232435863739SMike Smith 	int i;
232535863739SMike Smith 
232635863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
232735863739SMike Smith 		if (table[i].code == code)
232835863739SMike Smith 			return(table[i].string);
232935863739SMike Smith 	return(table[i + 1].string);
233035863739SMike Smith }
233135863739SMike Smith 
2332914da7d0SScott Long /*
2333914da7d0SScott Long  * Management Interface
2334914da7d0SScott Long  */
233535863739SMike Smith 
233635863739SMike Smith static int
2337c3d15322SScott Long aac_open(dev_t dev, int flags, int fmt, d_thread_t *td)
233835863739SMike Smith {
2339914da7d0SScott Long 	struct aac_softc *sc;
234035863739SMike Smith 
234135863739SMike Smith 	debug_called(2);
234235863739SMike Smith 
2343914da7d0SScott Long 	sc = dev->si_drv1;
2344914da7d0SScott Long 
234535863739SMike Smith 	/* Check to make sure the device isn't already open */
234635863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN) {
234735863739SMike Smith 		return EBUSY;
234835863739SMike Smith 	}
234935863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
235035863739SMike Smith 
235135863739SMike Smith 	return 0;
235235863739SMike Smith }
235335863739SMike Smith 
235435863739SMike Smith static int
2355c3d15322SScott Long aac_close(dev_t dev, int flags, int fmt, d_thread_t *td)
235635863739SMike Smith {
2357914da7d0SScott Long 	struct aac_softc *sc;
235835863739SMike Smith 
235935863739SMike Smith 	debug_called(2);
236035863739SMike Smith 
2361914da7d0SScott Long 	sc = dev->si_drv1;
2362914da7d0SScott Long 
236335863739SMike Smith 	/* Mark this unit as no longer open  */
236435863739SMike Smith 	sc->aac_state &= ~AAC_STATE_OPEN;
236535863739SMike Smith 
236635863739SMike Smith 	return 0;
236735863739SMike Smith }
236835863739SMike Smith 
236935863739SMike Smith static int
2370c3d15322SScott Long aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
237135863739SMike Smith {
2372914da7d0SScott Long 	union aac_statrequest *as;
2373914da7d0SScott Long 	struct aac_softc *sc;
23740b94a66eSMike Smith 	int error = 0;
2375b88ffdc8SScott Long 	uint32_t cookie;
237635863739SMike Smith 
237735863739SMike Smith 	debug_called(2);
237835863739SMike Smith 
2379914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2380914da7d0SScott Long 	sc = dev->si_drv1;
2381914da7d0SScott Long 
238235863739SMike Smith 	switch (cmd) {
23830b94a66eSMike Smith 	case AACIO_STATS:
23840b94a66eSMike Smith 		switch (as->as_item) {
23850b94a66eSMike Smith 		case AACQ_FREE:
23860b94a66eSMike Smith 		case AACQ_BIO:
23870b94a66eSMike Smith 		case AACQ_READY:
23880b94a66eSMike Smith 		case AACQ_BUSY:
2389c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2390c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
23910b94a66eSMike Smith 			break;
23920b94a66eSMike Smith 		default:
23930b94a66eSMike Smith 			error = ENOENT;
23940b94a66eSMike Smith 			break;
23950b94a66eSMike Smith 		}
23960b94a66eSMike Smith 	break;
23970b94a66eSMike Smith 
239835863739SMike Smith 	case FSACTL_SENDFIB:
2399fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2400fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
24010b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
240235863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
240335863739SMike Smith 		break;
240435863739SMike Smith 	case FSACTL_AIF_THREAD:
2405fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
24060b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
240735863739SMike Smith 		error = EINVAL;
240835863739SMike Smith 		break;
240935863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2410fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2411fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
24120b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
241335863739SMike Smith 		/*
241435863739SMike Smith 		 * Pass the caller out an AdapterFibContext.
241535863739SMike Smith 		 *
241635863739SMike Smith 		 * Note that because we only support one opener, we
241735863739SMike Smith 		 * basically ignore this.  Set the caller's context to a magic
241835863739SMike Smith 		 * number just in case.
24190b94a66eSMike Smith 		 *
24200b94a66eSMike Smith 		 * The Linux code hands the driver a pointer into kernel space,
24210b94a66eSMike Smith 		 * and then trusts it when the caller hands it back.  Aiee!
2422914da7d0SScott Long 		 * Here, we give it the proc pointer of the per-adapter aif
2423914da7d0SScott Long 		 * thread. It's only used as a sanity check in other calls.
242435863739SMike Smith 		 */
2425b88ffdc8SScott Long 		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2426b88ffdc8SScott Long 		error = copyout(&cookie, arg, sizeof(cookie));
242735863739SMike Smith 		break;
242835863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2429fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2430fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
24310b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2432fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
243335863739SMike Smith 		break;
243435863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2435fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
24360b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
243735863739SMike Smith 		/* don't do anything here */
243835863739SMike Smith 		break;
243935863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2440fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2441fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
24420b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2443fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
244435863739SMike Smith 		break;
244536e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
244636e0bf6eSScott Long 		arg = *(caddr_t*)arg;
244736e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
244836e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
244936e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
245036e0bf6eSScott Long 			break;
245136e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
245236e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2453914da7d0SScott Long 		/*
2454914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2455914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2456914da7d0SScott Long 		 * controller
2457914da7d0SScott Long 		 */
245836e0bf6eSScott Long 		error = 0;
245936e0bf6eSScott Long 		break;
246035863739SMike Smith 	default:
2461b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
246235863739SMike Smith 		error = EINVAL;
246335863739SMike Smith 		break;
246435863739SMike Smith 	}
246535863739SMike Smith 	return(error);
246635863739SMike Smith }
246735863739SMike Smith 
2468b3457b51SScott Long static int
2469c3d15322SScott Long aac_poll(dev_t dev, int poll_events, d_thread_t *td)
2470b3457b51SScott Long {
2471b3457b51SScott Long 	struct aac_softc *sc;
2472b3457b51SScott Long 	int revents;
2473b3457b51SScott Long 
2474b3457b51SScott Long 	sc = dev->si_drv1;
2475b3457b51SScott Long 	revents = 0;
2476b3457b51SScott Long 
2477c3d15322SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
2478b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2479b3457b51SScott Long 		if (sc->aac_aifq_tail != sc->aac_aifq_head)
2480b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2481b3457b51SScott Long 	}
2482b3457b51SScott Long 	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
2483b3457b51SScott Long 
2484b3457b51SScott Long 	if (revents == 0) {
2485b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2486b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2487b3457b51SScott Long 	}
2488b3457b51SScott Long 
2489b3457b51SScott Long 	return (revents);
2490b3457b51SScott Long }
2491b3457b51SScott Long 
2492914da7d0SScott Long /*
249335863739SMike Smith  * Send a FIB supplied from userspace
249435863739SMike Smith  */
249535863739SMike Smith static int
249635863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
249735863739SMike Smith {
249835863739SMike Smith 	struct aac_command *cm;
249935863739SMike Smith 	int size, error;
250035863739SMike Smith 
250135863739SMike Smith 	debug_called(2);
250235863739SMike Smith 
250335863739SMike Smith 	cm = NULL;
250435863739SMike Smith 
250535863739SMike Smith 	/*
250635863739SMike Smith 	 * Get a command
250735863739SMike Smith 	 */
2508ae543596SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
250935863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
251035863739SMike Smith 		error = EBUSY;
251135863739SMike Smith 		goto out;
251235863739SMike Smith 	}
251335863739SMike Smith 
251435863739SMike Smith 	/*
251535863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
251635863739SMike Smith 	 */
2517914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
2518914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
251935863739SMike Smith 		goto out;
252035863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
252135863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
2522b88ffdc8SScott Long 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
2523914da7d0SScott Long 			      size, sizeof(struct aac_fib));
252435863739SMike Smith 		size = sizeof(struct aac_fib);
252535863739SMike Smith 	}
252635863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
252735863739SMike Smith 		goto out;
252835863739SMike Smith 	cm->cm_fib->Header.Size = size;
2529f6c4dd3fSScott Long 	cm->cm_timestamp = time_second;
253035863739SMike Smith 
253135863739SMike Smith 	/*
253235863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
253335863739SMike Smith 	 */
2534d8a0a473SScott Long 	if ((error = aac_wait_command(cm)) != 0) {
253570545d1aSScott Long 		device_printf(sc->aac_dev,
253670545d1aSScott Long 			      "aac_wait_command return %d\n", error);
253735863739SMike Smith 		goto out;
2538b3457b51SScott Long 	}
253935863739SMike Smith 
254035863739SMike Smith 	/*
254135863739SMike Smith 	 * Copy the FIB and data back out to the caller.
254235863739SMike Smith 	 */
254335863739SMike Smith 	size = cm->cm_fib->Header.Size;
254435863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
2545b88ffdc8SScott Long 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
2546914da7d0SScott Long 			      size, sizeof(struct aac_fib));
254735863739SMike Smith 		size = sizeof(struct aac_fib);
254835863739SMike Smith 	}
254935863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
255035863739SMike Smith 
255135863739SMike Smith out:
2552f6c4dd3fSScott Long 	if (cm != NULL) {
255335863739SMike Smith 		aac_release_command(cm);
2554f6c4dd3fSScott Long 	}
2555ae543596SScott Long 
2556ae543596SScott Long 	AAC_LOCK_RELEASE(&sc->aac_io_lock);
255735863739SMike Smith 	return(error);
255835863739SMike Smith }
255935863739SMike Smith 
2560914da7d0SScott Long /*
256135863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
256236e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
256335863739SMike Smith  */
256435863739SMike Smith static void
256536e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
256635863739SMike Smith {
256736e0bf6eSScott Long 	struct aac_aif_command *aif;
256836e0bf6eSScott Long 	struct aac_container *co, *co_next;
2569cbfd045bSScott Long 	struct aac_mntinfo *mi;
2570cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
257136e0bf6eSScott Long 	u_int16_t rsize;
2572b3457b51SScott Long 	int next, found;
2573795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
257435863739SMike Smith 
257535863739SMike Smith 	debug_called(2);
257635863739SMike Smith 
257736e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
257836e0bf6eSScott Long 	aac_print_aif(sc, aif);
257936e0bf6eSScott Long 
258036e0bf6eSScott Long 	/* Is it an event that we should care about? */
258136e0bf6eSScott Long 	switch (aif->command) {
258236e0bf6eSScott Long 	case AifCmdEventNotify:
258336e0bf6eSScott Long 		switch (aif->data.EN.type) {
258436e0bf6eSScott Long 		case AifEnAddContainer:
258536e0bf6eSScott Long 		case AifEnDeleteContainer:
258636e0bf6eSScott Long 			/*
2587914da7d0SScott Long 			 * A container was added or deleted, but the message
2588914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
2589914da7d0SScott Long 			 * containers and sort things out.
259036e0bf6eSScott Long 			 */
2591fe3cb0e1SScott Long 			aac_alloc_sync_fib(sc, &fib, 0);
2592cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
259336e0bf6eSScott Long 			do {
259436e0bf6eSScott Long 				/*
2595914da7d0SScott Long 				 * Ask the controller for its containers one at
2596914da7d0SScott Long 				 * a time.
2597914da7d0SScott Long 				 * XXX What if the controller's list changes
2598914da7d0SScott Long 				 * midway through this enumaration?
259936e0bf6eSScott Long 				 * XXX This should be done async.
260036e0bf6eSScott Long 				 */
260139ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
260239ee03c3SScott Long 				mi->Command = VM_NameServe;
260339ee03c3SScott Long 				mi->MntType = FT_FILESYS;
2604cbfd045bSScott Long 				mi->MntCount = i;
260536e0bf6eSScott Long 				rsize = sizeof(mir);
2606cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
2607cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
2608795d7dc0SScott Long 					printf("Error probing container %d\n",
2609914da7d0SScott Long 					      i);
261036e0bf6eSScott Long 					continue;
261136e0bf6eSScott Long 				}
2612cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
2613795d7dc0SScott Long 				/* XXX Need to check if count changed */
2614795d7dc0SScott Long 				count = mir->MntRespCount;
261536e0bf6eSScott Long 				/*
2616914da7d0SScott Long 				 * Check the container against our list.
2617914da7d0SScott Long 				 * co->co_found was already set to 0 in a
2618914da7d0SScott Long 				 * previous run.
261936e0bf6eSScott Long 				 */
2620cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
2621cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
262236e0bf6eSScott Long 					found = 0;
2623914da7d0SScott Long 					TAILQ_FOREACH(co,
2624914da7d0SScott Long 						      &sc->aac_container_tqh,
2625914da7d0SScott Long 						      co_link) {
262636e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
2627cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
262836e0bf6eSScott Long 							co->co_found = 1;
262936e0bf6eSScott Long 							found = 1;
263036e0bf6eSScott Long 							break;
263136e0bf6eSScott Long 						}
263236e0bf6eSScott Long 					}
2633914da7d0SScott Long 					/*
2634914da7d0SScott Long 					 * If the container matched, continue
2635914da7d0SScott Long 					 * in the list.
2636914da7d0SScott Long 					 */
263736e0bf6eSScott Long 					if (found) {
263836e0bf6eSScott Long 						i++;
263936e0bf6eSScott Long 						continue;
264036e0bf6eSScott Long 					}
264136e0bf6eSScott Long 
264236e0bf6eSScott Long 					/*
2643914da7d0SScott Long 					 * This is a new container.  Do all the
264470545d1aSScott Long 					 * appropriate things to set it up.
264570545d1aSScott Long 					 */
2646cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
264736e0bf6eSScott Long 					added = 1;
264836e0bf6eSScott Long 				}
264936e0bf6eSScott Long 				i++;
2650795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
2651cbfd045bSScott Long 			aac_release_sync_fib(sc);
265236e0bf6eSScott Long 
265336e0bf6eSScott Long 			/*
2654914da7d0SScott Long 			 * Go through our list of containers and see which ones
2655914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
2656914da7d0SScott Long 			 * list them they must have been deleted.  Do the
2657914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
2658914da7d0SScott Long 			 * the co->co_found field.
265936e0bf6eSScott Long 			 */
266036e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
266136e0bf6eSScott Long 			while (co != NULL) {
266236e0bf6eSScott Long 				if (co->co_found == 0) {
2663914da7d0SScott Long 					device_delete_child(sc->aac_dev,
2664914da7d0SScott Long 							    co->co_disk);
266536e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
2666c3d15322SScott Long 					AAC_LOCK_ACQUIRE(&sc->
2667914da7d0SScott Long 							aac_container_lock);
2668914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
2669914da7d0SScott Long 						     co_link);
2670914da7d0SScott Long 					AAC_LOCK_RELEASE(&sc->
2671914da7d0SScott Long 							 aac_container_lock);
267236e0bf6eSScott Long 					FREE(co, M_AACBUF);
267336e0bf6eSScott Long 					co = co_next;
267436e0bf6eSScott Long 				} else {
267536e0bf6eSScott Long 					co->co_found = 0;
267636e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
267736e0bf6eSScott Long 				}
267836e0bf6eSScott Long 			}
267936e0bf6eSScott Long 
268036e0bf6eSScott Long 			/* Attach the newly created containers */
268136e0bf6eSScott Long 			if (added)
268236e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
268336e0bf6eSScott Long 
268436e0bf6eSScott Long 			break;
268536e0bf6eSScott Long 
268636e0bf6eSScott Long 		default:
268736e0bf6eSScott Long 			break;
268836e0bf6eSScott Long 		}
268936e0bf6eSScott Long 
269036e0bf6eSScott Long 	default:
269136e0bf6eSScott Long 		break;
269236e0bf6eSScott Long 	}
269336e0bf6eSScott Long 
269436e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
2695c3d15322SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
269635863739SMike Smith 	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
269735863739SMike Smith 	if (next != sc->aac_aifq_tail) {
269835863739SMike Smith 		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
269935863739SMike Smith 		sc->aac_aifq_head = next;
2700b3457b51SScott Long 
2701b3457b51SScott Long 		/* On the off chance that someone is sleeping for an aif... */
270235863739SMike Smith 		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
270335863739SMike Smith 			wakeup(sc->aac_aifq);
2704b3457b51SScott Long 		/* Wakeup any poll()ers */
2705512824f8SSeigo Tanimura 		selwakeuppri(&sc->rcv_select, PRIBIO);
270635863739SMike Smith 	}
2707b3457b51SScott Long 	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
270836e0bf6eSScott Long 
270936e0bf6eSScott Long 	return;
271035863739SMike Smith }
271135863739SMike Smith 
2712914da7d0SScott Long /*
27130b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
271436e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
271536e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
271636e0bf6eSScott Long  * returning what the card reported.
271735863739SMike Smith  */
271835863739SMike Smith static int
2719fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
272035863739SMike Smith {
272135863739SMike Smith 	struct aac_rev_check rev_check;
272235863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
272335863739SMike Smith 	int error = 0;
272435863739SMike Smith 
272535863739SMike Smith 	debug_called(2);
272635863739SMike Smith 
272735863739SMike Smith 	/*
272835863739SMike Smith 	 * Copyin the revision struct from userspace
272935863739SMike Smith 	 */
2730c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
2731c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
273235863739SMike Smith 		return error;
273335863739SMike Smith 	}
273435863739SMike Smith 
2735914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
2736914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
273735863739SMike Smith 
273835863739SMike Smith 	/*
273935863739SMike Smith 	 * Doctor up the response struct.
274035863739SMike Smith 	 */
274135863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
2742914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
2743914da7d0SScott Long 	    sc->aac_revision.external.ul;
2744914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
2745914da7d0SScott Long 	    sc->aac_revision.buildNumber;
274635863739SMike Smith 
2747c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
2748c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
274935863739SMike Smith }
275035863739SMike Smith 
2751914da7d0SScott Long /*
275235863739SMike Smith  * Pass the caller the next AIF in their queue
275335863739SMike Smith  */
275435863739SMike Smith static int
2755fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
275635863739SMike Smith {
275735863739SMike Smith 	struct get_adapter_fib_ioctl agf;
27589e2e96d8SScott Long 	int error;
275935863739SMike Smith 
276035863739SMike Smith 	debug_called(2);
276135863739SMike Smith 
276235863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
276335863739SMike Smith 
276435863739SMike Smith 		/*
276535863739SMike Smith 		 * Check the magic number that we gave the caller.
276635863739SMike Smith 		 */
2767b88ffdc8SScott Long 		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
276835863739SMike Smith 			error = EFAULT;
276935863739SMike Smith 		} else {
2770fb0c27d7SScott Long 			error = aac_return_aif(sc, agf.AifFib);
277135863739SMike Smith 			if ((error == EAGAIN) && (agf.Wait)) {
277235863739SMike Smith 				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
277335863739SMike Smith 				while (error == EAGAIN) {
2774914da7d0SScott Long 					error = tsleep(sc->aac_aifq, PRIBIO |
2775914da7d0SScott Long 						       PCATCH, "aacaif", 0);
277635863739SMike Smith 					if (error == 0)
2777914da7d0SScott Long 						error = aac_return_aif(sc,
2778914da7d0SScott Long 						    agf.AifFib);
277935863739SMike Smith 				}
278035863739SMike Smith 				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
278135863739SMike Smith 			}
278235863739SMike Smith 		}
278335863739SMike Smith 	}
278435863739SMike Smith 	return(error);
278535863739SMike Smith }
278635863739SMike Smith 
2787914da7d0SScott Long /*
27880b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
27890b94a66eSMike Smith  */
27900b94a66eSMike Smith static int
2791fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr)
27920b94a66eSMike Smith {
27933df780cfSScott Long 	int next, error;
27940b94a66eSMike Smith 
27950b94a66eSMike Smith 	debug_called(2);
27960b94a66eSMike Smith 
2797c3d15322SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
27980b94a66eSMike Smith 	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
27993df780cfSScott Long 		AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
28003df780cfSScott Long 		return (EAGAIN);
28013df780cfSScott Long 	}
28023df780cfSScott Long 
28033df780cfSScott Long 	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
28043df780cfSScott Long 	error = copyout(&sc->aac_aifq[next], uptr,
2805c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
280636e0bf6eSScott Long 	if (error)
280770545d1aSScott Long 		device_printf(sc->aac_dev,
280870545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
28093df780cfSScott Long 	else
28103df780cfSScott Long 		sc->aac_aifq_tail = next;
28113df780cfSScott Long 
2812b3457b51SScott Long 	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
28130b94a66eSMike Smith 	return(error);
28140b94a66eSMike Smith }
281536e0bf6eSScott Long 
2816914da7d0SScott Long /*
281736e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
281836e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
281936e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
282036e0bf6eSScott Long  */
282136e0bf6eSScott Long static int
282236e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
282336e0bf6eSScott Long {
282436e0bf6eSScott Long 	struct aac_query_disk query_disk;
282536e0bf6eSScott Long 	struct aac_container *co;
2826914da7d0SScott Long 	struct aac_disk	*disk;
282736e0bf6eSScott Long 	int error, id;
282836e0bf6eSScott Long 
282936e0bf6eSScott Long 	debug_called(2);
283036e0bf6eSScott Long 
2831914da7d0SScott Long 	disk = NULL;
2832914da7d0SScott Long 
2833914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
2834914da7d0SScott Long 		       sizeof(struct aac_query_disk));
283536e0bf6eSScott Long 	if (error)
283636e0bf6eSScott Long 		return (error);
283736e0bf6eSScott Long 
283836e0bf6eSScott Long 	id = query_disk.ContainerNumber;
283936e0bf6eSScott Long 	if (id == -1)
284036e0bf6eSScott Long 		return (EINVAL);
284136e0bf6eSScott Long 
2842c3d15322SScott Long 	AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
284336e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
284436e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
284536e0bf6eSScott Long 			break;
284636e0bf6eSScott Long 		}
284736e0bf6eSScott Long 
284836e0bf6eSScott Long 	if (co == NULL) {
284936e0bf6eSScott Long 			query_disk.Valid = 0;
285036e0bf6eSScott Long 			query_disk.Locked = 0;
285136e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
285236e0bf6eSScott Long 	} else {
285336e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
285436e0bf6eSScott Long 		query_disk.Valid = 1;
2855914da7d0SScott Long 		query_disk.Locked =
2856914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
285736e0bf6eSScott Long 		query_disk.Deleted = 0;
2858b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
285936e0bf6eSScott Long 		query_disk.Target = disk->unit;
286036e0bf6eSScott Long 		query_disk.Lun = 0;
286136e0bf6eSScott Long 		query_disk.UnMapped = 0;
28627540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
28630b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
286436e0bf6eSScott Long 	}
286536e0bf6eSScott Long 	AAC_LOCK_RELEASE(&sc->aac_container_lock);
286636e0bf6eSScott Long 
2867914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
2868914da7d0SScott Long 			sizeof(struct aac_query_disk));
286936e0bf6eSScott Long 
287036e0bf6eSScott Long 	return (error);
287136e0bf6eSScott Long }
287236e0bf6eSScott Long 
2873fe3cb0e1SScott Long static void
2874fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
2875fe3cb0e1SScott Long {
2876fe3cb0e1SScott Long 	struct aac_fib *fib;
2877fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
2878fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
2879fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
2880fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
2881fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
288270545d1aSScott Long 	struct aac_sim *caminf;
2883fe3cb0e1SScott Long 	device_t child;
2884fe3cb0e1SScott Long 	int i, found, error;
2885fe3cb0e1SScott Long 
2886fe3cb0e1SScott Long 	aac_alloc_sync_fib(sc, &fib, 0);
2887fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
288839ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
2889fe3cb0e1SScott Long 
2890fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
2891fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
2892fe3cb0e1SScott Long 	c_cmd->param = 0;
2893fe3cb0e1SScott Long 
2894fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
2895fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
2896fe3cb0e1SScott Long 	if (error) {
2897fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
2898fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
2899fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2900fe3cb0e1SScott Long 		return;
2901fe3cb0e1SScott Long 	}
2902fe3cb0e1SScott Long 
2903fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
2904fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
2905fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
2906fe3cb0e1SScott Long 		    c_resp->Status);
2907fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2908fe3cb0e1SScott Long 		return;
2909fe3cb0e1SScott Long 	}
2910fe3cb0e1SScott Long 
2911fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
2912fe3cb0e1SScott Long 
2913fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
291439ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
291539ee03c3SScott Long 
2916fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
2917fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
2918fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
2919fe3cb0e1SScott Long 	vmi->ObjId = 0;
2920fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
2921fe3cb0e1SScott Long 
2922fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
2923fe3cb0e1SScott Long 	    sizeof(struct aac_vmioctl));
2924fe3cb0e1SScott Long 	if (error) {
2925fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
2926fe3cb0e1SScott Long 		    error);
2927fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2928fe3cb0e1SScott Long 		return;
2929fe3cb0e1SScott Long 	}
2930fe3cb0e1SScott Long 
2931fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
2932fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
2933fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
2934fe3cb0e1SScott Long 		    vmi_resp->Status);
2935fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
2936fe3cb0e1SScott Long 		return;
2937fe3cb0e1SScott Long 	}
2938fe3cb0e1SScott Long 
2939fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
2940fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
2941fe3cb0e1SScott Long 
2942fe3cb0e1SScott Long 	found = 0;
2943fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
2944fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
2945fe3cb0e1SScott Long 			continue;
2946fe3cb0e1SScott Long 
2947a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
2948a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
2949fe3cb0e1SScott Long 		if (caminf == NULL)
2950fe3cb0e1SScott Long 			continue;
2951fe3cb0e1SScott Long 
2952fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
2953fe3cb0e1SScott Long 		if (child == NULL) {
2954fe3cb0e1SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
2955fe3cb0e1SScott Long 			continue;
2956fe3cb0e1SScott Long 		}
2957fe3cb0e1SScott Long 
2958fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
2959fe3cb0e1SScott Long 		caminf->BusNumber = i;
2960fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
2961fe3cb0e1SScott Long 		caminf->aac_sc = sc;
2962ddb8683eSScott Long 		caminf->sim_dev = child;
2963fe3cb0e1SScott Long 
2964fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
2965fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
296670545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
2967fe3cb0e1SScott Long 
2968fe3cb0e1SScott Long 		found = 1;
2969fe3cb0e1SScott Long 	}
2970fe3cb0e1SScott Long 
2971fe3cb0e1SScott Long 	if (found)
2972fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
2973fe3cb0e1SScott Long 
2974fe3cb0e1SScott Long 	return;
2975fe3cb0e1SScott Long }
2976