xref: /freebsd/sys/dev/aac/aac.c (revision 7ea2d5586c98cf8c18cde2b4c3a414edd8494d1f)
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_DRIVERNAME			"aac"
3835863739SMike Smith 
39f6c4dd3fSScott Long #include "opt_aac.h"
40f6c4dd3fSScott Long 
4136e0bf6eSScott Long /* #include <stddef.h> */
4235863739SMike Smith #include <sys/param.h>
4335863739SMike Smith #include <sys/systm.h>
4435863739SMike Smith #include <sys/malloc.h>
4535863739SMike Smith #include <sys/kernel.h>
4636e0bf6eSScott Long #include <sys/kthread.h>
473d04a9d7SScott Long #include <sys/sysctl.h>
48b3457b51SScott Long #include <sys/poll.h>
49891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
5035863739SMike Smith 
5135863739SMike Smith #include <sys/bus.h>
5235863739SMike Smith #include <sys/conf.h>
5335863739SMike Smith #include <sys/signalvar.h>
540b94a66eSMike Smith #include <sys/time.h>
5536e0bf6eSScott Long #include <sys/eventhandler.h>
567cb209f5SScott Long #include <sys/rman.h>
5735863739SMike Smith 
5835863739SMike Smith #include <machine/bus.h>
59b5f516cdSScott Long #include <sys/bus_dma.h>
6035863739SMike Smith #include <machine/resource.h>
6135863739SMike Smith 
627cb209f5SScott Long #include <dev/pci/pcireg.h>
637cb209f5SScott Long #include <dev/pci/pcivar.h>
647cb209f5SScott Long 
6535863739SMike Smith #include <dev/aac/aacreg.h>
660b0594cdSScott Long #include <sys/aac_ioctl.h>
6735863739SMike Smith #include <dev/aac/aacvar.h>
6835863739SMike Smith #include <dev/aac/aac_tables.h>
6935863739SMike Smith 
7035863739SMike Smith static void	aac_startup(void *arg);
71914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
72cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
73fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
7435863739SMike Smith 
7535863739SMike Smith /* Command Processing */
760b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7735863739SMike Smith static void	aac_complete(void *context, int pending);
7835863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7935863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
80d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
8170545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
8235863739SMike Smith 
8335863739SMike Smith /* Command Buffer Management */
84cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
85cd481291SScott Long 				   int nseg, int error);
86c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
87c6eafcf2SScott Long 				       int nseg, int error);
880b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
898480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
9035863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
9135863739SMike Smith 
9235863739SMike Smith /* Hardware Interface */
93c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
94c6eafcf2SScott Long 			       int error);
95fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9635863739SMike Smith static int	aac_init(struct aac_softc *sc);
9735863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
98c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
99c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
100c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
101f6c4dd3fSScott Long 				struct aac_command *cm);
102c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
103914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10436e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10536e0bf6eSScott Long 				     struct aac_fib *fib);
10635863739SMike Smith 
107b3457b51SScott Long /* Falcon/PPC interface */
108b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
109b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
110b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
111b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
112b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
113b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
114b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
115a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
116b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
117b3457b51SScott Long 
118b3457b51SScott Long struct aac_interface aac_fa_interface = {
119b3457b51SScott Long 	aac_fa_get_fwstatus,
120b3457b51SScott Long 	aac_fa_qnotify,
121b3457b51SScott Long 	aac_fa_get_istatus,
122b3457b51SScott Long 	aac_fa_clear_istatus,
123b3457b51SScott Long 	aac_fa_set_mailbox,
124a6d35632SScott Long 	aac_fa_get_mailbox,
1257cb209f5SScott Long 	aac_fa_set_interrupts,
1267cb209f5SScott Long 	NULL, NULL, NULL
127b3457b51SScott Long };
128b3457b51SScott Long 
12935863739SMike Smith /* StrongARM interface */
13035863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
13135863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13235863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
13335863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13435863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
135c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
136c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
137a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13835863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13935863739SMike Smith 
14035863739SMike Smith struct aac_interface aac_sa_interface = {
14135863739SMike Smith 	aac_sa_get_fwstatus,
14235863739SMike Smith 	aac_sa_qnotify,
14335863739SMike Smith 	aac_sa_get_istatus,
14435863739SMike Smith 	aac_sa_clear_istatus,
14535863739SMike Smith 	aac_sa_set_mailbox,
146a6d35632SScott Long 	aac_sa_get_mailbox,
1477cb209f5SScott Long 	aac_sa_set_interrupts,
1487cb209f5SScott Long 	NULL, NULL, NULL
14935863739SMike Smith };
15035863739SMike Smith 
15135863739SMike Smith /* i960Rx interface */
15235863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
15335863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15435863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
15535863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15635863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
157c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
158c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
159a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16035863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
1617cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
1627cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc);
1637cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16435863739SMike Smith 
16535863739SMike Smith struct aac_interface aac_rx_interface = {
16635863739SMike Smith 	aac_rx_get_fwstatus,
16735863739SMike Smith 	aac_rx_qnotify,
16835863739SMike Smith 	aac_rx_get_istatus,
16935863739SMike Smith 	aac_rx_clear_istatus,
17035863739SMike Smith 	aac_rx_set_mailbox,
171a6d35632SScott Long 	aac_rx_get_mailbox,
1727cb209f5SScott Long 	aac_rx_set_interrupts,
1737cb209f5SScott Long 	aac_rx_send_command,
1747cb209f5SScott Long 	aac_rx_get_outb_queue,
1757cb209f5SScott Long 	aac_rx_set_outb_queue
17635863739SMike Smith };
17735863739SMike Smith 
1784afedc31SScott Long /* Rocket/MIPS interface */
1794afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1804afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1814afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1824afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1834afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1844afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1854afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1864afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1874afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1887cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
1897cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc);
1907cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
1914afedc31SScott Long 
1924afedc31SScott Long struct aac_interface aac_rkt_interface = {
1934afedc31SScott Long 	aac_rkt_get_fwstatus,
1944afedc31SScott Long 	aac_rkt_qnotify,
1954afedc31SScott Long 	aac_rkt_get_istatus,
1964afedc31SScott Long 	aac_rkt_clear_istatus,
1974afedc31SScott Long 	aac_rkt_set_mailbox,
1984afedc31SScott Long 	aac_rkt_get_mailbox,
1997cb209f5SScott Long 	aac_rkt_set_interrupts,
2007cb209f5SScott Long 	aac_rkt_send_command,
2017cb209f5SScott Long 	aac_rkt_get_outb_queue,
2027cb209f5SScott Long 	aac_rkt_set_outb_queue
2034afedc31SScott Long };
2044afedc31SScott Long 
20535863739SMike Smith /* Debugging and Diagnostics */
20635863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
2076965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
208c6eafcf2SScott Long 				   u_int32_t code);
20935863739SMike Smith 
21035863739SMike Smith /* Management Interface */
21135863739SMike Smith static d_open_t		aac_open;
21235863739SMike Smith static d_close_t	aac_close;
21335863739SMike Smith static d_ioctl_t	aac_ioctl;
214b3457b51SScott Long static d_poll_t		aac_poll;
215c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
216c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
21736e0bf6eSScott Long 					   struct aac_fib *fib);
218fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
219a723a548SEd Maste static int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
220a723a548SEd Maste static int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
221fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
222a723a548SEd Maste static int		aac_return_aif(struct aac_softc *sc,
223a723a548SEd Maste 					struct aac_fib_context *ctx, caddr_t uptr);
22436e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
2257cb209f5SScott Long static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
2267cb209f5SScott Long static void		aac_ioctl_event(struct aac_softc *sc,
2277cb209f5SScott Long 				        struct aac_event *event, void *arg);
22835863739SMike Smith 
22935863739SMike Smith static struct cdevsw aac_cdevsw = {
230dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
231dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2327ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2337ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2347ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2357ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2367ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
23735863739SMike Smith };
23835863739SMike Smith 
23936e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
24036e0bf6eSScott Long 
2413d04a9d7SScott Long /* sysctl node */
2423d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2433d04a9d7SScott Long 
244914da7d0SScott Long /*
245914da7d0SScott Long  * Device Interface
246914da7d0SScott Long  */
24735863739SMike Smith 
248914da7d0SScott Long /*
24935863739SMike Smith  * Initialise the controller and softc
25035863739SMike Smith  */
25135863739SMike Smith int
25235863739SMike Smith aac_attach(struct aac_softc *sc)
25335863739SMike Smith {
25435863739SMike Smith 	int error, unit;
25535863739SMike Smith 
25635863739SMike Smith 	debug_called(1);
25735863739SMike Smith 
25835863739SMike Smith 	/*
25935863739SMike Smith 	 * Initialise per-controller queues.
26035863739SMike Smith 	 */
2610b94a66eSMike Smith 	aac_initq_free(sc);
2620b94a66eSMike Smith 	aac_initq_ready(sc);
2630b94a66eSMike Smith 	aac_initq_busy(sc);
2640b94a66eSMike Smith 	aac_initq_bio(sc);
26535863739SMike Smith 
26635863739SMike Smith 	/*
26735863739SMike Smith 	 * Initialise command-completion task.
26835863739SMike Smith 	 */
26935863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
27035863739SMike Smith 
27135863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
27235863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
27335863739SMike Smith 
27435863739SMike Smith 	/*
275fe94b852SScott Long 	 * Check that the firmware on the card is supported.
276fe94b852SScott Long 	 */
277fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
278fe94b852SScott Long 		return(error);
279fe94b852SScott Long 
280f6b1c44dSScott Long 	/*
281f6b1c44dSScott Long 	 * Initialize locks
282f6b1c44dSScott Long 	 */
283bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
284bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
285bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
286f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
287065dd78cSScott Long 	TAILQ_INIT(&sc->aac_ev_cmfree);
288f6b1c44dSScott 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,
308ef544f63SPaolo Pisati 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
309ef544f63SPaolo Pisati 				   aac_new_intr, 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,
315ef544f63SPaolo Pisati 				   INTR_TYPE_BIO, aac_fast_intr, NULL,
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,
321ef544f63SPaolo Pisati 					   NULL, (driver_intr_t *)aac_fast_intr,
322ef544f63SPaolo Pisati 					   sc, &sc->aac_intr)) {
3237cb209f5SScott Long 				device_printf(sc->aac_dev,
3247cb209f5SScott Long 					     "can't set up MPSAFE interrupt\n");
3257cb209f5SScott Long 				return (EINVAL);
3267cb209f5SScott Long 			}
3277cb209f5SScott Long 		}
3287cb209f5SScott Long 	}
3297cb209f5SScott Long 
3307cb209f5SScott Long 	/*
33135863739SMike Smith 	 * Print a little information about the controller.
33235863739SMike Smith 	 */
33335863739SMike Smith 	aac_describe_controller(sc);
33435863739SMike Smith 
33535863739SMike Smith 	/*
336ae543596SScott Long 	 * Register to probe our containers later.
337ae543596SScott Long 	 */
33835863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
33935863739SMike Smith 	sc->aac_ich.ich_arg = sc;
34035863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
341914da7d0SScott Long 		device_printf(sc->aac_dev,
342914da7d0SScott Long 			      "can't establish configuration hook\n");
34335863739SMike Smith 		return(ENXIO);
34435863739SMike Smith 	}
34535863739SMike Smith 
34635863739SMike Smith 	/*
34735863739SMike Smith 	 * Make the control device.
34835863739SMike Smith 	 */
34935863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3509e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3519e9466baSRobert Watson 				 0640, "aac%d", unit);
352157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3534aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
35435863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
35535863739SMike Smith 
35636e0bf6eSScott Long 	/* Create the AIF thread */
3573745c395SJulian Elischer 	if (kproc_create((void(*)(void *))aac_command_thread, sc,
358316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
35936e0bf6eSScott Long 		panic("Could not create AIF thread\n");
36036e0bf6eSScott Long 
36136e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3625f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3635f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3645f54d522SScott Long 		device_printf(sc->aac_dev,
3655f54d522SScott Long 			      "shutdown event registration failed\n");
36636e0bf6eSScott Long 
367fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
368a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
36970545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
370fe3cb0e1SScott Long 		aac_get_bus_info(sc);
37170545d1aSScott Long 	}
372fe3cb0e1SScott Long 
37335863739SMike Smith 	return(0);
37435863739SMike Smith }
37535863739SMike Smith 
3767cb209f5SScott Long void
3777cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3787cb209f5SScott Long {
3797cb209f5SScott Long 
3807cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3817cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3827cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3837cb209f5SScott Long 		break;
3847cb209f5SScott Long 	default:
3857cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3867cb209f5SScott Long 		    event->ev_type);
3877cb209f5SScott Long 		break;
3887cb209f5SScott Long 	}
3897cb209f5SScott Long 
3907cb209f5SScott Long 	return;
3917cb209f5SScott Long }
3927cb209f5SScott Long 
393914da7d0SScott Long /*
39435863739SMike Smith  * Probe for containers, create disks.
39535863739SMike Smith  */
39635863739SMike Smith static void
39735863739SMike Smith aac_startup(void *arg)
39835863739SMike Smith {
399914da7d0SScott Long 	struct aac_softc *sc;
400cbfd045bSScott Long 	struct aac_fib *fib;
401cbfd045bSScott Long 	struct aac_mntinfo *mi;
402cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
403795d7dc0SScott Long 	int count = 0, i = 0;
40435863739SMike Smith 
40535863739SMike Smith 	debug_called(1);
40635863739SMike Smith 
407914da7d0SScott Long 	sc = (struct aac_softc *)arg;
408914da7d0SScott Long 
40935863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
41035863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
41135863739SMike Smith 
4127cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
41303b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
414cbfd045bSScott Long 	mi = (struct aac_mntinfo *)&fib->data[0];
415cbfd045bSScott Long 
41635863739SMike Smith 	/* loop over possible containers */
41736e0bf6eSScott Long 	do {
41835863739SMike Smith 		/* request information on this container */
41939ee03c3SScott Long 		bzero(mi, sizeof(struct aac_mntinfo));
42039ee03c3SScott Long 		mi->Command = VM_NameServe;
42139ee03c3SScott Long 		mi->MntType = FT_FILESYS;
422cbfd045bSScott Long 		mi->MntCount = i;
423cbfd045bSScott Long 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
424cbfd045bSScott Long 				 sizeof(struct aac_mntinfo))) {
425795d7dc0SScott Long 			printf("error probing container %d", i);
42635863739SMike Smith 			continue;
42735863739SMike Smith 		}
42835863739SMike Smith 
429cbfd045bSScott Long 		mir = (struct aac_mntinforesp *)&fib->data[0];
430795d7dc0SScott Long 		/* XXX Need to check if count changed */
431795d7dc0SScott Long 		count = mir->MntRespCount;
432cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
43336e0bf6eSScott Long 		i++;
434795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
435cbfd045bSScott Long 
436cbfd045bSScott Long 	aac_release_sync_fib(sc);
4377cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
43835863739SMike Smith 
43935863739SMike Smith 	/* poke the bus to actually attach the child devices */
44035863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
44135863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
44235863739SMike Smith 
44335863739SMike Smith 	/* mark the controller up */
44435863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
44535863739SMike Smith 
44635863739SMike Smith 	/* enable interrupts now */
44735863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
44835863739SMike Smith }
44935863739SMike Smith 
450914da7d0SScott Long /*
451914da7d0SScott Long  * Create a device to respresent a new container
452914da7d0SScott Long  */
453914da7d0SScott Long static void
454cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
455914da7d0SScott Long {
456914da7d0SScott Long 	struct aac_container *co;
457914da7d0SScott Long 	device_t child;
458914da7d0SScott Long 
459914da7d0SScott Long 	/*
460914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
461914da7d0SScott Long 	 * the possible types may never show up.
462914da7d0SScott Long 	 */
463914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
464a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
465a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
466914da7d0SScott Long 		if (co == NULL)
467914da7d0SScott Long 			panic("Out of memory?!\n");
468914da7d0SScott Long 		debug(1, "id %x  name '%.16s'  size %u  type %d",
469914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
470914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
471914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
472914da7d0SScott Long 
473fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
474914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
475914da7d0SScott Long 		else
476914da7d0SScott Long 			device_set_ivars(child, co);
477914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
478914da7d0SScott Long 				mir->MntTable[0].VolType));
479914da7d0SScott Long 		co->co_disk = child;
480914da7d0SScott Long 		co->co_found = f;
481914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
482914da7d0SScott Long 		      sizeof(struct aac_mntobj));
483bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
484914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
485bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
486914da7d0SScott Long 	}
487914da7d0SScott Long }
488914da7d0SScott Long 
489914da7d0SScott Long /*
49035863739SMike Smith  * Free all of the resources associated with (sc)
49135863739SMike Smith  *
49235863739SMike Smith  * Should not be called if the controller is active.
49335863739SMike Smith  */
49435863739SMike Smith void
49535863739SMike Smith aac_free(struct aac_softc *sc)
49635863739SMike Smith {
497ffb37f33SScott Long 
49835863739SMike Smith 	debug_called(1);
49935863739SMike Smith 
50035863739SMike Smith 	/* remove the control device */
50135863739SMike Smith 	if (sc->aac_dev_t != NULL)
50235863739SMike Smith 		destroy_dev(sc->aac_dev_t);
50335863739SMike Smith 
5040b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
5058480cc63SScott Long 	aac_free_commands(sc);
5060b94a66eSMike Smith 	if (sc->aac_fib_dmat)
5070b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
50835863739SMike Smith 
509ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
510ffb37f33SScott Long 
51135863739SMike Smith 	/* destroy the common area */
51235863739SMike Smith 	if (sc->aac_common) {
51335863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
514c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
515c6eafcf2SScott Long 				sc->aac_common_dmamap);
51635863739SMike Smith 	}
5170b94a66eSMike Smith 	if (sc->aac_common_dmat)
5180b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
51935863739SMike Smith 
52035863739SMike Smith 	/* disconnect the interrupt handler */
52135863739SMike Smith 	if (sc->aac_intr)
52235863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
52335863739SMike Smith 	if (sc->aac_irq != NULL)
524c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
525c6eafcf2SScott Long 				     sc->aac_irq);
52635863739SMike Smith 
52735863739SMike Smith 	/* destroy data-transfer DMA tag */
52835863739SMike Smith 	if (sc->aac_buffer_dmat)
52935863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
53035863739SMike Smith 
53135863739SMike Smith 	/* destroy the parent DMA tag */
53235863739SMike Smith 	if (sc->aac_parent_dmat)
53335863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
53435863739SMike Smith 
53535863739SMike Smith 	/* release the register window mapping */
53635863739SMike Smith 	if (sc->aac_regs_resource != NULL)
537914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
538914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
53935863739SMike Smith }
54035863739SMike Smith 
541914da7d0SScott Long /*
54235863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
54335863739SMike Smith  */
54435863739SMike Smith int
54535863739SMike Smith aac_detach(device_t dev)
54635863739SMike Smith {
547914da7d0SScott Long 	struct aac_softc *sc;
54870545d1aSScott Long 	struct aac_container *co;
54970545d1aSScott Long 	struct aac_sim	*sim;
55035863739SMike Smith 	int error;
55135863739SMike Smith 
55235863739SMike Smith 	debug_called(1);
55335863739SMike Smith 
554914da7d0SScott Long 	sc = device_get_softc(dev);
555914da7d0SScott Long 
55635863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
55735863739SMike Smith 		return(EBUSY);
55835863739SMike Smith 
55970545d1aSScott Long 	/* Remove the child containers */
560a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
56170545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
56270545d1aSScott Long 		if (error)
56370545d1aSScott Long 			return (error);
56465ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
565a761a1caSScott Long 		free(co, M_AACBUF);
56670545d1aSScott Long 	}
56770545d1aSScott Long 
56870545d1aSScott Long 	/* Remove the CAM SIMs */
569a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
570a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
57170545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
57270545d1aSScott Long 		if (error)
57370545d1aSScott Long 			return (error);
574a761a1caSScott Long 		free(sim, M_AACBUF);
57570545d1aSScott Long 	}
57670545d1aSScott Long 
57736e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
57836e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
57936e0bf6eSScott Long 		wakeup(sc->aifthread);
58036e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
58136e0bf6eSScott Long 	}
58236e0bf6eSScott Long 
58336e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
58436e0bf6eSScott Long 		panic("Cannot shutdown AIF thread\n");
58536e0bf6eSScott Long 
58635863739SMike Smith 	if ((error = aac_shutdown(dev)))
58735863739SMike Smith 		return(error);
58835863739SMike Smith 
5895f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
5905f54d522SScott Long 
59135863739SMike Smith 	aac_free(sc);
59235863739SMike Smith 
593dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
594dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
595dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
596dc9efde5SScott Long 
59735863739SMike Smith 	return(0);
59835863739SMike Smith }
59935863739SMike Smith 
600914da7d0SScott Long /*
60135863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
60235863739SMike Smith  *
60335863739SMike Smith  * This function is called before detach or system shutdown.
60435863739SMike Smith  *
6050b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
60635863739SMike Smith  * allow shutdown if any device is open.
60735863739SMike Smith  */
60835863739SMike Smith int
60935863739SMike Smith aac_shutdown(device_t dev)
61035863739SMike Smith {
611914da7d0SScott Long 	struct aac_softc *sc;
612cbfd045bSScott Long 	struct aac_fib *fib;
613cbfd045bSScott Long 	struct aac_close_command *cc;
61435863739SMike Smith 
61535863739SMike Smith 	debug_called(1);
61635863739SMike Smith 
617914da7d0SScott Long 	sc = device_get_softc(dev);
618914da7d0SScott Long 
61935863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
62035863739SMike Smith 
62135863739SMike Smith 	/*
62235863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
62335863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
62435863739SMike Smith 	 * We've been closed and all I/O completed already
62535863739SMike Smith 	 */
62635863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
62735863739SMike Smith 
6287cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
62903b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
630cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
631cbfd045bSScott Long 
63239ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
633cbfd045bSScott Long 	cc->Command = VM_CloseAll;
634cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
635cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
636cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
63735863739SMike Smith 		printf("FAILED.\n");
63870545d1aSScott Long 	else
63970545d1aSScott Long 		printf("done\n");
64070545d1aSScott Long #if 0
641914da7d0SScott Long 	else {
642cbfd045bSScott Long 		fib->data[0] = 0;
64336e0bf6eSScott Long 		/*
644914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
64536e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
64636e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
64736e0bf6eSScott Long 		 * driver module with the intent to reload it later.
64836e0bf6eSScott Long 		 */
649cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
650cbfd045bSScott Long 		    fib, 1)) {
65135863739SMike Smith 			printf("FAILED.\n");
65235863739SMike Smith 		} else {
65335863739SMike Smith 			printf("done.\n");
65435863739SMike Smith 		}
65535863739SMike Smith 	}
65670545d1aSScott Long #endif
65735863739SMike Smith 
65835863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
6593576af8fSScott Long 	aac_release_sync_fib(sc);
6607cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
66135863739SMike Smith 
66235863739SMike Smith 	return(0);
66335863739SMike Smith }
66435863739SMike Smith 
665914da7d0SScott Long /*
66635863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
66735863739SMike Smith  */
66835863739SMike Smith int
66935863739SMike Smith aac_suspend(device_t dev)
67035863739SMike Smith {
671914da7d0SScott Long 	struct aac_softc *sc;
67235863739SMike Smith 
67335863739SMike Smith 	debug_called(1);
674914da7d0SScott Long 
675914da7d0SScott Long 	sc = device_get_softc(dev);
676914da7d0SScott Long 
67735863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
67835863739SMike Smith 
67935863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
68035863739SMike Smith 	return(0);
68135863739SMike Smith }
68235863739SMike Smith 
683914da7d0SScott Long /*
68435863739SMike Smith  * Bring the controller back to a state ready for operation.
68535863739SMike Smith  */
68635863739SMike Smith int
68735863739SMike Smith aac_resume(device_t dev)
68835863739SMike Smith {
689914da7d0SScott Long 	struct aac_softc *sc;
69035863739SMike Smith 
69135863739SMike Smith 	debug_called(1);
692914da7d0SScott Long 
693914da7d0SScott Long 	sc = device_get_softc(dev);
694914da7d0SScott Long 
69535863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
69635863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
69735863739SMike Smith 	return(0);
69835863739SMike Smith }
69935863739SMike Smith 
700914da7d0SScott Long /*
7017cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
70235863739SMike Smith  */
70335863739SMike Smith void
7047cb209f5SScott Long aac_new_intr(void *arg)
7057cb209f5SScott Long {
7067cb209f5SScott Long 	struct aac_softc *sc;
7077cb209f5SScott Long 	u_int32_t index, fast;
7087cb209f5SScott Long 	struct aac_command *cm;
7097cb209f5SScott Long 	struct aac_fib *fib;
7107cb209f5SScott Long 	int i;
7117cb209f5SScott Long 
7127cb209f5SScott Long 	debug_called(2);
7137cb209f5SScott Long 
7147cb209f5SScott Long 	sc = (struct aac_softc *)arg;
7157cb209f5SScott Long 
7167cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
7177cb209f5SScott Long 	while (1) {
7187cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
7197cb209f5SScott Long 		if (index == 0xffffffff)
7207cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
7217cb209f5SScott Long 		if (index == 0xffffffff)
7227cb209f5SScott Long 			break;
7237cb209f5SScott Long 		if (index & 2) {
7247cb209f5SScott Long 			if (index == 0xfffffffe) {
7257cb209f5SScott Long 				/* XXX This means that the controller wants
7267cb209f5SScott Long 				 * more work.  Ignore it for now.
7277cb209f5SScott Long 				 */
7287cb209f5SScott Long 				continue;
7297cb209f5SScott Long 			}
7307cb209f5SScott Long 			/* AIF */
7317cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
7327cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
7337cb209f5SScott Long 			if (fib == NULL) {
7347cb209f5SScott Long 				/* If we're really this short on memory,
7357cb209f5SScott Long 				 * hopefully breaking out of the handler will
7367cb209f5SScott Long 				 * allow something to get freed.  This
7377cb209f5SScott Long 				 * actually sucks a whole lot.
7387cb209f5SScott Long 				 */
7397cb209f5SScott Long 				break;
7407cb209f5SScott Long 			}
7417cb209f5SScott Long 			index &= ~2;
7427cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
7437cb209f5SScott Long 				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
7447cb209f5SScott Long 			aac_handle_aif(sc, fib);
7457cb209f5SScott Long 			free(fib, M_AACBUF);
7467cb209f5SScott Long 
7477cb209f5SScott Long 			/*
7487cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
7497cb209f5SScott Long 			 * know that we are done with it.
7507cb209f5SScott Long 			 */
7517cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
7527cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
7537cb209f5SScott Long 		} else {
7547cb209f5SScott Long 			fast = index & 1;
7557cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
7567cb209f5SScott Long 			fib = cm->cm_fib;
7577cb209f5SScott Long 			if (fast) {
7587cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
7597cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
7607cb209f5SScott Long 			}
7617cb209f5SScott Long 			aac_remove_busy(cm);
7627cb209f5SScott Long  			aac_unmap_command(cm);
7637cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
7647cb209f5SScott Long 
7657cb209f5SScott Long 			/* is there a completion handler? */
7667cb209f5SScott Long 			if (cm->cm_complete != NULL) {
7677cb209f5SScott Long 				cm->cm_complete(cm);
7687cb209f5SScott Long 			} else {
7697cb209f5SScott Long 				/* assume that someone is sleeping on this
7707cb209f5SScott Long 				 * command
7717cb209f5SScott Long 				 */
7727cb209f5SScott Long 				wakeup(cm);
7737cb209f5SScott Long 			}
7747cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
7757cb209f5SScott Long 		}
7767cb209f5SScott Long 	}
7777cb209f5SScott Long 	/* see if we can start some more I/O */
7787cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
7797cb209f5SScott Long 		aac_startio(sc);
7807cb209f5SScott Long 
7817cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
7827cb209f5SScott Long }
7837cb209f5SScott Long 
784ef544f63SPaolo Pisati int
7857cb209f5SScott Long aac_fast_intr(void *arg)
78635863739SMike Smith {
787914da7d0SScott Long 	struct aac_softc *sc;
78870545d1aSScott Long 	u_int16_t reason;
78935863739SMike Smith 
79035863739SMike Smith 	debug_called(2);
79135863739SMike Smith 
792914da7d0SScott Long 	sc = (struct aac_softc *)arg;
793914da7d0SScott Long 
794f30ac74cSScott Long 	/*
7959148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
7969148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
7979148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
7989148fa21SScott Long 	 * ugly.
799f30ac74cSScott Long 	 */
80035863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
801f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
802f30ac74cSScott Long 
8039c3a7fceSScott Long 	/* handle completion processing */
8049148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
8059148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
80635863739SMike Smith 
8079148fa21SScott Long 	/* controller wants to talk to us */
8089148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
80970545d1aSScott Long 		/*
8109148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
8119148fa21SScott Long 		 * that start with a NULL.
81270545d1aSScott Long 		 */
8139148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
8149148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
8159148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
81670545d1aSScott Long 
8179148fa21SScott Long 		/*
8189148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
819a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
8209148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
8219148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
8229148fa21SScott Long 		 * if needed.
8239148fa21SScott Long 		 */
82436e0bf6eSScott Long 		wakeup(sc->aifthread);
82536e0bf6eSScott Long 	}
826ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
8279148fa21SScott Long }
82835863739SMike Smith 
829c6eafcf2SScott Long /*
830914da7d0SScott Long  * Command Processing
831914da7d0SScott Long  */
83235863739SMike Smith 
833914da7d0SScott Long /*
83435863739SMike Smith  * Start as much queued I/O as possible on the controller
83535863739SMike Smith  */
836fe3cb0e1SScott Long void
83735863739SMike Smith aac_startio(struct aac_softc *sc)
83835863739SMike Smith {
83935863739SMike Smith 	struct aac_command *cm;
840397fa34fSScott Long 	int error;
84135863739SMike Smith 
84235863739SMike Smith 	debug_called(2);
84335863739SMike Smith 
84435863739SMike Smith 	for (;;) {
845914da7d0SScott Long 		/*
846397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
847397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
848397fa34fSScott Long 		 */
849397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
850397fa34fSScott Long 			break;
851397fa34fSScott Long 
852397fa34fSScott Long 		/*
853914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
854914da7d0SScott Long 		 * resources
855914da7d0SScott Long 		 */
85635863739SMike Smith 		cm = aac_dequeue_ready(sc);
85735863739SMike Smith 
858914da7d0SScott Long 		/*
859914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
860914da7d0SScott Long 		 * return)
861914da7d0SScott Long 		 */
8620b94a66eSMike Smith 		if (cm == NULL)
86335863739SMike Smith 			aac_bio_command(sc, &cm);
86435863739SMike Smith 
86535863739SMike Smith 		/* nothing to do? */
86635863739SMike Smith 		if (cm == NULL)
86735863739SMike Smith 			break;
86835863739SMike Smith 
869cd481291SScott Long 		/* don't map more than once */
870cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
8714102d44bSScott Long 			panic("aac: command %p already mapped", cm);
87235863739SMike Smith 
873397fa34fSScott Long 		/*
874397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
875397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
876397fa34fSScott Long 		 * busdma.
877397fa34fSScott Long 		 */
878cd481291SScott Long 		if (cm->cm_datalen != 0) {
879397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
880397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
881397fa34fSScott Long 						cm->cm_datalen,
882cd481291SScott Long 						aac_map_command_sg, cm, 0);
883cd481291SScott Long 			if (error == EINPROGRESS) {
884cd481291SScott Long 				debug(1, "freezing queue\n");
885cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
886cd481291SScott Long 				error = 0;
887614c22b2SScott Long 			} else if (error != 0)
888397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
889397fa34fSScott Long 				      "busdma\n", error);
890397fa34fSScott Long 		} else
8918778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
892cd481291SScott Long 	}
89335863739SMike Smith }
89435863739SMike Smith 
895914da7d0SScott Long /*
89635863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
89735863739SMike Smith  */
89835863739SMike Smith static void
89970545d1aSScott Long aac_command_thread(struct aac_softc *sc)
90035863739SMike Smith {
90135863739SMike Smith 	struct aac_fib *fib;
90235863739SMike Smith 	u_int32_t fib_size;
9039148fa21SScott Long 	int size, retval;
90435863739SMike Smith 
90536e0bf6eSScott Long 	debug_called(2);
90635863739SMike Smith 
907bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
908a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
90936e0bf6eSScott Long 
910a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
911a32a982dSScott Long 
912a32a982dSScott Long 		retval = 0;
913a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
914a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
915a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
91636e0bf6eSScott Long 
9179148fa21SScott Long 		/*
9189148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
9199148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
9209148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
9219148fa21SScott Long 		 */
9229148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
923bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
924a32a982dSScott Long 			aac_alloc_commands(sc);
925bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
9264102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
927a32a982dSScott Long 			aac_startio(sc);
928a32a982dSScott Long 		}
9299148fa21SScott Long 
9309148fa21SScott Long 		/*
9319148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
9329148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
9339148fa21SScott Long 		 * always fire.
9349148fa21SScott Long 		 */
9359148fa21SScott Long 		if (retval == EWOULDBLOCK)
93670545d1aSScott Long 			aac_timeout(sc);
93770545d1aSScott Long 
93870545d1aSScott Long 		/* Check the hardware printf message buffer */
9399148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
94070545d1aSScott Long 			aac_print_printf(sc);
94170545d1aSScott Long 
9429148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
9437cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
9447cb209f5SScott Long 			continue;
9457cb209f5SScott Long 		for (;;) {
9467cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
9477cb209f5SScott Long 					   &fib_size, &fib))
9487cb209f5SScott Long 				break;
94935863739SMike Smith 
95036e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
95136e0bf6eSScott Long 
95235863739SMike Smith 			switch (fib->Header.Command) {
95335863739SMike Smith 			case AifRequest:
95436e0bf6eSScott Long 				aac_handle_aif(sc, fib);
95535863739SMike Smith 				break;
95635863739SMike Smith 			default:
957914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
958914da7d0SScott Long 					      "from controller\n");
95935863739SMike Smith 				break;
96035863739SMike Smith 			}
96135863739SMike Smith 
96236e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
9637cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
96436e0bf6eSScott Long 				break;
9657cb209f5SScott Long 			}
96636e0bf6eSScott Long 
96770545d1aSScott Long 			/* Return the AIF to the controller. */
96836e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
96936e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
97036e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
97136e0bf6eSScott Long 
97236e0bf6eSScott Long 				/* XXX Compute the Size field? */
97336e0bf6eSScott Long 				size = fib->Header.Size;
97436e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
97536e0bf6eSScott Long 					size = sizeof(struct aac_fib);
97636e0bf6eSScott Long 					fib->Header.Size = size;
97736e0bf6eSScott Long 				}
97836e0bf6eSScott Long 				/*
979914da7d0SScott Long 				 * Since we did not generate this command, it
980914da7d0SScott Long 				 * cannot go through the normal
981914da7d0SScott Long 				 * enqueue->startio chain.
98236e0bf6eSScott Long 				 */
983914da7d0SScott Long 				aac_enqueue_response(sc,
984914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
985914da7d0SScott Long 						 fib);
98636e0bf6eSScott Long 			}
98736e0bf6eSScott Long 		}
98836e0bf6eSScott Long 	}
98936e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
990bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
99136e0bf6eSScott Long 	wakeup(sc->aac_dev);
99236e0bf6eSScott Long 
9933745c395SJulian Elischer 	kproc_exit(0);
99435863739SMike Smith }
99535863739SMike Smith 
996914da7d0SScott Long /*
9979c3a7fceSScott Long  * Process completed commands.
99835863739SMike Smith  */
99935863739SMike Smith static void
10009c3a7fceSScott Long aac_complete(void *context, int pending)
100135863739SMike Smith {
10029c3a7fceSScott Long 	struct aac_softc *sc;
100335863739SMike Smith 	struct aac_command *cm;
100435863739SMike Smith 	struct aac_fib *fib;
100535863739SMike Smith 	u_int32_t fib_size;
100635863739SMike Smith 
100735863739SMike Smith 	debug_called(2);
100835863739SMike Smith 
10099c3a7fceSScott Long 	sc = (struct aac_softc *)context;
10109c3a7fceSScott Long 
1011bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1012ae543596SScott Long 
10139c3a7fceSScott Long 	/* pull completed commands off the queue */
101435863739SMike Smith 	for (;;) {
101535863739SMike Smith 		/* look for completed FIBs on our queue */
1016914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1017914da7d0SScott Long 							&fib))
101835863739SMike Smith 			break;	/* nothing to do */
101935863739SMike Smith 
1020ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1021cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
102235863739SMike Smith 		if (cm == NULL) {
102335863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
10249c3a7fceSScott Long 			break;
10259c3a7fceSScott Long 		}
10260b94a66eSMike Smith 		aac_remove_busy(cm);
10277cb209f5SScott Long 
1028ecd1c51fSScott Long  		aac_unmap_command(cm);
102935863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
103035863739SMike Smith 
103135863739SMike Smith 		/* is there a completion handler? */
103235863739SMike Smith 		if (cm->cm_complete != NULL) {
103335863739SMike Smith 			cm->cm_complete(cm);
103435863739SMike Smith 		} else {
103535863739SMike Smith 			/* assume that someone is sleeping on this command */
103635863739SMike Smith 			wakeup(cm);
103735863739SMike Smith 		}
103835863739SMike Smith 	}
10390b94a66eSMike Smith 
10400b94a66eSMike Smith 	/* see if we can start some more I/O */
1041cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
10420b94a66eSMike Smith 	aac_startio(sc);
1043ae543596SScott Long 
1044bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
104535863739SMike Smith }
104635863739SMike Smith 
1047914da7d0SScott Long /*
104835863739SMike Smith  * Handle a bio submitted from a disk device.
104935863739SMike Smith  */
105035863739SMike Smith void
105135863739SMike Smith aac_submit_bio(struct bio *bp)
105235863739SMike Smith {
1053914da7d0SScott Long 	struct aac_disk *ad;
1054914da7d0SScott Long 	struct aac_softc *sc;
105535863739SMike Smith 
105635863739SMike Smith 	debug_called(2);
105735863739SMike Smith 
10587540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1059914da7d0SScott Long 	sc = ad->ad_controller;
1060914da7d0SScott Long 
106135863739SMike Smith 	/* queue the BIO and try to get some work done */
10620b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
106335863739SMike Smith 	aac_startio(sc);
106435863739SMike Smith }
106535863739SMike Smith 
1066914da7d0SScott Long /*
106735863739SMike Smith  * Get a bio and build a command to go with it.
106835863739SMike Smith  */
106935863739SMike Smith static int
107035863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
107135863739SMike Smith {
107235863739SMike Smith 	struct aac_command *cm;
107335863739SMike Smith 	struct aac_fib *fib;
107435863739SMike Smith 	struct aac_disk *ad;
107535863739SMike Smith 	struct bio *bp;
107635863739SMike Smith 
107735863739SMike Smith 	debug_called(2);
107835863739SMike Smith 
107935863739SMike Smith 	/* get the resources we will need */
108035863739SMike Smith 	cm = NULL;
1081a32a982dSScott Long 	bp = NULL;
108235863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
108335863739SMike Smith 		goto fail;
1084a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1085a32a982dSScott Long 		goto fail;
108635863739SMike Smith 
108735863739SMike Smith 	/* fill out the command */
10880b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
10890b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
10900b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
109135863739SMike Smith 	cm->cm_private = bp;
10922b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
109336e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
109435863739SMike Smith 
109535863739SMike Smith 	/* build the FIB */
109635863739SMike Smith 	fib = cm->cm_fib;
1097b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
109835863739SMike Smith 	fib->Header.XferState =
109935863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
110035863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1101f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
110235863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
110335863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1104f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1105f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1106f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
110735863739SMike Smith 
110835863739SMike Smith 	/* build the read/write request */
11097540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1110b85f5808SScott Long 
11117cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
11127cb209f5SScott Long 		struct aac_raw_io *raw;
11137cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
11147cb209f5SScott Long 		fib->Header.Command = RawIo;
11157cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
11167cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
11177cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
11187cb209f5SScott Long 		raw->BpTotal = 0;
11197cb209f5SScott Long 		raw->BpComplete = 0;
11207cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
11217cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
11227cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
11237cb209f5SScott Long 			raw->Flags = 1;
11247cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
11257cb209f5SScott Long 		} else {
11267cb209f5SScott Long 			raw->Flags = 0;
11277cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
11287cb209f5SScott Long 		}
11297cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1130b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
11319e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1132b85f5808SScott Long 			struct aac_blockread *br;
113335863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
113435863739SMike Smith 			br->Command = VM_CtBlockRead;
113535863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
113635863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
113735863739SMike Smith 			br->ByteCount = bp->bio_bcount;
113835863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
113935863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
114035863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
114135863739SMike Smith 		} else {
1142b85f5808SScott Long 			struct aac_blockwrite *bw;
114335863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
114435863739SMike Smith 			bw->Command = VM_CtBlockWrite;
114535863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
114635863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
114735863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1148b85f5808SScott Long 			bw->Stable = CUNSTABLE;
114935863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
115035863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
115135863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
115235863739SMike Smith 		}
1153b85f5808SScott Long 	} else {
1154b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1155b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1156b85f5808SScott Long 			struct aac_blockread64 *br;
1157b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1158b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1159b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1160b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1161b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1162b85f5808SScott Long 			br->Pad = 0;
1163b85f5808SScott Long 			br->Flags = 0;
1164b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
1165b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
1166eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1167b85f5808SScott Long 		} else {
1168b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1169b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1170b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1171b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1172b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1173b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1174b85f5808SScott Long 			bw->Pad = 0;
1175b85f5808SScott Long 			bw->Flags = 0;
1176b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
1177b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
1178eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1179b85f5808SScott Long 		}
1180b85f5808SScott Long 	}
118135863739SMike Smith 
118235863739SMike Smith 	*cmp = cm;
118335863739SMike Smith 	return(0);
118435863739SMike Smith 
118535863739SMike Smith fail:
11867cb209f5SScott Long 	if (bp != NULL)
11877cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
118835863739SMike Smith 	if (cm != NULL)
118935863739SMike Smith 		aac_release_command(cm);
119035863739SMike Smith 	return(ENOMEM);
119135863739SMike Smith }
119235863739SMike Smith 
1193914da7d0SScott Long /*
119435863739SMike Smith  * Handle a bio-instigated command that has been completed.
119535863739SMike Smith  */
119635863739SMike Smith static void
119735863739SMike Smith aac_bio_complete(struct aac_command *cm)
119835863739SMike Smith {
119935863739SMike Smith 	struct aac_blockread_response *brr;
120035863739SMike Smith 	struct aac_blockwrite_response *bwr;
120135863739SMike Smith 	struct bio *bp;
120235863739SMike Smith 	AAC_FSAStatus status;
120335863739SMike Smith 
120435863739SMike Smith 	/* fetch relevant status and then release the command */
120535863739SMike Smith 	bp = (struct bio *)cm->cm_private;
12069e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
120735863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
120835863739SMike Smith 		status = brr->Status;
120935863739SMike Smith 	} else {
121035863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
121135863739SMike Smith 		status = bwr->Status;
121235863739SMike Smith 	}
121335863739SMike Smith 	aac_release_command(cm);
121435863739SMike Smith 
121535863739SMike Smith 	/* fix up the bio based on status */
121635863739SMike Smith 	if (status == ST_OK) {
121735863739SMike Smith 		bp->bio_resid = 0;
121835863739SMike Smith 	} else {
121935863739SMike Smith 		bp->bio_error = EIO;
122035863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
12210b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1222914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1223914da7d0SScott Long 						    status);
122435863739SMike Smith 	}
12250b94a66eSMike Smith 	aac_biodone(bp);
122635863739SMike Smith }
122735863739SMike Smith 
1228914da7d0SScott Long /*
122935863739SMike Smith  * Submit a command to the controller, return when it completes.
1230b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1231b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1232d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1233d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1234d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1235d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1236d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
123735863739SMike Smith  */
123835863739SMike Smith static int
1239d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
124035863739SMike Smith {
1241ae543596SScott Long 	struct aac_softc *sc;
1242d8a0a473SScott Long 	int error;
124335863739SMike Smith 
124435863739SMike Smith 	debug_called(2);
124535863739SMike Smith 
1246ae543596SScott Long 	sc = cm->cm_sc;
1247ae543596SScott Long 
124835863739SMike Smith 	/* Put the command on the ready queue and get things going */
124936e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
125035863739SMike Smith 	aac_enqueue_ready(cm);
1251ae543596SScott Long 	aac_startio(sc);
1252ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
125335863739SMike Smith 	return(error);
125435863739SMike Smith }
125535863739SMike Smith 
1256914da7d0SScott Long /*
1257914da7d0SScott Long  *Command Buffer Management
1258914da7d0SScott Long  */
125935863739SMike Smith 
1260914da7d0SScott Long /*
126135863739SMike Smith  * Allocate a command.
126235863739SMike Smith  */
1263fe3cb0e1SScott Long int
126435863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
126535863739SMike Smith {
126635863739SMike Smith 	struct aac_command *cm;
126735863739SMike Smith 
126835863739SMike Smith 	debug_called(3);
126935863739SMike Smith 
1270ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1271b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1272ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1273ae543596SScott Long 			wakeup(sc->aifthread);
1274b85f5808SScott Long 		}
1275ae543596SScott Long 		return (EBUSY);
1276ffb37f33SScott Long 	}
127735863739SMike Smith 
12780b94a66eSMike Smith 	*cmp = cm;
12790b94a66eSMike Smith 	return(0);
12800b94a66eSMike Smith }
12810b94a66eSMike Smith 
1282914da7d0SScott Long /*
12830b94a66eSMike Smith  * Release a command back to the freelist.
12840b94a66eSMike Smith  */
1285fe3cb0e1SScott Long void
12860b94a66eSMike Smith aac_release_command(struct aac_command *cm)
12870b94a66eSMike Smith {
12887cb209f5SScott Long 	struct aac_event *event;
12897cb209f5SScott Long 	struct aac_softc *sc;
12907cb209f5SScott Long 
12910b94a66eSMike Smith 	debug_called(3);
12920b94a66eSMike Smith 
12930b94a66eSMike Smith 	/* (re)initialise the command/FIB */
129435863739SMike Smith 	cm->cm_sgtable = NULL;
129535863739SMike Smith 	cm->cm_flags = 0;
129635863739SMike Smith 	cm->cm_complete = NULL;
129735863739SMike Smith 	cm->cm_private = NULL;
129835863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
129935863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
130035863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
13017cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
130235863739SMike Smith 
130335863739SMike Smith 	/*
130435863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
130535863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
130635863739SMike Smith 	 * initialised here for debugging purposes only.
130735863739SMike Smith 	 */
1308f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1309f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
131035863739SMike Smith 
131135863739SMike Smith 	aac_enqueue_free(cm);
13127cb209f5SScott Long 
1313eb5cbaa0SEd Maste 	/*
1314eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1315eb5cbaa0SEd Maste 	 * stranded.
1316eb5cbaa0SEd Maste 	 */
13177cb209f5SScott Long 	sc = cm->cm_sc;
1318eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
13197cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
13207cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
13217cb209f5SScott Long 	}
132235863739SMike Smith }
132335863739SMike Smith 
1324914da7d0SScott Long /*
13250b94a66eSMike Smith  * Map helper for command/FIB allocation.
132635863739SMike Smith  */
132735863739SMike Smith static void
13280b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
132935863739SMike Smith {
13307cb209f5SScott Long 	uint64_t	*fibphys;
1331914da7d0SScott Long 
13327cb209f5SScott Long 	fibphys = (uint64_t *)arg;
133335863739SMike Smith 
133435863739SMike Smith 	debug_called(3);
133535863739SMike Smith 
1336ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
133735863739SMike Smith }
133835863739SMike Smith 
1339914da7d0SScott Long /*
13400b94a66eSMike Smith  * Allocate and initialise commands/FIBs for this adapter.
134135863739SMike Smith  */
13420b94a66eSMike Smith static int
13430b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
134435863739SMike Smith {
134535863739SMike Smith 	struct aac_command *cm;
1346ffb37f33SScott Long 	struct aac_fibmap *fm;
13477cb209f5SScott Long 	uint64_t fibphys;
1348ffb37f33SScott Long 	int i, error;
134935863739SMike Smith 
1350a6d35632SScott Long 	debug_called(2);
135135863739SMike Smith 
13527cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1353ffb37f33SScott Long 		return (ENOMEM);
1354ffb37f33SScott Long 
13558480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1356a6d35632SScott Long 	if (fm == NULL)
1357a6d35632SScott Long 		return (ENOMEM);
1358ffb37f33SScott Long 
13590b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1360ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1361ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
136270545d1aSScott Long 		device_printf(sc->aac_dev,
136370545d1aSScott Long 			      "Not enough contiguous memory available.\n");
13648480cc63SScott Long 		free(fm, M_AACBUF);
13650b94a66eSMike Smith 		return (ENOMEM);
136635863739SMike Smith 	}
1367128aa5a0SScott Long 
1368cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1369cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
13707cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1371ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1372128aa5a0SScott Long 
13730b94a66eSMike Smith 	/* initialise constant fields in the command structure */
13747cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
13757cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
13768480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1377ffb37f33SScott Long 		fm->aac_commands = cm;
137835863739SMike Smith 		cm->cm_sc = sc;
13797cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
13807cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
13817cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1382cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
138335863739SMike Smith 
1384ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
138593cfca22SScott Long 					       &cm->cm_datamap)) != 0)
13868480cc63SScott Long 			break;
138793cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
138893cfca22SScott Long 		aac_release_command(cm);
13898480cc63SScott Long 		sc->total_fibs++;
139093cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
139135863739SMike Smith 	}
1392ffb37f33SScott Long 
13938480cc63SScott Long 	if (i > 0) {
139493cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1395ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1396a6d35632SScott Long 		debug(1, "total_fibs= %d\n", sc->total_fibs);
1397bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
13980b94a66eSMike Smith 		return (0);
139935863739SMike Smith 	}
140035863739SMike Smith 
14018480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
14028480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
14038480cc63SScott Long 	free(fm, M_AACBUF);
14048480cc63SScott Long 	return (ENOMEM);
14058480cc63SScott Long }
14068480cc63SScott Long 
1407914da7d0SScott Long /*
14080b94a66eSMike Smith  * Free FIBs owned by this adapter.
140935863739SMike Smith  */
141035863739SMike Smith static void
14118480cc63SScott Long aac_free_commands(struct aac_softc *sc)
141235863739SMike Smith {
14138480cc63SScott Long 	struct aac_fibmap *fm;
1414ffb37f33SScott Long 	struct aac_command *cm;
141535863739SMike Smith 	int i;
141635863739SMike Smith 
141735863739SMike Smith 	debug_called(1);
141835863739SMike Smith 
14198480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
14208480cc63SScott Long 
14218480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
14228480cc63SScott Long 		/*
14238480cc63SScott Long 		 * We check against total_fibs to handle partially
14248480cc63SScott Long 		 * allocated blocks.
14258480cc63SScott Long 		 */
14267cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1427ffb37f33SScott Long 			cm = fm->aac_commands + i;
1428ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1429ffb37f33SScott Long 		}
1430ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1431ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
14328480cc63SScott Long 		free(fm, M_AACBUF);
14338480cc63SScott Long 	}
143435863739SMike Smith }
143535863739SMike Smith 
1436914da7d0SScott Long /*
143735863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
143835863739SMike Smith  */
143935863739SMike Smith static void
144035863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
144135863739SMike Smith {
1442cd481291SScott Long 	struct aac_softc *sc;
1443914da7d0SScott Long 	struct aac_command *cm;
1444914da7d0SScott Long 	struct aac_fib *fib;
144535863739SMike Smith 	int i;
144635863739SMike Smith 
144735863739SMike Smith 	debug_called(3);
144835863739SMike Smith 
1449914da7d0SScott Long 	cm = (struct aac_command *)arg;
1450cd481291SScott Long 	sc = cm->cm_sc;
1451914da7d0SScott Long 	fib = cm->cm_fib;
1452914da7d0SScott Long 
145335863739SMike Smith 	/* copy into the FIB */
1454b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
14557cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
14567cb209f5SScott Long 			struct aac_sg_tableraw *sg;
14577cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
14587cb209f5SScott Long 			sg->SgCount = nseg;
14597cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
14607cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
14617cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
14627cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
14637cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
14647cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
14657cb209f5SScott Long 			}
14667cb209f5SScott Long 			/* update the FIB size for the s/g count */
14677cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
14687cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1469b85f5808SScott Long 			struct aac_sg_table *sg;
1470b85f5808SScott Long 			sg = cm->cm_sgtable;
147135863739SMike Smith 			sg->SgCount = nseg;
147235863739SMike Smith 			for (i = 0; i < nseg; i++) {
147335863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
147435863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
147535863739SMike Smith 			}
147635863739SMike Smith 			/* update the FIB size for the s/g count */
147735863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1478b85f5808SScott Long 		} else {
1479b85f5808SScott Long 			struct aac_sg_table64 *sg;
1480b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1481b85f5808SScott Long 			sg->SgCount = nseg;
1482b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1483b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1484b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
148535863739SMike Smith 			}
1486b85f5808SScott Long 			/* update the FIB size for the s/g count */
1487b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1488b85f5808SScott Long 		}
1489b85f5808SScott Long 	}
149035863739SMike Smith 
1491cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1492cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
14937cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
14947cb209f5SScott Long 	 * and for the AIF bit
149535863739SMike Smith 	 */
14967cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
14977cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
149835863739SMike Smith 
1499cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1500cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
150135863739SMike Smith 
150235863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1503c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1504c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
150535863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1506c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1507c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
150835863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1509cd481291SScott Long 
15107cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
15117cb209f5SScott Long 		int count = 10000000L;
15127cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
15137cb209f5SScott Long 			if (--count == 0) {
15147cb209f5SScott Long 				aac_unmap_command(cm);
15157cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
15167cb209f5SScott Long 				aac_requeue_ready(cm);
15177cb209f5SScott Long 			}
15187cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
15197cb209f5SScott Long 		}
15207cb209f5SScott Long 	} else {
1521397fa34fSScott Long 		/* Put the FIB on the outbound queue */
15224102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
15234102d44bSScott Long 			aac_unmap_command(cm);
1524397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1525cd481291SScott Long 			aac_requeue_ready(cm);
15264102d44bSScott Long 		}
15277cb209f5SScott Long 	}
1528cd481291SScott Long 
1529cd481291SScott Long 	return;
153035863739SMike Smith }
153135863739SMike Smith 
1532914da7d0SScott Long /*
153335863739SMike Smith  * Unmap a command from controller-visible space.
153435863739SMike Smith  */
153535863739SMike Smith static void
153635863739SMike Smith aac_unmap_command(struct aac_command *cm)
153735863739SMike Smith {
1538914da7d0SScott Long 	struct aac_softc *sc;
153935863739SMike Smith 
154035863739SMike Smith 	debug_called(2);
154135863739SMike Smith 
1542914da7d0SScott Long 	sc = cm->cm_sc;
1543914da7d0SScott Long 
154435863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
154535863739SMike Smith 		return;
154635863739SMike Smith 
154735863739SMike Smith 	if (cm->cm_datalen != 0) {
154835863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1549c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1550c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
155135863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1552c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1553c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
155435863739SMike Smith 
155535863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
155635863739SMike Smith 	}
155735863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
155835863739SMike Smith }
155935863739SMike Smith 
1560914da7d0SScott Long /*
1561914da7d0SScott Long  * Hardware Interface
1562914da7d0SScott Long  */
156335863739SMike Smith 
1564914da7d0SScott Long /*
156535863739SMike Smith  * Initialise the adapter.
156635863739SMike Smith  */
156735863739SMike Smith static void
156835863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
156935863739SMike Smith {
1570914da7d0SScott Long 	struct aac_softc *sc;
157135863739SMike Smith 
157235863739SMike Smith 	debug_called(1);
157335863739SMike Smith 
1574914da7d0SScott Long 	sc = (struct aac_softc *)arg;
1575914da7d0SScott Long 
157635863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
157735863739SMike Smith }
157835863739SMike Smith 
1579a6d35632SScott Long static int
1580a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1581a6d35632SScott Long {
1582a441b3fcSScott Long 	u_int32_t major, minor, options = 0, atu_size = 0;
1583a441b3fcSScott Long 	int status;
1584a6d35632SScott Long 
1585a6d35632SScott Long 	debug_called(1);
1586a6d35632SScott Long 
1587fe94b852SScott Long 	/*
1588fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1589fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1590fe94b852SScott Long 	 */
1591a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1592fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1593fe94b852SScott Long 				     NULL)) {
1594fe94b852SScott Long 			device_printf(sc->aac_dev,
1595fe94b852SScott Long 				      "Error reading firmware version\n");
1596fe94b852SScott Long 			return (EIO);
1597fe94b852SScott Long 		}
1598fe94b852SScott Long 
1599fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1600a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1601a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1602fe94b852SScott Long 		if (major == 1) {
1603fe94b852SScott Long 			device_printf(sc->aac_dev,
1604fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1605fe94b852SScott Long 			    major, minor);
1606fe94b852SScott Long 			return (EINVAL);
1607fe94b852SScott Long 		}
1608fe94b852SScott Long 	}
1609fe94b852SScott Long 
1610a6d35632SScott Long 	/*
1611a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1612a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1613a441b3fcSScott Long 	 * command.
1614a6d35632SScott Long 	 */
1615a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1616a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1617a441b3fcSScott Long 			device_printf(sc->aac_dev,
1618a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1619a6d35632SScott Long 			return (EIO);
1620a6d35632SScott Long 		}
1621a441b3fcSScott Long 	} else {
1622a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
16237cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1624a6d35632SScott Long 		sc->supported_options = options;
1625a6d35632SScott Long 
1626a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1627a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1628a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1629a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1630a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1631cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1632cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1633a441b3fcSScott Long 			device_printf(sc->aac_dev,
1634a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1635a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1636a6d35632SScott Long 		}
1637a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1638a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
16397cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
16407cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
16417cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1642a441b3fcSScott Long 	}
1643a6d35632SScott Long 
1644a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
16457cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
16467cb209f5SScott Long 
16477cb209f5SScott Long 	/* Remap mem. resource, if required */
16487cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
16497cb209f5SScott Long 		atu_size > rman_get_size(sc->aac_regs_resource)) {
16507cb209f5SScott Long 		bus_release_resource(
16517cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
16527cb209f5SScott Long 			sc->aac_regs_rid, sc->aac_regs_resource);
16537cb209f5SScott Long 		sc->aac_regs_resource = bus_alloc_resource(
16547cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
16557cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
16567cb209f5SScott Long 		if (sc->aac_regs_resource == NULL) {
16577cb209f5SScott Long 			sc->aac_regs_resource = bus_alloc_resource_any(
16587cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
16597cb209f5SScott Long 				&sc->aac_regs_rid, RF_ACTIVE);
16607cb209f5SScott Long 			if (sc->aac_regs_resource == NULL) {
16617cb209f5SScott Long 				device_printf(sc->aac_dev,
16627cb209f5SScott Long 				    "couldn't allocate register window\n");
16637cb209f5SScott Long 				return (ENXIO);
16647cb209f5SScott Long 			}
16657cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
16667cb209f5SScott Long 		}
16677cb209f5SScott Long 		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
16687cb209f5SScott Long 		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
16697cb209f5SScott Long 	}
16707cb209f5SScott Long 
16717cb209f5SScott Long 	/* Read preferred settings */
16727cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
16737cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
16747cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1675a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
16767e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
16777e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1678a6d35632SScott Long 	else
1679a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
16807e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
16817e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1682a441b3fcSScott Long 
16837cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
16847cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
16857cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
16867cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
16877cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
16887cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
16897cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
16907cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
16917cb209f5SScott Long 	}
16927cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
16937cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
16947cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1695a6d35632SScott Long 
1696fe94b852SScott Long 	return (0);
1697fe94b852SScott Long }
1698fe94b852SScott Long 
169935863739SMike Smith static int
170035863739SMike Smith aac_init(struct aac_softc *sc)
170135863739SMike Smith {
170235863739SMike Smith 	struct aac_adapter_init	*ip;
170335863739SMike Smith 	time_t then;
1704b88ffdc8SScott Long 	u_int32_t code, qoffset;
1705a6d35632SScott Long 	int error;
170635863739SMike Smith 
170735863739SMike Smith 	debug_called(1);
170835863739SMike Smith 
170935863739SMike Smith 	/*
171035863739SMike Smith 	 * First wait for the adapter to come ready.
171135863739SMike Smith 	 */
17122b3b0f17SScott Long 	then = time_uptime;
171335863739SMike Smith 	do {
171435863739SMike Smith 		code = AAC_GET_FWSTATUS(sc);
171535863739SMike Smith 		if (code & AAC_SELF_TEST_FAILED) {
171635863739SMike Smith 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
171735863739SMike Smith 			return(ENXIO);
171835863739SMike Smith 		}
171935863739SMike Smith 		if (code & AAC_KERNEL_PANIC) {
1720914da7d0SScott Long 			device_printf(sc->aac_dev,
1721914da7d0SScott Long 				      "FATAL: controller kernel panic\n");
172235863739SMike Smith 			return(ENXIO);
172335863739SMike Smith 		}
17242b3b0f17SScott Long 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
1725914da7d0SScott Long 			device_printf(sc->aac_dev,
1726914da7d0SScott Long 				      "FATAL: controller not coming ready, "
1727c6eafcf2SScott Long 					   "status %x\n", code);
172835863739SMike Smith 			return(ENXIO);
172935863739SMike Smith 		}
173035863739SMike Smith 	} while (!(code & AAC_UP_AND_RUNNING));
173135863739SMike Smith 
1732a6d35632SScott Long 	error = ENOMEM;
1733a6d35632SScott Long 	/*
1734a6d35632SScott Long 	 * Create DMA tag for mapping buffers into controller-addressable space.
1735a6d35632SScott Long 	 */
1736a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1737a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1738a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1739a6d35632SScott Long 			       BUS_SPACE_MAXADDR :
1740a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1741a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1742a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1743a6d35632SScott Long 			       MAXBSIZE,		/* maxsize */
17447cb209f5SScott Long 			       sc->aac_sg_tablesize,	/* nsegments */
1745a6d35632SScott Long 			       MAXBSIZE,		/* maxsegsize */
1746a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1747f6b1c44dSScott Long 			       busdma_lock_mutex,	/* lockfunc */
1748f6b1c44dSScott Long 			       &sc->aac_io_lock,	/* lockfuncarg */
1749a6d35632SScott Long 			       &sc->aac_buffer_dmat)) {
1750a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1751a6d35632SScott Long 		goto out;
1752a6d35632SScott Long 	}
1753a6d35632SScott Long 
1754a6d35632SScott Long 	/*
1755a6d35632SScott Long 	 * Create DMA tag for mapping FIBs into controller-addressable space..
1756a6d35632SScott Long 	 */
1757a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1758a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1759a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1760a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1761a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
1762a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1763a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
17647cb209f5SScott Long 			       sc->aac_max_fibs_alloc *
17657cb209f5SScott Long 			       sc->aac_max_fib_size,  /* maxsize */
1766a6d35632SScott Long 			       1,			/* nsegments */
17677cb209f5SScott Long 			       sc->aac_max_fibs_alloc *
17687cb209f5SScott Long 			       sc->aac_max_fib_size,	/* maxsegsize */
17691248408dSScott Long 			       0,			/* flags */
1770f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
1771a6d35632SScott Long 			       &sc->aac_fib_dmat)) {
1772a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1773a6d35632SScott Long 		goto out;
1774a6d35632SScott Long 	}
1775a6d35632SScott Long 
177635863739SMike Smith 	/*
177735863739SMike Smith 	 * Create DMA tag for the common structure and allocate it.
177835863739SMike Smith 	 */
177935863739SMike Smith 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1780c6eafcf2SScott Long 			       1, 0,			/* algnmnt, boundary */
1781a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1782a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1783a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
178435863739SMike Smith 			       BUS_SPACE_MAXADDR, 	/* highaddr */
178535863739SMike Smith 			       NULL, NULL, 		/* filter, filterarg */
1786ffb37f33SScott Long 			       8192 + sizeof(struct aac_common), /* maxsize */
1787914da7d0SScott Long 			       1,			/* nsegments */
178835863739SMike Smith 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
17891248408dSScott Long 			       0,			/* flags */
1790f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
179135863739SMike Smith 			       &sc->aac_common_dmat)) {
1792914da7d0SScott Long 		device_printf(sc->aac_dev,
1793914da7d0SScott Long 			      "can't allocate common structure DMA tag\n");
1794a6d35632SScott Long 		goto out;
179535863739SMike Smith 	}
1796c6eafcf2SScott Long 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1797c6eafcf2SScott Long 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
179835863739SMike Smith 		device_printf(sc->aac_dev, "can't allocate common structure\n");
1799a6d35632SScott Long 		goto out;
180035863739SMike Smith 	}
1801ffb37f33SScott Long 
1802ffb37f33SScott Long 	/*
1803ffb37f33SScott Long 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1804ffb37f33SScott Long 	 * below address 8192 in physical memory.
1805ffb37f33SScott Long 	 * XXX If the padding is not needed, can it be put to use instead
1806ffb37f33SScott Long 	 * of ignored?
1807ffb37f33SScott Long 	 */
1808cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1809ffb37f33SScott Long 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1810ffb37f33SScott Long 			aac_common_map, sc, 0);
1811ffb37f33SScott Long 
1812ffb37f33SScott Long 	if (sc->aac_common_busaddr < 8192) {
1813eec256deSAlexander Kabaev 		sc->aac_common = (struct aac_common *)
1814eec256deSAlexander Kabaev 		    ((uint8_t *)sc->aac_common + 8192);
1815ffb37f33SScott Long 		sc->aac_common_busaddr += 8192;
1816ffb37f33SScott Long 	}
181735863739SMike Smith 	bzero(sc->aac_common, sizeof(*sc->aac_common));
181835863739SMike Smith 
1819ffb37f33SScott Long 	/* Allocate some FIBs and associated command structs */
1820ffb37f33SScott Long 	TAILQ_INIT(&sc->aac_fibmap_tqh);
18217cb209f5SScott Long 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
18228480cc63SScott Long 				  M_AACBUF, M_WAITOK|M_ZERO);
18238480cc63SScott Long 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1824ffb37f33SScott Long 		if (aac_alloc_commands(sc) != 0)
1825ffb37f33SScott Long 			break;
1826ffb37f33SScott Long 	}
1827ffb37f33SScott Long 	if (sc->total_fibs == 0)
1828a6d35632SScott Long 		goto out;
1829ffb37f33SScott Long 
183035863739SMike Smith 	/*
1831914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1832914da7d0SScott Long 	 * physical location of various important shared data structures.
183335863739SMike Smith 	 */
183435863739SMike Smith 	ip = &sc->aac_common->ac_init;
183535863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18367cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18377cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18387cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18397cb209f5SScott Long 	}
1840f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
184135863739SMike Smith 
1842c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1843c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1844149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
184535863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
184635863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
184735863739SMike Smith 
1848c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1849c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
185035863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
185135863739SMike Smith 
18524b00f859SScott Long 	/*
18534b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18544b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18554b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18564b00f859SScott Long 	 * Round up since the granularity is so high.
18574b00f859SScott Long 	 */
1858f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18594b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18604b00f859SScott Long 		ip->HostPhysMemPages =
18614b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1862204c0befSScott Long 	}
18632b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
186435863739SMike Smith 
18657cb209f5SScott Long 	ip->InitFlags = 0;
18667cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
18677cb209f5SScott Long 		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
18687cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
18697cb209f5SScott Long 	}
18707cb209f5SScott Long 
18717cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
18727cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
18737cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
18747cb209f5SScott Long 
187535863739SMike Smith 	/*
1876c6eafcf2SScott Long 	 * Initialise FIB queues.  Note that it appears that the layout of the
1877c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1878c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
187935863739SMike Smith 	 *
188035863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1881914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1882914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1883914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1884914da7d0SScott Long 	 * does.
188535863739SMike Smith 	 *
1886914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1887914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1888914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1889914da7d0SScott Long 	 * virtue of a table.
189035863739SMike Smith 	 */
1891b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
18920bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
18930bcbebd6SScott Long 	sc->aac_queues =
18940bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1895b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
189635863739SMike Smith 
1897c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1898c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1899c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1900c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1901c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1902c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1903c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1904c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1905c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1906c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1907c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1908c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1909c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1910c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1911c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1912c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1913c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1914c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1915c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1916c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1917c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1918c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1919c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1920c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1921c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1922c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1923c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1924c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1925c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1926c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1927c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1928c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1929c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1930c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1931c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1932c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1933c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1934c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1935c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1936c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1937c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1938c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1939c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1940c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1941c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1942c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1943c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1944c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
194535863739SMike Smith 
194635863739SMike Smith 	/*
194735863739SMike Smith 	 * Do controller-type-specific initialisation
194835863739SMike Smith 	 */
194935863739SMike Smith 	switch (sc->aac_hwif) {
195035863739SMike Smith 	case AAC_HWIF_I960RX:
195135863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
195235863739SMike Smith 		break;
19534afedc31SScott Long 	case AAC_HWIF_RKT:
19544afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
19554afedc31SScott Long 		break;
19564afedc31SScott Long 	default:
19574afedc31SScott Long 		break;
195835863739SMike Smith 	}
195935863739SMike Smith 
196035863739SMike Smith 	/*
196135863739SMike Smith 	 * Give the init structure to the controller.
196235863739SMike Smith 	 */
196335863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1964914da7d0SScott Long 			     sc->aac_common_busaddr +
1965914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1966914da7d0SScott Long 			     NULL)) {
1967914da7d0SScott Long 		device_printf(sc->aac_dev,
1968914da7d0SScott Long 			      "error establishing init structure\n");
1969a6d35632SScott Long 		error = EIO;
1970a6d35632SScott Long 		goto out;
197135863739SMike Smith 	}
197235863739SMike Smith 
1973a6d35632SScott Long 	error = 0;
1974a6d35632SScott Long out:
1975a6d35632SScott Long 	return(error);
197635863739SMike Smith }
197735863739SMike Smith 
1978914da7d0SScott Long /*
197935863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
19807cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
198135863739SMike Smith  */
198235863739SMike Smith static int
198335863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
198435863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
198535863739SMike Smith 		 u_int32_t *sp)
198635863739SMike Smith {
198735863739SMike Smith 	time_t then;
198835863739SMike Smith 	u_int32_t status;
198935863739SMike Smith 
199035863739SMike Smith 	debug_called(3);
199135863739SMike Smith 
199235863739SMike Smith 	/* populate the mailbox */
199335863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
199435863739SMike Smith 
199535863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
199635863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
199735863739SMike Smith 
199835863739SMike Smith 	/* then set it to signal the adapter */
199935863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
200035863739SMike Smith 
200135863739SMike Smith 	/* spin waiting for the command to complete */
20022b3b0f17SScott Long 	then = time_uptime;
200335863739SMike Smith 	do {
20042b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
2005a6d35632SScott Long 			debug(1, "timed out");
200635863739SMike Smith 			return(EIO);
200735863739SMike Smith 		}
200835863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
200935863739SMike Smith 
201035863739SMike Smith 	/* clear the completion flag */
201135863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
201235863739SMike Smith 
201335863739SMike Smith 	/* get the command status */
2014a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
201535863739SMike Smith 	if (sp != NULL)
201635863739SMike Smith 		*sp = status;
20177cb209f5SScott Long 
2018a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20197cb209f5SScott Long 		return (-1);
20200b94a66eSMike Smith 	return(0);
202135863739SMike Smith }
202235863739SMike Smith 
2023cbfd045bSScott Long int
202435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2025cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
202635863739SMike Smith {
202735863739SMike Smith 	debug_called(3);
20287cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
202935863739SMike Smith 
203035863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
203135863739SMike Smith 		return(EINVAL);
203235863739SMike Smith 
203335863739SMike Smith 	/*
203435863739SMike Smith 	 * Set up the sync FIB
203535863739SMike Smith 	 */
2036914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2037914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2038c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
203935863739SMike Smith 	fib->Header.XferState |= xferstate;
204035863739SMike Smith 	fib->Header.Command = command;
204135863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
204235863739SMike Smith 	fib->Header.Size = sizeof(struct aac_fib) + datasize;
204335863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2044b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2045c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2046914da7d0SScott Long 					 offsetof(struct aac_common,
2047914da7d0SScott Long 						  ac_sync_fib);
204835863739SMike Smith 
204935863739SMike Smith 	/*
205035863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
205135863739SMike Smith 	 */
2052914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2053914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
205435863739SMike Smith 		debug(2, "IO error");
205535863739SMike Smith 		return(EIO);
205635863739SMike Smith 	}
205735863739SMike Smith 
205835863739SMike Smith 	return (0);
205935863739SMike Smith }
206035863739SMike Smith 
2061914da7d0SScott Long /*
206235863739SMike Smith  * Adapter-space FIB queue manipulation
206335863739SMike Smith  *
206435863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
206535863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
206635863739SMike Smith  */
206735863739SMike Smith static struct {
206835863739SMike Smith 	int		size;
206935863739SMike Smith 	int		notify;
207035863739SMike Smith } aac_qinfo[] = {
207135863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
207235863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
207335863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
207435863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
207535863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
207635863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
207735863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
207835863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
207935863739SMike Smith };
208035863739SMike Smith 
208135863739SMike Smith /*
2082c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2083c6eafcf2SScott Long  * EBUSY if the queue is full.
208435863739SMike Smith  *
20850b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2086914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2087914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2088c6eafcf2SScott Long  *	 separate queue/notify interface).
208935863739SMike Smith  */
209035863739SMike Smith static int
2091f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
209235863739SMike Smith {
209335863739SMike Smith 	u_int32_t pi, ci;
20949e2e96d8SScott Long 	int error;
2095f6c4dd3fSScott Long 	u_int32_t fib_size;
2096f6c4dd3fSScott Long 	u_int32_t fib_addr;
2097f6c4dd3fSScott Long 
209836e0bf6eSScott Long 	debug_called(3);
209936e0bf6eSScott Long 
2100f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2101f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
210235863739SMike Smith 
210335863739SMike Smith 	/* get the producer/consumer indices */
210435863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
210535863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
210635863739SMike Smith 
210735863739SMike Smith 	/* wrap the queue? */
210835863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
210935863739SMike Smith 		pi = 0;
211035863739SMike Smith 
211135863739SMike Smith 	/* check for queue full */
211235863739SMike Smith 	if ((pi + 1) == ci) {
211335863739SMike Smith 		error = EBUSY;
211435863739SMike Smith 		goto out;
211535863739SMike Smith 	}
211635863739SMike Smith 
2117614c22b2SScott Long 	/*
2118614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2119614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2120614c22b2SScott Long 	 */
2121614c22b2SScott Long 	aac_enqueue_busy(cm);
2122614c22b2SScott Long 
212335863739SMike Smith 	/* populate queue entry */
212435863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
212535863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
212635863739SMike Smith 
212735863739SMike Smith 	/* update producer index */
212835863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
212935863739SMike Smith 
213035863739SMike Smith 	/* notify the adapter if we know how */
213135863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
213235863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
213335863739SMike Smith 
213435863739SMike Smith 	error = 0;
213535863739SMike Smith 
213635863739SMike Smith out:
213735863739SMike Smith 	return(error);
213835863739SMike Smith }
213935863739SMike Smith 
214035863739SMike Smith /*
214136e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
214236e0bf6eSScott Long  * success or ENOENT if the queue is empty.
214335863739SMike Smith  */
214435863739SMike Smith static int
2145c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2146c6eafcf2SScott Long 		struct aac_fib **fib_addr)
214735863739SMike Smith {
214835863739SMike Smith 	u_int32_t pi, ci;
2149149af931SScott Long 	u_int32_t fib_index;
21509e2e96d8SScott Long 	int error;
2151f6c4dd3fSScott Long 	int notify;
215235863739SMike Smith 
215335863739SMike Smith 	debug_called(3);
215435863739SMike Smith 
215535863739SMike Smith 	/* get the producer/consumer indices */
215635863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
215735863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
215835863739SMike Smith 
215935863739SMike Smith 	/* check for queue empty */
216035863739SMike Smith 	if (ci == pi) {
216135863739SMike Smith 		error = ENOENT;
216235863739SMike Smith 		goto out;
216335863739SMike Smith 	}
216435863739SMike Smith 
21657753acd2SScott Long 	/* wrap the pi so the following test works */
21667753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
21677753acd2SScott Long 		pi = 0;
21687753acd2SScott Long 
2169f6c4dd3fSScott Long 	notify = 0;
2170f6c4dd3fSScott Long 	if (ci == pi + 1)
2171f6c4dd3fSScott Long 		notify++;
2172f6c4dd3fSScott Long 
217335863739SMike Smith 	/* wrap the queue? */
217435863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
217535863739SMike Smith 		ci = 0;
217635863739SMike Smith 
217735863739SMike Smith 	/* fetch the entry */
217835863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2179149af931SScott Long 
2180149af931SScott Long 	switch (queue) {
2181149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2182149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2183149af931SScott Long 		/*
2184149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2185149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2186149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2187149af931SScott Long 		 * Therefore, we have to convert it to an index.
2188149af931SScott Long 		 */
2189149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2190149af931SScott Long 			sizeof(struct aac_fib);
2191149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2192149af931SScott Long 		break;
2193149af931SScott Long 
2194149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2195149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2196149af931SScott Long 	{
2197149af931SScott Long 		struct aac_command *cm;
2198149af931SScott Long 
2199149af931SScott Long 		/*
2200149af931SScott Long 		 * As above, an index is used instead of an actual address.
2201149af931SScott Long 		 * Gotta shift the index to account for the fast response
2202149af931SScott Long 		 * bit.  No other correction is needed since this value was
2203149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2204149af931SScott Long 		 * field.
2205149af931SScott Long 		 */
2206149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22077cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2208149af931SScott Long 		*fib_addr = cm->cm_fib;
220935863739SMike Smith 
2210f30ac74cSScott Long 		/*
2211f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2212149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2213f30ac74cSScott Long 		 */
2214149af931SScott Long 		if (fib_index & 0x01) {
2215f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2216f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2217f30ac74cSScott Long 		}
2218149af931SScott Long 		break;
2219149af931SScott Long 	}
2220149af931SScott Long 	default:
2221149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2222149af931SScott Long 		break;
2223149af931SScott Long 	}
2224149af931SScott Long 
222535863739SMike Smith 	/* update consumer index */
222635863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
222735863739SMike Smith 
222835863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2229f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
223035863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
223135863739SMike Smith 	error = 0;
223235863739SMike Smith 
223335863739SMike Smith out:
223435863739SMike Smith 	return(error);
223535863739SMike Smith }
223635863739SMike Smith 
2237914da7d0SScott Long /*
223836e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
223936e0bf6eSScott Long  */
224036e0bf6eSScott Long static int
224136e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
224236e0bf6eSScott Long {
224336e0bf6eSScott Long 	u_int32_t pi, ci;
22449e2e96d8SScott Long 	int error;
224536e0bf6eSScott Long 	u_int32_t fib_size;
224636e0bf6eSScott Long 	u_int32_t fib_addr;
224736e0bf6eSScott Long 
224836e0bf6eSScott Long 	debug_called(1);
224936e0bf6eSScott Long 
225036e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
225136e0bf6eSScott Long 	fib_size = fib->Header.Size;
225236e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
225336e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
225436e0bf6eSScott Long 
225536e0bf6eSScott Long 	/* get the producer/consumer indices */
225636e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
225736e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
225836e0bf6eSScott Long 
225936e0bf6eSScott Long 	/* wrap the queue? */
226036e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
226136e0bf6eSScott Long 		pi = 0;
226236e0bf6eSScott Long 
226336e0bf6eSScott Long 	/* check for queue full */
226436e0bf6eSScott Long 	if ((pi + 1) == ci) {
226536e0bf6eSScott Long 		error = EBUSY;
226636e0bf6eSScott Long 		goto out;
226736e0bf6eSScott Long 	}
226836e0bf6eSScott Long 
226936e0bf6eSScott Long 	/* populate queue entry */
227036e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
227136e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
227236e0bf6eSScott Long 
227336e0bf6eSScott Long 	/* update producer index */
227436e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
227536e0bf6eSScott Long 
227636e0bf6eSScott Long 	/* notify the adapter if we know how */
227736e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
227836e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
227936e0bf6eSScott Long 
228036e0bf6eSScott Long 	error = 0;
228136e0bf6eSScott Long 
228236e0bf6eSScott Long out:
228336e0bf6eSScott Long 	return(error);
228436e0bf6eSScott Long }
228536e0bf6eSScott Long 
2286914da7d0SScott Long /*
22870b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
22880b94a66eSMike Smith  * and complain about them.
22890b94a66eSMike Smith  */
22900b94a66eSMike Smith static void
22910b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
22920b94a66eSMike Smith {
22930b94a66eSMike Smith 	struct aac_command *cm;
22940b94a66eSMike Smith 	time_t deadline;
229515c37be0SScott Long 	int timedout, code;
22960b94a66eSMike Smith 
2297f6c4dd3fSScott Long 	/*
229870545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2299914da7d0SScott Long 	 * only.
2300914da7d0SScott Long 	 */
230115c37be0SScott Long 	timedout = 0;
23022b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23030b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2304f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2305f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
23060b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2307914da7d0SScott Long 			device_printf(sc->aac_dev,
2308914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
23092b3b0f17SScott Long 				      cm, (int)(time_uptime-cm->cm_timestamp));
23100b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
231115c37be0SScott Long 			timedout++;
23120b94a66eSMike Smith 		}
23130b94a66eSMike Smith 	}
23140b94a66eSMike Smith 
231515c37be0SScott Long 	if (timedout) {
231615c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
231715c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
231815c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
231915c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
232015c37be0SScott Long 		}
232115c37be0SScott Long 	}
23220b94a66eSMike Smith 	return;
23230b94a66eSMike Smith }
23240b94a66eSMike Smith 
2325914da7d0SScott Long /*
2326914da7d0SScott Long  * Interface Function Vectors
2327914da7d0SScott Long  */
232835863739SMike Smith 
2329914da7d0SScott Long /*
233035863739SMike Smith  * Read the current firmware status word.
233135863739SMike Smith  */
233235863739SMike Smith static int
233335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
233435863739SMike Smith {
233535863739SMike Smith 	debug_called(3);
233635863739SMike Smith 
233735863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
233835863739SMike Smith }
233935863739SMike Smith 
234035863739SMike Smith static int
234135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
234235863739SMike Smith {
234335863739SMike Smith 	debug_called(3);
234435863739SMike Smith 
234535863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
234635863739SMike Smith }
234735863739SMike Smith 
2348b3457b51SScott Long static int
2349b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2350b3457b51SScott Long {
2351b3457b51SScott Long 	int val;
2352b3457b51SScott Long 
2353b3457b51SScott Long 	debug_called(3);
2354b3457b51SScott Long 
2355b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2356b3457b51SScott Long 	return (val);
2357b3457b51SScott Long }
2358b3457b51SScott Long 
23594afedc31SScott Long static int
23604afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
23614afedc31SScott Long {
23624afedc31SScott Long 	debug_called(3);
23634afedc31SScott Long 
23644afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
23654afedc31SScott Long }
23664afedc31SScott Long 
2367914da7d0SScott Long /*
236835863739SMike Smith  * Notify the controller of a change in a given queue
236935863739SMike Smith  */
237035863739SMike Smith 
237135863739SMike Smith static void
237235863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
237335863739SMike Smith {
237435863739SMike Smith 	debug_called(3);
237535863739SMike Smith 
237635863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
237735863739SMike Smith }
237835863739SMike Smith 
237935863739SMike Smith static void
238035863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
238135863739SMike Smith {
238235863739SMike Smith 	debug_called(3);
238335863739SMike Smith 
238435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
238535863739SMike Smith }
238635863739SMike Smith 
2387b3457b51SScott Long static void
2388b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2389b3457b51SScott Long {
2390b3457b51SScott Long 	debug_called(3);
2391b3457b51SScott Long 
2392b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2393b3457b51SScott Long 	AAC_FA_HACK(sc);
2394b3457b51SScott Long }
2395b3457b51SScott Long 
23964afedc31SScott Long static void
23974afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
23984afedc31SScott Long {
23994afedc31SScott Long 	debug_called(3);
24004afedc31SScott Long 
24014afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
24024afedc31SScott Long }
24034afedc31SScott Long 
2404914da7d0SScott Long /*
240535863739SMike Smith  * Get the interrupt reason bits
240635863739SMike Smith  */
240735863739SMike Smith static int
240835863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
240935863739SMike Smith {
241035863739SMike Smith 	debug_called(3);
241135863739SMike Smith 
241235863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
241335863739SMike Smith }
241435863739SMike Smith 
241535863739SMike Smith static int
241635863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
241735863739SMike Smith {
241835863739SMike Smith 	debug_called(3);
241935863739SMike Smith 
242035863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
242135863739SMike Smith }
242235863739SMike Smith 
2423b3457b51SScott Long static int
2424b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2425b3457b51SScott Long {
2426b3457b51SScott Long 	int val;
2427b3457b51SScott Long 
2428b3457b51SScott Long 	debug_called(3);
2429b3457b51SScott Long 
2430b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2431b3457b51SScott Long 	return (val);
2432b3457b51SScott Long }
2433b3457b51SScott Long 
24344afedc31SScott Long static int
24354afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
24364afedc31SScott Long {
24374afedc31SScott Long 	debug_called(3);
24384afedc31SScott Long 
24394afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
24404afedc31SScott Long }
24414afedc31SScott Long 
2442914da7d0SScott Long /*
244335863739SMike Smith  * Clear some interrupt reason bits
244435863739SMike Smith  */
244535863739SMike Smith static void
244635863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
244735863739SMike Smith {
244835863739SMike Smith 	debug_called(3);
244935863739SMike Smith 
245035863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
245135863739SMike Smith }
245235863739SMike Smith 
245335863739SMike Smith static void
245435863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
245535863739SMike Smith {
245635863739SMike Smith 	debug_called(3);
245735863739SMike Smith 
245835863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
245935863739SMike Smith }
246035863739SMike Smith 
2461b3457b51SScott Long static void
2462b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2463b3457b51SScott Long {
2464b3457b51SScott Long 	debug_called(3);
2465b3457b51SScott Long 
2466b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2467b3457b51SScott Long 	AAC_FA_HACK(sc);
2468b3457b51SScott Long }
2469b3457b51SScott Long 
24704afedc31SScott Long static void
24714afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
24724afedc31SScott Long {
24734afedc31SScott Long 	debug_called(3);
24744afedc31SScott Long 
24754afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
24764afedc31SScott Long }
24774afedc31SScott Long 
2478914da7d0SScott Long /*
247935863739SMike Smith  * Populate the mailbox and set the command word
248035863739SMike Smith  */
248135863739SMike Smith static void
248235863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
248335863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
248435863739SMike Smith {
248535863739SMike Smith 	debug_called(4);
248635863739SMike Smith 
248735863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
248835863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
248935863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
249035863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
249135863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
249235863739SMike Smith }
249335863739SMike Smith 
249435863739SMike Smith static void
249535863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
249635863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249735863739SMike Smith {
249835863739SMike Smith 	debug_called(4);
249935863739SMike Smith 
250035863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
250135863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
250235863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
250335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
250435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
250535863739SMike Smith }
250635863739SMike Smith 
2507b3457b51SScott Long static void
2508b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2509b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2510b3457b51SScott Long {
2511b3457b51SScott Long 	debug_called(4);
2512b3457b51SScott Long 
2513b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2514b3457b51SScott Long 	AAC_FA_HACK(sc);
2515b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2516b3457b51SScott Long 	AAC_FA_HACK(sc);
2517b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2518b3457b51SScott Long 	AAC_FA_HACK(sc);
2519b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2520b3457b51SScott Long 	AAC_FA_HACK(sc);
2521b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2522b3457b51SScott Long 	AAC_FA_HACK(sc);
2523b3457b51SScott Long }
2524b3457b51SScott Long 
25254afedc31SScott Long static void
25264afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25274afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
25284afedc31SScott Long {
25294afedc31SScott Long 	debug_called(4);
25304afedc31SScott Long 
25314afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
25324afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
25334afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
25344afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
25354afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
25364afedc31SScott Long }
25374afedc31SScott Long 
2538914da7d0SScott Long /*
253935863739SMike Smith  * Fetch the immediate command status word
254035863739SMike Smith  */
254135863739SMike Smith static int
2542a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
254335863739SMike Smith {
254435863739SMike Smith 	debug_called(4);
254535863739SMike Smith 
2546a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
254735863739SMike Smith }
254835863739SMike Smith 
254935863739SMike Smith static int
2550a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
255135863739SMike Smith {
255235863739SMike Smith 	debug_called(4);
255335863739SMike Smith 
2554a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
255535863739SMike Smith }
255635863739SMike Smith 
2557b3457b51SScott Long static int
2558a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2559b3457b51SScott Long {
2560b3457b51SScott Long 	int val;
2561b3457b51SScott Long 
2562b3457b51SScott Long 	debug_called(4);
2563b3457b51SScott Long 
2564a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2565b3457b51SScott Long 	return (val);
2566b3457b51SScott Long }
2567b3457b51SScott Long 
25684afedc31SScott Long static int
25694afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
25704afedc31SScott Long {
25714afedc31SScott Long 	debug_called(4);
25724afedc31SScott Long 
25734afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
25744afedc31SScott Long }
25754afedc31SScott Long 
2576914da7d0SScott Long /*
257735863739SMike Smith  * Set/clear interrupt masks
257835863739SMike Smith  */
257935863739SMike Smith static void
258035863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
258135863739SMike Smith {
258235863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
258335863739SMike Smith 
258435863739SMike Smith 	if (enable) {
258535863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
258635863739SMike Smith 	} else {
258735863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
258835863739SMike Smith 	}
258935863739SMike Smith }
259035863739SMike Smith 
259135863739SMike Smith static void
259235863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
259335863739SMike Smith {
259435863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
259535863739SMike Smith 
259635863739SMike Smith 	if (enable) {
25977cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
25987cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
25997cb209f5SScott Long 		else
260035863739SMike Smith 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
260135863739SMike Smith 	} else {
260235863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
260335863739SMike Smith 	}
260435863739SMike Smith }
260535863739SMike Smith 
2606b3457b51SScott Long static void
2607b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2608b3457b51SScott Long {
2609b3457b51SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
2610b3457b51SScott Long 
2611b3457b51SScott Long 	if (enable) {
2612b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2613b3457b51SScott Long 		AAC_FA_HACK(sc);
2614b3457b51SScott Long 	} else {
2615b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2616b3457b51SScott Long 		AAC_FA_HACK(sc);
2617b3457b51SScott Long 	}
2618b3457b51SScott Long }
2619b3457b51SScott Long 
26204afedc31SScott Long static void
26214afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
26224afedc31SScott Long {
26234afedc31SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
26244afedc31SScott Long 
26254afedc31SScott Long 	if (enable) {
26267cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
26277cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
26287cb209f5SScott Long 		else
26294afedc31SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
26304afedc31SScott Long 	} else {
26314afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
26324afedc31SScott Long 	}
26334afedc31SScott Long }
26344afedc31SScott Long 
2635914da7d0SScott Long /*
26367cb209f5SScott Long  * New comm. interface: Send command functions
26377cb209f5SScott Long  */
26387cb209f5SScott Long static int
26397cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
26407cb209f5SScott Long {
26417cb209f5SScott Long 	u_int32_t index, device;
26427cb209f5SScott Long 
26437cb209f5SScott Long 	debug(2, "send command (new comm.)");
26447cb209f5SScott Long 
26457cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RX_IQUE);
26467cb209f5SScott Long 	if (index == 0xffffffffL)
26477cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RX_IQUE);
26487cb209f5SScott Long 	if (index == 0xffffffffL)
26497cb209f5SScott Long 		return index;
26507cb209f5SScott Long 	aac_enqueue_busy(cm);
26517cb209f5SScott Long 	device = index;
26527cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26537cb209f5SScott Long 	device += 4;
26547cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26557cb209f5SScott Long 	device += 4;
26567cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26577cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_IQUE, index);
26587cb209f5SScott Long 	return 0;
26597cb209f5SScott Long }
26607cb209f5SScott Long 
26617cb209f5SScott Long static int
26627cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
26637cb209f5SScott Long {
26647cb209f5SScott Long 	u_int32_t index, device;
26657cb209f5SScott Long 
26667cb209f5SScott Long 	debug(2, "send command (new comm.)");
26677cb209f5SScott Long 
26687cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
26697cb209f5SScott Long 	if (index == 0xffffffffL)
26707cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
26717cb209f5SScott Long 	if (index == 0xffffffffL)
26727cb209f5SScott Long 		return index;
26737cb209f5SScott Long 	aac_enqueue_busy(cm);
26747cb209f5SScott Long 	device = index;
26757cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26767cb209f5SScott Long 	device += 4;
26777cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26787cb209f5SScott Long 	device += 4;
26797cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26807cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
26817cb209f5SScott Long 	return 0;
26827cb209f5SScott Long }
26837cb209f5SScott Long 
26847cb209f5SScott Long /*
26857cb209f5SScott Long  * New comm. interface: get, set outbound queue index
26867cb209f5SScott Long  */
26877cb209f5SScott Long static int
26887cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
26897cb209f5SScott Long {
26907cb209f5SScott Long 	debug_called(3);
26917cb209f5SScott Long 
26927cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RX_OQUE));
26937cb209f5SScott Long }
26947cb209f5SScott Long 
26957cb209f5SScott Long static int
26967cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
26977cb209f5SScott Long {
26987cb209f5SScott Long 	debug_called(3);
26997cb209f5SScott Long 
27007cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
27017cb209f5SScott Long }
27027cb209f5SScott Long 
27037cb209f5SScott Long static void
27047cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
27057cb209f5SScott Long {
27067cb209f5SScott Long 	debug_called(3);
27077cb209f5SScott Long 
27087cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_OQUE, index);
27097cb209f5SScott Long }
27107cb209f5SScott Long 
27117cb209f5SScott Long static void
27127cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
27137cb209f5SScott Long {
27147cb209f5SScott Long 	debug_called(3);
27157cb209f5SScott Long 
27167cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
27177cb209f5SScott Long }
27187cb209f5SScott Long 
27197cb209f5SScott Long /*
2720914da7d0SScott Long  * Debugging and Diagnostics
2721914da7d0SScott Long  */
272235863739SMike Smith 
2723914da7d0SScott Long /*
272435863739SMike Smith  * Print some information about the controller.
272535863739SMike Smith  */
272635863739SMike Smith static void
272735863739SMike Smith aac_describe_controller(struct aac_softc *sc)
272835863739SMike Smith {
2729cbfd045bSScott Long 	struct aac_fib *fib;
273035863739SMike Smith 	struct aac_adapter_info	*info;
27317ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
273235863739SMike Smith 
273335863739SMike Smith 	debug_called(2);
273435863739SMike Smith 
273581b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
273603b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2737cbfd045bSScott Long 
27387ea2d558SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
27397ea2d558SEd Maste 		fib->data[0] = 0;
27407ea2d558SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
27417ea2d558SEd Maste 			device_printf(sc->aac_dev,
27427ea2d558SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
27437ea2d558SEd Maste 		else
27447ea2d558SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
27457ea2d558SEd Maste 			    &fib->data[0])->AdapterTypeText;
27467ea2d558SEd Maste 	}
27477ea2d558SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
27487ea2d558SEd Maste 		adapter_type,
27497ea2d558SEd Maste 		AAC_DRIVER_VERSION >> 24,
27507ea2d558SEd Maste 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
27517ea2d558SEd Maste 		AAC_DRIVER_VERSION & 0xFF,
27527ea2d558SEd Maste 		AAC_DRIVER_BUILD);
27537ea2d558SEd Maste 
2754cbfd045bSScott Long 	fib->data[0] = 0;
2755cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
275635863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2757fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
275881b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
275935863739SMike Smith 		return;
276035863739SMike Smith 	}
276135863739SMike Smith 
2762bd971c49SScott Long 	/* save the kernel revision structure for later use */
2763bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2764bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2765bd971c49SScott Long 
27667cb209f5SScott Long 
2767bd971c49SScott Long 	if (bootverbose) {
2768b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2769b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2770c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2771b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2772b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2773b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2774914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2775914da7d0SScott Long 		    info->batteryPlatform));
277635863739SMike Smith 
2777bd971c49SScott Long 		device_printf(sc->aac_dev,
2778bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
277935863739SMike Smith 		    info->KernelRevision.external.comp.major,
278035863739SMike Smith 		    info->KernelRevision.external.comp.minor,
278135863739SMike Smith 		    info->KernelRevision.external.comp.dash,
278236e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
278336e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2784fe3cb0e1SScott Long 
2785a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2786a6d35632SScott Long 			      sc->supported_options,
2787a6d35632SScott Long 			      "\20"
2788a6d35632SScott Long 			      "\1SNAPSHOT"
2789a6d35632SScott Long 			      "\2CLUSTERS"
2790a6d35632SScott Long 			      "\3WCACHE"
2791a6d35632SScott Long 			      "\4DATA64"
2792a6d35632SScott Long 			      "\5HOSTTIME"
2793a6d35632SScott Long 			      "\6RAID50"
2794a6d35632SScott Long 			      "\7WINDOW4GB"
2795a6d35632SScott Long 			      "\10SCSIUPGD"
2796a6d35632SScott Long 			      "\11SOFTERR"
2797a6d35632SScott Long 			      "\12NORECOND"
2798a6d35632SScott Long 			      "\13SGMAP64"
2799a6d35632SScott Long 			      "\14ALARM"
28007cb209f5SScott Long 			      "\15NONDASD"
28017cb209f5SScott Long 			      "\16SCSIMGT"
28027cb209f5SScott Long 			      "\17RAIDSCSI"
28037cb209f5SScott Long 			      "\21ADPTINFO"
28047cb209f5SScott Long 			      "\22NEWCOMM"
28057cb209f5SScott Long 			      "\23ARRAY64BIT"
28067cb209f5SScott Long 			      "\24HEATSENSOR");
2807a6d35632SScott Long 	}
2808bd971c49SScott Long 	aac_release_sync_fib(sc);
280981b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
281035863739SMike Smith }
281135863739SMike Smith 
2812914da7d0SScott Long /*
281335863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
281435863739SMike Smith  * same.
281535863739SMike Smith  */
281635863739SMike Smith static char *
281735863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
281835863739SMike Smith {
281935863739SMike Smith 	int i;
282035863739SMike Smith 
282135863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
282235863739SMike Smith 		if (table[i].code == code)
282335863739SMike Smith 			return(table[i].string);
282435863739SMike Smith 	return(table[i + 1].string);
282535863739SMike Smith }
282635863739SMike Smith 
2827914da7d0SScott Long /*
2828914da7d0SScott Long  * Management Interface
2829914da7d0SScott Long  */
283035863739SMike Smith 
283135863739SMike Smith static int
283289c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
283335863739SMike Smith {
2834914da7d0SScott Long 	struct aac_softc *sc;
283535863739SMike Smith 
283635863739SMike Smith 	debug_called(2);
283735863739SMike Smith 
2838914da7d0SScott Long 	sc = dev->si_drv1;
2839a723a548SEd Maste 	sc->aac_open_cnt++;
284035863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
284135863739SMike Smith 
284235863739SMike Smith 	return 0;
284335863739SMike Smith }
284435863739SMike Smith 
284535863739SMike Smith static int
284689c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
284735863739SMike Smith {
2848914da7d0SScott Long 	struct aac_softc *sc;
284935863739SMike Smith 
285035863739SMike Smith 	debug_called(2);
285135863739SMike Smith 
2852914da7d0SScott Long 	sc = dev->si_drv1;
2853a723a548SEd Maste 	sc->aac_open_cnt--;
285435863739SMike Smith 	/* Mark this unit as no longer open  */
2855a723a548SEd Maste 	if (sc->aac_open_cnt == 0)
285635863739SMike Smith 		sc->aac_state &= ~AAC_STATE_OPEN;
285735863739SMike Smith 
285835863739SMike Smith 	return 0;
285935863739SMike Smith }
286035863739SMike Smith 
286135863739SMike Smith static int
286289c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
286335863739SMike Smith {
2864914da7d0SScott Long 	union aac_statrequest *as;
2865914da7d0SScott Long 	struct aac_softc *sc;
28660b94a66eSMike Smith 	int error = 0;
286735863739SMike Smith 
286835863739SMike Smith 	debug_called(2);
286935863739SMike Smith 
2870914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2871914da7d0SScott Long 	sc = dev->si_drv1;
2872914da7d0SScott Long 
287335863739SMike Smith 	switch (cmd) {
28740b94a66eSMike Smith 	case AACIO_STATS:
28750b94a66eSMike Smith 		switch (as->as_item) {
28760b94a66eSMike Smith 		case AACQ_FREE:
28770b94a66eSMike Smith 		case AACQ_BIO:
28780b94a66eSMike Smith 		case AACQ_READY:
28790b94a66eSMike Smith 		case AACQ_BUSY:
2880c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2881c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
28820b94a66eSMike Smith 			break;
28830b94a66eSMike Smith 		default:
28840b94a66eSMike Smith 			error = ENOENT;
28850b94a66eSMike Smith 			break;
28860b94a66eSMike Smith 		}
28870b94a66eSMike Smith 	break;
28880b94a66eSMike Smith 
288935863739SMike Smith 	case FSACTL_SENDFIB:
2890fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2891fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
28920b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
289335863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
289435863739SMike Smith 		break;
289535863739SMike Smith 	case FSACTL_AIF_THREAD:
2896fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
28970b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
289835863739SMike Smith 		error = EINVAL;
289935863739SMike Smith 		break;
290035863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2901fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2902fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
29030b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
2904a723a548SEd Maste 		error = aac_open_aif(sc, arg);
290535863739SMike Smith 		break;
290635863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2907fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2908fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
29090b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2910fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
291135863739SMike Smith 		break;
291235863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2913a723a548SEd Maste 		arg = *(caddr_t*)arg;
2914fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
29150b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2916a723a548SEd Maste 		error = aac_close_aif(sc, arg);
291735863739SMike Smith 		break;
291835863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2919fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2920fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
29210b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2922fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
292335863739SMike Smith 		break;
292436e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
292536e0bf6eSScott Long 		arg = *(caddr_t*)arg;
292636e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
292736e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
292836e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
292936e0bf6eSScott Long 		break;
293036e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
293136e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2932914da7d0SScott Long 		/*
2933914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2934914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2935914da7d0SScott Long 		 * controller
2936914da7d0SScott Long 		 */
293736e0bf6eSScott Long 		error = 0;
293836e0bf6eSScott Long 		break;
29397cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
29407cb209f5SScott Long 		arg = *(caddr_t*)arg;
29417cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
29427cb209f5SScott Long 		debug(1, "FSACTL_GET_PCI_INFO");
29437cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
29447cb209f5SScott Long 		break;
294535863739SMike Smith 	default:
2946b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
294735863739SMike Smith 		error = EINVAL;
294835863739SMike Smith 		break;
294935863739SMike Smith 	}
295035863739SMike Smith 	return(error);
295135863739SMike Smith }
295235863739SMike Smith 
2953b3457b51SScott Long static int
295489c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2955b3457b51SScott Long {
2956b3457b51SScott Long 	struct aac_softc *sc;
2957b3457b51SScott Long 	int revents;
2958b3457b51SScott Long 
2959b3457b51SScott Long 	sc = dev->si_drv1;
2960b3457b51SScott Long 	revents = 0;
2961b3457b51SScott Long 
2962bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2963b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2964a723a548SEd Maste 		if (sc->aifq_idx != 0 || sc->aifq_filled)
2965b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2966b3457b51SScott Long 	}
2967bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2968b3457b51SScott Long 
2969b3457b51SScott Long 	if (revents == 0) {
2970b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2971b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2972b3457b51SScott Long 	}
2973b3457b51SScott Long 
2974b3457b51SScott Long 	return (revents);
2975b3457b51SScott Long }
2976b3457b51SScott Long 
29777cb209f5SScott Long static void
29787cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
29797cb209f5SScott Long {
29807cb209f5SScott Long 
29817cb209f5SScott Long 	switch (event->ev_type) {
29827cb209f5SScott Long 	case AAC_EVENT_CMFREE:
29837cb209f5SScott Long 		mtx_lock(&sc->aac_io_lock);
29841a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
29857cb209f5SScott Long 			aac_add_event(sc, event);
29867cb209f5SScott Long 			mtx_unlock(&sc->aac_io_lock);
29877cb209f5SScott Long 			return;
29887cb209f5SScott Long 		}
29897cb209f5SScott Long 		free(event, M_AACBUF);
29908eeb2ca6SScott Long 		wakeup(arg);
29917cb209f5SScott Long 		mtx_unlock(&sc->aac_io_lock);
29927cb209f5SScott Long 		break;
29937cb209f5SScott Long 	default:
29947cb209f5SScott Long 		break;
29957cb209f5SScott Long 	}
29967cb209f5SScott Long }
29977cb209f5SScott Long 
2998914da7d0SScott Long /*
299935863739SMike Smith  * Send a FIB supplied from userspace
300035863739SMike Smith  */
300135863739SMike Smith static int
300235863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
300335863739SMike Smith {
300435863739SMike Smith 	struct aac_command *cm;
300535863739SMike Smith 	int size, error;
300635863739SMike Smith 
300735863739SMike Smith 	debug_called(2);
300835863739SMike Smith 
300935863739SMike Smith 	cm = NULL;
301035863739SMike Smith 
301135863739SMike Smith 	/*
301235863739SMike Smith 	 * Get a command
301335863739SMike Smith 	 */
3014bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
301535863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
30167cb209f5SScott Long 		struct aac_event *event;
30177cb209f5SScott Long 
30187cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
30197cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
30207cb209f5SScott Long 		if (event == NULL) {
302135863739SMike Smith 			error = EBUSY;
302235863739SMike Smith 			goto out;
302335863739SMike Smith 		}
30247cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
30257cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
30267cb209f5SScott Long 		event->ev_arg = &cm;
30277cb209f5SScott Long 		aac_add_event(sc, event);
30288eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
30297cb209f5SScott Long 	}
303093cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
303135863739SMike Smith 
303235863739SMike Smith 	/*
303335863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
303435863739SMike Smith 	 */
3035914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3036914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
303735863739SMike Smith 		goto out;
303835863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
303935863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
3040b88ffdc8SScott Long 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
3041914da7d0SScott Long 			      size, sizeof(struct aac_fib));
304235863739SMike Smith 		size = sizeof(struct aac_fib);
304335863739SMike Smith 	}
304435863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
304535863739SMike Smith 		goto out;
304635863739SMike Smith 	cm->cm_fib->Header.Size = size;
30472b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
304835863739SMike Smith 
304935863739SMike Smith 	/*
305035863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
305135863739SMike Smith 	 */
305293cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3053d8a0a473SScott Long 	if ((error = aac_wait_command(cm)) != 0) {
305470545d1aSScott Long 		device_printf(sc->aac_dev,
305570545d1aSScott Long 			      "aac_wait_command return %d\n", error);
305635863739SMike Smith 		goto out;
3057b3457b51SScott Long 	}
305893cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
305935863739SMike Smith 
306035863739SMike Smith 	/*
306135863739SMike Smith 	 * Copy the FIB and data back out to the caller.
306235863739SMike Smith 	 */
306335863739SMike Smith 	size = cm->cm_fib->Header.Size;
306435863739SMike Smith 	if (size > sizeof(struct aac_fib)) {
3065b88ffdc8SScott Long 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
3066914da7d0SScott Long 			      size, sizeof(struct aac_fib));
306735863739SMike Smith 		size = sizeof(struct aac_fib);
306835863739SMike Smith 	}
306935863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
307093cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
307135863739SMike Smith 
307235863739SMike Smith out:
3073f6c4dd3fSScott Long 	if (cm != NULL) {
307435863739SMike Smith 		aac_release_command(cm);
3075f6c4dd3fSScott Long 	}
3076ae543596SScott Long 
3077bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
307835863739SMike Smith 	return(error);
307935863739SMike Smith }
308035863739SMike Smith 
3081914da7d0SScott Long /*
308235863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
308336e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
308435863739SMike Smith  */
308535863739SMike Smith static void
308636e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
308735863739SMike Smith {
308836e0bf6eSScott Long 	struct aac_aif_command *aif;
308936e0bf6eSScott Long 	struct aac_container *co, *co_next;
3090a723a548SEd Maste 	struct aac_fib_context *ctx;
3091cbfd045bSScott Long 	struct aac_mntinfo *mi;
3092cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
309336e0bf6eSScott Long 	u_int16_t rsize;
3094a723a548SEd Maste 	int next, current, found;
3095795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
309635863739SMike Smith 
309735863739SMike Smith 	debug_called(2);
309835863739SMike Smith 
309936e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
310036e0bf6eSScott Long 	aac_print_aif(sc, aif);
310136e0bf6eSScott Long 
310236e0bf6eSScott Long 	/* Is it an event that we should care about? */
310336e0bf6eSScott Long 	switch (aif->command) {
310436e0bf6eSScott Long 	case AifCmdEventNotify:
310536e0bf6eSScott Long 		switch (aif->data.EN.type) {
310636e0bf6eSScott Long 		case AifEnAddContainer:
310736e0bf6eSScott Long 		case AifEnDeleteContainer:
310836e0bf6eSScott Long 			/*
3109914da7d0SScott Long 			 * A container was added or deleted, but the message
3110914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3111914da7d0SScott Long 			 * containers and sort things out.
311236e0bf6eSScott Long 			 */
311303b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
3114cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
311536e0bf6eSScott Long 			do {
311636e0bf6eSScott Long 				/*
3117914da7d0SScott Long 				 * Ask the controller for its containers one at
3118914da7d0SScott Long 				 * a time.
3119914da7d0SScott Long 				 * XXX What if the controller's list changes
3120914da7d0SScott Long 				 * midway through this enumaration?
312136e0bf6eSScott Long 				 * XXX This should be done async.
312236e0bf6eSScott Long 				 */
312339ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
312439ee03c3SScott Long 				mi->Command = VM_NameServe;
312539ee03c3SScott Long 				mi->MntType = FT_FILESYS;
3126cbfd045bSScott Long 				mi->MntCount = i;
312736e0bf6eSScott Long 				rsize = sizeof(mir);
3128cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
3129cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
3130795d7dc0SScott Long 					printf("Error probing container %d\n",
3131914da7d0SScott Long 					      i);
313236e0bf6eSScott Long 					continue;
313336e0bf6eSScott Long 				}
3134cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
3135795d7dc0SScott Long 				/* XXX Need to check if count changed */
3136795d7dc0SScott Long 				count = mir->MntRespCount;
313736e0bf6eSScott Long 				/*
3138914da7d0SScott Long 				 * Check the container against our list.
3139914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3140914da7d0SScott Long 				 * previous run.
314136e0bf6eSScott Long 				 */
3142cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3143cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
314436e0bf6eSScott Long 					found = 0;
3145914da7d0SScott Long 					TAILQ_FOREACH(co,
3146914da7d0SScott Long 						      &sc->aac_container_tqh,
3147914da7d0SScott Long 						      co_link) {
314836e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3149cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
315036e0bf6eSScott Long 							co->co_found = 1;
315136e0bf6eSScott Long 							found = 1;
315236e0bf6eSScott Long 							break;
315336e0bf6eSScott Long 						}
315436e0bf6eSScott Long 					}
3155914da7d0SScott Long 					/*
3156914da7d0SScott Long 					 * If the container matched, continue
3157914da7d0SScott Long 					 * in the list.
3158914da7d0SScott Long 					 */
315936e0bf6eSScott Long 					if (found) {
316036e0bf6eSScott Long 						i++;
316136e0bf6eSScott Long 						continue;
316236e0bf6eSScott Long 					}
316336e0bf6eSScott Long 
316436e0bf6eSScott Long 					/*
3165914da7d0SScott Long 					 * This is a new container.  Do all the
316670545d1aSScott Long 					 * appropriate things to set it up.
316770545d1aSScott Long 					 */
3168cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
316936e0bf6eSScott Long 					added = 1;
317036e0bf6eSScott Long 				}
317136e0bf6eSScott Long 				i++;
3172795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3173cbfd045bSScott Long 			aac_release_sync_fib(sc);
317436e0bf6eSScott Long 
317536e0bf6eSScott Long 			/*
3176914da7d0SScott Long 			 * Go through our list of containers and see which ones
3177914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3178914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3179914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3180914da7d0SScott Long 			 * the co->co_found field.
318136e0bf6eSScott Long 			 */
318236e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
318336e0bf6eSScott Long 			while (co != NULL) {
318436e0bf6eSScott Long 				if (co->co_found == 0) {
31857cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
31867cb209f5SScott Long 					mtx_lock(&Giant);
3187914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3188914da7d0SScott Long 							    co->co_disk);
31897cb209f5SScott Long 					mtx_unlock(&Giant);
31907cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
319136e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3192bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3193914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3194914da7d0SScott Long 						     co_link);
3195bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3196ba1d57e7SScott Long 					free(co, M_AACBUF);
319736e0bf6eSScott Long 					co = co_next;
319836e0bf6eSScott Long 				} else {
319936e0bf6eSScott Long 					co->co_found = 0;
320036e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
320136e0bf6eSScott Long 				}
320236e0bf6eSScott Long 			}
320336e0bf6eSScott Long 
320436e0bf6eSScott Long 			/* Attach the newly created containers */
32057cb209f5SScott Long 			if (added) {
32067cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
32077cb209f5SScott Long 				mtx_lock(&Giant);
320836e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
32097cb209f5SScott Long 				mtx_unlock(&Giant);
32107cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
32117cb209f5SScott Long 			}
321236e0bf6eSScott Long 
321336e0bf6eSScott Long 			break;
321436e0bf6eSScott Long 
321536e0bf6eSScott Long 		default:
321636e0bf6eSScott Long 			break;
321736e0bf6eSScott Long 		}
321836e0bf6eSScott Long 
321936e0bf6eSScott Long 	default:
322036e0bf6eSScott Long 		break;
322136e0bf6eSScott Long 	}
322236e0bf6eSScott Long 
322336e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3224bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3225a723a548SEd Maste 	current = sc->aifq_idx;
3226a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3227a723a548SEd Maste 	if (next == 0)
3228a723a548SEd Maste 		sc->aifq_filled = 1;
3229a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3230a723a548SEd Maste 	/* modify AIF contexts */
3231a723a548SEd Maste 	if (sc->aifq_filled) {
3232a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3233a723a548SEd Maste 			if (next == ctx->ctx_idx)
3234a723a548SEd Maste 				ctx->ctx_wrap = 1;
3235a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3236a723a548SEd Maste 				ctx->ctx_idx = next;
3237a723a548SEd Maste 		}
3238a723a548SEd Maste 	}
3239a723a548SEd Maste 	sc->aifq_idx = next;
3240b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
324135863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
324235863739SMike Smith 		wakeup(sc->aac_aifq);
3243b3457b51SScott Long 	/* Wakeup any poll()ers */
3244512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3245bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
324636e0bf6eSScott Long 
324736e0bf6eSScott Long 	return;
324835863739SMike Smith }
324935863739SMike Smith 
3250914da7d0SScott Long /*
32510b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
325236e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
325336e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
325436e0bf6eSScott Long  * returning what the card reported.
325535863739SMike Smith  */
325635863739SMike Smith static int
3257fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
325835863739SMike Smith {
325935863739SMike Smith 	struct aac_rev_check rev_check;
326035863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
326135863739SMike Smith 	int error = 0;
326235863739SMike Smith 
326335863739SMike Smith 	debug_called(2);
326435863739SMike Smith 
326535863739SMike Smith 	/*
326635863739SMike Smith 	 * Copyin the revision struct from userspace
326735863739SMike Smith 	 */
3268c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3269c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
327035863739SMike Smith 		return error;
327135863739SMike Smith 	}
327235863739SMike Smith 
3273914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
3274914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
327535863739SMike Smith 
327635863739SMike Smith 	/*
327735863739SMike Smith 	 * Doctor up the response struct.
327835863739SMike Smith 	 */
327935863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3280914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3281914da7d0SScott Long 	    sc->aac_revision.external.ul;
3282914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3283914da7d0SScott Long 	    sc->aac_revision.buildNumber;
328435863739SMike Smith 
3285c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3286c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
328735863739SMike Smith }
328835863739SMike Smith 
3289914da7d0SScott Long /*
3290a723a548SEd Maste  * Pass the fib context to the caller
3291a723a548SEd Maste  */
3292a723a548SEd Maste static int
3293a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3294a723a548SEd Maste {
3295a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3296a723a548SEd Maste 	int error = 0;
3297a723a548SEd Maste 
3298a723a548SEd Maste 	debug_called(2);
3299a723a548SEd Maste 
3300a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3301a723a548SEd Maste 	if (fibctx == NULL)
3302a723a548SEd Maste 		return (ENOMEM);
3303a723a548SEd Maste 
3304a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3305a723a548SEd Maste 	/* all elements are already 0, add to queue */
3306a723a548SEd Maste 	if (sc->fibctx == NULL)
3307a723a548SEd Maste 		sc->fibctx = fibctx;
3308a723a548SEd Maste 	else {
3309a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3310a723a548SEd Maste 			;
3311a723a548SEd Maste 		ctx->next = fibctx;
3312a723a548SEd Maste 		fibctx->prev = ctx;
3313a723a548SEd Maste 	}
3314a723a548SEd Maste 
3315a723a548SEd Maste 	/* evaluate unique value */
3316a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3317a723a548SEd Maste 	ctx = sc->fibctx;
3318a723a548SEd Maste 	while (ctx != fibctx) {
3319a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3320a723a548SEd Maste 			fibctx->unique++;
3321a723a548SEd Maste 			ctx = sc->fibctx;
3322a723a548SEd Maste 		} else {
3323a723a548SEd Maste 			ctx = ctx->next;
3324a723a548SEd Maste 		}
3325a723a548SEd Maste 	}
3326a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3327a723a548SEd Maste 
3328a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3329a723a548SEd Maste 	if (error)
3330a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3331a723a548SEd Maste 	return error;
3332a723a548SEd Maste }
3333a723a548SEd Maste 
3334a723a548SEd Maste /*
3335a723a548SEd Maste  * Close the caller's fib context
3336a723a548SEd Maste  */
3337a723a548SEd Maste static int
3338a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3339a723a548SEd Maste {
3340a723a548SEd Maste 	struct aac_fib_context *ctx;
3341a723a548SEd Maste 
3342a723a548SEd Maste 	debug_called(2);
3343a723a548SEd Maste 
3344a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3345a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3346a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3347a723a548SEd Maste 			if (ctx == sc->fibctx)
3348a723a548SEd Maste 				sc->fibctx = NULL;
3349a723a548SEd Maste 			else {
3350a723a548SEd Maste 				ctx->prev->next = ctx->next;
3351a723a548SEd Maste 				if (ctx->next)
3352a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3353a723a548SEd Maste 			}
3354a723a548SEd Maste 			break;
3355a723a548SEd Maste 		}
3356a723a548SEd Maste 	}
3357a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3358a723a548SEd Maste 	if (ctx)
3359a723a548SEd Maste 		free(ctx, M_AACBUF);
3360a723a548SEd Maste 
3361a723a548SEd Maste 	return 0;
3362a723a548SEd Maste }
3363a723a548SEd Maste 
3364a723a548SEd Maste /*
336535863739SMike Smith  * Pass the caller the next AIF in their queue
336635863739SMike Smith  */
336735863739SMike Smith static int
3368fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
336935863739SMike Smith {
337035863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3371a723a548SEd Maste 	struct aac_fib_context *ctx;
33729e2e96d8SScott Long 	int error;
337335863739SMike Smith 
337435863739SMike Smith 	debug_called(2);
337535863739SMike Smith 
337635863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3377a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3378a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3379a723a548SEd Maste 				break;
3380a723a548SEd Maste 		}
3381a723a548SEd Maste 		if (!ctx)
3382a723a548SEd Maste 			return (EFAULT);
338335863739SMike Smith 
3384a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3385a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
3386a723a548SEd Maste 			debug(2, "aac_getnext_aif(): waiting for AIF");
338735863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
338835863739SMike Smith 			while (error == EAGAIN) {
3389914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3390914da7d0SScott Long 					       PCATCH, "aacaif", 0);
339135863739SMike Smith 				if (error == 0)
3392a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
339335863739SMike Smith 			}
339435863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
339535863739SMike Smith 		}
339635863739SMike Smith 	}
339735863739SMike Smith 	return(error);
339835863739SMike Smith }
339935863739SMike Smith 
3400914da7d0SScott Long /*
34010b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
34020b94a66eSMike Smith  */
34030b94a66eSMike Smith static int
3404a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
34050b94a66eSMike Smith {
3406a723a548SEd Maste 	int current, error;
34070b94a66eSMike Smith 
34080b94a66eSMike Smith 	debug_called(2);
34090b94a66eSMike Smith 
3410bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3411a723a548SEd Maste 	current = ctx->ctx_idx;
3412a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3413a723a548SEd Maste 		/* empty */
3414bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
34153df780cfSScott Long 		return (EAGAIN);
34163df780cfSScott Long 	}
3417a723a548SEd Maste 	error =
3418a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
341936e0bf6eSScott Long 	if (error)
342070545d1aSScott Long 		device_printf(sc->aac_dev,
342170545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3422a723a548SEd Maste 	else {
3423a723a548SEd Maste 		ctx->ctx_wrap = 0;
3424a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3425a723a548SEd Maste 	}
3426bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
34270b94a66eSMike Smith 	return(error);
34280b94a66eSMike Smith }
342936e0bf6eSScott Long 
34307cb209f5SScott Long static int
34317cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
34327cb209f5SScott Long {
34337cb209f5SScott Long 	struct aac_pci_info {
34347cb209f5SScott Long 		u_int32_t bus;
34357cb209f5SScott Long 		u_int32_t slot;
34367cb209f5SScott Long 	} pciinf;
34377cb209f5SScott Long 	int error;
34387cb209f5SScott Long 
34397cb209f5SScott Long 	debug_called(2);
34407cb209f5SScott Long 
34417cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
34427cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
34437cb209f5SScott Long 
34447cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
34457cb209f5SScott Long 			sizeof(struct aac_pci_info));
34467cb209f5SScott Long 
34477cb209f5SScott Long 	return (error);
34487cb209f5SScott Long }
34497cb209f5SScott Long 
3450914da7d0SScott Long /*
345136e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
345236e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
345336e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
345436e0bf6eSScott Long  */
345536e0bf6eSScott Long static int
345636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
345736e0bf6eSScott Long {
345836e0bf6eSScott Long 	struct aac_query_disk query_disk;
345936e0bf6eSScott Long 	struct aac_container *co;
3460914da7d0SScott Long 	struct aac_disk	*disk;
346136e0bf6eSScott Long 	int error, id;
346236e0bf6eSScott Long 
346336e0bf6eSScott Long 	debug_called(2);
346436e0bf6eSScott Long 
3465914da7d0SScott Long 	disk = NULL;
3466914da7d0SScott Long 
3467914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3468914da7d0SScott Long 		       sizeof(struct aac_query_disk));
346936e0bf6eSScott Long 	if (error)
347036e0bf6eSScott Long 		return (error);
347136e0bf6eSScott Long 
347236e0bf6eSScott Long 	id = query_disk.ContainerNumber;
347336e0bf6eSScott Long 	if (id == -1)
347436e0bf6eSScott Long 		return (EINVAL);
347536e0bf6eSScott Long 
3476bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
347736e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
347836e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
347936e0bf6eSScott Long 			break;
348036e0bf6eSScott Long 		}
348136e0bf6eSScott Long 
348236e0bf6eSScott Long 	if (co == NULL) {
348336e0bf6eSScott Long 			query_disk.Valid = 0;
348436e0bf6eSScott Long 			query_disk.Locked = 0;
348536e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
348636e0bf6eSScott Long 	} else {
348736e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
348836e0bf6eSScott Long 		query_disk.Valid = 1;
3489914da7d0SScott Long 		query_disk.Locked =
3490914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
349136e0bf6eSScott Long 		query_disk.Deleted = 0;
3492b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
349336e0bf6eSScott Long 		query_disk.Target = disk->unit;
349436e0bf6eSScott Long 		query_disk.Lun = 0;
349536e0bf6eSScott Long 		query_disk.UnMapped = 0;
34967540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
34970b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
349836e0bf6eSScott Long 	}
3499bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
350036e0bf6eSScott Long 
3501914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3502914da7d0SScott Long 			sizeof(struct aac_query_disk));
350336e0bf6eSScott Long 
350436e0bf6eSScott Long 	return (error);
350536e0bf6eSScott Long }
350636e0bf6eSScott Long 
3507fe3cb0e1SScott Long static void
3508fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3509fe3cb0e1SScott Long {
3510fe3cb0e1SScott Long 	struct aac_fib *fib;
3511fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3512fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3513fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3514fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3515fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
351670545d1aSScott Long 	struct aac_sim *caminf;
3517fe3cb0e1SScott Long 	device_t child;
3518fe3cb0e1SScott Long 	int i, found, error;
3519fe3cb0e1SScott Long 
35201ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
352103b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3522fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
352339ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3524fe3cb0e1SScott Long 
3525fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3526fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3527fe3cb0e1SScott Long 	c_cmd->param = 0;
3528fe3cb0e1SScott Long 
3529fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3530fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3531fe3cb0e1SScott Long 	if (error) {
3532fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3533fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3534fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35351ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3536fe3cb0e1SScott Long 		return;
3537fe3cb0e1SScott Long 	}
3538fe3cb0e1SScott Long 
3539fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3540fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3541fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3542fe3cb0e1SScott Long 		    c_resp->Status);
3543fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35441ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3545fe3cb0e1SScott Long 		return;
3546fe3cb0e1SScott Long 	}
3547fe3cb0e1SScott Long 
3548fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3549fe3cb0e1SScott Long 
3550fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
355139ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
355239ee03c3SScott Long 
3553fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3554fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3555fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3556fe3cb0e1SScott Long 	vmi->ObjId = 0;
3557fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3558fe3cb0e1SScott Long 
3559fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3560fe3cb0e1SScott Long 	    sizeof(struct aac_vmioctl));
3561fe3cb0e1SScott Long 	if (error) {
3562fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3563fe3cb0e1SScott Long 		    error);
3564fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35651ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3566fe3cb0e1SScott Long 		return;
3567fe3cb0e1SScott Long 	}
3568fe3cb0e1SScott Long 
3569fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3570fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3571fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3572fe3cb0e1SScott Long 		    vmi_resp->Status);
3573fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35741ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3575fe3cb0e1SScott Long 		return;
3576fe3cb0e1SScott Long 	}
3577fe3cb0e1SScott Long 
3578fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3579fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
35801ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3581fe3cb0e1SScott Long 
3582fe3cb0e1SScott Long 	found = 0;
3583fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3584fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3585fe3cb0e1SScott Long 			continue;
3586fe3cb0e1SScott Long 
3587a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3588a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3589b5f516cdSScott Long 		if (caminf == NULL) {
3590b5f516cdSScott Long 			device_printf(sc->aac_dev,
3591b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3592b5f516cdSScott Long 			break;
35937cb209f5SScott Long 		};
3594fe3cb0e1SScott Long 
3595fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3596fe3cb0e1SScott Long 		if (child == NULL) {
3597b5f516cdSScott Long 			device_printf(sc->aac_dev,
3598b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3599b5f516cdSScott Long 			    i);
3600b5f516cdSScott Long 			free(caminf, M_AACBUF);
3601b5f516cdSScott Long 			break;
3602fe3cb0e1SScott Long 		}
3603fe3cb0e1SScott Long 
3604fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3605fe3cb0e1SScott Long 		caminf->BusNumber = i;
3606fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3607fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3608ddb8683eSScott Long 		caminf->sim_dev = child;
3609fe3cb0e1SScott Long 
3610fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3611fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
361270545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3613fe3cb0e1SScott Long 
3614fe3cb0e1SScott Long 		found = 1;
3615fe3cb0e1SScott Long 	}
3616fe3cb0e1SScott Long 
3617fe3cb0e1SScott Long 	if (found)
3618fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3619fe3cb0e1SScott Long 
3620fe3cb0e1SScott Long 	return;
3621fe3cb0e1SScott Long }
3622