xref: /freebsd/sys/dev/aac/aac.c (revision 3e5077108665f024058fbc64d290cf3c9c0057c0)
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_DRIVERNAME			"aac"
3735863739SMike Smith 
38f6c4dd3fSScott Long #include "opt_aac.h"
39f6c4dd3fSScott Long 
4036e0bf6eSScott Long /* #include <stddef.h> */
4135863739SMike Smith #include <sys/param.h>
4235863739SMike Smith #include <sys/systm.h>
4335863739SMike Smith #include <sys/malloc.h>
4435863739SMike Smith #include <sys/kernel.h>
4536e0bf6eSScott Long #include <sys/kthread.h>
463d04a9d7SScott Long #include <sys/sysctl.h>
47b3457b51SScott Long #include <sys/poll.h>
48891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
4935863739SMike Smith 
5035863739SMike Smith #include <sys/bus.h>
5135863739SMike Smith #include <sys/conf.h>
5235863739SMike Smith #include <sys/signalvar.h>
530b94a66eSMike Smith #include <sys/time.h>
5436e0bf6eSScott Long #include <sys/eventhandler.h>
557cb209f5SScott Long #include <sys/rman.h>
5635863739SMike Smith 
5735863739SMike Smith #include <machine/bus.h>
58b5f516cdSScott Long #include <sys/bus_dma.h>
5935863739SMike Smith #include <machine/resource.h>
6035863739SMike Smith 
617cb209f5SScott Long #include <dev/pci/pcireg.h>
627cb209f5SScott Long #include <dev/pci/pcivar.h>
637cb209f5SScott Long 
6435863739SMike Smith #include <dev/aac/aacreg.h>
650b0594cdSScott Long #include <sys/aac_ioctl.h>
6635863739SMike Smith #include <dev/aac/aacvar.h>
6735863739SMike Smith #include <dev/aac/aac_tables.h>
6835863739SMike Smith 
6935863739SMike Smith static void	aac_startup(void *arg);
70914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
71cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
72fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
73ff0991c4SAttilio Rao static void	aac_daemon(void *arg);
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 */
9304f4d586SEd Maste static int	aac_alloc(struct aac_softc *sc);
94c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
95c6eafcf2SScott Long 			       int error);
96fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9735863739SMike Smith static int	aac_init(struct aac_softc *sc);
9835863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
99c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
100c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
10104f4d586SEd Maste static int	aac_setup_intr(struct aac_softc *sc);
102c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
103f6c4dd3fSScott Long 				struct aac_command *cm);
104c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
105914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10636e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10736e0bf6eSScott Long 				     struct aac_fib *fib);
10835863739SMike Smith 
10935863739SMike Smith /* StrongARM interface */
11035863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
11135863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
11235863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
11335863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
11435863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
115c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
116c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
117a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
11835863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
11935863739SMike Smith 
12035863739SMike Smith struct aac_interface aac_sa_interface = {
12135863739SMike Smith 	aac_sa_get_fwstatus,
12235863739SMike Smith 	aac_sa_qnotify,
12335863739SMike Smith 	aac_sa_get_istatus,
12435863739SMike Smith 	aac_sa_clear_istatus,
12535863739SMike Smith 	aac_sa_set_mailbox,
126a6d35632SScott Long 	aac_sa_get_mailbox,
1277cb209f5SScott Long 	aac_sa_set_interrupts,
1287cb209f5SScott Long 	NULL, NULL, NULL
12935863739SMike Smith };
13035863739SMike Smith 
13135863739SMike Smith /* i960Rx interface */
13235863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
13335863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
13435863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
13535863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
13635863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
137c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
138c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
139a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
14035863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
1417cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
1427cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc);
1437cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
14435863739SMike Smith 
14535863739SMike Smith struct aac_interface aac_rx_interface = {
14635863739SMike Smith 	aac_rx_get_fwstatus,
14735863739SMike Smith 	aac_rx_qnotify,
14835863739SMike Smith 	aac_rx_get_istatus,
14935863739SMike Smith 	aac_rx_clear_istatus,
15035863739SMike Smith 	aac_rx_set_mailbox,
151a6d35632SScott Long 	aac_rx_get_mailbox,
1527cb209f5SScott Long 	aac_rx_set_interrupts,
1537cb209f5SScott Long 	aac_rx_send_command,
1547cb209f5SScott Long 	aac_rx_get_outb_queue,
1557cb209f5SScott Long 	aac_rx_set_outb_queue
15635863739SMike Smith };
15735863739SMike Smith 
1584afedc31SScott Long /* Rocket/MIPS interface */
1594afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1604afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1614afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1624afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1634afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1644afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1654afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1664afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1674afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1687cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
1697cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc);
1707cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
1714afedc31SScott Long 
1724afedc31SScott Long struct aac_interface aac_rkt_interface = {
1734afedc31SScott Long 	aac_rkt_get_fwstatus,
1744afedc31SScott Long 	aac_rkt_qnotify,
1754afedc31SScott Long 	aac_rkt_get_istatus,
1764afedc31SScott Long 	aac_rkt_clear_istatus,
1774afedc31SScott Long 	aac_rkt_set_mailbox,
1784afedc31SScott Long 	aac_rkt_get_mailbox,
1797cb209f5SScott Long 	aac_rkt_set_interrupts,
1807cb209f5SScott Long 	aac_rkt_send_command,
1817cb209f5SScott Long 	aac_rkt_get_outb_queue,
1827cb209f5SScott Long 	aac_rkt_set_outb_queue
1834afedc31SScott Long };
1844afedc31SScott Long 
18535863739SMike Smith /* Debugging and Diagnostics */
18635863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
1876965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
188c6eafcf2SScott Long 				   u_int32_t code);
18935863739SMike Smith 
19035863739SMike Smith /* Management Interface */
19135863739SMike Smith static d_open_t		aac_open;
19235863739SMike Smith static d_close_t	aac_close;
19335863739SMike Smith static d_ioctl_t	aac_ioctl;
194b3457b51SScott Long static d_poll_t		aac_poll;
195c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
196f355c0e0SEd Maste static int		aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
197c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
19836e0bf6eSScott Long 					   struct aac_fib *fib);
199fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
200a723a548SEd Maste static int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
201a723a548SEd Maste static int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
202fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
203a723a548SEd Maste static int		aac_return_aif(struct aac_softc *sc,
204a723a548SEd Maste 					struct aac_fib_context *ctx, caddr_t uptr);
20536e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
2067cb209f5SScott Long static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
2076d307336SEd Maste static int		aac_supported_features(struct aac_softc *sc, caddr_t uptr);
2087cb209f5SScott Long static void		aac_ioctl_event(struct aac_softc *sc,
2097cb209f5SScott Long 					struct aac_event *event, void *arg);
21004f4d586SEd Maste static struct aac_mntinforesp *
21104f4d586SEd Maste 	aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid);
21235863739SMike Smith 
21335863739SMike Smith static struct cdevsw aac_cdevsw = {
214dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
215dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2167ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2177ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2187ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2197ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2207ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
22135863739SMike Smith };
22235863739SMike Smith 
22336e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
22436e0bf6eSScott Long 
2253d04a9d7SScott Long /* sysctl node */
2263d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2273d04a9d7SScott Long 
228914da7d0SScott Long /*
229914da7d0SScott Long  * Device Interface
230914da7d0SScott Long  */
23135863739SMike Smith 
232914da7d0SScott Long /*
2334109ba51SEd Maste  * Initialize the controller and softc
23435863739SMike Smith  */
23535863739SMike Smith int
23635863739SMike Smith aac_attach(struct aac_softc *sc)
23735863739SMike Smith {
23835863739SMike Smith 	int error, unit;
23935863739SMike Smith 
24031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24135863739SMike Smith 
24235863739SMike Smith 	/*
2434109ba51SEd Maste 	 * Initialize per-controller queues.
24435863739SMike Smith 	 */
2450b94a66eSMike Smith 	aac_initq_free(sc);
2460b94a66eSMike Smith 	aac_initq_ready(sc);
2470b94a66eSMike Smith 	aac_initq_busy(sc);
2480b94a66eSMike Smith 	aac_initq_bio(sc);
24935863739SMike Smith 
25035863739SMike Smith 	/*
2514109ba51SEd Maste 	 * Initialize command-completion task.
25235863739SMike Smith 	 */
25335863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
25435863739SMike Smith 
25535863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
25635863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
25735863739SMike Smith 
25835863739SMike Smith 	/*
259fe94b852SScott Long 	 * Check that the firmware on the card is supported.
260fe94b852SScott Long 	 */
261fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
262fe94b852SScott Long 		return(error);
263fe94b852SScott Long 
264f6b1c44dSScott Long 	/*
265f6b1c44dSScott Long 	 * Initialize locks
266f6b1c44dSScott Long 	 */
267bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
268bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
269bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
270f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
271065dd78cSScott Long 	TAILQ_INIT(&sc->aac_ev_cmfree);
272f6b1c44dSScott Long 
273ff0991c4SAttilio Rao 	/* Initialize the clock daemon callout. */
274ff0991c4SAttilio Rao 	callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0);
275ff0991c4SAttilio Rao 
2760b94a66eSMike Smith 	/*
2774109ba51SEd Maste 	 * Initialize the adapter.
27835863739SMike Smith 	 */
27904f4d586SEd Maste 	if ((error = aac_alloc(sc)) != 0)
28004f4d586SEd Maste 		return(error);
2810b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
28235863739SMike Smith 		return(error);
28335863739SMike Smith 
28435863739SMike Smith 	/*
2857cb209f5SScott Long 	 * Allocate and connect our interrupt.
2867cb209f5SScott Long 	 */
28704f4d586SEd Maste 	if ((error = aac_setup_intr(sc)) != 0)
28804f4d586SEd Maste 		return(error);
2897cb209f5SScott Long 
2907cb209f5SScott Long 	/*
29135863739SMike Smith 	 * Print a little information about the controller.
29235863739SMike Smith 	 */
29335863739SMike Smith 	aac_describe_controller(sc);
29435863739SMike Smith 
29535863739SMike Smith 	/*
296ae543596SScott Long 	 * Register to probe our containers later.
297ae543596SScott Long 	 */
29835863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
29935863739SMike Smith 	sc->aac_ich.ich_arg = sc;
30035863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
301914da7d0SScott Long 		device_printf(sc->aac_dev,
302914da7d0SScott Long 			      "can't establish configuration hook\n");
30335863739SMike Smith 		return(ENXIO);
30435863739SMike Smith 	}
30535863739SMike Smith 
30635863739SMike Smith 	/*
30735863739SMike Smith 	 * Make the control device.
30835863739SMike Smith 	 */
30935863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3109e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3119e9466baSRobert Watson 				 0640, "aac%d", unit);
312157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3134aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
31435863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
31535863739SMike Smith 
31636e0bf6eSScott Long 	/* Create the AIF thread */
3173745c395SJulian Elischer 	if (kproc_create((void(*)(void *))aac_command_thread, sc,
318316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
319a620bad0SEd Maste 		panic("Could not create AIF thread");
32036e0bf6eSScott Long 
32136e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3225f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3235f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3245f54d522SScott Long 		device_printf(sc->aac_dev,
3255f54d522SScott Long 			      "shutdown event registration failed\n");
32636e0bf6eSScott Long 
327fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
328a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
32970545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
330fe3cb0e1SScott Long 		aac_get_bus_info(sc);
33170545d1aSScott Long 	}
332fe3cb0e1SScott Long 
333ff0991c4SAttilio Rao 	mtx_lock(&sc->aac_io_lock);
334867b1d34SEd Maste 	callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc);
335ff0991c4SAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
336ff0991c4SAttilio Rao 
33735863739SMike Smith 	return(0);
33835863739SMike Smith }
33935863739SMike Smith 
340ff0991c4SAttilio Rao static void
341ff0991c4SAttilio Rao aac_daemon(void *arg)
342ff0991c4SAttilio Rao {
343ff0991c4SAttilio Rao 	struct timeval tv;
344ff0991c4SAttilio Rao 	struct aac_softc *sc;
345ff0991c4SAttilio Rao 	struct aac_fib *fib;
346ff0991c4SAttilio Rao 
347ff0991c4SAttilio Rao 	sc = arg;
348ff0991c4SAttilio Rao 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
349ff0991c4SAttilio Rao 
350ff0991c4SAttilio Rao 	if (callout_pending(&sc->aac_daemontime) ||
351ff0991c4SAttilio Rao 	    callout_active(&sc->aac_daemontime) == 0)
352ff0991c4SAttilio Rao 		return;
353ff0991c4SAttilio Rao 	getmicrotime(&tv);
354ff0991c4SAttilio Rao 	aac_alloc_sync_fib(sc, &fib);
355ff0991c4SAttilio Rao 	*(uint32_t *)fib->data = tv.tv_sec;
356ff0991c4SAttilio Rao 	aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t));
357ff0991c4SAttilio Rao 	aac_release_sync_fib(sc);
358ff0991c4SAttilio Rao 	callout_schedule(&sc->aac_daemontime, 30 * 60 * hz);
359ff0991c4SAttilio Rao }
360ff0991c4SAttilio Rao 
3617cb209f5SScott Long void
3627cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3637cb209f5SScott Long {
3647cb209f5SScott Long 
3657cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3667cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3677cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3687cb209f5SScott Long 		break;
3697cb209f5SScott Long 	default:
3707cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3717cb209f5SScott Long 		    event->ev_type);
3727cb209f5SScott Long 		break;
3737cb209f5SScott Long 	}
3747cb209f5SScott Long 
3757cb209f5SScott Long 	return;
3767cb209f5SScott Long }
3777cb209f5SScott Long 
378914da7d0SScott Long /*
37904f4d586SEd Maste  * Request information of container #cid
38004f4d586SEd Maste  */
38104f4d586SEd Maste static struct aac_mntinforesp *
38204f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid)
38304f4d586SEd Maste {
38404f4d586SEd Maste 	struct aac_mntinfo *mi;
38504f4d586SEd Maste 
38604f4d586SEd Maste 	mi = (struct aac_mntinfo *)&fib->data[0];
387523da39bSEd Maste 	/* use 64-bit LBA if enabled */
388523da39bSEd Maste 	mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ?
389523da39bSEd Maste 	    VM_NameServe64 : VM_NameServe;
39004f4d586SEd Maste 	mi->MntType = FT_FILESYS;
39104f4d586SEd Maste 	mi->MntCount = cid;
39204f4d586SEd Maste 
39304f4d586SEd Maste 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
39404f4d586SEd Maste 			 sizeof(struct aac_mntinfo))) {
395a620bad0SEd Maste 		printf("Error probing container %d\n", cid);
39604f4d586SEd Maste 		return (NULL);
39704f4d586SEd Maste 	}
39804f4d586SEd Maste 
39904f4d586SEd Maste 	return ((struct aac_mntinforesp *)&fib->data[0]);
40004f4d586SEd Maste }
40104f4d586SEd Maste 
40204f4d586SEd Maste /*
40335863739SMike Smith  * Probe for containers, create disks.
40435863739SMike Smith  */
40535863739SMike Smith static void
40635863739SMike Smith aac_startup(void *arg)
40735863739SMike Smith {
408914da7d0SScott Long 	struct aac_softc *sc;
409cbfd045bSScott Long 	struct aac_fib *fib;
41004f4d586SEd Maste 	struct aac_mntinforesp *mir;
411795d7dc0SScott Long 	int count = 0, i = 0;
41235863739SMike Smith 
413914da7d0SScott Long 	sc = (struct aac_softc *)arg;
41431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
415914da7d0SScott Long 
41635863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
41735863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
41835863739SMike Smith 
4197cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
42003b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
421cbfd045bSScott Long 
42235863739SMike Smith 	/* loop over possible containers */
42336e0bf6eSScott Long 	do {
42404f4d586SEd Maste 		if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
42535863739SMike Smith 			continue;
42604f4d586SEd Maste 		if (i == 0)
427795d7dc0SScott Long 			count = mir->MntRespCount;
428cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
42936e0bf6eSScott Long 		i++;
430795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
431cbfd045bSScott Long 
432cbfd045bSScott Long 	aac_release_sync_fib(sc);
4337cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
43435863739SMike Smith 
43535863739SMike Smith 	/* poke the bus to actually attach the child devices */
43635863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
43735863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
43835863739SMike Smith 
43935863739SMike Smith 	/* mark the controller up */
44035863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
44135863739SMike Smith 
44235863739SMike Smith 	/* enable interrupts now */
44335863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
44435863739SMike Smith }
44535863739SMike Smith 
446914da7d0SScott Long /*
4474109ba51SEd Maste  * Create a device to represent a new container
448914da7d0SScott Long  */
449914da7d0SScott Long static void
450cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
451914da7d0SScott Long {
452914da7d0SScott Long 	struct aac_container *co;
453914da7d0SScott Long 	device_t child;
454914da7d0SScott Long 
455914da7d0SScott Long 	/*
456914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
457914da7d0SScott Long 	 * the possible types may never show up.
458914da7d0SScott Long 	 */
459914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
460a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
461a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
462914da7d0SScott Long 		if (co == NULL)
463a620bad0SEd Maste 			panic("Out of memory?!");
46431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x  name '%.16s'  size %u  type %d",
465914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
466914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
467914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
468914da7d0SScott Long 
469fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
470914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
471914da7d0SScott Long 		else
472914da7d0SScott Long 			device_set_ivars(child, co);
473914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
474914da7d0SScott Long 				mir->MntTable[0].VolType));
475914da7d0SScott Long 		co->co_disk = child;
476914da7d0SScott Long 		co->co_found = f;
477914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
478914da7d0SScott Long 		      sizeof(struct aac_mntobj));
479bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
480914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
481bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
482914da7d0SScott Long 	}
483914da7d0SScott Long }
484914da7d0SScott Long 
485914da7d0SScott Long /*
48604f4d586SEd Maste  * Allocate resources associated with (sc)
48704f4d586SEd Maste  */
48804f4d586SEd Maste static int
48904f4d586SEd Maste aac_alloc(struct aac_softc *sc)
49004f4d586SEd Maste {
49131a0399eSEd Maste 
49231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
49331a0399eSEd Maste 
49404f4d586SEd Maste 	/*
49504f4d586SEd Maste 	 * Create DMA tag for mapping buffers into controller-addressable space.
49604f4d586SEd Maste 	 */
49704f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
49804f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
49904f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
50004f4d586SEd Maste 			       BUS_SPACE_MAXADDR :
50104f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
50204f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
50304f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
50404f4d586SEd Maste 			       MAXBSIZE,		/* maxsize */
50504f4d586SEd Maste 			       sc->aac_sg_tablesize,	/* nsegments */
50604f4d586SEd Maste 			       MAXBSIZE,		/* maxsegsize */
50704f4d586SEd Maste 			       BUS_DMA_ALLOCNOW,	/* flags */
50804f4d586SEd Maste 			       busdma_lock_mutex,	/* lockfunc */
50904f4d586SEd Maste 			       &sc->aac_io_lock,	/* lockfuncarg */
51004f4d586SEd Maste 			       &sc->aac_buffer_dmat)) {
51104f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
51204f4d586SEd Maste 		return (ENOMEM);
51304f4d586SEd Maste 	}
51404f4d586SEd Maste 
51504f4d586SEd Maste 	/*
51604f4d586SEd Maste 	 * Create DMA tag for mapping FIBs into controller-addressable space..
51704f4d586SEd Maste 	 */
51804f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
51904f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
52004f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
52104f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
52204f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
52304f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
52404f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
52504f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
52604f4d586SEd Maste 			       sc->aac_max_fib_size,  /* maxsize */
52704f4d586SEd Maste 			       1,			/* nsegments */
52804f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
52904f4d586SEd Maste 			       sc->aac_max_fib_size,	/* maxsize */
53004f4d586SEd Maste 			       0,			/* flags */
53104f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
53204f4d586SEd Maste 			       &sc->aac_fib_dmat)) {
533c2ede4b3SMartin Blapp 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");
53404f4d586SEd Maste 		return (ENOMEM);
53504f4d586SEd Maste 	}
53604f4d586SEd Maste 
53704f4d586SEd Maste 	/*
53804f4d586SEd Maste 	 * Create DMA tag for the common structure and allocate it.
53904f4d586SEd Maste 	 */
54004f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
54104f4d586SEd Maste 			       1, 0,			/* algnmnt, boundary */
54204f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
54304f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
54404f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
54504f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
54604f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
54704f4d586SEd Maste 			       8192 + sizeof(struct aac_common), /* maxsize */
54804f4d586SEd Maste 			       1,			/* nsegments */
54904f4d586SEd Maste 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
55004f4d586SEd Maste 			       0,			/* flags */
55104f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
55204f4d586SEd Maste 			       &sc->aac_common_dmat)) {
55304f4d586SEd Maste 		device_printf(sc->aac_dev,
55404f4d586SEd Maste 			      "can't allocate common structure DMA tag\n");
55504f4d586SEd Maste 		return (ENOMEM);
55604f4d586SEd Maste 	}
55704f4d586SEd Maste 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
55804f4d586SEd Maste 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
55904f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate common structure\n");
56004f4d586SEd Maste 		return (ENOMEM);
56104f4d586SEd Maste 	}
56204f4d586SEd Maste 
56304f4d586SEd Maste 	/*
56404f4d586SEd Maste 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
56504f4d586SEd Maste 	 * below address 8192 in physical memory.
56604f4d586SEd Maste 	 * XXX If the padding is not needed, can it be put to use instead
56704f4d586SEd Maste 	 * of ignored?
56804f4d586SEd Maste 	 */
56904f4d586SEd Maste 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
57004f4d586SEd Maste 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
57104f4d586SEd Maste 			aac_common_map, sc, 0);
57204f4d586SEd Maste 
57304f4d586SEd Maste 	if (sc->aac_common_busaddr < 8192) {
57404f4d586SEd Maste 		sc->aac_common = (struct aac_common *)
57504f4d586SEd Maste 		    ((uint8_t *)sc->aac_common + 8192);
57604f4d586SEd Maste 		sc->aac_common_busaddr += 8192;
57704f4d586SEd Maste 	}
57804f4d586SEd Maste 	bzero(sc->aac_common, sizeof(*sc->aac_common));
57904f4d586SEd Maste 
58004f4d586SEd Maste 	/* Allocate some FIBs and associated command structs */
58104f4d586SEd Maste 	TAILQ_INIT(&sc->aac_fibmap_tqh);
58204f4d586SEd Maste 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
58304f4d586SEd Maste 				  M_AACBUF, M_WAITOK|M_ZERO);
58423e876b1SJung-uk Kim 	while (sc->total_fibs < sc->aac_max_fibs) {
58504f4d586SEd Maste 		if (aac_alloc_commands(sc) != 0)
58604f4d586SEd Maste 			break;
58704f4d586SEd Maste 	}
58804f4d586SEd Maste 	if (sc->total_fibs == 0)
58904f4d586SEd Maste 		return (ENOMEM);
59004f4d586SEd Maste 
59104f4d586SEd Maste 	return (0);
59204f4d586SEd Maste }
59304f4d586SEd Maste 
59404f4d586SEd Maste /*
59535863739SMike Smith  * Free all of the resources associated with (sc)
59635863739SMike Smith  *
59735863739SMike Smith  * Should not be called if the controller is active.
59835863739SMike Smith  */
59935863739SMike Smith void
60035863739SMike Smith aac_free(struct aac_softc *sc)
60135863739SMike Smith {
602ffb37f33SScott Long 
60331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
60435863739SMike Smith 
60535863739SMike Smith 	/* remove the control device */
60635863739SMike Smith 	if (sc->aac_dev_t != NULL)
60735863739SMike Smith 		destroy_dev(sc->aac_dev_t);
60835863739SMike Smith 
6090b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
6108480cc63SScott Long 	aac_free_commands(sc);
6110b94a66eSMike Smith 	if (sc->aac_fib_dmat)
6120b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
61335863739SMike Smith 
614ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
615ffb37f33SScott Long 
61635863739SMike Smith 	/* destroy the common area */
61735863739SMike Smith 	if (sc->aac_common) {
61835863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
619c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
620c6eafcf2SScott Long 				sc->aac_common_dmamap);
62135863739SMike Smith 	}
6220b94a66eSMike Smith 	if (sc->aac_common_dmat)
6230b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
62435863739SMike Smith 
62535863739SMike Smith 	/* disconnect the interrupt handler */
62635863739SMike Smith 	if (sc->aac_intr)
62735863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
62835863739SMike Smith 	if (sc->aac_irq != NULL)
629c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
630c6eafcf2SScott Long 				     sc->aac_irq);
63135863739SMike Smith 
63235863739SMike Smith 	/* destroy data-transfer DMA tag */
63335863739SMike Smith 	if (sc->aac_buffer_dmat)
63435863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
63535863739SMike Smith 
63635863739SMike Smith 	/* destroy the parent DMA tag */
63735863739SMike Smith 	if (sc->aac_parent_dmat)
63835863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
63935863739SMike Smith 
64035863739SMike Smith 	/* release the register window mapping */
641ff0991c4SAttilio Rao 	if (sc->aac_regs_res0 != NULL)
642914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
643ff0991c4SAttilio Rao 				     sc->aac_regs_rid0, sc->aac_regs_res0);
644ff0991c4SAttilio Rao 	if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL)
645ff0991c4SAttilio Rao 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
646ff0991c4SAttilio Rao 				     sc->aac_regs_rid1, sc->aac_regs_res1);
64735863739SMike Smith }
64835863739SMike Smith 
649914da7d0SScott Long /*
65035863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
65135863739SMike Smith  */
65235863739SMike Smith int
65335863739SMike Smith aac_detach(device_t dev)
65435863739SMike Smith {
655914da7d0SScott Long 	struct aac_softc *sc;
65670545d1aSScott Long 	struct aac_container *co;
65770545d1aSScott Long 	struct aac_sim	*sim;
65835863739SMike Smith 	int error;
65935863739SMike Smith 
660914da7d0SScott Long 	sc = device_get_softc(dev);
66131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
662914da7d0SScott Long 
66335863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
66435863739SMike Smith 		return(EBUSY);
66535863739SMike Smith 
666ff0991c4SAttilio Rao 	callout_drain(&sc->aac_daemontime);
667ff0991c4SAttilio Rao 
66870545d1aSScott Long 	/* Remove the child containers */
669a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
67070545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
67170545d1aSScott Long 		if (error)
67270545d1aSScott Long 			return (error);
67365ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
674a761a1caSScott Long 		free(co, M_AACBUF);
67570545d1aSScott Long 	}
67670545d1aSScott Long 
67770545d1aSScott Long 	/* Remove the CAM SIMs */
678a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
679a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
68070545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
68170545d1aSScott Long 		if (error)
68270545d1aSScott Long 			return (error);
683a761a1caSScott Long 		free(sim, M_AACBUF);
68470545d1aSScott Long 	}
68570545d1aSScott Long 
68636e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
68736e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
68836e0bf6eSScott Long 		wakeup(sc->aifthread);
68936e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
69036e0bf6eSScott Long 	}
69136e0bf6eSScott Long 
69236e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
693a620bad0SEd Maste 		panic("Cannot shutdown AIF thread");
69436e0bf6eSScott Long 
69535863739SMike Smith 	if ((error = aac_shutdown(dev)))
69635863739SMike Smith 		return(error);
69735863739SMike Smith 
6985f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
6995f54d522SScott Long 
70035863739SMike Smith 	aac_free(sc);
70135863739SMike Smith 
702dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
703dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
704dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
705dc9efde5SScott Long 
70635863739SMike Smith 	return(0);
70735863739SMike Smith }
70835863739SMike Smith 
709914da7d0SScott Long /*
71035863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
71135863739SMike Smith  *
71235863739SMike Smith  * This function is called before detach or system shutdown.
71335863739SMike Smith  *
7140b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
71535863739SMike Smith  * allow shutdown if any device is open.
71635863739SMike Smith  */
71735863739SMike Smith int
71835863739SMike Smith aac_shutdown(device_t dev)
71935863739SMike Smith {
720914da7d0SScott Long 	struct aac_softc *sc;
721cbfd045bSScott Long 	struct aac_fib *fib;
722cbfd045bSScott Long 	struct aac_close_command *cc;
72335863739SMike Smith 
724914da7d0SScott Long 	sc = device_get_softc(dev);
72531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
726914da7d0SScott Long 
72735863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
72835863739SMike Smith 
72935863739SMike Smith 	/*
73035863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
73135863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
73235863739SMike Smith 	 * We've been closed and all I/O completed already
73335863739SMike Smith 	 */
73435863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
73535863739SMike Smith 
7367cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
73703b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
738cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
739cbfd045bSScott Long 
74039ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
741cbfd045bSScott Long 	cc->Command = VM_CloseAll;
742cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
743cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
744cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
74535863739SMike Smith 		printf("FAILED.\n");
74670545d1aSScott Long 	else
74770545d1aSScott Long 		printf("done\n");
74870545d1aSScott Long #if 0
749914da7d0SScott Long 	else {
750cbfd045bSScott Long 		fib->data[0] = 0;
75136e0bf6eSScott Long 		/*
752914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
75336e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
75436e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
75536e0bf6eSScott Long 		 * driver module with the intent to reload it later.
75636e0bf6eSScott Long 		 */
757cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
758cbfd045bSScott Long 		    fib, 1)) {
75935863739SMike Smith 			printf("FAILED.\n");
76035863739SMike Smith 		} else {
76135863739SMike Smith 			printf("done.\n");
76235863739SMike Smith 		}
76335863739SMike Smith 	}
76470545d1aSScott Long #endif
76535863739SMike Smith 
76635863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
7673576af8fSScott Long 	aac_release_sync_fib(sc);
7687cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
76935863739SMike Smith 
77035863739SMike Smith 	return(0);
77135863739SMike Smith }
77235863739SMike Smith 
773914da7d0SScott Long /*
77435863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
77535863739SMike Smith  */
77635863739SMike Smith int
77735863739SMike Smith aac_suspend(device_t dev)
77835863739SMike Smith {
779914da7d0SScott Long 	struct aac_softc *sc;
78035863739SMike Smith 
781914da7d0SScott Long 	sc = device_get_softc(dev);
782914da7d0SScott Long 
78331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
78435863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
78535863739SMike Smith 
78635863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
78735863739SMike Smith 	return(0);
78835863739SMike Smith }
78935863739SMike Smith 
790914da7d0SScott Long /*
79135863739SMike Smith  * Bring the controller back to a state ready for operation.
79235863739SMike Smith  */
79335863739SMike Smith int
79435863739SMike Smith aac_resume(device_t dev)
79535863739SMike Smith {
796914da7d0SScott Long 	struct aac_softc *sc;
79735863739SMike Smith 
798914da7d0SScott Long 	sc = device_get_softc(dev);
799914da7d0SScott Long 
80031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
80135863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
80235863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
80335863739SMike Smith 	return(0);
80435863739SMike Smith }
80535863739SMike Smith 
806914da7d0SScott Long /*
8077cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
80835863739SMike Smith  */
80935863739SMike Smith void
8107cb209f5SScott Long aac_new_intr(void *arg)
8117cb209f5SScott Long {
8127cb209f5SScott Long 	struct aac_softc *sc;
8137cb209f5SScott Long 	u_int32_t index, fast;
8147cb209f5SScott Long 	struct aac_command *cm;
8157cb209f5SScott Long 	struct aac_fib *fib;
8167cb209f5SScott Long 	int i;
8177cb209f5SScott Long 
8187cb209f5SScott Long 	sc = (struct aac_softc *)arg;
8197cb209f5SScott Long 
82031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
8217cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
8227cb209f5SScott Long 	while (1) {
8237cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
8247cb209f5SScott Long 		if (index == 0xffffffff)
8257cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
8267cb209f5SScott Long 		if (index == 0xffffffff)
8277cb209f5SScott Long 			break;
8287cb209f5SScott Long 		if (index & 2) {
8297cb209f5SScott Long 			if (index == 0xfffffffe) {
8307cb209f5SScott Long 				/* XXX This means that the controller wants
8317cb209f5SScott Long 				 * more work.  Ignore it for now.
8327cb209f5SScott Long 				 */
8337cb209f5SScott Long 				continue;
8347cb209f5SScott Long 			}
8357cb209f5SScott Long 			/* AIF */
8367cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
8377cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
8387cb209f5SScott Long 			if (fib == NULL) {
8397cb209f5SScott Long 				/* If we're really this short on memory,
8407cb209f5SScott Long 				 * hopefully breaking out of the handler will
8417cb209f5SScott Long 				 * allow something to get freed.  This
8427cb209f5SScott Long 				 * actually sucks a whole lot.
8437cb209f5SScott Long 				 */
8447cb209f5SScott Long 				break;
8457cb209f5SScott Long 			}
8467cb209f5SScott Long 			index &= ~2;
8477cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
848ff0991c4SAttilio Rao 				((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4);
8497cb209f5SScott Long 			aac_handle_aif(sc, fib);
8507cb209f5SScott Long 			free(fib, M_AACBUF);
8517cb209f5SScott Long 
8527cb209f5SScott Long 			/*
8537cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
8547cb209f5SScott Long 			 * know that we are done with it.
8557cb209f5SScott Long 			 */
8567cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
8577cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
8587cb209f5SScott Long 		} else {
8597cb209f5SScott Long 			fast = index & 1;
8607cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
8617cb209f5SScott Long 			fib = cm->cm_fib;
8627cb209f5SScott Long 			if (fast) {
8637cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
8647cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
8657cb209f5SScott Long 			}
8667cb209f5SScott Long 			aac_remove_busy(cm);
8677cb209f5SScott Long  			aac_unmap_command(cm);
8687cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
8697cb209f5SScott Long 
8707cb209f5SScott Long 			/* is there a completion handler? */
8717cb209f5SScott Long 			if (cm->cm_complete != NULL) {
8727cb209f5SScott Long 				cm->cm_complete(cm);
8737cb209f5SScott Long 			} else {
8747cb209f5SScott Long 				/* assume that someone is sleeping on this
8757cb209f5SScott Long 				 * command
8767cb209f5SScott Long 				 */
8777cb209f5SScott Long 				wakeup(cm);
8787cb209f5SScott Long 			}
8797cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
8807cb209f5SScott Long 		}
8817cb209f5SScott Long 	}
8827cb209f5SScott Long 	/* see if we can start some more I/O */
8837cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
8847cb209f5SScott Long 		aac_startio(sc);
8857cb209f5SScott Long 
8867cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
8877cb209f5SScott Long }
8887cb209f5SScott Long 
889e46b9eeaSEd Maste /*
890e46b9eeaSEd Maste  * Interrupt filter for !NEW_COMM interface.
891e46b9eeaSEd Maste  */
892ef544f63SPaolo Pisati int
893e46b9eeaSEd Maste aac_filter(void *arg)
89435863739SMike Smith {
895914da7d0SScott Long 	struct aac_softc *sc;
89670545d1aSScott Long 	u_int16_t reason;
89735863739SMike Smith 
898914da7d0SScott Long 	sc = (struct aac_softc *)arg;
899914da7d0SScott Long 
90031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
901f30ac74cSScott Long 	/*
9029148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
9039148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
9049148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
9059148fa21SScott Long 	 * ugly.
906f30ac74cSScott Long 	 */
90735863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
908f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
909f30ac74cSScott Long 
9109c3a7fceSScott Long 	/* handle completion processing */
9119148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
9129148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
91335863739SMike Smith 
9149148fa21SScott Long 	/* controller wants to talk to us */
9159148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
91670545d1aSScott Long 		/*
9179148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
9189148fa21SScott Long 		 * that start with a NULL.
91970545d1aSScott Long 		 */
9209148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
9219148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
9229148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
92370545d1aSScott Long 
9249148fa21SScott Long 		/*
9259148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
926a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
9279148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
9289148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
9299148fa21SScott Long 		 * if needed.
9309148fa21SScott Long 		 */
93136e0bf6eSScott Long 		wakeup(sc->aifthread);
93236e0bf6eSScott Long 	}
933ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
9349148fa21SScott Long }
93535863739SMike Smith 
936c6eafcf2SScott Long /*
937914da7d0SScott Long  * Command Processing
938914da7d0SScott Long  */
93935863739SMike Smith 
940914da7d0SScott Long /*
94135863739SMike Smith  * Start as much queued I/O as possible on the controller
94235863739SMike Smith  */
943fe3cb0e1SScott Long void
94435863739SMike Smith aac_startio(struct aac_softc *sc)
94535863739SMike Smith {
94635863739SMike Smith 	struct aac_command *cm;
947397fa34fSScott Long 	int error;
94835863739SMike Smith 
94931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
95035863739SMike Smith 
95135863739SMike Smith 	for (;;) {
952914da7d0SScott Long 		/*
953397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
954397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
955397fa34fSScott Long 		 */
956397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
957397fa34fSScott Long 			break;
958397fa34fSScott Long 
959397fa34fSScott Long 		/*
960914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
961914da7d0SScott Long 		 * resources
962914da7d0SScott Long 		 */
96335863739SMike Smith 		cm = aac_dequeue_ready(sc);
96435863739SMike Smith 
965914da7d0SScott Long 		/*
966914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
967914da7d0SScott Long 		 * return)
968914da7d0SScott Long 		 */
9690b94a66eSMike Smith 		if (cm == NULL)
97035863739SMike Smith 			aac_bio_command(sc, &cm);
97135863739SMike Smith 
97235863739SMike Smith 		/* nothing to do? */
97335863739SMike Smith 		if (cm == NULL)
97435863739SMike Smith 			break;
97535863739SMike Smith 
976cd481291SScott Long 		/* don't map more than once */
977cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
9784102d44bSScott Long 			panic("aac: command %p already mapped", cm);
97935863739SMike Smith 
980397fa34fSScott Long 		/*
981397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
982397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
983397fa34fSScott Long 		 * busdma.
984397fa34fSScott Long 		 */
985cd481291SScott Long 		if (cm->cm_datalen != 0) {
986397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
987397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
988397fa34fSScott Long 						cm->cm_datalen,
989cd481291SScott Long 						aac_map_command_sg, cm, 0);
990cd481291SScott Long 			if (error == EINPROGRESS) {
99131a0399eSEd Maste 				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
992cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
993cd481291SScott Long 				error = 0;
994614c22b2SScott Long 			} else if (error != 0)
995397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
996a620bad0SEd Maste 				      "busdma", error);
997397fa34fSScott Long 		} else
9988778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
999cd481291SScott Long 	}
100035863739SMike Smith }
100135863739SMike Smith 
1002914da7d0SScott Long /*
100335863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
100435863739SMike Smith  */
100535863739SMike Smith static void
100670545d1aSScott Long aac_command_thread(struct aac_softc *sc)
100735863739SMike Smith {
100835863739SMike Smith 	struct aac_fib *fib;
100935863739SMike Smith 	u_int32_t fib_size;
10109148fa21SScott Long 	int size, retval;
101135863739SMike Smith 
101231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
101335863739SMike Smith 
1014bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1015a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
101636e0bf6eSScott Long 
1017a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1018a32a982dSScott Long 
1019a32a982dSScott Long 		retval = 0;
1020a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1021a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1022a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
102336e0bf6eSScott Long 
10249148fa21SScott Long 		/*
10259148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
10269148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
10279148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
10289148fa21SScott Long 		 */
10299148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1030bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
1031a32a982dSScott Long 			aac_alloc_commands(sc);
1032bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
10334102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1034a32a982dSScott Long 			aac_startio(sc);
1035a32a982dSScott Long 		}
10369148fa21SScott Long 
10379148fa21SScott Long 		/*
10389148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
10399148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
10409148fa21SScott Long 		 * always fire.
10419148fa21SScott Long 		 */
10429148fa21SScott Long 		if (retval == EWOULDBLOCK)
104370545d1aSScott Long 			aac_timeout(sc);
104470545d1aSScott Long 
104570545d1aSScott Long 		/* Check the hardware printf message buffer */
10469148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
104770545d1aSScott Long 			aac_print_printf(sc);
104870545d1aSScott Long 
10499148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
10507cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
10517cb209f5SScott Long 			continue;
10527cb209f5SScott Long 		for (;;) {
10537cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
10547cb209f5SScott Long 					   &fib_size, &fib))
10557cb209f5SScott Long 				break;
105635863739SMike Smith 
105736e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
105836e0bf6eSScott Long 
105935863739SMike Smith 			switch (fib->Header.Command) {
106035863739SMike Smith 			case AifRequest:
106136e0bf6eSScott Long 				aac_handle_aif(sc, fib);
106235863739SMike Smith 				break;
106335863739SMike Smith 			default:
1064914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
1065914da7d0SScott Long 					      "from controller\n");
106635863739SMike Smith 				break;
106735863739SMike Smith 			}
106835863739SMike Smith 
106936e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
10707cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
107136e0bf6eSScott Long 				break;
10727cb209f5SScott Long 			}
107336e0bf6eSScott Long 
107470545d1aSScott Long 			/* Return the AIF to the controller. */
107536e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
107636e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
107736e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
107836e0bf6eSScott Long 
107936e0bf6eSScott Long 				/* XXX Compute the Size field? */
108036e0bf6eSScott Long 				size = fib->Header.Size;
108136e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
108236e0bf6eSScott Long 					size = sizeof(struct aac_fib);
108336e0bf6eSScott Long 					fib->Header.Size = size;
108436e0bf6eSScott Long 				}
108536e0bf6eSScott Long 				/*
1086914da7d0SScott Long 				 * Since we did not generate this command, it
1087914da7d0SScott Long 				 * cannot go through the normal
1088914da7d0SScott Long 				 * enqueue->startio chain.
108936e0bf6eSScott Long 				 */
1090914da7d0SScott Long 				aac_enqueue_response(sc,
1091914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
1092914da7d0SScott Long 						 fib);
109336e0bf6eSScott Long 			}
109436e0bf6eSScott Long 		}
109536e0bf6eSScott Long 	}
109636e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1097bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
109836e0bf6eSScott Long 	wakeup(sc->aac_dev);
109936e0bf6eSScott Long 
11003745c395SJulian Elischer 	kproc_exit(0);
110135863739SMike Smith }
110235863739SMike Smith 
1103914da7d0SScott Long /*
11049c3a7fceSScott Long  * Process completed commands.
110535863739SMike Smith  */
110635863739SMike Smith static void
11079c3a7fceSScott Long aac_complete(void *context, int pending)
110835863739SMike Smith {
11099c3a7fceSScott Long 	struct aac_softc *sc;
111035863739SMike Smith 	struct aac_command *cm;
111135863739SMike Smith 	struct aac_fib *fib;
111235863739SMike Smith 	u_int32_t fib_size;
111335863739SMike Smith 
11149c3a7fceSScott Long 	sc = (struct aac_softc *)context;
111531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
11169c3a7fceSScott Long 
1117bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1118ae543596SScott Long 
11199c3a7fceSScott Long 	/* pull completed commands off the queue */
112035863739SMike Smith 	for (;;) {
112135863739SMike Smith 		/* look for completed FIBs on our queue */
1122914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1123914da7d0SScott Long 							&fib))
112435863739SMike Smith 			break;	/* nothing to do */
112535863739SMike Smith 
1126ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1127cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
112835863739SMike Smith 		if (cm == NULL) {
112935863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
11309c3a7fceSScott Long 			break;
11319c3a7fceSScott Long 		}
1132*3e507710SEd Maste 		if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0)
1133*3e507710SEd Maste 			device_printf(sc->aac_dev,
1134*3e507710SEd Maste 			    "COMMAND %p COMPLETED AFTER %d SECONDS\n",
1135*3e507710SEd Maste 			    cm, (int)(time_uptime-cm->cm_timestamp));
1136*3e507710SEd Maste 
11370b94a66eSMike Smith 		aac_remove_busy(cm);
11387cb209f5SScott Long 
1139ecd1c51fSScott Long  		aac_unmap_command(cm);
114035863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
114135863739SMike Smith 
114235863739SMike Smith 		/* is there a completion handler? */
114335863739SMike Smith 		if (cm->cm_complete != NULL) {
114435863739SMike Smith 			cm->cm_complete(cm);
114535863739SMike Smith 		} else {
114635863739SMike Smith 			/* assume that someone is sleeping on this command */
114735863739SMike Smith 			wakeup(cm);
114835863739SMike Smith 		}
114935863739SMike Smith 	}
11500b94a66eSMike Smith 
11510b94a66eSMike Smith 	/* see if we can start some more I/O */
1152cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
11530b94a66eSMike Smith 	aac_startio(sc);
1154ae543596SScott Long 
1155bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
115635863739SMike Smith }
115735863739SMike Smith 
1158914da7d0SScott Long /*
115935863739SMike Smith  * Handle a bio submitted from a disk device.
116035863739SMike Smith  */
116135863739SMike Smith void
116235863739SMike Smith aac_submit_bio(struct bio *bp)
116335863739SMike Smith {
1164914da7d0SScott Long 	struct aac_disk *ad;
1165914da7d0SScott Long 	struct aac_softc *sc;
116635863739SMike Smith 
11677540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1168914da7d0SScott Long 	sc = ad->ad_controller;
116931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1170914da7d0SScott Long 
117135863739SMike Smith 	/* queue the BIO and try to get some work done */
11720b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
117335863739SMike Smith 	aac_startio(sc);
117435863739SMike Smith }
117535863739SMike Smith 
1176914da7d0SScott Long /*
117735863739SMike Smith  * Get a bio and build a command to go with it.
117835863739SMike Smith  */
117935863739SMike Smith static int
118035863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
118135863739SMike Smith {
118235863739SMike Smith 	struct aac_command *cm;
118335863739SMike Smith 	struct aac_fib *fib;
118435863739SMike Smith 	struct aac_disk *ad;
118535863739SMike Smith 	struct bio *bp;
118635863739SMike Smith 
118731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
118835863739SMike Smith 
118935863739SMike Smith 	/* get the resources we will need */
119035863739SMike Smith 	cm = NULL;
1191a32a982dSScott Long 	bp = NULL;
119235863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
119335863739SMike Smith 		goto fail;
1194a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1195a32a982dSScott Long 		goto fail;
119635863739SMike Smith 
119735863739SMike Smith 	/* fill out the command */
11980b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
11990b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
12000b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
120135863739SMike Smith 	cm->cm_private = bp;
12022b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
120335863739SMike Smith 
120435863739SMike Smith 	/* build the FIB */
120535863739SMike Smith 	fib = cm->cm_fib;
1206b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
120735863739SMike Smith 	fib->Header.XferState =
120835863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
120935863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1210f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
121135863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
121235863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1213f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1214f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1215f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
121635863739SMike Smith 
121735863739SMike Smith 	/* build the read/write request */
12187540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1219b85f5808SScott Long 
12207cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
12217cb209f5SScott Long 		struct aac_raw_io *raw;
12227cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
12237cb209f5SScott Long 		fib->Header.Command = RawIo;
12247cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
12257cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
12267cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
12277cb209f5SScott Long 		raw->BpTotal = 0;
12287cb209f5SScott Long 		raw->BpComplete = 0;
12297cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
12307cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
12317cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
12327cb209f5SScott Long 			raw->Flags = 1;
12337cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
12347cb209f5SScott Long 		} else {
12357cb209f5SScott Long 			raw->Flags = 0;
12367cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
12377cb209f5SScott Long 		}
12387cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1239b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
12409e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1241b85f5808SScott Long 			struct aac_blockread *br;
124235863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
124335863739SMike Smith 			br->Command = VM_CtBlockRead;
124435863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
124535863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
124635863739SMike Smith 			br->ByteCount = bp->bio_bcount;
124735863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
124835863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
124935863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
125035863739SMike Smith 		} else {
1251b85f5808SScott Long 			struct aac_blockwrite *bw;
125235863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
125335863739SMike Smith 			bw->Command = VM_CtBlockWrite;
125435863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
125535863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
125635863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1257b85f5808SScott Long 			bw->Stable = CUNSTABLE;
125835863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
125935863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
126035863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
126135863739SMike Smith 		}
1262b85f5808SScott Long 	} else {
1263b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1264b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1265b85f5808SScott Long 			struct aac_blockread64 *br;
1266b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1267b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1268b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1269b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1270b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1271b85f5808SScott Long 			br->Pad = 0;
1272b85f5808SScott Long 			br->Flags = 0;
1273b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
127454e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAIN;
1275eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1276b85f5808SScott Long 		} else {
1277b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1278b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1279b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1280b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1281b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1282b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1283b85f5808SScott Long 			bw->Pad = 0;
1284b85f5808SScott Long 			bw->Flags = 0;
1285b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
128654e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAOUT;
1287eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1288b85f5808SScott Long 		}
1289b85f5808SScott Long 	}
129035863739SMike Smith 
129135863739SMike Smith 	*cmp = cm;
129235863739SMike Smith 	return(0);
129335863739SMike Smith 
129435863739SMike Smith fail:
12957cb209f5SScott Long 	if (bp != NULL)
12967cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
129735863739SMike Smith 	if (cm != NULL)
129835863739SMike Smith 		aac_release_command(cm);
129935863739SMike Smith 	return(ENOMEM);
130035863739SMike Smith }
130135863739SMike Smith 
1302914da7d0SScott Long /*
130335863739SMike Smith  * Handle a bio-instigated command that has been completed.
130435863739SMike Smith  */
130535863739SMike Smith static void
130635863739SMike Smith aac_bio_complete(struct aac_command *cm)
130735863739SMike Smith {
130835863739SMike Smith 	struct aac_blockread_response *brr;
130935863739SMike Smith 	struct aac_blockwrite_response *bwr;
131035863739SMike Smith 	struct bio *bp;
131135863739SMike Smith 	AAC_FSAStatus status;
131235863739SMike Smith 
131335863739SMike Smith 	/* fetch relevant status and then release the command */
131435863739SMike Smith 	bp = (struct bio *)cm->cm_private;
13159e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
131635863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
131735863739SMike Smith 		status = brr->Status;
131835863739SMike Smith 	} else {
131935863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
132035863739SMike Smith 		status = bwr->Status;
132135863739SMike Smith 	}
132235863739SMike Smith 	aac_release_command(cm);
132335863739SMike Smith 
132435863739SMike Smith 	/* fix up the bio based on status */
132535863739SMike Smith 	if (status == ST_OK) {
132635863739SMike Smith 		bp->bio_resid = 0;
132735863739SMike Smith 	} else {
132835863739SMike Smith 		bp->bio_error = EIO;
132935863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
13300b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1331914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1332914da7d0SScott Long 						    status);
133335863739SMike Smith 	}
13340b94a66eSMike Smith 	aac_biodone(bp);
133535863739SMike Smith }
133635863739SMike Smith 
1337914da7d0SScott Long /*
133835863739SMike Smith  * Submit a command to the controller, return when it completes.
1339b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1340b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1341d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1342d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1343d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1344d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1345d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
134635863739SMike Smith  */
134735863739SMike Smith static int
1348d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
134935863739SMike Smith {
1350ae543596SScott Long 	struct aac_softc *sc;
1351d8a0a473SScott Long 	int error;
135235863739SMike Smith 
1353ae543596SScott Long 	sc = cm->cm_sc;
135431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1355ae543596SScott Long 
135635863739SMike Smith 	/* Put the command on the ready queue and get things going */
135735863739SMike Smith 	aac_enqueue_ready(cm);
1358ae543596SScott Long 	aac_startio(sc);
1359ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
136035863739SMike Smith 	return(error);
136135863739SMike Smith }
136235863739SMike Smith 
1363914da7d0SScott Long /*
1364914da7d0SScott Long  *Command Buffer Management
1365914da7d0SScott Long  */
136635863739SMike Smith 
1367914da7d0SScott Long /*
136835863739SMike Smith  * Allocate a command.
136935863739SMike Smith  */
1370fe3cb0e1SScott Long int
137135863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
137235863739SMike Smith {
137335863739SMike Smith 	struct aac_command *cm;
137435863739SMike Smith 
137531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
137635863739SMike Smith 
1377ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1378b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1379ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1380ae543596SScott Long 			wakeup(sc->aifthread);
1381b85f5808SScott Long 		}
1382ae543596SScott Long 		return (EBUSY);
1383ffb37f33SScott Long 	}
138435863739SMike Smith 
13850b94a66eSMike Smith 	*cmp = cm;
13860b94a66eSMike Smith 	return(0);
13870b94a66eSMike Smith }
13880b94a66eSMike Smith 
1389914da7d0SScott Long /*
13900b94a66eSMike Smith  * Release a command back to the freelist.
13910b94a66eSMike Smith  */
1392fe3cb0e1SScott Long void
13930b94a66eSMike Smith aac_release_command(struct aac_command *cm)
13940b94a66eSMike Smith {
13957cb209f5SScott Long 	struct aac_event *event;
13967cb209f5SScott Long 	struct aac_softc *sc;
13977cb209f5SScott Long 
139831a0399eSEd Maste 	sc = cm->cm_sc;
139931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
14000b94a66eSMike Smith 
14014109ba51SEd Maste 	/* (re)initialize the command/FIB */
140235863739SMike Smith 	cm->cm_sgtable = NULL;
140335863739SMike Smith 	cm->cm_flags = 0;
140435863739SMike Smith 	cm->cm_complete = NULL;
140535863739SMike Smith 	cm->cm_private = NULL;
1406dbfc5960SEd Maste 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
140735863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
140835863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
140935863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
14107cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
141135863739SMike Smith 
141235863739SMike Smith 	/*
141335863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
141435863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
14154109ba51SEd Maste 	 * initialized here for debugging purposes only.
141635863739SMike Smith 	 */
1417f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1418f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
141935863739SMike Smith 
142035863739SMike Smith 	aac_enqueue_free(cm);
14217cb209f5SScott Long 
1422eb5cbaa0SEd Maste 	/*
1423eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1424eb5cbaa0SEd Maste 	 * stranded.
1425eb5cbaa0SEd Maste 	 */
1426eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
14277cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
14287cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
14297cb209f5SScott Long 	}
143035863739SMike Smith }
143135863739SMike Smith 
1432914da7d0SScott Long /*
14330b94a66eSMike Smith  * Map helper for command/FIB allocation.
143435863739SMike Smith  */
143535863739SMike Smith static void
14360b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
143735863739SMike Smith {
14387cb209f5SScott Long 	uint64_t	*fibphys;
1439914da7d0SScott Long 
14407cb209f5SScott Long 	fibphys = (uint64_t *)arg;
144135863739SMike Smith 
1442ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
144335863739SMike Smith }
144435863739SMike Smith 
1445914da7d0SScott Long /*
14464109ba51SEd Maste  * Allocate and initialize commands/FIBs for this adapter.
144735863739SMike Smith  */
14480b94a66eSMike Smith static int
14490b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
145035863739SMike Smith {
145135863739SMike Smith 	struct aac_command *cm;
1452ffb37f33SScott Long 	struct aac_fibmap *fm;
14537cb209f5SScott Long 	uint64_t fibphys;
1454ffb37f33SScott Long 	int i, error;
145535863739SMike Smith 
145631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
145735863739SMike Smith 
14587cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1459ffb37f33SScott Long 		return (ENOMEM);
1460ffb37f33SScott Long 
14618480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1462a6d35632SScott Long 	if (fm == NULL)
1463a6d35632SScott Long 		return (ENOMEM);
1464ffb37f33SScott Long 
14650b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1466ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1467ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
146870545d1aSScott Long 		device_printf(sc->aac_dev,
146970545d1aSScott Long 			      "Not enough contiguous memory available.\n");
14708480cc63SScott Long 		free(fm, M_AACBUF);
14710b94a66eSMike Smith 		return (ENOMEM);
147235863739SMike Smith 	}
1473128aa5a0SScott Long 
1474cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1475cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
14767cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1477ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1478128aa5a0SScott Long 
14794109ba51SEd Maste 	/* initialize constant fields in the command structure */
14807cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
14817cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
14828480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1483ffb37f33SScott Long 		fm->aac_commands = cm;
148435863739SMike Smith 		cm->cm_sc = sc;
14857cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
14867cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
14877cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1488cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
148935863739SMike Smith 
1490ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
149193cfca22SScott Long 					       &cm->cm_datamap)) != 0)
14928480cc63SScott Long 			break;
149393cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
149493cfca22SScott Long 		aac_release_command(cm);
14958480cc63SScott Long 		sc->total_fibs++;
149693cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
149735863739SMike Smith 	}
1498ffb37f33SScott Long 
14998480cc63SScott Long 	if (i > 0) {
150093cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1501ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
150231a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1503bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
15040b94a66eSMike Smith 		return (0);
150535863739SMike Smith 	}
150635863739SMike Smith 
15078480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
15088480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15098480cc63SScott Long 	free(fm, M_AACBUF);
15108480cc63SScott Long 	return (ENOMEM);
15118480cc63SScott Long }
15128480cc63SScott Long 
1513914da7d0SScott Long /*
15140b94a66eSMike Smith  * Free FIBs owned by this adapter.
151535863739SMike Smith  */
151635863739SMike Smith static void
15178480cc63SScott Long aac_free_commands(struct aac_softc *sc)
151835863739SMike Smith {
15198480cc63SScott Long 	struct aac_fibmap *fm;
1520ffb37f33SScott Long 	struct aac_command *cm;
152135863739SMike Smith 	int i;
152235863739SMike Smith 
152331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
152435863739SMike Smith 
15258480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
15268480cc63SScott Long 
15278480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
15288480cc63SScott Long 		/*
15298480cc63SScott Long 		 * We check against total_fibs to handle partially
15308480cc63SScott Long 		 * allocated blocks.
15318480cc63SScott Long 		 */
15327cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1533ffb37f33SScott Long 			cm = fm->aac_commands + i;
1534ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1535ffb37f33SScott Long 		}
1536ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1537ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15388480cc63SScott Long 		free(fm, M_AACBUF);
15398480cc63SScott Long 	}
154035863739SMike Smith }
154135863739SMike Smith 
1542914da7d0SScott Long /*
154335863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
154435863739SMike Smith  */
154535863739SMike Smith static void
154635863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
154735863739SMike Smith {
1548cd481291SScott Long 	struct aac_softc *sc;
1549914da7d0SScott Long 	struct aac_command *cm;
1550914da7d0SScott Long 	struct aac_fib *fib;
155135863739SMike Smith 	int i;
155235863739SMike Smith 
1553914da7d0SScott Long 	cm = (struct aac_command *)arg;
1554cd481291SScott Long 	sc = cm->cm_sc;
1555914da7d0SScott Long 	fib = cm->cm_fib;
155631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1557914da7d0SScott Long 
155835863739SMike Smith 	/* copy into the FIB */
1559b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
15607cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
15617cb209f5SScott Long 			struct aac_sg_tableraw *sg;
15627cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
15637cb209f5SScott Long 			sg->SgCount = nseg;
15647cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
15657cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
15667cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
15677cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
15687cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
15697cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
15707cb209f5SScott Long 			}
15717cb209f5SScott Long 			/* update the FIB size for the s/g count */
15727cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
15737cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1574b85f5808SScott Long 			struct aac_sg_table *sg;
1575b85f5808SScott Long 			sg = cm->cm_sgtable;
157635863739SMike Smith 			sg->SgCount = nseg;
157735863739SMike Smith 			for (i = 0; i < nseg; i++) {
157835863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
157935863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
158035863739SMike Smith 			}
158135863739SMike Smith 			/* update the FIB size for the s/g count */
158235863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1583b85f5808SScott Long 		} else {
1584b85f5808SScott Long 			struct aac_sg_table64 *sg;
1585b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1586b85f5808SScott Long 			sg->SgCount = nseg;
1587b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1588b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1589b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
159035863739SMike Smith 			}
1591b85f5808SScott Long 			/* update the FIB size for the s/g count */
1592b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1593b85f5808SScott Long 		}
1594b85f5808SScott Long 	}
159535863739SMike Smith 
1596cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1597cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
15987cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
15997cb209f5SScott Long 	 * and for the AIF bit
160035863739SMike Smith 	 */
16017cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
16027cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
160335863739SMike Smith 
1604cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1605cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
160635863739SMike Smith 
160735863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1608c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1609c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
161035863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1611c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1612c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
161335863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1614cd481291SScott Long 
16157cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
16167cb209f5SScott Long 		int count = 10000000L;
16177cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
16187cb209f5SScott Long 			if (--count == 0) {
16197cb209f5SScott Long 				aac_unmap_command(cm);
16207cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
16217cb209f5SScott Long 				aac_requeue_ready(cm);
16227cb209f5SScott Long 			}
16237cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
16247cb209f5SScott Long 		}
16257cb209f5SScott Long 	} else {
1626397fa34fSScott Long 		/* Put the FIB on the outbound queue */
16274102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
16284102d44bSScott Long 			aac_unmap_command(cm);
1629397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1630cd481291SScott Long 			aac_requeue_ready(cm);
16314102d44bSScott Long 		}
16327cb209f5SScott Long 	}
1633cd481291SScott Long 
1634cd481291SScott Long 	return;
163535863739SMike Smith }
163635863739SMike Smith 
1637914da7d0SScott Long /*
163835863739SMike Smith  * Unmap a command from controller-visible space.
163935863739SMike Smith  */
164035863739SMike Smith static void
164135863739SMike Smith aac_unmap_command(struct aac_command *cm)
164235863739SMike Smith {
1643914da7d0SScott Long 	struct aac_softc *sc;
164435863739SMike Smith 
1645914da7d0SScott Long 	sc = cm->cm_sc;
164631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1647914da7d0SScott Long 
164835863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
164935863739SMike Smith 		return;
165035863739SMike Smith 
165135863739SMike Smith 	if (cm->cm_datalen != 0) {
165235863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1653c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1654c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
165535863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1656c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1657c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
165835863739SMike Smith 
165935863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
166035863739SMike Smith 	}
166135863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
166235863739SMike Smith }
166335863739SMike Smith 
1664914da7d0SScott Long /*
1665914da7d0SScott Long  * Hardware Interface
1666914da7d0SScott Long  */
166735863739SMike Smith 
1668914da7d0SScott Long /*
16694109ba51SEd Maste  * Initialize the adapter.
167035863739SMike Smith  */
167135863739SMike Smith static void
167235863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
167335863739SMike Smith {
1674914da7d0SScott Long 	struct aac_softc *sc;
167535863739SMike Smith 
1676914da7d0SScott Long 	sc = (struct aac_softc *)arg;
167731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1678914da7d0SScott Long 
167935863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
168035863739SMike Smith }
168135863739SMike Smith 
1682a6d35632SScott Long static int
1683a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1684a6d35632SScott Long {
168504f4d586SEd Maste 	u_int32_t code, major, minor, options = 0, atu_size = 0;
1686a441b3fcSScott Long 	int status;
168704f4d586SEd Maste 	time_t then;
1688a6d35632SScott Long 
168931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
169004f4d586SEd Maste 	/*
169104f4d586SEd Maste 	 * Wait for the adapter to come ready.
169204f4d586SEd Maste 	 */
169304f4d586SEd Maste 	then = time_uptime;
169404f4d586SEd Maste 	do {
169504f4d586SEd Maste 		code = AAC_GET_FWSTATUS(sc);
169604f4d586SEd Maste 		if (code & AAC_SELF_TEST_FAILED) {
169704f4d586SEd Maste 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
169804f4d586SEd Maste 			return(ENXIO);
169904f4d586SEd Maste 		}
170004f4d586SEd Maste 		if (code & AAC_KERNEL_PANIC) {
170104f4d586SEd Maste 			device_printf(sc->aac_dev,
1702a620bad0SEd Maste 				      "FATAL: controller kernel panic");
170304f4d586SEd Maste 			return(ENXIO);
170404f4d586SEd Maste 		}
170504f4d586SEd Maste 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
170604f4d586SEd Maste 			device_printf(sc->aac_dev,
170704f4d586SEd Maste 				      "FATAL: controller not coming ready, "
170804f4d586SEd Maste 					   "status %x\n", code);
170904f4d586SEd Maste 			return(ENXIO);
171004f4d586SEd Maste 		}
171104f4d586SEd Maste 	} while (!(code & AAC_UP_AND_RUNNING));
1712a6d35632SScott Long 
1713fe94b852SScott Long 	/*
1714fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1715fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1716fe94b852SScott Long 	 */
1717a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1718fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1719fe94b852SScott Long 				     NULL)) {
1720fe94b852SScott Long 			device_printf(sc->aac_dev,
1721fe94b852SScott Long 				      "Error reading firmware version\n");
1722fe94b852SScott Long 			return (EIO);
1723fe94b852SScott Long 		}
1724fe94b852SScott Long 
1725fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1726a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1727a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1728fe94b852SScott Long 		if (major == 1) {
1729fe94b852SScott Long 			device_printf(sc->aac_dev,
1730fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1731fe94b852SScott Long 			    major, minor);
1732fe94b852SScott Long 			return (EINVAL);
1733fe94b852SScott Long 		}
1734fe94b852SScott Long 	}
1735fe94b852SScott Long 
1736a6d35632SScott Long 	/*
1737a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1738a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1739a441b3fcSScott Long 	 * command.
1740a6d35632SScott Long 	 */
1741a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1742a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1743a441b3fcSScott Long 			device_printf(sc->aac_dev,
1744a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1745a6d35632SScott Long 			return (EIO);
1746a6d35632SScott Long 		}
1747a441b3fcSScott Long 	} else {
1748a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
17497cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1750a6d35632SScott Long 		sc->supported_options = options;
1751a6d35632SScott Long 
1752a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1753a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1754a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1755a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1756a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1757cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1758cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1759a441b3fcSScott Long 			device_printf(sc->aac_dev,
1760a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1761a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1762a6d35632SScott Long 		}
1763a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1764a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
17657cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
17667cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
17677cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1768a441b3fcSScott Long 	}
1769a6d35632SScott Long 
1770a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
17717cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
17727cb209f5SScott Long 
17737cb209f5SScott Long 	/* Remap mem. resource, if required */
17747cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1775ff0991c4SAttilio Rao 		atu_size > rman_get_size(sc->aac_regs_res1)) {
17767cb209f5SScott Long 		bus_release_resource(
17777cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
1778ff0991c4SAttilio Rao 			sc->aac_regs_rid1, sc->aac_regs_res1);
1779ff0991c4SAttilio Rao 		sc->aac_regs_res1 = bus_alloc_resource(
1780ff0991c4SAttilio Rao 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1,
17817cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
1782ff0991c4SAttilio Rao 		if (sc->aac_regs_res1 == NULL) {
1783ff0991c4SAttilio Rao 			sc->aac_regs_res1 = bus_alloc_resource_any(
17847cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
1785ff0991c4SAttilio Rao 				&sc->aac_regs_rid1, RF_ACTIVE);
1786ff0991c4SAttilio Rao 			if (sc->aac_regs_res1 == NULL) {
17877cb209f5SScott Long 				device_printf(sc->aac_dev,
17887cb209f5SScott Long 				    "couldn't allocate register window\n");
17897cb209f5SScott Long 				return (ENXIO);
17907cb209f5SScott Long 			}
17917cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
17927cb209f5SScott Long 		}
1793ff0991c4SAttilio Rao 		sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1);
1794ff0991c4SAttilio Rao 		sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1);
1795ff0991c4SAttilio Rao 
1796ff0991c4SAttilio Rao 		if (sc->aac_hwif == AAC_HWIF_NARK) {
1797ff0991c4SAttilio Rao 			sc->aac_regs_res0 = sc->aac_regs_res1;
1798ff0991c4SAttilio Rao 			sc->aac_regs_rid0 = sc->aac_regs_rid1;
1799ff0991c4SAttilio Rao 			sc->aac_btag0 = sc->aac_btag1;
1800ff0991c4SAttilio Rao 			sc->aac_bhandle0 = sc->aac_bhandle1;
1801ff0991c4SAttilio Rao 		}
18027cb209f5SScott Long 	}
18037cb209f5SScott Long 
18047cb209f5SScott Long 	/* Read preferred settings */
18057cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
18067cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
18077cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1808a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18097e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
18107e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1811a6d35632SScott Long 	else
1812a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18137e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
18147e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1815a441b3fcSScott Long 
18167cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
18177cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
18187cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
18197cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
18207cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
18217cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
18227cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
18237cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
18247cb209f5SScott Long 	}
18257cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
18267cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
18277cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1828a6d35632SScott Long 
1829f355c0e0SEd Maste 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1830f355c0e0SEd Maste 		sc->flags |= AAC_FLAGS_RAW_IO;
1831f355c0e0SEd Maste 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1832f355c0e0SEd Maste 	}
1833523da39bSEd Maste 	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1834523da39bSEd Maste 	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1835523da39bSEd Maste 		sc->flags |= AAC_FLAGS_LBA_64BIT;
1836523da39bSEd Maste 		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1837523da39bSEd Maste 	}
1838f355c0e0SEd Maste 
1839fe94b852SScott Long 	return (0);
1840fe94b852SScott Long }
1841fe94b852SScott Long 
184235863739SMike Smith static int
184335863739SMike Smith aac_init(struct aac_softc *sc)
184435863739SMike Smith {
184535863739SMike Smith 	struct aac_adapter_init	*ip;
184604f4d586SEd Maste 	u_int32_t qoffset;
1847a6d35632SScott Long 	int error;
184835863739SMike Smith 
184931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1850ffb37f33SScott Long 
185135863739SMike Smith 	/*
1852914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1853914da7d0SScott Long 	 * physical location of various important shared data structures.
185435863739SMike Smith 	 */
185535863739SMike Smith 	ip = &sc->aac_common->ac_init;
185635863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18577cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18587cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18597cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18607cb209f5SScott Long 	}
1861f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
186235863739SMike Smith 
1863c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1864c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1865149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
186635863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
186735863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
186835863739SMike Smith 
1869c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1870c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
187135863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
187235863739SMike Smith 
18734b00f859SScott Long 	/*
18744b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18754b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18764b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18774b00f859SScott Long 	 * Round up since the granularity is so high.
18784b00f859SScott Long 	 */
1879f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18804b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18814b00f859SScott Long 		ip->HostPhysMemPages =
18824b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1883204c0befSScott Long 	}
18842b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
188535863739SMike Smith 
18867cb209f5SScott Long 	ip->InitFlags = 0;
18877cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1888e71d3b9cSEd Maste 		ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED;
18897cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
18907cb209f5SScott Long 	}
18917cb209f5SScott Long 
18927cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
18937cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
18947cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
18957cb209f5SScott Long 
189635863739SMike Smith 	/*
18974109ba51SEd Maste 	 * Initialize FIB queues.  Note that it appears that the layout of the
1898c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1899c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
190035863739SMike Smith 	 *
190135863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1902914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1903914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1904914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1905914da7d0SScott Long 	 * does.
190635863739SMike Smith 	 *
1907914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1908914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1909914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1910914da7d0SScott Long 	 * virtue of a table.
191135863739SMike Smith 	 */
1912b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
19130bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
19140bcbebd6SScott Long 	sc->aac_queues =
19150bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1916b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
191735863739SMike Smith 
1918c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1919c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1920c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1921c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1922c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1923c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1924c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1925c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1926c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1927c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1928c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1929c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1930c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1931c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1932c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1933c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1934c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1935c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1936c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1937c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1938c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1939c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1940c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1941c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1942c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1943c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1944c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1945c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1946c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1947c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1948c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1949c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1950c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1951c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1952c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1953c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1954c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1955c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1956c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1957c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1958c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1959c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1960c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1961c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1962c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1963c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1964c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1965c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
196635863739SMike Smith 
196735863739SMike Smith 	/*
196835863739SMike Smith 	 * Do controller-type-specific initialisation
196935863739SMike Smith 	 */
197035863739SMike Smith 	switch (sc->aac_hwif) {
197135863739SMike Smith 	case AAC_HWIF_I960RX:
1972ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0);
197335863739SMike Smith 		break;
19744afedc31SScott Long 	case AAC_HWIF_RKT:
1975ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0);
19764afedc31SScott Long 		break;
19774afedc31SScott Long 	default:
19784afedc31SScott Long 		break;
197935863739SMike Smith 	}
198035863739SMike Smith 
198135863739SMike Smith 	/*
198235863739SMike Smith 	 * Give the init structure to the controller.
198335863739SMike Smith 	 */
198435863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1985914da7d0SScott Long 			     sc->aac_common_busaddr +
1986914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1987914da7d0SScott Long 			     NULL)) {
1988914da7d0SScott Long 		device_printf(sc->aac_dev,
1989914da7d0SScott Long 			      "error establishing init structure\n");
1990a6d35632SScott Long 		error = EIO;
1991a6d35632SScott Long 		goto out;
199235863739SMike Smith 	}
199335863739SMike Smith 
1994a6d35632SScott Long 	error = 0;
1995a6d35632SScott Long out:
1996a6d35632SScott Long 	return(error);
199735863739SMike Smith }
199835863739SMike Smith 
199904f4d586SEd Maste static int
200004f4d586SEd Maste aac_setup_intr(struct aac_softc *sc)
200104f4d586SEd Maste {
200204f4d586SEd Maste 	sc->aac_irq_rid = 0;
200304f4d586SEd Maste 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
200404f4d586SEd Maste 			   			  &sc->aac_irq_rid,
200504f4d586SEd Maste 			   			  RF_SHAREABLE |
200604f4d586SEd Maste 						  RF_ACTIVE)) == NULL) {
200704f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
200804f4d586SEd Maste 		return (EINVAL);
200904f4d586SEd Maste 	}
201004f4d586SEd Maste 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
201104f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
201204f4d586SEd Maste 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
201304f4d586SEd Maste 				   aac_new_intr, sc, &sc->aac_intr)) {
201404f4d586SEd Maste 			device_printf(sc->aac_dev, "can't set up interrupt\n");
201504f4d586SEd Maste 			return (EINVAL);
201604f4d586SEd Maste 		}
201704f4d586SEd Maste 	} else {
201804f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2019e46b9eeaSEd Maste 				   INTR_TYPE_BIO, aac_filter, NULL,
202004f4d586SEd Maste 				   sc, &sc->aac_intr)) {
202104f4d586SEd Maste 			device_printf(sc->aac_dev,
2022e46b9eeaSEd Maste 				      "can't set up interrupt filter\n");
202304f4d586SEd Maste 			return (EINVAL);
202404f4d586SEd Maste 		}
202504f4d586SEd Maste 	}
202604f4d586SEd Maste 	return (0);
202704f4d586SEd Maste }
202804f4d586SEd Maste 
2029914da7d0SScott Long /*
203035863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
20317cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
203235863739SMike Smith  */
203335863739SMike Smith static int
203435863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
203535863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
203635863739SMike Smith 		 u_int32_t *sp)
203735863739SMike Smith {
203835863739SMike Smith 	time_t then;
203935863739SMike Smith 	u_int32_t status;
204035863739SMike Smith 
204131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
204235863739SMike Smith 
204335863739SMike Smith 	/* populate the mailbox */
204435863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
204535863739SMike Smith 
204635863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
204735863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
204835863739SMike Smith 
204935863739SMike Smith 	/* then set it to signal the adapter */
205035863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
205135863739SMike Smith 
205235863739SMike Smith 	/* spin waiting for the command to complete */
20532b3b0f17SScott Long 	then = time_uptime;
205435863739SMike Smith 	do {
20552b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
205631a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
205735863739SMike Smith 			return(EIO);
205835863739SMike Smith 		}
205935863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
206035863739SMike Smith 
206135863739SMike Smith 	/* clear the completion flag */
206235863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
206335863739SMike Smith 
206435863739SMike Smith 	/* get the command status */
2065a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
206635863739SMike Smith 	if (sp != NULL)
206735863739SMike Smith 		*sp = status;
20687cb209f5SScott Long 
2069a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20707cb209f5SScott Long 		return (-1);
20710b94a66eSMike Smith 	return(0);
207235863739SMike Smith }
207335863739SMike Smith 
2074cbfd045bSScott Long int
207535863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2076cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
207735863739SMike Smith {
207831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
20797cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
208035863739SMike Smith 
208135863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
208235863739SMike Smith 		return(EINVAL);
208335863739SMike Smith 
208435863739SMike Smith 	/*
208535863739SMike Smith 	 * Set up the sync FIB
208635863739SMike Smith 	 */
2087914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2088914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2089c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
209035863739SMike Smith 	fib->Header.XferState |= xferstate;
209135863739SMike Smith 	fib->Header.Command = command;
209235863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
209342ef13a2SEd Maste 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
209435863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2095b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2096c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2097914da7d0SScott Long 					 offsetof(struct aac_common,
2098914da7d0SScott Long 						  ac_sync_fib);
209935863739SMike Smith 
210035863739SMike Smith 	/*
210135863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
210235863739SMike Smith 	 */
2103914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2104914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
210531a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
210635863739SMike Smith 		return(EIO);
210735863739SMike Smith 	}
210835863739SMike Smith 
210935863739SMike Smith 	return (0);
211035863739SMike Smith }
211135863739SMike Smith 
2112914da7d0SScott Long /*
211335863739SMike Smith  * Adapter-space FIB queue manipulation
211435863739SMike Smith  *
211535863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
211635863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
211735863739SMike Smith  */
211835863739SMike Smith static struct {
211935863739SMike Smith 	int		size;
212035863739SMike Smith 	int		notify;
212135863739SMike Smith } aac_qinfo[] = {
212235863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
212335863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
212435863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
212535863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
212635863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
212735863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
212835863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
212935863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
213035863739SMike Smith };
213135863739SMike Smith 
213235863739SMike Smith /*
2133c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2134c6eafcf2SScott Long  * EBUSY if the queue is full.
213535863739SMike Smith  *
21360b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2137914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2138914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2139c6eafcf2SScott Long  *	 separate queue/notify interface).
214035863739SMike Smith  */
214135863739SMike Smith static int
2142f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
214335863739SMike Smith {
214435863739SMike Smith 	u_int32_t pi, ci;
21459e2e96d8SScott Long 	int error;
2146f6c4dd3fSScott Long 	u_int32_t fib_size;
2147f6c4dd3fSScott Long 	u_int32_t fib_addr;
2148f6c4dd3fSScott Long 
214931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
215036e0bf6eSScott Long 
2151f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2152f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
215335863739SMike Smith 
215435863739SMike Smith 	/* get the producer/consumer indices */
215535863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
215635863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
215735863739SMike Smith 
215835863739SMike Smith 	/* wrap the queue? */
215935863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
216035863739SMike Smith 		pi = 0;
216135863739SMike Smith 
216235863739SMike Smith 	/* check for queue full */
216335863739SMike Smith 	if ((pi + 1) == ci) {
216435863739SMike Smith 		error = EBUSY;
216535863739SMike Smith 		goto out;
216635863739SMike Smith 	}
216735863739SMike Smith 
2168614c22b2SScott Long 	/*
2169614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2170614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2171614c22b2SScott Long 	 */
2172614c22b2SScott Long 	aac_enqueue_busy(cm);
2173614c22b2SScott Long 
217435863739SMike Smith 	/* populate queue entry */
217535863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
217635863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
217735863739SMike Smith 
217835863739SMike Smith 	/* update producer index */
217935863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
218035863739SMike Smith 
218135863739SMike Smith 	/* notify the adapter if we know how */
218235863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
218335863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
218435863739SMike Smith 
218535863739SMike Smith 	error = 0;
218635863739SMike Smith 
218735863739SMike Smith out:
218835863739SMike Smith 	return(error);
218935863739SMike Smith }
219035863739SMike Smith 
219135863739SMike Smith /*
219236e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
219336e0bf6eSScott Long  * success or ENOENT if the queue is empty.
219435863739SMike Smith  */
219535863739SMike Smith static int
2196c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2197c6eafcf2SScott Long 		struct aac_fib **fib_addr)
219835863739SMike Smith {
219935863739SMike Smith 	u_int32_t pi, ci;
2200149af931SScott Long 	u_int32_t fib_index;
22019e2e96d8SScott Long 	int error;
2202f6c4dd3fSScott Long 	int notify;
220335863739SMike Smith 
220431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
220535863739SMike Smith 
220635863739SMike Smith 	/* get the producer/consumer indices */
220735863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
220835863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
220935863739SMike Smith 
221035863739SMike Smith 	/* check for queue empty */
221135863739SMike Smith 	if (ci == pi) {
221235863739SMike Smith 		error = ENOENT;
221335863739SMike Smith 		goto out;
221435863739SMike Smith 	}
221535863739SMike Smith 
22167753acd2SScott Long 	/* wrap the pi so the following test works */
22177753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
22187753acd2SScott Long 		pi = 0;
22197753acd2SScott Long 
2220f6c4dd3fSScott Long 	notify = 0;
2221f6c4dd3fSScott Long 	if (ci == pi + 1)
2222f6c4dd3fSScott Long 		notify++;
2223f6c4dd3fSScott Long 
222435863739SMike Smith 	/* wrap the queue? */
222535863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
222635863739SMike Smith 		ci = 0;
222735863739SMike Smith 
222835863739SMike Smith 	/* fetch the entry */
222935863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2230149af931SScott Long 
2231149af931SScott Long 	switch (queue) {
2232149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2233149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2234149af931SScott Long 		/*
2235149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2236149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2237149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2238149af931SScott Long 		 * Therefore, we have to convert it to an index.
2239149af931SScott Long 		 */
2240149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2241149af931SScott Long 			sizeof(struct aac_fib);
2242149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2243149af931SScott Long 		break;
2244149af931SScott Long 
2245149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2246149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2247149af931SScott Long 	{
2248149af931SScott Long 		struct aac_command *cm;
2249149af931SScott Long 
2250149af931SScott Long 		/*
2251149af931SScott Long 		 * As above, an index is used instead of an actual address.
2252149af931SScott Long 		 * Gotta shift the index to account for the fast response
2253149af931SScott Long 		 * bit.  No other correction is needed since this value was
2254149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2255149af931SScott Long 		 * field.
2256149af931SScott Long 		 */
2257149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22587cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2259149af931SScott Long 		*fib_addr = cm->cm_fib;
226035863739SMike Smith 
2261f30ac74cSScott Long 		/*
2262f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2263149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2264f30ac74cSScott Long 		 */
2265149af931SScott Long 		if (fib_index & 0x01) {
2266f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2267f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2268f30ac74cSScott Long 		}
2269149af931SScott Long 		break;
2270149af931SScott Long 	}
2271149af931SScott Long 	default:
2272149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2273149af931SScott Long 		break;
2274149af931SScott Long 	}
2275149af931SScott Long 
227635863739SMike Smith 	/* update consumer index */
227735863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
227835863739SMike Smith 
227935863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2280f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
228135863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
228235863739SMike Smith 	error = 0;
228335863739SMike Smith 
228435863739SMike Smith out:
228535863739SMike Smith 	return(error);
228635863739SMike Smith }
228735863739SMike Smith 
2288914da7d0SScott Long /*
228936e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
229036e0bf6eSScott Long  */
229136e0bf6eSScott Long static int
229236e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
229336e0bf6eSScott Long {
229436e0bf6eSScott Long 	u_int32_t pi, ci;
22959e2e96d8SScott Long 	int error;
229636e0bf6eSScott Long 	u_int32_t fib_size;
229736e0bf6eSScott Long 	u_int32_t fib_addr;
229836e0bf6eSScott Long 
229931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
230036e0bf6eSScott Long 
230136e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
230236e0bf6eSScott Long 	fib_size = fib->Header.Size;
230336e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
230436e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
230536e0bf6eSScott Long 
230636e0bf6eSScott Long 	/* get the producer/consumer indices */
230736e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
230836e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
230936e0bf6eSScott Long 
231036e0bf6eSScott Long 	/* wrap the queue? */
231136e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
231236e0bf6eSScott Long 		pi = 0;
231336e0bf6eSScott Long 
231436e0bf6eSScott Long 	/* check for queue full */
231536e0bf6eSScott Long 	if ((pi + 1) == ci) {
231636e0bf6eSScott Long 		error = EBUSY;
231736e0bf6eSScott Long 		goto out;
231836e0bf6eSScott Long 	}
231936e0bf6eSScott Long 
232036e0bf6eSScott Long 	/* populate queue entry */
232136e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
232236e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
232336e0bf6eSScott Long 
232436e0bf6eSScott Long 	/* update producer index */
232536e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
232636e0bf6eSScott Long 
232736e0bf6eSScott Long 	/* notify the adapter if we know how */
232836e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
232936e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
233036e0bf6eSScott Long 
233136e0bf6eSScott Long 	error = 0;
233236e0bf6eSScott Long 
233336e0bf6eSScott Long out:
233436e0bf6eSScott Long 	return(error);
233536e0bf6eSScott Long }
233636e0bf6eSScott Long 
2337914da7d0SScott Long /*
23380b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
23390b94a66eSMike Smith  * and complain about them.
23400b94a66eSMike Smith  */
23410b94a66eSMike Smith static void
23420b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
23430b94a66eSMike Smith {
23440b94a66eSMike Smith 	struct aac_command *cm;
23450b94a66eSMike Smith 	time_t deadline;
234615c37be0SScott Long 	int timedout, code;
23470b94a66eSMike Smith 
2348f6c4dd3fSScott Long 	/*
234970545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2350914da7d0SScott Long 	 * only.
2351914da7d0SScott Long 	 */
235215c37be0SScott Long 	timedout = 0;
23532b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23540b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2355f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2356*3e507710SEd Maste 		    && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) {
23570b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2358914da7d0SScott Long 			device_printf(sc->aac_dev,
23595aa4bb5bSEd Maste 			    "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n",
23605aa4bb5bSEd Maste 			    cm, cm->cm_fib->Header.Command,
23615aa4bb5bSEd Maste 			    (int)(time_uptime-cm->cm_timestamp));
23620b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
236315c37be0SScott Long 			timedout++;
23640b94a66eSMike Smith 		}
23650b94a66eSMike Smith 	}
23660b94a66eSMike Smith 
236715c37be0SScott Long 	if (timedout) {
236815c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
236915c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
237015c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
237115c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
237215c37be0SScott Long 		}
237315c37be0SScott Long 	}
23740b94a66eSMike Smith 	return;
23750b94a66eSMike Smith }
23760b94a66eSMike Smith 
2377914da7d0SScott Long /*
2378914da7d0SScott Long  * Interface Function Vectors
2379914da7d0SScott Long  */
238035863739SMike Smith 
2381914da7d0SScott Long /*
238235863739SMike Smith  * Read the current firmware status word.
238335863739SMike Smith  */
238435863739SMike Smith static int
238535863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
238635863739SMike Smith {
238731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
238835863739SMike Smith 
2389ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS));
239035863739SMike Smith }
239135863739SMike Smith 
239235863739SMike Smith static int
239335863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
239435863739SMike Smith {
239531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
239635863739SMike Smith 
23974824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
23984824be88SEd Maste 	    AAC_RX_OMR0 : AAC_RX_FWSTATUS));
239935863739SMike Smith }
240035863739SMike Smith 
2401b3457b51SScott Long static int
24024afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
24034afedc31SScott Long {
240431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24054afedc31SScott Long 
24064824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
24074824be88SEd Maste 	    AAC_RKT_OMR0 : AAC_RKT_FWSTATUS));
24084afedc31SScott Long }
24094afedc31SScott Long 
2410914da7d0SScott Long /*
241135863739SMike Smith  * Notify the controller of a change in a given queue
241235863739SMike Smith  */
241335863739SMike Smith 
241435863739SMike Smith static void
241535863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
241635863739SMike Smith {
241731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241835863739SMike Smith 
2419ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
242035863739SMike Smith }
242135863739SMike Smith 
242235863739SMike Smith static void
242335863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
242435863739SMike Smith {
242531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
242635863739SMike Smith 
2427ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit);
242835863739SMike Smith }
242935863739SMike Smith 
2430b3457b51SScott Long static void
24314afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
24324afedc31SScott Long {
243331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24344afedc31SScott Long 
2435ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit);
24364afedc31SScott Long }
24374afedc31SScott Long 
2438914da7d0SScott Long /*
243935863739SMike Smith  * Get the interrupt reason bits
244035863739SMike Smith  */
244135863739SMike Smith static int
244235863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
244335863739SMike Smith {
244431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
244535863739SMike Smith 
2446ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0));
244735863739SMike Smith }
244835863739SMike Smith 
244935863739SMike Smith static int
245035863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
245135863739SMike Smith {
245231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
245335863739SMike Smith 
2454ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR));
245535863739SMike Smith }
245635863739SMike Smith 
2457b3457b51SScott Long static int
24584afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
24594afedc31SScott Long {
246031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24614afedc31SScott Long 
2462ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR));
24634afedc31SScott Long }
24644afedc31SScott Long 
2465914da7d0SScott Long /*
246635863739SMike Smith  * Clear some interrupt reason bits
246735863739SMike Smith  */
246835863739SMike Smith static void
246935863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
247035863739SMike Smith {
247131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
247235863739SMike Smith 
2473ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
247435863739SMike Smith }
247535863739SMike Smith 
247635863739SMike Smith static void
247735863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
247835863739SMike Smith {
247931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
248035863739SMike Smith 
2481ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask);
248235863739SMike Smith }
248335863739SMike Smith 
2484b3457b51SScott Long static void
24854afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
24864afedc31SScott Long {
248731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24884afedc31SScott Long 
2489ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask);
24904afedc31SScott Long }
24914afedc31SScott Long 
2492914da7d0SScott Long /*
249335863739SMike Smith  * Populate the mailbox and set the command word
249435863739SMike Smith  */
249535863739SMike Smith static void
249635863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
249735863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249835863739SMike Smith {
249931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
250035863739SMike Smith 
2501ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command);
2502ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2503ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2504ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2505ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
250635863739SMike Smith }
250735863739SMike Smith 
250835863739SMike Smith static void
250935863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
251035863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
251135863739SMike Smith {
251231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
251335863739SMike Smith 
2514ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command);
2515ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2516ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2517ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2518ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
251935863739SMike Smith }
252035863739SMike Smith 
2521b3457b51SScott Long static void
25224afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25234afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
25244afedc31SScott Long {
252531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25264afedc31SScott Long 
2527ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command);
2528ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2529ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2530ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2531ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
25324afedc31SScott Long }
25334afedc31SScott Long 
2534914da7d0SScott Long /*
253535863739SMike Smith  * Fetch the immediate command status word
253635863739SMike Smith  */
253735863739SMike Smith static int
2538a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
253935863739SMike Smith {
254031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
254135863739SMike Smith 
2542ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
254335863739SMike Smith }
254435863739SMike Smith 
254535863739SMike Smith static int
2546a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
254735863739SMike Smith {
254831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
254935863739SMike Smith 
2550ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
255135863739SMike Smith }
255235863739SMike Smith 
2553b3457b51SScott Long static int
25544afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
25554afedc31SScott Long {
255631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25574afedc31SScott Long 
2558ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
25594afedc31SScott Long }
25604afedc31SScott Long 
2561914da7d0SScott Long /*
256235863739SMike Smith  * Set/clear interrupt masks
256335863739SMike Smith  */
256435863739SMike Smith static void
256535863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
256635863739SMike Smith {
256731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
256835863739SMike Smith 
256935863739SMike Smith 	if (enable) {
2570ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
257135863739SMike Smith 	} else {
2572ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
257335863739SMike Smith 	}
257435863739SMike Smith }
257535863739SMike Smith 
257635863739SMike Smith static void
257735863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
257835863739SMike Smith {
257931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
258035863739SMike Smith 
258135863739SMike Smith 	if (enable) {
25827cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2583ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
25847cb209f5SScott Long 		else
2585ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
258635863739SMike Smith 	} else {
2587ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0);
258835863739SMike Smith 	}
258935863739SMike Smith }
259035863739SMike Smith 
2591b3457b51SScott Long static void
25924afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
25934afedc31SScott Long {
259431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
25954afedc31SScott Long 
25964afedc31SScott Long 	if (enable) {
25977cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2598ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
25997cb209f5SScott Long 		else
2600ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
26014afedc31SScott Long 	} else {
2602ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0);
26034afedc31SScott Long 	}
26044afedc31SScott Long }
26054afedc31SScott Long 
2606914da7d0SScott Long /*
26077cb209f5SScott Long  * New comm. interface: Send command functions
26087cb209f5SScott Long  */
26097cb209f5SScott Long static int
26107cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
26117cb209f5SScott Long {
26127cb209f5SScott Long 	u_int32_t index, device;
26137cb209f5SScott Long 
261431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
26157cb209f5SScott Long 
2616ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
26177cb209f5SScott Long 	if (index == 0xffffffffL)
2618ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
26197cb209f5SScott Long 	if (index == 0xffffffffL)
26207cb209f5SScott Long 		return index;
26217cb209f5SScott Long 	aac_enqueue_busy(cm);
26227cb209f5SScott Long 	device = index;
2623ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26247cb209f5SScott Long 	device += 4;
2625ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26267cb209f5SScott Long 	device += 4;
2627ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2628ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index);
26297cb209f5SScott Long 	return 0;
26307cb209f5SScott Long }
26317cb209f5SScott Long 
26327cb209f5SScott Long static int
26337cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
26347cb209f5SScott Long {
26357cb209f5SScott Long 	u_int32_t index, device;
26367cb209f5SScott Long 
263731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
26387cb209f5SScott Long 
2639ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
26407cb209f5SScott Long 	if (index == 0xffffffffL)
2641ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
26427cb209f5SScott Long 	if (index == 0xffffffffL)
26437cb209f5SScott Long 		return index;
26447cb209f5SScott Long 	aac_enqueue_busy(cm);
26457cb209f5SScott Long 	device = index;
2646ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26477cb209f5SScott Long 	device += 4;
2648ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26497cb209f5SScott Long 	device += 4;
2650ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2651ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index);
26527cb209f5SScott Long 	return 0;
26537cb209f5SScott Long }
26547cb209f5SScott Long 
26557cb209f5SScott Long /*
26567cb209f5SScott Long  * New comm. interface: get, set outbound queue index
26577cb209f5SScott Long  */
26587cb209f5SScott Long static int
26597cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
26607cb209f5SScott Long {
266131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26627cb209f5SScott Long 
2663ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE));
26647cb209f5SScott Long }
26657cb209f5SScott Long 
26667cb209f5SScott Long static int
26677cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
26687cb209f5SScott Long {
266931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26707cb209f5SScott Long 
2671ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE));
26727cb209f5SScott Long }
26737cb209f5SScott Long 
26747cb209f5SScott Long static void
26757cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
26767cb209f5SScott Long {
267731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26787cb209f5SScott Long 
2679ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index);
26807cb209f5SScott Long }
26817cb209f5SScott Long 
26827cb209f5SScott Long static void
26837cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
26847cb209f5SScott Long {
268531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26867cb209f5SScott Long 
2687ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index);
26887cb209f5SScott Long }
26897cb209f5SScott Long 
26907cb209f5SScott Long /*
2691914da7d0SScott Long  * Debugging and Diagnostics
2692914da7d0SScott Long  */
269335863739SMike Smith 
2694914da7d0SScott Long /*
269535863739SMike Smith  * Print some information about the controller.
269635863739SMike Smith  */
269735863739SMike Smith static void
269835863739SMike Smith aac_describe_controller(struct aac_softc *sc)
269935863739SMike Smith {
2700cbfd045bSScott Long 	struct aac_fib *fib;
270135863739SMike Smith 	struct aac_adapter_info	*info;
27027ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
270335863739SMike Smith 
270431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
270535863739SMike Smith 
270681b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
270703b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2708cbfd045bSScott Long 
2709cbfd045bSScott Long 	fib->data[0] = 0;
2710cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
271135863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2712fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
271381b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
271435863739SMike Smith 		return;
271535863739SMike Smith 	}
271635863739SMike Smith 
2717bd971c49SScott Long 	/* save the kernel revision structure for later use */
2718bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2719bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2720bd971c49SScott Long 
2721bd971c49SScott Long 	if (bootverbose) {
2722b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2723b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2724c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2725b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2726b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2727b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2728914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2729914da7d0SScott Long 		    info->batteryPlatform));
273035863739SMike Smith 
2731bd971c49SScott Long 		device_printf(sc->aac_dev,
2732bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
273335863739SMike Smith 		    info->KernelRevision.external.comp.major,
273435863739SMike Smith 		    info->KernelRevision.external.comp.minor,
273535863739SMike Smith 		    info->KernelRevision.external.comp.dash,
273636e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
273736e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2738fe3cb0e1SScott Long 
2739a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2740a6d35632SScott Long 			      sc->supported_options,
2741a6d35632SScott Long 			      "\20"
2742a6d35632SScott Long 			      "\1SNAPSHOT"
2743a6d35632SScott Long 			      "\2CLUSTERS"
2744a6d35632SScott Long 			      "\3WCACHE"
2745a6d35632SScott Long 			      "\4DATA64"
2746a6d35632SScott Long 			      "\5HOSTTIME"
2747a6d35632SScott Long 			      "\6RAID50"
2748a6d35632SScott Long 			      "\7WINDOW4GB"
2749a6d35632SScott Long 			      "\10SCSIUPGD"
2750a6d35632SScott Long 			      "\11SOFTERR"
2751a6d35632SScott Long 			      "\12NORECOND"
2752a6d35632SScott Long 			      "\13SGMAP64"
2753a6d35632SScott Long 			      "\14ALARM"
27547cb209f5SScott Long 			      "\15NONDASD"
27557cb209f5SScott Long 			      "\16SCSIMGT"
27567cb209f5SScott Long 			      "\17RAIDSCSI"
27577cb209f5SScott Long 			      "\21ADPTINFO"
27587cb209f5SScott Long 			      "\22NEWCOMM"
27597cb209f5SScott Long 			      "\23ARRAY64BIT"
27607cb209f5SScott Long 			      "\24HEATSENSOR");
2761a6d35632SScott Long 	}
276255aa1136SEd Maste 
276355aa1136SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
276455aa1136SEd Maste 		fib->data[0] = 0;
276555aa1136SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
276655aa1136SEd Maste 			device_printf(sc->aac_dev,
276755aa1136SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
276855aa1136SEd Maste 		else
276955aa1136SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
277055aa1136SEd Maste 			    &fib->data[0])->AdapterTypeText;
277155aa1136SEd Maste 	}
277255aa1136SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
277355aa1136SEd Maste 		adapter_type,
27748e7e6335SEd Maste 		AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION,
27758e7e6335SEd Maste 		AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD);
277655aa1136SEd Maste 
2777bd971c49SScott Long 	aac_release_sync_fib(sc);
277881b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
277935863739SMike Smith }
278035863739SMike Smith 
2781914da7d0SScott Long /*
278235863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
278335863739SMike Smith  * same.
278435863739SMike Smith  */
278535863739SMike Smith static char *
278635863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
278735863739SMike Smith {
278835863739SMike Smith 	int i;
278935863739SMike Smith 
279035863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
279135863739SMike Smith 		if (table[i].code == code)
279235863739SMike Smith 			return(table[i].string);
279335863739SMike Smith 	return(table[i + 1].string);
279435863739SMike Smith }
279535863739SMike Smith 
2796914da7d0SScott Long /*
2797914da7d0SScott Long  * Management Interface
2798914da7d0SScott Long  */
279935863739SMike Smith 
280035863739SMike Smith static int
280100b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
280235863739SMike Smith {
2803914da7d0SScott Long 	struct aac_softc *sc;
280435863739SMike Smith 
2805914da7d0SScott Long 	sc = dev->si_drv1;
280631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2807a723a548SEd Maste 	sc->aac_open_cnt++;
280835863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
280935863739SMike Smith 
281035863739SMike Smith 	return 0;
281135863739SMike Smith }
281235863739SMike Smith 
281335863739SMike Smith static int
281400b4e54aSWarner Losh aac_close(struct cdev *dev, int flags, int fmt, struct thread *td)
281535863739SMike Smith {
2816914da7d0SScott Long 	struct aac_softc *sc;
281735863739SMike Smith 
2818914da7d0SScott Long 	sc = dev->si_drv1;
281931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2820a723a548SEd Maste 	sc->aac_open_cnt--;
282135863739SMike Smith 	/* Mark this unit as no longer open  */
2822a723a548SEd Maste 	if (sc->aac_open_cnt == 0)
282335863739SMike Smith 		sc->aac_state &= ~AAC_STATE_OPEN;
282435863739SMike Smith 
282535863739SMike Smith 	return 0;
282635863739SMike Smith }
282735863739SMike Smith 
282835863739SMike Smith static int
282900b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
283035863739SMike Smith {
2831914da7d0SScott Long 	union aac_statrequest *as;
2832914da7d0SScott Long 	struct aac_softc *sc;
28330b94a66eSMike Smith 	int error = 0;
283435863739SMike Smith 
2835914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2836914da7d0SScott Long 	sc = dev->si_drv1;
283731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2838914da7d0SScott Long 
283935863739SMike Smith 	switch (cmd) {
28400b94a66eSMike Smith 	case AACIO_STATS:
28410b94a66eSMike Smith 		switch (as->as_item) {
28420b94a66eSMike Smith 		case AACQ_FREE:
28430b94a66eSMike Smith 		case AACQ_BIO:
28440b94a66eSMike Smith 		case AACQ_READY:
28450b94a66eSMike Smith 		case AACQ_BUSY:
2846c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2847c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
28480b94a66eSMike Smith 			break;
28490b94a66eSMike Smith 		default:
28500b94a66eSMike Smith 			error = ENOENT;
28510b94a66eSMike Smith 			break;
28520b94a66eSMike Smith 		}
28530b94a66eSMike Smith 	break;
28540b94a66eSMike Smith 
285535863739SMike Smith 	case FSACTL_SENDFIB:
2856f355c0e0SEd Maste 	case FSACTL_SEND_LARGE_FIB:
2857fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2858fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
2859f355c0e0SEd Maste 	case FSACTL_LNX_SEND_LARGE_FIB:
286031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
286135863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
286235863739SMike Smith 		break;
2863f355c0e0SEd Maste 	case FSACTL_SEND_RAW_SRB:
2864f355c0e0SEd Maste 		arg = *(caddr_t*)arg;
2865f355c0e0SEd Maste 	case FSACTL_LNX_SEND_RAW_SRB:
286631a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2867f355c0e0SEd Maste 		error = aac_ioctl_send_raw_srb(sc, arg);
2868f355c0e0SEd Maste 		break;
286935863739SMike Smith 	case FSACTL_AIF_THREAD:
2870fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
287131a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
287235863739SMike Smith 		error = EINVAL;
287335863739SMike Smith 		break;
287435863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2875fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2876fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
287731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2878a723a548SEd Maste 		error = aac_open_aif(sc, arg);
287935863739SMike Smith 		break;
288035863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2881fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2882fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
288331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2884fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
288535863739SMike Smith 		break;
288635863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2887a723a548SEd Maste 		arg = *(caddr_t*)arg;
2888fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
288931a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2890a723a548SEd Maste 		error = aac_close_aif(sc, arg);
289135863739SMike Smith 		break;
289235863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2893fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2894fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
289531a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
2896fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
289735863739SMike Smith 		break;
289836e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
289936e0bf6eSScott Long 		arg = *(caddr_t*)arg;
290036e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
290131a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
290236e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
290336e0bf6eSScott Long 		break;
290436e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
290536e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2906914da7d0SScott Long 		/*
2907914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2908914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2909914da7d0SScott Long 		 * controller
2910914da7d0SScott Long 		 */
291136e0bf6eSScott Long 		error = 0;
291236e0bf6eSScott Long 		break;
29137cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
29147cb209f5SScott Long 		arg = *(caddr_t*)arg;
29157cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
291631a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
29177cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
29187cb209f5SScott Long 		break;
29196d307336SEd Maste 	case FSACTL_GET_FEATURES:
29206d307336SEd Maste 		arg = *(caddr_t*)arg;
29216d307336SEd Maste 	case FSACTL_LNX_GET_FEATURES:
29226d307336SEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
29236d307336SEd Maste 		error = aac_supported_features(sc, arg);
29246d307336SEd Maste 		break;
292535863739SMike Smith 	default:
292631a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
292735863739SMike Smith 		error = EINVAL;
292835863739SMike Smith 		break;
292935863739SMike Smith 	}
293035863739SMike Smith 	return(error);
293135863739SMike Smith }
293235863739SMike Smith 
2933b3457b51SScott Long static int
293400b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td)
2935b3457b51SScott Long {
2936b3457b51SScott Long 	struct aac_softc *sc;
2937ef0b687cSEd Maste 	struct aac_fib_context *ctx;
2938b3457b51SScott Long 	int revents;
2939b3457b51SScott Long 
2940b3457b51SScott Long 	sc = dev->si_drv1;
2941b3457b51SScott Long 	revents = 0;
2942b3457b51SScott Long 
2943bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2944b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2945ef0b687cSEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
2946ef0b687cSEd Maste 			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
2947b3457b51SScott Long 				revents |= poll_events & (POLLIN | POLLRDNORM);
2948ef0b687cSEd Maste 				break;
2949ef0b687cSEd Maste 			}
2950ef0b687cSEd Maste 		}
2951b3457b51SScott Long 	}
2952bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2953b3457b51SScott Long 
2954b3457b51SScott Long 	if (revents == 0) {
2955b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2956b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2957b3457b51SScott Long 	}
2958b3457b51SScott Long 
2959b3457b51SScott Long 	return (revents);
2960b3457b51SScott Long }
2961b3457b51SScott Long 
29627cb209f5SScott Long static void
29637cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
29647cb209f5SScott Long {
29657cb209f5SScott Long 
29667cb209f5SScott Long 	switch (event->ev_type) {
29677cb209f5SScott Long 	case AAC_EVENT_CMFREE:
29680c40d5beSEd Maste 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
29691a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
29707cb209f5SScott Long 			aac_add_event(sc, event);
29717cb209f5SScott Long 			return;
29727cb209f5SScott Long 		}
29737cb209f5SScott Long 		free(event, M_AACBUF);
29748eeb2ca6SScott Long 		wakeup(arg);
29757cb209f5SScott Long 		break;
29767cb209f5SScott Long 	default:
29777cb209f5SScott Long 		break;
29787cb209f5SScott Long 	}
29797cb209f5SScott Long }
29807cb209f5SScott Long 
2981914da7d0SScott Long /*
298235863739SMike Smith  * Send a FIB supplied from userspace
298335863739SMike Smith  */
298435863739SMike Smith static int
298535863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
298635863739SMike Smith {
298735863739SMike Smith 	struct aac_command *cm;
298835863739SMike Smith 	int size, error;
298935863739SMike Smith 
299031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
299135863739SMike Smith 
299235863739SMike Smith 	cm = NULL;
299335863739SMike Smith 
299435863739SMike Smith 	/*
299535863739SMike Smith 	 * Get a command
299635863739SMike Smith 	 */
2997bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
299835863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
29997cb209f5SScott Long 		struct aac_event *event;
30007cb209f5SScott Long 
30017cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
30027cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
30037cb209f5SScott Long 		if (event == NULL) {
300435863739SMike Smith 			error = EBUSY;
3005f16627aaSEd Maste 			mtx_unlock(&sc->aac_io_lock);
300635863739SMike Smith 			goto out;
300735863739SMike Smith 		}
30087cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
30097cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
30107cb209f5SScott Long 		event->ev_arg = &cm;
30117cb209f5SScott Long 		aac_add_event(sc, event);
30128eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
30137cb209f5SScott Long 	}
301493cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
301535863739SMike Smith 
301635863739SMike Smith 	/*
301735863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
301835863739SMike Smith 	 */
3019914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3020914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
302135863739SMike Smith 		goto out;
302235863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3023f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3024f355c0e0SEd Maste 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3025f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3026f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
302735863739SMike Smith 	}
302835863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
302935863739SMike Smith 		goto out;
303035863739SMike Smith 	cm->cm_fib->Header.Size = size;
30312b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
303235863739SMike Smith 
303335863739SMike Smith 	/*
303435863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
303535863739SMike Smith 	 */
303693cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3037f16627aaSEd Maste 	error = aac_wait_command(cm);
3038f16627aaSEd Maste 	mtx_unlock(&sc->aac_io_lock);
3039f16627aaSEd Maste 	if (error != 0) {
304070545d1aSScott Long 		device_printf(sc->aac_dev,
304170545d1aSScott Long 			      "aac_wait_command return %d\n", error);
304235863739SMike Smith 		goto out;
3043b3457b51SScott Long 	}
304435863739SMike Smith 
304535863739SMike Smith 	/*
304635863739SMike Smith 	 * Copy the FIB and data back out to the caller.
304735863739SMike Smith 	 */
304835863739SMike Smith 	size = cm->cm_fib->Header.Size;
3049f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3050f355c0e0SEd Maste 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3051f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3052f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
305335863739SMike Smith 	}
305435863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
305535863739SMike Smith 
305635863739SMike Smith out:
3057f6c4dd3fSScott Long 	if (cm != NULL) {
3058f16627aaSEd Maste 		mtx_lock(&sc->aac_io_lock);
305935863739SMike Smith 		aac_release_command(cm);
3060bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
3061f16627aaSEd Maste 	}
306235863739SMike Smith 	return(error);
306335863739SMike Smith }
306435863739SMike Smith 
3065914da7d0SScott Long /*
3066f355c0e0SEd Maste  * Send a passthrough FIB supplied from userspace
3067f355c0e0SEd Maste  */
3068f355c0e0SEd Maste static int
3069f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3070f355c0e0SEd Maste {
30717b90e5ecSAttilio Rao 	struct aac_command *cm;
30727b90e5ecSAttilio Rao 	struct aac_event *event;
30737b90e5ecSAttilio Rao 	struct aac_fib *fib;
30747b90e5ecSAttilio Rao 	struct aac_srb *srbcmd, *user_srb;
30757b90e5ecSAttilio Rao 	struct aac_sg_entry *sge;
30767b90e5ecSAttilio Rao 	struct aac_sg_entry64 *sge64;
30777b90e5ecSAttilio Rao 	void *srb_sg_address, *ureply;
30787b90e5ecSAttilio Rao 	uint32_t fibsize, srb_sg_bytecount;
30797b90e5ecSAttilio Rao 	int error, transfer_data;
30807b90e5ecSAttilio Rao 
30817b90e5ecSAttilio Rao 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
30827b90e5ecSAttilio Rao 
30837b90e5ecSAttilio Rao 	cm = NULL;
30847b90e5ecSAttilio Rao 	transfer_data = 0;
30857b90e5ecSAttilio Rao 	fibsize = 0;
30867b90e5ecSAttilio Rao 	user_srb = (struct aac_srb *)arg;
30877b90e5ecSAttilio Rao 
30887b90e5ecSAttilio Rao 	mtx_lock(&sc->aac_io_lock);
30897b90e5ecSAttilio Rao 	if (aac_alloc_command(sc, &cm)) {
30907b90e5ecSAttilio Rao 		 event = malloc(sizeof(struct aac_event), M_AACBUF,
30917b90e5ecSAttilio Rao 		    M_NOWAIT | M_ZERO);
30927b90e5ecSAttilio Rao 		if (event == NULL) {
30937b90e5ecSAttilio Rao 			error = EBUSY;
30947b90e5ecSAttilio Rao 			mtx_unlock(&sc->aac_io_lock);
30957b90e5ecSAttilio Rao 			goto out;
30967b90e5ecSAttilio Rao 		}
30977b90e5ecSAttilio Rao 		event->ev_type = AAC_EVENT_CMFREE;
30987b90e5ecSAttilio Rao 		event->ev_callback = aac_ioctl_event;
30997b90e5ecSAttilio Rao 		event->ev_arg = &cm;
31007b90e5ecSAttilio Rao 		aac_add_event(sc, event);
31017b90e5ecSAttilio Rao 		msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0);
31027b90e5ecSAttilio Rao 	}
31037b90e5ecSAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
31047b90e5ecSAttilio Rao 
31057b90e5ecSAttilio Rao 	cm->cm_data = NULL;
31067b90e5ecSAttilio Rao 	fib = cm->cm_fib;
31077b90e5ecSAttilio Rao 	srbcmd = (struct aac_srb *)fib->data;
31087b90e5ecSAttilio Rao 	error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t));
31097b90e5ecSAttilio Rao 	if (error != 0)
31107b90e5ecSAttilio Rao 		goto out;
31117b90e5ecSAttilio Rao 	if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) {
31127b90e5ecSAttilio Rao 		error = EINVAL;
31137b90e5ecSAttilio Rao 		goto out;
31147b90e5ecSAttilio Rao 	}
31157b90e5ecSAttilio Rao 	error = copyin(user_srb, srbcmd, fibsize);
31167b90e5ecSAttilio Rao 	if (error != 0)
31177b90e5ecSAttilio Rao 		goto out;
31187b90e5ecSAttilio Rao 	srbcmd->function = 0;
31197b90e5ecSAttilio Rao 	srbcmd->retry_limit = 0;
31207b90e5ecSAttilio Rao 	if (srbcmd->sg_map.SgCount > 1) {
31217b90e5ecSAttilio Rao 		error = EINVAL;
31227b90e5ecSAttilio Rao 		goto out;
31237b90e5ecSAttilio Rao 	}
31247b90e5ecSAttilio Rao 
31257b90e5ecSAttilio Rao 	/* Retrieve correct SG entries. */
31267b90e5ecSAttilio Rao 	if (fibsize == (sizeof(struct aac_srb) +
31277b90e5ecSAttilio Rao 	    srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) {
31287b90e5ecSAttilio Rao 		sge = srbcmd->sg_map.SgEntry;
31297b90e5ecSAttilio Rao 		sge64 = NULL;
31307b90e5ecSAttilio Rao 		srb_sg_bytecount = sge->SgByteCount;
31316eafba26SAttilio Rao 		srb_sg_address = (void *)(uintptr_t)sge->SgAddress;
31327b90e5ecSAttilio Rao 	}
31337b90e5ecSAttilio Rao #ifdef __amd64__
31347b90e5ecSAttilio Rao 	else if (fibsize == (sizeof(struct aac_srb) +
31357b90e5ecSAttilio Rao 	    srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) {
31367b90e5ecSAttilio Rao 		sge = NULL;
31377b90e5ecSAttilio Rao 		sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry;
31387b90e5ecSAttilio Rao 		srb_sg_bytecount = sge64->SgByteCount;
31397b90e5ecSAttilio Rao 		srb_sg_address = (void *)sge64->SgAddress;
31407b90e5ecSAttilio Rao 		if (sge64->SgAddress > 0xffffffffull &&
31417b90e5ecSAttilio Rao 		    (sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
31427b90e5ecSAttilio Rao 			error = EINVAL;
31437b90e5ecSAttilio Rao 			goto out;
31447b90e5ecSAttilio Rao 		}
31457b90e5ecSAttilio Rao 	}
31467b90e5ecSAttilio Rao #endif
31477b90e5ecSAttilio Rao 	else {
31487b90e5ecSAttilio Rao 		error = EINVAL;
31497b90e5ecSAttilio Rao 		goto out;
31507b90e5ecSAttilio Rao 	}
31517b90e5ecSAttilio Rao 	ureply = (char *)arg + fibsize;
31527b90e5ecSAttilio Rao 	srbcmd->data_len = srb_sg_bytecount;
31537b90e5ecSAttilio Rao 	if (srbcmd->sg_map.SgCount == 1)
31547b90e5ecSAttilio Rao 		transfer_data = 1;
31557b90e5ecSAttilio Rao 
31567b90e5ecSAttilio Rao 	cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map;
31577b90e5ecSAttilio Rao 	if (transfer_data) {
31587b90e5ecSAttilio Rao 		cm->cm_datalen = srb_sg_bytecount;
31597b90e5ecSAttilio Rao 		cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT);
31607b90e5ecSAttilio Rao 		if (cm->cm_data == NULL) {
31617b90e5ecSAttilio Rao 			error = ENOMEM;
31627b90e5ecSAttilio Rao 			goto out;
31637b90e5ecSAttilio Rao 		}
31647b90e5ecSAttilio Rao 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)
31657b90e5ecSAttilio Rao 			cm->cm_flags |= AAC_CMD_DATAIN;
31667b90e5ecSAttilio Rao 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) {
31677b90e5ecSAttilio Rao 			cm->cm_flags |= AAC_CMD_DATAOUT;
31687b90e5ecSAttilio Rao 			error = copyin(srb_sg_address, cm->cm_data,
31697b90e5ecSAttilio Rao 			    cm->cm_datalen);
31707b90e5ecSAttilio Rao 			if (error != 0)
31717b90e5ecSAttilio Rao 				goto out;
31727b90e5ecSAttilio Rao 		}
31737b90e5ecSAttilio Rao 	}
31747b90e5ecSAttilio Rao 
31757b90e5ecSAttilio Rao 	fib->Header.Size = sizeof(struct aac_fib_header) +
31767b90e5ecSAttilio Rao 	    sizeof(struct aac_srb);
31777b90e5ecSAttilio Rao 	fib->Header.XferState =
31787b90e5ecSAttilio Rao 	    AAC_FIBSTATE_HOSTOWNED   |
31797b90e5ecSAttilio Rao 	    AAC_FIBSTATE_INITIALISED |
31807b90e5ecSAttilio Rao 	    AAC_FIBSTATE_EMPTY       |
31817b90e5ecSAttilio Rao 	    AAC_FIBSTATE_FROMHOST    |
31827b90e5ecSAttilio Rao 	    AAC_FIBSTATE_REXPECTED   |
31837b90e5ecSAttilio Rao 	    AAC_FIBSTATE_NORM        |
31847b90e5ecSAttilio Rao 	    AAC_FIBSTATE_ASYNC       |
31857b90e5ecSAttilio Rao 	    AAC_FIBSTATE_FAST_RESPONSE;
31867b90e5ecSAttilio Rao 	fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ?
31877b90e5ecSAttilio Rao 	    ScsiPortCommandU64 : ScsiPortCommand;
31887b90e5ecSAttilio Rao 
31897b90e5ecSAttilio Rao 	mtx_lock(&sc->aac_io_lock);
31907b90e5ecSAttilio Rao 	aac_wait_command(cm);
31917b90e5ecSAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
31927b90e5ecSAttilio Rao 
31937b90e5ecSAttilio Rao 	if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) {
31947b90e5ecSAttilio Rao 		error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen);
31957b90e5ecSAttilio Rao 		if (error != 0)
31967b90e5ecSAttilio Rao 			goto out;
31977b90e5ecSAttilio Rao 	}
31987b90e5ecSAttilio Rao 	error = copyout(fib->data, ureply, sizeof(struct aac_srb_response));
31997b90e5ecSAttilio Rao out:
32007b90e5ecSAttilio Rao 	if (cm != NULL) {
32017b90e5ecSAttilio Rao 		if (cm->cm_data != NULL)
32027b90e5ecSAttilio Rao 			free(cm->cm_data, M_AACBUF);
32037b90e5ecSAttilio Rao 		mtx_lock(&sc->aac_io_lock);
32047b90e5ecSAttilio Rao 		aac_release_command(cm);
32057b90e5ecSAttilio Rao 		mtx_unlock(&sc->aac_io_lock);
32067b90e5ecSAttilio Rao 	}
32077b90e5ecSAttilio Rao 	return(error);
3208f355c0e0SEd Maste }
3209f355c0e0SEd Maste 
3210f355c0e0SEd Maste /*
321135863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
321236e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
321335863739SMike Smith  */
321435863739SMike Smith static void
321536e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
321635863739SMike Smith {
321736e0bf6eSScott Long 	struct aac_aif_command *aif;
321836e0bf6eSScott Long 	struct aac_container *co, *co_next;
3219a723a548SEd Maste 	struct aac_fib_context *ctx;
322004f4d586SEd Maste 	struct aac_mntinforesp *mir;
3221a723a548SEd Maste 	int next, current, found;
3222795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
322335863739SMike Smith 
322431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
322535863739SMike Smith 
322636e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
322736e0bf6eSScott Long 	aac_print_aif(sc, aif);
322836e0bf6eSScott Long 
322936e0bf6eSScott Long 	/* Is it an event that we should care about? */
323036e0bf6eSScott Long 	switch (aif->command) {
323136e0bf6eSScott Long 	case AifCmdEventNotify:
323236e0bf6eSScott Long 		switch (aif->data.EN.type) {
323336e0bf6eSScott Long 		case AifEnAddContainer:
323436e0bf6eSScott Long 		case AifEnDeleteContainer:
323536e0bf6eSScott Long 			/*
3236914da7d0SScott Long 			 * A container was added or deleted, but the message
3237914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3238914da7d0SScott Long 			 * containers and sort things out.
323936e0bf6eSScott Long 			 */
324003b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
324136e0bf6eSScott Long 			do {
324236e0bf6eSScott Long 				/*
3243914da7d0SScott Long 				 * Ask the controller for its containers one at
3244914da7d0SScott Long 				 * a time.
3245914da7d0SScott Long 				 * XXX What if the controller's list changes
3246914da7d0SScott Long 				 * midway through this enumaration?
324736e0bf6eSScott Long 				 * XXX This should be done async.
324836e0bf6eSScott Long 				 */
324904f4d586SEd Maste 				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
325036e0bf6eSScott Long 					continue;
325104f4d586SEd Maste 				if (i == 0)
3252795d7dc0SScott Long 					count = mir->MntRespCount;
325336e0bf6eSScott Long 				/*
3254914da7d0SScott Long 				 * Check the container against our list.
3255914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3256914da7d0SScott Long 				 * previous run.
325736e0bf6eSScott Long 				 */
3258cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3259cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
326036e0bf6eSScott Long 					found = 0;
3261914da7d0SScott Long 					TAILQ_FOREACH(co,
3262914da7d0SScott Long 						      &sc->aac_container_tqh,
3263914da7d0SScott Long 						      co_link) {
326436e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3265cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
326636e0bf6eSScott Long 							co->co_found = 1;
326736e0bf6eSScott Long 							found = 1;
326836e0bf6eSScott Long 							break;
326936e0bf6eSScott Long 						}
327036e0bf6eSScott Long 					}
3271914da7d0SScott Long 					/*
3272914da7d0SScott Long 					 * If the container matched, continue
3273914da7d0SScott Long 					 * in the list.
3274914da7d0SScott Long 					 */
327536e0bf6eSScott Long 					if (found) {
327636e0bf6eSScott Long 						i++;
327736e0bf6eSScott Long 						continue;
327836e0bf6eSScott Long 					}
327936e0bf6eSScott Long 
328036e0bf6eSScott Long 					/*
3281914da7d0SScott Long 					 * This is a new container.  Do all the
328270545d1aSScott Long 					 * appropriate things to set it up.
328370545d1aSScott Long 					 */
3284cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
328536e0bf6eSScott Long 					added = 1;
328636e0bf6eSScott Long 				}
328736e0bf6eSScott Long 				i++;
3288795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3289cbfd045bSScott Long 			aac_release_sync_fib(sc);
329036e0bf6eSScott Long 
329136e0bf6eSScott Long 			/*
3292914da7d0SScott Long 			 * Go through our list of containers and see which ones
3293914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3294914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3295914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3296914da7d0SScott Long 			 * the co->co_found field.
329736e0bf6eSScott Long 			 */
329836e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
329936e0bf6eSScott Long 			while (co != NULL) {
330036e0bf6eSScott Long 				if (co->co_found == 0) {
33017cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
3302a56fe095SJohn Baldwin 					mtx_lock(&Giant);
3303914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3304914da7d0SScott Long 							    co->co_disk);
3305a56fe095SJohn Baldwin 					mtx_unlock(&Giant);
33067cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
330736e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3308bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3309914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3310914da7d0SScott Long 						     co_link);
3311bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3312ba1d57e7SScott Long 					free(co, M_AACBUF);
331336e0bf6eSScott Long 					co = co_next;
331436e0bf6eSScott Long 				} else {
331536e0bf6eSScott Long 					co->co_found = 0;
331636e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
331736e0bf6eSScott Long 				}
331836e0bf6eSScott Long 			}
331936e0bf6eSScott Long 
332036e0bf6eSScott Long 			/* Attach the newly created containers */
33217cb209f5SScott Long 			if (added) {
33227cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
3323a56fe095SJohn Baldwin 				mtx_lock(&Giant);
332436e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
3325a56fe095SJohn Baldwin 				mtx_unlock(&Giant);
33267cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
33277cb209f5SScott Long 			}
332836e0bf6eSScott Long 
332936e0bf6eSScott Long 			break;
333036e0bf6eSScott Long 
333136e0bf6eSScott Long 		default:
333236e0bf6eSScott Long 			break;
333336e0bf6eSScott Long 		}
333436e0bf6eSScott Long 
333536e0bf6eSScott Long 	default:
333636e0bf6eSScott Long 		break;
333736e0bf6eSScott Long 	}
333836e0bf6eSScott Long 
333936e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3340bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3341a723a548SEd Maste 	current = sc->aifq_idx;
3342a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3343a723a548SEd Maste 	if (next == 0)
3344a723a548SEd Maste 		sc->aifq_filled = 1;
3345a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3346a723a548SEd Maste 	/* modify AIF contexts */
3347a723a548SEd Maste 	if (sc->aifq_filled) {
3348a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3349a723a548SEd Maste 			if (next == ctx->ctx_idx)
3350a723a548SEd Maste 				ctx->ctx_wrap = 1;
3351a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3352a723a548SEd Maste 				ctx->ctx_idx = next;
3353a723a548SEd Maste 		}
3354a723a548SEd Maste 	}
3355a723a548SEd Maste 	sc->aifq_idx = next;
3356b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
335735863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
335835863739SMike Smith 		wakeup(sc->aac_aifq);
3359b3457b51SScott Long 	/* Wakeup any poll()ers */
3360512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3361bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
336236e0bf6eSScott Long 
336336e0bf6eSScott Long 	return;
336435863739SMike Smith }
336535863739SMike Smith 
3366914da7d0SScott Long /*
33670b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
336836e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
336936e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
337036e0bf6eSScott Long  * returning what the card reported.
337135863739SMike Smith  */
337235863739SMike Smith static int
3373fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
337435863739SMike Smith {
337535863739SMike Smith 	struct aac_rev_check rev_check;
337635863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
337735863739SMike Smith 	int error = 0;
337835863739SMike Smith 
337931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
338035863739SMike Smith 
338135863739SMike Smith 	/*
338235863739SMike Smith 	 * Copyin the revision struct from userspace
338335863739SMike Smith 	 */
3384c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3385c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
338635863739SMike Smith 		return error;
338735863739SMike Smith 	}
338835863739SMike Smith 
338931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3390914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
339135863739SMike Smith 
339235863739SMike Smith 	/*
339335863739SMike Smith 	 * Doctor up the response struct.
339435863739SMike Smith 	 */
339535863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
33968e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.major =
33978e7e6335SEd Maste 	    AAC_DRIVER_MAJOR_VERSION;
33988e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.minor =
33998e7e6335SEd Maste 	    AAC_DRIVER_MINOR_VERSION;
34008e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.type =
34018e7e6335SEd Maste 	    AAC_DRIVER_TYPE;
34028e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.dash =
34038e7e6335SEd Maste 	    AAC_DRIVER_BUGFIX_LEVEL;
3404914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
34058e7e6335SEd Maste 	    AAC_DRIVER_BUILD;
340635863739SMike Smith 
3407c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3408c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
340935863739SMike Smith }
341035863739SMike Smith 
3411914da7d0SScott Long /*
3412a723a548SEd Maste  * Pass the fib context to the caller
3413a723a548SEd Maste  */
3414a723a548SEd Maste static int
3415a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3416a723a548SEd Maste {
3417a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3418a723a548SEd Maste 	int error = 0;
3419a723a548SEd Maste 
342031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3421a723a548SEd Maste 
3422a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3423a723a548SEd Maste 	if (fibctx == NULL)
3424a723a548SEd Maste 		return (ENOMEM);
3425a723a548SEd Maste 
3426a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3427a723a548SEd Maste 	/* all elements are already 0, add to queue */
3428a723a548SEd Maste 	if (sc->fibctx == NULL)
3429a723a548SEd Maste 		sc->fibctx = fibctx;
3430a723a548SEd Maste 	else {
3431a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3432a723a548SEd Maste 			;
3433a723a548SEd Maste 		ctx->next = fibctx;
3434a723a548SEd Maste 		fibctx->prev = ctx;
3435a723a548SEd Maste 	}
3436a723a548SEd Maste 
3437a723a548SEd Maste 	/* evaluate unique value */
3438a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3439a723a548SEd Maste 	ctx = sc->fibctx;
3440a723a548SEd Maste 	while (ctx != fibctx) {
3441a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3442a723a548SEd Maste 			fibctx->unique++;
3443a723a548SEd Maste 			ctx = sc->fibctx;
3444a723a548SEd Maste 		} else {
3445a723a548SEd Maste 			ctx = ctx->next;
3446a723a548SEd Maste 		}
3447a723a548SEd Maste 	}
3448a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3449a723a548SEd Maste 
3450a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3451a723a548SEd Maste 	if (error)
3452a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3453a723a548SEd Maste 	return error;
3454a723a548SEd Maste }
3455a723a548SEd Maste 
3456a723a548SEd Maste /*
3457a723a548SEd Maste  * Close the caller's fib context
3458a723a548SEd Maste  */
3459a723a548SEd Maste static int
3460a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3461a723a548SEd Maste {
3462a723a548SEd Maste 	struct aac_fib_context *ctx;
3463a723a548SEd Maste 
346431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3465a723a548SEd Maste 
3466a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3467a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3468a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3469a723a548SEd Maste 			if (ctx == sc->fibctx)
3470a723a548SEd Maste 				sc->fibctx = NULL;
3471a723a548SEd Maste 			else {
3472a723a548SEd Maste 				ctx->prev->next = ctx->next;
3473a723a548SEd Maste 				if (ctx->next)
3474a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3475a723a548SEd Maste 			}
3476a723a548SEd Maste 			break;
3477a723a548SEd Maste 		}
3478a723a548SEd Maste 	}
3479a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3480a723a548SEd Maste 	if (ctx)
3481a723a548SEd Maste 		free(ctx, M_AACBUF);
3482a723a548SEd Maste 
3483a723a548SEd Maste 	return 0;
3484a723a548SEd Maste }
3485a723a548SEd Maste 
3486a723a548SEd Maste /*
348735863739SMike Smith  * Pass the caller the next AIF in their queue
348835863739SMike Smith  */
348935863739SMike Smith static int
3490fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
349135863739SMike Smith {
349235863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3493a723a548SEd Maste 	struct aac_fib_context *ctx;
34949e2e96d8SScott Long 	int error;
349535863739SMike Smith 
349631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
349735863739SMike Smith 
349835863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3499a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3500a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3501a723a548SEd Maste 				break;
3502a723a548SEd Maste 		}
3503a723a548SEd Maste 		if (!ctx)
3504a723a548SEd Maste 			return (EFAULT);
350535863739SMike Smith 
3506a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3507a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
350831a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
350935863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
351035863739SMike Smith 			while (error == EAGAIN) {
3511914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3512914da7d0SScott Long 					       PCATCH, "aacaif", 0);
351335863739SMike Smith 				if (error == 0)
3514a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
351535863739SMike Smith 			}
351635863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
351735863739SMike Smith 		}
351835863739SMike Smith 	}
351935863739SMike Smith 	return(error);
352035863739SMike Smith }
352135863739SMike Smith 
3522914da7d0SScott Long /*
35230b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
35240b94a66eSMike Smith  */
35250b94a66eSMike Smith static int
3526a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
35270b94a66eSMike Smith {
3528a723a548SEd Maste 	int current, error;
35290b94a66eSMike Smith 
353031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35310b94a66eSMike Smith 
3532bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3533a723a548SEd Maste 	current = ctx->ctx_idx;
3534a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3535a723a548SEd Maste 		/* empty */
3536bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
35373df780cfSScott Long 		return (EAGAIN);
35383df780cfSScott Long 	}
3539a723a548SEd Maste 	error =
3540a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
354136e0bf6eSScott Long 	if (error)
354270545d1aSScott Long 		device_printf(sc->aac_dev,
354370545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3544a723a548SEd Maste 	else {
3545a723a548SEd Maste 		ctx->ctx_wrap = 0;
3546a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3547a723a548SEd Maste 	}
3548bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
35490b94a66eSMike Smith 	return(error);
35500b94a66eSMike Smith }
355136e0bf6eSScott Long 
35527cb209f5SScott Long static int
35537cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
35547cb209f5SScott Long {
35557cb209f5SScott Long 	struct aac_pci_info {
35567cb209f5SScott Long 		u_int32_t bus;
35577cb209f5SScott Long 		u_int32_t slot;
35587cb209f5SScott Long 	} pciinf;
35597cb209f5SScott Long 	int error;
35607cb209f5SScott Long 
356131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35627cb209f5SScott Long 
35637cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
35647cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
35657cb209f5SScott Long 
35667cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
35677cb209f5SScott Long 			sizeof(struct aac_pci_info));
35687cb209f5SScott Long 
35697cb209f5SScott Long 	return (error);
35707cb209f5SScott Long }
35717cb209f5SScott Long 
35726d307336SEd Maste static int
35736d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr)
35746d307336SEd Maste {
35756d307336SEd Maste 	struct aac_features f;
35766d307336SEd Maste 	int error;
35776d307336SEd Maste 
35786d307336SEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35796d307336SEd Maste 
35806d307336SEd Maste 	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
35816d307336SEd Maste 		return (error);
35826d307336SEd Maste 
35836d307336SEd Maste 	/*
35846d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35856d307336SEd Maste 	 * ALL zero in the featuresState, the driver will return the current
35866d307336SEd Maste 	 * state of all the supported features, the data field will not be
35876d307336SEd Maste 	 * valid.
35886d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35896d307336SEd Maste 	 * a specific bit set in the featuresState, the driver will return the
35906d307336SEd Maste 	 * current state of this specific feature and whatever data that are
35916d307336SEd Maste 	 * associated with the feature in the data field or perform whatever
35926d307336SEd Maste 	 * action needed indicates in the data field.
35936d307336SEd Maste 	 */
35946d307336SEd Maste 	if (f.feat.fValue == 0) {
35956d307336SEd Maste 		f.feat.fBits.largeLBA =
35966d307336SEd Maste 		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35976d307336SEd Maste 		/* TODO: In the future, add other features state here as well */
35986d307336SEd Maste 	} else {
35996d307336SEd Maste 		if (f.feat.fBits.largeLBA)
36006d307336SEd Maste 			f.feat.fBits.largeLBA =
36016d307336SEd Maste 			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
36026d307336SEd Maste 		/* TODO: Add other features state and data in the future */
36036d307336SEd Maste 	}
36046d307336SEd Maste 
36056d307336SEd Maste 	error = copyout(&f, uptr, sizeof (f));
36066d307336SEd Maste 	return (error);
36076d307336SEd Maste }
36086d307336SEd Maste 
3609914da7d0SScott Long /*
361036e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
361136e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
361236e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
361336e0bf6eSScott Long  */
361436e0bf6eSScott Long static int
361536e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
361636e0bf6eSScott Long {
361736e0bf6eSScott Long 	struct aac_query_disk query_disk;
361836e0bf6eSScott Long 	struct aac_container *co;
3619914da7d0SScott Long 	struct aac_disk	*disk;
362036e0bf6eSScott Long 	int error, id;
362136e0bf6eSScott Long 
362231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
362336e0bf6eSScott Long 
3624914da7d0SScott Long 	disk = NULL;
3625914da7d0SScott Long 
3626914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3627914da7d0SScott Long 		       sizeof(struct aac_query_disk));
362836e0bf6eSScott Long 	if (error)
362936e0bf6eSScott Long 		return (error);
363036e0bf6eSScott Long 
363136e0bf6eSScott Long 	id = query_disk.ContainerNumber;
363236e0bf6eSScott Long 	if (id == -1)
363336e0bf6eSScott Long 		return (EINVAL);
363436e0bf6eSScott Long 
3635bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
363636e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
363736e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
363836e0bf6eSScott Long 			break;
363936e0bf6eSScott Long 		}
364036e0bf6eSScott Long 
364136e0bf6eSScott Long 	if (co == NULL) {
364236e0bf6eSScott Long 			query_disk.Valid = 0;
364336e0bf6eSScott Long 			query_disk.Locked = 0;
364436e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
364536e0bf6eSScott Long 	} else {
364636e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
364736e0bf6eSScott Long 		query_disk.Valid = 1;
3648914da7d0SScott Long 		query_disk.Locked =
3649914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
365036e0bf6eSScott Long 		query_disk.Deleted = 0;
3651b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
365236e0bf6eSScott Long 		query_disk.Target = disk->unit;
365336e0bf6eSScott Long 		query_disk.Lun = 0;
365436e0bf6eSScott Long 		query_disk.UnMapped = 0;
36557540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
36560b7ed341SPoul-Henning Kamp 			disk->ad_disk->d_name, disk->ad_disk->d_unit);
365736e0bf6eSScott Long 	}
3658bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
365936e0bf6eSScott Long 
3660914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3661914da7d0SScott Long 			sizeof(struct aac_query_disk));
366236e0bf6eSScott Long 
366336e0bf6eSScott Long 	return (error);
366436e0bf6eSScott Long }
366536e0bf6eSScott Long 
3666fe3cb0e1SScott Long static void
3667fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3668fe3cb0e1SScott Long {
3669fe3cb0e1SScott Long 	struct aac_fib *fib;
3670fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3671fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3672fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3673fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3674fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
367570545d1aSScott Long 	struct aac_sim *caminf;
3676fe3cb0e1SScott Long 	device_t child;
3677fe3cb0e1SScott Long 	int i, found, error;
3678fe3cb0e1SScott Long 
36791ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
368003b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3681fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
368239ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3683fe3cb0e1SScott Long 
3684fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3685fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3686fe3cb0e1SScott Long 	c_cmd->param = 0;
3687fe3cb0e1SScott Long 
3688fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3689fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3690fe3cb0e1SScott Long 	if (error) {
3691fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3692fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3693fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36941ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3695fe3cb0e1SScott Long 		return;
3696fe3cb0e1SScott Long 	}
3697fe3cb0e1SScott Long 
3698fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3699fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3700fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3701fe3cb0e1SScott Long 		    c_resp->Status);
3702fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
37031ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3704fe3cb0e1SScott Long 		return;
3705fe3cb0e1SScott Long 	}
3706fe3cb0e1SScott Long 
3707fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3708fe3cb0e1SScott Long 
3709fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
371039ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
371139ee03c3SScott Long 
3712fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3713fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3714fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3715fe3cb0e1SScott Long 	vmi->ObjId = 0;
3716fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3717fe3cb0e1SScott Long 
3718fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
371942ef13a2SEd Maste 	    sizeof(struct aac_vmi_businf_resp));
3720fe3cb0e1SScott Long 	if (error) {
3721fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3722fe3cb0e1SScott Long 		    error);
3723fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
37241ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3725fe3cb0e1SScott Long 		return;
3726fe3cb0e1SScott Long 	}
3727fe3cb0e1SScott Long 
3728fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3729fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3730fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3731fe3cb0e1SScott Long 		    vmi_resp->Status);
3732fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
37331ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3734fe3cb0e1SScott Long 		return;
3735fe3cb0e1SScott Long 	}
3736fe3cb0e1SScott Long 
3737fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3738fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
37391ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3740fe3cb0e1SScott Long 
3741fe3cb0e1SScott Long 	found = 0;
3742fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3743fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3744fe3cb0e1SScott Long 			continue;
3745fe3cb0e1SScott Long 
3746a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3747a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3748b5f516cdSScott Long 		if (caminf == NULL) {
3749b5f516cdSScott Long 			device_printf(sc->aac_dev,
3750b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3751b5f516cdSScott Long 			break;
37527cb209f5SScott Long 		};
3753fe3cb0e1SScott Long 
3754fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3755fe3cb0e1SScott Long 		if (child == NULL) {
3756b5f516cdSScott Long 			device_printf(sc->aac_dev,
3757b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3758b5f516cdSScott Long 			    i);
3759b5f516cdSScott Long 			free(caminf, M_AACBUF);
3760b5f516cdSScott Long 			break;
3761fe3cb0e1SScott Long 		}
3762fe3cb0e1SScott Long 
3763fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3764fe3cb0e1SScott Long 		caminf->BusNumber = i;
3765fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3766fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3767ddb8683eSScott Long 		caminf->sim_dev = child;
3768fe3cb0e1SScott Long 
3769fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3770fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
377170545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3772fe3cb0e1SScott Long 
3773fe3cb0e1SScott Long 		found = 1;
3774fe3cb0e1SScott Long 	}
3775fe3cb0e1SScott Long 
3776fe3cb0e1SScott Long 	if (found)
3777fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3778fe3cb0e1SScott Long 
3779fe3cb0e1SScott Long 	return;
3780fe3cb0e1SScott Long }
3781