xref: /freebsd/sys/dev/aac/aac.c (revision 81b3da088a026fcacbf41f11c1e93e2548bb2b5f)
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  */
367cb209f5SScott Long #define AAC_DRIVER_VERSION		0x02000000
377cb209f5SScott Long #define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
387cb209f5SScott Long #define AAC_DRIVERNAME			"aac"
3935863739SMike Smith 
40f6c4dd3fSScott Long #include "opt_aac.h"
41f6c4dd3fSScott Long 
4236e0bf6eSScott Long /* #include <stddef.h> */
4335863739SMike Smith #include <sys/param.h>
4435863739SMike Smith #include <sys/systm.h>
4535863739SMike Smith #include <sys/malloc.h>
4635863739SMike Smith #include <sys/kernel.h>
4736e0bf6eSScott Long #include <sys/kthread.h>
483d04a9d7SScott Long #include <sys/sysctl.h>
49b3457b51SScott Long #include <sys/poll.h>
50891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
5135863739SMike Smith 
5235863739SMike Smith #include <sys/bus.h>
5335863739SMike Smith #include <sys/conf.h>
5435863739SMike Smith #include <sys/signalvar.h>
550b94a66eSMike Smith #include <sys/time.h>
5636e0bf6eSScott Long #include <sys/eventhandler.h>
577cb209f5SScott Long #include <sys/rman.h>
5835863739SMike Smith 
5935863739SMike Smith #include <machine/bus.h>
60b5f516cdSScott Long #include <sys/bus_dma.h>
6135863739SMike Smith #include <machine/resource.h>
6235863739SMike Smith 
637cb209f5SScott Long #include <dev/pci/pcireg.h>
647cb209f5SScott Long #include <dev/pci/pcivar.h>
657cb209f5SScott Long 
6635863739SMike Smith #include <dev/aac/aacreg.h>
670b0594cdSScott Long #include <sys/aac_ioctl.h>
6835863739SMike Smith #include <dev/aac/aacvar.h>
6935863739SMike Smith #include <dev/aac/aac_tables.h>
7035863739SMike Smith 
7135863739SMike Smith static void	aac_startup(void *arg);
72914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
73cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
74fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
7535863739SMike Smith 
7635863739SMike Smith /* Command Processing */
770b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7835863739SMike Smith static void	aac_complete(void *context, int pending);
7935863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
8035863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
81d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
8270545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
8335863739SMike Smith 
8435863739SMike Smith /* Command Buffer Management */
85cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
86cd481291SScott Long 				   int nseg, int error);
87c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
88c6eafcf2SScott Long 				       int nseg, int error);
890b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
908480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
9135863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
9235863739SMike Smith 
9335863739SMike Smith /* Hardware Interface */
94c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
95c6eafcf2SScott Long 			       int error);
96fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9735863739SMike Smith static int	aac_init(struct aac_softc *sc);
9835863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
99c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
100c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
101c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
102f6c4dd3fSScott Long 				struct aac_command *cm);
103c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
104914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10536e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10636e0bf6eSScott Long 				     struct aac_fib *fib);
10735863739SMike Smith 
108b3457b51SScott Long /* Falcon/PPC interface */
109b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
110b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
111b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
112b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
113b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
114b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
115b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
116a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
117b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
118b3457b51SScott Long 
119b3457b51SScott Long struct aac_interface aac_fa_interface = {
120b3457b51SScott Long 	aac_fa_get_fwstatus,
121b3457b51SScott Long 	aac_fa_qnotify,
122b3457b51SScott Long 	aac_fa_get_istatus,
123b3457b51SScott Long 	aac_fa_clear_istatus,
124b3457b51SScott Long 	aac_fa_set_mailbox,
125a6d35632SScott Long 	aac_fa_get_mailbox,
1267cb209f5SScott Long 	aac_fa_set_interrupts,
1277cb209f5SScott Long 	NULL, NULL, NULL
128b3457b51SScott Long };
129b3457b51SScott Long 
13035863739SMike Smith /* StrongARM interface */
13135863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
13235863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13335863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
13435863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13535863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
136c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
137c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
138a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13935863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
14035863739SMike Smith 
14135863739SMike Smith struct aac_interface aac_sa_interface = {
14235863739SMike Smith 	aac_sa_get_fwstatus,
14335863739SMike Smith 	aac_sa_qnotify,
14435863739SMike Smith 	aac_sa_get_istatus,
14535863739SMike Smith 	aac_sa_clear_istatus,
14635863739SMike Smith 	aac_sa_set_mailbox,
147a6d35632SScott Long 	aac_sa_get_mailbox,
1487cb209f5SScott Long 	aac_sa_set_interrupts,
1497cb209f5SScott Long 	NULL, NULL, NULL
15035863739SMike Smith };
15135863739SMike Smith 
15235863739SMike Smith /* i960Rx interface */
15335863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
15435863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15535863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
15635863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15735863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
158c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
159c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
160a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16135863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
1627cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
1637cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc);
1647cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16535863739SMike Smith 
16635863739SMike Smith struct aac_interface aac_rx_interface = {
16735863739SMike Smith 	aac_rx_get_fwstatus,
16835863739SMike Smith 	aac_rx_qnotify,
16935863739SMike Smith 	aac_rx_get_istatus,
17035863739SMike Smith 	aac_rx_clear_istatus,
17135863739SMike Smith 	aac_rx_set_mailbox,
172a6d35632SScott Long 	aac_rx_get_mailbox,
1737cb209f5SScott Long 	aac_rx_set_interrupts,
1747cb209f5SScott Long 	aac_rx_send_command,
1757cb209f5SScott Long 	aac_rx_get_outb_queue,
1767cb209f5SScott Long 	aac_rx_set_outb_queue
17735863739SMike Smith };
17835863739SMike Smith 
1794afedc31SScott Long /* Rocket/MIPS interface */
1804afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1814afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1824afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1834afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1844afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1854afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1864afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1874afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1884afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1897cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
1907cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc);
1917cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
1924afedc31SScott Long 
1934afedc31SScott Long struct aac_interface aac_rkt_interface = {
1944afedc31SScott Long 	aac_rkt_get_fwstatus,
1954afedc31SScott Long 	aac_rkt_qnotify,
1964afedc31SScott Long 	aac_rkt_get_istatus,
1974afedc31SScott Long 	aac_rkt_clear_istatus,
1984afedc31SScott Long 	aac_rkt_set_mailbox,
1994afedc31SScott Long 	aac_rkt_get_mailbox,
2007cb209f5SScott Long 	aac_rkt_set_interrupts,
2017cb209f5SScott Long 	aac_rkt_send_command,
2027cb209f5SScott Long 	aac_rkt_get_outb_queue,
2037cb209f5SScott Long 	aac_rkt_set_outb_queue
2044afedc31SScott Long };
2054afedc31SScott Long 
20635863739SMike Smith /* Debugging and Diagnostics */
20735863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
2086965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
209c6eafcf2SScott Long 				   u_int32_t code);
21035863739SMike Smith 
21135863739SMike Smith /* Management Interface */
21235863739SMike Smith static d_open_t		aac_open;
21335863739SMike Smith static d_close_t	aac_close;
21435863739SMike Smith static d_ioctl_t	aac_ioctl;
215b3457b51SScott Long static d_poll_t		aac_poll;
216c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
217c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
21836e0bf6eSScott Long 					   struct aac_fib *fib);
219fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
220fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
221fb0c27d7SScott Long static int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
22236e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
2237cb209f5SScott Long static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
2247cb209f5SScott Long static void		aac_ioctl_event(struct aac_softc *sc,
2257cb209f5SScott Long 				        struct aac_event *event, void *arg);
22635863739SMike Smith 
22735863739SMike Smith static struct cdevsw aac_cdevsw = {
228dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
229dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2307ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2317ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2327ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2337ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2347ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
23535863739SMike Smith };
23635863739SMike Smith 
23736e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
23836e0bf6eSScott Long 
2393d04a9d7SScott Long /* sysctl node */
2403d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2413d04a9d7SScott Long 
242914da7d0SScott Long /*
243914da7d0SScott Long  * Device Interface
244914da7d0SScott Long  */
24535863739SMike Smith 
246914da7d0SScott Long /*
24735863739SMike Smith  * Initialise the controller and softc
24835863739SMike Smith  */
24935863739SMike Smith int
25035863739SMike Smith aac_attach(struct aac_softc *sc)
25135863739SMike Smith {
25235863739SMike Smith 	int error, unit;
25335863739SMike Smith 
25435863739SMike Smith 	debug_called(1);
25535863739SMike Smith 
25635863739SMike Smith 	/*
25735863739SMike Smith 	 * Initialise per-controller queues.
25835863739SMike Smith 	 */
2590b94a66eSMike Smith 	aac_initq_free(sc);
2600b94a66eSMike Smith 	aac_initq_ready(sc);
2610b94a66eSMike Smith 	aac_initq_busy(sc);
2620b94a66eSMike Smith 	aac_initq_bio(sc);
26335863739SMike Smith 
26435863739SMike Smith 	/*
26535863739SMike Smith 	 * Initialise command-completion task.
26635863739SMike Smith 	 */
26735863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
26835863739SMike Smith 
26935863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
27035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
27135863739SMike Smith 
27235863739SMike Smith 	/*
273fe94b852SScott Long 	 * Check that the firmware on the card is supported.
274fe94b852SScott Long 	 */
275fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
276fe94b852SScott Long 		return(error);
277fe94b852SScott Long 
278f6b1c44dSScott Long 	/*
279f6b1c44dSScott Long 	 * Initialize locks
280f6b1c44dSScott Long 	 */
281bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
282bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
283bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
284f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
285f6b1c44dSScott Long 
2863df780cfSScott Long 	/* Initialize the local AIF queue pointers */
2873df780cfSScott Long 	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
288cbfd045bSScott Long 
2890b94a66eSMike Smith 	/*
29035863739SMike Smith 	 * Initialise the adapter.
29135863739SMike Smith 	 */
2920b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
29335863739SMike Smith 		return(error);
29435863739SMike Smith 
29535863739SMike Smith 	/*
2967cb209f5SScott Long 	 * Allocate and connect our interrupt.
2977cb209f5SScott Long 	 */
2987cb209f5SScott Long 	sc->aac_irq_rid = 0;
2997cb209f5SScott Long 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
3007cb209f5SScott Long 			   			  &sc->aac_irq_rid,
3017cb209f5SScott Long 			   			  RF_SHAREABLE |
3027cb209f5SScott Long 						  RF_ACTIVE)) == NULL) {
3037cb209f5SScott Long 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
3047cb209f5SScott Long 		return (EINVAL);
3057cb209f5SScott Long 	}
3067cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
3077cb209f5SScott Long 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
3087cb209f5SScott Long 				   INTR_MPSAFE|INTR_TYPE_BIO, aac_new_intr,
3097cb209f5SScott Long 				   sc, &sc->aac_intr)) {
3107cb209f5SScott Long 			device_printf(sc->aac_dev, "can't set up interrupt\n");
3117cb209f5SScott Long 			return (EINVAL);
3127cb209f5SScott Long 		}
3137cb209f5SScott Long 	} else {
3147cb209f5SScott Long 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
3157cb209f5SScott Long 				   INTR_FAST|INTR_TYPE_BIO, aac_fast_intr,
3167cb209f5SScott Long 				   sc, &sc->aac_intr)) {
3177cb209f5SScott Long 			device_printf(sc->aac_dev,
3187cb209f5SScott Long 				      "can't set up FAST interrupt\n");
3197cb209f5SScott Long 			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
3207cb209f5SScott Long 					   INTR_MPSAFE|INTR_TYPE_BIO,
3217cb209f5SScott Long 					   aac_fast_intr, sc, &sc->aac_intr)) {
3227cb209f5SScott Long 				device_printf(sc->aac_dev,
3237cb209f5SScott Long 					     "can't set up MPSAFE interrupt\n");
3247cb209f5SScott Long 				return (EINVAL);
3257cb209f5SScott Long 			}
3267cb209f5SScott Long 		}
3277cb209f5SScott Long 	}
3287cb209f5SScott Long 
3297cb209f5SScott Long 	/*
33035863739SMike Smith 	 * Print a little information about the controller.
33135863739SMike Smith 	 */
33235863739SMike Smith 	aac_describe_controller(sc);
33335863739SMike Smith 
33435863739SMike Smith 	/*
335ae543596SScott Long 	 * Register to probe our containers later.
336ae543596SScott Long 	 */
33735863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
33835863739SMike Smith 	sc->aac_ich.ich_arg = sc;
33935863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
340914da7d0SScott Long 		device_printf(sc->aac_dev,
341914da7d0SScott Long 			      "can't establish configuration hook\n");
34235863739SMike Smith 		return(ENXIO);
34335863739SMike Smith 	}
34435863739SMike Smith 
34535863739SMike Smith 	/*
34635863739SMike Smith 	 * Make the control device.
34735863739SMike Smith 	 */
34835863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3499e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3509e9466baSRobert Watson 				 0640, "aac%d", unit);
351157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3524aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
35335863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
35435863739SMike Smith 
35536e0bf6eSScott Long 	/* Create the AIF thread */
35670545d1aSScott Long 	if (kthread_create((void(*)(void *))aac_command_thread, sc,
357316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
35836e0bf6eSScott Long 		panic("Could not create AIF thread\n");
35936e0bf6eSScott Long 
36036e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3615f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3625f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3635f54d522SScott Long 		device_printf(sc->aac_dev,
3645f54d522SScott Long 			      "shutdown event registration failed\n");
36536e0bf6eSScott Long 
366fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
367a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
36870545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
369fe3cb0e1SScott Long 		aac_get_bus_info(sc);
37070545d1aSScott Long 	}
371fe3cb0e1SScott Long 
37235863739SMike Smith 	return(0);
37335863739SMike Smith }
37435863739SMike Smith 
3757cb209f5SScott Long void
3767cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3777cb209f5SScott Long {
3787cb209f5SScott Long 
3797cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3807cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3817cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3827cb209f5SScott Long 		break;
3837cb209f5SScott Long 	default:
3847cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3857cb209f5SScott Long 		    event->ev_type);
3867cb209f5SScott Long 		break;
3877cb209f5SScott Long 	}
3887cb209f5SScott Long 
3897cb209f5SScott Long 	return;
3907cb209f5SScott Long }
3917cb209f5SScott Long 
392914da7d0SScott Long /*
39335863739SMike Smith  * Probe for containers, create disks.
39435863739SMike Smith  */
39535863739SMike Smith static void
39635863739SMike Smith aac_startup(void *arg)
39735863739SMike Smith {
398914da7d0SScott Long 	struct aac_softc *sc;
399cbfd045bSScott Long 	struct aac_fib *fib;
400cbfd045bSScott Long 	struct aac_mntinfo *mi;
401cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
402795d7dc0SScott Long 	int count = 0, i = 0;
40335863739SMike Smith 
40435863739SMike Smith 	debug_called(1);
40535863739SMike Smith 
406914da7d0SScott Long 	sc = (struct aac_softc *)arg;
407914da7d0SScott Long 
40835863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
40935863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
41035863739SMike Smith 
4117cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
41203b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
413cbfd045bSScott Long 	mi = (struct aac_mntinfo *)&fib->data[0];
414cbfd045bSScott Long 
41535863739SMike Smith 	/* loop over possible containers */
41636e0bf6eSScott Long 	do {
41735863739SMike Smith 		/* request information on this container */
41839ee03c3SScott Long 		bzero(mi, sizeof(struct aac_mntinfo));
41939ee03c3SScott Long 		mi->Command = VM_NameServe;
42039ee03c3SScott Long 		mi->MntType = FT_FILESYS;
421cbfd045bSScott Long 		mi->MntCount = i;
422cbfd045bSScott Long 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
423cbfd045bSScott Long 				 sizeof(struct aac_mntinfo))) {
424795d7dc0SScott Long 			printf("error probing container %d", i);
42535863739SMike Smith 			continue;
42635863739SMike Smith 		}
42735863739SMike Smith 
428cbfd045bSScott Long 		mir = (struct aac_mntinforesp *)&fib->data[0];
429795d7dc0SScott Long 		/* XXX Need to check if count changed */
430795d7dc0SScott Long 		count = mir->MntRespCount;
431cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
43236e0bf6eSScott Long 		i++;
433795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
434cbfd045bSScott Long 
435cbfd045bSScott Long 	aac_release_sync_fib(sc);
4367cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
43735863739SMike Smith 
43835863739SMike Smith 	/* poke the bus to actually attach the child devices */
43935863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
44035863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
44135863739SMike Smith 
44235863739SMike Smith 	/* mark the controller up */
44335863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
44435863739SMike Smith 
44535863739SMike Smith 	/* enable interrupts now */
44635863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
44735863739SMike Smith }
44835863739SMike Smith 
449914da7d0SScott Long /*
450914da7d0SScott Long  * Create a device to respresent a new container
451914da7d0SScott Long  */
452914da7d0SScott Long static void
453cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
454914da7d0SScott Long {
455914da7d0SScott Long 	struct aac_container *co;
456914da7d0SScott Long 	device_t child;
457914da7d0SScott Long 
458914da7d0SScott Long 	/*
459914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
460914da7d0SScott Long 	 * the possible types may never show up.
461914da7d0SScott Long 	 */
462914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
463a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
464a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
465914da7d0SScott Long 		if (co == NULL)
466914da7d0SScott Long 			panic("Out of memory?!\n");
467914da7d0SScott Long 		debug(1, "id %x  name '%.16s'  size %u  type %d",
468914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
469914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
470914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
471914da7d0SScott Long 
472fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
473914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
474914da7d0SScott Long 		else
475914da7d0SScott Long 			device_set_ivars(child, co);
476914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
477914da7d0SScott Long 				mir->MntTable[0].VolType));
478914da7d0SScott Long 		co->co_disk = child;
479914da7d0SScott Long 		co->co_found = f;
480914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
481914da7d0SScott Long 		      sizeof(struct aac_mntobj));
482bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
483914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
484bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
485914da7d0SScott Long 	}
486914da7d0SScott Long }
487914da7d0SScott Long 
488914da7d0SScott Long /*
48935863739SMike Smith  * Free all of the resources associated with (sc)
49035863739SMike Smith  *
49135863739SMike Smith  * Should not be called if the controller is active.
49235863739SMike Smith  */
49335863739SMike Smith void
49435863739SMike Smith aac_free(struct aac_softc *sc)
49535863739SMike Smith {
496ffb37f33SScott Long 
49735863739SMike Smith 	debug_called(1);
49835863739SMike Smith 
49935863739SMike Smith 	/* remove the control device */
50035863739SMike Smith 	if (sc->aac_dev_t != NULL)
50135863739SMike Smith 		destroy_dev(sc->aac_dev_t);
50235863739SMike Smith 
5030b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
5048480cc63SScott Long 	aac_free_commands(sc);
5050b94a66eSMike Smith 	if (sc->aac_fib_dmat)
5060b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
50735863739SMike Smith 
508ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
509ffb37f33SScott Long 
51035863739SMike Smith 	/* destroy the common area */
51135863739SMike Smith 	if (sc->aac_common) {
51235863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
513c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
514c6eafcf2SScott Long 				sc->aac_common_dmamap);
51535863739SMike Smith 	}
5160b94a66eSMike Smith 	if (sc->aac_common_dmat)
5170b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
51835863739SMike Smith 
51935863739SMike Smith 	/* disconnect the interrupt handler */
52035863739SMike Smith 	if (sc->aac_intr)
52135863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
52235863739SMike Smith 	if (sc->aac_irq != NULL)
523c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
524c6eafcf2SScott Long 				     sc->aac_irq);
52535863739SMike Smith 
52635863739SMike Smith 	/* destroy data-transfer DMA tag */
52735863739SMike Smith 	if (sc->aac_buffer_dmat)
52835863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
52935863739SMike Smith 
53035863739SMike Smith 	/* destroy the parent DMA tag */
53135863739SMike Smith 	if (sc->aac_parent_dmat)
53235863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
53335863739SMike Smith 
53435863739SMike Smith 	/* release the register window mapping */
53535863739SMike Smith 	if (sc->aac_regs_resource != NULL)
536914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
537914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
53835863739SMike Smith }
53935863739SMike Smith 
540914da7d0SScott Long /*
54135863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
54235863739SMike Smith  */
54335863739SMike Smith int
54435863739SMike Smith aac_detach(device_t dev)
54535863739SMike Smith {
546914da7d0SScott Long 	struct aac_softc *sc;
54770545d1aSScott Long 	struct aac_container *co;
54870545d1aSScott Long 	struct aac_sim	*sim;
54935863739SMike Smith 	int error;
55035863739SMike Smith 
55135863739SMike Smith 	debug_called(1);
55235863739SMike Smith 
553914da7d0SScott Long 	sc = device_get_softc(dev);
554914da7d0SScott Long 
55535863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
55635863739SMike Smith 		return(EBUSY);
55735863739SMike Smith 
55870545d1aSScott Long 	/* Remove the child containers */
559a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
56070545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
56170545d1aSScott Long 		if (error)
56270545d1aSScott Long 			return (error);
56365ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
564a761a1caSScott Long 		free(co, M_AACBUF);
56570545d1aSScott Long 	}
56670545d1aSScott Long 
56770545d1aSScott Long 	/* Remove the CAM SIMs */
568a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
569a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
57070545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
57170545d1aSScott Long 		if (error)
57270545d1aSScott Long 			return (error);
573a761a1caSScott Long 		free(sim, M_AACBUF);
57470545d1aSScott Long 	}
57570545d1aSScott Long 
57636e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
57736e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
57836e0bf6eSScott Long 		wakeup(sc->aifthread);
57936e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
58036e0bf6eSScott Long 	}
58136e0bf6eSScott Long 
58236e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
58336e0bf6eSScott Long 		panic("Cannot shutdown AIF thread\n");
58436e0bf6eSScott Long 
58535863739SMike Smith 	if ((error = aac_shutdown(dev)))
58635863739SMike Smith 		return(error);
58735863739SMike Smith 
5885f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
5895f54d522SScott Long 
59035863739SMike Smith 	aac_free(sc);
59135863739SMike Smith 
592dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
593dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
594dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
595dc9efde5SScott Long 
59635863739SMike Smith 	return(0);
59735863739SMike Smith }
59835863739SMike Smith 
599914da7d0SScott Long /*
60035863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
60135863739SMike Smith  *
60235863739SMike Smith  * This function is called before detach or system shutdown.
60335863739SMike Smith  *
6040b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
60535863739SMike Smith  * allow shutdown if any device is open.
60635863739SMike Smith  */
60735863739SMike Smith int
60835863739SMike Smith aac_shutdown(device_t dev)
60935863739SMike Smith {
610914da7d0SScott Long 	struct aac_softc *sc;
611cbfd045bSScott Long 	struct aac_fib *fib;
612cbfd045bSScott Long 	struct aac_close_command *cc;
61335863739SMike Smith 
61435863739SMike Smith 	debug_called(1);
61535863739SMike Smith 
616914da7d0SScott Long 	sc = device_get_softc(dev);
617914da7d0SScott Long 
61835863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
61935863739SMike Smith 
62035863739SMike Smith 	/*
62135863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
62235863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
62335863739SMike Smith 	 * We've been closed and all I/O completed already
62435863739SMike Smith 	 */
62535863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
62635863739SMike Smith 
6277cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
62803b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
629cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
630cbfd045bSScott Long 
63139ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
632cbfd045bSScott Long 	cc->Command = VM_CloseAll;
633cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
634cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
635cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
63635863739SMike Smith 		printf("FAILED.\n");
63770545d1aSScott Long 	else
63870545d1aSScott Long 		printf("done\n");
63970545d1aSScott Long #if 0
640914da7d0SScott Long 	else {
641cbfd045bSScott Long 		fib->data[0] = 0;
64236e0bf6eSScott Long 		/*
643914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
64436e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
64536e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
64636e0bf6eSScott Long 		 * driver module with the intent to reload it later.
64736e0bf6eSScott Long 		 */
648cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
649cbfd045bSScott Long 		    fib, 1)) {
65035863739SMike Smith 			printf("FAILED.\n");
65135863739SMike Smith 		} else {
65235863739SMike Smith 			printf("done.\n");
65335863739SMike Smith 		}
65435863739SMike Smith 	}
65570545d1aSScott Long #endif
65635863739SMike Smith 
65735863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
6583576af8fSScott Long 	aac_release_sync_fib(sc);
6597cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
66035863739SMike Smith 
66135863739SMike Smith 	return(0);
66235863739SMike Smith }
66335863739SMike Smith 
664914da7d0SScott Long /*
66535863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
66635863739SMike Smith  */
66735863739SMike Smith int
66835863739SMike Smith aac_suspend(device_t dev)
66935863739SMike Smith {
670914da7d0SScott Long 	struct aac_softc *sc;
67135863739SMike Smith 
67235863739SMike Smith 	debug_called(1);
673914da7d0SScott Long 
674914da7d0SScott Long 	sc = device_get_softc(dev);
675914da7d0SScott Long 
67635863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
67735863739SMike Smith 
67835863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
67935863739SMike Smith 	return(0);
68035863739SMike Smith }
68135863739SMike Smith 
682914da7d0SScott Long /*
68335863739SMike Smith  * Bring the controller back to a state ready for operation.
68435863739SMike Smith  */
68535863739SMike Smith int
68635863739SMike Smith aac_resume(device_t dev)
68735863739SMike Smith {
688914da7d0SScott Long 	struct aac_softc *sc;
68935863739SMike Smith 
69035863739SMike Smith 	debug_called(1);
691914da7d0SScott Long 
692914da7d0SScott Long 	sc = device_get_softc(dev);
693914da7d0SScott Long 
69435863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
69535863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
69635863739SMike Smith 	return(0);
69735863739SMike Smith }
69835863739SMike Smith 
699914da7d0SScott Long /*
7007cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
70135863739SMike Smith  */
70235863739SMike Smith void
7037cb209f5SScott Long aac_new_intr(void *arg)
7047cb209f5SScott Long {
7057cb209f5SScott Long 	struct aac_softc *sc;
7067cb209f5SScott Long 	u_int32_t index, fast;
7077cb209f5SScott Long 	struct aac_command *cm;
7087cb209f5SScott Long 	struct aac_fib *fib;
7097cb209f5SScott Long 	int i;
7107cb209f5SScott Long 
7117cb209f5SScott Long 	debug_called(2);
7127cb209f5SScott Long 
7137cb209f5SScott Long 	sc = (struct aac_softc *)arg;
7147cb209f5SScott Long 
7157cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
7167cb209f5SScott Long 	while (1) {
7177cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
7187cb209f5SScott Long 		if (index == 0xffffffff)
7197cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
7207cb209f5SScott Long 		if (index == 0xffffffff)
7217cb209f5SScott Long 			break;
7227cb209f5SScott Long 		if (index & 2) {
7237cb209f5SScott Long 			if (index == 0xfffffffe) {
7247cb209f5SScott Long 				/* XXX This means that the controller wants
7257cb209f5SScott Long 				 * more work.  Ignore it for now.
7267cb209f5SScott Long 				 */
7277cb209f5SScott Long 				continue;
7287cb209f5SScott Long 			}
7297cb209f5SScott Long 			/* AIF */
7307cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
7317cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
7327cb209f5SScott Long 			if (fib == NULL) {
7337cb209f5SScott Long 				/* If we're really this short on memory,
7347cb209f5SScott Long 				 * hopefully breaking out of the handler will
7357cb209f5SScott Long 				 * allow something to get freed.  This
7367cb209f5SScott Long 				 * actually sucks a whole lot.
7377cb209f5SScott Long 				 */
7387cb209f5SScott Long 				break;
7397cb209f5SScott Long 			}
7407cb209f5SScott Long 			index &= ~2;
7417cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
7427cb209f5SScott Long 				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
7437cb209f5SScott Long 			aac_handle_aif(sc, fib);
7447cb209f5SScott Long 			free(fib, M_AACBUF);
7457cb209f5SScott Long 
7467cb209f5SScott Long 			/*
7477cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
7487cb209f5SScott Long 			 * know that we are done with it.
7497cb209f5SScott Long 			 */
7507cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
7517cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
7527cb209f5SScott Long 		} else {
7537cb209f5SScott Long 			fast = index & 1;
7547cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
7557cb209f5SScott Long 			fib = cm->cm_fib;
7567cb209f5SScott Long 			if (fast) {
7577cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
7587cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
7597cb209f5SScott Long 			}
7607cb209f5SScott Long 			aac_remove_busy(cm);
7617cb209f5SScott Long  			aac_unmap_command(cm);
7627cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
7637cb209f5SScott Long 
7647cb209f5SScott Long 			/* is there a completion handler? */
7657cb209f5SScott Long 			if (cm->cm_complete != NULL) {
7667cb209f5SScott Long 				cm->cm_complete(cm);
7677cb209f5SScott Long 			} else {
7687cb209f5SScott Long 				/* assume that someone is sleeping on this
7697cb209f5SScott Long 				 * command
7707cb209f5SScott Long 				 */
7717cb209f5SScott Long 				wakeup(cm);
7727cb209f5SScott Long 			}
7737cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
7747cb209f5SScott Long 		}
7757cb209f5SScott Long 	}
7767cb209f5SScott Long 	/* see if we can start some more I/O */
7777cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
7787cb209f5SScott Long 		aac_startio(sc);
7797cb209f5SScott Long 
7807cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
7817cb209f5SScott Long }
7827cb209f5SScott Long 
7837cb209f5SScott Long void
7847cb209f5SScott Long aac_fast_intr(void *arg)
78535863739SMike Smith {
786914da7d0SScott Long 	struct aac_softc *sc;
78770545d1aSScott Long 	u_int16_t reason;
78835863739SMike Smith 
78935863739SMike Smith 	debug_called(2);
79035863739SMike Smith 
791914da7d0SScott Long 	sc = (struct aac_softc *)arg;
792914da7d0SScott Long 
793f30ac74cSScott Long 	/*
7949148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
7959148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
7969148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
7979148fa21SScott Long 	 * ugly.
798f30ac74cSScott Long 	 */
79935863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
800f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
801f30ac74cSScott Long 
8029c3a7fceSScott Long 	/* handle completion processing */
8039148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
8049148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
80535863739SMike Smith 
8069148fa21SScott Long 	/* controller wants to talk to us */
8079148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
80870545d1aSScott Long 		/*
8099148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
8109148fa21SScott Long 		 * that start with a NULL.
81170545d1aSScott Long 		 */
8129148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
8139148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
8149148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
81570545d1aSScott Long 
8169148fa21SScott Long 		/*
8179148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
818a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
8199148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
8209148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
8219148fa21SScott Long 		 * if needed.
8229148fa21SScott Long 		 */
82336e0bf6eSScott Long 		wakeup(sc->aifthread);
82436e0bf6eSScott Long 	}
8259148fa21SScott Long }
82635863739SMike Smith 
827c6eafcf2SScott Long /*
828914da7d0SScott Long  * Command Processing
829914da7d0SScott Long  */
83035863739SMike Smith 
831914da7d0SScott Long /*
83235863739SMike Smith  * Start as much queued I/O as possible on the controller
83335863739SMike Smith  */
834fe3cb0e1SScott Long void
83535863739SMike Smith aac_startio(struct aac_softc *sc)
83635863739SMike Smith {
83735863739SMike Smith 	struct aac_command *cm;
838397fa34fSScott Long 	int error;
83935863739SMike Smith 
84035863739SMike Smith 	debug_called(2);
84135863739SMike Smith 
84235863739SMike Smith 	for (;;) {
843914da7d0SScott Long 		/*
844397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
845397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
846397fa34fSScott Long 		 */
847397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
848397fa34fSScott Long 			break;
849397fa34fSScott Long 
850397fa34fSScott Long 		/*
851914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
852914da7d0SScott Long 		 * resources
853914da7d0SScott Long 		 */
85435863739SMike Smith 		cm = aac_dequeue_ready(sc);
85535863739SMike Smith 
856914da7d0SScott Long 		/*
857914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
858914da7d0SScott Long 		 * return)
859914da7d0SScott Long 		 */
8600b94a66eSMike Smith 		if (cm == NULL)
86135863739SMike Smith 			aac_bio_command(sc, &cm);
86235863739SMike Smith 
86335863739SMike Smith 		/* nothing to do? */
86435863739SMike Smith 		if (cm == NULL)
86535863739SMike Smith 			break;
86635863739SMike Smith 
867cd481291SScott Long 		/* don't map more than once */
868cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
8694102d44bSScott Long 			panic("aac: command %p already mapped", cm);
87035863739SMike Smith 
871397fa34fSScott Long 		/*
872397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
873397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
874397fa34fSScott Long 		 * busdma.
875397fa34fSScott Long 		 */
876cd481291SScott Long 		if (cm->cm_datalen != 0) {
877397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
878397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
879397fa34fSScott Long 						cm->cm_datalen,
880cd481291SScott Long 						aac_map_command_sg, cm, 0);
881cd481291SScott Long 			if (error == EINPROGRESS) {
882cd481291SScott Long 				debug(1, "freezing queue\n");
883cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
884cd481291SScott Long 				error = 0;
885614c22b2SScott Long 			} else if (error != 0)
886397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
887397fa34fSScott Long 				      "busdma\n", error);
888397fa34fSScott Long 		} else
8898778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
890cd481291SScott Long 	}
89135863739SMike Smith }
89235863739SMike Smith 
893914da7d0SScott Long /*
89435863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
89535863739SMike Smith  */
89635863739SMike Smith static void
89770545d1aSScott Long aac_command_thread(struct aac_softc *sc)
89835863739SMike Smith {
89935863739SMike Smith 	struct aac_fib *fib;
90035863739SMike Smith 	u_int32_t fib_size;
9019148fa21SScott Long 	int size, retval;
90235863739SMike Smith 
90336e0bf6eSScott Long 	debug_called(2);
90435863739SMike Smith 
905bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
906a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
90736e0bf6eSScott Long 
908a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
909a32a982dSScott Long 
910a32a982dSScott Long 		retval = 0;
911a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
912a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
913a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
91436e0bf6eSScott Long 
9159148fa21SScott Long 		/*
9169148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
9179148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
9189148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
9199148fa21SScott Long 		 */
9209148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
921bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
922a32a982dSScott Long 			aac_alloc_commands(sc);
923bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
9244102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
925a32a982dSScott Long 			aac_startio(sc);
926a32a982dSScott Long 		}
9279148fa21SScott Long 
9289148fa21SScott Long 		/*
9299148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
9309148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
9319148fa21SScott Long 		 * always fire.
9329148fa21SScott Long 		 */
9339148fa21SScott Long 		if (retval == EWOULDBLOCK)
93470545d1aSScott Long 			aac_timeout(sc);
93570545d1aSScott Long 
93670545d1aSScott Long 		/* Check the hardware printf message buffer */
9379148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
93870545d1aSScott Long 			aac_print_printf(sc);
93970545d1aSScott Long 
9409148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
9417cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
9427cb209f5SScott Long 			continue;
9437cb209f5SScott Long 		for (;;) {
9447cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
9457cb209f5SScott Long 					   &fib_size, &fib))
9467cb209f5SScott Long 				break;
94735863739SMike Smith 
94836e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
94936e0bf6eSScott Long 
95035863739SMike Smith 			switch (fib->Header.Command) {
95135863739SMike Smith 			case AifRequest:
95236e0bf6eSScott Long 				aac_handle_aif(sc, fib);
95335863739SMike Smith 				break;
95435863739SMike Smith 			default:
955914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
956914da7d0SScott Long 					      "from controller\n");
95735863739SMike Smith 				break;
95835863739SMike Smith 			}
95935863739SMike Smith 
96036e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
9617cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
96236e0bf6eSScott Long 				break;
9637cb209f5SScott Long 			}
96436e0bf6eSScott Long 
96570545d1aSScott Long 			/* Return the AIF to the controller. */
96636e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
96736e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
96836e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
96936e0bf6eSScott Long 
97036e0bf6eSScott Long 				/* XXX Compute the Size field? */
97136e0bf6eSScott Long 				size = fib->Header.Size;
97236e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
97336e0bf6eSScott Long 					size = sizeof(struct aac_fib);
97436e0bf6eSScott Long 					fib->Header.Size = size;
97536e0bf6eSScott Long 				}
97636e0bf6eSScott Long 				/*
977914da7d0SScott Long 				 * Since we did not generate this command, it
978914da7d0SScott Long 				 * cannot go through the normal
979914da7d0SScott Long 				 * enqueue->startio chain.
98036e0bf6eSScott Long 				 */
981914da7d0SScott Long 				aac_enqueue_response(sc,
982914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
983914da7d0SScott Long 						 fib);
98436e0bf6eSScott Long 			}
98536e0bf6eSScott Long 		}
98636e0bf6eSScott Long 	}
98736e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
988bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
98936e0bf6eSScott Long 	wakeup(sc->aac_dev);
99036e0bf6eSScott Long 
99136e0bf6eSScott Long 	kthread_exit(0);
99235863739SMike Smith }
99335863739SMike Smith 
994914da7d0SScott Long /*
9959c3a7fceSScott Long  * Process completed commands.
99635863739SMike Smith  */
99735863739SMike Smith static void
9989c3a7fceSScott Long aac_complete(void *context, int pending)
99935863739SMike Smith {
10009c3a7fceSScott Long 	struct aac_softc *sc;
100135863739SMike Smith 	struct aac_command *cm;
100235863739SMike Smith 	struct aac_fib *fib;
100335863739SMike Smith 	u_int32_t fib_size;
100435863739SMike Smith 
100535863739SMike Smith 	debug_called(2);
100635863739SMike Smith 
10079c3a7fceSScott Long 	sc = (struct aac_softc *)context;
10089c3a7fceSScott Long 
1009bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1010ae543596SScott Long 
10119c3a7fceSScott Long 	/* pull completed commands off the queue */
101235863739SMike Smith 	for (;;) {
101335863739SMike Smith 		/* look for completed FIBs on our queue */
1014914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1015914da7d0SScott Long 							&fib))
101635863739SMike Smith 			break;	/* nothing to do */
101735863739SMike Smith 
1018ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1019cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
102035863739SMike Smith 		if (cm == NULL) {
102135863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
10229c3a7fceSScott Long 			break;
10239c3a7fceSScott Long 		}
10240b94a66eSMike Smith 		aac_remove_busy(cm);
10257cb209f5SScott Long 
1026ecd1c51fSScott Long  		aac_unmap_command(cm);
102735863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
102835863739SMike Smith 
102935863739SMike Smith 		/* is there a completion handler? */
103035863739SMike Smith 		if (cm->cm_complete != NULL) {
103135863739SMike Smith 			cm->cm_complete(cm);
103235863739SMike Smith 		} else {
103335863739SMike Smith 			/* assume that someone is sleeping on this command */
103435863739SMike Smith 			wakeup(cm);
103535863739SMike Smith 		}
103635863739SMike Smith 	}
10370b94a66eSMike Smith 
10380b94a66eSMike Smith 	/* see if we can start some more I/O */
1039cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
10400b94a66eSMike Smith 	aac_startio(sc);
1041ae543596SScott Long 
1042bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
104335863739SMike Smith }
104435863739SMike Smith 
1045914da7d0SScott Long /*
104635863739SMike Smith  * Handle a bio submitted from a disk device.
104735863739SMike Smith  */
104835863739SMike Smith void
104935863739SMike Smith aac_submit_bio(struct bio *bp)
105035863739SMike Smith {
1051914da7d0SScott Long 	struct aac_disk *ad;
1052914da7d0SScott Long 	struct aac_softc *sc;
105335863739SMike Smith 
105435863739SMike Smith 	debug_called(2);
105535863739SMike Smith 
10567540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1057914da7d0SScott Long 	sc = ad->ad_controller;
1058914da7d0SScott Long 
105935863739SMike Smith 	/* queue the BIO and try to get some work done */
10600b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
106135863739SMike Smith 	aac_startio(sc);
106235863739SMike Smith }
106335863739SMike Smith 
1064914da7d0SScott Long /*
106535863739SMike Smith  * Get a bio and build a command to go with it.
106635863739SMike Smith  */
106735863739SMike Smith static int
106835863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
106935863739SMike Smith {
107035863739SMike Smith 	struct aac_command *cm;
107135863739SMike Smith 	struct aac_fib *fib;
107235863739SMike Smith 	struct aac_disk *ad;
107335863739SMike Smith 	struct bio *bp;
107435863739SMike Smith 
107535863739SMike Smith 	debug_called(2);
107635863739SMike Smith 
107735863739SMike Smith 	/* get the resources we will need */
107835863739SMike Smith 	cm = NULL;
1079a32a982dSScott Long 	bp = NULL;
108035863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
108135863739SMike Smith 		goto fail;
1082a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1083a32a982dSScott Long 		goto fail;
108435863739SMike Smith 
108535863739SMike Smith 	/* fill out the command */
10860b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
10870b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
10880b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
108935863739SMike Smith 	cm->cm_private = bp;
10902b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
109136e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
109235863739SMike Smith 
109335863739SMike Smith 	/* build the FIB */
109435863739SMike Smith 	fib = cm->cm_fib;
1095b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
109635863739SMike Smith 	fib->Header.XferState =
109735863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
109835863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1099f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
110035863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
110135863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1102f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1103f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1104f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
110535863739SMike Smith 
110635863739SMike Smith 	/* build the read/write request */
11077540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1108b85f5808SScott Long 
11097cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
11107cb209f5SScott Long 		struct aac_raw_io *raw;
11117cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
11127cb209f5SScott Long 		fib->Header.Command = RawIo;
11137cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
11147cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
11157cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
11167cb209f5SScott Long 		raw->BpTotal = 0;
11177cb209f5SScott Long 		raw->BpComplete = 0;
11187cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
11197cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
11207cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
11217cb209f5SScott Long 			raw->Flags = 1;
11227cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
11237cb209f5SScott Long 		} else {
11247cb209f5SScott Long 			raw->Flags = 0;
11257cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
11267cb209f5SScott Long 		}
11277cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1128b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
11299e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1130b85f5808SScott Long 			struct aac_blockread *br;
113135863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
113235863739SMike Smith 			br->Command = VM_CtBlockRead;
113335863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
113435863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
113535863739SMike Smith 			br->ByteCount = bp->bio_bcount;
113635863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
113735863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
113835863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
113935863739SMike Smith 		} else {
1140b85f5808SScott Long 			struct aac_blockwrite *bw;
114135863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
114235863739SMike Smith 			bw->Command = VM_CtBlockWrite;
114335863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
114435863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
114535863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1146b85f5808SScott Long 			bw->Stable = CUNSTABLE;
114735863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
114835863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
114935863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
115035863739SMike Smith 		}
1151b85f5808SScott Long 	} else {
1152b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1153b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1154b85f5808SScott Long 			struct aac_blockread64 *br;
1155b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1156b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1157b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1158b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1159b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1160b85f5808SScott Long 			br->Pad = 0;
1161b85f5808SScott Long 			br->Flags = 0;
1162b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
1163b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
1164eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1165b85f5808SScott Long 		} else {
1166b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1167b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1168b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1169b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1170b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1171b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1172b85f5808SScott Long 			bw->Pad = 0;
1173b85f5808SScott Long 			bw->Flags = 0;
1174b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
1175b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
1176eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1177b85f5808SScott Long 		}
1178b85f5808SScott Long 	}
117935863739SMike Smith 
118035863739SMike Smith 	*cmp = cm;
118135863739SMike Smith 	return(0);
118235863739SMike Smith 
118335863739SMike Smith fail:
11847cb209f5SScott Long 	if (bp != NULL)
11857cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
118635863739SMike Smith 	if (cm != NULL)
118735863739SMike Smith 		aac_release_command(cm);
118835863739SMike Smith 	return(ENOMEM);
118935863739SMike Smith }
119035863739SMike Smith 
1191914da7d0SScott Long /*
119235863739SMike Smith  * Handle a bio-instigated command that has been completed.
119335863739SMike Smith  */
119435863739SMike Smith static void
119535863739SMike Smith aac_bio_complete(struct aac_command *cm)
119635863739SMike Smith {
119735863739SMike Smith 	struct aac_blockread_response *brr;
119835863739SMike Smith 	struct aac_blockwrite_response *bwr;
119935863739SMike Smith 	struct bio *bp;
120035863739SMike Smith 	AAC_FSAStatus status;
120135863739SMike Smith 
120235863739SMike Smith 	/* fetch relevant status and then release the command */
120335863739SMike Smith 	bp = (struct bio *)cm->cm_private;
12049e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
120535863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
120635863739SMike Smith 		status = brr->Status;
120735863739SMike Smith 	} else {
120835863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
120935863739SMike Smith 		status = bwr->Status;
121035863739SMike Smith 	}
121135863739SMike Smith 	aac_release_command(cm);
121235863739SMike Smith 
121335863739SMike Smith 	/* fix up the bio based on status */
121435863739SMike Smith 	if (status == ST_OK) {
121535863739SMike Smith 		bp->bio_resid = 0;
121635863739SMike Smith 	} else {
121735863739SMike Smith 		bp->bio_error = EIO;
121835863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
12190b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1220914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1221914da7d0SScott Long 						    status);
122235863739SMike Smith 	}
12230b94a66eSMike Smith 	aac_biodone(bp);
122435863739SMike Smith }
122535863739SMike Smith 
1226914da7d0SScott Long /*
122735863739SMike Smith  * Submit a command to the controller, return when it completes.
1228b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1229b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1230d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1231d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1232d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1233d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1234d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
123535863739SMike Smith  */
123635863739SMike Smith static int
1237d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
123835863739SMike Smith {
1239ae543596SScott Long 	struct aac_softc *sc;
1240d8a0a473SScott Long 	int error;
124135863739SMike Smith 
124235863739SMike Smith 	debug_called(2);
124335863739SMike Smith 
1244ae543596SScott Long 	sc = cm->cm_sc;
1245ae543596SScott Long 
124635863739SMike Smith 	/* Put the command on the ready queue and get things going */
124736e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
124835863739SMike Smith 	aac_enqueue_ready(cm);
1249ae543596SScott Long 	aac_startio(sc);
1250ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
125135863739SMike Smith 	return(error);
125235863739SMike Smith }
125335863739SMike Smith 
1254914da7d0SScott Long /*
1255914da7d0SScott Long  *Command Buffer Management
1256914da7d0SScott Long  */
125735863739SMike Smith 
1258914da7d0SScott Long /*
125935863739SMike Smith  * Allocate a command.
126035863739SMike Smith  */
1261fe3cb0e1SScott Long int
126235863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
126335863739SMike Smith {
126435863739SMike Smith 	struct aac_command *cm;
126535863739SMike Smith 
126635863739SMike Smith 	debug_called(3);
126735863739SMike Smith 
1268ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1269b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1270ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1271ae543596SScott Long 			wakeup(sc->aifthread);
1272b85f5808SScott Long 		}
1273ae543596SScott Long 		return (EBUSY);
1274ffb37f33SScott Long 	}
127535863739SMike Smith 
12760b94a66eSMike Smith 	*cmp = cm;
12770b94a66eSMike Smith 	return(0);
12780b94a66eSMike Smith }
12790b94a66eSMike Smith 
1280914da7d0SScott Long /*
12810b94a66eSMike Smith  * Release a command back to the freelist.
12820b94a66eSMike Smith  */
1283fe3cb0e1SScott Long void
12840b94a66eSMike Smith aac_release_command(struct aac_command *cm)
12850b94a66eSMike Smith {
12867cb209f5SScott Long 	struct aac_event *event;
12877cb209f5SScott Long 	struct aac_softc *sc;
12887cb209f5SScott Long 
12890b94a66eSMike Smith 	debug_called(3);
12900b94a66eSMike Smith 
12910b94a66eSMike Smith 	/* (re)initialise the command/FIB */
129235863739SMike Smith 	cm->cm_sgtable = NULL;
129335863739SMike Smith 	cm->cm_flags = 0;
129435863739SMike Smith 	cm->cm_complete = NULL;
129535863739SMike Smith 	cm->cm_private = NULL;
129635863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
129735863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
129835863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
12997cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
130035863739SMike Smith 
130135863739SMike Smith 	/*
130235863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
130335863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
130435863739SMike Smith 	 * initialised here for debugging purposes only.
130535863739SMike Smith 	 */
1306f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1307f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
130835863739SMike Smith 
130935863739SMike Smith 	aac_enqueue_free(cm);
13107cb209f5SScott Long 
13117cb209f5SScott Long 	sc = cm->cm_sc;
13127cb209f5SScott Long 	event = TAILQ_FIRST(&sc->aac_ev_cmfree);
13137cb209f5SScott Long 	if (event != NULL) {
13147cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
13157cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
13167cb209f5SScott Long 	}
131735863739SMike Smith }
131835863739SMike Smith 
1319914da7d0SScott Long /*
13200b94a66eSMike Smith  * Map helper for command/FIB allocation.
132135863739SMike Smith  */
132235863739SMike Smith static void
13230b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
132435863739SMike Smith {
13257cb209f5SScott Long 	uint64_t	*fibphys;
1326914da7d0SScott Long 
13277cb209f5SScott Long 	fibphys = (uint64_t *)arg;
132835863739SMike Smith 
132935863739SMike Smith 	debug_called(3);
133035863739SMike Smith 
1331ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
133235863739SMike Smith }
133335863739SMike Smith 
1334914da7d0SScott Long /*
13350b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
133635863739SMike Smith  */
13370b94a66eSMike Smith static int
13380b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
133935863739SMike Smith {
134035863739SMike Smith 	struct aac_command *cm;
1341ffb37f33SScott Long 	struct aac_fibmap *fm;
13427cb209f5SScott Long 	uint64_t fibphys;
1343ffb37f33SScott Long 	int i, error;
134435863739SMike Smith 
1345a6d35632SScott Long 	debug_called(2);
134635863739SMike Smith 
13477cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1348ffb37f33SScott Long 		return (ENOMEM);
1349ffb37f33SScott Long 
13508480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1351a6d35632SScott Long 	if (fm == NULL)
1352a6d35632SScott Long 		return (ENOMEM);
1353ffb37f33SScott Long 
13540b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1355ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1356ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
135770545d1aSScott Long 		device_printf(sc->aac_dev,
135870545d1aSScott Long 			      "Not enough contiguous memory available.\n");
13598480cc63SScott Long 		free(fm, M_AACBUF);
13600b94a66eSMike Smith 		return (ENOMEM);
136135863739SMike Smith 	}
1362128aa5a0SScott Long 
1363cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1364cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
13657cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1366ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1367128aa5a0SScott Long 
13680b94a66eSMike Smith 	/* initialise constant fields in the command structure */
1369bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
13707cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
13717cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
13728480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1373ffb37f33SScott Long 		fm->aac_commands = cm;
137435863739SMike Smith 		cm->cm_sc = sc;
13757cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
13767cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
13777cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1378cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
137935863739SMike Smith 
1380ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1381ffb37f33SScott Long 					       &cm->cm_datamap)) == 0)
138235863739SMike Smith 			aac_release_command(cm);
1383ffb37f33SScott Long 		else
13848480cc63SScott Long 			break;
13858480cc63SScott Long 		sc->total_fibs++;
138635863739SMike Smith 	}
1387ffb37f33SScott Long 
13888480cc63SScott Long 	if (i > 0) {
1389ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1390a6d35632SScott Long 		debug(1, "total_fibs= %d\n", sc->total_fibs);
1391bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
13920b94a66eSMike Smith 		return (0);
139335863739SMike Smith 	}
139435863739SMike Smith 
1395bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
13968480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
13978480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
13988480cc63SScott Long 	free(fm, M_AACBUF);
13998480cc63SScott Long 	return (ENOMEM);
14008480cc63SScott Long }
14018480cc63SScott Long 
1402914da7d0SScott Long /*
14030b94a66eSMike Smith  * Free FIBs owned by this adapter.
140435863739SMike Smith  */
140535863739SMike Smith static void
14068480cc63SScott Long aac_free_commands(struct aac_softc *sc)
140735863739SMike Smith {
14088480cc63SScott Long 	struct aac_fibmap *fm;
1409ffb37f33SScott Long 	struct aac_command *cm;
141035863739SMike Smith 	int i;
141135863739SMike Smith 
141235863739SMike Smith 	debug_called(1);
141335863739SMike Smith 
14148480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
14158480cc63SScott Long 
14168480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
14178480cc63SScott Long 		/*
14188480cc63SScott Long 		 * We check against total_fibs to handle partially
14198480cc63SScott Long 		 * allocated blocks.
14208480cc63SScott Long 		 */
14217cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1422ffb37f33SScott Long 			cm = fm->aac_commands + i;
1423ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1424ffb37f33SScott Long 		}
1425ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1426ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
14278480cc63SScott Long 		free(fm, M_AACBUF);
14288480cc63SScott Long 	}
142935863739SMike Smith }
143035863739SMike Smith 
1431914da7d0SScott Long /*
143235863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
143335863739SMike Smith  */
143435863739SMike Smith static void
143535863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
143635863739SMike Smith {
1437cd481291SScott Long 	struct aac_softc *sc;
1438914da7d0SScott Long 	struct aac_command *cm;
1439914da7d0SScott Long 	struct aac_fib *fib;
144035863739SMike Smith 	int i;
144135863739SMike Smith 
144235863739SMike Smith 	debug_called(3);
144335863739SMike Smith 
1444914da7d0SScott Long 	cm = (struct aac_command *)arg;
1445cd481291SScott Long 	sc = cm->cm_sc;
1446914da7d0SScott Long 	fib = cm->cm_fib;
1447914da7d0SScott Long 
144835863739SMike Smith 	/* copy into the FIB */
1449b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
14507cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
14517cb209f5SScott Long 			struct aac_sg_tableraw *sg;
14527cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
14537cb209f5SScott Long 			sg->SgCount = nseg;
14547cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
14557cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
14567cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
14577cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
14587cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
14597cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
14607cb209f5SScott Long 			}
14617cb209f5SScott Long 			/* update the FIB size for the s/g count */
14627cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
14637cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1464b85f5808SScott Long 			struct aac_sg_table *sg;
1465b85f5808SScott Long 			sg = cm->cm_sgtable;
146635863739SMike Smith 			sg->SgCount = nseg;
146735863739SMike Smith 			for (i = 0; i < nseg; i++) {
146835863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
146935863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
147035863739SMike Smith 			}
147135863739SMike Smith 			/* update the FIB size for the s/g count */
147235863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1473b85f5808SScott Long 		} else {
1474b85f5808SScott Long 			struct aac_sg_table64 *sg;
1475b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1476b85f5808SScott Long 			sg->SgCount = nseg;
1477b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1478b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1479b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
148035863739SMike Smith 			}
1481b85f5808SScott Long 			/* update the FIB size for the s/g count */
1482b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1483b85f5808SScott Long 		}
1484b85f5808SScott Long 	}
148535863739SMike Smith 
1486cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1487cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
14887cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
14897cb209f5SScott Long 	 * and for the AIF bit
149035863739SMike Smith 	 */
14917cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
14927cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
149335863739SMike Smith 
1494cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1495cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
149635863739SMike Smith 
149735863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1498c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1499c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
150035863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1501c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1502c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
150335863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1504cd481291SScott Long 
15057cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
15067cb209f5SScott Long 		int count = 10000000L;
15077cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
15087cb209f5SScott Long 			if (--count == 0) {
15097cb209f5SScott Long 				aac_unmap_command(cm);
15107cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
15117cb209f5SScott Long 				aac_requeue_ready(cm);
15127cb209f5SScott Long 			}
15137cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
15147cb209f5SScott Long 		}
15157cb209f5SScott Long 	} else {
1516397fa34fSScott Long 		/* Put the FIB on the outbound queue */
15174102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
15184102d44bSScott Long 			aac_unmap_command(cm);
1519397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1520cd481291SScott Long 			aac_requeue_ready(cm);
15214102d44bSScott Long 		}
15227cb209f5SScott Long 	}
1523cd481291SScott Long 
1524cd481291SScott Long 	return;
152535863739SMike Smith }
152635863739SMike Smith 
1527914da7d0SScott Long /*
152835863739SMike Smith  * Unmap a command from controller-visible space.
152935863739SMike Smith  */
153035863739SMike Smith static void
153135863739SMike Smith aac_unmap_command(struct aac_command *cm)
153235863739SMike Smith {
1533914da7d0SScott Long 	struct aac_softc *sc;
153435863739SMike Smith 
153535863739SMike Smith 	debug_called(2);
153635863739SMike Smith 
1537914da7d0SScott Long 	sc = cm->cm_sc;
1538914da7d0SScott Long 
153935863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
154035863739SMike Smith 		return;
154135863739SMike Smith 
154235863739SMike Smith 	if (cm->cm_datalen != 0) {
154335863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1544c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1545c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
154635863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1547c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1548c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
154935863739SMike Smith 
155035863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
155135863739SMike Smith 	}
155235863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
155335863739SMike Smith }
155435863739SMike Smith 
1555914da7d0SScott Long /*
1556914da7d0SScott Long  * Hardware Interface
1557914da7d0SScott Long  */
155835863739SMike Smith 
1559914da7d0SScott Long /*
156035863739SMike Smith  * Initialise the adapter.
156135863739SMike Smith  */
156235863739SMike Smith static void
156335863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
156435863739SMike Smith {
1565914da7d0SScott Long 	struct aac_softc *sc;
156635863739SMike Smith 
156735863739SMike Smith 	debug_called(1);
156835863739SMike Smith 
1569914da7d0SScott Long 	sc = (struct aac_softc *)arg;
1570914da7d0SScott Long 
157135863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
157235863739SMike Smith }
157335863739SMike Smith 
1574a6d35632SScott Long static int
1575a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1576a6d35632SScott Long {
15777cb209f5SScott Long 	u_int32_t major, minor, options, atu_size;
1578a6d35632SScott Long 
1579a6d35632SScott Long 	debug_called(1);
1580a6d35632SScott Long 
1581fe94b852SScott Long 	/*
1582fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1583fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1584fe94b852SScott Long 	 */
1585a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1586fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1587fe94b852SScott Long 				     NULL)) {
1588fe94b852SScott Long 			device_printf(sc->aac_dev,
1589fe94b852SScott Long 				      "Error reading firmware version\n");
1590fe94b852SScott Long 			return (EIO);
1591fe94b852SScott Long 		}
1592fe94b852SScott Long 
1593fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1594a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1595a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1596fe94b852SScott Long 		if (major == 1) {
1597fe94b852SScott Long 			device_printf(sc->aac_dev,
1598fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1599fe94b852SScott Long 			    major, minor);
1600fe94b852SScott Long 			return (EINVAL);
1601fe94b852SScott Long 		}
1602fe94b852SScott Long 	}
1603fe94b852SScott Long 
1604a6d35632SScott Long 	/*
1605a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1606a6d35632SScott Long 	 * work-arounds to enable.
1607a6d35632SScott Long 	 */
1608a6d35632SScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1609a6d35632SScott Long 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1610a6d35632SScott Long 		return (EIO);
1611a6d35632SScott Long 	}
1612a6d35632SScott Long 	options = AAC_GET_MAILBOX(sc, 1);
16137cb209f5SScott Long 	atu_size = AAC_GET_MAILBOX(sc, 2);
1614a6d35632SScott Long 	sc->supported_options = options;
1615a6d35632SScott Long 
1616a6d35632SScott Long 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1617a6d35632SScott Long 	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1618a6d35632SScott Long 		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1619a6d35632SScott Long 	if (options & AAC_SUPPORTED_NONDASD)
1620a6d35632SScott Long 		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1621cd481291SScott Long 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1622cd481291SScott Long 	     && (sizeof(bus_addr_t) > 4)) {
1623a6d35632SScott Long 		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1624a6d35632SScott Long 		sc->flags |= AAC_FLAGS_SG_64BIT;
1625a6d35632SScott Long 	}
16267cb209f5SScott Long 	if ((options & AAC_SUPPORTED_NEW_COMM) && sc->aac_if.aif_send_command)
16277cb209f5SScott Long 		sc->flags |= AAC_FLAGS_NEW_COMM;
16287cb209f5SScott Long 	if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
16297cb209f5SScott Long 		sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1630a6d35632SScott Long 
1631a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
16327cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
16337cb209f5SScott Long 
16347cb209f5SScott Long 	/* Remap mem. resource, if required */
16357cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
16367cb209f5SScott Long 		atu_size > rman_get_size(sc->aac_regs_resource)) {
16377cb209f5SScott Long 		bus_release_resource(
16387cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
16397cb209f5SScott Long 			sc->aac_regs_rid, sc->aac_regs_resource);
16407cb209f5SScott Long 		sc->aac_regs_resource = bus_alloc_resource(
16417cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
16427cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
16437cb209f5SScott Long 		if (sc->aac_regs_resource == NULL) {
16447cb209f5SScott Long 			sc->aac_regs_resource = bus_alloc_resource_any(
16457cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
16467cb209f5SScott Long 				&sc->aac_regs_rid, RF_ACTIVE);
16477cb209f5SScott Long 			if (sc->aac_regs_resource == NULL) {
16487cb209f5SScott Long 				device_printf(sc->aac_dev,
16497cb209f5SScott Long 				    "couldn't allocate register window\n");
16507cb209f5SScott Long 				return (ENXIO);
16517cb209f5SScott Long 			}
16527cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
16537cb209f5SScott Long 		}
16547cb209f5SScott Long 		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
16557cb209f5SScott Long 		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
16567cb209f5SScott Long 	}
16577cb209f5SScott Long 
16587cb209f5SScott Long 	/* Read preferred settings */
16597cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
16607cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
16617cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
16627cb209f5SScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite64)
16637cb209f5SScott Long 			+ sizeof(struct aac_sg_table64)) / sizeof(struct aac_sg_table64);
1664a6d35632SScott Long 	else
16657cb209f5SScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite)
16667cb209f5SScott Long 			+ sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_table);
16677cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
16687cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
16697cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
16707cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
16717cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
16727cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
16737cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
16747cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
16757cb209f5SScott Long 	}
16767cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
16777cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
16787cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1679a6d35632SScott Long 
1680fe94b852SScott Long 	return (0);
1681fe94b852SScott Long }
1682fe94b852SScott Long 
168335863739SMike Smith static int
168435863739SMike Smith aac_init(struct aac_softc *sc)
168535863739SMike Smith {
168635863739SMike Smith 	struct aac_adapter_init	*ip;
168735863739SMike Smith 	time_t then;
1688b88ffdc8SScott Long 	u_int32_t code, qoffset;
1689a6d35632SScott Long 	int error;
169035863739SMike Smith 
169135863739SMike Smith 	debug_called(1);
169235863739SMike Smith 
169335863739SMike Smith 	/*
169435863739SMike Smith 	 * First wait for the adapter to come ready.
169535863739SMike Smith 	 */
16962b3b0f17SScott Long 	then = time_uptime;
169735863739SMike Smith 	do {
169835863739SMike Smith 		code = AAC_GET_FWSTATUS(sc);
169935863739SMike Smith 		if (code & AAC_SELF_TEST_FAILED) {
170035863739SMike Smith 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
170135863739SMike Smith 			return(ENXIO);
170235863739SMike Smith 		}
170335863739SMike Smith 		if (code & AAC_KERNEL_PANIC) {
1704914da7d0SScott Long 			device_printf(sc->aac_dev,
1705914da7d0SScott Long 				      "FATAL: controller kernel panic\n");
170635863739SMike Smith 			return(ENXIO);
170735863739SMike Smith 		}
17082b3b0f17SScott Long 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
1709914da7d0SScott Long 			device_printf(sc->aac_dev,
1710914da7d0SScott Long 				      "FATAL: controller not coming ready, "
1711c6eafcf2SScott Long 					   "status %x\n", code);
171235863739SMike Smith 			return(ENXIO);
171335863739SMike Smith 		}
171435863739SMike Smith 	} while (!(code & AAC_UP_AND_RUNNING));
171535863739SMike Smith 
1716a6d35632SScott Long 	error = ENOMEM;
1717a6d35632SScott Long 	/*
1718a6d35632SScott Long 	 * Create DMA tag for mapping buffers into controller-addressable space.
1719a6d35632SScott Long 	 */
1720a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1721a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1722a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1723a6d35632SScott Long 			       BUS_SPACE_MAXADDR :
1724a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1725a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1726a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1727a6d35632SScott Long 			       MAXBSIZE,		/* maxsize */
17287cb209f5SScott Long 			       sc->aac_sg_tablesize,	/* nsegments */
1729a6d35632SScott Long 			       MAXBSIZE,		/* maxsegsize */
1730a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1731f6b1c44dSScott Long 			       busdma_lock_mutex,	/* lockfunc */
1732f6b1c44dSScott Long 			       &sc->aac_io_lock,	/* lockfuncarg */
1733a6d35632SScott Long 			       &sc->aac_buffer_dmat)) {
1734a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1735a6d35632SScott Long 		goto out;
1736a6d35632SScott Long 	}
1737a6d35632SScott Long 
1738a6d35632SScott Long 	/*
1739a6d35632SScott Long 	 * Create DMA tag for mapping FIBs into controller-addressable space..
1740a6d35632SScott Long 	 */
1741a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1742a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1743a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1744a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1745a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
1746a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1747a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
17487cb209f5SScott Long 			       sc->aac_max_fibs_alloc *
17497cb209f5SScott Long 			       sc->aac_max_fib_size,  /* maxsize */
1750a6d35632SScott Long 			       1,			/* nsegments */
17517cb209f5SScott Long 			       sc->aac_max_fibs_alloc *
17527cb209f5SScott Long 			       sc->aac_max_fib_size,	/* maxsegsize */
17531248408dSScott Long 			       0,			/* flags */
1754f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
1755a6d35632SScott Long 			       &sc->aac_fib_dmat)) {
1756a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1757a6d35632SScott Long 		goto out;
1758a6d35632SScott Long 	}
1759a6d35632SScott Long 
176035863739SMike Smith 	/*
176135863739SMike Smith 	 * Create DMA tag for the common structure and allocate it.
176235863739SMike Smith 	 */
176335863739SMike Smith 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1764c6eafcf2SScott Long 			       1, 0,			/* algnmnt, boundary */
1765a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1766a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1767a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
176835863739SMike Smith 			       BUS_SPACE_MAXADDR, 	/* highaddr */
176935863739SMike Smith 			       NULL, NULL, 		/* filter, filterarg */
1770ffb37f33SScott Long 			       8192 + sizeof(struct aac_common), /* maxsize */
1771914da7d0SScott Long 			       1,			/* nsegments */
177235863739SMike Smith 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
17731248408dSScott Long 			       0,			/* flags */
1774f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
177535863739SMike Smith 			       &sc->aac_common_dmat)) {
1776914da7d0SScott Long 		device_printf(sc->aac_dev,
1777914da7d0SScott Long 			      "can't allocate common structure DMA tag\n");
1778a6d35632SScott Long 		goto out;
177935863739SMike Smith 	}
1780c6eafcf2SScott Long 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1781c6eafcf2SScott Long 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
178235863739SMike Smith 		device_printf(sc->aac_dev, "can't allocate common structure\n");
1783a6d35632SScott Long 		goto out;
178435863739SMike Smith 	}
1785ffb37f33SScott Long 
1786ffb37f33SScott Long 	/*
1787ffb37f33SScott Long 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1788ffb37f33SScott Long 	 * below address 8192 in physical memory.
1789ffb37f33SScott Long 	 * XXX If the padding is not needed, can it be put to use instead
1790ffb37f33SScott Long 	 * of ignored?
1791ffb37f33SScott Long 	 */
1792cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1793ffb37f33SScott Long 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1794ffb37f33SScott Long 			aac_common_map, sc, 0);
1795ffb37f33SScott Long 
1796ffb37f33SScott Long 	if (sc->aac_common_busaddr < 8192) {
1797eec256deSAlexander Kabaev 		sc->aac_common = (struct aac_common *)
1798eec256deSAlexander Kabaev 		    ((uint8_t *)sc->aac_common + 8192);
1799ffb37f33SScott Long 		sc->aac_common_busaddr += 8192;
1800ffb37f33SScott Long 	}
180135863739SMike Smith 	bzero(sc->aac_common, sizeof(*sc->aac_common));
180235863739SMike Smith 
1803ffb37f33SScott Long 	/* Allocate some FIBs and associated command structs */
1804ffb37f33SScott Long 	TAILQ_INIT(&sc->aac_fibmap_tqh);
18057cb209f5SScott Long 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
18068480cc63SScott Long 				  M_AACBUF, M_WAITOK|M_ZERO);
18078480cc63SScott Long 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1808ffb37f33SScott Long 		if (aac_alloc_commands(sc) != 0)
1809ffb37f33SScott Long 			break;
1810ffb37f33SScott Long 	}
1811ffb37f33SScott Long 	if (sc->total_fibs == 0)
1812a6d35632SScott Long 		goto out;
1813ffb37f33SScott Long 
181435863739SMike Smith 	/*
1815914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1816914da7d0SScott Long 	 * physical location of various important shared data structures.
181735863739SMike Smith 	 */
181835863739SMike Smith 	ip = &sc->aac_common->ac_init;
181935863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18207cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18217cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18227cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18237cb209f5SScott Long 	}
1824f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
182535863739SMike Smith 
1826c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1827c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1828149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
182935863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
183035863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
183135863739SMike Smith 
1832c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1833c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
183435863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
183535863739SMike Smith 
18364b00f859SScott Long 	/*
18374b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18384b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18394b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18404b00f859SScott Long 	 * Round up since the granularity is so high.
18414b00f859SScott Long 	 */
1842f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18434b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18444b00f859SScott Long 		ip->HostPhysMemPages =
18454b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1846204c0befSScott Long 	}
18472b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
184835863739SMike Smith 
18497cb209f5SScott Long 	ip->InitFlags = 0;
18507cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
18517cb209f5SScott Long 		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
18527cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
18537cb209f5SScott Long 	}
18547cb209f5SScott Long 
18557cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
18567cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
18577cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
18587cb209f5SScott Long 
185935863739SMike Smith 	/*
1860c6eafcf2SScott Long 	 * Initialise FIB queues.  Note that it appears that the layout of the
1861c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1862c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
186335863739SMike Smith 	 *
186435863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1865914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1866914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1867914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1868914da7d0SScott Long 	 * does.
186935863739SMike Smith 	 *
1870914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1871914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1872914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1873914da7d0SScott Long 	 * virtue of a table.
187435863739SMike Smith 	 */
1875b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
18760bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
18770bcbebd6SScott Long 	sc->aac_queues =
18780bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1879b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
188035863739SMike Smith 
1881c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1882c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1883c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1884c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1885c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1886c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1887c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1888c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1889c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1890c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1891c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1892c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1893c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1894c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1895c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1896c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1897c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1898c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1899c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1900c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1901c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1902c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1903c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1904c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1905c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1906c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1907c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1908c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1909c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1910c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1911c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1912c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1913c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1914c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1915c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1916c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1917c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1918c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1919c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1920c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1921c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1922c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1923c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1924c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1925c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1926c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1927c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1928c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
192935863739SMike Smith 
193035863739SMike Smith 	/*
193135863739SMike Smith 	 * Do controller-type-specific initialisation
193235863739SMike Smith 	 */
193335863739SMike Smith 	switch (sc->aac_hwif) {
193435863739SMike Smith 	case AAC_HWIF_I960RX:
193535863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
193635863739SMike Smith 		break;
19374afedc31SScott Long 	case AAC_HWIF_RKT:
19384afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
19394afedc31SScott Long 		break;
19404afedc31SScott Long 	default:
19414afedc31SScott Long 		break;
194235863739SMike Smith 	}
194335863739SMike Smith 
194435863739SMike Smith 	/*
194535863739SMike Smith 	 * Give the init structure to the controller.
194635863739SMike Smith 	 */
194735863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1948914da7d0SScott Long 			     sc->aac_common_busaddr +
1949914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1950914da7d0SScott Long 			     NULL)) {
1951914da7d0SScott Long 		device_printf(sc->aac_dev,
1952914da7d0SScott Long 			      "error establishing init structure\n");
1953a6d35632SScott Long 		error = EIO;
1954a6d35632SScott Long 		goto out;
195535863739SMike Smith 	}
195635863739SMike Smith 
1957a6d35632SScott Long 	error = 0;
1958a6d35632SScott Long out:
1959a6d35632SScott Long 	return(error);
196035863739SMike Smith }
196135863739SMike Smith 
1962914da7d0SScott Long /*
196335863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
19647cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
196535863739SMike Smith  */
196635863739SMike Smith static int
196735863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
196835863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
196935863739SMike Smith 		 u_int32_t *sp)
197035863739SMike Smith {
197135863739SMike Smith 	time_t then;
197235863739SMike Smith 	u_int32_t status;
197335863739SMike Smith 
197435863739SMike Smith 	debug_called(3);
197535863739SMike Smith 
197635863739SMike Smith 	/* populate the mailbox */
197735863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
197835863739SMike Smith 
197935863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
198035863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
198135863739SMike Smith 
198235863739SMike Smith 	/* then set it to signal the adapter */
198335863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
198435863739SMike Smith 
198535863739SMike Smith 	/* spin waiting for the command to complete */
19862b3b0f17SScott Long 	then = time_uptime;
198735863739SMike Smith 	do {
19882b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
1989a6d35632SScott Long 			debug(1, "timed out");
199035863739SMike Smith 			return(EIO);
199135863739SMike Smith 		}
199235863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
199335863739SMike Smith 
199435863739SMike Smith 	/* clear the completion flag */
199535863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
199635863739SMike Smith 
199735863739SMike Smith 	/* get the command status */
1998a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
199935863739SMike Smith 	if (sp != NULL)
200035863739SMike Smith 		*sp = status;
20017cb209f5SScott Long 
20027cb209f5SScott Long 	if (status != 0x01)
20037cb209f5SScott Long 		return (-1);
20040b94a66eSMike Smith 	return(0);
200535863739SMike Smith }
200635863739SMike Smith 
2007cbfd045bSScott Long int
200835863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2009cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
201035863739SMike Smith {
201135863739SMike Smith 	debug_called(3);
20127cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
201335863739SMike Smith 
201435863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
201535863739SMike Smith 		return(EINVAL);
201635863739SMike Smith 
201735863739SMike Smith 	/*
201835863739SMike Smith 	 * Set up the sync FIB
201935863739SMike Smith 	 */
2020914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2021914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2022c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
202335863739SMike Smith 	fib->Header.XferState |= xferstate;
202435863739SMike Smith 	fib->Header.Command = command;
202535863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
202635863739SMike Smith 	fib->Header.Size = sizeof(struct aac_fib) + datasize;
202735863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2028b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2029c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2030914da7d0SScott Long 					 offsetof(struct aac_common,
2031914da7d0SScott Long 						  ac_sync_fib);
203235863739SMike Smith 
203335863739SMike Smith 	/*
203435863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
203535863739SMike Smith 	 */
2036914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2037914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
203835863739SMike Smith 		debug(2, "IO error");
203935863739SMike Smith 		return(EIO);
204035863739SMike Smith 	}
204135863739SMike Smith 
204235863739SMike Smith 	return (0);
204335863739SMike Smith }
204435863739SMike Smith 
2045914da7d0SScott Long /*
204635863739SMike Smith  * Adapter-space FIB queue manipulation
204735863739SMike Smith  *
204835863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
204935863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
205035863739SMike Smith  */
205135863739SMike Smith static struct {
205235863739SMike Smith 	int		size;
205335863739SMike Smith 	int		notify;
205435863739SMike Smith } aac_qinfo[] = {
205535863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
205635863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
205735863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
205835863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
205935863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
206035863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
206135863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
206235863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
206335863739SMike Smith };
206435863739SMike Smith 
206535863739SMike Smith /*
2066c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2067c6eafcf2SScott Long  * EBUSY if the queue is full.
206835863739SMike Smith  *
20690b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2070914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2071914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2072c6eafcf2SScott Long  *	 separate queue/notify interface).
207335863739SMike Smith  */
207435863739SMike Smith static int
2075f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
207635863739SMike Smith {
207735863739SMike Smith 	u_int32_t pi, ci;
20789e2e96d8SScott Long 	int error;
2079f6c4dd3fSScott Long 	u_int32_t fib_size;
2080f6c4dd3fSScott Long 	u_int32_t fib_addr;
2081f6c4dd3fSScott Long 
208236e0bf6eSScott Long 	debug_called(3);
208336e0bf6eSScott Long 
2084f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2085f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
208635863739SMike Smith 
208735863739SMike Smith 	/* get the producer/consumer indices */
208835863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
208935863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
209035863739SMike Smith 
209135863739SMike Smith 	/* wrap the queue? */
209235863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
209335863739SMike Smith 		pi = 0;
209435863739SMike Smith 
209535863739SMike Smith 	/* check for queue full */
209635863739SMike Smith 	if ((pi + 1) == ci) {
209735863739SMike Smith 		error = EBUSY;
209835863739SMike Smith 		goto out;
209935863739SMike Smith 	}
210035863739SMike Smith 
2101614c22b2SScott Long 	/*
2102614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2103614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2104614c22b2SScott Long 	 */
2105614c22b2SScott Long 	aac_enqueue_busy(cm);
2106614c22b2SScott Long 
210735863739SMike Smith 	/* populate queue entry */
210835863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
210935863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
211035863739SMike Smith 
211135863739SMike Smith 	/* update producer index */
211235863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
211335863739SMike Smith 
211435863739SMike Smith 	/* notify the adapter if we know how */
211535863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
211635863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
211735863739SMike Smith 
211835863739SMike Smith 	error = 0;
211935863739SMike Smith 
212035863739SMike Smith out:
212135863739SMike Smith 	return(error);
212235863739SMike Smith }
212335863739SMike Smith 
212435863739SMike Smith /*
212536e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
212636e0bf6eSScott Long  * success or ENOENT if the queue is empty.
212735863739SMike Smith  */
212835863739SMike Smith static int
2129c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2130c6eafcf2SScott Long 		struct aac_fib **fib_addr)
213135863739SMike Smith {
213235863739SMike Smith 	u_int32_t pi, ci;
2133149af931SScott Long 	u_int32_t fib_index;
21349e2e96d8SScott Long 	int error;
2135f6c4dd3fSScott Long 	int notify;
213635863739SMike Smith 
213735863739SMike Smith 	debug_called(3);
213835863739SMike Smith 
213935863739SMike Smith 	/* get the producer/consumer indices */
214035863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
214135863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
214235863739SMike Smith 
214335863739SMike Smith 	/* check for queue empty */
214435863739SMike Smith 	if (ci == pi) {
214535863739SMike Smith 		error = ENOENT;
214635863739SMike Smith 		goto out;
214735863739SMike Smith 	}
214835863739SMike Smith 
21497753acd2SScott Long 	/* wrap the pi so the following test works */
21507753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
21517753acd2SScott Long 		pi = 0;
21527753acd2SScott Long 
2153f6c4dd3fSScott Long 	notify = 0;
2154f6c4dd3fSScott Long 	if (ci == pi + 1)
2155f6c4dd3fSScott Long 		notify++;
2156f6c4dd3fSScott Long 
215735863739SMike Smith 	/* wrap the queue? */
215835863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
215935863739SMike Smith 		ci = 0;
216035863739SMike Smith 
216135863739SMike Smith 	/* fetch the entry */
216235863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2163149af931SScott Long 
2164149af931SScott Long 	switch (queue) {
2165149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2166149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2167149af931SScott Long 		/*
2168149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2169149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2170149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2171149af931SScott Long 		 * Therefore, we have to convert it to an index.
2172149af931SScott Long 		 */
2173149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2174149af931SScott Long 			sizeof(struct aac_fib);
2175149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2176149af931SScott Long 		break;
2177149af931SScott Long 
2178149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2179149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2180149af931SScott Long 	{
2181149af931SScott Long 		struct aac_command *cm;
2182149af931SScott Long 
2183149af931SScott Long 		/*
2184149af931SScott Long 		 * As above, an index is used instead of an actual address.
2185149af931SScott Long 		 * Gotta shift the index to account for the fast response
2186149af931SScott Long 		 * bit.  No other correction is needed since this value was
2187149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2188149af931SScott Long 		 * field.
2189149af931SScott Long 		 */
2190149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
21917cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2192149af931SScott Long 		*fib_addr = cm->cm_fib;
219335863739SMike Smith 
2194f30ac74cSScott Long 		/*
2195f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2196149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2197f30ac74cSScott Long 		 */
2198149af931SScott Long 		if (fib_index & 0x01) {
2199f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2200f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2201f30ac74cSScott Long 		}
2202149af931SScott Long 		break;
2203149af931SScott Long 	}
2204149af931SScott Long 	default:
2205149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2206149af931SScott Long 		break;
2207149af931SScott Long 	}
2208149af931SScott Long 
220935863739SMike Smith 	/* update consumer index */
221035863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
221135863739SMike Smith 
221235863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2213f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
221435863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
221535863739SMike Smith 	error = 0;
221635863739SMike Smith 
221735863739SMike Smith out:
221835863739SMike Smith 	return(error);
221935863739SMike Smith }
222035863739SMike Smith 
2221914da7d0SScott Long /*
222236e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
222336e0bf6eSScott Long  */
222436e0bf6eSScott Long static int
222536e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
222636e0bf6eSScott Long {
222736e0bf6eSScott Long 	u_int32_t pi, ci;
22289e2e96d8SScott Long 	int error;
222936e0bf6eSScott Long 	u_int32_t fib_size;
223036e0bf6eSScott Long 	u_int32_t fib_addr;
223136e0bf6eSScott Long 
223236e0bf6eSScott Long 	debug_called(1);
223336e0bf6eSScott Long 
223436e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
223536e0bf6eSScott Long 	fib_size = fib->Header.Size;
223636e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
223736e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
223836e0bf6eSScott Long 
223936e0bf6eSScott Long 	/* get the producer/consumer indices */
224036e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
224136e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
224236e0bf6eSScott Long 
224336e0bf6eSScott Long 	/* wrap the queue? */
224436e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
224536e0bf6eSScott Long 		pi = 0;
224636e0bf6eSScott Long 
224736e0bf6eSScott Long 	/* check for queue full */
224836e0bf6eSScott Long 	if ((pi + 1) == ci) {
224936e0bf6eSScott Long 		error = EBUSY;
225036e0bf6eSScott Long 		goto out;
225136e0bf6eSScott Long 	}
225236e0bf6eSScott Long 
225336e0bf6eSScott Long 	/* populate queue entry */
225436e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
225536e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
225636e0bf6eSScott Long 
225736e0bf6eSScott Long 	/* update producer index */
225836e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
225936e0bf6eSScott Long 
226036e0bf6eSScott Long 	/* notify the adapter if we know how */
226136e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
226236e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
226336e0bf6eSScott Long 
226436e0bf6eSScott Long 	error = 0;
226536e0bf6eSScott Long 
226636e0bf6eSScott Long out:
226736e0bf6eSScott Long 	return(error);
226836e0bf6eSScott Long }
226936e0bf6eSScott Long 
2270914da7d0SScott Long /*
22710b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
22720b94a66eSMike Smith  * and complain about them.
22730b94a66eSMike Smith  */
22740b94a66eSMike Smith static void
22750b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
22760b94a66eSMike Smith {
22770b94a66eSMike Smith 	struct aac_command *cm;
22780b94a66eSMike Smith 	time_t deadline;
227915c37be0SScott Long 	int timedout, code;
22800b94a66eSMike Smith 
2281f6c4dd3fSScott Long 	/*
228270545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2283914da7d0SScott Long 	 * only.
2284914da7d0SScott Long 	 */
228515c37be0SScott Long 	timedout = 0;
22862b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
22870b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2288f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2289f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
22900b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2291914da7d0SScott Long 			device_printf(sc->aac_dev,
2292914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
22932b3b0f17SScott Long 				      cm, (int)(time_uptime-cm->cm_timestamp));
22940b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
229515c37be0SScott Long 			timedout++;
22960b94a66eSMike Smith 		}
22970b94a66eSMike Smith 	}
22980b94a66eSMike Smith 
229915c37be0SScott Long 	if (timedout) {
230015c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
230115c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
230215c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
230315c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
230415c37be0SScott Long 		}
230515c37be0SScott Long 	}
23060b94a66eSMike Smith 	return;
23070b94a66eSMike Smith }
23080b94a66eSMike Smith 
2309914da7d0SScott Long /*
2310914da7d0SScott Long  * Interface Function Vectors
2311914da7d0SScott Long  */
231235863739SMike Smith 
2313914da7d0SScott Long /*
231435863739SMike Smith  * Read the current firmware status word.
231535863739SMike Smith  */
231635863739SMike Smith static int
231735863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
231835863739SMike Smith {
231935863739SMike Smith 	debug_called(3);
232035863739SMike Smith 
232135863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
232235863739SMike Smith }
232335863739SMike Smith 
232435863739SMike Smith static int
232535863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
232635863739SMike Smith {
232735863739SMike Smith 	debug_called(3);
232835863739SMike Smith 
232935863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
233035863739SMike Smith }
233135863739SMike Smith 
2332b3457b51SScott Long static int
2333b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2334b3457b51SScott Long {
2335b3457b51SScott Long 	int val;
2336b3457b51SScott Long 
2337b3457b51SScott Long 	debug_called(3);
2338b3457b51SScott Long 
2339b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2340b3457b51SScott Long 	return (val);
2341b3457b51SScott Long }
2342b3457b51SScott Long 
23434afedc31SScott Long static int
23444afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
23454afedc31SScott Long {
23464afedc31SScott Long 	debug_called(3);
23474afedc31SScott Long 
23484afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
23494afedc31SScott Long }
23504afedc31SScott Long 
2351914da7d0SScott Long /*
235235863739SMike Smith  * Notify the controller of a change in a given queue
235335863739SMike Smith  */
235435863739SMike Smith 
235535863739SMike Smith static void
235635863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
235735863739SMike Smith {
235835863739SMike Smith 	debug_called(3);
235935863739SMike Smith 
236035863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
236135863739SMike Smith }
236235863739SMike Smith 
236335863739SMike Smith static void
236435863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
236535863739SMike Smith {
236635863739SMike Smith 	debug_called(3);
236735863739SMike Smith 
236835863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
236935863739SMike Smith }
237035863739SMike Smith 
2371b3457b51SScott Long static void
2372b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2373b3457b51SScott Long {
2374b3457b51SScott Long 	debug_called(3);
2375b3457b51SScott Long 
2376b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2377b3457b51SScott Long 	AAC_FA_HACK(sc);
2378b3457b51SScott Long }
2379b3457b51SScott Long 
23804afedc31SScott Long static void
23814afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
23824afedc31SScott Long {
23834afedc31SScott Long 	debug_called(3);
23844afedc31SScott Long 
23854afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
23864afedc31SScott Long }
23874afedc31SScott Long 
2388914da7d0SScott Long /*
238935863739SMike Smith  * Get the interrupt reason bits
239035863739SMike Smith  */
239135863739SMike Smith static int
239235863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
239335863739SMike Smith {
239435863739SMike Smith 	debug_called(3);
239535863739SMike Smith 
239635863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
239735863739SMike Smith }
239835863739SMike Smith 
239935863739SMike Smith static int
240035863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
240135863739SMike Smith {
240235863739SMike Smith 	debug_called(3);
240335863739SMike Smith 
240435863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
240535863739SMike Smith }
240635863739SMike Smith 
2407b3457b51SScott Long static int
2408b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2409b3457b51SScott Long {
2410b3457b51SScott Long 	int val;
2411b3457b51SScott Long 
2412b3457b51SScott Long 	debug_called(3);
2413b3457b51SScott Long 
2414b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2415b3457b51SScott Long 	return (val);
2416b3457b51SScott Long }
2417b3457b51SScott Long 
24184afedc31SScott Long static int
24194afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
24204afedc31SScott Long {
24214afedc31SScott Long 	debug_called(3);
24224afedc31SScott Long 
24234afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
24244afedc31SScott Long }
24254afedc31SScott Long 
2426914da7d0SScott Long /*
242735863739SMike Smith  * Clear some interrupt reason bits
242835863739SMike Smith  */
242935863739SMike Smith static void
243035863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
243135863739SMike Smith {
243235863739SMike Smith 	debug_called(3);
243335863739SMike Smith 
243435863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
243535863739SMike Smith }
243635863739SMike Smith 
243735863739SMike Smith static void
243835863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
243935863739SMike Smith {
244035863739SMike Smith 	debug_called(3);
244135863739SMike Smith 
244235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
244335863739SMike Smith }
244435863739SMike Smith 
2445b3457b51SScott Long static void
2446b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2447b3457b51SScott Long {
2448b3457b51SScott Long 	debug_called(3);
2449b3457b51SScott Long 
2450b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2451b3457b51SScott Long 	AAC_FA_HACK(sc);
2452b3457b51SScott Long }
2453b3457b51SScott Long 
24544afedc31SScott Long static void
24554afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
24564afedc31SScott Long {
24574afedc31SScott Long 	debug_called(3);
24584afedc31SScott Long 
24594afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
24604afedc31SScott Long }
24614afedc31SScott Long 
2462914da7d0SScott Long /*
246335863739SMike Smith  * Populate the mailbox and set the command word
246435863739SMike Smith  */
246535863739SMike Smith static void
246635863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
246735863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
246835863739SMike Smith {
246935863739SMike Smith 	debug_called(4);
247035863739SMike Smith 
247135863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
247235863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
247335863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
247435863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
247535863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
247635863739SMike Smith }
247735863739SMike Smith 
247835863739SMike Smith static void
247935863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
248035863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
248135863739SMike Smith {
248235863739SMike Smith 	debug_called(4);
248335863739SMike Smith 
248435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
248535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
248635863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
248735863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
248835863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
248935863739SMike Smith }
249035863739SMike Smith 
2491b3457b51SScott Long static void
2492b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2493b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2494b3457b51SScott Long {
2495b3457b51SScott Long 	debug_called(4);
2496b3457b51SScott Long 
2497b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2498b3457b51SScott Long 	AAC_FA_HACK(sc);
2499b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2500b3457b51SScott Long 	AAC_FA_HACK(sc);
2501b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2502b3457b51SScott Long 	AAC_FA_HACK(sc);
2503b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2504b3457b51SScott Long 	AAC_FA_HACK(sc);
2505b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2506b3457b51SScott Long 	AAC_FA_HACK(sc);
2507b3457b51SScott Long }
2508b3457b51SScott Long 
25094afedc31SScott Long static void
25104afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25114afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
25124afedc31SScott Long {
25134afedc31SScott Long 	debug_called(4);
25144afedc31SScott Long 
25154afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
25164afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
25174afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
25184afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
25194afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
25204afedc31SScott Long }
25214afedc31SScott Long 
2522914da7d0SScott Long /*
252335863739SMike Smith  * Fetch the immediate command status word
252435863739SMike Smith  */
252535863739SMike Smith static int
2526a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
252735863739SMike Smith {
252835863739SMike Smith 	debug_called(4);
252935863739SMike Smith 
2530a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
253135863739SMike Smith }
253235863739SMike Smith 
253335863739SMike Smith static int
2534a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
253535863739SMike Smith {
253635863739SMike Smith 	debug_called(4);
253735863739SMike Smith 
2538a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
253935863739SMike Smith }
254035863739SMike Smith 
2541b3457b51SScott Long static int
2542a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2543b3457b51SScott Long {
2544b3457b51SScott Long 	int val;
2545b3457b51SScott Long 
2546b3457b51SScott Long 	debug_called(4);
2547b3457b51SScott Long 
2548a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2549b3457b51SScott Long 	return (val);
2550b3457b51SScott Long }
2551b3457b51SScott Long 
25524afedc31SScott Long static int
25534afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
25544afedc31SScott Long {
25554afedc31SScott Long 	debug_called(4);
25564afedc31SScott Long 
25574afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
25584afedc31SScott Long }
25594afedc31SScott Long 
2560914da7d0SScott Long /*
256135863739SMike Smith  * Set/clear interrupt masks
256235863739SMike Smith  */
256335863739SMike Smith static void
256435863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
256535863739SMike Smith {
256635863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
256735863739SMike Smith 
256835863739SMike Smith 	if (enable) {
256935863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
257035863739SMike Smith 	} else {
257135863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
257235863739SMike Smith 	}
257335863739SMike Smith }
257435863739SMike Smith 
257535863739SMike Smith static void
257635863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
257735863739SMike Smith {
257835863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
257935863739SMike Smith 
258035863739SMike Smith 	if (enable) {
25817cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
25827cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
25837cb209f5SScott Long 		else
258435863739SMike Smith 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
258535863739SMike Smith 	} else {
258635863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
258735863739SMike Smith 	}
258835863739SMike Smith }
258935863739SMike Smith 
2590b3457b51SScott Long static void
2591b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2592b3457b51SScott Long {
2593b3457b51SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
2594b3457b51SScott Long 
2595b3457b51SScott Long 	if (enable) {
2596b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2597b3457b51SScott Long 		AAC_FA_HACK(sc);
2598b3457b51SScott Long 	} else {
2599b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2600b3457b51SScott Long 		AAC_FA_HACK(sc);
2601b3457b51SScott Long 	}
2602b3457b51SScott Long }
2603b3457b51SScott Long 
26044afedc31SScott Long static void
26054afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
26064afedc31SScott Long {
26074afedc31SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
26084afedc31SScott Long 
26094afedc31SScott Long 	if (enable) {
26107cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
26117cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
26127cb209f5SScott Long 		else
26134afedc31SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
26144afedc31SScott Long 	} else {
26154afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
26164afedc31SScott Long 	}
26174afedc31SScott Long }
26184afedc31SScott Long 
2619914da7d0SScott Long /*
26207cb209f5SScott Long  * New comm. interface: Send command functions
26217cb209f5SScott Long  */
26227cb209f5SScott Long static int
26237cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
26247cb209f5SScott Long {
26257cb209f5SScott Long 	u_int32_t index, device;
26267cb209f5SScott Long 
26277cb209f5SScott Long 	debug(2, "send command (new comm.)");
26287cb209f5SScott Long 
26297cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RX_IQUE);
26307cb209f5SScott Long 	if (index == 0xffffffffL)
26317cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RX_IQUE);
26327cb209f5SScott Long 	if (index == 0xffffffffL)
26337cb209f5SScott Long 		return index;
26347cb209f5SScott Long 	aac_enqueue_busy(cm);
26357cb209f5SScott Long 	device = index;
26367cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26377cb209f5SScott Long 	device += 4;
26387cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26397cb209f5SScott Long 	device += 4;
26407cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26417cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_IQUE, index);
26427cb209f5SScott Long 	return 0;
26437cb209f5SScott Long }
26447cb209f5SScott Long 
26457cb209f5SScott Long static int
26467cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
26477cb209f5SScott Long {
26487cb209f5SScott Long 	u_int32_t index, device;
26497cb209f5SScott Long 
26507cb209f5SScott Long 	debug(2, "send command (new comm.)");
26517cb209f5SScott Long 
26527cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
26537cb209f5SScott Long 	if (index == 0xffffffffL)
26547cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
26557cb209f5SScott Long 	if (index == 0xffffffffL)
26567cb209f5SScott Long 		return index;
26577cb209f5SScott Long 	aac_enqueue_busy(cm);
26587cb209f5SScott Long 	device = index;
26597cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26607cb209f5SScott Long 	device += 4;
26617cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26627cb209f5SScott Long 	device += 4;
26637cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26647cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
26657cb209f5SScott Long 	return 0;
26667cb209f5SScott Long }
26677cb209f5SScott Long 
26687cb209f5SScott Long /*
26697cb209f5SScott Long  * New comm. interface: get, set outbound queue index
26707cb209f5SScott Long  */
26717cb209f5SScott Long static int
26727cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
26737cb209f5SScott Long {
26747cb209f5SScott Long 	debug_called(3);
26757cb209f5SScott Long 
26767cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RX_OQUE));
26777cb209f5SScott Long }
26787cb209f5SScott Long 
26797cb209f5SScott Long static int
26807cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
26817cb209f5SScott Long {
26827cb209f5SScott Long 	debug_called(3);
26837cb209f5SScott Long 
26847cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
26857cb209f5SScott Long }
26867cb209f5SScott Long 
26877cb209f5SScott Long static void
26887cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
26897cb209f5SScott Long {
26907cb209f5SScott Long 	debug_called(3);
26917cb209f5SScott Long 
26927cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_OQUE, index);
26937cb209f5SScott Long }
26947cb209f5SScott Long 
26957cb209f5SScott Long static void
26967cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
26977cb209f5SScott Long {
26987cb209f5SScott Long 	debug_called(3);
26997cb209f5SScott Long 
27007cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
27017cb209f5SScott Long }
27027cb209f5SScott Long 
27037cb209f5SScott Long /*
2704914da7d0SScott Long  * Debugging and Diagnostics
2705914da7d0SScott Long  */
270635863739SMike Smith 
2707914da7d0SScott Long /*
270835863739SMike Smith  * Print some information about the controller.
270935863739SMike Smith  */
271035863739SMike Smith static void
271135863739SMike Smith aac_describe_controller(struct aac_softc *sc)
271235863739SMike Smith {
2713cbfd045bSScott Long 	struct aac_fib *fib;
271435863739SMike Smith 	struct aac_adapter_info	*info;
271535863739SMike Smith 
271635863739SMike Smith 	debug_called(2);
271735863739SMike Smith 
271881b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
271903b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2720cbfd045bSScott Long 
2721cbfd045bSScott Long 	fib->data[0] = 0;
2722cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
272335863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2724fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
272581b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
272635863739SMike Smith 		return;
272735863739SMike Smith 	}
272835863739SMike Smith 
2729bd971c49SScott Long 	/* save the kernel revision structure for later use */
2730bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2731bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2732bd971c49SScott Long 
27337cb209f5SScott Long 	device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n",
27347cb209f5SScott Long 		AAC_DRIVER_VERSION >> 24,
27357cb209f5SScott Long 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
27367cb209f5SScott Long 		AAC_DRIVER_VERSION & 0xFF,
27377cb209f5SScott Long 		AAC_DRIVER_BUILD);
27387cb209f5SScott Long 
2739bd971c49SScott Long 	if (bootverbose) {
2740b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2741b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2742c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2743b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2744b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2745b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2746914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2747914da7d0SScott Long 		    info->batteryPlatform));
274835863739SMike Smith 
2749bd971c49SScott Long 		device_printf(sc->aac_dev,
2750bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
275135863739SMike Smith 		    info->KernelRevision.external.comp.major,
275235863739SMike Smith 		    info->KernelRevision.external.comp.minor,
275335863739SMike Smith 		    info->KernelRevision.external.comp.dash,
275436e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
275536e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2756fe3cb0e1SScott Long 
2757a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2758a6d35632SScott Long 			      sc->supported_options,
2759a6d35632SScott Long 			      "\20"
2760a6d35632SScott Long 			      "\1SNAPSHOT"
2761a6d35632SScott Long 			      "\2CLUSTERS"
2762a6d35632SScott Long 			      "\3WCACHE"
2763a6d35632SScott Long 			      "\4DATA64"
2764a6d35632SScott Long 			      "\5HOSTTIME"
2765a6d35632SScott Long 			      "\6RAID50"
2766a6d35632SScott Long 			      "\7WINDOW4GB"
2767a6d35632SScott Long 			      "\10SCSIUPGD"
2768a6d35632SScott Long 			      "\11SOFTERR"
2769a6d35632SScott Long 			      "\12NORECOND"
2770a6d35632SScott Long 			      "\13SGMAP64"
2771a6d35632SScott Long 			      "\14ALARM"
27727cb209f5SScott Long 			      "\15NONDASD"
27737cb209f5SScott Long 			      "\16SCSIMGT"
27747cb209f5SScott Long 			      "\17RAIDSCSI"
27757cb209f5SScott Long 			      "\21ADPTINFO"
27767cb209f5SScott Long 			      "\22NEWCOMM"
27777cb209f5SScott Long 			      "\23ARRAY64BIT"
27787cb209f5SScott Long 			      "\24HEATSENSOR");
2779a6d35632SScott Long 	}
2780bd971c49SScott Long 	aac_release_sync_fib(sc);
278181b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
278235863739SMike Smith }
278335863739SMike Smith 
2784914da7d0SScott Long /*
278535863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
278635863739SMike Smith  * same.
278735863739SMike Smith  */
278835863739SMike Smith static char *
278935863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
279035863739SMike Smith {
279135863739SMike Smith 	int i;
279235863739SMike Smith 
279335863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
279435863739SMike Smith 		if (table[i].code == code)
279535863739SMike Smith 			return(table[i].string);
279635863739SMike Smith 	return(table[i + 1].string);
279735863739SMike Smith }
279835863739SMike Smith 
2799914da7d0SScott Long /*
2800914da7d0SScott Long  * Management Interface
2801914da7d0SScott Long  */
280235863739SMike Smith 
280335863739SMike Smith static int
280489c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
280535863739SMike Smith {
2806914da7d0SScott Long 	struct aac_softc *sc;
280735863739SMike Smith 
280835863739SMike Smith 	debug_called(2);
280935863739SMike Smith 
2810914da7d0SScott Long 	sc = dev->si_drv1;
2811914da7d0SScott Long 
281235863739SMike Smith 	/* Check to make sure the device isn't already open */
281335863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN) {
281435863739SMike Smith 		return EBUSY;
281535863739SMike Smith 	}
281635863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
281735863739SMike Smith 
281835863739SMike Smith 	return 0;
281935863739SMike Smith }
282035863739SMike Smith 
282135863739SMike Smith static int
282289c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
282335863739SMike Smith {
2824914da7d0SScott Long 	struct aac_softc *sc;
282535863739SMike Smith 
282635863739SMike Smith 	debug_called(2);
282735863739SMike Smith 
2828914da7d0SScott Long 	sc = dev->si_drv1;
2829914da7d0SScott Long 
283035863739SMike Smith 	/* Mark this unit as no longer open  */
283135863739SMike Smith 	sc->aac_state &= ~AAC_STATE_OPEN;
283235863739SMike Smith 
283335863739SMike Smith 	return 0;
283435863739SMike Smith }
283535863739SMike Smith 
283635863739SMike Smith static int
283789c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
283835863739SMike Smith {
2839914da7d0SScott Long 	union aac_statrequest *as;
2840914da7d0SScott Long 	struct aac_softc *sc;
28410b94a66eSMike Smith 	int error = 0;
2842b88ffdc8SScott Long 	uint32_t cookie;
284335863739SMike Smith 
284435863739SMike Smith 	debug_called(2);
284535863739SMike Smith 
2846914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2847914da7d0SScott Long 	sc = dev->si_drv1;
2848914da7d0SScott Long 
284935863739SMike Smith 	switch (cmd) {
28500b94a66eSMike Smith 	case AACIO_STATS:
28510b94a66eSMike Smith 		switch (as->as_item) {
28520b94a66eSMike Smith 		case AACQ_FREE:
28530b94a66eSMike Smith 		case AACQ_BIO:
28540b94a66eSMike Smith 		case AACQ_READY:
28550b94a66eSMike Smith 		case AACQ_BUSY:
2856c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2857c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
28580b94a66eSMike Smith 			break;
28590b94a66eSMike Smith 		default:
28600b94a66eSMike Smith 			error = ENOENT;
28610b94a66eSMike Smith 			break;
28620b94a66eSMike Smith 		}
28630b94a66eSMike Smith 	break;
28640b94a66eSMike Smith 
286535863739SMike Smith 	case FSACTL_SENDFIB:
2866fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2867fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
28680b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
286935863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
287035863739SMike Smith 		break;
287135863739SMike Smith 	case FSACTL_AIF_THREAD:
2872fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
28730b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
287435863739SMike Smith 		error = EINVAL;
287535863739SMike Smith 		break;
287635863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2877fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2878fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
28790b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
288035863739SMike Smith 		/*
288135863739SMike Smith 		 * Pass the caller out an AdapterFibContext.
288235863739SMike Smith 		 *
288335863739SMike Smith 		 * Note that because we only support one opener, we
288435863739SMike Smith 		 * basically ignore this.  Set the caller's context to a magic
288535863739SMike Smith 		 * number just in case.
28860b94a66eSMike Smith 		 *
28870b94a66eSMike Smith 		 * The Linux code hands the driver a pointer into kernel space,
28880b94a66eSMike Smith 		 * and then trusts it when the caller hands it back.  Aiee!
2889914da7d0SScott Long 		 * Here, we give it the proc pointer of the per-adapter aif
2890914da7d0SScott Long 		 * thread. It's only used as a sanity check in other calls.
289135863739SMike Smith 		 */
2892b88ffdc8SScott Long 		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2893b88ffdc8SScott Long 		error = copyout(&cookie, arg, sizeof(cookie));
289435863739SMike Smith 		break;
289535863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2896fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2897fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
28980b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2899fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
290035863739SMike Smith 		break;
290135863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2902fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
29030b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
290435863739SMike Smith 		/* don't do anything here */
290535863739SMike Smith 		break;
290635863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2907fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2908fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
29090b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2910fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
291135863739SMike Smith 		break;
291236e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
291336e0bf6eSScott Long 		arg = *(caddr_t*)arg;
291436e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
291536e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
291636e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
291736e0bf6eSScott Long 		break;
291836e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
291936e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2920914da7d0SScott Long 		/*
2921914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2922914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2923914da7d0SScott Long 		 * controller
2924914da7d0SScott Long 		 */
292536e0bf6eSScott Long 		error = 0;
292636e0bf6eSScott Long 		break;
29277cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
29287cb209f5SScott Long 		arg = *(caddr_t*)arg;
29297cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
29307cb209f5SScott Long 		debug(1, "FSACTL_GET_PCI_INFO");
29317cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
29327cb209f5SScott Long 		break;
293335863739SMike Smith 	default:
2934b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
293535863739SMike Smith 		error = EINVAL;
293635863739SMike Smith 		break;
293735863739SMike Smith 	}
293835863739SMike Smith 	return(error);
293935863739SMike Smith }
294035863739SMike Smith 
2941b3457b51SScott Long static int
294289c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2943b3457b51SScott Long {
2944b3457b51SScott Long 	struct aac_softc *sc;
2945b3457b51SScott Long 	int revents;
2946b3457b51SScott Long 
2947b3457b51SScott Long 	sc = dev->si_drv1;
2948b3457b51SScott Long 	revents = 0;
2949b3457b51SScott Long 
2950bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2951b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2952b3457b51SScott Long 		if (sc->aac_aifq_tail != sc->aac_aifq_head)
2953b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2954b3457b51SScott Long 	}
2955bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2956b3457b51SScott Long 
2957b3457b51SScott Long 	if (revents == 0) {
2958b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2959b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2960b3457b51SScott Long 	}
2961b3457b51SScott Long 
2962b3457b51SScott Long 	return (revents);
2963b3457b51SScott Long }
2964b3457b51SScott Long 
29657cb209f5SScott Long static void
29667cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
29677cb209f5SScott Long {
29687cb209f5SScott Long 
29697cb209f5SScott Long 	switch (event->ev_type) {
29707cb209f5SScott Long 	case AAC_EVENT_CMFREE:
29717cb209f5SScott Long 		mtx_lock(&sc->aac_io_lock);
29727cb209f5SScott Long 		if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) {
29737cb209f5SScott Long 			aac_add_event(sc, event);
29747cb209f5SScott Long 			mtx_unlock(&sc->aac_io_lock);
29757cb209f5SScott Long 			return;
29767cb209f5SScott Long 		}
29777cb209f5SScott Long 		free(event, M_AACBUF);
29788eeb2ca6SScott Long 		wakeup(arg);
29797cb209f5SScott Long 		mtx_unlock(&sc->aac_io_lock);
29807cb209f5SScott Long 		break;
29817cb209f5SScott Long 	default:
29827cb209f5SScott Long 		break;
29837cb209f5SScott Long 	}
29847cb209f5SScott Long }
29857cb209f5SScott Long 
2986914da7d0SScott Long /*
298735863739SMike Smith  * Send a FIB supplied from userspace
298835863739SMike Smith  */
298935863739SMike Smith static int
299035863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
299135863739SMike Smith {
299235863739SMike Smith 	struct aac_command *cm;
299335863739SMike Smith 	int size, error;
299435863739SMike Smith 
299535863739SMike Smith 	debug_called(2);
299635863739SMike Smith 
299735863739SMike Smith 	cm = NULL;
299835863739SMike Smith 
299935863739SMike Smith 	/*
300035863739SMike Smith 	 * Get a command
300135863739SMike Smith 	 */
3002bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
300335863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
30047cb209f5SScott Long 		struct aac_event *event;
30057cb209f5SScott Long 
30067cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
30077cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
30087cb209f5SScott Long 		if (event == NULL) {
300935863739SMike Smith 			error = EBUSY;
301035863739SMike Smith 			goto out;
301135863739SMike Smith 		}
30127cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
30137cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
30147cb209f5SScott Long 		event->ev_arg = &cm;
30157cb209f5SScott Long 		aac_add_event(sc, event);
30168eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
30177cb209f5SScott Long 	}
301835863739SMike Smith 
301935863739SMike Smith 	/*
302035863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
302135863739SMike Smith 	 */
3022914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3023914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
302435863739SMike Smith 		goto out;
302535863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
302635863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
3027b88ffdc8SScott Long 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
3028914da7d0SScott Long 			      size, sizeof(struct aac_fib));
302935863739SMike Smith 		size = sizeof(struct aac_fib);
303035863739SMike Smith 	}
303135863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
303235863739SMike Smith 		goto out;
303335863739SMike Smith 	cm->cm_fib->Header.Size = size;
30342b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
303535863739SMike Smith 
303635863739SMike Smith 	/*
303735863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
303835863739SMike Smith 	 */
3039d8a0a473SScott Long 	if ((error = aac_wait_command(cm)) != 0) {
304070545d1aSScott Long 		device_printf(sc->aac_dev,
304170545d1aSScott Long 			      "aac_wait_command return %d\n", error);
304235863739SMike Smith 		goto out;
3043b3457b51SScott Long 	}
304435863739SMike Smith 
304535863739SMike Smith 	/*
304635863739SMike Smith 	 * Copy the FIB and data back out to the caller.
304735863739SMike Smith 	 */
304835863739SMike Smith 	size = cm->cm_fib->Header.Size;
304935863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
3050b88ffdc8SScott Long 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
3051914da7d0SScott Long 			      size, sizeof(struct aac_fib));
305235863739SMike Smith 		size = sizeof(struct aac_fib);
305335863739SMike Smith 	}
305435863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
305535863739SMike Smith 
305635863739SMike Smith out:
3057f6c4dd3fSScott Long 	if (cm != NULL) {
305835863739SMike Smith 		aac_release_command(cm);
3059f6c4dd3fSScott Long 	}
3060ae543596SScott Long 
3061bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
306235863739SMike Smith 	return(error);
306335863739SMike Smith }
306435863739SMike Smith 
3065914da7d0SScott Long /*
306635863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
306736e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
306835863739SMike Smith  */
306935863739SMike Smith static void
307036e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
307135863739SMike Smith {
307236e0bf6eSScott Long 	struct aac_aif_command *aif;
307336e0bf6eSScott Long 	struct aac_container *co, *co_next;
3074cbfd045bSScott Long 	struct aac_mntinfo *mi;
3075cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
307636e0bf6eSScott Long 	u_int16_t rsize;
3077b3457b51SScott Long 	int next, found;
3078795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
307935863739SMike Smith 
308035863739SMike Smith 	debug_called(2);
308135863739SMike Smith 
308236e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
308336e0bf6eSScott Long 	aac_print_aif(sc, aif);
308436e0bf6eSScott Long 
308536e0bf6eSScott Long 	/* Is it an event that we should care about? */
308636e0bf6eSScott Long 	switch (aif->command) {
308736e0bf6eSScott Long 	case AifCmdEventNotify:
308836e0bf6eSScott Long 		switch (aif->data.EN.type) {
308936e0bf6eSScott Long 		case AifEnAddContainer:
309036e0bf6eSScott Long 		case AifEnDeleteContainer:
309136e0bf6eSScott Long 			/*
3092914da7d0SScott Long 			 * A container was added or deleted, but the message
3093914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3094914da7d0SScott Long 			 * containers and sort things out.
309536e0bf6eSScott Long 			 */
309603b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
3097cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
309836e0bf6eSScott Long 			do {
309936e0bf6eSScott Long 				/*
3100914da7d0SScott Long 				 * Ask the controller for its containers one at
3101914da7d0SScott Long 				 * a time.
3102914da7d0SScott Long 				 * XXX What if the controller's list changes
3103914da7d0SScott Long 				 * midway through this enumaration?
310436e0bf6eSScott Long 				 * XXX This should be done async.
310536e0bf6eSScott Long 				 */
310639ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
310739ee03c3SScott Long 				mi->Command = VM_NameServe;
310839ee03c3SScott Long 				mi->MntType = FT_FILESYS;
3109cbfd045bSScott Long 				mi->MntCount = i;
311036e0bf6eSScott Long 				rsize = sizeof(mir);
3111cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
3112cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
3113795d7dc0SScott Long 					printf("Error probing container %d\n",
3114914da7d0SScott Long 					      i);
311536e0bf6eSScott Long 					continue;
311636e0bf6eSScott Long 				}
3117cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
3118795d7dc0SScott Long 				/* XXX Need to check if count changed */
3119795d7dc0SScott Long 				count = mir->MntRespCount;
312036e0bf6eSScott Long 				/*
3121914da7d0SScott Long 				 * Check the container against our list.
3122914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3123914da7d0SScott Long 				 * previous run.
312436e0bf6eSScott Long 				 */
3125cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3126cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
312736e0bf6eSScott Long 					found = 0;
3128914da7d0SScott Long 					TAILQ_FOREACH(co,
3129914da7d0SScott Long 						      &sc->aac_container_tqh,
3130914da7d0SScott Long 						      co_link) {
313136e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3132cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
313336e0bf6eSScott Long 							co->co_found = 1;
313436e0bf6eSScott Long 							found = 1;
313536e0bf6eSScott Long 							break;
313636e0bf6eSScott Long 						}
313736e0bf6eSScott Long 					}
3138914da7d0SScott Long 					/*
3139914da7d0SScott Long 					 * If the container matched, continue
3140914da7d0SScott Long 					 * in the list.
3141914da7d0SScott Long 					 */
314236e0bf6eSScott Long 					if (found) {
314336e0bf6eSScott Long 						i++;
314436e0bf6eSScott Long 						continue;
314536e0bf6eSScott Long 					}
314636e0bf6eSScott Long 
314736e0bf6eSScott Long 					/*
3148914da7d0SScott Long 					 * This is a new container.  Do all the
314970545d1aSScott Long 					 * appropriate things to set it up.
315070545d1aSScott Long 					 */
3151cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
315236e0bf6eSScott Long 					added = 1;
315336e0bf6eSScott Long 				}
315436e0bf6eSScott Long 				i++;
3155795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3156cbfd045bSScott Long 			aac_release_sync_fib(sc);
315736e0bf6eSScott Long 
315836e0bf6eSScott Long 			/*
3159914da7d0SScott Long 			 * Go through our list of containers and see which ones
3160914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3161914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3162914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3163914da7d0SScott Long 			 * the co->co_found field.
316436e0bf6eSScott Long 			 */
316536e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
316636e0bf6eSScott Long 			while (co != NULL) {
316736e0bf6eSScott Long 				if (co->co_found == 0) {
31687cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
31697cb209f5SScott Long 					mtx_lock(&Giant);
3170914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3171914da7d0SScott Long 							    co->co_disk);
31727cb209f5SScott Long 					mtx_unlock(&Giant);
31737cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
317436e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3175bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3176914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3177914da7d0SScott Long 						     co_link);
3178bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3179ba1d57e7SScott Long 					free(co, M_AACBUF);
318036e0bf6eSScott Long 					co = co_next;
318136e0bf6eSScott Long 				} else {
318236e0bf6eSScott Long 					co->co_found = 0;
318336e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
318436e0bf6eSScott Long 				}
318536e0bf6eSScott Long 			}
318636e0bf6eSScott Long 
318736e0bf6eSScott Long 			/* Attach the newly created containers */
31887cb209f5SScott Long 			if (added) {
31897cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
31907cb209f5SScott Long 				mtx_lock(&Giant);
319136e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
31927cb209f5SScott Long 				mtx_unlock(&Giant);
31937cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
31947cb209f5SScott Long 			}
319536e0bf6eSScott Long 
319636e0bf6eSScott Long 			break;
319736e0bf6eSScott Long 
319836e0bf6eSScott Long 		default:
319936e0bf6eSScott Long 			break;
320036e0bf6eSScott Long 		}
320136e0bf6eSScott Long 
320236e0bf6eSScott Long 	default:
320336e0bf6eSScott Long 		break;
320436e0bf6eSScott Long 	}
320536e0bf6eSScott Long 
320636e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3207bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
320835863739SMike Smith 	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
320935863739SMike Smith 	if (next != sc->aac_aifq_tail) {
321035863739SMike Smith 		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
321135863739SMike Smith 		sc->aac_aifq_head = next;
3212b3457b51SScott Long 
3213b3457b51SScott Long 		/* On the off chance that someone is sleeping for an aif... */
321435863739SMike Smith 		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
321535863739SMike Smith 			wakeup(sc->aac_aifq);
3216b3457b51SScott Long 		/* Wakeup any poll()ers */
3217512824f8SSeigo Tanimura 		selwakeuppri(&sc->rcv_select, PRIBIO);
321835863739SMike Smith 	}
3219bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
322036e0bf6eSScott Long 
322136e0bf6eSScott Long 	return;
322235863739SMike Smith }
322335863739SMike Smith 
3224914da7d0SScott Long /*
32250b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
322636e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
322736e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
322836e0bf6eSScott Long  * returning what the card reported.
322935863739SMike Smith  */
323035863739SMike Smith static int
3231fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
323235863739SMike Smith {
323335863739SMike Smith 	struct aac_rev_check rev_check;
323435863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
323535863739SMike Smith 	int error = 0;
323635863739SMike Smith 
323735863739SMike Smith 	debug_called(2);
323835863739SMike Smith 
323935863739SMike Smith 	/*
324035863739SMike Smith 	 * Copyin the revision struct from userspace
324135863739SMike Smith 	 */
3242c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3243c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
324435863739SMike Smith 		return error;
324535863739SMike Smith 	}
324635863739SMike Smith 
3247914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
3248914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
324935863739SMike Smith 
325035863739SMike Smith 	/*
325135863739SMike Smith 	 * Doctor up the response struct.
325235863739SMike Smith 	 */
325335863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3254914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3255914da7d0SScott Long 	    sc->aac_revision.external.ul;
3256914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3257914da7d0SScott Long 	    sc->aac_revision.buildNumber;
325835863739SMike Smith 
3259c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3260c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
326135863739SMike Smith }
326235863739SMike Smith 
3263914da7d0SScott Long /*
326435863739SMike Smith  * Pass the caller the next AIF in their queue
326535863739SMike Smith  */
326635863739SMike Smith static int
3267fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
326835863739SMike Smith {
326935863739SMike Smith 	struct get_adapter_fib_ioctl agf;
32709e2e96d8SScott Long 	int error;
327135863739SMike Smith 
327235863739SMike Smith 	debug_called(2);
327335863739SMike Smith 
327435863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
327535863739SMike Smith 
327635863739SMike Smith 		/*
327735863739SMike Smith 		 * Check the magic number that we gave the caller.
327835863739SMike Smith 		 */
3279b88ffdc8SScott Long 		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
328035863739SMike Smith 			error = EFAULT;
328135863739SMike Smith 		} else {
3282fb0c27d7SScott Long 			error = aac_return_aif(sc, agf.AifFib);
328335863739SMike Smith 			if ((error == EAGAIN) && (agf.Wait)) {
328435863739SMike Smith 				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
328535863739SMike Smith 				while (error == EAGAIN) {
3286914da7d0SScott Long 					error = tsleep(sc->aac_aifq, PRIBIO |
3287914da7d0SScott Long 						       PCATCH, "aacaif", 0);
328835863739SMike Smith 					if (error == 0)
3289914da7d0SScott Long 						error = aac_return_aif(sc,
3290914da7d0SScott Long 						    agf.AifFib);
329135863739SMike Smith 				}
329235863739SMike Smith 				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
329335863739SMike Smith 			}
329435863739SMike Smith 		}
329535863739SMike Smith 	}
329635863739SMike Smith 	return(error);
329735863739SMike Smith }
329835863739SMike Smith 
3299914da7d0SScott Long /*
33000b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
33010b94a66eSMike Smith  */
33020b94a66eSMike Smith static int
3303fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr)
33040b94a66eSMike Smith {
33053df780cfSScott Long 	int next, error;
33060b94a66eSMike Smith 
33070b94a66eSMike Smith 	debug_called(2);
33080b94a66eSMike Smith 
3309bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
33100b94a66eSMike Smith 	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
3311bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
33123df780cfSScott Long 		return (EAGAIN);
33133df780cfSScott Long 	}
33143df780cfSScott Long 
33153df780cfSScott Long 	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
33163df780cfSScott Long 	error = copyout(&sc->aac_aifq[next], uptr,
3317c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
331836e0bf6eSScott Long 	if (error)
331970545d1aSScott Long 		device_printf(sc->aac_dev,
332070545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
33213df780cfSScott Long 	else
33223df780cfSScott Long 		sc->aac_aifq_tail = next;
33233df780cfSScott Long 
3324bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
33250b94a66eSMike Smith 	return(error);
33260b94a66eSMike Smith }
332736e0bf6eSScott Long 
33287cb209f5SScott Long static int
33297cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
33307cb209f5SScott Long {
33317cb209f5SScott Long 	struct aac_pci_info {
33327cb209f5SScott Long 		u_int32_t bus;
33337cb209f5SScott Long 		u_int32_t slot;
33347cb209f5SScott Long 	} pciinf;
33357cb209f5SScott Long 	int error;
33367cb209f5SScott Long 
33377cb209f5SScott Long 	debug_called(2);
33387cb209f5SScott Long 
33397cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
33407cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
33417cb209f5SScott Long 
33427cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
33437cb209f5SScott Long 			sizeof(struct aac_pci_info));
33447cb209f5SScott Long 
33457cb209f5SScott Long 	return (error);
33467cb209f5SScott Long }
33477cb209f5SScott Long 
3348914da7d0SScott Long /*
334936e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
335036e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
335136e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
335236e0bf6eSScott Long  */
335336e0bf6eSScott Long static int
335436e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
335536e0bf6eSScott Long {
335636e0bf6eSScott Long 	struct aac_query_disk query_disk;
335736e0bf6eSScott Long 	struct aac_container *co;
3358914da7d0SScott Long 	struct aac_disk	*disk;
335936e0bf6eSScott Long 	int error, id;
336036e0bf6eSScott Long 
336136e0bf6eSScott Long 	debug_called(2);
336236e0bf6eSScott Long 
3363914da7d0SScott Long 	disk = NULL;
3364914da7d0SScott Long 
3365914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3366914da7d0SScott Long 		       sizeof(struct aac_query_disk));
336736e0bf6eSScott Long 	if (error)
336836e0bf6eSScott Long 		return (error);
336936e0bf6eSScott Long 
337036e0bf6eSScott Long 	id = query_disk.ContainerNumber;
337136e0bf6eSScott Long 	if (id == -1)
337236e0bf6eSScott Long 		return (EINVAL);
337336e0bf6eSScott Long 
3374bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
337536e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
337636e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
337736e0bf6eSScott Long 			break;
337836e0bf6eSScott Long 		}
337936e0bf6eSScott Long 
338036e0bf6eSScott Long 	if (co == NULL) {
338136e0bf6eSScott Long 			query_disk.Valid = 0;
338236e0bf6eSScott Long 			query_disk.Locked = 0;
338336e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
338436e0bf6eSScott Long 	} else {
338536e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
338636e0bf6eSScott Long 		query_disk.Valid = 1;
3387914da7d0SScott Long 		query_disk.Locked =
3388914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
338936e0bf6eSScott Long 		query_disk.Deleted = 0;
3390b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
339136e0bf6eSScott Long 		query_disk.Target = disk->unit;
339236e0bf6eSScott Long 		query_disk.Lun = 0;
339336e0bf6eSScott Long 		query_disk.UnMapped = 0;
33947540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
33950b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
339636e0bf6eSScott Long 	}
3397bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
339836e0bf6eSScott Long 
3399914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3400914da7d0SScott Long 			sizeof(struct aac_query_disk));
340136e0bf6eSScott Long 
340236e0bf6eSScott Long 	return (error);
340336e0bf6eSScott Long }
340436e0bf6eSScott Long 
3405fe3cb0e1SScott Long static void
3406fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3407fe3cb0e1SScott Long {
3408fe3cb0e1SScott Long 	struct aac_fib *fib;
3409fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3410fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3411fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3412fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3413fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
341470545d1aSScott Long 	struct aac_sim *caminf;
3415fe3cb0e1SScott Long 	device_t child;
3416fe3cb0e1SScott Long 	int i, found, error;
3417fe3cb0e1SScott Long 
341803b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3419fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
342039ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3421fe3cb0e1SScott Long 
3422fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3423fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3424fe3cb0e1SScott Long 	c_cmd->param = 0;
3425fe3cb0e1SScott Long 
3426fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3427fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3428fe3cb0e1SScott Long 	if (error) {
3429fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3430fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3431fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3432fe3cb0e1SScott Long 		return;
3433fe3cb0e1SScott Long 	}
3434fe3cb0e1SScott Long 
3435fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3436fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3437fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3438fe3cb0e1SScott Long 		    c_resp->Status);
3439fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3440fe3cb0e1SScott Long 		return;
3441fe3cb0e1SScott Long 	}
3442fe3cb0e1SScott Long 
3443fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3444fe3cb0e1SScott Long 
3445fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
344639ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
344739ee03c3SScott Long 
3448fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3449fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3450fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3451fe3cb0e1SScott Long 	vmi->ObjId = 0;
3452fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3453fe3cb0e1SScott Long 
3454fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3455fe3cb0e1SScott Long 	    sizeof(struct aac_vmioctl));
3456fe3cb0e1SScott Long 	if (error) {
3457fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3458fe3cb0e1SScott Long 		    error);
3459fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3460fe3cb0e1SScott Long 		return;
3461fe3cb0e1SScott Long 	}
3462fe3cb0e1SScott Long 
3463fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3464fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3465fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3466fe3cb0e1SScott Long 		    vmi_resp->Status);
3467fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3468fe3cb0e1SScott Long 		return;
3469fe3cb0e1SScott Long 	}
3470fe3cb0e1SScott Long 
3471fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3472fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
3473fe3cb0e1SScott Long 
3474fe3cb0e1SScott Long 	found = 0;
3475fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3476fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3477fe3cb0e1SScott Long 			continue;
3478fe3cb0e1SScott Long 
3479a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3480a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3481b5f516cdSScott Long 		if (caminf == NULL) {
3482b5f516cdSScott Long 			device_printf(sc->aac_dev,
3483b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3484b5f516cdSScott Long 			break;
34857cb209f5SScott Long 		};
3486fe3cb0e1SScott Long 
3487fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3488fe3cb0e1SScott Long 		if (child == NULL) {
3489b5f516cdSScott Long 			device_printf(sc->aac_dev,
3490b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3491b5f516cdSScott Long 			    i);
3492b5f516cdSScott Long 			free(caminf, M_AACBUF);
3493b5f516cdSScott Long 			break;
3494fe3cb0e1SScott Long 		}
3495fe3cb0e1SScott Long 
3496fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3497fe3cb0e1SScott Long 		caminf->BusNumber = i;
3498fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3499fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3500ddb8683eSScott Long 		caminf->sim_dev = child;
3501fe3cb0e1SScott Long 
3502fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3503fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
350470545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3505fe3cb0e1SScott Long 
3506fe3cb0e1SScott Long 		found = 1;
3507fe3cb0e1SScott Long 	}
3508fe3cb0e1SScott Long 
3509fe3cb0e1SScott Long 	if (found)
3510fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3511fe3cb0e1SScott Long 
3512fe3cb0e1SScott Long 	return;
3513fe3cb0e1SScott Long }
3514