xref: /freebsd/sys/dev/aac/aac.c (revision 8eeb2ca6bfe7f58ceacb02165b50fc39fa369228)
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 
271803b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2719cbfd045bSScott Long 
2720cbfd045bSScott Long 	fib->data[0] = 0;
2721cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
272235863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2723fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
272435863739SMike Smith 		return;
272535863739SMike Smith 	}
272635863739SMike Smith 
2727bd971c49SScott Long 	/* save the kernel revision structure for later use */
2728bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2729bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2730bd971c49SScott Long 
27317cb209f5SScott Long 	device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n",
27327cb209f5SScott Long 		AAC_DRIVER_VERSION >> 24,
27337cb209f5SScott Long 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
27347cb209f5SScott Long 		AAC_DRIVER_VERSION & 0xFF,
27357cb209f5SScott Long 		AAC_DRIVER_BUILD);
27367cb209f5SScott Long 
2737bd971c49SScott Long 	if (bootverbose) {
2738b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2739b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2740c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2741b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2742b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2743b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2744914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2745914da7d0SScott Long 		    info->batteryPlatform));
274635863739SMike Smith 
2747bd971c49SScott Long 		device_printf(sc->aac_dev,
2748bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
274935863739SMike Smith 		    info->KernelRevision.external.comp.major,
275035863739SMike Smith 		    info->KernelRevision.external.comp.minor,
275135863739SMike Smith 		    info->KernelRevision.external.comp.dash,
275236e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
275336e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2754fe3cb0e1SScott Long 
2755a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2756a6d35632SScott Long 			      sc->supported_options,
2757a6d35632SScott Long 			      "\20"
2758a6d35632SScott Long 			      "\1SNAPSHOT"
2759a6d35632SScott Long 			      "\2CLUSTERS"
2760a6d35632SScott Long 			      "\3WCACHE"
2761a6d35632SScott Long 			      "\4DATA64"
2762a6d35632SScott Long 			      "\5HOSTTIME"
2763a6d35632SScott Long 			      "\6RAID50"
2764a6d35632SScott Long 			      "\7WINDOW4GB"
2765a6d35632SScott Long 			      "\10SCSIUPGD"
2766a6d35632SScott Long 			      "\11SOFTERR"
2767a6d35632SScott Long 			      "\12NORECOND"
2768a6d35632SScott Long 			      "\13SGMAP64"
2769a6d35632SScott Long 			      "\14ALARM"
27707cb209f5SScott Long 			      "\15NONDASD"
27717cb209f5SScott Long 			      "\16SCSIMGT"
27727cb209f5SScott Long 			      "\17RAIDSCSI"
27737cb209f5SScott Long 			      "\21ADPTINFO"
27747cb209f5SScott Long 			      "\22NEWCOMM"
27757cb209f5SScott Long 			      "\23ARRAY64BIT"
27767cb209f5SScott Long 			      "\24HEATSENSOR");
2777a6d35632SScott Long 	}
2778bd971c49SScott Long 	aac_release_sync_fib(sc);
277935863739SMike Smith }
278035863739SMike Smith 
2781914da7d0SScott Long /*
278235863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
278335863739SMike Smith  * same.
278435863739SMike Smith  */
278535863739SMike Smith static char *
278635863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
278735863739SMike Smith {
278835863739SMike Smith 	int i;
278935863739SMike Smith 
279035863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
279135863739SMike Smith 		if (table[i].code == code)
279235863739SMike Smith 			return(table[i].string);
279335863739SMike Smith 	return(table[i + 1].string);
279435863739SMike Smith }
279535863739SMike Smith 
2796914da7d0SScott Long /*
2797914da7d0SScott Long  * Management Interface
2798914da7d0SScott Long  */
279935863739SMike Smith 
280035863739SMike Smith static int
280189c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
280235863739SMike Smith {
2803914da7d0SScott Long 	struct aac_softc *sc;
280435863739SMike Smith 
280535863739SMike Smith 	debug_called(2);
280635863739SMike Smith 
2807914da7d0SScott Long 	sc = dev->si_drv1;
2808914da7d0SScott Long 
280935863739SMike Smith 	/* Check to make sure the device isn't already open */
281035863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN) {
281135863739SMike Smith 		return EBUSY;
281235863739SMike Smith 	}
281335863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
281435863739SMike Smith 
281535863739SMike Smith 	return 0;
281635863739SMike Smith }
281735863739SMike Smith 
281835863739SMike Smith static int
281989c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
282035863739SMike Smith {
2821914da7d0SScott Long 	struct aac_softc *sc;
282235863739SMike Smith 
282335863739SMike Smith 	debug_called(2);
282435863739SMike Smith 
2825914da7d0SScott Long 	sc = dev->si_drv1;
2826914da7d0SScott Long 
282735863739SMike Smith 	/* Mark this unit as no longer open  */
282835863739SMike Smith 	sc->aac_state &= ~AAC_STATE_OPEN;
282935863739SMike Smith 
283035863739SMike Smith 	return 0;
283135863739SMike Smith }
283235863739SMike Smith 
283335863739SMike Smith static int
283489c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
283535863739SMike Smith {
2836914da7d0SScott Long 	union aac_statrequest *as;
2837914da7d0SScott Long 	struct aac_softc *sc;
28380b94a66eSMike Smith 	int error = 0;
2839b88ffdc8SScott Long 	uint32_t cookie;
284035863739SMike Smith 
284135863739SMike Smith 	debug_called(2);
284235863739SMike Smith 
2843914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2844914da7d0SScott Long 	sc = dev->si_drv1;
2845914da7d0SScott Long 
284635863739SMike Smith 	switch (cmd) {
28470b94a66eSMike Smith 	case AACIO_STATS:
28480b94a66eSMike Smith 		switch (as->as_item) {
28490b94a66eSMike Smith 		case AACQ_FREE:
28500b94a66eSMike Smith 		case AACQ_BIO:
28510b94a66eSMike Smith 		case AACQ_READY:
28520b94a66eSMike Smith 		case AACQ_BUSY:
2853c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2854c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
28550b94a66eSMike Smith 			break;
28560b94a66eSMike Smith 		default:
28570b94a66eSMike Smith 			error = ENOENT;
28580b94a66eSMike Smith 			break;
28590b94a66eSMike Smith 		}
28600b94a66eSMike Smith 	break;
28610b94a66eSMike Smith 
286235863739SMike Smith 	case FSACTL_SENDFIB:
2863fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2864fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
28650b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
286635863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
286735863739SMike Smith 		break;
286835863739SMike Smith 	case FSACTL_AIF_THREAD:
2869fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
28700b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
287135863739SMike Smith 		error = EINVAL;
287235863739SMike Smith 		break;
287335863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2874fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2875fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
28760b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
287735863739SMike Smith 		/*
287835863739SMike Smith 		 * Pass the caller out an AdapterFibContext.
287935863739SMike Smith 		 *
288035863739SMike Smith 		 * Note that because we only support one opener, we
288135863739SMike Smith 		 * basically ignore this.  Set the caller's context to a magic
288235863739SMike Smith 		 * number just in case.
28830b94a66eSMike Smith 		 *
28840b94a66eSMike Smith 		 * The Linux code hands the driver a pointer into kernel space,
28850b94a66eSMike Smith 		 * and then trusts it when the caller hands it back.  Aiee!
2886914da7d0SScott Long 		 * Here, we give it the proc pointer of the per-adapter aif
2887914da7d0SScott Long 		 * thread. It's only used as a sanity check in other calls.
288835863739SMike Smith 		 */
2889b88ffdc8SScott Long 		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2890b88ffdc8SScott Long 		error = copyout(&cookie, arg, sizeof(cookie));
289135863739SMike Smith 		break;
289235863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2893fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2894fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
28950b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2896fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
289735863739SMike Smith 		break;
289835863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2899fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
29000b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
290135863739SMike Smith 		/* don't do anything here */
290235863739SMike Smith 		break;
290335863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2904fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2905fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
29060b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2907fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
290835863739SMike Smith 		break;
290936e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
291036e0bf6eSScott Long 		arg = *(caddr_t*)arg;
291136e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
291236e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
291336e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
291436e0bf6eSScott Long 		break;
291536e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
291636e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2917914da7d0SScott Long 		/*
2918914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2919914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2920914da7d0SScott Long 		 * controller
2921914da7d0SScott Long 		 */
292236e0bf6eSScott Long 		error = 0;
292336e0bf6eSScott Long 		break;
29247cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
29257cb209f5SScott Long 		arg = *(caddr_t*)arg;
29267cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
29277cb209f5SScott Long 		debug(1, "FSACTL_GET_PCI_INFO");
29287cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
29297cb209f5SScott Long 		break;
293035863739SMike Smith 	default:
2931b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
293235863739SMike Smith 		error = EINVAL;
293335863739SMike Smith 		break;
293435863739SMike Smith 	}
293535863739SMike Smith 	return(error);
293635863739SMike Smith }
293735863739SMike Smith 
2938b3457b51SScott Long static int
293989c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2940b3457b51SScott Long {
2941b3457b51SScott Long 	struct aac_softc *sc;
2942b3457b51SScott Long 	int revents;
2943b3457b51SScott Long 
2944b3457b51SScott Long 	sc = dev->si_drv1;
2945b3457b51SScott Long 	revents = 0;
2946b3457b51SScott Long 
2947bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2948b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2949b3457b51SScott Long 		if (sc->aac_aifq_tail != sc->aac_aifq_head)
2950b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2951b3457b51SScott Long 	}
2952bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2953b3457b51SScott Long 
2954b3457b51SScott Long 	if (revents == 0) {
2955b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2956b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2957b3457b51SScott Long 	}
2958b3457b51SScott Long 
2959b3457b51SScott Long 	return (revents);
2960b3457b51SScott Long }
2961b3457b51SScott Long 
29627cb209f5SScott Long static void
29637cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
29647cb209f5SScott Long {
29657cb209f5SScott Long 
29667cb209f5SScott Long 	switch (event->ev_type) {
29677cb209f5SScott Long 	case AAC_EVENT_CMFREE:
29687cb209f5SScott Long 		mtx_lock(&sc->aac_io_lock);
29697cb209f5SScott Long 		if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) {
29707cb209f5SScott Long 			aac_add_event(sc, event);
29717cb209f5SScott Long 			mtx_unlock(&sc->aac_io_lock);
29727cb209f5SScott Long 			return;
29737cb209f5SScott Long 		}
29747cb209f5SScott Long 		free(event, M_AACBUF);
29758eeb2ca6SScott Long 		wakeup(arg);
29767cb209f5SScott Long 		mtx_unlock(&sc->aac_io_lock);
29777cb209f5SScott Long 		break;
29787cb209f5SScott Long 	default:
29797cb209f5SScott Long 		break;
29807cb209f5SScott Long 	}
29817cb209f5SScott Long }
29827cb209f5SScott Long 
2983914da7d0SScott Long /*
298435863739SMike Smith  * Send a FIB supplied from userspace
298535863739SMike Smith  */
298635863739SMike Smith static int
298735863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
298835863739SMike Smith {
298935863739SMike Smith 	struct aac_command *cm;
299035863739SMike Smith 	int size, error;
299135863739SMike Smith 
299235863739SMike Smith 	debug_called(2);
299335863739SMike Smith 
299435863739SMike Smith 	cm = NULL;
299535863739SMike Smith 
299635863739SMike Smith 	/*
299735863739SMike Smith 	 * Get a command
299835863739SMike Smith 	 */
2999bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
300035863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
30017cb209f5SScott Long 		struct aac_event *event;
30027cb209f5SScott Long 
30037cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
30047cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
30057cb209f5SScott Long 		if (event == NULL) {
300635863739SMike Smith 			error = EBUSY;
300735863739SMike Smith 			goto out;
300835863739SMike Smith 		}
30097cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
30107cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
30117cb209f5SScott Long 		event->ev_arg = &cm;
30127cb209f5SScott Long 		aac_add_event(sc, event);
30138eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
30147cb209f5SScott Long 	}
301535863739SMike Smith 
301635863739SMike Smith 	/*
301735863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
301835863739SMike Smith 	 */
3019914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3020914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
302135863739SMike Smith 		goto out;
302235863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
302335863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
3024b88ffdc8SScott Long 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
3025914da7d0SScott Long 			      size, sizeof(struct aac_fib));
302635863739SMike Smith 		size = sizeof(struct aac_fib);
302735863739SMike Smith 	}
302835863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
302935863739SMike Smith 		goto out;
303035863739SMike Smith 	cm->cm_fib->Header.Size = size;
30312b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
303235863739SMike Smith 
303335863739SMike Smith 	/*
303435863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
303535863739SMike Smith 	 */
3036d8a0a473SScott Long 	if ((error = aac_wait_command(cm)) != 0) {
303770545d1aSScott Long 		device_printf(sc->aac_dev,
303870545d1aSScott Long 			      "aac_wait_command return %d\n", error);
303935863739SMike Smith 		goto out;
3040b3457b51SScott Long 	}
304135863739SMike Smith 
304235863739SMike Smith 	/*
304335863739SMike Smith 	 * Copy the FIB and data back out to the caller.
304435863739SMike Smith 	 */
304535863739SMike Smith 	size = cm->cm_fib->Header.Size;
304635863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
3047b88ffdc8SScott Long 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
3048914da7d0SScott Long 			      size, sizeof(struct aac_fib));
304935863739SMike Smith 		size = sizeof(struct aac_fib);
305035863739SMike Smith 	}
305135863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
305235863739SMike Smith 
305335863739SMike Smith out:
3054f6c4dd3fSScott Long 	if (cm != NULL) {
305535863739SMike Smith 		aac_release_command(cm);
3056f6c4dd3fSScott Long 	}
3057ae543596SScott Long 
3058bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
305935863739SMike Smith 	return(error);
306035863739SMike Smith }
306135863739SMike Smith 
3062914da7d0SScott Long /*
306335863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
306436e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
306535863739SMike Smith  */
306635863739SMike Smith static void
306736e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
306835863739SMike Smith {
306936e0bf6eSScott Long 	struct aac_aif_command *aif;
307036e0bf6eSScott Long 	struct aac_container *co, *co_next;
3071cbfd045bSScott Long 	struct aac_mntinfo *mi;
3072cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
307336e0bf6eSScott Long 	u_int16_t rsize;
3074b3457b51SScott Long 	int next, found;
3075795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
307635863739SMike Smith 
307735863739SMike Smith 	debug_called(2);
307835863739SMike Smith 
307936e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
308036e0bf6eSScott Long 	aac_print_aif(sc, aif);
308136e0bf6eSScott Long 
308236e0bf6eSScott Long 	/* Is it an event that we should care about? */
308336e0bf6eSScott Long 	switch (aif->command) {
308436e0bf6eSScott Long 	case AifCmdEventNotify:
308536e0bf6eSScott Long 		switch (aif->data.EN.type) {
308636e0bf6eSScott Long 		case AifEnAddContainer:
308736e0bf6eSScott Long 		case AifEnDeleteContainer:
308836e0bf6eSScott Long 			/*
3089914da7d0SScott Long 			 * A container was added or deleted, but the message
3090914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3091914da7d0SScott Long 			 * containers and sort things out.
309236e0bf6eSScott Long 			 */
309303b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
3094cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
309536e0bf6eSScott Long 			do {
309636e0bf6eSScott Long 				/*
3097914da7d0SScott Long 				 * Ask the controller for its containers one at
3098914da7d0SScott Long 				 * a time.
3099914da7d0SScott Long 				 * XXX What if the controller's list changes
3100914da7d0SScott Long 				 * midway through this enumaration?
310136e0bf6eSScott Long 				 * XXX This should be done async.
310236e0bf6eSScott Long 				 */
310339ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
310439ee03c3SScott Long 				mi->Command = VM_NameServe;
310539ee03c3SScott Long 				mi->MntType = FT_FILESYS;
3106cbfd045bSScott Long 				mi->MntCount = i;
310736e0bf6eSScott Long 				rsize = sizeof(mir);
3108cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
3109cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
3110795d7dc0SScott Long 					printf("Error probing container %d\n",
3111914da7d0SScott Long 					      i);
311236e0bf6eSScott Long 					continue;
311336e0bf6eSScott Long 				}
3114cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
3115795d7dc0SScott Long 				/* XXX Need to check if count changed */
3116795d7dc0SScott Long 				count = mir->MntRespCount;
311736e0bf6eSScott Long 				/*
3118914da7d0SScott Long 				 * Check the container against our list.
3119914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3120914da7d0SScott Long 				 * previous run.
312136e0bf6eSScott Long 				 */
3122cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3123cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
312436e0bf6eSScott Long 					found = 0;
3125914da7d0SScott Long 					TAILQ_FOREACH(co,
3126914da7d0SScott Long 						      &sc->aac_container_tqh,
3127914da7d0SScott Long 						      co_link) {
312836e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3129cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
313036e0bf6eSScott Long 							co->co_found = 1;
313136e0bf6eSScott Long 							found = 1;
313236e0bf6eSScott Long 							break;
313336e0bf6eSScott Long 						}
313436e0bf6eSScott Long 					}
3135914da7d0SScott Long 					/*
3136914da7d0SScott Long 					 * If the container matched, continue
3137914da7d0SScott Long 					 * in the list.
3138914da7d0SScott Long 					 */
313936e0bf6eSScott Long 					if (found) {
314036e0bf6eSScott Long 						i++;
314136e0bf6eSScott Long 						continue;
314236e0bf6eSScott Long 					}
314336e0bf6eSScott Long 
314436e0bf6eSScott Long 					/*
3145914da7d0SScott Long 					 * This is a new container.  Do all the
314670545d1aSScott Long 					 * appropriate things to set it up.
314770545d1aSScott Long 					 */
3148cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
314936e0bf6eSScott Long 					added = 1;
315036e0bf6eSScott Long 				}
315136e0bf6eSScott Long 				i++;
3152795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3153cbfd045bSScott Long 			aac_release_sync_fib(sc);
315436e0bf6eSScott Long 
315536e0bf6eSScott Long 			/*
3156914da7d0SScott Long 			 * Go through our list of containers and see which ones
3157914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3158914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3159914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3160914da7d0SScott Long 			 * the co->co_found field.
316136e0bf6eSScott Long 			 */
316236e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
316336e0bf6eSScott Long 			while (co != NULL) {
316436e0bf6eSScott Long 				if (co->co_found == 0) {
31657cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
31667cb209f5SScott Long 					mtx_lock(&Giant);
3167914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3168914da7d0SScott Long 							    co->co_disk);
31697cb209f5SScott Long 					mtx_unlock(&Giant);
31707cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
317136e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3172bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3173914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3174914da7d0SScott Long 						     co_link);
3175bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3176ba1d57e7SScott Long 					free(co, M_AACBUF);
317736e0bf6eSScott Long 					co = co_next;
317836e0bf6eSScott Long 				} else {
317936e0bf6eSScott Long 					co->co_found = 0;
318036e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
318136e0bf6eSScott Long 				}
318236e0bf6eSScott Long 			}
318336e0bf6eSScott Long 
318436e0bf6eSScott Long 			/* Attach the newly created containers */
31857cb209f5SScott Long 			if (added) {
31867cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
31877cb209f5SScott Long 				mtx_lock(&Giant);
318836e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
31897cb209f5SScott Long 				mtx_unlock(&Giant);
31907cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
31917cb209f5SScott Long 			}
319236e0bf6eSScott Long 
319336e0bf6eSScott Long 			break;
319436e0bf6eSScott Long 
319536e0bf6eSScott Long 		default:
319636e0bf6eSScott Long 			break;
319736e0bf6eSScott Long 		}
319836e0bf6eSScott Long 
319936e0bf6eSScott Long 	default:
320036e0bf6eSScott Long 		break;
320136e0bf6eSScott Long 	}
320236e0bf6eSScott Long 
320336e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3204bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
320535863739SMike Smith 	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
320635863739SMike Smith 	if (next != sc->aac_aifq_tail) {
320735863739SMike Smith 		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
320835863739SMike Smith 		sc->aac_aifq_head = next;
3209b3457b51SScott Long 
3210b3457b51SScott Long 		/* On the off chance that someone is sleeping for an aif... */
321135863739SMike Smith 		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
321235863739SMike Smith 			wakeup(sc->aac_aifq);
3213b3457b51SScott Long 		/* Wakeup any poll()ers */
3214512824f8SSeigo Tanimura 		selwakeuppri(&sc->rcv_select, PRIBIO);
321535863739SMike Smith 	}
3216bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
321736e0bf6eSScott Long 
321836e0bf6eSScott Long 	return;
321935863739SMike Smith }
322035863739SMike Smith 
3221914da7d0SScott Long /*
32220b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
322336e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
322436e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
322536e0bf6eSScott Long  * returning what the card reported.
322635863739SMike Smith  */
322735863739SMike Smith static int
3228fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
322935863739SMike Smith {
323035863739SMike Smith 	struct aac_rev_check rev_check;
323135863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
323235863739SMike Smith 	int error = 0;
323335863739SMike Smith 
323435863739SMike Smith 	debug_called(2);
323535863739SMike Smith 
323635863739SMike Smith 	/*
323735863739SMike Smith 	 * Copyin the revision struct from userspace
323835863739SMike Smith 	 */
3239c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3240c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
324135863739SMike Smith 		return error;
324235863739SMike Smith 	}
324335863739SMike Smith 
3244914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
3245914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
324635863739SMike Smith 
324735863739SMike Smith 	/*
324835863739SMike Smith 	 * Doctor up the response struct.
324935863739SMike Smith 	 */
325035863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3251914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3252914da7d0SScott Long 	    sc->aac_revision.external.ul;
3253914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3254914da7d0SScott Long 	    sc->aac_revision.buildNumber;
325535863739SMike Smith 
3256c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3257c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
325835863739SMike Smith }
325935863739SMike Smith 
3260914da7d0SScott Long /*
326135863739SMike Smith  * Pass the caller the next AIF in their queue
326235863739SMike Smith  */
326335863739SMike Smith static int
3264fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
326535863739SMike Smith {
326635863739SMike Smith 	struct get_adapter_fib_ioctl agf;
32679e2e96d8SScott Long 	int error;
326835863739SMike Smith 
326935863739SMike Smith 	debug_called(2);
327035863739SMike Smith 
327135863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
327235863739SMike Smith 
327335863739SMike Smith 		/*
327435863739SMike Smith 		 * Check the magic number that we gave the caller.
327535863739SMike Smith 		 */
3276b88ffdc8SScott Long 		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
327735863739SMike Smith 			error = EFAULT;
327835863739SMike Smith 		} else {
3279fb0c27d7SScott Long 			error = aac_return_aif(sc, agf.AifFib);
328035863739SMike Smith 			if ((error == EAGAIN) && (agf.Wait)) {
328135863739SMike Smith 				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
328235863739SMike Smith 				while (error == EAGAIN) {
3283914da7d0SScott Long 					error = tsleep(sc->aac_aifq, PRIBIO |
3284914da7d0SScott Long 						       PCATCH, "aacaif", 0);
328535863739SMike Smith 					if (error == 0)
3286914da7d0SScott Long 						error = aac_return_aif(sc,
3287914da7d0SScott Long 						    agf.AifFib);
328835863739SMike Smith 				}
328935863739SMike Smith 				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
329035863739SMike Smith 			}
329135863739SMike Smith 		}
329235863739SMike Smith 	}
329335863739SMike Smith 	return(error);
329435863739SMike Smith }
329535863739SMike Smith 
3296914da7d0SScott Long /*
32970b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
32980b94a66eSMike Smith  */
32990b94a66eSMike Smith static int
3300fb0c27d7SScott Long aac_return_aif(struct aac_softc *sc, caddr_t uptr)
33010b94a66eSMike Smith {
33023df780cfSScott Long 	int next, error;
33030b94a66eSMike Smith 
33040b94a66eSMike Smith 	debug_called(2);
33050b94a66eSMike Smith 
3306bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
33070b94a66eSMike Smith 	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
3308bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
33093df780cfSScott Long 		return (EAGAIN);
33103df780cfSScott Long 	}
33113df780cfSScott Long 
33123df780cfSScott Long 	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
33133df780cfSScott Long 	error = copyout(&sc->aac_aifq[next], uptr,
3314c6eafcf2SScott Long 			sizeof(struct aac_aif_command));
331536e0bf6eSScott Long 	if (error)
331670545d1aSScott Long 		device_printf(sc->aac_dev,
331770545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
33183df780cfSScott Long 	else
33193df780cfSScott Long 		sc->aac_aifq_tail = next;
33203df780cfSScott Long 
3321bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
33220b94a66eSMike Smith 	return(error);
33230b94a66eSMike Smith }
332436e0bf6eSScott Long 
33257cb209f5SScott Long static int
33267cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
33277cb209f5SScott Long {
33287cb209f5SScott Long 	struct aac_pci_info {
33297cb209f5SScott Long 		u_int32_t bus;
33307cb209f5SScott Long 		u_int32_t slot;
33317cb209f5SScott Long 	} pciinf;
33327cb209f5SScott Long 	int error;
33337cb209f5SScott Long 
33347cb209f5SScott Long 	debug_called(2);
33357cb209f5SScott Long 
33367cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
33377cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
33387cb209f5SScott Long 
33397cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
33407cb209f5SScott Long 			sizeof(struct aac_pci_info));
33417cb209f5SScott Long 
33427cb209f5SScott Long 	return (error);
33437cb209f5SScott Long }
33447cb209f5SScott Long 
3345914da7d0SScott Long /*
334636e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
334736e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
334836e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
334936e0bf6eSScott Long  */
335036e0bf6eSScott Long static int
335136e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
335236e0bf6eSScott Long {
335336e0bf6eSScott Long 	struct aac_query_disk query_disk;
335436e0bf6eSScott Long 	struct aac_container *co;
3355914da7d0SScott Long 	struct aac_disk	*disk;
335636e0bf6eSScott Long 	int error, id;
335736e0bf6eSScott Long 
335836e0bf6eSScott Long 	debug_called(2);
335936e0bf6eSScott Long 
3360914da7d0SScott Long 	disk = NULL;
3361914da7d0SScott Long 
3362914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3363914da7d0SScott Long 		       sizeof(struct aac_query_disk));
336436e0bf6eSScott Long 	if (error)
336536e0bf6eSScott Long 		return (error);
336636e0bf6eSScott Long 
336736e0bf6eSScott Long 	id = query_disk.ContainerNumber;
336836e0bf6eSScott Long 	if (id == -1)
336936e0bf6eSScott Long 		return (EINVAL);
337036e0bf6eSScott Long 
3371bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
337236e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
337336e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
337436e0bf6eSScott Long 			break;
337536e0bf6eSScott Long 		}
337636e0bf6eSScott Long 
337736e0bf6eSScott Long 	if (co == NULL) {
337836e0bf6eSScott Long 			query_disk.Valid = 0;
337936e0bf6eSScott Long 			query_disk.Locked = 0;
338036e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
338136e0bf6eSScott Long 	} else {
338236e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
338336e0bf6eSScott Long 		query_disk.Valid = 1;
3384914da7d0SScott Long 		query_disk.Locked =
3385914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
338636e0bf6eSScott Long 		query_disk.Deleted = 0;
3387b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
338836e0bf6eSScott Long 		query_disk.Target = disk->unit;
338936e0bf6eSScott Long 		query_disk.Lun = 0;
339036e0bf6eSScott Long 		query_disk.UnMapped = 0;
33917540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
33920b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
339336e0bf6eSScott Long 	}
3394bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
339536e0bf6eSScott Long 
3396914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3397914da7d0SScott Long 			sizeof(struct aac_query_disk));
339836e0bf6eSScott Long 
339936e0bf6eSScott Long 	return (error);
340036e0bf6eSScott Long }
340136e0bf6eSScott Long 
3402fe3cb0e1SScott Long static void
3403fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3404fe3cb0e1SScott Long {
3405fe3cb0e1SScott Long 	struct aac_fib *fib;
3406fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3407fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3408fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3409fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3410fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
341170545d1aSScott Long 	struct aac_sim *caminf;
3412fe3cb0e1SScott Long 	device_t child;
3413fe3cb0e1SScott Long 	int i, found, error;
3414fe3cb0e1SScott Long 
341503b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3416fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
341739ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3418fe3cb0e1SScott Long 
3419fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3420fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3421fe3cb0e1SScott Long 	c_cmd->param = 0;
3422fe3cb0e1SScott Long 
3423fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3424fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3425fe3cb0e1SScott Long 	if (error) {
3426fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3427fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3428fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3429fe3cb0e1SScott Long 		return;
3430fe3cb0e1SScott Long 	}
3431fe3cb0e1SScott Long 
3432fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3433fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3434fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3435fe3cb0e1SScott Long 		    c_resp->Status);
3436fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3437fe3cb0e1SScott Long 		return;
3438fe3cb0e1SScott Long 	}
3439fe3cb0e1SScott Long 
3440fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3441fe3cb0e1SScott Long 
3442fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
344339ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
344439ee03c3SScott Long 
3445fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3446fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3447fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3448fe3cb0e1SScott Long 	vmi->ObjId = 0;
3449fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3450fe3cb0e1SScott Long 
3451fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3452fe3cb0e1SScott Long 	    sizeof(struct aac_vmioctl));
3453fe3cb0e1SScott Long 	if (error) {
3454fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3455fe3cb0e1SScott Long 		    error);
3456fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3457fe3cb0e1SScott Long 		return;
3458fe3cb0e1SScott Long 	}
3459fe3cb0e1SScott Long 
3460fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3461fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3462fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3463fe3cb0e1SScott Long 		    vmi_resp->Status);
3464fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
3465fe3cb0e1SScott Long 		return;
3466fe3cb0e1SScott Long 	}
3467fe3cb0e1SScott Long 
3468fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3469fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
3470fe3cb0e1SScott Long 
3471fe3cb0e1SScott Long 	found = 0;
3472fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3473fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3474fe3cb0e1SScott Long 			continue;
3475fe3cb0e1SScott Long 
3476a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3477a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3478b5f516cdSScott Long 		if (caminf == NULL) {
3479b5f516cdSScott Long 			device_printf(sc->aac_dev,
3480b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3481b5f516cdSScott Long 			break;
34827cb209f5SScott Long 		};
3483fe3cb0e1SScott Long 
3484fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3485fe3cb0e1SScott Long 		if (child == NULL) {
3486b5f516cdSScott Long 			device_printf(sc->aac_dev,
3487b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3488b5f516cdSScott Long 			    i);
3489b5f516cdSScott Long 			free(caminf, M_AACBUF);
3490b5f516cdSScott Long 			break;
3491fe3cb0e1SScott Long 		}
3492fe3cb0e1SScott Long 
3493fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3494fe3cb0e1SScott Long 		caminf->BusNumber = i;
3495fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3496fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3497ddb8683eSScott Long 		caminf->sim_dev = child;
3498fe3cb0e1SScott Long 
3499fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3500fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
350170545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3502fe3cb0e1SScott Long 
3503fe3cb0e1SScott Long 		found = 1;
3504fe3cb0e1SScott Long 	}
3505fe3cb0e1SScott Long 
3506fe3cb0e1SScott Long 	if (found)
3507fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3508fe3cb0e1SScott Long 
3509fe3cb0e1SScott Long 	return;
3510fe3cb0e1SScott Long }
3511