xref: /freebsd/sys/dev/aac/aac.c (revision dbb34a64a0849f52ab4ac9134ea2ad0daf3000fa)
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_ioctl_t	aac_ioctl;
193b3457b51SScott Long static d_poll_t		aac_poll;
194dfe2c294SAttilio Rao static void		aac_cdevpriv_dtor(void *arg);
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,
215dfe2c294SAttilio Rao 	.d_flags =	D_NEEDGIANT,
2167ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2177ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2187ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2197ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
22035863739SMike Smith };
22135863739SMike Smith 
22236e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
22336e0bf6eSScott Long 
2243d04a9d7SScott Long /* sysctl node */
2253d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2263d04a9d7SScott Long 
227914da7d0SScott Long /*
228914da7d0SScott Long  * Device Interface
229914da7d0SScott Long  */
23035863739SMike Smith 
231914da7d0SScott Long /*
2324109ba51SEd Maste  * Initialize the controller and softc
23335863739SMike Smith  */
23435863739SMike Smith int
23535863739SMike Smith aac_attach(struct aac_softc *sc)
23635863739SMike Smith {
23735863739SMike Smith 	int error, unit;
23835863739SMike Smith 
23931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24035863739SMike Smith 
24135863739SMike Smith 	/*
2424109ba51SEd Maste 	 * Initialize per-controller queues.
24335863739SMike Smith 	 */
2440b94a66eSMike Smith 	aac_initq_free(sc);
2450b94a66eSMike Smith 	aac_initq_ready(sc);
2460b94a66eSMike Smith 	aac_initq_busy(sc);
2470b94a66eSMike Smith 	aac_initq_bio(sc);
24835863739SMike Smith 
24935863739SMike Smith 	/*
2504109ba51SEd Maste 	 * Initialize command-completion task.
25135863739SMike Smith 	 */
25235863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
25335863739SMike Smith 
25435863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
25535863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
25635863739SMike Smith 
25735863739SMike Smith 	/*
258fe94b852SScott Long 	 * Check that the firmware on the card is supported.
259fe94b852SScott Long 	 */
260fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
261fe94b852SScott Long 		return(error);
262fe94b852SScott Long 
263f6b1c44dSScott Long 	/*
264f6b1c44dSScott Long 	 * Initialize locks
265f6b1c44dSScott Long 	 */
266bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
267bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
268bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
269f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
270065dd78cSScott Long 	TAILQ_INIT(&sc->aac_ev_cmfree);
271f6b1c44dSScott Long 
272ff0991c4SAttilio Rao 	/* Initialize the clock daemon callout. */
273ff0991c4SAttilio Rao 	callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0);
274ff0991c4SAttilio Rao 
2750b94a66eSMike Smith 	/*
2764109ba51SEd Maste 	 * Initialize the adapter.
27735863739SMike Smith 	 */
27804f4d586SEd Maste 	if ((error = aac_alloc(sc)) != 0)
27904f4d586SEd Maste 		return(error);
2800b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
28135863739SMike Smith 		return(error);
28235863739SMike Smith 
28335863739SMike Smith 	/*
2847cb209f5SScott Long 	 * Allocate and connect our interrupt.
2857cb209f5SScott Long 	 */
28604f4d586SEd Maste 	if ((error = aac_setup_intr(sc)) != 0)
28704f4d586SEd Maste 		return(error);
2887cb209f5SScott Long 
2897cb209f5SScott Long 	/*
29035863739SMike Smith 	 * Print a little information about the controller.
29135863739SMike Smith 	 */
29235863739SMike Smith 	aac_describe_controller(sc);
29335863739SMike Smith 
29435863739SMike Smith 	/*
295ae543596SScott Long 	 * Register to probe our containers later.
296ae543596SScott Long 	 */
29735863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
29835863739SMike Smith 	sc->aac_ich.ich_arg = sc;
29935863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
300914da7d0SScott Long 		device_printf(sc->aac_dev,
301914da7d0SScott Long 			      "can't establish configuration hook\n");
30235863739SMike Smith 		return(ENXIO);
30335863739SMike Smith 	}
30435863739SMike Smith 
30535863739SMike Smith 	/*
30635863739SMike Smith 	 * Make the control device.
30735863739SMike Smith 	 */
30835863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3099e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3109e9466baSRobert Watson 				 0640, "aac%d", unit);
311157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3124aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
31335863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
31435863739SMike Smith 
31536e0bf6eSScott Long 	/* Create the AIF thread */
3163745c395SJulian Elischer 	if (kproc_create((void(*)(void *))aac_command_thread, sc,
317316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
318a620bad0SEd Maste 		panic("Could not create AIF thread");
31936e0bf6eSScott Long 
32036e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3215f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3225f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3235f54d522SScott Long 		device_printf(sc->aac_dev,
3245f54d522SScott Long 			      "shutdown event registration failed\n");
32536e0bf6eSScott Long 
326fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
327a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
32870545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
329fe3cb0e1SScott Long 		aac_get_bus_info(sc);
33070545d1aSScott Long 	}
331fe3cb0e1SScott Long 
332ff0991c4SAttilio Rao 	mtx_lock(&sc->aac_io_lock);
333867b1d34SEd Maste 	callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc);
334ff0991c4SAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
335ff0991c4SAttilio Rao 
33635863739SMike Smith 	return(0);
33735863739SMike Smith }
33835863739SMike Smith 
339ff0991c4SAttilio Rao static void
340ff0991c4SAttilio Rao aac_daemon(void *arg)
341ff0991c4SAttilio Rao {
342ff0991c4SAttilio Rao 	struct timeval tv;
343ff0991c4SAttilio Rao 	struct aac_softc *sc;
344ff0991c4SAttilio Rao 	struct aac_fib *fib;
345ff0991c4SAttilio Rao 
346ff0991c4SAttilio Rao 	sc = arg;
347ff0991c4SAttilio Rao 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
348ff0991c4SAttilio Rao 
349ff0991c4SAttilio Rao 	if (callout_pending(&sc->aac_daemontime) ||
350ff0991c4SAttilio Rao 	    callout_active(&sc->aac_daemontime) == 0)
351ff0991c4SAttilio Rao 		return;
352ff0991c4SAttilio Rao 	getmicrotime(&tv);
353ff0991c4SAttilio Rao 	aac_alloc_sync_fib(sc, &fib);
354ff0991c4SAttilio Rao 	*(uint32_t *)fib->data = tv.tv_sec;
355ff0991c4SAttilio Rao 	aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t));
356ff0991c4SAttilio Rao 	aac_release_sync_fib(sc);
357ff0991c4SAttilio Rao 	callout_schedule(&sc->aac_daemontime, 30 * 60 * hz);
358ff0991c4SAttilio Rao }
359ff0991c4SAttilio Rao 
3607cb209f5SScott Long void
3617cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3627cb209f5SScott Long {
3637cb209f5SScott Long 
3647cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3657cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3667cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3677cb209f5SScott Long 		break;
3687cb209f5SScott Long 	default:
3697cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3707cb209f5SScott Long 		    event->ev_type);
3717cb209f5SScott Long 		break;
3727cb209f5SScott Long 	}
3737cb209f5SScott Long 
3747cb209f5SScott Long 	return;
3757cb209f5SScott Long }
3767cb209f5SScott Long 
377914da7d0SScott Long /*
37804f4d586SEd Maste  * Request information of container #cid
37904f4d586SEd Maste  */
38004f4d586SEd Maste static struct aac_mntinforesp *
38104f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid)
38204f4d586SEd Maste {
38304f4d586SEd Maste 	struct aac_mntinfo *mi;
38404f4d586SEd Maste 
38504f4d586SEd Maste 	mi = (struct aac_mntinfo *)&fib->data[0];
386523da39bSEd Maste 	/* use 64-bit LBA if enabled */
387523da39bSEd Maste 	mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ?
388523da39bSEd Maste 	    VM_NameServe64 : VM_NameServe;
38904f4d586SEd Maste 	mi->MntType = FT_FILESYS;
39004f4d586SEd Maste 	mi->MntCount = cid;
39104f4d586SEd Maste 
39204f4d586SEd Maste 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
39304f4d586SEd Maste 			 sizeof(struct aac_mntinfo))) {
394*dbb34a64SEd Maste 		device_printf(sc->aac_dev, "Error probing container %d\n", cid);
39504f4d586SEd Maste 		return (NULL);
39604f4d586SEd Maste 	}
39704f4d586SEd Maste 
39804f4d586SEd Maste 	return ((struct aac_mntinforesp *)&fib->data[0]);
39904f4d586SEd Maste }
40004f4d586SEd Maste 
40104f4d586SEd Maste /*
40235863739SMike Smith  * Probe for containers, create disks.
40335863739SMike Smith  */
40435863739SMike Smith static void
40535863739SMike Smith aac_startup(void *arg)
40635863739SMike Smith {
407914da7d0SScott Long 	struct aac_softc *sc;
408cbfd045bSScott Long 	struct aac_fib *fib;
40904f4d586SEd Maste 	struct aac_mntinforesp *mir;
410795d7dc0SScott Long 	int count = 0, i = 0;
41135863739SMike Smith 
412914da7d0SScott Long 	sc = (struct aac_softc *)arg;
41331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
414914da7d0SScott Long 
41535863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
41635863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
41735863739SMike Smith 
4187cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
41903b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
420cbfd045bSScott Long 
42135863739SMike Smith 	/* loop over possible containers */
42236e0bf6eSScott Long 	do {
42304f4d586SEd Maste 		if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
42435863739SMike Smith 			continue;
42504f4d586SEd Maste 		if (i == 0)
426795d7dc0SScott Long 			count = mir->MntRespCount;
427cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
42836e0bf6eSScott Long 		i++;
429795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
430cbfd045bSScott Long 
431cbfd045bSScott Long 	aac_release_sync_fib(sc);
4327cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
43335863739SMike Smith 
43435863739SMike Smith 	/* poke the bus to actually attach the child devices */
43535863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
43635863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
43735863739SMike Smith 
43835863739SMike Smith 	/* mark the controller up */
43935863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
44035863739SMike Smith 
44135863739SMike Smith 	/* enable interrupts now */
44235863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
44335863739SMike Smith }
44435863739SMike Smith 
445914da7d0SScott Long /*
4464109ba51SEd Maste  * Create a device to represent a new container
447914da7d0SScott Long  */
448914da7d0SScott Long static void
449cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
450914da7d0SScott Long {
451914da7d0SScott Long 	struct aac_container *co;
452914da7d0SScott Long 	device_t child;
453914da7d0SScott Long 
454914da7d0SScott Long 	/*
455914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
456914da7d0SScott Long 	 * the possible types may never show up.
457914da7d0SScott Long 	 */
458914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
459a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
460a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
461914da7d0SScott Long 		if (co == NULL)
462a620bad0SEd Maste 			panic("Out of memory?!");
46331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x  name '%.16s'  size %u  type %d",
464914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
465914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
466914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
467914da7d0SScott Long 
468fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
469914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
470914da7d0SScott Long 		else
471914da7d0SScott Long 			device_set_ivars(child, co);
472914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
473914da7d0SScott Long 				mir->MntTable[0].VolType));
474914da7d0SScott Long 		co->co_disk = child;
475914da7d0SScott Long 		co->co_found = f;
476914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
477914da7d0SScott Long 		      sizeof(struct aac_mntobj));
478bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
479914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
480bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
481914da7d0SScott Long 	}
482914da7d0SScott Long }
483914da7d0SScott Long 
484914da7d0SScott Long /*
48504f4d586SEd Maste  * Allocate resources associated with (sc)
48604f4d586SEd Maste  */
48704f4d586SEd Maste static int
48804f4d586SEd Maste aac_alloc(struct aac_softc *sc)
48904f4d586SEd Maste {
49031a0399eSEd Maste 
49131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
49231a0399eSEd Maste 
49304f4d586SEd Maste 	/*
49404f4d586SEd Maste 	 * Create DMA tag for mapping buffers into controller-addressable space.
49504f4d586SEd Maste 	 */
49604f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
49704f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
49804f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
49904f4d586SEd Maste 			       BUS_SPACE_MAXADDR :
50004f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
50104f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
50204f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
50304f4d586SEd Maste 			       MAXBSIZE,		/* maxsize */
50404f4d586SEd Maste 			       sc->aac_sg_tablesize,	/* nsegments */
50504f4d586SEd Maste 			       MAXBSIZE,		/* maxsegsize */
50604f4d586SEd Maste 			       BUS_DMA_ALLOCNOW,	/* flags */
50704f4d586SEd Maste 			       busdma_lock_mutex,	/* lockfunc */
50804f4d586SEd Maste 			       &sc->aac_io_lock,	/* lockfuncarg */
50904f4d586SEd Maste 			       &sc->aac_buffer_dmat)) {
51004f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
51104f4d586SEd Maste 		return (ENOMEM);
51204f4d586SEd Maste 	}
51304f4d586SEd Maste 
51404f4d586SEd Maste 	/*
51504f4d586SEd Maste 	 * Create DMA tag for mapping FIBs into controller-addressable space..
51604f4d586SEd Maste 	 */
51704f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
51804f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
51904f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
52004f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
52104f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
52204f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
52304f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
52404f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
52504f4d586SEd Maste 			       sc->aac_max_fib_size,  /* maxsize */
52604f4d586SEd Maste 			       1,			/* nsegments */
52704f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
52804f4d586SEd Maste 			       sc->aac_max_fib_size,	/* maxsize */
52904f4d586SEd Maste 			       0,			/* flags */
53004f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
53104f4d586SEd Maste 			       &sc->aac_fib_dmat)) {
532c2ede4b3SMartin Blapp 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");
53304f4d586SEd Maste 		return (ENOMEM);
53404f4d586SEd Maste 	}
53504f4d586SEd Maste 
53604f4d586SEd Maste 	/*
53704f4d586SEd Maste 	 * Create DMA tag for the common structure and allocate it.
53804f4d586SEd Maste 	 */
53904f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
54004f4d586SEd Maste 			       1, 0,			/* algnmnt, boundary */
54104f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
54204f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
54304f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
54404f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
54504f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
54604f4d586SEd Maste 			       8192 + sizeof(struct aac_common), /* maxsize */
54704f4d586SEd Maste 			       1,			/* nsegments */
54804f4d586SEd Maste 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
54904f4d586SEd Maste 			       0,			/* flags */
55004f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
55104f4d586SEd Maste 			       &sc->aac_common_dmat)) {
55204f4d586SEd Maste 		device_printf(sc->aac_dev,
55304f4d586SEd Maste 			      "can't allocate common structure DMA tag\n");
55404f4d586SEd Maste 		return (ENOMEM);
55504f4d586SEd Maste 	}
55604f4d586SEd Maste 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
55704f4d586SEd Maste 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
55804f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate common structure\n");
55904f4d586SEd Maste 		return (ENOMEM);
56004f4d586SEd Maste 	}
56104f4d586SEd Maste 
56204f4d586SEd Maste 	/*
56304f4d586SEd Maste 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
56404f4d586SEd Maste 	 * below address 8192 in physical memory.
56504f4d586SEd Maste 	 * XXX If the padding is not needed, can it be put to use instead
56604f4d586SEd Maste 	 * of ignored?
56704f4d586SEd Maste 	 */
56804f4d586SEd Maste 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
56904f4d586SEd Maste 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
57004f4d586SEd Maste 			aac_common_map, sc, 0);
57104f4d586SEd Maste 
57204f4d586SEd Maste 	if (sc->aac_common_busaddr < 8192) {
57304f4d586SEd Maste 		sc->aac_common = (struct aac_common *)
57404f4d586SEd Maste 		    ((uint8_t *)sc->aac_common + 8192);
57504f4d586SEd Maste 		sc->aac_common_busaddr += 8192;
57604f4d586SEd Maste 	}
57704f4d586SEd Maste 	bzero(sc->aac_common, sizeof(*sc->aac_common));
57804f4d586SEd Maste 
57904f4d586SEd Maste 	/* Allocate some FIBs and associated command structs */
58004f4d586SEd Maste 	TAILQ_INIT(&sc->aac_fibmap_tqh);
58104f4d586SEd Maste 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
58204f4d586SEd Maste 				  M_AACBUF, M_WAITOK|M_ZERO);
58323e876b1SJung-uk Kim 	while (sc->total_fibs < sc->aac_max_fibs) {
58404f4d586SEd Maste 		if (aac_alloc_commands(sc) != 0)
58504f4d586SEd Maste 			break;
58604f4d586SEd Maste 	}
58704f4d586SEd Maste 	if (sc->total_fibs == 0)
58804f4d586SEd Maste 		return (ENOMEM);
58904f4d586SEd Maste 
59004f4d586SEd Maste 	return (0);
59104f4d586SEd Maste }
59204f4d586SEd Maste 
59304f4d586SEd Maste /*
59435863739SMike Smith  * Free all of the resources associated with (sc)
59535863739SMike Smith  *
59635863739SMike Smith  * Should not be called if the controller is active.
59735863739SMike Smith  */
59835863739SMike Smith void
59935863739SMike Smith aac_free(struct aac_softc *sc)
60035863739SMike Smith {
601ffb37f33SScott Long 
60231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
60335863739SMike Smith 
60435863739SMike Smith 	/* remove the control device */
60535863739SMike Smith 	if (sc->aac_dev_t != NULL)
60635863739SMike Smith 		destroy_dev(sc->aac_dev_t);
60735863739SMike Smith 
6080b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
6098480cc63SScott Long 	aac_free_commands(sc);
6100b94a66eSMike Smith 	if (sc->aac_fib_dmat)
6110b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
61235863739SMike Smith 
613ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
614ffb37f33SScott Long 
61535863739SMike Smith 	/* destroy the common area */
61635863739SMike Smith 	if (sc->aac_common) {
61735863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
618c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
619c6eafcf2SScott Long 				sc->aac_common_dmamap);
62035863739SMike Smith 	}
6210b94a66eSMike Smith 	if (sc->aac_common_dmat)
6220b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
62335863739SMike Smith 
62435863739SMike Smith 	/* disconnect the interrupt handler */
62535863739SMike Smith 	if (sc->aac_intr)
62635863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
62735863739SMike Smith 	if (sc->aac_irq != NULL)
628c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
629c6eafcf2SScott Long 				     sc->aac_irq);
63035863739SMike Smith 
63135863739SMike Smith 	/* destroy data-transfer DMA tag */
63235863739SMike Smith 	if (sc->aac_buffer_dmat)
63335863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
63435863739SMike Smith 
63535863739SMike Smith 	/* destroy the parent DMA tag */
63635863739SMike Smith 	if (sc->aac_parent_dmat)
63735863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
63835863739SMike Smith 
63935863739SMike Smith 	/* release the register window mapping */
640ff0991c4SAttilio Rao 	if (sc->aac_regs_res0 != NULL)
641914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
642ff0991c4SAttilio Rao 				     sc->aac_regs_rid0, sc->aac_regs_res0);
643ff0991c4SAttilio Rao 	if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL)
644ff0991c4SAttilio Rao 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
645ff0991c4SAttilio Rao 				     sc->aac_regs_rid1, sc->aac_regs_res1);
64635863739SMike Smith }
64735863739SMike Smith 
648914da7d0SScott Long /*
64935863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
65035863739SMike Smith  */
65135863739SMike Smith int
65235863739SMike Smith aac_detach(device_t dev)
65335863739SMike Smith {
654914da7d0SScott Long 	struct aac_softc *sc;
65570545d1aSScott Long 	struct aac_container *co;
65670545d1aSScott Long 	struct aac_sim	*sim;
65735863739SMike Smith 	int error;
65835863739SMike Smith 
659914da7d0SScott Long 	sc = device_get_softc(dev);
66031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
661914da7d0SScott Long 
662ff0991c4SAttilio Rao 	callout_drain(&sc->aac_daemontime);
663ff0991c4SAttilio Rao 
66470545d1aSScott Long 	/* Remove the child containers */
665a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
66670545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
66770545d1aSScott Long 		if (error)
66870545d1aSScott Long 			return (error);
66965ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
670a761a1caSScott Long 		free(co, M_AACBUF);
67170545d1aSScott Long 	}
67270545d1aSScott Long 
67370545d1aSScott Long 	/* Remove the CAM SIMs */
674a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
675a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
67670545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
67770545d1aSScott Long 		if (error)
67870545d1aSScott Long 			return (error);
679a761a1caSScott Long 		free(sim, M_AACBUF);
68070545d1aSScott Long 	}
68170545d1aSScott Long 
68236e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
68336e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
68436e0bf6eSScott Long 		wakeup(sc->aifthread);
68536e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
68636e0bf6eSScott Long 	}
68736e0bf6eSScott Long 
68836e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
689a620bad0SEd Maste 		panic("Cannot shutdown AIF thread");
69036e0bf6eSScott Long 
69135863739SMike Smith 	if ((error = aac_shutdown(dev)))
69235863739SMike Smith 		return(error);
69335863739SMike Smith 
6945f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
6955f54d522SScott Long 
69635863739SMike Smith 	aac_free(sc);
69735863739SMike Smith 
698dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
699dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
700dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
701dc9efde5SScott Long 
70235863739SMike Smith 	return(0);
70335863739SMike Smith }
70435863739SMike Smith 
705914da7d0SScott Long /*
70635863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
70735863739SMike Smith  *
70835863739SMike Smith  * This function is called before detach or system shutdown.
70935863739SMike Smith  *
7100b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
71135863739SMike Smith  * allow shutdown if any device is open.
71235863739SMike Smith  */
71335863739SMike Smith int
71435863739SMike Smith aac_shutdown(device_t dev)
71535863739SMike Smith {
716914da7d0SScott Long 	struct aac_softc *sc;
717cbfd045bSScott Long 	struct aac_fib *fib;
718cbfd045bSScott Long 	struct aac_close_command *cc;
71935863739SMike Smith 
720914da7d0SScott Long 	sc = device_get_softc(dev);
72131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
722914da7d0SScott Long 
72335863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
72435863739SMike Smith 
72535863739SMike Smith 	/*
72635863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
72735863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
72835863739SMike Smith 	 * We've been closed and all I/O completed already
72935863739SMike Smith 	 */
73035863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
73135863739SMike Smith 
7327cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
73303b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
734cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
735cbfd045bSScott Long 
73639ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
737cbfd045bSScott Long 	cc->Command = VM_CloseAll;
738cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
739cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
740cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
74135863739SMike Smith 		printf("FAILED.\n");
74270545d1aSScott Long 	else
74370545d1aSScott Long 		printf("done\n");
74470545d1aSScott Long #if 0
745914da7d0SScott Long 	else {
746cbfd045bSScott Long 		fib->data[0] = 0;
74736e0bf6eSScott Long 		/*
748914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
74936e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
75036e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
75136e0bf6eSScott Long 		 * driver module with the intent to reload it later.
75236e0bf6eSScott Long 		 */
753cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
754cbfd045bSScott Long 		    fib, 1)) {
75535863739SMike Smith 			printf("FAILED.\n");
75635863739SMike Smith 		} else {
75735863739SMike Smith 			printf("done.\n");
75835863739SMike Smith 		}
75935863739SMike Smith 	}
76070545d1aSScott Long #endif
76135863739SMike Smith 
76235863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
7633576af8fSScott Long 	aac_release_sync_fib(sc);
7647cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
76535863739SMike Smith 
76635863739SMike Smith 	return(0);
76735863739SMike Smith }
76835863739SMike Smith 
769914da7d0SScott Long /*
77035863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
77135863739SMike Smith  */
77235863739SMike Smith int
77335863739SMike Smith aac_suspend(device_t dev)
77435863739SMike Smith {
775914da7d0SScott Long 	struct aac_softc *sc;
77635863739SMike Smith 
777914da7d0SScott Long 	sc = device_get_softc(dev);
778914da7d0SScott Long 
77931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
78035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
78135863739SMike Smith 
78235863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
78335863739SMike Smith 	return(0);
78435863739SMike Smith }
78535863739SMike Smith 
786914da7d0SScott Long /*
78735863739SMike Smith  * Bring the controller back to a state ready for operation.
78835863739SMike Smith  */
78935863739SMike Smith int
79035863739SMike Smith aac_resume(device_t dev)
79135863739SMike Smith {
792914da7d0SScott Long 	struct aac_softc *sc;
79335863739SMike Smith 
794914da7d0SScott Long 	sc = device_get_softc(dev);
795914da7d0SScott Long 
79631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
79735863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
79835863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
79935863739SMike Smith 	return(0);
80035863739SMike Smith }
80135863739SMike Smith 
802914da7d0SScott Long /*
8037cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
80435863739SMike Smith  */
80535863739SMike Smith void
8067cb209f5SScott Long aac_new_intr(void *arg)
8077cb209f5SScott Long {
8087cb209f5SScott Long 	struct aac_softc *sc;
8097cb209f5SScott Long 	u_int32_t index, fast;
8107cb209f5SScott Long 	struct aac_command *cm;
8117cb209f5SScott Long 	struct aac_fib *fib;
8127cb209f5SScott Long 	int i;
8137cb209f5SScott Long 
8147cb209f5SScott Long 	sc = (struct aac_softc *)arg;
8157cb209f5SScott Long 
81631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
8177cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
8187cb209f5SScott Long 	while (1) {
8197cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
8207cb209f5SScott Long 		if (index == 0xffffffff)
8217cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
8227cb209f5SScott Long 		if (index == 0xffffffff)
8237cb209f5SScott Long 			break;
8247cb209f5SScott Long 		if (index & 2) {
8257cb209f5SScott Long 			if (index == 0xfffffffe) {
8267cb209f5SScott Long 				/* XXX This means that the controller wants
8277cb209f5SScott Long 				 * more work.  Ignore it for now.
8287cb209f5SScott Long 				 */
8297cb209f5SScott Long 				continue;
8307cb209f5SScott Long 			}
8317cb209f5SScott Long 			/* AIF */
8327cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
8337cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
8347cb209f5SScott Long 			if (fib == NULL) {
8357cb209f5SScott Long 				/* If we're really this short on memory,
8367cb209f5SScott Long 				 * hopefully breaking out of the handler will
8377cb209f5SScott Long 				 * allow something to get freed.  This
8387cb209f5SScott Long 				 * actually sucks a whole lot.
8397cb209f5SScott Long 				 */
8407cb209f5SScott Long 				break;
8417cb209f5SScott Long 			}
8427cb209f5SScott Long 			index &= ~2;
8437cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
844ff0991c4SAttilio Rao 				((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4);
8457cb209f5SScott Long 			aac_handle_aif(sc, fib);
8467cb209f5SScott Long 			free(fib, M_AACBUF);
8477cb209f5SScott Long 
8487cb209f5SScott Long 			/*
8497cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
8507cb209f5SScott Long 			 * know that we are done with it.
8517cb209f5SScott Long 			 */
8527cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
8537cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
8547cb209f5SScott Long 		} else {
8557cb209f5SScott Long 			fast = index & 1;
8567cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
8577cb209f5SScott Long 			fib = cm->cm_fib;
8587cb209f5SScott Long 			if (fast) {
8597cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
8607cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
8617cb209f5SScott Long 			}
8627cb209f5SScott Long 			aac_remove_busy(cm);
8637cb209f5SScott Long  			aac_unmap_command(cm);
8647cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
8657cb209f5SScott Long 
8667cb209f5SScott Long 			/* is there a completion handler? */
8677cb209f5SScott Long 			if (cm->cm_complete != NULL) {
8687cb209f5SScott Long 				cm->cm_complete(cm);
8697cb209f5SScott Long 			} else {
8707cb209f5SScott Long 				/* assume that someone is sleeping on this
8717cb209f5SScott Long 				 * command
8727cb209f5SScott Long 				 */
8737cb209f5SScott Long 				wakeup(cm);
8747cb209f5SScott Long 			}
8757cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
8767cb209f5SScott Long 		}
8777cb209f5SScott Long 	}
8787cb209f5SScott Long 	/* see if we can start some more I/O */
8797cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
8807cb209f5SScott Long 		aac_startio(sc);
8817cb209f5SScott Long 
8827cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
8837cb209f5SScott Long }
8847cb209f5SScott Long 
885e46b9eeaSEd Maste /*
886e46b9eeaSEd Maste  * Interrupt filter for !NEW_COMM interface.
887e46b9eeaSEd Maste  */
888ef544f63SPaolo Pisati int
889e46b9eeaSEd Maste aac_filter(void *arg)
89035863739SMike Smith {
891914da7d0SScott Long 	struct aac_softc *sc;
89270545d1aSScott Long 	u_int16_t reason;
89335863739SMike Smith 
894914da7d0SScott Long 	sc = (struct aac_softc *)arg;
895914da7d0SScott Long 
89631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
897f30ac74cSScott Long 	/*
8989148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
8999148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
9009148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
9019148fa21SScott Long 	 * ugly.
902f30ac74cSScott Long 	 */
90335863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
904f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
905f30ac74cSScott Long 
9069c3a7fceSScott Long 	/* handle completion processing */
9079148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
9089148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
90935863739SMike Smith 
9109148fa21SScott Long 	/* controller wants to talk to us */
9119148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
91270545d1aSScott Long 		/*
9139148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
9149148fa21SScott Long 		 * that start with a NULL.
91570545d1aSScott Long 		 */
9169148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
9179148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
9189148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
91970545d1aSScott Long 
9209148fa21SScott Long 		/*
9219148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
922a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
9239148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
9249148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
9259148fa21SScott Long 		 * if needed.
9269148fa21SScott Long 		 */
92736e0bf6eSScott Long 		wakeup(sc->aifthread);
92836e0bf6eSScott Long 	}
929ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
9309148fa21SScott Long }
93135863739SMike Smith 
932c6eafcf2SScott Long /*
933914da7d0SScott Long  * Command Processing
934914da7d0SScott Long  */
93535863739SMike Smith 
936914da7d0SScott Long /*
93735863739SMike Smith  * Start as much queued I/O as possible on the controller
93835863739SMike Smith  */
939fe3cb0e1SScott Long void
94035863739SMike Smith aac_startio(struct aac_softc *sc)
94135863739SMike Smith {
94235863739SMike Smith 	struct aac_command *cm;
943397fa34fSScott Long 	int error;
94435863739SMike Smith 
94531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
94635863739SMike Smith 
94735863739SMike Smith 	for (;;) {
948914da7d0SScott Long 		/*
949397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
950397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
951397fa34fSScott Long 		 */
952397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
953397fa34fSScott Long 			break;
954397fa34fSScott Long 
955397fa34fSScott Long 		/*
956914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
957914da7d0SScott Long 		 * resources
958914da7d0SScott Long 		 */
95935863739SMike Smith 		cm = aac_dequeue_ready(sc);
96035863739SMike Smith 
961914da7d0SScott Long 		/*
962914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
963914da7d0SScott Long 		 * return)
964914da7d0SScott Long 		 */
9650b94a66eSMike Smith 		if (cm == NULL)
96635863739SMike Smith 			aac_bio_command(sc, &cm);
96735863739SMike Smith 
96835863739SMike Smith 		/* nothing to do? */
96935863739SMike Smith 		if (cm == NULL)
97035863739SMike Smith 			break;
97135863739SMike Smith 
972cd481291SScott Long 		/* don't map more than once */
973cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
9744102d44bSScott Long 			panic("aac: command %p already mapped", cm);
97535863739SMike Smith 
976397fa34fSScott Long 		/*
977397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
978397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
979397fa34fSScott Long 		 * busdma.
980397fa34fSScott Long 		 */
981cd481291SScott Long 		if (cm->cm_datalen != 0) {
982397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
983397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
984397fa34fSScott Long 						cm->cm_datalen,
985cd481291SScott Long 						aac_map_command_sg, cm, 0);
986cd481291SScott Long 			if (error == EINPROGRESS) {
98731a0399eSEd Maste 				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
988cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
989cd481291SScott Long 				error = 0;
990614c22b2SScott Long 			} else if (error != 0)
991397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
992a620bad0SEd Maste 				      "busdma", error);
993397fa34fSScott Long 		} else
9948778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
995cd481291SScott Long 	}
99635863739SMike Smith }
99735863739SMike Smith 
998914da7d0SScott Long /*
99935863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
100035863739SMike Smith  */
100135863739SMike Smith static void
100270545d1aSScott Long aac_command_thread(struct aac_softc *sc)
100335863739SMike Smith {
100435863739SMike Smith 	struct aac_fib *fib;
100535863739SMike Smith 	u_int32_t fib_size;
10069148fa21SScott Long 	int size, retval;
100735863739SMike Smith 
100831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
100935863739SMike Smith 
1010bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1011a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
101236e0bf6eSScott Long 
1013a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1014a32a982dSScott Long 
1015a32a982dSScott Long 		retval = 0;
1016a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1017a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1018a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
101936e0bf6eSScott Long 
10209148fa21SScott Long 		/*
10219148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
10229148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
10239148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
10249148fa21SScott Long 		 */
10259148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1026bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
1027a32a982dSScott Long 			aac_alloc_commands(sc);
1028bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
10294102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1030a32a982dSScott Long 			aac_startio(sc);
1031a32a982dSScott Long 		}
10329148fa21SScott Long 
10339148fa21SScott Long 		/*
10349148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
10359148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
10369148fa21SScott Long 		 * always fire.
10379148fa21SScott Long 		 */
10389148fa21SScott Long 		if (retval == EWOULDBLOCK)
103970545d1aSScott Long 			aac_timeout(sc);
104070545d1aSScott Long 
104170545d1aSScott Long 		/* Check the hardware printf message buffer */
10429148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
104370545d1aSScott Long 			aac_print_printf(sc);
104470545d1aSScott Long 
10459148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
10467cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
10477cb209f5SScott Long 			continue;
10487cb209f5SScott Long 		for (;;) {
10497cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
10507cb209f5SScott Long 					   &fib_size, &fib))
10517cb209f5SScott Long 				break;
105235863739SMike Smith 
105336e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
105436e0bf6eSScott Long 
105535863739SMike Smith 			switch (fib->Header.Command) {
105635863739SMike Smith 			case AifRequest:
105736e0bf6eSScott Long 				aac_handle_aif(sc, fib);
105835863739SMike Smith 				break;
105935863739SMike Smith 			default:
1060914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
1061914da7d0SScott Long 					      "from controller\n");
106235863739SMike Smith 				break;
106335863739SMike Smith 			}
106435863739SMike Smith 
106536e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
10667cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
106736e0bf6eSScott Long 				break;
10687cb209f5SScott Long 			}
106936e0bf6eSScott Long 
107070545d1aSScott Long 			/* Return the AIF to the controller. */
107136e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
107236e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
107336e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
107436e0bf6eSScott Long 
107536e0bf6eSScott Long 				/* XXX Compute the Size field? */
107636e0bf6eSScott Long 				size = fib->Header.Size;
107736e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
107836e0bf6eSScott Long 					size = sizeof(struct aac_fib);
107936e0bf6eSScott Long 					fib->Header.Size = size;
108036e0bf6eSScott Long 				}
108136e0bf6eSScott Long 				/*
1082914da7d0SScott Long 				 * Since we did not generate this command, it
1083914da7d0SScott Long 				 * cannot go through the normal
1084914da7d0SScott Long 				 * enqueue->startio chain.
108536e0bf6eSScott Long 				 */
1086914da7d0SScott Long 				aac_enqueue_response(sc,
1087914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
1088914da7d0SScott Long 						 fib);
108936e0bf6eSScott Long 			}
109036e0bf6eSScott Long 		}
109136e0bf6eSScott Long 	}
109236e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1093bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
109436e0bf6eSScott Long 	wakeup(sc->aac_dev);
109536e0bf6eSScott Long 
10963745c395SJulian Elischer 	kproc_exit(0);
109735863739SMike Smith }
109835863739SMike Smith 
1099914da7d0SScott Long /*
11009c3a7fceSScott Long  * Process completed commands.
110135863739SMike Smith  */
110235863739SMike Smith static void
11039c3a7fceSScott Long aac_complete(void *context, int pending)
110435863739SMike Smith {
11059c3a7fceSScott Long 	struct aac_softc *sc;
110635863739SMike Smith 	struct aac_command *cm;
110735863739SMike Smith 	struct aac_fib *fib;
110835863739SMike Smith 	u_int32_t fib_size;
110935863739SMike Smith 
11109c3a7fceSScott Long 	sc = (struct aac_softc *)context;
111131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
11129c3a7fceSScott Long 
1113bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1114ae543596SScott Long 
11159c3a7fceSScott Long 	/* pull completed commands off the queue */
111635863739SMike Smith 	for (;;) {
111735863739SMike Smith 		/* look for completed FIBs on our queue */
1118914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1119914da7d0SScott Long 							&fib))
112035863739SMike Smith 			break;	/* nothing to do */
112135863739SMike Smith 
1122ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1123cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
112435863739SMike Smith 		if (cm == NULL) {
112535863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
11269c3a7fceSScott Long 			break;
11279c3a7fceSScott Long 		}
11283e507710SEd Maste 		if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0)
11293e507710SEd Maste 			device_printf(sc->aac_dev,
11303e507710SEd Maste 			    "COMMAND %p COMPLETED AFTER %d SECONDS\n",
11313e507710SEd Maste 			    cm, (int)(time_uptime-cm->cm_timestamp));
11323e507710SEd Maste 
11330b94a66eSMike Smith 		aac_remove_busy(cm);
11347cb209f5SScott Long 
1135ecd1c51fSScott Long  		aac_unmap_command(cm);
113635863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
113735863739SMike Smith 
113835863739SMike Smith 		/* is there a completion handler? */
113935863739SMike Smith 		if (cm->cm_complete != NULL) {
114035863739SMike Smith 			cm->cm_complete(cm);
114135863739SMike Smith 		} else {
114235863739SMike Smith 			/* assume that someone is sleeping on this command */
114335863739SMike Smith 			wakeup(cm);
114435863739SMike Smith 		}
114535863739SMike Smith 	}
11460b94a66eSMike Smith 
11470b94a66eSMike Smith 	/* see if we can start some more I/O */
1148cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
11490b94a66eSMike Smith 	aac_startio(sc);
1150ae543596SScott Long 
1151bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
115235863739SMike Smith }
115335863739SMike Smith 
1154914da7d0SScott Long /*
115535863739SMike Smith  * Handle a bio submitted from a disk device.
115635863739SMike Smith  */
115735863739SMike Smith void
115835863739SMike Smith aac_submit_bio(struct bio *bp)
115935863739SMike Smith {
1160914da7d0SScott Long 	struct aac_disk *ad;
1161914da7d0SScott Long 	struct aac_softc *sc;
116235863739SMike Smith 
11637540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1164914da7d0SScott Long 	sc = ad->ad_controller;
116531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1166914da7d0SScott Long 
116735863739SMike Smith 	/* queue the BIO and try to get some work done */
11680b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
116935863739SMike Smith 	aac_startio(sc);
117035863739SMike Smith }
117135863739SMike Smith 
1172914da7d0SScott Long /*
117335863739SMike Smith  * Get a bio and build a command to go with it.
117435863739SMike Smith  */
117535863739SMike Smith static int
117635863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
117735863739SMike Smith {
117835863739SMike Smith 	struct aac_command *cm;
117935863739SMike Smith 	struct aac_fib *fib;
118035863739SMike Smith 	struct aac_disk *ad;
118135863739SMike Smith 	struct bio *bp;
118235863739SMike Smith 
118331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
118435863739SMike Smith 
118535863739SMike Smith 	/* get the resources we will need */
118635863739SMike Smith 	cm = NULL;
1187a32a982dSScott Long 	bp = NULL;
118835863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
118935863739SMike Smith 		goto fail;
1190a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1191a32a982dSScott Long 		goto fail;
119235863739SMike Smith 
119335863739SMike Smith 	/* fill out the command */
11940b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
11950b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
11960b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
119735863739SMike Smith 	cm->cm_private = bp;
11982b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
119935863739SMike Smith 
120035863739SMike Smith 	/* build the FIB */
120135863739SMike Smith 	fib = cm->cm_fib;
1202b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
120335863739SMike Smith 	fib->Header.XferState =
120435863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
120535863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1206f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
120735863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
120835863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1209f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1210f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1211f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
121235863739SMike Smith 
121335863739SMike Smith 	/* build the read/write request */
12147540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1215b85f5808SScott Long 
12167cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
12177cb209f5SScott Long 		struct aac_raw_io *raw;
12187cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
12197cb209f5SScott Long 		fib->Header.Command = RawIo;
12207cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
12217cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
12227cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
12237cb209f5SScott Long 		raw->BpTotal = 0;
12247cb209f5SScott Long 		raw->BpComplete = 0;
12257cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
12267cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
12277cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
12287cb209f5SScott Long 			raw->Flags = 1;
12297cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
12307cb209f5SScott Long 		} else {
12317cb209f5SScott Long 			raw->Flags = 0;
12327cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
12337cb209f5SScott Long 		}
12347cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1235b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
12369e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1237b85f5808SScott Long 			struct aac_blockread *br;
123835863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
123935863739SMike Smith 			br->Command = VM_CtBlockRead;
124035863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
124135863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
124235863739SMike Smith 			br->ByteCount = bp->bio_bcount;
124335863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
124435863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
124535863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
124635863739SMike Smith 		} else {
1247b85f5808SScott Long 			struct aac_blockwrite *bw;
124835863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
124935863739SMike Smith 			bw->Command = VM_CtBlockWrite;
125035863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
125135863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
125235863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1253b85f5808SScott Long 			bw->Stable = CUNSTABLE;
125435863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
125535863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
125635863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
125735863739SMike Smith 		}
1258b85f5808SScott Long 	} else {
1259b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1260b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1261b85f5808SScott Long 			struct aac_blockread64 *br;
1262b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1263b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1264b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1265b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1266b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1267b85f5808SScott Long 			br->Pad = 0;
1268b85f5808SScott Long 			br->Flags = 0;
1269b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
127054e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAIN;
1271eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1272b85f5808SScott Long 		} else {
1273b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1274b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1275b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1276b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1277b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1278b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1279b85f5808SScott Long 			bw->Pad = 0;
1280b85f5808SScott Long 			bw->Flags = 0;
1281b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
128254e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAOUT;
1283eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1284b85f5808SScott Long 		}
1285b85f5808SScott Long 	}
128635863739SMike Smith 
128735863739SMike Smith 	*cmp = cm;
128835863739SMike Smith 	return(0);
128935863739SMike Smith 
129035863739SMike Smith fail:
12917cb209f5SScott Long 	if (bp != NULL)
12927cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
129335863739SMike Smith 	if (cm != NULL)
129435863739SMike Smith 		aac_release_command(cm);
129535863739SMike Smith 	return(ENOMEM);
129635863739SMike Smith }
129735863739SMike Smith 
1298914da7d0SScott Long /*
129935863739SMike Smith  * Handle a bio-instigated command that has been completed.
130035863739SMike Smith  */
130135863739SMike Smith static void
130235863739SMike Smith aac_bio_complete(struct aac_command *cm)
130335863739SMike Smith {
130435863739SMike Smith 	struct aac_blockread_response *brr;
130535863739SMike Smith 	struct aac_blockwrite_response *bwr;
130635863739SMike Smith 	struct bio *bp;
130735863739SMike Smith 	AAC_FSAStatus status;
130835863739SMike Smith 
130935863739SMike Smith 	/* fetch relevant status and then release the command */
131035863739SMike Smith 	bp = (struct bio *)cm->cm_private;
13119e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
131235863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
131335863739SMike Smith 		status = brr->Status;
131435863739SMike Smith 	} else {
131535863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
131635863739SMike Smith 		status = bwr->Status;
131735863739SMike Smith 	}
131835863739SMike Smith 	aac_release_command(cm);
131935863739SMike Smith 
132035863739SMike Smith 	/* fix up the bio based on status */
132135863739SMike Smith 	if (status == ST_OK) {
132235863739SMike Smith 		bp->bio_resid = 0;
132335863739SMike Smith 	} else {
132435863739SMike Smith 		bp->bio_error = EIO;
132535863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
13260b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1327914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1328914da7d0SScott Long 						    status);
132935863739SMike Smith 	}
13300b94a66eSMike Smith 	aac_biodone(bp);
133135863739SMike Smith }
133235863739SMike Smith 
1333914da7d0SScott Long /*
133435863739SMike Smith  * Submit a command to the controller, return when it completes.
1335b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1336b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1337d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1338d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1339d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1340d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1341d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
134235863739SMike Smith  */
134335863739SMike Smith static int
1344d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
134535863739SMike Smith {
1346ae543596SScott Long 	struct aac_softc *sc;
1347d8a0a473SScott Long 	int error;
134835863739SMike Smith 
1349ae543596SScott Long 	sc = cm->cm_sc;
135031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1351ae543596SScott Long 
135235863739SMike Smith 	/* Put the command on the ready queue and get things going */
135335863739SMike Smith 	aac_enqueue_ready(cm);
1354ae543596SScott Long 	aac_startio(sc);
1355ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
135635863739SMike Smith 	return(error);
135735863739SMike Smith }
135835863739SMike Smith 
1359914da7d0SScott Long /*
1360914da7d0SScott Long  *Command Buffer Management
1361914da7d0SScott Long  */
136235863739SMike Smith 
1363914da7d0SScott Long /*
136435863739SMike Smith  * Allocate a command.
136535863739SMike Smith  */
1366fe3cb0e1SScott Long int
136735863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
136835863739SMike Smith {
136935863739SMike Smith 	struct aac_command *cm;
137035863739SMike Smith 
137131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
137235863739SMike Smith 
1373ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1374b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1375ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1376ae543596SScott Long 			wakeup(sc->aifthread);
1377b85f5808SScott Long 		}
1378ae543596SScott Long 		return (EBUSY);
1379ffb37f33SScott Long 	}
138035863739SMike Smith 
13810b94a66eSMike Smith 	*cmp = cm;
13820b94a66eSMike Smith 	return(0);
13830b94a66eSMike Smith }
13840b94a66eSMike Smith 
1385914da7d0SScott Long /*
13860b94a66eSMike Smith  * Release a command back to the freelist.
13870b94a66eSMike Smith  */
1388fe3cb0e1SScott Long void
13890b94a66eSMike Smith aac_release_command(struct aac_command *cm)
13900b94a66eSMike Smith {
13917cb209f5SScott Long 	struct aac_event *event;
13927cb209f5SScott Long 	struct aac_softc *sc;
13937cb209f5SScott Long 
139431a0399eSEd Maste 	sc = cm->cm_sc;
139531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
13960b94a66eSMike Smith 
13974109ba51SEd Maste 	/* (re)initialize the command/FIB */
139835863739SMike Smith 	cm->cm_sgtable = NULL;
139935863739SMike Smith 	cm->cm_flags = 0;
140035863739SMike Smith 	cm->cm_complete = NULL;
140135863739SMike Smith 	cm->cm_private = NULL;
1402dbfc5960SEd Maste 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
140335863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
140435863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
140535863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
14067cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
140735863739SMike Smith 
140835863739SMike Smith 	/*
140935863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
141035863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
14114109ba51SEd Maste 	 * initialized here for debugging purposes only.
141235863739SMike Smith 	 */
1413f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1414f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
141535863739SMike Smith 
141635863739SMike Smith 	aac_enqueue_free(cm);
14177cb209f5SScott Long 
1418eb5cbaa0SEd Maste 	/*
1419eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1420eb5cbaa0SEd Maste 	 * stranded.
1421eb5cbaa0SEd Maste 	 */
1422eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
14237cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
14247cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
14257cb209f5SScott Long 	}
142635863739SMike Smith }
142735863739SMike Smith 
1428914da7d0SScott Long /*
14290b94a66eSMike Smith  * Map helper for command/FIB allocation.
143035863739SMike Smith  */
143135863739SMike Smith static void
14320b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
143335863739SMike Smith {
14347cb209f5SScott Long 	uint64_t	*fibphys;
1435914da7d0SScott Long 
14367cb209f5SScott Long 	fibphys = (uint64_t *)arg;
143735863739SMike Smith 
1438ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
143935863739SMike Smith }
144035863739SMike Smith 
1441914da7d0SScott Long /*
14424109ba51SEd Maste  * Allocate and initialize commands/FIBs for this adapter.
144335863739SMike Smith  */
14440b94a66eSMike Smith static int
14450b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
144635863739SMike Smith {
144735863739SMike Smith 	struct aac_command *cm;
1448ffb37f33SScott Long 	struct aac_fibmap *fm;
14497cb209f5SScott Long 	uint64_t fibphys;
1450ffb37f33SScott Long 	int i, error;
145135863739SMike Smith 
145231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
145335863739SMike Smith 
14547cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1455ffb37f33SScott Long 		return (ENOMEM);
1456ffb37f33SScott Long 
14578480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1458a6d35632SScott Long 	if (fm == NULL)
1459a6d35632SScott Long 		return (ENOMEM);
1460ffb37f33SScott Long 
14610b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1462ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1463ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
146470545d1aSScott Long 		device_printf(sc->aac_dev,
146570545d1aSScott Long 			      "Not enough contiguous memory available.\n");
14668480cc63SScott Long 		free(fm, M_AACBUF);
14670b94a66eSMike Smith 		return (ENOMEM);
146835863739SMike Smith 	}
1469128aa5a0SScott Long 
1470cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1471cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
14727cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1473ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1474128aa5a0SScott Long 
14754109ba51SEd Maste 	/* initialize constant fields in the command structure */
14767cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
14777cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
14788480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1479ffb37f33SScott Long 		fm->aac_commands = cm;
148035863739SMike Smith 		cm->cm_sc = sc;
14817cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
14827cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
14837cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1484cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
148535863739SMike Smith 
1486ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
148793cfca22SScott Long 					       &cm->cm_datamap)) != 0)
14888480cc63SScott Long 			break;
148993cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
149093cfca22SScott Long 		aac_release_command(cm);
14918480cc63SScott Long 		sc->total_fibs++;
149293cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
149335863739SMike Smith 	}
1494ffb37f33SScott Long 
14958480cc63SScott Long 	if (i > 0) {
149693cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1497ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
149831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1499bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
15000b94a66eSMike Smith 		return (0);
150135863739SMike Smith 	}
150235863739SMike Smith 
15038480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
15048480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15058480cc63SScott Long 	free(fm, M_AACBUF);
15068480cc63SScott Long 	return (ENOMEM);
15078480cc63SScott Long }
15088480cc63SScott Long 
1509914da7d0SScott Long /*
15100b94a66eSMike Smith  * Free FIBs owned by this adapter.
151135863739SMike Smith  */
151235863739SMike Smith static void
15138480cc63SScott Long aac_free_commands(struct aac_softc *sc)
151435863739SMike Smith {
15158480cc63SScott Long 	struct aac_fibmap *fm;
1516ffb37f33SScott Long 	struct aac_command *cm;
151735863739SMike Smith 	int i;
151835863739SMike Smith 
151931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
152035863739SMike Smith 
15218480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
15228480cc63SScott Long 
15238480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
15248480cc63SScott Long 		/*
15258480cc63SScott Long 		 * We check against total_fibs to handle partially
15268480cc63SScott Long 		 * allocated blocks.
15278480cc63SScott Long 		 */
15287cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1529ffb37f33SScott Long 			cm = fm->aac_commands + i;
1530ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1531ffb37f33SScott Long 		}
1532ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1533ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15348480cc63SScott Long 		free(fm, M_AACBUF);
15358480cc63SScott Long 	}
153635863739SMike Smith }
153735863739SMike Smith 
1538914da7d0SScott Long /*
153935863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
154035863739SMike Smith  */
154135863739SMike Smith static void
154235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
154335863739SMike Smith {
1544cd481291SScott Long 	struct aac_softc *sc;
1545914da7d0SScott Long 	struct aac_command *cm;
1546914da7d0SScott Long 	struct aac_fib *fib;
154735863739SMike Smith 	int i;
154835863739SMike Smith 
1549914da7d0SScott Long 	cm = (struct aac_command *)arg;
1550cd481291SScott Long 	sc = cm->cm_sc;
1551914da7d0SScott Long 	fib = cm->cm_fib;
155231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1553914da7d0SScott Long 
155435863739SMike Smith 	/* copy into the FIB */
1555b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
15567cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
15577cb209f5SScott Long 			struct aac_sg_tableraw *sg;
15587cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
15597cb209f5SScott Long 			sg->SgCount = nseg;
15607cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
15617cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
15627cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
15637cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
15647cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
15657cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
15667cb209f5SScott Long 			}
15677cb209f5SScott Long 			/* update the FIB size for the s/g count */
15687cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
15697cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1570b85f5808SScott Long 			struct aac_sg_table *sg;
1571b85f5808SScott Long 			sg = cm->cm_sgtable;
157235863739SMike Smith 			sg->SgCount = nseg;
157335863739SMike Smith 			for (i = 0; i < nseg; i++) {
157435863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
157535863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
157635863739SMike Smith 			}
157735863739SMike Smith 			/* update the FIB size for the s/g count */
157835863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1579b85f5808SScott Long 		} else {
1580b85f5808SScott Long 			struct aac_sg_table64 *sg;
1581b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1582b85f5808SScott Long 			sg->SgCount = nseg;
1583b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1584b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1585b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
158635863739SMike Smith 			}
1587b85f5808SScott Long 			/* update the FIB size for the s/g count */
1588b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1589b85f5808SScott Long 		}
1590b85f5808SScott Long 	}
159135863739SMike Smith 
1592cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1593cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
15947cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
15957cb209f5SScott Long 	 * and for the AIF bit
159635863739SMike Smith 	 */
15977cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
15987cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
159935863739SMike Smith 
1600cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1601cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
160235863739SMike Smith 
160335863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1604c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1605c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
160635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1607c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1608c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
160935863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1610cd481291SScott Long 
16117cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
16127cb209f5SScott Long 		int count = 10000000L;
16137cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
16147cb209f5SScott Long 			if (--count == 0) {
16157cb209f5SScott Long 				aac_unmap_command(cm);
16167cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
16177cb209f5SScott Long 				aac_requeue_ready(cm);
16187cb209f5SScott Long 			}
16197cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
16207cb209f5SScott Long 		}
16217cb209f5SScott Long 	} else {
1622397fa34fSScott Long 		/* Put the FIB on the outbound queue */
16234102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
16244102d44bSScott Long 			aac_unmap_command(cm);
1625397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1626cd481291SScott Long 			aac_requeue_ready(cm);
16274102d44bSScott Long 		}
16287cb209f5SScott Long 	}
1629cd481291SScott Long 
1630cd481291SScott Long 	return;
163135863739SMike Smith }
163235863739SMike Smith 
1633914da7d0SScott Long /*
163435863739SMike Smith  * Unmap a command from controller-visible space.
163535863739SMike Smith  */
163635863739SMike Smith static void
163735863739SMike Smith aac_unmap_command(struct aac_command *cm)
163835863739SMike Smith {
1639914da7d0SScott Long 	struct aac_softc *sc;
164035863739SMike Smith 
1641914da7d0SScott Long 	sc = cm->cm_sc;
164231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1643914da7d0SScott Long 
164435863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
164535863739SMike Smith 		return;
164635863739SMike Smith 
164735863739SMike Smith 	if (cm->cm_datalen != 0) {
164835863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1649c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1650c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
165135863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1652c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1653c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
165435863739SMike Smith 
165535863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
165635863739SMike Smith 	}
165735863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
165835863739SMike Smith }
165935863739SMike Smith 
1660914da7d0SScott Long /*
1661914da7d0SScott Long  * Hardware Interface
1662914da7d0SScott Long  */
166335863739SMike Smith 
1664914da7d0SScott Long /*
16654109ba51SEd Maste  * Initialize the adapter.
166635863739SMike Smith  */
166735863739SMike Smith static void
166835863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
166935863739SMike Smith {
1670914da7d0SScott Long 	struct aac_softc *sc;
167135863739SMike Smith 
1672914da7d0SScott Long 	sc = (struct aac_softc *)arg;
167331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1674914da7d0SScott Long 
167535863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
167635863739SMike Smith }
167735863739SMike Smith 
1678a6d35632SScott Long static int
1679a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1680a6d35632SScott Long {
168104f4d586SEd Maste 	u_int32_t code, major, minor, options = 0, atu_size = 0;
1682a441b3fcSScott Long 	int status;
168304f4d586SEd Maste 	time_t then;
1684a6d35632SScott Long 
168531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
168604f4d586SEd Maste 	/*
168704f4d586SEd Maste 	 * Wait for the adapter to come ready.
168804f4d586SEd Maste 	 */
168904f4d586SEd Maste 	then = time_uptime;
169004f4d586SEd Maste 	do {
169104f4d586SEd Maste 		code = AAC_GET_FWSTATUS(sc);
169204f4d586SEd Maste 		if (code & AAC_SELF_TEST_FAILED) {
169304f4d586SEd Maste 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
169404f4d586SEd Maste 			return(ENXIO);
169504f4d586SEd Maste 		}
169604f4d586SEd Maste 		if (code & AAC_KERNEL_PANIC) {
169704f4d586SEd Maste 			device_printf(sc->aac_dev,
1698a620bad0SEd Maste 				      "FATAL: controller kernel panic");
169904f4d586SEd Maste 			return(ENXIO);
170004f4d586SEd Maste 		}
170104f4d586SEd Maste 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
170204f4d586SEd Maste 			device_printf(sc->aac_dev,
170304f4d586SEd Maste 				      "FATAL: controller not coming ready, "
170404f4d586SEd Maste 					   "status %x\n", code);
170504f4d586SEd Maste 			return(ENXIO);
170604f4d586SEd Maste 		}
170704f4d586SEd Maste 	} while (!(code & AAC_UP_AND_RUNNING));
1708a6d35632SScott Long 
1709fe94b852SScott Long 	/*
1710fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1711fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1712fe94b852SScott Long 	 */
1713a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1714fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1715fe94b852SScott Long 				     NULL)) {
1716fe94b852SScott Long 			device_printf(sc->aac_dev,
1717fe94b852SScott Long 				      "Error reading firmware version\n");
1718fe94b852SScott Long 			return (EIO);
1719fe94b852SScott Long 		}
1720fe94b852SScott Long 
1721fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1722a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1723a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1724fe94b852SScott Long 		if (major == 1) {
1725fe94b852SScott Long 			device_printf(sc->aac_dev,
1726fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1727fe94b852SScott Long 			    major, minor);
1728fe94b852SScott Long 			return (EINVAL);
1729fe94b852SScott Long 		}
1730fe94b852SScott Long 	}
1731fe94b852SScott Long 
1732a6d35632SScott Long 	/*
1733a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1734a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1735a441b3fcSScott Long 	 * command.
1736a6d35632SScott Long 	 */
1737a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1738a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1739a441b3fcSScott Long 			device_printf(sc->aac_dev,
1740a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1741a6d35632SScott Long 			return (EIO);
1742a6d35632SScott Long 		}
1743a441b3fcSScott Long 	} else {
1744a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
17457cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1746a6d35632SScott Long 		sc->supported_options = options;
1747a6d35632SScott Long 
1748a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1749a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1750a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1751a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1752a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1753cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1754cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1755a441b3fcSScott Long 			device_printf(sc->aac_dev,
1756a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1757a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1758a6d35632SScott Long 		}
1759a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1760a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
17617cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
17627cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
17637cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1764a441b3fcSScott Long 	}
1765a6d35632SScott Long 
1766a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
17677cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
17687cb209f5SScott Long 
17697cb209f5SScott Long 	/* Remap mem. resource, if required */
17707cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1771ff0991c4SAttilio Rao 		atu_size > rman_get_size(sc->aac_regs_res1)) {
17727cb209f5SScott Long 		bus_release_resource(
17737cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
1774ff0991c4SAttilio Rao 			sc->aac_regs_rid1, sc->aac_regs_res1);
1775ff0991c4SAttilio Rao 		sc->aac_regs_res1 = bus_alloc_resource(
1776ff0991c4SAttilio Rao 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1,
17777cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
1778ff0991c4SAttilio Rao 		if (sc->aac_regs_res1 == NULL) {
1779ff0991c4SAttilio Rao 			sc->aac_regs_res1 = bus_alloc_resource_any(
17807cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
1781ff0991c4SAttilio Rao 				&sc->aac_regs_rid1, RF_ACTIVE);
1782ff0991c4SAttilio Rao 			if (sc->aac_regs_res1 == NULL) {
17837cb209f5SScott Long 				device_printf(sc->aac_dev,
17847cb209f5SScott Long 				    "couldn't allocate register window\n");
17857cb209f5SScott Long 				return (ENXIO);
17867cb209f5SScott Long 			}
17877cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
17887cb209f5SScott Long 		}
1789ff0991c4SAttilio Rao 		sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1);
1790ff0991c4SAttilio Rao 		sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1);
1791ff0991c4SAttilio Rao 
1792ff0991c4SAttilio Rao 		if (sc->aac_hwif == AAC_HWIF_NARK) {
1793ff0991c4SAttilio Rao 			sc->aac_regs_res0 = sc->aac_regs_res1;
1794ff0991c4SAttilio Rao 			sc->aac_regs_rid0 = sc->aac_regs_rid1;
1795ff0991c4SAttilio Rao 			sc->aac_btag0 = sc->aac_btag1;
1796ff0991c4SAttilio Rao 			sc->aac_bhandle0 = sc->aac_bhandle1;
1797ff0991c4SAttilio Rao 		}
17987cb209f5SScott Long 	}
17997cb209f5SScott Long 
18007cb209f5SScott Long 	/* Read preferred settings */
18017cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
18027cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
18037cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1804a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18057e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
18067e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1807a6d35632SScott Long 	else
1808a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18097e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
18107e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1811a441b3fcSScott Long 
18127cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
18137cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
18147cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
18157cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
18167cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
18177cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
18187cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
18197cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
18207cb209f5SScott Long 	}
18217cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
18227cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
18237cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1824a6d35632SScott Long 
1825f355c0e0SEd Maste 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1826f355c0e0SEd Maste 		sc->flags |= AAC_FLAGS_RAW_IO;
1827f355c0e0SEd Maste 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1828f355c0e0SEd Maste 	}
1829523da39bSEd Maste 	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1830523da39bSEd Maste 	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1831523da39bSEd Maste 		sc->flags |= AAC_FLAGS_LBA_64BIT;
1832523da39bSEd Maste 		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1833523da39bSEd Maste 	}
1834f355c0e0SEd Maste 
1835fe94b852SScott Long 	return (0);
1836fe94b852SScott Long }
1837fe94b852SScott Long 
183835863739SMike Smith static int
183935863739SMike Smith aac_init(struct aac_softc *sc)
184035863739SMike Smith {
184135863739SMike Smith 	struct aac_adapter_init	*ip;
184204f4d586SEd Maste 	u_int32_t qoffset;
1843a6d35632SScott Long 	int error;
184435863739SMike Smith 
184531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1846ffb37f33SScott Long 
184735863739SMike Smith 	/*
1848914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1849914da7d0SScott Long 	 * physical location of various important shared data structures.
185035863739SMike Smith 	 */
185135863739SMike Smith 	ip = &sc->aac_common->ac_init;
185235863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18537cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18547cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18557cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18567cb209f5SScott Long 	}
1857f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
185835863739SMike Smith 
1859c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1860c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1861149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
186235863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
186335863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
186435863739SMike Smith 
1865c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1866c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
186735863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
186835863739SMike Smith 
18694b00f859SScott Long 	/*
18704b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18714b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18724b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18734b00f859SScott Long 	 * Round up since the granularity is so high.
18744b00f859SScott Long 	 */
1875f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18764b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18774b00f859SScott Long 		ip->HostPhysMemPages =
18784b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1879204c0befSScott Long 	}
18802b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
188135863739SMike Smith 
18827cb209f5SScott Long 	ip->InitFlags = 0;
18837cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1884e71d3b9cSEd Maste 		ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED;
18857cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
18867cb209f5SScott Long 	}
18877cb209f5SScott Long 
18887cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
18897cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
18907cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
18917cb209f5SScott Long 
189235863739SMike Smith 	/*
18934109ba51SEd Maste 	 * Initialize FIB queues.  Note that it appears that the layout of the
1894c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1895c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
189635863739SMike Smith 	 *
189735863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1898914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1899914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1900914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1901914da7d0SScott Long 	 * does.
190235863739SMike Smith 	 *
1903914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1904914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1905914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1906914da7d0SScott Long 	 * virtue of a table.
190735863739SMike Smith 	 */
1908b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
19090bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
19100bcbebd6SScott Long 	sc->aac_queues =
19110bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1912b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
191335863739SMike Smith 
1914c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1915c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1916c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1917c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1918c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1919c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1920c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1921c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1922c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1923c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1924c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1925c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1926c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1927c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1928c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1929c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1930c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1931c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1932c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1933c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1934c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1935c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1936c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1937c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1938c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1939c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1940c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1941c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1942c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1943c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1944c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1945c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1946c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1947c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1948c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1949c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1950c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1951c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1952c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1953c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1954c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1955c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1956c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1957c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1958c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1959c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1960c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1961c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
196235863739SMike Smith 
196335863739SMike Smith 	/*
196435863739SMike Smith 	 * Do controller-type-specific initialisation
196535863739SMike Smith 	 */
196635863739SMike Smith 	switch (sc->aac_hwif) {
196735863739SMike Smith 	case AAC_HWIF_I960RX:
1968ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0);
196935863739SMike Smith 		break;
19704afedc31SScott Long 	case AAC_HWIF_RKT:
1971ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0);
19724afedc31SScott Long 		break;
19734afedc31SScott Long 	default:
19744afedc31SScott Long 		break;
197535863739SMike Smith 	}
197635863739SMike Smith 
197735863739SMike Smith 	/*
197835863739SMike Smith 	 * Give the init structure to the controller.
197935863739SMike Smith 	 */
198035863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1981914da7d0SScott Long 			     sc->aac_common_busaddr +
1982914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1983914da7d0SScott Long 			     NULL)) {
1984914da7d0SScott Long 		device_printf(sc->aac_dev,
1985914da7d0SScott Long 			      "error establishing init structure\n");
1986a6d35632SScott Long 		error = EIO;
1987a6d35632SScott Long 		goto out;
198835863739SMike Smith 	}
198935863739SMike Smith 
1990a6d35632SScott Long 	error = 0;
1991a6d35632SScott Long out:
1992a6d35632SScott Long 	return(error);
199335863739SMike Smith }
199435863739SMike Smith 
199504f4d586SEd Maste static int
199604f4d586SEd Maste aac_setup_intr(struct aac_softc *sc)
199704f4d586SEd Maste {
199804f4d586SEd Maste 	sc->aac_irq_rid = 0;
199904f4d586SEd Maste 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
200004f4d586SEd Maste 			   			  &sc->aac_irq_rid,
200104f4d586SEd Maste 			   			  RF_SHAREABLE |
200204f4d586SEd Maste 						  RF_ACTIVE)) == NULL) {
200304f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
200404f4d586SEd Maste 		return (EINVAL);
200504f4d586SEd Maste 	}
200604f4d586SEd Maste 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
200704f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
200804f4d586SEd Maste 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
200904f4d586SEd Maste 				   aac_new_intr, sc, &sc->aac_intr)) {
201004f4d586SEd Maste 			device_printf(sc->aac_dev, "can't set up interrupt\n");
201104f4d586SEd Maste 			return (EINVAL);
201204f4d586SEd Maste 		}
201304f4d586SEd Maste 	} else {
201404f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2015e46b9eeaSEd Maste 				   INTR_TYPE_BIO, aac_filter, NULL,
201604f4d586SEd Maste 				   sc, &sc->aac_intr)) {
201704f4d586SEd Maste 			device_printf(sc->aac_dev,
2018e46b9eeaSEd Maste 				      "can't set up interrupt filter\n");
201904f4d586SEd Maste 			return (EINVAL);
202004f4d586SEd Maste 		}
202104f4d586SEd Maste 	}
202204f4d586SEd Maste 	return (0);
202304f4d586SEd Maste }
202404f4d586SEd Maste 
2025914da7d0SScott Long /*
202635863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
20277cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
202835863739SMike Smith  */
202935863739SMike Smith static int
203035863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
203135863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
203235863739SMike Smith 		 u_int32_t *sp)
203335863739SMike Smith {
203435863739SMike Smith 	time_t then;
203535863739SMike Smith 	u_int32_t status;
203635863739SMike Smith 
203731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
203835863739SMike Smith 
203935863739SMike Smith 	/* populate the mailbox */
204035863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
204135863739SMike Smith 
204235863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
204335863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
204435863739SMike Smith 
204535863739SMike Smith 	/* then set it to signal the adapter */
204635863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
204735863739SMike Smith 
204835863739SMike Smith 	/* spin waiting for the command to complete */
20492b3b0f17SScott Long 	then = time_uptime;
205035863739SMike Smith 	do {
20512b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
205231a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
205335863739SMike Smith 			return(EIO);
205435863739SMike Smith 		}
205535863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
205635863739SMike Smith 
205735863739SMike Smith 	/* clear the completion flag */
205835863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
205935863739SMike Smith 
206035863739SMike Smith 	/* get the command status */
2061a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
206235863739SMike Smith 	if (sp != NULL)
206335863739SMike Smith 		*sp = status;
20647cb209f5SScott Long 
2065a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20667cb209f5SScott Long 		return (-1);
20670b94a66eSMike Smith 	return(0);
206835863739SMike Smith }
206935863739SMike Smith 
2070cbfd045bSScott Long int
207135863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2072cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
207335863739SMike Smith {
207431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
20757cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
207635863739SMike Smith 
207735863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
207835863739SMike Smith 		return(EINVAL);
207935863739SMike Smith 
208035863739SMike Smith 	/*
208135863739SMike Smith 	 * Set up the sync FIB
208235863739SMike Smith 	 */
2083914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2084914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2085c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
208635863739SMike Smith 	fib->Header.XferState |= xferstate;
208735863739SMike Smith 	fib->Header.Command = command;
208835863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
208942ef13a2SEd Maste 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
209035863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2091b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2092c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2093914da7d0SScott Long 					 offsetof(struct aac_common,
2094914da7d0SScott Long 						  ac_sync_fib);
209535863739SMike Smith 
209635863739SMike Smith 	/*
209735863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
209835863739SMike Smith 	 */
2099914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2100914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
210131a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
210235863739SMike Smith 		return(EIO);
210335863739SMike Smith 	}
210435863739SMike Smith 
210535863739SMike Smith 	return (0);
210635863739SMike Smith }
210735863739SMike Smith 
2108914da7d0SScott Long /*
210935863739SMike Smith  * Adapter-space FIB queue manipulation
211035863739SMike Smith  *
211135863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
211235863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
211335863739SMike Smith  */
211435863739SMike Smith static struct {
211535863739SMike Smith 	int		size;
211635863739SMike Smith 	int		notify;
211735863739SMike Smith } aac_qinfo[] = {
211835863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
211935863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
212035863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
212135863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
212235863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
212335863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
212435863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
212535863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
212635863739SMike Smith };
212735863739SMike Smith 
212835863739SMike Smith /*
2129c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2130c6eafcf2SScott Long  * EBUSY if the queue is full.
213135863739SMike Smith  *
21320b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2133914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2134914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2135c6eafcf2SScott Long  *	 separate queue/notify interface).
213635863739SMike Smith  */
213735863739SMike Smith static int
2138f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
213935863739SMike Smith {
214035863739SMike Smith 	u_int32_t pi, ci;
21419e2e96d8SScott Long 	int error;
2142f6c4dd3fSScott Long 	u_int32_t fib_size;
2143f6c4dd3fSScott Long 	u_int32_t fib_addr;
2144f6c4dd3fSScott Long 
214531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
214636e0bf6eSScott Long 
2147f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2148f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
214935863739SMike Smith 
215035863739SMike Smith 	/* get the producer/consumer indices */
215135863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
215235863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
215335863739SMike Smith 
215435863739SMike Smith 	/* wrap the queue? */
215535863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
215635863739SMike Smith 		pi = 0;
215735863739SMike Smith 
215835863739SMike Smith 	/* check for queue full */
215935863739SMike Smith 	if ((pi + 1) == ci) {
216035863739SMike Smith 		error = EBUSY;
216135863739SMike Smith 		goto out;
216235863739SMike Smith 	}
216335863739SMike Smith 
2164614c22b2SScott Long 	/*
2165614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2166614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2167614c22b2SScott Long 	 */
2168614c22b2SScott Long 	aac_enqueue_busy(cm);
2169614c22b2SScott Long 
217035863739SMike Smith 	/* populate queue entry */
217135863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
217235863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
217335863739SMike Smith 
217435863739SMike Smith 	/* update producer index */
217535863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
217635863739SMike Smith 
217735863739SMike Smith 	/* notify the adapter if we know how */
217835863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
217935863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
218035863739SMike Smith 
218135863739SMike Smith 	error = 0;
218235863739SMike Smith 
218335863739SMike Smith out:
218435863739SMike Smith 	return(error);
218535863739SMike Smith }
218635863739SMike Smith 
218735863739SMike Smith /*
218836e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
218936e0bf6eSScott Long  * success or ENOENT if the queue is empty.
219035863739SMike Smith  */
219135863739SMike Smith static int
2192c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2193c6eafcf2SScott Long 		struct aac_fib **fib_addr)
219435863739SMike Smith {
219535863739SMike Smith 	u_int32_t pi, ci;
2196149af931SScott Long 	u_int32_t fib_index;
21979e2e96d8SScott Long 	int error;
2198f6c4dd3fSScott Long 	int notify;
219935863739SMike Smith 
220031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
220135863739SMike Smith 
220235863739SMike Smith 	/* get the producer/consumer indices */
220335863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
220435863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
220535863739SMike Smith 
220635863739SMike Smith 	/* check for queue empty */
220735863739SMike Smith 	if (ci == pi) {
220835863739SMike Smith 		error = ENOENT;
220935863739SMike Smith 		goto out;
221035863739SMike Smith 	}
221135863739SMike Smith 
22127753acd2SScott Long 	/* wrap the pi so the following test works */
22137753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
22147753acd2SScott Long 		pi = 0;
22157753acd2SScott Long 
2216f6c4dd3fSScott Long 	notify = 0;
2217f6c4dd3fSScott Long 	if (ci == pi + 1)
2218f6c4dd3fSScott Long 		notify++;
2219f6c4dd3fSScott Long 
222035863739SMike Smith 	/* wrap the queue? */
222135863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
222235863739SMike Smith 		ci = 0;
222335863739SMike Smith 
222435863739SMike Smith 	/* fetch the entry */
222535863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2226149af931SScott Long 
2227149af931SScott Long 	switch (queue) {
2228149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2229149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2230149af931SScott Long 		/*
2231149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2232149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2233149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2234149af931SScott Long 		 * Therefore, we have to convert it to an index.
2235149af931SScott Long 		 */
2236149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2237149af931SScott Long 			sizeof(struct aac_fib);
2238149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2239149af931SScott Long 		break;
2240149af931SScott Long 
2241149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2242149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2243149af931SScott Long 	{
2244149af931SScott Long 		struct aac_command *cm;
2245149af931SScott Long 
2246149af931SScott Long 		/*
2247149af931SScott Long 		 * As above, an index is used instead of an actual address.
2248149af931SScott Long 		 * Gotta shift the index to account for the fast response
2249149af931SScott Long 		 * bit.  No other correction is needed since this value was
2250149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2251149af931SScott Long 		 * field.
2252149af931SScott Long 		 */
2253149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22547cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2255149af931SScott Long 		*fib_addr = cm->cm_fib;
225635863739SMike Smith 
2257f30ac74cSScott Long 		/*
2258f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2259149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2260f30ac74cSScott Long 		 */
2261149af931SScott Long 		if (fib_index & 0x01) {
2262f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2263f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2264f30ac74cSScott Long 		}
2265149af931SScott Long 		break;
2266149af931SScott Long 	}
2267149af931SScott Long 	default:
2268149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2269149af931SScott Long 		break;
2270149af931SScott Long 	}
2271149af931SScott Long 
227235863739SMike Smith 	/* update consumer index */
227335863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
227435863739SMike Smith 
227535863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2276f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
227735863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
227835863739SMike Smith 	error = 0;
227935863739SMike Smith 
228035863739SMike Smith out:
228135863739SMike Smith 	return(error);
228235863739SMike Smith }
228335863739SMike Smith 
2284914da7d0SScott Long /*
228536e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
228636e0bf6eSScott Long  */
228736e0bf6eSScott Long static int
228836e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
228936e0bf6eSScott Long {
229036e0bf6eSScott Long 	u_int32_t pi, ci;
22919e2e96d8SScott Long 	int error;
229236e0bf6eSScott Long 	u_int32_t fib_size;
229336e0bf6eSScott Long 	u_int32_t fib_addr;
229436e0bf6eSScott Long 
229531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
229636e0bf6eSScott Long 
229736e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
229836e0bf6eSScott Long 	fib_size = fib->Header.Size;
229936e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
230036e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
230136e0bf6eSScott Long 
230236e0bf6eSScott Long 	/* get the producer/consumer indices */
230336e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
230436e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
230536e0bf6eSScott Long 
230636e0bf6eSScott Long 	/* wrap the queue? */
230736e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
230836e0bf6eSScott Long 		pi = 0;
230936e0bf6eSScott Long 
231036e0bf6eSScott Long 	/* check for queue full */
231136e0bf6eSScott Long 	if ((pi + 1) == ci) {
231236e0bf6eSScott Long 		error = EBUSY;
231336e0bf6eSScott Long 		goto out;
231436e0bf6eSScott Long 	}
231536e0bf6eSScott Long 
231636e0bf6eSScott Long 	/* populate queue entry */
231736e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
231836e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
231936e0bf6eSScott Long 
232036e0bf6eSScott Long 	/* update producer index */
232136e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
232236e0bf6eSScott Long 
232336e0bf6eSScott Long 	/* notify the adapter if we know how */
232436e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
232536e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
232636e0bf6eSScott Long 
232736e0bf6eSScott Long 	error = 0;
232836e0bf6eSScott Long 
232936e0bf6eSScott Long out:
233036e0bf6eSScott Long 	return(error);
233136e0bf6eSScott Long }
233236e0bf6eSScott Long 
2333914da7d0SScott Long /*
23340b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
23350b94a66eSMike Smith  * and complain about them.
23360b94a66eSMike Smith  */
23370b94a66eSMike Smith static void
23380b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
23390b94a66eSMike Smith {
23400b94a66eSMike Smith 	struct aac_command *cm;
23410b94a66eSMike Smith 	time_t deadline;
234215c37be0SScott Long 	int timedout, code;
23430b94a66eSMike Smith 
2344f6c4dd3fSScott Long 	/*
234570545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2346914da7d0SScott Long 	 * only.
2347914da7d0SScott Long 	 */
234815c37be0SScott Long 	timedout = 0;
23492b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23500b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2351f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
23523e507710SEd Maste 		    && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) {
23530b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2354914da7d0SScott Long 			device_printf(sc->aac_dev,
23555aa4bb5bSEd Maste 			    "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n",
23565aa4bb5bSEd Maste 			    cm, cm->cm_fib->Header.Command,
23575aa4bb5bSEd Maste 			    (int)(time_uptime-cm->cm_timestamp));
23580b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
235915c37be0SScott Long 			timedout++;
23600b94a66eSMike Smith 		}
23610b94a66eSMike Smith 	}
23620b94a66eSMike Smith 
236315c37be0SScott Long 	if (timedout) {
236415c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
236515c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
236615c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
236715c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
236815c37be0SScott Long 		}
236915c37be0SScott Long 	}
23700b94a66eSMike Smith 	return;
23710b94a66eSMike Smith }
23720b94a66eSMike Smith 
2373914da7d0SScott Long /*
2374914da7d0SScott Long  * Interface Function Vectors
2375914da7d0SScott Long  */
237635863739SMike Smith 
2377914da7d0SScott Long /*
237835863739SMike Smith  * Read the current firmware status word.
237935863739SMike Smith  */
238035863739SMike Smith static int
238135863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
238235863739SMike Smith {
238331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
238435863739SMike Smith 
2385ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS));
238635863739SMike Smith }
238735863739SMike Smith 
238835863739SMike Smith static int
238935863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
239035863739SMike Smith {
239131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
239235863739SMike Smith 
23934824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
23944824be88SEd Maste 	    AAC_RX_OMR0 : AAC_RX_FWSTATUS));
239535863739SMike Smith }
239635863739SMike Smith 
2397b3457b51SScott Long static int
23984afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
23994afedc31SScott Long {
240031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24014afedc31SScott Long 
24024824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
24034824be88SEd Maste 	    AAC_RKT_OMR0 : AAC_RKT_FWSTATUS));
24044afedc31SScott Long }
24054afedc31SScott Long 
2406914da7d0SScott Long /*
240735863739SMike Smith  * Notify the controller of a change in a given queue
240835863739SMike Smith  */
240935863739SMike Smith 
241035863739SMike Smith static void
241135863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
241235863739SMike Smith {
241331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241435863739SMike Smith 
2415ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
241635863739SMike Smith }
241735863739SMike Smith 
241835863739SMike Smith static void
241935863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
242035863739SMike Smith {
242131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
242235863739SMike Smith 
2423ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit);
242435863739SMike Smith }
242535863739SMike Smith 
2426b3457b51SScott Long static void
24274afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
24284afedc31SScott Long {
242931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24304afedc31SScott Long 
2431ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit);
24324afedc31SScott Long }
24334afedc31SScott Long 
2434914da7d0SScott Long /*
243535863739SMike Smith  * Get the interrupt reason bits
243635863739SMike Smith  */
243735863739SMike Smith static int
243835863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
243935863739SMike Smith {
244031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
244135863739SMike Smith 
2442ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0));
244335863739SMike Smith }
244435863739SMike Smith 
244535863739SMike Smith static int
244635863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
244735863739SMike Smith {
244831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
244935863739SMike Smith 
2450ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR));
245135863739SMike Smith }
245235863739SMike Smith 
2453b3457b51SScott Long static int
24544afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
24554afedc31SScott Long {
245631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24574afedc31SScott Long 
2458ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR));
24594afedc31SScott Long }
24604afedc31SScott Long 
2461914da7d0SScott Long /*
246235863739SMike Smith  * Clear some interrupt reason bits
246335863739SMike Smith  */
246435863739SMike Smith static void
246535863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
246635863739SMike Smith {
246731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
246835863739SMike Smith 
2469ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
247035863739SMike Smith }
247135863739SMike Smith 
247235863739SMike Smith static void
247335863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
247435863739SMike Smith {
247531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
247635863739SMike Smith 
2477ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask);
247835863739SMike Smith }
247935863739SMike Smith 
2480b3457b51SScott Long static void
24814afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
24824afedc31SScott Long {
248331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24844afedc31SScott Long 
2485ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask);
24864afedc31SScott Long }
24874afedc31SScott Long 
2488914da7d0SScott Long /*
248935863739SMike Smith  * Populate the mailbox and set the command word
249035863739SMike Smith  */
249135863739SMike Smith static void
249235863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
249335863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249435863739SMike Smith {
249531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
249635863739SMike Smith 
2497ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command);
2498ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2499ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2500ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2501ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
250235863739SMike Smith }
250335863739SMike Smith 
250435863739SMike Smith static void
250535863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
250635863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
250735863739SMike Smith {
250831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
250935863739SMike Smith 
2510ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command);
2511ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2512ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2513ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2514ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
251535863739SMike Smith }
251635863739SMike Smith 
2517b3457b51SScott Long static void
25184afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25194afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
25204afedc31SScott Long {
252131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25224afedc31SScott Long 
2523ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command);
2524ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2525ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2526ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2527ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
25284afedc31SScott Long }
25294afedc31SScott Long 
2530914da7d0SScott Long /*
253135863739SMike Smith  * Fetch the immediate command status word
253235863739SMike Smith  */
253335863739SMike Smith static int
2534a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
253535863739SMike Smith {
253631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
253735863739SMike Smith 
2538ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
253935863739SMike Smith }
254035863739SMike Smith 
254135863739SMike Smith static int
2542a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
254335863739SMike Smith {
254431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
254535863739SMike Smith 
2546ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
254735863739SMike Smith }
254835863739SMike Smith 
2549b3457b51SScott Long static int
25504afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
25514afedc31SScott Long {
255231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25534afedc31SScott Long 
2554ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
25554afedc31SScott Long }
25564afedc31SScott Long 
2557914da7d0SScott Long /*
255835863739SMike Smith  * Set/clear interrupt masks
255935863739SMike Smith  */
256035863739SMike Smith static void
256135863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
256235863739SMike Smith {
256331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
256435863739SMike Smith 
256535863739SMike Smith 	if (enable) {
2566ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
256735863739SMike Smith 	} else {
2568ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
256935863739SMike Smith 	}
257035863739SMike Smith }
257135863739SMike Smith 
257235863739SMike Smith static void
257335863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
257435863739SMike Smith {
257531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
257635863739SMike Smith 
257735863739SMike Smith 	if (enable) {
25787cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2579ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
25807cb209f5SScott Long 		else
2581ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
258235863739SMike Smith 	} else {
2583ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0);
258435863739SMike Smith 	}
258535863739SMike Smith }
258635863739SMike Smith 
2587b3457b51SScott Long static void
25884afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
25894afedc31SScott Long {
259031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
25914afedc31SScott Long 
25924afedc31SScott Long 	if (enable) {
25937cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2594ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
25957cb209f5SScott Long 		else
2596ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
25974afedc31SScott Long 	} else {
2598ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0);
25994afedc31SScott Long 	}
26004afedc31SScott Long }
26014afedc31SScott Long 
2602914da7d0SScott Long /*
26037cb209f5SScott Long  * New comm. interface: Send command functions
26047cb209f5SScott Long  */
26057cb209f5SScott Long static int
26067cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
26077cb209f5SScott Long {
26087cb209f5SScott Long 	u_int32_t index, device;
26097cb209f5SScott Long 
261031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
26117cb209f5SScott Long 
2612ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
26137cb209f5SScott Long 	if (index == 0xffffffffL)
2614ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
26157cb209f5SScott Long 	if (index == 0xffffffffL)
26167cb209f5SScott Long 		return index;
26177cb209f5SScott Long 	aac_enqueue_busy(cm);
26187cb209f5SScott Long 	device = index;
2619ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26207cb209f5SScott Long 	device += 4;
2621ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26227cb209f5SScott Long 	device += 4;
2623ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2624ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index);
26257cb209f5SScott Long 	return 0;
26267cb209f5SScott Long }
26277cb209f5SScott Long 
26287cb209f5SScott Long static int
26297cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
26307cb209f5SScott Long {
26317cb209f5SScott Long 	u_int32_t index, device;
26327cb209f5SScott Long 
263331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
26347cb209f5SScott Long 
2635ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
26367cb209f5SScott Long 	if (index == 0xffffffffL)
2637ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
26387cb209f5SScott Long 	if (index == 0xffffffffL)
26397cb209f5SScott Long 		return index;
26407cb209f5SScott Long 	aac_enqueue_busy(cm);
26417cb209f5SScott Long 	device = index;
2642ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26437cb209f5SScott Long 	device += 4;
2644ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26457cb209f5SScott Long 	device += 4;
2646ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2647ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index);
26487cb209f5SScott Long 	return 0;
26497cb209f5SScott Long }
26507cb209f5SScott Long 
26517cb209f5SScott Long /*
26527cb209f5SScott Long  * New comm. interface: get, set outbound queue index
26537cb209f5SScott Long  */
26547cb209f5SScott Long static int
26557cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
26567cb209f5SScott Long {
265731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26587cb209f5SScott Long 
2659ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE));
26607cb209f5SScott Long }
26617cb209f5SScott Long 
26627cb209f5SScott Long static int
26637cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
26647cb209f5SScott Long {
266531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26667cb209f5SScott Long 
2667ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE));
26687cb209f5SScott Long }
26697cb209f5SScott Long 
26707cb209f5SScott Long static void
26717cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
26727cb209f5SScott Long {
267331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26747cb209f5SScott Long 
2675ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index);
26767cb209f5SScott Long }
26777cb209f5SScott Long 
26787cb209f5SScott Long static void
26797cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
26807cb209f5SScott Long {
268131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26827cb209f5SScott Long 
2683ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index);
26847cb209f5SScott Long }
26857cb209f5SScott Long 
26867cb209f5SScott Long /*
2687914da7d0SScott Long  * Debugging and Diagnostics
2688914da7d0SScott Long  */
268935863739SMike Smith 
2690914da7d0SScott Long /*
269135863739SMike Smith  * Print some information about the controller.
269235863739SMike Smith  */
269335863739SMike Smith static void
269435863739SMike Smith aac_describe_controller(struct aac_softc *sc)
269535863739SMike Smith {
2696cbfd045bSScott Long 	struct aac_fib *fib;
269735863739SMike Smith 	struct aac_adapter_info	*info;
26987ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
269935863739SMike Smith 
270031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
270135863739SMike Smith 
270281b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
270303b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2704cbfd045bSScott Long 
2705cbfd045bSScott Long 	fib->data[0] = 0;
2706cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
270735863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2708fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
270981b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
271035863739SMike Smith 		return;
271135863739SMike Smith 	}
271235863739SMike Smith 
2713bd971c49SScott Long 	/* save the kernel revision structure for later use */
2714bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2715bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2716bd971c49SScott Long 
2717bd971c49SScott Long 	if (bootverbose) {
2718b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2719b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2720c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2721b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2722b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2723b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2724914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2725914da7d0SScott Long 		    info->batteryPlatform));
272635863739SMike Smith 
2727bd971c49SScott Long 		device_printf(sc->aac_dev,
2728bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
272935863739SMike Smith 		    info->KernelRevision.external.comp.major,
273035863739SMike Smith 		    info->KernelRevision.external.comp.minor,
273135863739SMike Smith 		    info->KernelRevision.external.comp.dash,
273236e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
273336e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2734fe3cb0e1SScott Long 
2735a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2736a6d35632SScott Long 			      sc->supported_options,
2737a6d35632SScott Long 			      "\20"
2738a6d35632SScott Long 			      "\1SNAPSHOT"
2739a6d35632SScott Long 			      "\2CLUSTERS"
2740a6d35632SScott Long 			      "\3WCACHE"
2741a6d35632SScott Long 			      "\4DATA64"
2742a6d35632SScott Long 			      "\5HOSTTIME"
2743a6d35632SScott Long 			      "\6RAID50"
2744a6d35632SScott Long 			      "\7WINDOW4GB"
2745a6d35632SScott Long 			      "\10SCSIUPGD"
2746a6d35632SScott Long 			      "\11SOFTERR"
2747a6d35632SScott Long 			      "\12NORECOND"
2748a6d35632SScott Long 			      "\13SGMAP64"
2749a6d35632SScott Long 			      "\14ALARM"
27507cb209f5SScott Long 			      "\15NONDASD"
27517cb209f5SScott Long 			      "\16SCSIMGT"
27527cb209f5SScott Long 			      "\17RAIDSCSI"
27537cb209f5SScott Long 			      "\21ADPTINFO"
27547cb209f5SScott Long 			      "\22NEWCOMM"
27557cb209f5SScott Long 			      "\23ARRAY64BIT"
27567cb209f5SScott Long 			      "\24HEATSENSOR");
2757a6d35632SScott Long 	}
275855aa1136SEd Maste 
275955aa1136SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
276055aa1136SEd Maste 		fib->data[0] = 0;
276155aa1136SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
276255aa1136SEd Maste 			device_printf(sc->aac_dev,
276355aa1136SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
276455aa1136SEd Maste 		else
276555aa1136SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
276655aa1136SEd Maste 			    &fib->data[0])->AdapterTypeText;
276755aa1136SEd Maste 	}
276855aa1136SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
276955aa1136SEd Maste 		adapter_type,
27708e7e6335SEd Maste 		AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION,
27718e7e6335SEd Maste 		AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD);
277255aa1136SEd Maste 
2773bd971c49SScott Long 	aac_release_sync_fib(sc);
277481b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
277535863739SMike Smith }
277635863739SMike Smith 
2777914da7d0SScott Long /*
277835863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
277935863739SMike Smith  * same.
278035863739SMike Smith  */
278135863739SMike Smith static char *
278235863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
278335863739SMike Smith {
278435863739SMike Smith 	int i;
278535863739SMike Smith 
278635863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
278735863739SMike Smith 		if (table[i].code == code)
278835863739SMike Smith 			return(table[i].string);
278935863739SMike Smith 	return(table[i + 1].string);
279035863739SMike Smith }
279135863739SMike Smith 
2792914da7d0SScott Long /*
2793914da7d0SScott Long  * Management Interface
2794914da7d0SScott Long  */
279535863739SMike Smith 
279635863739SMike Smith static int
279700b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
279835863739SMike Smith {
2799914da7d0SScott Long 	struct aac_softc *sc;
280035863739SMike Smith 
2801914da7d0SScott Long 	sc = dev->si_drv1;
280231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
280304f798ecSAttilio Rao 	device_busy(sc->aac_dev);
2804dfe2c294SAttilio Rao 	devfs_set_cdevpriv(sc, aac_cdevpriv_dtor);
280535863739SMike Smith 
280635863739SMike Smith 	return 0;
280735863739SMike Smith }
280835863739SMike Smith 
280935863739SMike Smith static int
281000b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
281135863739SMike Smith {
2812914da7d0SScott Long 	union aac_statrequest *as;
2813914da7d0SScott Long 	struct aac_softc *sc;
28140b94a66eSMike Smith 	int error = 0;
281535863739SMike Smith 
2816914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2817914da7d0SScott Long 	sc = dev->si_drv1;
281831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2819914da7d0SScott Long 
282035863739SMike Smith 	switch (cmd) {
28210b94a66eSMike Smith 	case AACIO_STATS:
28220b94a66eSMike Smith 		switch (as->as_item) {
28230b94a66eSMike Smith 		case AACQ_FREE:
28240b94a66eSMike Smith 		case AACQ_BIO:
28250b94a66eSMike Smith 		case AACQ_READY:
28260b94a66eSMike Smith 		case AACQ_BUSY:
2827c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2828c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
28290b94a66eSMike Smith 			break;
28300b94a66eSMike Smith 		default:
28310b94a66eSMike Smith 			error = ENOENT;
28320b94a66eSMike Smith 			break;
28330b94a66eSMike Smith 		}
28340b94a66eSMike Smith 	break;
28350b94a66eSMike Smith 
283635863739SMike Smith 	case FSACTL_SENDFIB:
2837f355c0e0SEd Maste 	case FSACTL_SEND_LARGE_FIB:
2838fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2839fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
2840f355c0e0SEd Maste 	case FSACTL_LNX_SEND_LARGE_FIB:
284131a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
284235863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
284335863739SMike Smith 		break;
2844f355c0e0SEd Maste 	case FSACTL_SEND_RAW_SRB:
2845f355c0e0SEd Maste 		arg = *(caddr_t*)arg;
2846f355c0e0SEd Maste 	case FSACTL_LNX_SEND_RAW_SRB:
284731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2848f355c0e0SEd Maste 		error = aac_ioctl_send_raw_srb(sc, arg);
2849f355c0e0SEd Maste 		break;
285035863739SMike Smith 	case FSACTL_AIF_THREAD:
2851fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
285231a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
285335863739SMike Smith 		error = EINVAL;
285435863739SMike Smith 		break;
285535863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2856fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2857fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
285831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2859a723a548SEd Maste 		error = aac_open_aif(sc, arg);
286035863739SMike Smith 		break;
286135863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2862fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2863fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
286431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2865fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
286635863739SMike Smith 		break;
286735863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2868a723a548SEd Maste 		arg = *(caddr_t*)arg;
2869fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
287031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2871a723a548SEd Maste 		error = aac_close_aif(sc, arg);
287235863739SMike Smith 		break;
287335863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2874fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2875fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
287631a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
2877fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
287835863739SMike Smith 		break;
287936e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
288036e0bf6eSScott Long 		arg = *(caddr_t*)arg;
288136e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
288231a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
288336e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
288436e0bf6eSScott Long 		break;
288536e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
288636e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2887914da7d0SScott Long 		/*
2888914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2889914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2890914da7d0SScott Long 		 * controller
2891914da7d0SScott Long 		 */
289236e0bf6eSScott Long 		error = 0;
289336e0bf6eSScott Long 		break;
28947cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
28957cb209f5SScott Long 		arg = *(caddr_t*)arg;
28967cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
289731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
28987cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
28997cb209f5SScott Long 		break;
29006d307336SEd Maste 	case FSACTL_GET_FEATURES:
29016d307336SEd Maste 		arg = *(caddr_t*)arg;
29026d307336SEd Maste 	case FSACTL_LNX_GET_FEATURES:
29036d307336SEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
29046d307336SEd Maste 		error = aac_supported_features(sc, arg);
29056d307336SEd Maste 		break;
290635863739SMike Smith 	default:
290731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
290835863739SMike Smith 		error = EINVAL;
290935863739SMike Smith 		break;
291035863739SMike Smith 	}
291135863739SMike Smith 	return(error);
291235863739SMike Smith }
291335863739SMike Smith 
2914b3457b51SScott Long static int
291500b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td)
2916b3457b51SScott Long {
2917b3457b51SScott Long 	struct aac_softc *sc;
2918ef0b687cSEd Maste 	struct aac_fib_context *ctx;
2919b3457b51SScott Long 	int revents;
2920b3457b51SScott Long 
2921b3457b51SScott Long 	sc = dev->si_drv1;
2922b3457b51SScott Long 	revents = 0;
2923b3457b51SScott Long 
2924bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2925b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2926ef0b687cSEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
2927ef0b687cSEd Maste 			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
2928b3457b51SScott Long 				revents |= poll_events & (POLLIN | POLLRDNORM);
2929ef0b687cSEd Maste 				break;
2930ef0b687cSEd Maste 			}
2931ef0b687cSEd Maste 		}
2932b3457b51SScott Long 	}
2933bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2934b3457b51SScott Long 
2935b3457b51SScott Long 	if (revents == 0) {
2936b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2937b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2938b3457b51SScott Long 	}
2939b3457b51SScott Long 
2940b3457b51SScott Long 	return (revents);
2941b3457b51SScott Long }
2942b3457b51SScott Long 
29437cb209f5SScott Long static void
29447cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
29457cb209f5SScott Long {
29467cb209f5SScott Long 
29477cb209f5SScott Long 	switch (event->ev_type) {
29487cb209f5SScott Long 	case AAC_EVENT_CMFREE:
29490c40d5beSEd Maste 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
29501a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
29517cb209f5SScott Long 			aac_add_event(sc, event);
29527cb209f5SScott Long 			return;
29537cb209f5SScott Long 		}
29547cb209f5SScott Long 		free(event, M_AACBUF);
29558eeb2ca6SScott Long 		wakeup(arg);
29567cb209f5SScott Long 		break;
29577cb209f5SScott Long 	default:
29587cb209f5SScott Long 		break;
29597cb209f5SScott Long 	}
29607cb209f5SScott Long }
29617cb209f5SScott Long 
2962914da7d0SScott Long /*
296335863739SMike Smith  * Send a FIB supplied from userspace
296435863739SMike Smith  */
296535863739SMike Smith static int
296635863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
296735863739SMike Smith {
296835863739SMike Smith 	struct aac_command *cm;
296935863739SMike Smith 	int size, error;
297035863739SMike Smith 
297131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
297235863739SMike Smith 
297335863739SMike Smith 	cm = NULL;
297435863739SMike Smith 
297535863739SMike Smith 	/*
297635863739SMike Smith 	 * Get a command
297735863739SMike Smith 	 */
2978bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
297935863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
29807cb209f5SScott Long 		struct aac_event *event;
29817cb209f5SScott Long 
29827cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
29837cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
29847cb209f5SScott Long 		if (event == NULL) {
298535863739SMike Smith 			error = EBUSY;
2986f16627aaSEd Maste 			mtx_unlock(&sc->aac_io_lock);
298735863739SMike Smith 			goto out;
298835863739SMike Smith 		}
29897cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
29907cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
29917cb209f5SScott Long 		event->ev_arg = &cm;
29927cb209f5SScott Long 		aac_add_event(sc, event);
29938eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
29947cb209f5SScott Long 	}
299593cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
299635863739SMike Smith 
299735863739SMike Smith 	/*
299835863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
299935863739SMike Smith 	 */
3000914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3001914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
300235863739SMike Smith 		goto out;
300335863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3004f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3005f355c0e0SEd Maste 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3006f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3007f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
300835863739SMike Smith 	}
300935863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
301035863739SMike Smith 		goto out;
301135863739SMike Smith 	cm->cm_fib->Header.Size = size;
30122b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
301335863739SMike Smith 
301435863739SMike Smith 	/*
301535863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
301635863739SMike Smith 	 */
301793cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3018f16627aaSEd Maste 	error = aac_wait_command(cm);
3019f16627aaSEd Maste 	mtx_unlock(&sc->aac_io_lock);
3020f16627aaSEd Maste 	if (error != 0) {
302170545d1aSScott Long 		device_printf(sc->aac_dev,
302270545d1aSScott Long 			      "aac_wait_command return %d\n", error);
302335863739SMike Smith 		goto out;
3024b3457b51SScott Long 	}
302535863739SMike Smith 
302635863739SMike Smith 	/*
302735863739SMike Smith 	 * Copy the FIB and data back out to the caller.
302835863739SMike Smith 	 */
302935863739SMike Smith 	size = cm->cm_fib->Header.Size;
3030f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3031f355c0e0SEd Maste 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3032f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3033f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
303435863739SMike Smith 	}
303535863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
303635863739SMike Smith 
303735863739SMike Smith out:
3038f6c4dd3fSScott Long 	if (cm != NULL) {
3039f16627aaSEd Maste 		mtx_lock(&sc->aac_io_lock);
304035863739SMike Smith 		aac_release_command(cm);
3041bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
3042f16627aaSEd Maste 	}
304335863739SMike Smith 	return(error);
304435863739SMike Smith }
304535863739SMike Smith 
3046914da7d0SScott Long /*
3047f355c0e0SEd Maste  * Send a passthrough FIB supplied from userspace
3048f355c0e0SEd Maste  */
3049f355c0e0SEd Maste static int
3050f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3051f355c0e0SEd Maste {
30527b90e5ecSAttilio Rao 	struct aac_command *cm;
30537b90e5ecSAttilio Rao 	struct aac_event *event;
30547b90e5ecSAttilio Rao 	struct aac_fib *fib;
30557b90e5ecSAttilio Rao 	struct aac_srb *srbcmd, *user_srb;
30567b90e5ecSAttilio Rao 	struct aac_sg_entry *sge;
30577b90e5ecSAttilio Rao 	struct aac_sg_entry64 *sge64;
30587b90e5ecSAttilio Rao 	void *srb_sg_address, *ureply;
30597b90e5ecSAttilio Rao 	uint32_t fibsize, srb_sg_bytecount;
30607b90e5ecSAttilio Rao 	int error, transfer_data;
30617b90e5ecSAttilio Rao 
30627b90e5ecSAttilio Rao 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
30637b90e5ecSAttilio Rao 
30647b90e5ecSAttilio Rao 	cm = NULL;
30657b90e5ecSAttilio Rao 	transfer_data = 0;
30667b90e5ecSAttilio Rao 	fibsize = 0;
30677b90e5ecSAttilio Rao 	user_srb = (struct aac_srb *)arg;
30687b90e5ecSAttilio Rao 
30697b90e5ecSAttilio Rao 	mtx_lock(&sc->aac_io_lock);
30707b90e5ecSAttilio Rao 	if (aac_alloc_command(sc, &cm)) {
30717b90e5ecSAttilio Rao 		 event = malloc(sizeof(struct aac_event), M_AACBUF,
30727b90e5ecSAttilio Rao 		    M_NOWAIT | M_ZERO);
30737b90e5ecSAttilio Rao 		if (event == NULL) {
30747b90e5ecSAttilio Rao 			error = EBUSY;
30757b90e5ecSAttilio Rao 			mtx_unlock(&sc->aac_io_lock);
30767b90e5ecSAttilio Rao 			goto out;
30777b90e5ecSAttilio Rao 		}
30787b90e5ecSAttilio Rao 		event->ev_type = AAC_EVENT_CMFREE;
30797b90e5ecSAttilio Rao 		event->ev_callback = aac_ioctl_event;
30807b90e5ecSAttilio Rao 		event->ev_arg = &cm;
30817b90e5ecSAttilio Rao 		aac_add_event(sc, event);
30827b90e5ecSAttilio Rao 		msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0);
30837b90e5ecSAttilio Rao 	}
30847b90e5ecSAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
30857b90e5ecSAttilio Rao 
30867b90e5ecSAttilio Rao 	cm->cm_data = NULL;
30877b90e5ecSAttilio Rao 	fib = cm->cm_fib;
30887b90e5ecSAttilio Rao 	srbcmd = (struct aac_srb *)fib->data;
30897b90e5ecSAttilio Rao 	error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t));
30907b90e5ecSAttilio Rao 	if (error != 0)
30917b90e5ecSAttilio Rao 		goto out;
30927b90e5ecSAttilio Rao 	if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) {
30937b90e5ecSAttilio Rao 		error = EINVAL;
30947b90e5ecSAttilio Rao 		goto out;
30957b90e5ecSAttilio Rao 	}
30967b90e5ecSAttilio Rao 	error = copyin(user_srb, srbcmd, fibsize);
30977b90e5ecSAttilio Rao 	if (error != 0)
30987b90e5ecSAttilio Rao 		goto out;
30997b90e5ecSAttilio Rao 	srbcmd->function = 0;
31007b90e5ecSAttilio Rao 	srbcmd->retry_limit = 0;
31017b90e5ecSAttilio Rao 	if (srbcmd->sg_map.SgCount > 1) {
31027b90e5ecSAttilio Rao 		error = EINVAL;
31037b90e5ecSAttilio Rao 		goto out;
31047b90e5ecSAttilio Rao 	}
31057b90e5ecSAttilio Rao 
31067b90e5ecSAttilio Rao 	/* Retrieve correct SG entries. */
31077b90e5ecSAttilio Rao 	if (fibsize == (sizeof(struct aac_srb) +
31087b90e5ecSAttilio Rao 	    srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) {
31097b90e5ecSAttilio Rao 		sge = srbcmd->sg_map.SgEntry;
31107b90e5ecSAttilio Rao 		sge64 = NULL;
31117b90e5ecSAttilio Rao 		srb_sg_bytecount = sge->SgByteCount;
31126eafba26SAttilio Rao 		srb_sg_address = (void *)(uintptr_t)sge->SgAddress;
31137b90e5ecSAttilio Rao 	}
31147b90e5ecSAttilio Rao #ifdef __amd64__
31157b90e5ecSAttilio Rao 	else if (fibsize == (sizeof(struct aac_srb) +
31167b90e5ecSAttilio Rao 	    srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) {
31177b90e5ecSAttilio Rao 		sge = NULL;
31187b90e5ecSAttilio Rao 		sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry;
31197b90e5ecSAttilio Rao 		srb_sg_bytecount = sge64->SgByteCount;
31207b90e5ecSAttilio Rao 		srb_sg_address = (void *)sge64->SgAddress;
31217b90e5ecSAttilio Rao 		if (sge64->SgAddress > 0xffffffffull &&
31227b90e5ecSAttilio Rao 		    (sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
31237b90e5ecSAttilio Rao 			error = EINVAL;
31247b90e5ecSAttilio Rao 			goto out;
31257b90e5ecSAttilio Rao 		}
31267b90e5ecSAttilio Rao 	}
31277b90e5ecSAttilio Rao #endif
31287b90e5ecSAttilio Rao 	else {
31297b90e5ecSAttilio Rao 		error = EINVAL;
31307b90e5ecSAttilio Rao 		goto out;
31317b90e5ecSAttilio Rao 	}
31327b90e5ecSAttilio Rao 	ureply = (char *)arg + fibsize;
31337b90e5ecSAttilio Rao 	srbcmd->data_len = srb_sg_bytecount;
31347b90e5ecSAttilio Rao 	if (srbcmd->sg_map.SgCount == 1)
31357b90e5ecSAttilio Rao 		transfer_data = 1;
31367b90e5ecSAttilio Rao 
31377b90e5ecSAttilio Rao 	cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map;
31387b90e5ecSAttilio Rao 	if (transfer_data) {
31397b90e5ecSAttilio Rao 		cm->cm_datalen = srb_sg_bytecount;
31407b90e5ecSAttilio Rao 		cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT);
31417b90e5ecSAttilio Rao 		if (cm->cm_data == NULL) {
31427b90e5ecSAttilio Rao 			error = ENOMEM;
31437b90e5ecSAttilio Rao 			goto out;
31447b90e5ecSAttilio Rao 		}
31457b90e5ecSAttilio Rao 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)
31467b90e5ecSAttilio Rao 			cm->cm_flags |= AAC_CMD_DATAIN;
31477b90e5ecSAttilio Rao 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) {
31487b90e5ecSAttilio Rao 			cm->cm_flags |= AAC_CMD_DATAOUT;
31497b90e5ecSAttilio Rao 			error = copyin(srb_sg_address, cm->cm_data,
31507b90e5ecSAttilio Rao 			    cm->cm_datalen);
31517b90e5ecSAttilio Rao 			if (error != 0)
31527b90e5ecSAttilio Rao 				goto out;
31537b90e5ecSAttilio Rao 		}
31547b90e5ecSAttilio Rao 	}
31557b90e5ecSAttilio Rao 
31567b90e5ecSAttilio Rao 	fib->Header.Size = sizeof(struct aac_fib_header) +
31577b90e5ecSAttilio Rao 	    sizeof(struct aac_srb);
31587b90e5ecSAttilio Rao 	fib->Header.XferState =
31597b90e5ecSAttilio Rao 	    AAC_FIBSTATE_HOSTOWNED   |
31607b90e5ecSAttilio Rao 	    AAC_FIBSTATE_INITIALISED |
31617b90e5ecSAttilio Rao 	    AAC_FIBSTATE_EMPTY       |
31627b90e5ecSAttilio Rao 	    AAC_FIBSTATE_FROMHOST    |
31637b90e5ecSAttilio Rao 	    AAC_FIBSTATE_REXPECTED   |
31647b90e5ecSAttilio Rao 	    AAC_FIBSTATE_NORM        |
31657b90e5ecSAttilio Rao 	    AAC_FIBSTATE_ASYNC       |
31667b90e5ecSAttilio Rao 	    AAC_FIBSTATE_FAST_RESPONSE;
31677b90e5ecSAttilio Rao 	fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ?
31687b90e5ecSAttilio Rao 	    ScsiPortCommandU64 : ScsiPortCommand;
31697b90e5ecSAttilio Rao 
31707b90e5ecSAttilio Rao 	mtx_lock(&sc->aac_io_lock);
31717b90e5ecSAttilio Rao 	aac_wait_command(cm);
31727b90e5ecSAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
31737b90e5ecSAttilio Rao 
31747b90e5ecSAttilio Rao 	if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) {
31757b90e5ecSAttilio Rao 		error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen);
31767b90e5ecSAttilio Rao 		if (error != 0)
31777b90e5ecSAttilio Rao 			goto out;
31787b90e5ecSAttilio Rao 	}
31797b90e5ecSAttilio Rao 	error = copyout(fib->data, ureply, sizeof(struct aac_srb_response));
31807b90e5ecSAttilio Rao out:
31817b90e5ecSAttilio Rao 	if (cm != NULL) {
31827b90e5ecSAttilio Rao 		if (cm->cm_data != NULL)
31837b90e5ecSAttilio Rao 			free(cm->cm_data, M_AACBUF);
31847b90e5ecSAttilio Rao 		mtx_lock(&sc->aac_io_lock);
31857b90e5ecSAttilio Rao 		aac_release_command(cm);
31867b90e5ecSAttilio Rao 		mtx_unlock(&sc->aac_io_lock);
31877b90e5ecSAttilio Rao 	}
31887b90e5ecSAttilio Rao 	return(error);
3189f355c0e0SEd Maste }
3190f355c0e0SEd Maste 
3191f355c0e0SEd Maste /*
3192dfe2c294SAttilio Rao  * cdevpriv interface private destructor.
3193dfe2c294SAttilio Rao  */
3194dfe2c294SAttilio Rao static void
3195dfe2c294SAttilio Rao aac_cdevpriv_dtor(void *arg)
3196dfe2c294SAttilio Rao {
3197dfe2c294SAttilio Rao 	struct aac_softc *sc;
3198dfe2c294SAttilio Rao 
3199dfe2c294SAttilio Rao 	sc = arg;
3200dfe2c294SAttilio Rao 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3201dfe2c294SAttilio Rao 	mtx_lock(&Giant);
3202dfe2c294SAttilio Rao 	device_unbusy(sc->aac_dev);
3203dfe2c294SAttilio Rao 	mtx_unlock(&Giant);
3204dfe2c294SAttilio Rao }
3205dfe2c294SAttilio Rao 
3206dfe2c294SAttilio Rao /*
320735863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
320836e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
320935863739SMike Smith  */
321035863739SMike Smith static void
321136e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
321235863739SMike Smith {
321336e0bf6eSScott Long 	struct aac_aif_command *aif;
321436e0bf6eSScott Long 	struct aac_container *co, *co_next;
3215a723a548SEd Maste 	struct aac_fib_context *ctx;
321604f4d586SEd Maste 	struct aac_mntinforesp *mir;
3217a723a548SEd Maste 	int next, current, found;
3218795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
321935863739SMike Smith 
322031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
322135863739SMike Smith 
322236e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
322336e0bf6eSScott Long 	aac_print_aif(sc, aif);
322436e0bf6eSScott Long 
322536e0bf6eSScott Long 	/* Is it an event that we should care about? */
322636e0bf6eSScott Long 	switch (aif->command) {
322736e0bf6eSScott Long 	case AifCmdEventNotify:
322836e0bf6eSScott Long 		switch (aif->data.EN.type) {
322936e0bf6eSScott Long 		case AifEnAddContainer:
323036e0bf6eSScott Long 		case AifEnDeleteContainer:
323136e0bf6eSScott Long 			/*
3232914da7d0SScott Long 			 * A container was added or deleted, but the message
3233914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3234914da7d0SScott Long 			 * containers and sort things out.
323536e0bf6eSScott Long 			 */
323603b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
323736e0bf6eSScott Long 			do {
323836e0bf6eSScott Long 				/*
3239914da7d0SScott Long 				 * Ask the controller for its containers one at
3240914da7d0SScott Long 				 * a time.
3241914da7d0SScott Long 				 * XXX What if the controller's list changes
3242914da7d0SScott Long 				 * midway through this enumaration?
324336e0bf6eSScott Long 				 * XXX This should be done async.
324436e0bf6eSScott Long 				 */
324504f4d586SEd Maste 				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
324636e0bf6eSScott Long 					continue;
324704f4d586SEd Maste 				if (i == 0)
3248795d7dc0SScott Long 					count = mir->MntRespCount;
324936e0bf6eSScott Long 				/*
3250914da7d0SScott Long 				 * Check the container against our list.
3251914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3252914da7d0SScott Long 				 * previous run.
325336e0bf6eSScott Long 				 */
3254cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3255cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
325636e0bf6eSScott Long 					found = 0;
3257914da7d0SScott Long 					TAILQ_FOREACH(co,
3258914da7d0SScott Long 						      &sc->aac_container_tqh,
3259914da7d0SScott Long 						      co_link) {
326036e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3261cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
326236e0bf6eSScott Long 							co->co_found = 1;
326336e0bf6eSScott Long 							found = 1;
326436e0bf6eSScott Long 							break;
326536e0bf6eSScott Long 						}
326636e0bf6eSScott Long 					}
3267914da7d0SScott Long 					/*
3268914da7d0SScott Long 					 * If the container matched, continue
3269914da7d0SScott Long 					 * in the list.
3270914da7d0SScott Long 					 */
327136e0bf6eSScott Long 					if (found) {
327236e0bf6eSScott Long 						i++;
327336e0bf6eSScott Long 						continue;
327436e0bf6eSScott Long 					}
327536e0bf6eSScott Long 
327636e0bf6eSScott Long 					/*
3277914da7d0SScott Long 					 * This is a new container.  Do all the
327870545d1aSScott Long 					 * appropriate things to set it up.
327970545d1aSScott Long 					 */
3280cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
328136e0bf6eSScott Long 					added = 1;
328236e0bf6eSScott Long 				}
328336e0bf6eSScott Long 				i++;
3284795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3285cbfd045bSScott Long 			aac_release_sync_fib(sc);
328636e0bf6eSScott Long 
328736e0bf6eSScott Long 			/*
3288914da7d0SScott Long 			 * Go through our list of containers and see which ones
3289914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3290914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3291914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3292914da7d0SScott Long 			 * the co->co_found field.
329336e0bf6eSScott Long 			 */
329436e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
329536e0bf6eSScott Long 			while (co != NULL) {
329636e0bf6eSScott Long 				if (co->co_found == 0) {
32977cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
3298a56fe095SJohn Baldwin 					mtx_lock(&Giant);
3299914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3300914da7d0SScott Long 							    co->co_disk);
3301a56fe095SJohn Baldwin 					mtx_unlock(&Giant);
33027cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
330336e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3304bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3305914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3306914da7d0SScott Long 						     co_link);
3307bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3308ba1d57e7SScott Long 					free(co, M_AACBUF);
330936e0bf6eSScott Long 					co = co_next;
331036e0bf6eSScott Long 				} else {
331136e0bf6eSScott Long 					co->co_found = 0;
331236e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
331336e0bf6eSScott Long 				}
331436e0bf6eSScott Long 			}
331536e0bf6eSScott Long 
331636e0bf6eSScott Long 			/* Attach the newly created containers */
33177cb209f5SScott Long 			if (added) {
33187cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
3319a56fe095SJohn Baldwin 				mtx_lock(&Giant);
332036e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
3321a56fe095SJohn Baldwin 				mtx_unlock(&Giant);
33227cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
33237cb209f5SScott Long 			}
332436e0bf6eSScott Long 
332536e0bf6eSScott Long 			break;
332636e0bf6eSScott Long 
332736e0bf6eSScott Long 		default:
332836e0bf6eSScott Long 			break;
332936e0bf6eSScott Long 		}
333036e0bf6eSScott Long 
333136e0bf6eSScott Long 	default:
333236e0bf6eSScott Long 		break;
333336e0bf6eSScott Long 	}
333436e0bf6eSScott Long 
333536e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3336bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3337a723a548SEd Maste 	current = sc->aifq_idx;
3338a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3339a723a548SEd Maste 	if (next == 0)
3340a723a548SEd Maste 		sc->aifq_filled = 1;
3341a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3342a723a548SEd Maste 	/* modify AIF contexts */
3343a723a548SEd Maste 	if (sc->aifq_filled) {
3344a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3345a723a548SEd Maste 			if (next == ctx->ctx_idx)
3346a723a548SEd Maste 				ctx->ctx_wrap = 1;
3347a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3348a723a548SEd Maste 				ctx->ctx_idx = next;
3349a723a548SEd Maste 		}
3350a723a548SEd Maste 	}
3351a723a548SEd Maste 	sc->aifq_idx = next;
3352b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
335335863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
335435863739SMike Smith 		wakeup(sc->aac_aifq);
3355b3457b51SScott Long 	/* Wakeup any poll()ers */
3356512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3357bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
335836e0bf6eSScott Long 
335936e0bf6eSScott Long 	return;
336035863739SMike Smith }
336135863739SMike Smith 
3362914da7d0SScott Long /*
33630b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
336436e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
336536e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
336636e0bf6eSScott Long  * returning what the card reported.
336735863739SMike Smith  */
336835863739SMike Smith static int
3369fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
337035863739SMike Smith {
337135863739SMike Smith 	struct aac_rev_check rev_check;
337235863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
337335863739SMike Smith 	int error = 0;
337435863739SMike Smith 
337531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
337635863739SMike Smith 
337735863739SMike Smith 	/*
337835863739SMike Smith 	 * Copyin the revision struct from userspace
337935863739SMike Smith 	 */
3380c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3381c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
338235863739SMike Smith 		return error;
338335863739SMike Smith 	}
338435863739SMike Smith 
338531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3386914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
338735863739SMike Smith 
338835863739SMike Smith 	/*
338935863739SMike Smith 	 * Doctor up the response struct.
339035863739SMike Smith 	 */
339135863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
33928e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.major =
33938e7e6335SEd Maste 	    AAC_DRIVER_MAJOR_VERSION;
33948e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.minor =
33958e7e6335SEd Maste 	    AAC_DRIVER_MINOR_VERSION;
33968e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.type =
33978e7e6335SEd Maste 	    AAC_DRIVER_TYPE;
33988e7e6335SEd Maste 	rev_check_resp.adapterSWRevision.external.comp.dash =
33998e7e6335SEd Maste 	    AAC_DRIVER_BUGFIX_LEVEL;
3400914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
34018e7e6335SEd Maste 	    AAC_DRIVER_BUILD;
340235863739SMike Smith 
3403c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3404c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
340535863739SMike Smith }
340635863739SMike Smith 
3407914da7d0SScott Long /*
3408a723a548SEd Maste  * Pass the fib context to the caller
3409a723a548SEd Maste  */
3410a723a548SEd Maste static int
3411a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3412a723a548SEd Maste {
3413a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3414a723a548SEd Maste 	int error = 0;
3415a723a548SEd Maste 
341631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3417a723a548SEd Maste 
3418a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3419a723a548SEd Maste 	if (fibctx == NULL)
3420a723a548SEd Maste 		return (ENOMEM);
3421a723a548SEd Maste 
3422a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3423a723a548SEd Maste 	/* all elements are already 0, add to queue */
3424a723a548SEd Maste 	if (sc->fibctx == NULL)
3425a723a548SEd Maste 		sc->fibctx = fibctx;
3426a723a548SEd Maste 	else {
3427a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3428a723a548SEd Maste 			;
3429a723a548SEd Maste 		ctx->next = fibctx;
3430a723a548SEd Maste 		fibctx->prev = ctx;
3431a723a548SEd Maste 	}
3432a723a548SEd Maste 
3433a723a548SEd Maste 	/* evaluate unique value */
3434a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3435a723a548SEd Maste 	ctx = sc->fibctx;
3436a723a548SEd Maste 	while (ctx != fibctx) {
3437a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3438a723a548SEd Maste 			fibctx->unique++;
3439a723a548SEd Maste 			ctx = sc->fibctx;
3440a723a548SEd Maste 		} else {
3441a723a548SEd Maste 			ctx = ctx->next;
3442a723a548SEd Maste 		}
3443a723a548SEd Maste 	}
3444a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3445a723a548SEd Maste 
3446a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3447a723a548SEd Maste 	if (error)
3448a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3449a723a548SEd Maste 	return error;
3450a723a548SEd Maste }
3451a723a548SEd Maste 
3452a723a548SEd Maste /*
3453a723a548SEd Maste  * Close the caller's fib context
3454a723a548SEd Maste  */
3455a723a548SEd Maste static int
3456a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3457a723a548SEd Maste {
3458a723a548SEd Maste 	struct aac_fib_context *ctx;
3459a723a548SEd Maste 
346031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3461a723a548SEd Maste 
3462a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3463a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3464a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3465a723a548SEd Maste 			if (ctx == sc->fibctx)
3466a723a548SEd Maste 				sc->fibctx = NULL;
3467a723a548SEd Maste 			else {
3468a723a548SEd Maste 				ctx->prev->next = ctx->next;
3469a723a548SEd Maste 				if (ctx->next)
3470a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3471a723a548SEd Maste 			}
3472a723a548SEd Maste 			break;
3473a723a548SEd Maste 		}
3474a723a548SEd Maste 	}
3475a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3476a723a548SEd Maste 	if (ctx)
3477a723a548SEd Maste 		free(ctx, M_AACBUF);
3478a723a548SEd Maste 
3479a723a548SEd Maste 	return 0;
3480a723a548SEd Maste }
3481a723a548SEd Maste 
3482a723a548SEd Maste /*
348335863739SMike Smith  * Pass the caller the next AIF in their queue
348435863739SMike Smith  */
348535863739SMike Smith static int
3486fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
348735863739SMike Smith {
348835863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3489a723a548SEd Maste 	struct aac_fib_context *ctx;
34909e2e96d8SScott Long 	int error;
349135863739SMike Smith 
349231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
349335863739SMike Smith 
349435863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3495a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3496a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3497a723a548SEd Maste 				break;
3498a723a548SEd Maste 		}
3499a723a548SEd Maste 		if (!ctx)
3500a723a548SEd Maste 			return (EFAULT);
350135863739SMike Smith 
3502a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3503a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
350431a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
350535863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
350635863739SMike Smith 			while (error == EAGAIN) {
3507914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3508914da7d0SScott Long 					       PCATCH, "aacaif", 0);
350935863739SMike Smith 				if (error == 0)
3510a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
351135863739SMike Smith 			}
351235863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
351335863739SMike Smith 		}
351435863739SMike Smith 	}
351535863739SMike Smith 	return(error);
351635863739SMike Smith }
351735863739SMike Smith 
3518914da7d0SScott Long /*
35190b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
35200b94a66eSMike Smith  */
35210b94a66eSMike Smith static int
3522a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
35230b94a66eSMike Smith {
3524a723a548SEd Maste 	int current, error;
35250b94a66eSMike Smith 
352631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35270b94a66eSMike Smith 
3528bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3529a723a548SEd Maste 	current = ctx->ctx_idx;
3530a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3531a723a548SEd Maste 		/* empty */
3532bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
35333df780cfSScott Long 		return (EAGAIN);
35343df780cfSScott Long 	}
3535a723a548SEd Maste 	error =
3536a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
353736e0bf6eSScott Long 	if (error)
353870545d1aSScott Long 		device_printf(sc->aac_dev,
353970545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3540a723a548SEd Maste 	else {
3541a723a548SEd Maste 		ctx->ctx_wrap = 0;
3542a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3543a723a548SEd Maste 	}
3544bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
35450b94a66eSMike Smith 	return(error);
35460b94a66eSMike Smith }
354736e0bf6eSScott Long 
35487cb209f5SScott Long static int
35497cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
35507cb209f5SScott Long {
35517cb209f5SScott Long 	struct aac_pci_info {
35527cb209f5SScott Long 		u_int32_t bus;
35537cb209f5SScott Long 		u_int32_t slot;
35547cb209f5SScott Long 	} pciinf;
35557cb209f5SScott Long 	int error;
35567cb209f5SScott Long 
355731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35587cb209f5SScott Long 
35597cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
35607cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
35617cb209f5SScott Long 
35627cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
35637cb209f5SScott Long 			sizeof(struct aac_pci_info));
35647cb209f5SScott Long 
35657cb209f5SScott Long 	return (error);
35667cb209f5SScott Long }
35677cb209f5SScott Long 
35686d307336SEd Maste static int
35696d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr)
35706d307336SEd Maste {
35716d307336SEd Maste 	struct aac_features f;
35726d307336SEd Maste 	int error;
35736d307336SEd Maste 
35746d307336SEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35756d307336SEd Maste 
35766d307336SEd Maste 	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
35776d307336SEd Maste 		return (error);
35786d307336SEd Maste 
35796d307336SEd Maste 	/*
35806d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35816d307336SEd Maste 	 * ALL zero in the featuresState, the driver will return the current
35826d307336SEd Maste 	 * state of all the supported features, the data field will not be
35836d307336SEd Maste 	 * valid.
35846d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35856d307336SEd Maste 	 * a specific bit set in the featuresState, the driver will return the
35866d307336SEd Maste 	 * current state of this specific feature and whatever data that are
35876d307336SEd Maste 	 * associated with the feature in the data field or perform whatever
35886d307336SEd Maste 	 * action needed indicates in the data field.
35896d307336SEd Maste 	 */
35906d307336SEd Maste 	if (f.feat.fValue == 0) {
35916d307336SEd Maste 		f.feat.fBits.largeLBA =
35926d307336SEd Maste 		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35936d307336SEd Maste 		/* TODO: In the future, add other features state here as well */
35946d307336SEd Maste 	} else {
35956d307336SEd Maste 		if (f.feat.fBits.largeLBA)
35966d307336SEd Maste 			f.feat.fBits.largeLBA =
35976d307336SEd Maste 			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35986d307336SEd Maste 		/* TODO: Add other features state and data in the future */
35996d307336SEd Maste 	}
36006d307336SEd Maste 
36016d307336SEd Maste 	error = copyout(&f, uptr, sizeof (f));
36026d307336SEd Maste 	return (error);
36036d307336SEd Maste }
36046d307336SEd Maste 
3605914da7d0SScott Long /*
360636e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
360736e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
360836e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
360936e0bf6eSScott Long  */
361036e0bf6eSScott Long static int
361136e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
361236e0bf6eSScott Long {
361336e0bf6eSScott Long 	struct aac_query_disk query_disk;
361436e0bf6eSScott Long 	struct aac_container *co;
3615914da7d0SScott Long 	struct aac_disk	*disk;
361636e0bf6eSScott Long 	int error, id;
361736e0bf6eSScott Long 
361831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
361936e0bf6eSScott Long 
3620914da7d0SScott Long 	disk = NULL;
3621914da7d0SScott Long 
3622914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3623914da7d0SScott Long 		       sizeof(struct aac_query_disk));
362436e0bf6eSScott Long 	if (error)
362536e0bf6eSScott Long 		return (error);
362636e0bf6eSScott Long 
362736e0bf6eSScott Long 	id = query_disk.ContainerNumber;
362836e0bf6eSScott Long 	if (id == -1)
362936e0bf6eSScott Long 		return (EINVAL);
363036e0bf6eSScott Long 
3631bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
363236e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
363336e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
363436e0bf6eSScott Long 			break;
363536e0bf6eSScott Long 		}
363636e0bf6eSScott Long 
363736e0bf6eSScott Long 	if (co == NULL) {
363836e0bf6eSScott Long 			query_disk.Valid = 0;
363936e0bf6eSScott Long 			query_disk.Locked = 0;
364036e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
364136e0bf6eSScott Long 	} else {
364236e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
364336e0bf6eSScott Long 		query_disk.Valid = 1;
3644914da7d0SScott Long 		query_disk.Locked =
3645914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
364636e0bf6eSScott Long 		query_disk.Deleted = 0;
3647b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
364836e0bf6eSScott Long 		query_disk.Target = disk->unit;
364936e0bf6eSScott Long 		query_disk.Lun = 0;
365036e0bf6eSScott Long 		query_disk.UnMapped = 0;
36517540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
36520b7ed341SPoul-Henning Kamp 			disk->ad_disk->d_name, disk->ad_disk->d_unit);
365336e0bf6eSScott Long 	}
3654bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
365536e0bf6eSScott Long 
3656914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3657914da7d0SScott Long 			sizeof(struct aac_query_disk));
365836e0bf6eSScott Long 
365936e0bf6eSScott Long 	return (error);
366036e0bf6eSScott Long }
366136e0bf6eSScott Long 
3662fe3cb0e1SScott Long static void
3663fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3664fe3cb0e1SScott Long {
3665fe3cb0e1SScott Long 	struct aac_fib *fib;
3666fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3667fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3668fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3669fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3670fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
367170545d1aSScott Long 	struct aac_sim *caminf;
3672fe3cb0e1SScott Long 	device_t child;
3673fe3cb0e1SScott Long 	int i, found, error;
3674fe3cb0e1SScott Long 
36751ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
367603b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3677fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
367839ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3679fe3cb0e1SScott Long 
3680fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3681fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3682fe3cb0e1SScott Long 	c_cmd->param = 0;
3683fe3cb0e1SScott Long 
3684fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3685fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3686fe3cb0e1SScott Long 	if (error) {
3687fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3688fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3689fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36901ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3691fe3cb0e1SScott Long 		return;
3692fe3cb0e1SScott Long 	}
3693fe3cb0e1SScott Long 
3694fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3695fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3696fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3697fe3cb0e1SScott Long 		    c_resp->Status);
3698fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36991ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3700fe3cb0e1SScott Long 		return;
3701fe3cb0e1SScott Long 	}
3702fe3cb0e1SScott Long 
3703fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3704fe3cb0e1SScott Long 
3705fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
370639ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
370739ee03c3SScott Long 
3708fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3709fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3710fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3711fe3cb0e1SScott Long 	vmi->ObjId = 0;
3712fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3713fe3cb0e1SScott Long 
3714fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
371542ef13a2SEd Maste 	    sizeof(struct aac_vmi_businf_resp));
3716fe3cb0e1SScott Long 	if (error) {
3717fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3718fe3cb0e1SScott Long 		    error);
3719fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
37201ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3721fe3cb0e1SScott Long 		return;
3722fe3cb0e1SScott Long 	}
3723fe3cb0e1SScott Long 
3724fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3725fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3726fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3727fe3cb0e1SScott Long 		    vmi_resp->Status);
3728fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
37291ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3730fe3cb0e1SScott Long 		return;
3731fe3cb0e1SScott Long 	}
3732fe3cb0e1SScott Long 
3733fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3734fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
37351ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3736fe3cb0e1SScott Long 
3737fe3cb0e1SScott Long 	found = 0;
3738fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3739fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3740fe3cb0e1SScott Long 			continue;
3741fe3cb0e1SScott Long 
3742a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3743a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3744b5f516cdSScott Long 		if (caminf == NULL) {
3745b5f516cdSScott Long 			device_printf(sc->aac_dev,
3746b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3747b5f516cdSScott Long 			break;
37487cb209f5SScott Long 		};
3749fe3cb0e1SScott Long 
3750fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3751fe3cb0e1SScott Long 		if (child == NULL) {
3752b5f516cdSScott Long 			device_printf(sc->aac_dev,
3753b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3754b5f516cdSScott Long 			    i);
3755b5f516cdSScott Long 			free(caminf, M_AACBUF);
3756b5f516cdSScott Long 			break;
3757fe3cb0e1SScott Long 		}
3758fe3cb0e1SScott Long 
3759fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3760fe3cb0e1SScott Long 		caminf->BusNumber = i;
3761fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3762fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3763ddb8683eSScott Long 		caminf->sim_dev = child;
3764fe3cb0e1SScott Long 
3765fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3766fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
376770545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3768fe3cb0e1SScott Long 
3769fe3cb0e1SScott Long 		found = 1;
3770fe3cb0e1SScott Long 	}
3771fe3cb0e1SScott Long 
3772fe3cb0e1SScott Long 	if (found)
3773fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3774fe3cb0e1SScott Long 
3775fe3cb0e1SScott Long 	return;
3776fe3cb0e1SScott Long }
3777