xref: /freebsd/sys/dev/aac/aac.c (revision e46b9eeadae7eadf4f4ad7e023fc3657370e14b4)
135863739SMike Smith /*-
235863739SMike Smith  * Copyright (c) 2000 Michael Smith
3c6eafcf2SScott Long  * Copyright (c) 2001 Scott Long
435863739SMike Smith  * Copyright (c) 2000 BSDi
5c6eafcf2SScott Long  * Copyright (c) 2001 Adaptec, Inc.
635863739SMike Smith  * All rights reserved.
735863739SMike Smith  *
835863739SMike Smith  * Redistribution and use in source and binary forms, with or without
935863739SMike Smith  * modification, are permitted provided that the following conditions
1035863739SMike Smith  * are met:
1135863739SMike Smith  * 1. Redistributions of source code must retain the above copyright
1235863739SMike Smith  *    notice, this list of conditions and the following disclaimer.
1335863739SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1435863739SMike Smith  *    notice, this list of conditions and the following disclaimer in the
1535863739SMike Smith  *    documentation and/or other materials provided with the distribution.
1635863739SMike Smith  *
1735863739SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1835863739SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1935863739SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2035863739SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2135863739SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2235863739SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2335863739SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2435863739SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2535863739SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2635863739SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2735863739SMike Smith  * SUCH DAMAGE.
2835863739SMike Smith  */
2935863739SMike Smith 
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
32aad970f1SDavid E. O'Brien 
3335863739SMike Smith /*
3435863739SMike Smith  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3535863739SMike Smith  */
367cb209f5SScott Long #define AAC_DRIVER_VERSION		0x02000000
377cb209f5SScott Long #define AAC_DRIVERNAME			"aac"
3835863739SMike Smith 
39f6c4dd3fSScott Long #include "opt_aac.h"
40f6c4dd3fSScott Long 
4136e0bf6eSScott Long /* #include <stddef.h> */
4235863739SMike Smith #include <sys/param.h>
4335863739SMike Smith #include <sys/systm.h>
4435863739SMike Smith #include <sys/malloc.h>
4535863739SMike Smith #include <sys/kernel.h>
4636e0bf6eSScott Long #include <sys/kthread.h>
473d04a9d7SScott Long #include <sys/sysctl.h>
48b3457b51SScott Long #include <sys/poll.h>
49891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
5035863739SMike Smith 
5135863739SMike Smith #include <sys/bus.h>
5235863739SMike Smith #include <sys/conf.h>
5335863739SMike Smith #include <sys/signalvar.h>
540b94a66eSMike Smith #include <sys/time.h>
5536e0bf6eSScott Long #include <sys/eventhandler.h>
567cb209f5SScott Long #include <sys/rman.h>
5735863739SMike Smith 
5835863739SMike Smith #include <machine/bus.h>
59b5f516cdSScott Long #include <sys/bus_dma.h>
6035863739SMike Smith #include <machine/resource.h>
6135863739SMike Smith 
627cb209f5SScott Long #include <dev/pci/pcireg.h>
637cb209f5SScott Long #include <dev/pci/pcivar.h>
647cb209f5SScott Long 
6535863739SMike Smith #include <dev/aac/aacreg.h>
660b0594cdSScott Long #include <sys/aac_ioctl.h>
6735863739SMike Smith #include <dev/aac/aacvar.h>
6835863739SMike Smith #include <dev/aac/aac_tables.h>
6935863739SMike Smith 
7035863739SMike Smith static void	aac_startup(void *arg);
71914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
72cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
73fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
74ff0991c4SAttilio Rao static void	aac_daemon(void *arg);
7535863739SMike Smith 
7635863739SMike Smith /* Command Processing */
770b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7835863739SMike Smith static void	aac_complete(void *context, int pending);
7935863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
8035863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
81d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
8270545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
8335863739SMike Smith 
8435863739SMike Smith /* Command Buffer Management */
85cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
86cd481291SScott Long 				   int nseg, int error);
87c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
88c6eafcf2SScott Long 				       int nseg, int error);
890b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
908480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
9135863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
9235863739SMike Smith 
9335863739SMike Smith /* Hardware Interface */
9404f4d586SEd Maste static int	aac_alloc(struct aac_softc *sc);
95c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
96c6eafcf2SScott Long 			       int error);
97fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9835863739SMike Smith static int	aac_init(struct aac_softc *sc);
9935863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
100c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
101c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
10204f4d586SEd Maste static int	aac_setup_intr(struct aac_softc *sc);
103c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
104f6c4dd3fSScott Long 				struct aac_command *cm);
105c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
106914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10736e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10836e0bf6eSScott Long 				     struct aac_fib *fib);
10935863739SMike Smith 
110b3457b51SScott Long /* Falcon/PPC interface */
111b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
112b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
113b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
114b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
115b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
116b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
117b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
118a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
119b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
120b3457b51SScott Long 
121b3457b51SScott Long struct aac_interface aac_fa_interface = {
122b3457b51SScott Long 	aac_fa_get_fwstatus,
123b3457b51SScott Long 	aac_fa_qnotify,
124b3457b51SScott Long 	aac_fa_get_istatus,
125b3457b51SScott Long 	aac_fa_clear_istatus,
126b3457b51SScott Long 	aac_fa_set_mailbox,
127a6d35632SScott Long 	aac_fa_get_mailbox,
1287cb209f5SScott Long 	aac_fa_set_interrupts,
1297cb209f5SScott Long 	NULL, NULL, NULL
130b3457b51SScott Long };
131b3457b51SScott Long 
13235863739SMike Smith /* StrongARM interface */
13335863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
13435863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13535863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
13635863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13735863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
138c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
139c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
140a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
14135863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
14235863739SMike Smith 
14335863739SMike Smith struct aac_interface aac_sa_interface = {
14435863739SMike Smith 	aac_sa_get_fwstatus,
14535863739SMike Smith 	aac_sa_qnotify,
14635863739SMike Smith 	aac_sa_get_istatus,
14735863739SMike Smith 	aac_sa_clear_istatus,
14835863739SMike Smith 	aac_sa_set_mailbox,
149a6d35632SScott Long 	aac_sa_get_mailbox,
1507cb209f5SScott Long 	aac_sa_set_interrupts,
1517cb209f5SScott Long 	NULL, NULL, NULL
15235863739SMike Smith };
15335863739SMike Smith 
15435863739SMike Smith /* i960Rx interface */
15535863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
15635863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15735863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
15835863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15935863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
160c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
161c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
162a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16335863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
1647cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
1657cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc);
1667cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16735863739SMike Smith 
16835863739SMike Smith struct aac_interface aac_rx_interface = {
16935863739SMike Smith 	aac_rx_get_fwstatus,
17035863739SMike Smith 	aac_rx_qnotify,
17135863739SMike Smith 	aac_rx_get_istatus,
17235863739SMike Smith 	aac_rx_clear_istatus,
17335863739SMike Smith 	aac_rx_set_mailbox,
174a6d35632SScott Long 	aac_rx_get_mailbox,
1757cb209f5SScott Long 	aac_rx_set_interrupts,
1767cb209f5SScott Long 	aac_rx_send_command,
1777cb209f5SScott Long 	aac_rx_get_outb_queue,
1787cb209f5SScott Long 	aac_rx_set_outb_queue
17935863739SMike Smith };
18035863739SMike Smith 
1814afedc31SScott Long /* Rocket/MIPS interface */
1824afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1834afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1844afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1854afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1864afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1874afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1884afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1894afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1904afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1917cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
1927cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc);
1937cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
1944afedc31SScott Long 
1954afedc31SScott Long struct aac_interface aac_rkt_interface = {
1964afedc31SScott Long 	aac_rkt_get_fwstatus,
1974afedc31SScott Long 	aac_rkt_qnotify,
1984afedc31SScott Long 	aac_rkt_get_istatus,
1994afedc31SScott Long 	aac_rkt_clear_istatus,
2004afedc31SScott Long 	aac_rkt_set_mailbox,
2014afedc31SScott Long 	aac_rkt_get_mailbox,
2027cb209f5SScott Long 	aac_rkt_set_interrupts,
2037cb209f5SScott Long 	aac_rkt_send_command,
2047cb209f5SScott Long 	aac_rkt_get_outb_queue,
2057cb209f5SScott Long 	aac_rkt_set_outb_queue
2064afedc31SScott Long };
2074afedc31SScott Long 
20835863739SMike Smith /* Debugging and Diagnostics */
20935863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
2106965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
211c6eafcf2SScott Long 				   u_int32_t code);
21235863739SMike Smith 
21335863739SMike Smith /* Management Interface */
21435863739SMike Smith static d_open_t		aac_open;
21535863739SMike Smith static d_close_t	aac_close;
21635863739SMike Smith static d_ioctl_t	aac_ioctl;
217b3457b51SScott Long static d_poll_t		aac_poll;
218c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
219f355c0e0SEd Maste static int		aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
220c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
22136e0bf6eSScott Long 					   struct aac_fib *fib);
222fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
223a723a548SEd Maste static int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
224a723a548SEd Maste static int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
225fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
226a723a548SEd Maste static int		aac_return_aif(struct aac_softc *sc,
227a723a548SEd Maste 					struct aac_fib_context *ctx, caddr_t uptr);
22836e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
2297cb209f5SScott Long static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
2306d307336SEd Maste static int		aac_supported_features(struct aac_softc *sc, caddr_t uptr);
2317cb209f5SScott Long static void		aac_ioctl_event(struct aac_softc *sc,
2327cb209f5SScott Long 					struct aac_event *event, void *arg);
23304f4d586SEd Maste static struct aac_mntinforesp *
23404f4d586SEd Maste 	aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid);
23535863739SMike Smith 
23635863739SMike Smith static struct cdevsw aac_cdevsw = {
237dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
238dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2397ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2407ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2417ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2427ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2437ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
24435863739SMike Smith };
24535863739SMike Smith 
24636e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
24736e0bf6eSScott Long 
2483d04a9d7SScott Long /* sysctl node */
2493d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2503d04a9d7SScott Long 
251914da7d0SScott Long /*
252914da7d0SScott Long  * Device Interface
253914da7d0SScott Long  */
25435863739SMike Smith 
255914da7d0SScott Long /*
2564109ba51SEd Maste  * Initialize the controller and softc
25735863739SMike Smith  */
25835863739SMike Smith int
25935863739SMike Smith aac_attach(struct aac_softc *sc)
26035863739SMike Smith {
26135863739SMike Smith 	int error, unit;
26235863739SMike Smith 
26331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26435863739SMike Smith 
26535863739SMike Smith 	/*
2664109ba51SEd Maste 	 * Initialize per-controller queues.
26735863739SMike Smith 	 */
2680b94a66eSMike Smith 	aac_initq_free(sc);
2690b94a66eSMike Smith 	aac_initq_ready(sc);
2700b94a66eSMike Smith 	aac_initq_busy(sc);
2710b94a66eSMike Smith 	aac_initq_bio(sc);
27235863739SMike Smith 
27335863739SMike Smith 	/*
2744109ba51SEd Maste 	 * Initialize command-completion task.
27535863739SMike Smith 	 */
27635863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
27735863739SMike Smith 
27835863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
27935863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
28035863739SMike Smith 
28135863739SMike Smith 	/*
282fe94b852SScott Long 	 * Check that the firmware on the card is supported.
283fe94b852SScott Long 	 */
284fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
285fe94b852SScott Long 		return(error);
286fe94b852SScott Long 
287f6b1c44dSScott Long 	/*
288f6b1c44dSScott Long 	 * Initialize locks
289f6b1c44dSScott Long 	 */
290bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
291bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
292bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
293f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
294065dd78cSScott Long 	TAILQ_INIT(&sc->aac_ev_cmfree);
295f6b1c44dSScott Long 
296ff0991c4SAttilio Rao 	/* Initialize the clock daemon callout. */
297ff0991c4SAttilio Rao 	callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0);
298ff0991c4SAttilio Rao 
2990b94a66eSMike Smith 	/*
3004109ba51SEd Maste 	 * Initialize the adapter.
30135863739SMike Smith 	 */
30204f4d586SEd Maste 	if ((error = aac_alloc(sc)) != 0)
30304f4d586SEd Maste 		return(error);
3040b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
30535863739SMike Smith 		return(error);
30635863739SMike Smith 
30735863739SMike Smith 	/*
3087cb209f5SScott Long 	 * Allocate and connect our interrupt.
3097cb209f5SScott Long 	 */
31004f4d586SEd Maste 	if ((error = aac_setup_intr(sc)) != 0)
31104f4d586SEd Maste 		return(error);
3127cb209f5SScott Long 
3137cb209f5SScott Long 	/*
31435863739SMike Smith 	 * Print a little information about the controller.
31535863739SMike Smith 	 */
31635863739SMike Smith 	aac_describe_controller(sc);
31735863739SMike Smith 
31835863739SMike Smith 	/*
319ae543596SScott Long 	 * Register to probe our containers later.
320ae543596SScott Long 	 */
32135863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
32235863739SMike Smith 	sc->aac_ich.ich_arg = sc;
32335863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
324914da7d0SScott Long 		device_printf(sc->aac_dev,
325914da7d0SScott Long 			      "can't establish configuration hook\n");
32635863739SMike Smith 		return(ENXIO);
32735863739SMike Smith 	}
32835863739SMike Smith 
32935863739SMike Smith 	/*
33035863739SMike Smith 	 * Make the control device.
33135863739SMike Smith 	 */
33235863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3339e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3349e9466baSRobert Watson 				 0640, "aac%d", unit);
335157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3364aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
33735863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
33835863739SMike Smith 
33936e0bf6eSScott Long 	/* Create the AIF thread */
3403745c395SJulian Elischer 	if (kproc_create((void(*)(void *))aac_command_thread, sc,
341316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
342a620bad0SEd Maste 		panic("Could not create AIF thread");
34336e0bf6eSScott Long 
34436e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3455f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3465f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3475f54d522SScott Long 		device_printf(sc->aac_dev,
3485f54d522SScott Long 			      "shutdown event registration failed\n");
34936e0bf6eSScott Long 
350fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
351a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
35270545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
353fe3cb0e1SScott Long 		aac_get_bus_info(sc);
35470545d1aSScott Long 	}
355fe3cb0e1SScott Long 
356ff0991c4SAttilio Rao 	mtx_lock(&sc->aac_io_lock);
357867b1d34SEd Maste 	callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc);
358ff0991c4SAttilio Rao 	mtx_unlock(&sc->aac_io_lock);
359ff0991c4SAttilio Rao 
36035863739SMike Smith 	return(0);
36135863739SMike Smith }
36235863739SMike Smith 
363ff0991c4SAttilio Rao static void
364ff0991c4SAttilio Rao aac_daemon(void *arg)
365ff0991c4SAttilio Rao {
366ff0991c4SAttilio Rao 	struct timeval tv;
367ff0991c4SAttilio Rao 	struct aac_softc *sc;
368ff0991c4SAttilio Rao 	struct aac_fib *fib;
369ff0991c4SAttilio Rao 
370ff0991c4SAttilio Rao 	sc = arg;
371ff0991c4SAttilio Rao 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
372ff0991c4SAttilio Rao 
373ff0991c4SAttilio Rao 	if (callout_pending(&sc->aac_daemontime) ||
374ff0991c4SAttilio Rao 	    callout_active(&sc->aac_daemontime) == 0)
375ff0991c4SAttilio Rao 		return;
376ff0991c4SAttilio Rao 	getmicrotime(&tv);
377ff0991c4SAttilio Rao 	aac_alloc_sync_fib(sc, &fib);
378ff0991c4SAttilio Rao 	*(uint32_t *)fib->data = tv.tv_sec;
379ff0991c4SAttilio Rao 	aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t));
380ff0991c4SAttilio Rao 	aac_release_sync_fib(sc);
381ff0991c4SAttilio Rao 	callout_schedule(&sc->aac_daemontime, 30 * 60 * hz);
382ff0991c4SAttilio Rao }
383ff0991c4SAttilio Rao 
3847cb209f5SScott Long void
3857cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3867cb209f5SScott Long {
3877cb209f5SScott Long 
3887cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3897cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3907cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3917cb209f5SScott Long 		break;
3927cb209f5SScott Long 	default:
3937cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3947cb209f5SScott Long 		    event->ev_type);
3957cb209f5SScott Long 		break;
3967cb209f5SScott Long 	}
3977cb209f5SScott Long 
3987cb209f5SScott Long 	return;
3997cb209f5SScott Long }
4007cb209f5SScott Long 
401914da7d0SScott Long /*
40204f4d586SEd Maste  * Request information of container #cid
40304f4d586SEd Maste  */
40404f4d586SEd Maste static struct aac_mntinforesp *
40504f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid)
40604f4d586SEd Maste {
40704f4d586SEd Maste 	struct aac_mntinfo *mi;
40804f4d586SEd Maste 
40904f4d586SEd Maste 	mi = (struct aac_mntinfo *)&fib->data[0];
410523da39bSEd Maste 	/* use 64-bit LBA if enabled */
411523da39bSEd Maste 	mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ?
412523da39bSEd Maste 	    VM_NameServe64 : VM_NameServe;
41304f4d586SEd Maste 	mi->MntType = FT_FILESYS;
41404f4d586SEd Maste 	mi->MntCount = cid;
41504f4d586SEd Maste 
41604f4d586SEd Maste 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
41704f4d586SEd Maste 			 sizeof(struct aac_mntinfo))) {
418a620bad0SEd Maste 		printf("Error probing container %d\n", cid);
41904f4d586SEd Maste 		return (NULL);
42004f4d586SEd Maste 	}
42104f4d586SEd Maste 
42204f4d586SEd Maste 	return ((struct aac_mntinforesp *)&fib->data[0]);
42304f4d586SEd Maste }
42404f4d586SEd Maste 
42504f4d586SEd Maste /*
42635863739SMike Smith  * Probe for containers, create disks.
42735863739SMike Smith  */
42835863739SMike Smith static void
42935863739SMike Smith aac_startup(void *arg)
43035863739SMike Smith {
431914da7d0SScott Long 	struct aac_softc *sc;
432cbfd045bSScott Long 	struct aac_fib *fib;
43304f4d586SEd Maste 	struct aac_mntinforesp *mir;
434795d7dc0SScott Long 	int count = 0, i = 0;
43535863739SMike Smith 
436914da7d0SScott Long 	sc = (struct aac_softc *)arg;
43731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
438914da7d0SScott Long 
43935863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
44035863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
44135863739SMike Smith 
4427cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
44303b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
444cbfd045bSScott Long 
44535863739SMike Smith 	/* loop over possible containers */
44636e0bf6eSScott Long 	do {
44704f4d586SEd Maste 		if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
44835863739SMike Smith 			continue;
44904f4d586SEd Maste 		if (i == 0)
450795d7dc0SScott Long 			count = mir->MntRespCount;
451cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
45236e0bf6eSScott Long 		i++;
453795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
454cbfd045bSScott Long 
455cbfd045bSScott Long 	aac_release_sync_fib(sc);
4567cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
45735863739SMike Smith 
45835863739SMike Smith 	/* poke the bus to actually attach the child devices */
45935863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
46035863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
46135863739SMike Smith 
46235863739SMike Smith 	/* mark the controller up */
46335863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
46435863739SMike Smith 
46535863739SMike Smith 	/* enable interrupts now */
46635863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
46735863739SMike Smith }
46835863739SMike Smith 
469914da7d0SScott Long /*
4704109ba51SEd Maste  * Create a device to represent a new container
471914da7d0SScott Long  */
472914da7d0SScott Long static void
473cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
474914da7d0SScott Long {
475914da7d0SScott Long 	struct aac_container *co;
476914da7d0SScott Long 	device_t child;
477914da7d0SScott Long 
478914da7d0SScott Long 	/*
479914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
480914da7d0SScott Long 	 * the possible types may never show up.
481914da7d0SScott Long 	 */
482914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
483a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
484a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
485914da7d0SScott Long 		if (co == NULL)
486a620bad0SEd Maste 			panic("Out of memory?!");
48731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x  name '%.16s'  size %u  type %d",
488914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
489914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
490914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
491914da7d0SScott Long 
492fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
493914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
494914da7d0SScott Long 		else
495914da7d0SScott Long 			device_set_ivars(child, co);
496914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
497914da7d0SScott Long 				mir->MntTable[0].VolType));
498914da7d0SScott Long 		co->co_disk = child;
499914da7d0SScott Long 		co->co_found = f;
500914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
501914da7d0SScott Long 		      sizeof(struct aac_mntobj));
502bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
503914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
504bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
505914da7d0SScott Long 	}
506914da7d0SScott Long }
507914da7d0SScott Long 
508914da7d0SScott Long /*
50904f4d586SEd Maste  * Allocate resources associated with (sc)
51004f4d586SEd Maste  */
51104f4d586SEd Maste static int
51204f4d586SEd Maste aac_alloc(struct aac_softc *sc)
51304f4d586SEd Maste {
51431a0399eSEd Maste 
51531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
51631a0399eSEd Maste 
51704f4d586SEd Maste 	/*
51804f4d586SEd Maste 	 * Create DMA tag for mapping buffers into controller-addressable space.
51904f4d586SEd Maste 	 */
52004f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
52104f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
52204f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
52304f4d586SEd Maste 			       BUS_SPACE_MAXADDR :
52404f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
52504f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
52604f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
52704f4d586SEd Maste 			       MAXBSIZE,		/* maxsize */
52804f4d586SEd Maste 			       sc->aac_sg_tablesize,	/* nsegments */
52904f4d586SEd Maste 			       MAXBSIZE,		/* maxsegsize */
53004f4d586SEd Maste 			       BUS_DMA_ALLOCNOW,	/* flags */
53104f4d586SEd Maste 			       busdma_lock_mutex,	/* lockfunc */
53204f4d586SEd Maste 			       &sc->aac_io_lock,	/* lockfuncarg */
53304f4d586SEd Maste 			       &sc->aac_buffer_dmat)) {
53404f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
53504f4d586SEd Maste 		return (ENOMEM);
53604f4d586SEd Maste 	}
53704f4d586SEd Maste 
53804f4d586SEd Maste 	/*
53904f4d586SEd Maste 	 * Create DMA tag for mapping FIBs into controller-addressable space..
54004f4d586SEd Maste 	 */
54104f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
54204f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
54304f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
54404f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
54504f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
54604f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
54704f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
54804f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
54904f4d586SEd Maste 			       sc->aac_max_fib_size,  /* maxsize */
55004f4d586SEd Maste 			       1,			/* nsegments */
55104f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
55204f4d586SEd Maste 			       sc->aac_max_fib_size,	/* maxsize */
55304f4d586SEd Maste 			       0,			/* flags */
55404f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
55504f4d586SEd Maste 			       &sc->aac_fib_dmat)) {
55604f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
55704f4d586SEd Maste 		return (ENOMEM);
55804f4d586SEd Maste 	}
55904f4d586SEd Maste 
56004f4d586SEd Maste 	/*
56104f4d586SEd Maste 	 * Create DMA tag for the common structure and allocate it.
56204f4d586SEd Maste 	 */
56304f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
56404f4d586SEd Maste 			       1, 0,			/* algnmnt, boundary */
56504f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
56604f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
56704f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
56804f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
56904f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
57004f4d586SEd Maste 			       8192 + sizeof(struct aac_common), /* maxsize */
57104f4d586SEd Maste 			       1,			/* nsegments */
57204f4d586SEd Maste 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
57304f4d586SEd Maste 			       0,			/* flags */
57404f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
57504f4d586SEd Maste 			       &sc->aac_common_dmat)) {
57604f4d586SEd Maste 		device_printf(sc->aac_dev,
57704f4d586SEd Maste 			      "can't allocate common structure DMA tag\n");
57804f4d586SEd Maste 		return (ENOMEM);
57904f4d586SEd Maste 	}
58004f4d586SEd Maste 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
58104f4d586SEd Maste 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
58204f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate common structure\n");
58304f4d586SEd Maste 		return (ENOMEM);
58404f4d586SEd Maste 	}
58504f4d586SEd Maste 
58604f4d586SEd Maste 	/*
58704f4d586SEd Maste 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
58804f4d586SEd Maste 	 * below address 8192 in physical memory.
58904f4d586SEd Maste 	 * XXX If the padding is not needed, can it be put to use instead
59004f4d586SEd Maste 	 * of ignored?
59104f4d586SEd Maste 	 */
59204f4d586SEd Maste 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
59304f4d586SEd Maste 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
59404f4d586SEd Maste 			aac_common_map, sc, 0);
59504f4d586SEd Maste 
59604f4d586SEd Maste 	if (sc->aac_common_busaddr < 8192) {
59704f4d586SEd Maste 		sc->aac_common = (struct aac_common *)
59804f4d586SEd Maste 		    ((uint8_t *)sc->aac_common + 8192);
59904f4d586SEd Maste 		sc->aac_common_busaddr += 8192;
60004f4d586SEd Maste 	}
60104f4d586SEd Maste 	bzero(sc->aac_common, sizeof(*sc->aac_common));
60204f4d586SEd Maste 
60304f4d586SEd Maste 	/* Allocate some FIBs and associated command structs */
60404f4d586SEd Maste 	TAILQ_INIT(&sc->aac_fibmap_tqh);
60504f4d586SEd Maste 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
60604f4d586SEd Maste 				  M_AACBUF, M_WAITOK|M_ZERO);
60704f4d586SEd Maste 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
60804f4d586SEd Maste 		if (aac_alloc_commands(sc) != 0)
60904f4d586SEd Maste 			break;
61004f4d586SEd Maste 	}
61104f4d586SEd Maste 	if (sc->total_fibs == 0)
61204f4d586SEd Maste 		return (ENOMEM);
61304f4d586SEd Maste 
61404f4d586SEd Maste 	return (0);
61504f4d586SEd Maste }
61604f4d586SEd Maste 
61704f4d586SEd Maste /*
61835863739SMike Smith  * Free all of the resources associated with (sc)
61935863739SMike Smith  *
62035863739SMike Smith  * Should not be called if the controller is active.
62135863739SMike Smith  */
62235863739SMike Smith void
62335863739SMike Smith aac_free(struct aac_softc *sc)
62435863739SMike Smith {
625ffb37f33SScott Long 
62631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
62735863739SMike Smith 
62835863739SMike Smith 	/* remove the control device */
62935863739SMike Smith 	if (sc->aac_dev_t != NULL)
63035863739SMike Smith 		destroy_dev(sc->aac_dev_t);
63135863739SMike Smith 
6320b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
6338480cc63SScott Long 	aac_free_commands(sc);
6340b94a66eSMike Smith 	if (sc->aac_fib_dmat)
6350b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
63635863739SMike Smith 
637ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
638ffb37f33SScott Long 
63935863739SMike Smith 	/* destroy the common area */
64035863739SMike Smith 	if (sc->aac_common) {
64135863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
642c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
643c6eafcf2SScott Long 				sc->aac_common_dmamap);
64435863739SMike Smith 	}
6450b94a66eSMike Smith 	if (sc->aac_common_dmat)
6460b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
64735863739SMike Smith 
64835863739SMike Smith 	/* disconnect the interrupt handler */
64935863739SMike Smith 	if (sc->aac_intr)
65035863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
65135863739SMike Smith 	if (sc->aac_irq != NULL)
652c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
653c6eafcf2SScott Long 				     sc->aac_irq);
65435863739SMike Smith 
65535863739SMike Smith 	/* destroy data-transfer DMA tag */
65635863739SMike Smith 	if (sc->aac_buffer_dmat)
65735863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
65835863739SMike Smith 
65935863739SMike Smith 	/* destroy the parent DMA tag */
66035863739SMike Smith 	if (sc->aac_parent_dmat)
66135863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
66235863739SMike Smith 
66335863739SMike Smith 	/* release the register window mapping */
664ff0991c4SAttilio Rao 	if (sc->aac_regs_res0 != NULL)
665914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
666ff0991c4SAttilio Rao 				     sc->aac_regs_rid0, sc->aac_regs_res0);
667ff0991c4SAttilio Rao 	if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL)
668ff0991c4SAttilio Rao 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
669ff0991c4SAttilio Rao 				     sc->aac_regs_rid1, sc->aac_regs_res1);
67035863739SMike Smith }
67135863739SMike Smith 
672914da7d0SScott Long /*
67335863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
67435863739SMike Smith  */
67535863739SMike Smith int
67635863739SMike Smith aac_detach(device_t dev)
67735863739SMike Smith {
678914da7d0SScott Long 	struct aac_softc *sc;
67970545d1aSScott Long 	struct aac_container *co;
68070545d1aSScott Long 	struct aac_sim	*sim;
68135863739SMike Smith 	int error;
68235863739SMike Smith 
683914da7d0SScott Long 	sc = device_get_softc(dev);
68431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
685914da7d0SScott Long 
68635863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
68735863739SMike Smith 		return(EBUSY);
68835863739SMike Smith 
689ff0991c4SAttilio Rao 	callout_drain(&sc->aac_daemontime);
690ff0991c4SAttilio Rao 
69170545d1aSScott Long 	/* Remove the child containers */
692a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
69370545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
69470545d1aSScott Long 		if (error)
69570545d1aSScott Long 			return (error);
69665ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
697a761a1caSScott Long 		free(co, M_AACBUF);
69870545d1aSScott Long 	}
69970545d1aSScott Long 
70070545d1aSScott Long 	/* Remove the CAM SIMs */
701a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
702a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
70370545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
70470545d1aSScott Long 		if (error)
70570545d1aSScott Long 			return (error);
706a761a1caSScott Long 		free(sim, M_AACBUF);
70770545d1aSScott Long 	}
70870545d1aSScott Long 
70936e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
71036e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
71136e0bf6eSScott Long 		wakeup(sc->aifthread);
71236e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
71336e0bf6eSScott Long 	}
71436e0bf6eSScott Long 
71536e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
716a620bad0SEd Maste 		panic("Cannot shutdown AIF thread");
71736e0bf6eSScott Long 
71835863739SMike Smith 	if ((error = aac_shutdown(dev)))
71935863739SMike Smith 		return(error);
72035863739SMike Smith 
7215f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
7225f54d522SScott Long 
72335863739SMike Smith 	aac_free(sc);
72435863739SMike Smith 
725dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
726dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
727dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
728dc9efde5SScott Long 
72935863739SMike Smith 	return(0);
73035863739SMike Smith }
73135863739SMike Smith 
732914da7d0SScott Long /*
73335863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
73435863739SMike Smith  *
73535863739SMike Smith  * This function is called before detach or system shutdown.
73635863739SMike Smith  *
7370b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
73835863739SMike Smith  * allow shutdown if any device is open.
73935863739SMike Smith  */
74035863739SMike Smith int
74135863739SMike Smith aac_shutdown(device_t dev)
74235863739SMike Smith {
743914da7d0SScott Long 	struct aac_softc *sc;
744cbfd045bSScott Long 	struct aac_fib *fib;
745cbfd045bSScott Long 	struct aac_close_command *cc;
74635863739SMike Smith 
747914da7d0SScott Long 	sc = device_get_softc(dev);
74831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
749914da7d0SScott Long 
75035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
75135863739SMike Smith 
75235863739SMike Smith 	/*
75335863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
75435863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
75535863739SMike Smith 	 * We've been closed and all I/O completed already
75635863739SMike Smith 	 */
75735863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
75835863739SMike Smith 
7597cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
76003b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
761cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
762cbfd045bSScott Long 
76339ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
764cbfd045bSScott Long 	cc->Command = VM_CloseAll;
765cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
766cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
767cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
76835863739SMike Smith 		printf("FAILED.\n");
76970545d1aSScott Long 	else
77070545d1aSScott Long 		printf("done\n");
77170545d1aSScott Long #if 0
772914da7d0SScott Long 	else {
773cbfd045bSScott Long 		fib->data[0] = 0;
77436e0bf6eSScott Long 		/*
775914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
77636e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
77736e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
77836e0bf6eSScott Long 		 * driver module with the intent to reload it later.
77936e0bf6eSScott Long 		 */
780cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
781cbfd045bSScott Long 		    fib, 1)) {
78235863739SMike Smith 			printf("FAILED.\n");
78335863739SMike Smith 		} else {
78435863739SMike Smith 			printf("done.\n");
78535863739SMike Smith 		}
78635863739SMike Smith 	}
78770545d1aSScott Long #endif
78835863739SMike Smith 
78935863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
7903576af8fSScott Long 	aac_release_sync_fib(sc);
7917cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
79235863739SMike Smith 
79335863739SMike Smith 	return(0);
79435863739SMike Smith }
79535863739SMike Smith 
796914da7d0SScott Long /*
79735863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
79835863739SMike Smith  */
79935863739SMike Smith int
80035863739SMike Smith aac_suspend(device_t dev)
80135863739SMike Smith {
802914da7d0SScott Long 	struct aac_softc *sc;
80335863739SMike Smith 
804914da7d0SScott Long 	sc = device_get_softc(dev);
805914da7d0SScott Long 
80631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
80735863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
80835863739SMike Smith 
80935863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
81035863739SMike Smith 	return(0);
81135863739SMike Smith }
81235863739SMike Smith 
813914da7d0SScott Long /*
81435863739SMike Smith  * Bring the controller back to a state ready for operation.
81535863739SMike Smith  */
81635863739SMike Smith int
81735863739SMike Smith aac_resume(device_t dev)
81835863739SMike Smith {
819914da7d0SScott Long 	struct aac_softc *sc;
82035863739SMike Smith 
821914da7d0SScott Long 	sc = device_get_softc(dev);
822914da7d0SScott Long 
82331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
82435863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
82535863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
82635863739SMike Smith 	return(0);
82735863739SMike Smith }
82835863739SMike Smith 
829914da7d0SScott Long /*
8307cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
83135863739SMike Smith  */
83235863739SMike Smith void
8337cb209f5SScott Long aac_new_intr(void *arg)
8347cb209f5SScott Long {
8357cb209f5SScott Long 	struct aac_softc *sc;
8367cb209f5SScott Long 	u_int32_t index, fast;
8377cb209f5SScott Long 	struct aac_command *cm;
8387cb209f5SScott Long 	struct aac_fib *fib;
8397cb209f5SScott Long 	int i;
8407cb209f5SScott Long 
8417cb209f5SScott Long 	sc = (struct aac_softc *)arg;
8427cb209f5SScott Long 
84331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
8447cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
8457cb209f5SScott Long 	while (1) {
8467cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
8477cb209f5SScott Long 		if (index == 0xffffffff)
8487cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
8497cb209f5SScott Long 		if (index == 0xffffffff)
8507cb209f5SScott Long 			break;
8517cb209f5SScott Long 		if (index & 2) {
8527cb209f5SScott Long 			if (index == 0xfffffffe) {
8537cb209f5SScott Long 				/* XXX This means that the controller wants
8547cb209f5SScott Long 				 * more work.  Ignore it for now.
8557cb209f5SScott Long 				 */
8567cb209f5SScott Long 				continue;
8577cb209f5SScott Long 			}
8587cb209f5SScott Long 			/* AIF */
8597cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
8607cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
8617cb209f5SScott Long 			if (fib == NULL) {
8627cb209f5SScott Long 				/* If we're really this short on memory,
8637cb209f5SScott Long 				 * hopefully breaking out of the handler will
8647cb209f5SScott Long 				 * allow something to get freed.  This
8657cb209f5SScott Long 				 * actually sucks a whole lot.
8667cb209f5SScott Long 				 */
8677cb209f5SScott Long 				break;
8687cb209f5SScott Long 			}
8697cb209f5SScott Long 			index &= ~2;
8707cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
871ff0991c4SAttilio Rao 				((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4);
8727cb209f5SScott Long 			aac_handle_aif(sc, fib);
8737cb209f5SScott Long 			free(fib, M_AACBUF);
8747cb209f5SScott Long 
8757cb209f5SScott Long 			/*
8767cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
8777cb209f5SScott Long 			 * know that we are done with it.
8787cb209f5SScott Long 			 */
8797cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
8807cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
8817cb209f5SScott Long 		} else {
8827cb209f5SScott Long 			fast = index & 1;
8837cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
8847cb209f5SScott Long 			fib = cm->cm_fib;
8857cb209f5SScott Long 			if (fast) {
8867cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
8877cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
8887cb209f5SScott Long 			}
8897cb209f5SScott Long 			aac_remove_busy(cm);
8907cb209f5SScott Long  			aac_unmap_command(cm);
8917cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
8927cb209f5SScott Long 
8937cb209f5SScott Long 			/* is there a completion handler? */
8947cb209f5SScott Long 			if (cm->cm_complete != NULL) {
8957cb209f5SScott Long 				cm->cm_complete(cm);
8967cb209f5SScott Long 			} else {
8977cb209f5SScott Long 				/* assume that someone is sleeping on this
8987cb209f5SScott Long 				 * command
8997cb209f5SScott Long 				 */
9007cb209f5SScott Long 				wakeup(cm);
9017cb209f5SScott Long 			}
9027cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
9037cb209f5SScott Long 		}
9047cb209f5SScott Long 	}
9057cb209f5SScott Long 	/* see if we can start some more I/O */
9067cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
9077cb209f5SScott Long 		aac_startio(sc);
9087cb209f5SScott Long 
9097cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
9107cb209f5SScott Long }
9117cb209f5SScott Long 
912e46b9eeaSEd Maste /*
913e46b9eeaSEd Maste  * Interrupt filter for !NEW_COMM interface.
914e46b9eeaSEd Maste  */
915ef544f63SPaolo Pisati int
916e46b9eeaSEd Maste aac_filter(void *arg)
91735863739SMike Smith {
918914da7d0SScott Long 	struct aac_softc *sc;
91970545d1aSScott Long 	u_int16_t reason;
92035863739SMike Smith 
921914da7d0SScott Long 	sc = (struct aac_softc *)arg;
922914da7d0SScott Long 
92331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
924f30ac74cSScott Long 	/*
9259148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
9269148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
9279148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
9289148fa21SScott Long 	 * ugly.
929f30ac74cSScott Long 	 */
93035863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
931f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
932f30ac74cSScott Long 
9339c3a7fceSScott Long 	/* handle completion processing */
9349148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
9359148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
93635863739SMike Smith 
9379148fa21SScott Long 	/* controller wants to talk to us */
9389148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
93970545d1aSScott Long 		/*
9409148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
9419148fa21SScott Long 		 * that start with a NULL.
94270545d1aSScott Long 		 */
9439148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
9449148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
9459148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
94670545d1aSScott Long 
9479148fa21SScott Long 		/*
9489148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
949a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
9509148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
9519148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
9529148fa21SScott Long 		 * if needed.
9539148fa21SScott Long 		 */
95436e0bf6eSScott Long 		wakeup(sc->aifthread);
95536e0bf6eSScott Long 	}
956ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
9579148fa21SScott Long }
95835863739SMike Smith 
959c6eafcf2SScott Long /*
960914da7d0SScott Long  * Command Processing
961914da7d0SScott Long  */
96235863739SMike Smith 
963914da7d0SScott Long /*
96435863739SMike Smith  * Start as much queued I/O as possible on the controller
96535863739SMike Smith  */
966fe3cb0e1SScott Long void
96735863739SMike Smith aac_startio(struct aac_softc *sc)
96835863739SMike Smith {
96935863739SMike Smith 	struct aac_command *cm;
970397fa34fSScott Long 	int error;
97135863739SMike Smith 
97231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
97335863739SMike Smith 
97435863739SMike Smith 	for (;;) {
975914da7d0SScott Long 		/*
976397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
977397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
978397fa34fSScott Long 		 */
979397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
980397fa34fSScott Long 			break;
981397fa34fSScott Long 
982397fa34fSScott Long 		/*
983914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
984914da7d0SScott Long 		 * resources
985914da7d0SScott Long 		 */
98635863739SMike Smith 		cm = aac_dequeue_ready(sc);
98735863739SMike Smith 
988914da7d0SScott Long 		/*
989914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
990914da7d0SScott Long 		 * return)
991914da7d0SScott Long 		 */
9920b94a66eSMike Smith 		if (cm == NULL)
99335863739SMike Smith 			aac_bio_command(sc, &cm);
99435863739SMike Smith 
99535863739SMike Smith 		/* nothing to do? */
99635863739SMike Smith 		if (cm == NULL)
99735863739SMike Smith 			break;
99835863739SMike Smith 
999cd481291SScott Long 		/* don't map more than once */
1000cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
10014102d44bSScott Long 			panic("aac: command %p already mapped", cm);
100235863739SMike Smith 
1003397fa34fSScott Long 		/*
1004397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
1005397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
1006397fa34fSScott Long 		 * busdma.
1007397fa34fSScott Long 		 */
1008cd481291SScott Long 		if (cm->cm_datalen != 0) {
1009397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
1010397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
1011397fa34fSScott Long 						cm->cm_datalen,
1012cd481291SScott Long 						aac_map_command_sg, cm, 0);
1013cd481291SScott Long 			if (error == EINPROGRESS) {
101431a0399eSEd Maste 				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
1015cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
1016cd481291SScott Long 				error = 0;
1017614c22b2SScott Long 			} else if (error != 0)
1018397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
1019a620bad0SEd Maste 				      "busdma", error);
1020397fa34fSScott Long 		} else
10218778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
1022cd481291SScott Long 	}
102335863739SMike Smith }
102435863739SMike Smith 
1025914da7d0SScott Long /*
102635863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
102735863739SMike Smith  */
102835863739SMike Smith static void
102970545d1aSScott Long aac_command_thread(struct aac_softc *sc)
103035863739SMike Smith {
103135863739SMike Smith 	struct aac_fib *fib;
103235863739SMike Smith 	u_int32_t fib_size;
10339148fa21SScott Long 	int size, retval;
103435863739SMike Smith 
103531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
103635863739SMike Smith 
1037bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1038a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
103936e0bf6eSScott Long 
1040a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1041a32a982dSScott Long 
1042a32a982dSScott Long 		retval = 0;
1043a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1044a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1045a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
104636e0bf6eSScott Long 
10479148fa21SScott Long 		/*
10489148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
10499148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
10509148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
10519148fa21SScott Long 		 */
10529148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1053bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
1054a32a982dSScott Long 			aac_alloc_commands(sc);
1055bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
10564102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1057a32a982dSScott Long 			aac_startio(sc);
1058a32a982dSScott Long 		}
10599148fa21SScott Long 
10609148fa21SScott Long 		/*
10619148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
10629148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
10639148fa21SScott Long 		 * always fire.
10649148fa21SScott Long 		 */
10659148fa21SScott Long 		if (retval == EWOULDBLOCK)
106670545d1aSScott Long 			aac_timeout(sc);
106770545d1aSScott Long 
106870545d1aSScott Long 		/* Check the hardware printf message buffer */
10699148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
107070545d1aSScott Long 			aac_print_printf(sc);
107170545d1aSScott Long 
10729148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
10737cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
10747cb209f5SScott Long 			continue;
10757cb209f5SScott Long 		for (;;) {
10767cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
10777cb209f5SScott Long 					   &fib_size, &fib))
10787cb209f5SScott Long 				break;
107935863739SMike Smith 
108036e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
108136e0bf6eSScott Long 
108235863739SMike Smith 			switch (fib->Header.Command) {
108335863739SMike Smith 			case AifRequest:
108436e0bf6eSScott Long 				aac_handle_aif(sc, fib);
108535863739SMike Smith 				break;
108635863739SMike Smith 			default:
1087914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
1088914da7d0SScott Long 					      "from controller\n");
108935863739SMike Smith 				break;
109035863739SMike Smith 			}
109135863739SMike Smith 
109236e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
10937cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
109436e0bf6eSScott Long 				break;
10957cb209f5SScott Long 			}
109636e0bf6eSScott Long 
109770545d1aSScott Long 			/* Return the AIF to the controller. */
109836e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
109936e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
110036e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
110136e0bf6eSScott Long 
110236e0bf6eSScott Long 				/* XXX Compute the Size field? */
110336e0bf6eSScott Long 				size = fib->Header.Size;
110436e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
110536e0bf6eSScott Long 					size = sizeof(struct aac_fib);
110636e0bf6eSScott Long 					fib->Header.Size = size;
110736e0bf6eSScott Long 				}
110836e0bf6eSScott Long 				/*
1109914da7d0SScott Long 				 * Since we did not generate this command, it
1110914da7d0SScott Long 				 * cannot go through the normal
1111914da7d0SScott Long 				 * enqueue->startio chain.
111236e0bf6eSScott Long 				 */
1113914da7d0SScott Long 				aac_enqueue_response(sc,
1114914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
1115914da7d0SScott Long 						 fib);
111636e0bf6eSScott Long 			}
111736e0bf6eSScott Long 		}
111836e0bf6eSScott Long 	}
111936e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1120bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
112136e0bf6eSScott Long 	wakeup(sc->aac_dev);
112236e0bf6eSScott Long 
11233745c395SJulian Elischer 	kproc_exit(0);
112435863739SMike Smith }
112535863739SMike Smith 
1126914da7d0SScott Long /*
11279c3a7fceSScott Long  * Process completed commands.
112835863739SMike Smith  */
112935863739SMike Smith static void
11309c3a7fceSScott Long aac_complete(void *context, int pending)
113135863739SMike Smith {
11329c3a7fceSScott Long 	struct aac_softc *sc;
113335863739SMike Smith 	struct aac_command *cm;
113435863739SMike Smith 	struct aac_fib *fib;
113535863739SMike Smith 	u_int32_t fib_size;
113635863739SMike Smith 
11379c3a7fceSScott Long 	sc = (struct aac_softc *)context;
113831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
11399c3a7fceSScott Long 
1140bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1141ae543596SScott Long 
11429c3a7fceSScott Long 	/* pull completed commands off the queue */
114335863739SMike Smith 	for (;;) {
114435863739SMike Smith 		/* look for completed FIBs on our queue */
1145914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1146914da7d0SScott Long 							&fib))
114735863739SMike Smith 			break;	/* nothing to do */
114835863739SMike Smith 
1149ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1150cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
115135863739SMike Smith 		if (cm == NULL) {
115235863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
11539c3a7fceSScott Long 			break;
11549c3a7fceSScott Long 		}
11550b94a66eSMike Smith 		aac_remove_busy(cm);
11567cb209f5SScott Long 
1157ecd1c51fSScott Long  		aac_unmap_command(cm);
115835863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
115935863739SMike Smith 
116035863739SMike Smith 		/* is there a completion handler? */
116135863739SMike Smith 		if (cm->cm_complete != NULL) {
116235863739SMike Smith 			cm->cm_complete(cm);
116335863739SMike Smith 		} else {
116435863739SMike Smith 			/* assume that someone is sleeping on this command */
116535863739SMike Smith 			wakeup(cm);
116635863739SMike Smith 		}
116735863739SMike Smith 	}
11680b94a66eSMike Smith 
11690b94a66eSMike Smith 	/* see if we can start some more I/O */
1170cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
11710b94a66eSMike Smith 	aac_startio(sc);
1172ae543596SScott Long 
1173bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
117435863739SMike Smith }
117535863739SMike Smith 
1176914da7d0SScott Long /*
117735863739SMike Smith  * Handle a bio submitted from a disk device.
117835863739SMike Smith  */
117935863739SMike Smith void
118035863739SMike Smith aac_submit_bio(struct bio *bp)
118135863739SMike Smith {
1182914da7d0SScott Long 	struct aac_disk *ad;
1183914da7d0SScott Long 	struct aac_softc *sc;
118435863739SMike Smith 
11857540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1186914da7d0SScott Long 	sc = ad->ad_controller;
118731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1188914da7d0SScott Long 
118935863739SMike Smith 	/* queue the BIO and try to get some work done */
11900b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
119135863739SMike Smith 	aac_startio(sc);
119235863739SMike Smith }
119335863739SMike Smith 
1194914da7d0SScott Long /*
119535863739SMike Smith  * Get a bio and build a command to go with it.
119635863739SMike Smith  */
119735863739SMike Smith static int
119835863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
119935863739SMike Smith {
120035863739SMike Smith 	struct aac_command *cm;
120135863739SMike Smith 	struct aac_fib *fib;
120235863739SMike Smith 	struct aac_disk *ad;
120335863739SMike Smith 	struct bio *bp;
120435863739SMike Smith 
120531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
120635863739SMike Smith 
120735863739SMike Smith 	/* get the resources we will need */
120835863739SMike Smith 	cm = NULL;
1209a32a982dSScott Long 	bp = NULL;
121035863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
121135863739SMike Smith 		goto fail;
1212a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1213a32a982dSScott Long 		goto fail;
121435863739SMike Smith 
121535863739SMike Smith 	/* fill out the command */
12160b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
12170b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
12180b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
121935863739SMike Smith 	cm->cm_private = bp;
12202b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
122136e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
122235863739SMike Smith 
122335863739SMike Smith 	/* build the FIB */
122435863739SMike Smith 	fib = cm->cm_fib;
1225b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
122635863739SMike Smith 	fib->Header.XferState =
122735863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
122835863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1229f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
123035863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
123135863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1232f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1233f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1234f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
123535863739SMike Smith 
123635863739SMike Smith 	/* build the read/write request */
12377540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1238b85f5808SScott Long 
12397cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
12407cb209f5SScott Long 		struct aac_raw_io *raw;
12417cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
12427cb209f5SScott Long 		fib->Header.Command = RawIo;
12437cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
12447cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
12457cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
12467cb209f5SScott Long 		raw->BpTotal = 0;
12477cb209f5SScott Long 		raw->BpComplete = 0;
12487cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
12497cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
12507cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
12517cb209f5SScott Long 			raw->Flags = 1;
12527cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
12537cb209f5SScott Long 		} else {
12547cb209f5SScott Long 			raw->Flags = 0;
12557cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
12567cb209f5SScott Long 		}
12577cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1258b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
12599e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1260b85f5808SScott Long 			struct aac_blockread *br;
126135863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
126235863739SMike Smith 			br->Command = VM_CtBlockRead;
126335863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
126435863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
126535863739SMike Smith 			br->ByteCount = bp->bio_bcount;
126635863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
126735863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
126835863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
126935863739SMike Smith 		} else {
1270b85f5808SScott Long 			struct aac_blockwrite *bw;
127135863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
127235863739SMike Smith 			bw->Command = VM_CtBlockWrite;
127335863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
127435863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
127535863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1276b85f5808SScott Long 			bw->Stable = CUNSTABLE;
127735863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
127835863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
127935863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
128035863739SMike Smith 		}
1281b85f5808SScott Long 	} else {
1282b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1283b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1284b85f5808SScott Long 			struct aac_blockread64 *br;
1285b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1286b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1287b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1288b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1289b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1290b85f5808SScott Long 			br->Pad = 0;
1291b85f5808SScott Long 			br->Flags = 0;
1292b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
129354e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAIN;
1294eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1295b85f5808SScott Long 		} else {
1296b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1297b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1298b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1299b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1300b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1301b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1302b85f5808SScott Long 			bw->Pad = 0;
1303b85f5808SScott Long 			bw->Flags = 0;
1304b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
130554e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAOUT;
1306eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1307b85f5808SScott Long 		}
1308b85f5808SScott Long 	}
130935863739SMike Smith 
131035863739SMike Smith 	*cmp = cm;
131135863739SMike Smith 	return(0);
131235863739SMike Smith 
131335863739SMike Smith fail:
13147cb209f5SScott Long 	if (bp != NULL)
13157cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
131635863739SMike Smith 	if (cm != NULL)
131735863739SMike Smith 		aac_release_command(cm);
131835863739SMike Smith 	return(ENOMEM);
131935863739SMike Smith }
132035863739SMike Smith 
1321914da7d0SScott Long /*
132235863739SMike Smith  * Handle a bio-instigated command that has been completed.
132335863739SMike Smith  */
132435863739SMike Smith static void
132535863739SMike Smith aac_bio_complete(struct aac_command *cm)
132635863739SMike Smith {
132735863739SMike Smith 	struct aac_blockread_response *brr;
132835863739SMike Smith 	struct aac_blockwrite_response *bwr;
132935863739SMike Smith 	struct bio *bp;
133035863739SMike Smith 	AAC_FSAStatus status;
133135863739SMike Smith 
133235863739SMike Smith 	/* fetch relevant status and then release the command */
133335863739SMike Smith 	bp = (struct bio *)cm->cm_private;
13349e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
133535863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
133635863739SMike Smith 		status = brr->Status;
133735863739SMike Smith 	} else {
133835863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
133935863739SMike Smith 		status = bwr->Status;
134035863739SMike Smith 	}
134135863739SMike Smith 	aac_release_command(cm);
134235863739SMike Smith 
134335863739SMike Smith 	/* fix up the bio based on status */
134435863739SMike Smith 	if (status == ST_OK) {
134535863739SMike Smith 		bp->bio_resid = 0;
134635863739SMike Smith 	} else {
134735863739SMike Smith 		bp->bio_error = EIO;
134835863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
13490b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1350914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1351914da7d0SScott Long 						    status);
135235863739SMike Smith 	}
13530b94a66eSMike Smith 	aac_biodone(bp);
135435863739SMike Smith }
135535863739SMike Smith 
1356914da7d0SScott Long /*
135735863739SMike Smith  * Submit a command to the controller, return when it completes.
1358b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1359b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1360d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1361d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1362d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1363d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1364d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
136535863739SMike Smith  */
136635863739SMike Smith static int
1367d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
136835863739SMike Smith {
1369ae543596SScott Long 	struct aac_softc *sc;
1370d8a0a473SScott Long 	int error;
137135863739SMike Smith 
1372ae543596SScott Long 	sc = cm->cm_sc;
137331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1374ae543596SScott Long 
137535863739SMike Smith 	/* Put the command on the ready queue and get things going */
137636e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
137735863739SMike Smith 	aac_enqueue_ready(cm);
1378ae543596SScott Long 	aac_startio(sc);
1379ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
138035863739SMike Smith 	return(error);
138135863739SMike Smith }
138235863739SMike Smith 
1383914da7d0SScott Long /*
1384914da7d0SScott Long  *Command Buffer Management
1385914da7d0SScott Long  */
138635863739SMike Smith 
1387914da7d0SScott Long /*
138835863739SMike Smith  * Allocate a command.
138935863739SMike Smith  */
1390fe3cb0e1SScott Long int
139135863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
139235863739SMike Smith {
139335863739SMike Smith 	struct aac_command *cm;
139435863739SMike Smith 
139531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
139635863739SMike Smith 
1397ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1398b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1399ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1400ae543596SScott Long 			wakeup(sc->aifthread);
1401b85f5808SScott Long 		}
1402ae543596SScott Long 		return (EBUSY);
1403ffb37f33SScott Long 	}
140435863739SMike Smith 
14050b94a66eSMike Smith 	*cmp = cm;
14060b94a66eSMike Smith 	return(0);
14070b94a66eSMike Smith }
14080b94a66eSMike Smith 
1409914da7d0SScott Long /*
14100b94a66eSMike Smith  * Release a command back to the freelist.
14110b94a66eSMike Smith  */
1412fe3cb0e1SScott Long void
14130b94a66eSMike Smith aac_release_command(struct aac_command *cm)
14140b94a66eSMike Smith {
14157cb209f5SScott Long 	struct aac_event *event;
14167cb209f5SScott Long 	struct aac_softc *sc;
14177cb209f5SScott Long 
141831a0399eSEd Maste 	sc = cm->cm_sc;
141931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
14200b94a66eSMike Smith 
14214109ba51SEd Maste 	/* (re)initialize the command/FIB */
142235863739SMike Smith 	cm->cm_sgtable = NULL;
142335863739SMike Smith 	cm->cm_flags = 0;
142435863739SMike Smith 	cm->cm_complete = NULL;
142535863739SMike Smith 	cm->cm_private = NULL;
142635863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
142735863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
142835863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
14297cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
143035863739SMike Smith 
143135863739SMike Smith 	/*
143235863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
143335863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
14344109ba51SEd Maste 	 * initialized here for debugging purposes only.
143535863739SMike Smith 	 */
1436f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1437f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
143835863739SMike Smith 
143935863739SMike Smith 	aac_enqueue_free(cm);
14407cb209f5SScott Long 
1441eb5cbaa0SEd Maste 	/*
1442eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1443eb5cbaa0SEd Maste 	 * stranded.
1444eb5cbaa0SEd Maste 	 */
1445eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
14467cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
14477cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
14487cb209f5SScott Long 	}
144935863739SMike Smith }
145035863739SMike Smith 
1451914da7d0SScott Long /*
14520b94a66eSMike Smith  * Map helper for command/FIB allocation.
145335863739SMike Smith  */
145435863739SMike Smith static void
14550b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
145635863739SMike Smith {
14577cb209f5SScott Long 	uint64_t	*fibphys;
1458914da7d0SScott Long 
14597cb209f5SScott Long 	fibphys = (uint64_t *)arg;
146035863739SMike Smith 
1461ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
146235863739SMike Smith }
146335863739SMike Smith 
1464914da7d0SScott Long /*
14654109ba51SEd Maste  * Allocate and initialize commands/FIBs for this adapter.
146635863739SMike Smith  */
14670b94a66eSMike Smith static int
14680b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
146935863739SMike Smith {
147035863739SMike Smith 	struct aac_command *cm;
1471ffb37f33SScott Long 	struct aac_fibmap *fm;
14727cb209f5SScott Long 	uint64_t fibphys;
1473ffb37f33SScott Long 	int i, error;
147435863739SMike Smith 
147531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
147635863739SMike Smith 
14777cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1478ffb37f33SScott Long 		return (ENOMEM);
1479ffb37f33SScott Long 
14808480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1481a6d35632SScott Long 	if (fm == NULL)
1482a6d35632SScott Long 		return (ENOMEM);
1483ffb37f33SScott Long 
14840b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1485ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1486ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
148770545d1aSScott Long 		device_printf(sc->aac_dev,
148870545d1aSScott Long 			      "Not enough contiguous memory available.\n");
14898480cc63SScott Long 		free(fm, M_AACBUF);
14900b94a66eSMike Smith 		return (ENOMEM);
149135863739SMike Smith 	}
1492128aa5a0SScott Long 
1493cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1494cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
14957cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1496ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1497128aa5a0SScott Long 
14984109ba51SEd Maste 	/* initialize constant fields in the command structure */
14997cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
15007cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
15018480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1502ffb37f33SScott Long 		fm->aac_commands = cm;
150335863739SMike Smith 		cm->cm_sc = sc;
15047cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
15057cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
15067cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1507cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
150835863739SMike Smith 
1509ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
151093cfca22SScott Long 					       &cm->cm_datamap)) != 0)
15118480cc63SScott Long 			break;
151293cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
151393cfca22SScott Long 		aac_release_command(cm);
15148480cc63SScott Long 		sc->total_fibs++;
151593cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
151635863739SMike Smith 	}
1517ffb37f33SScott Long 
15188480cc63SScott Long 	if (i > 0) {
151993cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1520ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
152131a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1522bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
15230b94a66eSMike Smith 		return (0);
152435863739SMike Smith 	}
152535863739SMike Smith 
15268480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
15278480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15288480cc63SScott Long 	free(fm, M_AACBUF);
15298480cc63SScott Long 	return (ENOMEM);
15308480cc63SScott Long }
15318480cc63SScott Long 
1532914da7d0SScott Long /*
15330b94a66eSMike Smith  * Free FIBs owned by this adapter.
153435863739SMike Smith  */
153535863739SMike Smith static void
15368480cc63SScott Long aac_free_commands(struct aac_softc *sc)
153735863739SMike Smith {
15388480cc63SScott Long 	struct aac_fibmap *fm;
1539ffb37f33SScott Long 	struct aac_command *cm;
154035863739SMike Smith 	int i;
154135863739SMike Smith 
154231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
154335863739SMike Smith 
15448480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
15458480cc63SScott Long 
15468480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
15478480cc63SScott Long 		/*
15488480cc63SScott Long 		 * We check against total_fibs to handle partially
15498480cc63SScott Long 		 * allocated blocks.
15508480cc63SScott Long 		 */
15517cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1552ffb37f33SScott Long 			cm = fm->aac_commands + i;
1553ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1554ffb37f33SScott Long 		}
1555ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1556ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15578480cc63SScott Long 		free(fm, M_AACBUF);
15588480cc63SScott Long 	}
155935863739SMike Smith }
156035863739SMike Smith 
1561914da7d0SScott Long /*
156235863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
156335863739SMike Smith  */
156435863739SMike Smith static void
156535863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
156635863739SMike Smith {
1567cd481291SScott Long 	struct aac_softc *sc;
1568914da7d0SScott Long 	struct aac_command *cm;
1569914da7d0SScott Long 	struct aac_fib *fib;
157035863739SMike Smith 	int i;
157135863739SMike Smith 
1572914da7d0SScott Long 	cm = (struct aac_command *)arg;
1573cd481291SScott Long 	sc = cm->cm_sc;
1574914da7d0SScott Long 	fib = cm->cm_fib;
157531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1576914da7d0SScott Long 
157735863739SMike Smith 	/* copy into the FIB */
1578b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
15797cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
15807cb209f5SScott Long 			struct aac_sg_tableraw *sg;
15817cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
15827cb209f5SScott Long 			sg->SgCount = nseg;
15837cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
15847cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
15857cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
15867cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
15877cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
15887cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
15897cb209f5SScott Long 			}
15907cb209f5SScott Long 			/* update the FIB size for the s/g count */
15917cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
15927cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1593b85f5808SScott Long 			struct aac_sg_table *sg;
1594b85f5808SScott Long 			sg = cm->cm_sgtable;
159535863739SMike Smith 			sg->SgCount = nseg;
159635863739SMike Smith 			for (i = 0; i < nseg; i++) {
159735863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
159835863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
159935863739SMike Smith 			}
160035863739SMike Smith 			/* update the FIB size for the s/g count */
160135863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1602b85f5808SScott Long 		} else {
1603b85f5808SScott Long 			struct aac_sg_table64 *sg;
1604b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1605b85f5808SScott Long 			sg->SgCount = nseg;
1606b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1607b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1608b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
160935863739SMike Smith 			}
1610b85f5808SScott Long 			/* update the FIB size for the s/g count */
1611b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1612b85f5808SScott Long 		}
1613b85f5808SScott Long 	}
161435863739SMike Smith 
1615cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1616cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
16177cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
16187cb209f5SScott Long 	 * and for the AIF bit
161935863739SMike Smith 	 */
16207cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
16217cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
162235863739SMike Smith 
1623cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1624cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
162535863739SMike Smith 
162635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1627c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1628c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
162935863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1630c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1631c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
163235863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1633cd481291SScott Long 
16347cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
16357cb209f5SScott Long 		int count = 10000000L;
16367cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
16377cb209f5SScott Long 			if (--count == 0) {
16387cb209f5SScott Long 				aac_unmap_command(cm);
16397cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
16407cb209f5SScott Long 				aac_requeue_ready(cm);
16417cb209f5SScott Long 			}
16427cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
16437cb209f5SScott Long 		}
16447cb209f5SScott Long 	} else {
1645397fa34fSScott Long 		/* Put the FIB on the outbound queue */
16464102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
16474102d44bSScott Long 			aac_unmap_command(cm);
1648397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1649cd481291SScott Long 			aac_requeue_ready(cm);
16504102d44bSScott Long 		}
16517cb209f5SScott Long 	}
1652cd481291SScott Long 
1653cd481291SScott Long 	return;
165435863739SMike Smith }
165535863739SMike Smith 
1656914da7d0SScott Long /*
165735863739SMike Smith  * Unmap a command from controller-visible space.
165835863739SMike Smith  */
165935863739SMike Smith static void
166035863739SMike Smith aac_unmap_command(struct aac_command *cm)
166135863739SMike Smith {
1662914da7d0SScott Long 	struct aac_softc *sc;
166335863739SMike Smith 
1664914da7d0SScott Long 	sc = cm->cm_sc;
166531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1666914da7d0SScott Long 
166735863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
166835863739SMike Smith 		return;
166935863739SMike Smith 
167035863739SMike Smith 	if (cm->cm_datalen != 0) {
167135863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1672c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1673c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
167435863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1675c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1676c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
167735863739SMike Smith 
167835863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
167935863739SMike Smith 	}
168035863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
168135863739SMike Smith }
168235863739SMike Smith 
1683914da7d0SScott Long /*
1684914da7d0SScott Long  * Hardware Interface
1685914da7d0SScott Long  */
168635863739SMike Smith 
1687914da7d0SScott Long /*
16884109ba51SEd Maste  * Initialize the adapter.
168935863739SMike Smith  */
169035863739SMike Smith static void
169135863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
169235863739SMike Smith {
1693914da7d0SScott Long 	struct aac_softc *sc;
169435863739SMike Smith 
1695914da7d0SScott Long 	sc = (struct aac_softc *)arg;
169631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1697914da7d0SScott Long 
169835863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
169935863739SMike Smith }
170035863739SMike Smith 
1701a6d35632SScott Long static int
1702a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1703a6d35632SScott Long {
170404f4d586SEd Maste 	u_int32_t code, major, minor, options = 0, atu_size = 0;
1705a441b3fcSScott Long 	int status;
170604f4d586SEd Maste 	time_t then;
1707a6d35632SScott Long 
170831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
170904f4d586SEd Maste 	/*
171004f4d586SEd Maste 	 * Wait for the adapter to come ready.
171104f4d586SEd Maste 	 */
171204f4d586SEd Maste 	then = time_uptime;
171304f4d586SEd Maste 	do {
171404f4d586SEd Maste 		code = AAC_GET_FWSTATUS(sc);
171504f4d586SEd Maste 		if (code & AAC_SELF_TEST_FAILED) {
171604f4d586SEd Maste 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
171704f4d586SEd Maste 			return(ENXIO);
171804f4d586SEd Maste 		}
171904f4d586SEd Maste 		if (code & AAC_KERNEL_PANIC) {
172004f4d586SEd Maste 			device_printf(sc->aac_dev,
1721a620bad0SEd Maste 				      "FATAL: controller kernel panic");
172204f4d586SEd Maste 			return(ENXIO);
172304f4d586SEd Maste 		}
172404f4d586SEd Maste 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
172504f4d586SEd Maste 			device_printf(sc->aac_dev,
172604f4d586SEd Maste 				      "FATAL: controller not coming ready, "
172704f4d586SEd Maste 					   "status %x\n", code);
172804f4d586SEd Maste 			return(ENXIO);
172904f4d586SEd Maste 		}
173004f4d586SEd Maste 	} while (!(code & AAC_UP_AND_RUNNING));
1731a6d35632SScott Long 
1732fe94b852SScott Long 	/*
1733fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1734fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1735fe94b852SScott Long 	 */
1736a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1737fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1738fe94b852SScott Long 				     NULL)) {
1739fe94b852SScott Long 			device_printf(sc->aac_dev,
1740fe94b852SScott Long 				      "Error reading firmware version\n");
1741fe94b852SScott Long 			return (EIO);
1742fe94b852SScott Long 		}
1743fe94b852SScott Long 
1744fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1745a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1746a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1747fe94b852SScott Long 		if (major == 1) {
1748fe94b852SScott Long 			device_printf(sc->aac_dev,
1749fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1750fe94b852SScott Long 			    major, minor);
1751fe94b852SScott Long 			return (EINVAL);
1752fe94b852SScott Long 		}
1753fe94b852SScott Long 	}
1754fe94b852SScott Long 
1755a6d35632SScott Long 	/*
1756a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1757a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1758a441b3fcSScott Long 	 * command.
1759a6d35632SScott Long 	 */
1760a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1761a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1762a441b3fcSScott Long 			device_printf(sc->aac_dev,
1763a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1764a6d35632SScott Long 			return (EIO);
1765a6d35632SScott Long 		}
1766a441b3fcSScott Long 	} else {
1767a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
17687cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1769a6d35632SScott Long 		sc->supported_options = options;
1770a6d35632SScott Long 
1771a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1772a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1773a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1774a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1775a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1776cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1777cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1778a441b3fcSScott Long 			device_printf(sc->aac_dev,
1779a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1780a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1781a6d35632SScott Long 		}
1782a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1783a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
17847cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
17857cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
17867cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1787a441b3fcSScott Long 	}
1788a6d35632SScott Long 
1789a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
17907cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
17917cb209f5SScott Long 
17927cb209f5SScott Long 	/* Remap mem. resource, if required */
17937cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1794ff0991c4SAttilio Rao 		atu_size > rman_get_size(sc->aac_regs_res1)) {
17957cb209f5SScott Long 		bus_release_resource(
17967cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
1797ff0991c4SAttilio Rao 			sc->aac_regs_rid1, sc->aac_regs_res1);
1798ff0991c4SAttilio Rao 		sc->aac_regs_res1 = bus_alloc_resource(
1799ff0991c4SAttilio Rao 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1,
18007cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
1801ff0991c4SAttilio Rao 		if (sc->aac_regs_res1 == NULL) {
1802ff0991c4SAttilio Rao 			sc->aac_regs_res1 = bus_alloc_resource_any(
18037cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
1804ff0991c4SAttilio Rao 				&sc->aac_regs_rid1, RF_ACTIVE);
1805ff0991c4SAttilio Rao 			if (sc->aac_regs_res1 == NULL) {
18067cb209f5SScott Long 				device_printf(sc->aac_dev,
18077cb209f5SScott Long 				    "couldn't allocate register window\n");
18087cb209f5SScott Long 				return (ENXIO);
18097cb209f5SScott Long 			}
18107cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
18117cb209f5SScott Long 		}
1812ff0991c4SAttilio Rao 		sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1);
1813ff0991c4SAttilio Rao 		sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1);
1814ff0991c4SAttilio Rao 
1815ff0991c4SAttilio Rao 		if (sc->aac_hwif == AAC_HWIF_NARK) {
1816ff0991c4SAttilio Rao 			sc->aac_regs_res0 = sc->aac_regs_res1;
1817ff0991c4SAttilio Rao 			sc->aac_regs_rid0 = sc->aac_regs_rid1;
1818ff0991c4SAttilio Rao 			sc->aac_btag0 = sc->aac_btag1;
1819ff0991c4SAttilio Rao 			sc->aac_bhandle0 = sc->aac_bhandle1;
1820ff0991c4SAttilio Rao 		}
18217cb209f5SScott Long 	}
18227cb209f5SScott Long 
18237cb209f5SScott Long 	/* Read preferred settings */
18247cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
18257cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
18267cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1827a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18287e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
18297e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1830a6d35632SScott Long 	else
1831a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18327e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
18337e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1834a441b3fcSScott Long 
18357cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
18367cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
18377cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
18387cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
18397cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
18407cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
18417cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
18427cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
18437cb209f5SScott Long 	}
18447cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
18457cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
18467cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1847a6d35632SScott Long 
1848f355c0e0SEd Maste 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1849f355c0e0SEd Maste 		sc->flags |= AAC_FLAGS_RAW_IO;
1850f355c0e0SEd Maste 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1851f355c0e0SEd Maste 	}
1852523da39bSEd Maste 	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1853523da39bSEd Maste 	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1854523da39bSEd Maste 		sc->flags |= AAC_FLAGS_LBA_64BIT;
1855523da39bSEd Maste 		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1856523da39bSEd Maste 	}
1857f355c0e0SEd Maste 
1858fe94b852SScott Long 	return (0);
1859fe94b852SScott Long }
1860fe94b852SScott Long 
186135863739SMike Smith static int
186235863739SMike Smith aac_init(struct aac_softc *sc)
186335863739SMike Smith {
186435863739SMike Smith 	struct aac_adapter_init	*ip;
186504f4d586SEd Maste 	u_int32_t qoffset;
1866a6d35632SScott Long 	int error;
186735863739SMike Smith 
186831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1869ffb37f33SScott Long 
187035863739SMike Smith 	/*
1871914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1872914da7d0SScott Long 	 * physical location of various important shared data structures.
187335863739SMike Smith 	 */
187435863739SMike Smith 	ip = &sc->aac_common->ac_init;
187535863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18767cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18777cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18787cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18797cb209f5SScott Long 	}
1880f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
188135863739SMike Smith 
1882c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1883c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1884149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
188535863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
188635863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
188735863739SMike Smith 
1888c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1889c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
189035863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
189135863739SMike Smith 
18924b00f859SScott Long 	/*
18934b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18944b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18954b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18964b00f859SScott Long 	 * Round up since the granularity is so high.
18974b00f859SScott Long 	 */
1898f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18994b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
19004b00f859SScott Long 		ip->HostPhysMemPages =
19014b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1902204c0befSScott Long 	}
19032b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
190435863739SMike Smith 
19057cb209f5SScott Long 	ip->InitFlags = 0;
19067cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
19077cb209f5SScott Long 		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
19087cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
19097cb209f5SScott Long 	}
19107cb209f5SScott Long 
19117cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
19127cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
19137cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
19147cb209f5SScott Long 
191535863739SMike Smith 	/*
19164109ba51SEd Maste 	 * Initialize FIB queues.  Note that it appears that the layout of the
1917c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1918c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
191935863739SMike Smith 	 *
192035863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1921914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1922914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1923914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1924914da7d0SScott Long 	 * does.
192535863739SMike Smith 	 *
1926914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1927914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1928914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1929914da7d0SScott Long 	 * virtue of a table.
193035863739SMike Smith 	 */
1931b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
19320bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
19330bcbebd6SScott Long 	sc->aac_queues =
19340bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1935b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
193635863739SMike Smith 
1937c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1938c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1939c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1940c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1941c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1942c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1943c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1944c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1945c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1946c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1947c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1948c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1949c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1950c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1951c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1952c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1953c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1954c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1955c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1956c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1957c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1958c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1959c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1960c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1961c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1962c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1963c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1964c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1965c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1966c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1967c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1968c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1969c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1970c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1971c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1972c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1973c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1974c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1975c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1976c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1977c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1978c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1979c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1980c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1981c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1982c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1983c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1984c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
198535863739SMike Smith 
198635863739SMike Smith 	/*
198735863739SMike Smith 	 * Do controller-type-specific initialisation
198835863739SMike Smith 	 */
198935863739SMike Smith 	switch (sc->aac_hwif) {
199035863739SMike Smith 	case AAC_HWIF_I960RX:
1991ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0);
199235863739SMike Smith 		break;
19934afedc31SScott Long 	case AAC_HWIF_RKT:
1994ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0);
19954afedc31SScott Long 		break;
19964afedc31SScott Long 	default:
19974afedc31SScott Long 		break;
199835863739SMike Smith 	}
199935863739SMike Smith 
200035863739SMike Smith 	/*
200135863739SMike Smith 	 * Give the init structure to the controller.
200235863739SMike Smith 	 */
200335863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
2004914da7d0SScott Long 			     sc->aac_common_busaddr +
2005914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
2006914da7d0SScott Long 			     NULL)) {
2007914da7d0SScott Long 		device_printf(sc->aac_dev,
2008914da7d0SScott Long 			      "error establishing init structure\n");
2009a6d35632SScott Long 		error = EIO;
2010a6d35632SScott Long 		goto out;
201135863739SMike Smith 	}
201235863739SMike Smith 
2013a6d35632SScott Long 	error = 0;
2014a6d35632SScott Long out:
2015a6d35632SScott Long 	return(error);
201635863739SMike Smith }
201735863739SMike Smith 
201804f4d586SEd Maste static int
201904f4d586SEd Maste aac_setup_intr(struct aac_softc *sc)
202004f4d586SEd Maste {
202104f4d586SEd Maste 	sc->aac_irq_rid = 0;
202204f4d586SEd Maste 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
202304f4d586SEd Maste 			   			  &sc->aac_irq_rid,
202404f4d586SEd Maste 			   			  RF_SHAREABLE |
202504f4d586SEd Maste 						  RF_ACTIVE)) == NULL) {
202604f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
202704f4d586SEd Maste 		return (EINVAL);
202804f4d586SEd Maste 	}
202904f4d586SEd Maste 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
203004f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
203104f4d586SEd Maste 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
203204f4d586SEd Maste 				   aac_new_intr, sc, &sc->aac_intr)) {
203304f4d586SEd Maste 			device_printf(sc->aac_dev, "can't set up interrupt\n");
203404f4d586SEd Maste 			return (EINVAL);
203504f4d586SEd Maste 		}
203604f4d586SEd Maste 	} else {
203704f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2038e46b9eeaSEd Maste 				   INTR_TYPE_BIO, aac_filter, NULL,
203904f4d586SEd Maste 				   sc, &sc->aac_intr)) {
204004f4d586SEd Maste 			device_printf(sc->aac_dev,
2041e46b9eeaSEd Maste 				      "can't set up interrupt filter\n");
204204f4d586SEd Maste 			return (EINVAL);
204304f4d586SEd Maste 		}
204404f4d586SEd Maste 	}
204504f4d586SEd Maste 	return (0);
204604f4d586SEd Maste }
204704f4d586SEd Maste 
2048914da7d0SScott Long /*
204935863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
20507cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
205135863739SMike Smith  */
205235863739SMike Smith static int
205335863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
205435863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
205535863739SMike Smith 		 u_int32_t *sp)
205635863739SMike Smith {
205735863739SMike Smith 	time_t then;
205835863739SMike Smith 	u_int32_t status;
205935863739SMike Smith 
206031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
206135863739SMike Smith 
206235863739SMike Smith 	/* populate the mailbox */
206335863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
206435863739SMike Smith 
206535863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
206635863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
206735863739SMike Smith 
206835863739SMike Smith 	/* then set it to signal the adapter */
206935863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
207035863739SMike Smith 
207135863739SMike Smith 	/* spin waiting for the command to complete */
20722b3b0f17SScott Long 	then = time_uptime;
207335863739SMike Smith 	do {
20742b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
207531a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
207635863739SMike Smith 			return(EIO);
207735863739SMike Smith 		}
207835863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
207935863739SMike Smith 
208035863739SMike Smith 	/* clear the completion flag */
208135863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
208235863739SMike Smith 
208335863739SMike Smith 	/* get the command status */
2084a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
208535863739SMike Smith 	if (sp != NULL)
208635863739SMike Smith 		*sp = status;
20877cb209f5SScott Long 
2088a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20897cb209f5SScott Long 		return (-1);
20900b94a66eSMike Smith 	return(0);
209135863739SMike Smith }
209235863739SMike Smith 
2093cbfd045bSScott Long int
209435863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2095cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
209635863739SMike Smith {
209731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
20987cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
209935863739SMike Smith 
210035863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
210135863739SMike Smith 		return(EINVAL);
210235863739SMike Smith 
210335863739SMike Smith 	/*
210435863739SMike Smith 	 * Set up the sync FIB
210535863739SMike Smith 	 */
2106914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2107914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2108c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
210935863739SMike Smith 	fib->Header.XferState |= xferstate;
211035863739SMike Smith 	fib->Header.Command = command;
211135863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
211242ef13a2SEd Maste 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
211335863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2114b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2115c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2116914da7d0SScott Long 					 offsetof(struct aac_common,
2117914da7d0SScott Long 						  ac_sync_fib);
211835863739SMike Smith 
211935863739SMike Smith 	/*
212035863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
212135863739SMike Smith 	 */
2122914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2123914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
212431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
212535863739SMike Smith 		return(EIO);
212635863739SMike Smith 	}
212735863739SMike Smith 
212835863739SMike Smith 	return (0);
212935863739SMike Smith }
213035863739SMike Smith 
2131914da7d0SScott Long /*
213235863739SMike Smith  * Adapter-space FIB queue manipulation
213335863739SMike Smith  *
213435863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
213535863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
213635863739SMike Smith  */
213735863739SMike Smith static struct {
213835863739SMike Smith 	int		size;
213935863739SMike Smith 	int		notify;
214035863739SMike Smith } aac_qinfo[] = {
214135863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
214235863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
214335863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
214435863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
214535863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
214635863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
214735863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
214835863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
214935863739SMike Smith };
215035863739SMike Smith 
215135863739SMike Smith /*
2152c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2153c6eafcf2SScott Long  * EBUSY if the queue is full.
215435863739SMike Smith  *
21550b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2156914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2157914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2158c6eafcf2SScott Long  *	 separate queue/notify interface).
215935863739SMike Smith  */
216035863739SMike Smith static int
2161f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
216235863739SMike Smith {
216335863739SMike Smith 	u_int32_t pi, ci;
21649e2e96d8SScott Long 	int error;
2165f6c4dd3fSScott Long 	u_int32_t fib_size;
2166f6c4dd3fSScott Long 	u_int32_t fib_addr;
2167f6c4dd3fSScott Long 
216831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
216936e0bf6eSScott Long 
2170f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2171f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
217235863739SMike Smith 
217335863739SMike Smith 	/* get the producer/consumer indices */
217435863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
217535863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
217635863739SMike Smith 
217735863739SMike Smith 	/* wrap the queue? */
217835863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
217935863739SMike Smith 		pi = 0;
218035863739SMike Smith 
218135863739SMike Smith 	/* check for queue full */
218235863739SMike Smith 	if ((pi + 1) == ci) {
218335863739SMike Smith 		error = EBUSY;
218435863739SMike Smith 		goto out;
218535863739SMike Smith 	}
218635863739SMike Smith 
2187614c22b2SScott Long 	/*
2188614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2189614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2190614c22b2SScott Long 	 */
2191614c22b2SScott Long 	aac_enqueue_busy(cm);
2192614c22b2SScott Long 
219335863739SMike Smith 	/* populate queue entry */
219435863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
219535863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
219635863739SMike Smith 
219735863739SMike Smith 	/* update producer index */
219835863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
219935863739SMike Smith 
220035863739SMike Smith 	/* notify the adapter if we know how */
220135863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
220235863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
220335863739SMike Smith 
220435863739SMike Smith 	error = 0;
220535863739SMike Smith 
220635863739SMike Smith out:
220735863739SMike Smith 	return(error);
220835863739SMike Smith }
220935863739SMike Smith 
221035863739SMike Smith /*
221136e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
221236e0bf6eSScott Long  * success or ENOENT if the queue is empty.
221335863739SMike Smith  */
221435863739SMike Smith static int
2215c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2216c6eafcf2SScott Long 		struct aac_fib **fib_addr)
221735863739SMike Smith {
221835863739SMike Smith 	u_int32_t pi, ci;
2219149af931SScott Long 	u_int32_t fib_index;
22209e2e96d8SScott Long 	int error;
2221f6c4dd3fSScott Long 	int notify;
222235863739SMike Smith 
222331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
222435863739SMike Smith 
222535863739SMike Smith 	/* get the producer/consumer indices */
222635863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
222735863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
222835863739SMike Smith 
222935863739SMike Smith 	/* check for queue empty */
223035863739SMike Smith 	if (ci == pi) {
223135863739SMike Smith 		error = ENOENT;
223235863739SMike Smith 		goto out;
223335863739SMike Smith 	}
223435863739SMike Smith 
22357753acd2SScott Long 	/* wrap the pi so the following test works */
22367753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
22377753acd2SScott Long 		pi = 0;
22387753acd2SScott Long 
2239f6c4dd3fSScott Long 	notify = 0;
2240f6c4dd3fSScott Long 	if (ci == pi + 1)
2241f6c4dd3fSScott Long 		notify++;
2242f6c4dd3fSScott Long 
224335863739SMike Smith 	/* wrap the queue? */
224435863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
224535863739SMike Smith 		ci = 0;
224635863739SMike Smith 
224735863739SMike Smith 	/* fetch the entry */
224835863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2249149af931SScott Long 
2250149af931SScott Long 	switch (queue) {
2251149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2252149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2253149af931SScott Long 		/*
2254149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2255149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2256149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2257149af931SScott Long 		 * Therefore, we have to convert it to an index.
2258149af931SScott Long 		 */
2259149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2260149af931SScott Long 			sizeof(struct aac_fib);
2261149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2262149af931SScott Long 		break;
2263149af931SScott Long 
2264149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2265149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2266149af931SScott Long 	{
2267149af931SScott Long 		struct aac_command *cm;
2268149af931SScott Long 
2269149af931SScott Long 		/*
2270149af931SScott Long 		 * As above, an index is used instead of an actual address.
2271149af931SScott Long 		 * Gotta shift the index to account for the fast response
2272149af931SScott Long 		 * bit.  No other correction is needed since this value was
2273149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2274149af931SScott Long 		 * field.
2275149af931SScott Long 		 */
2276149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22777cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2278149af931SScott Long 		*fib_addr = cm->cm_fib;
227935863739SMike Smith 
2280f30ac74cSScott Long 		/*
2281f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2282149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2283f30ac74cSScott Long 		 */
2284149af931SScott Long 		if (fib_index & 0x01) {
2285f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2286f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2287f30ac74cSScott Long 		}
2288149af931SScott Long 		break;
2289149af931SScott Long 	}
2290149af931SScott Long 	default:
2291149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2292149af931SScott Long 		break;
2293149af931SScott Long 	}
2294149af931SScott Long 
229535863739SMike Smith 	/* update consumer index */
229635863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
229735863739SMike Smith 
229835863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2299f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
230035863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
230135863739SMike Smith 	error = 0;
230235863739SMike Smith 
230335863739SMike Smith out:
230435863739SMike Smith 	return(error);
230535863739SMike Smith }
230635863739SMike Smith 
2307914da7d0SScott Long /*
230836e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
230936e0bf6eSScott Long  */
231036e0bf6eSScott Long static int
231136e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
231236e0bf6eSScott Long {
231336e0bf6eSScott Long 	u_int32_t pi, ci;
23149e2e96d8SScott Long 	int error;
231536e0bf6eSScott Long 	u_int32_t fib_size;
231636e0bf6eSScott Long 	u_int32_t fib_addr;
231736e0bf6eSScott Long 
231831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
231936e0bf6eSScott Long 
232036e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
232136e0bf6eSScott Long 	fib_size = fib->Header.Size;
232236e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
232336e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
232436e0bf6eSScott Long 
232536e0bf6eSScott Long 	/* get the producer/consumer indices */
232636e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
232736e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
232836e0bf6eSScott Long 
232936e0bf6eSScott Long 	/* wrap the queue? */
233036e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
233136e0bf6eSScott Long 		pi = 0;
233236e0bf6eSScott Long 
233336e0bf6eSScott Long 	/* check for queue full */
233436e0bf6eSScott Long 	if ((pi + 1) == ci) {
233536e0bf6eSScott Long 		error = EBUSY;
233636e0bf6eSScott Long 		goto out;
233736e0bf6eSScott Long 	}
233836e0bf6eSScott Long 
233936e0bf6eSScott Long 	/* populate queue entry */
234036e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
234136e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
234236e0bf6eSScott Long 
234336e0bf6eSScott Long 	/* update producer index */
234436e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
234536e0bf6eSScott Long 
234636e0bf6eSScott Long 	/* notify the adapter if we know how */
234736e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
234836e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
234936e0bf6eSScott Long 
235036e0bf6eSScott Long 	error = 0;
235136e0bf6eSScott Long 
235236e0bf6eSScott Long out:
235336e0bf6eSScott Long 	return(error);
235436e0bf6eSScott Long }
235536e0bf6eSScott Long 
2356914da7d0SScott Long /*
23570b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
23580b94a66eSMike Smith  * and complain about them.
23590b94a66eSMike Smith  */
23600b94a66eSMike Smith static void
23610b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
23620b94a66eSMike Smith {
23630b94a66eSMike Smith 	struct aac_command *cm;
23640b94a66eSMike Smith 	time_t deadline;
236515c37be0SScott Long 	int timedout, code;
23660b94a66eSMike Smith 
2367f6c4dd3fSScott Long 	/*
236870545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2369914da7d0SScott Long 	 * only.
2370914da7d0SScott Long 	 */
237115c37be0SScott Long 	timedout = 0;
23722b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23730b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2374f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2375f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
23760b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2377914da7d0SScott Long 			device_printf(sc->aac_dev,
2378914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
23792b3b0f17SScott Long 				      cm, (int)(time_uptime-cm->cm_timestamp));
23800b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
238115c37be0SScott Long 			timedout++;
23820b94a66eSMike Smith 		}
23830b94a66eSMike Smith 	}
23840b94a66eSMike Smith 
238515c37be0SScott Long 	if (timedout) {
238615c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
238715c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
238815c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
238915c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
239015c37be0SScott Long 		}
239115c37be0SScott Long 	}
23920b94a66eSMike Smith 	return;
23930b94a66eSMike Smith }
23940b94a66eSMike Smith 
2395914da7d0SScott Long /*
2396914da7d0SScott Long  * Interface Function Vectors
2397914da7d0SScott Long  */
239835863739SMike Smith 
2399914da7d0SScott Long /*
240035863739SMike Smith  * Read the current firmware status word.
240135863739SMike Smith  */
240235863739SMike Smith static int
240335863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
240435863739SMike Smith {
240531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
240635863739SMike Smith 
2407ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS));
240835863739SMike Smith }
240935863739SMike Smith 
241035863739SMike Smith static int
241135863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
241235863739SMike Smith {
241331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241435863739SMike Smith 
24154824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
24164824be88SEd Maste 	    AAC_RX_OMR0 : AAC_RX_FWSTATUS));
241735863739SMike Smith }
241835863739SMike Smith 
2419b3457b51SScott Long static int
2420b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2421b3457b51SScott Long {
2422b3457b51SScott Long 	int val;
2423b3457b51SScott Long 
242431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2425b3457b51SScott Long 
2426ff0991c4SAttilio Rao 	val = AAC_MEM0_GETREG4(sc, AAC_FA_FWSTATUS);
2427b3457b51SScott Long 	return (val);
2428b3457b51SScott Long }
2429b3457b51SScott Long 
24304afedc31SScott Long static int
24314afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
24324afedc31SScott Long {
243331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24344afedc31SScott Long 
24354824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
24364824be88SEd Maste 	    AAC_RKT_OMR0 : AAC_RKT_FWSTATUS));
24374afedc31SScott Long }
24384afedc31SScott Long 
2439914da7d0SScott Long /*
244035863739SMike Smith  * Notify the controller of a change in a given queue
244135863739SMike Smith  */
244235863739SMike Smith 
244335863739SMike Smith static void
244435863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
244535863739SMike Smith {
244631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
244735863739SMike Smith 
2448ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
244935863739SMike Smith }
245035863739SMike Smith 
245135863739SMike Smith static void
245235863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
245335863739SMike Smith {
245431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
245535863739SMike Smith 
2456ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit);
245735863739SMike Smith }
245835863739SMike Smith 
2459b3457b51SScott Long static void
2460b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2461b3457b51SScott Long {
246231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2463b3457b51SScott Long 
2464ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2465b3457b51SScott Long 	AAC_FA_HACK(sc);
2466b3457b51SScott Long }
2467b3457b51SScott Long 
24684afedc31SScott Long static void
24694afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
24704afedc31SScott Long {
247131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24724afedc31SScott Long 
2473ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit);
24744afedc31SScott Long }
24754afedc31SScott Long 
2476914da7d0SScott Long /*
247735863739SMike Smith  * Get the interrupt reason bits
247835863739SMike Smith  */
247935863739SMike Smith static int
248035863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
248135863739SMike Smith {
248231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
248335863739SMike Smith 
2484ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0));
248535863739SMike Smith }
248635863739SMike Smith 
248735863739SMike Smith static int
248835863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
248935863739SMike Smith {
249031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
249135863739SMike Smith 
2492ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR));
249335863739SMike Smith }
249435863739SMike Smith 
2495b3457b51SScott Long static int
2496b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2497b3457b51SScott Long {
2498b3457b51SScott Long 	int val;
2499b3457b51SScott Long 
250031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2501b3457b51SScott Long 
2502ff0991c4SAttilio Rao 	val = AAC_MEM0_GETREG2(sc, AAC_FA_DOORBELL0);
2503b3457b51SScott Long 	return (val);
2504b3457b51SScott Long }
2505b3457b51SScott Long 
25064afedc31SScott Long static int
25074afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
25084afedc31SScott Long {
250931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25104afedc31SScott Long 
2511ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR));
25124afedc31SScott Long }
25134afedc31SScott Long 
2514914da7d0SScott Long /*
251535863739SMike Smith  * Clear some interrupt reason bits
251635863739SMike Smith  */
251735863739SMike Smith static void
251835863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
251935863739SMike Smith {
252031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
252135863739SMike Smith 
2522ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
252335863739SMike Smith }
252435863739SMike Smith 
252535863739SMike Smith static void
252635863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
252735863739SMike Smith {
252831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
252935863739SMike Smith 
2530ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask);
253135863739SMike Smith }
253235863739SMike Smith 
2533b3457b51SScott Long static void
2534b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2535b3457b51SScott Long {
253631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2537b3457b51SScott Long 
2538ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2539b3457b51SScott Long 	AAC_FA_HACK(sc);
2540b3457b51SScott Long }
2541b3457b51SScott Long 
25424afedc31SScott Long static void
25434afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
25444afedc31SScott Long {
254531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25464afedc31SScott Long 
2547ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask);
25484afedc31SScott Long }
25494afedc31SScott Long 
2550914da7d0SScott Long /*
255135863739SMike Smith  * Populate the mailbox and set the command word
255235863739SMike Smith  */
255335863739SMike Smith static void
255435863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
255535863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
255635863739SMike Smith {
255731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
255835863739SMike Smith 
2559ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command);
2560ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2561ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2562ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2563ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
256435863739SMike Smith }
256535863739SMike Smith 
256635863739SMike Smith static void
256735863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
256835863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
256935863739SMike Smith {
257031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
257135863739SMike Smith 
2572ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command);
2573ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2574ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2575ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2576ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
257735863739SMike Smith }
257835863739SMike Smith 
2579b3457b51SScott Long static void
2580b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2581b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2582b3457b51SScott Long {
258331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2584b3457b51SScott Long 
2585ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX, command);
2586b3457b51SScott Long 	AAC_FA_HACK(sc);
2587ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2588b3457b51SScott Long 	AAC_FA_HACK(sc);
2589ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2590b3457b51SScott Long 	AAC_FA_HACK(sc);
2591ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2592b3457b51SScott Long 	AAC_FA_HACK(sc);
2593ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2594b3457b51SScott Long 	AAC_FA_HACK(sc);
2595b3457b51SScott Long }
2596b3457b51SScott Long 
25974afedc31SScott Long static void
25984afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25994afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
26004afedc31SScott Long {
260131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26024afedc31SScott Long 
2603ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command);
2604ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2605ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2606ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2607ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
26084afedc31SScott Long }
26094afedc31SScott Long 
2610914da7d0SScott Long /*
261135863739SMike Smith  * Fetch the immediate command status word
261235863739SMike Smith  */
261335863739SMike Smith static int
2614a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
261535863739SMike Smith {
261631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
261735863739SMike Smith 
2618ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
261935863739SMike Smith }
262035863739SMike Smith 
262135863739SMike Smith static int
2622a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
262335863739SMike Smith {
262431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
262535863739SMike Smith 
2626ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
262735863739SMike Smith }
262835863739SMike Smith 
2629b3457b51SScott Long static int
2630a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2631b3457b51SScott Long {
2632b3457b51SScott Long 	int val;
2633b3457b51SScott Long 
263431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2635b3457b51SScott Long 
2636ff0991c4SAttilio Rao 	val = AAC_MEM1_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2637b3457b51SScott Long 	return (val);
2638b3457b51SScott Long }
2639b3457b51SScott Long 
26404afedc31SScott Long static int
26414afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
26424afedc31SScott Long {
264331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26444afedc31SScott Long 
2645ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
26464afedc31SScott Long }
26474afedc31SScott Long 
2648914da7d0SScott Long /*
264935863739SMike Smith  * Set/clear interrupt masks
265035863739SMike Smith  */
265135863739SMike Smith static void
265235863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
265335863739SMike Smith {
265431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
265535863739SMike Smith 
265635863739SMike Smith 	if (enable) {
2657ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
265835863739SMike Smith 	} else {
2659ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
266035863739SMike Smith 	}
266135863739SMike Smith }
266235863739SMike Smith 
266335863739SMike Smith static void
266435863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
266535863739SMike Smith {
266631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
266735863739SMike Smith 
266835863739SMike Smith 	if (enable) {
26697cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2670ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
26717cb209f5SScott Long 		else
2672ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
267335863739SMike Smith 	} else {
2674ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0);
267535863739SMike Smith 	}
267635863739SMike Smith }
267735863739SMike Smith 
2678b3457b51SScott Long static void
2679b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2680b3457b51SScott Long {
268131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2682b3457b51SScott Long 
2683b3457b51SScott Long 	if (enable) {
2684ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2685b3457b51SScott Long 		AAC_FA_HACK(sc);
2686b3457b51SScott Long 	} else {
2687ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_FA_MASK0, ~0);
2688b3457b51SScott Long 		AAC_FA_HACK(sc);
2689b3457b51SScott Long 	}
2690b3457b51SScott Long }
2691b3457b51SScott Long 
26924afedc31SScott Long static void
26934afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
26944afedc31SScott Long {
269531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
26964afedc31SScott Long 
26974afedc31SScott Long 	if (enable) {
26987cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2699ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
27007cb209f5SScott Long 		else
2701ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
27024afedc31SScott Long 	} else {
2703ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0);
27044afedc31SScott Long 	}
27054afedc31SScott Long }
27064afedc31SScott Long 
2707914da7d0SScott Long /*
27087cb209f5SScott Long  * New comm. interface: Send command functions
27097cb209f5SScott Long  */
27107cb209f5SScott Long static int
27117cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
27127cb209f5SScott Long {
27137cb209f5SScott Long 	u_int32_t index, device;
27147cb209f5SScott Long 
271531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
27167cb209f5SScott Long 
2717ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
27187cb209f5SScott Long 	if (index == 0xffffffffL)
2719ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
27207cb209f5SScott Long 	if (index == 0xffffffffL)
27217cb209f5SScott Long 		return index;
27227cb209f5SScott Long 	aac_enqueue_busy(cm);
27237cb209f5SScott Long 	device = index;
2724ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
27257cb209f5SScott Long 	device += 4;
2726ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
27277cb209f5SScott Long 	device += 4;
2728ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2729ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index);
27307cb209f5SScott Long 	return 0;
27317cb209f5SScott Long }
27327cb209f5SScott Long 
27337cb209f5SScott Long static int
27347cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
27357cb209f5SScott Long {
27367cb209f5SScott Long 	u_int32_t index, device;
27377cb209f5SScott Long 
273831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
27397cb209f5SScott Long 
2740ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
27417cb209f5SScott Long 	if (index == 0xffffffffL)
2742ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
27437cb209f5SScott Long 	if (index == 0xffffffffL)
27447cb209f5SScott Long 		return index;
27457cb209f5SScott Long 	aac_enqueue_busy(cm);
27467cb209f5SScott Long 	device = index;
2747ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
27487cb209f5SScott Long 	device += 4;
2749ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
27507cb209f5SScott Long 	device += 4;
2751ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2752ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index);
27537cb209f5SScott Long 	return 0;
27547cb209f5SScott Long }
27557cb209f5SScott Long 
27567cb209f5SScott Long /*
27577cb209f5SScott Long  * New comm. interface: get, set outbound queue index
27587cb209f5SScott Long  */
27597cb209f5SScott Long static int
27607cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
27617cb209f5SScott Long {
276231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27637cb209f5SScott Long 
2764ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE));
27657cb209f5SScott Long }
27667cb209f5SScott Long 
27677cb209f5SScott Long static int
27687cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
27697cb209f5SScott Long {
277031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27717cb209f5SScott Long 
2772ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE));
27737cb209f5SScott Long }
27747cb209f5SScott Long 
27757cb209f5SScott Long static void
27767cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
27777cb209f5SScott Long {
277831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27797cb209f5SScott Long 
2780ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index);
27817cb209f5SScott Long }
27827cb209f5SScott Long 
27837cb209f5SScott Long static void
27847cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
27857cb209f5SScott Long {
278631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27877cb209f5SScott Long 
2788ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index);
27897cb209f5SScott Long }
27907cb209f5SScott Long 
27917cb209f5SScott Long /*
2792914da7d0SScott Long  * Debugging and Diagnostics
2793914da7d0SScott Long  */
279435863739SMike Smith 
2795914da7d0SScott Long /*
279635863739SMike Smith  * Print some information about the controller.
279735863739SMike Smith  */
279835863739SMike Smith static void
279935863739SMike Smith aac_describe_controller(struct aac_softc *sc)
280035863739SMike Smith {
2801cbfd045bSScott Long 	struct aac_fib *fib;
280235863739SMike Smith 	struct aac_adapter_info	*info;
28037ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
280435863739SMike Smith 
280531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
280635863739SMike Smith 
280781b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
280803b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2809cbfd045bSScott Long 
2810cbfd045bSScott Long 	fib->data[0] = 0;
2811cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
281235863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2813fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
281481b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
281535863739SMike Smith 		return;
281635863739SMike Smith 	}
281735863739SMike Smith 
2818bd971c49SScott Long 	/* save the kernel revision structure for later use */
2819bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2820bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2821bd971c49SScott Long 
2822bd971c49SScott Long 	if (bootverbose) {
2823b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2824b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2825c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2826b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2827b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2828b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2829914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2830914da7d0SScott Long 		    info->batteryPlatform));
283135863739SMike Smith 
2832bd971c49SScott Long 		device_printf(sc->aac_dev,
2833bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
283435863739SMike Smith 		    info->KernelRevision.external.comp.major,
283535863739SMike Smith 		    info->KernelRevision.external.comp.minor,
283635863739SMike Smith 		    info->KernelRevision.external.comp.dash,
283736e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
283836e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2839fe3cb0e1SScott Long 
2840a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2841a6d35632SScott Long 			      sc->supported_options,
2842a6d35632SScott Long 			      "\20"
2843a6d35632SScott Long 			      "\1SNAPSHOT"
2844a6d35632SScott Long 			      "\2CLUSTERS"
2845a6d35632SScott Long 			      "\3WCACHE"
2846a6d35632SScott Long 			      "\4DATA64"
2847a6d35632SScott Long 			      "\5HOSTTIME"
2848a6d35632SScott Long 			      "\6RAID50"
2849a6d35632SScott Long 			      "\7WINDOW4GB"
2850a6d35632SScott Long 			      "\10SCSIUPGD"
2851a6d35632SScott Long 			      "\11SOFTERR"
2852a6d35632SScott Long 			      "\12NORECOND"
2853a6d35632SScott Long 			      "\13SGMAP64"
2854a6d35632SScott Long 			      "\14ALARM"
28557cb209f5SScott Long 			      "\15NONDASD"
28567cb209f5SScott Long 			      "\16SCSIMGT"
28577cb209f5SScott Long 			      "\17RAIDSCSI"
28587cb209f5SScott Long 			      "\21ADPTINFO"
28597cb209f5SScott Long 			      "\22NEWCOMM"
28607cb209f5SScott Long 			      "\23ARRAY64BIT"
28617cb209f5SScott Long 			      "\24HEATSENSOR");
2862a6d35632SScott Long 	}
286355aa1136SEd Maste 
286455aa1136SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
286555aa1136SEd Maste 		fib->data[0] = 0;
286655aa1136SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
286755aa1136SEd Maste 			device_printf(sc->aac_dev,
286855aa1136SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
286955aa1136SEd Maste 		else
287055aa1136SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
287155aa1136SEd Maste 			    &fib->data[0])->AdapterTypeText;
287255aa1136SEd Maste 	}
287355aa1136SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
287455aa1136SEd Maste 		adapter_type,
287555aa1136SEd Maste 		AAC_DRIVER_VERSION >> 24,
287655aa1136SEd Maste 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
287755aa1136SEd Maste 		AAC_DRIVER_VERSION & 0xFF,
287855aa1136SEd Maste 		AAC_DRIVER_BUILD);
287955aa1136SEd Maste 
2880bd971c49SScott Long 	aac_release_sync_fib(sc);
288181b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
288235863739SMike Smith }
288335863739SMike Smith 
2884914da7d0SScott Long /*
288535863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
288635863739SMike Smith  * same.
288735863739SMike Smith  */
288835863739SMike Smith static char *
288935863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
289035863739SMike Smith {
289135863739SMike Smith 	int i;
289235863739SMike Smith 
289335863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
289435863739SMike Smith 		if (table[i].code == code)
289535863739SMike Smith 			return(table[i].string);
289635863739SMike Smith 	return(table[i + 1].string);
289735863739SMike Smith }
289835863739SMike Smith 
2899914da7d0SScott Long /*
2900914da7d0SScott Long  * Management Interface
2901914da7d0SScott Long  */
290235863739SMike Smith 
290335863739SMike Smith static int
290400b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
290535863739SMike Smith {
2906914da7d0SScott Long 	struct aac_softc *sc;
290735863739SMike Smith 
2908914da7d0SScott Long 	sc = dev->si_drv1;
290931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2910a723a548SEd Maste 	sc->aac_open_cnt++;
291135863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
291235863739SMike Smith 
291335863739SMike Smith 	return 0;
291435863739SMike Smith }
291535863739SMike Smith 
291635863739SMike Smith static int
291700b4e54aSWarner Losh aac_close(struct cdev *dev, int flags, int fmt, struct thread *td)
291835863739SMike Smith {
2919914da7d0SScott Long 	struct aac_softc *sc;
292035863739SMike Smith 
2921914da7d0SScott Long 	sc = dev->si_drv1;
292231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2923a723a548SEd Maste 	sc->aac_open_cnt--;
292435863739SMike Smith 	/* Mark this unit as no longer open  */
2925a723a548SEd Maste 	if (sc->aac_open_cnt == 0)
292635863739SMike Smith 		sc->aac_state &= ~AAC_STATE_OPEN;
292735863739SMike Smith 
292835863739SMike Smith 	return 0;
292935863739SMike Smith }
293035863739SMike Smith 
293135863739SMike Smith static int
293200b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
293335863739SMike Smith {
2934914da7d0SScott Long 	union aac_statrequest *as;
2935914da7d0SScott Long 	struct aac_softc *sc;
29360b94a66eSMike Smith 	int error = 0;
293735863739SMike Smith 
2938914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2939914da7d0SScott Long 	sc = dev->si_drv1;
294031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2941914da7d0SScott Long 
294235863739SMike Smith 	switch (cmd) {
29430b94a66eSMike Smith 	case AACIO_STATS:
29440b94a66eSMike Smith 		switch (as->as_item) {
29450b94a66eSMike Smith 		case AACQ_FREE:
29460b94a66eSMike Smith 		case AACQ_BIO:
29470b94a66eSMike Smith 		case AACQ_READY:
29480b94a66eSMike Smith 		case AACQ_BUSY:
2949c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2950c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
29510b94a66eSMike Smith 			break;
29520b94a66eSMike Smith 		default:
29530b94a66eSMike Smith 			error = ENOENT;
29540b94a66eSMike Smith 			break;
29550b94a66eSMike Smith 		}
29560b94a66eSMike Smith 	break;
29570b94a66eSMike Smith 
295835863739SMike Smith 	case FSACTL_SENDFIB:
2959f355c0e0SEd Maste 	case FSACTL_SEND_LARGE_FIB:
2960fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2961fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
2962f355c0e0SEd Maste 	case FSACTL_LNX_SEND_LARGE_FIB:
296331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
296435863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
296535863739SMike Smith 		break;
2966f355c0e0SEd Maste 	case FSACTL_SEND_RAW_SRB:
2967f355c0e0SEd Maste 		arg = *(caddr_t*)arg;
2968f355c0e0SEd Maste 	case FSACTL_LNX_SEND_RAW_SRB:
296931a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2970f355c0e0SEd Maste 		error = aac_ioctl_send_raw_srb(sc, arg);
2971f355c0e0SEd Maste 		break;
297235863739SMike Smith 	case FSACTL_AIF_THREAD:
2973fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
297431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
297535863739SMike Smith 		error = EINVAL;
297635863739SMike Smith 		break;
297735863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2978fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2979fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
298031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2981a723a548SEd Maste 		error = aac_open_aif(sc, arg);
298235863739SMike Smith 		break;
298335863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2984fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2985fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
298631a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2987fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
298835863739SMike Smith 		break;
298935863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2990a723a548SEd Maste 		arg = *(caddr_t*)arg;
2991fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
299231a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2993a723a548SEd Maste 		error = aac_close_aif(sc, arg);
299435863739SMike Smith 		break;
299535863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2996fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2997fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
299831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
2999fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
300035863739SMike Smith 		break;
300136e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
300236e0bf6eSScott Long 		arg = *(caddr_t*)arg;
300336e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
300431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
300536e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
300636e0bf6eSScott Long 		break;
300736e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
300836e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
3009914da7d0SScott Long 		/*
3010914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
3011914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
3012914da7d0SScott Long 		 * controller
3013914da7d0SScott Long 		 */
301436e0bf6eSScott Long 		error = 0;
301536e0bf6eSScott Long 		break;
30167cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
30177cb209f5SScott Long 		arg = *(caddr_t*)arg;
30187cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
301931a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
30207cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
30217cb209f5SScott Long 		break;
30226d307336SEd Maste 	case FSACTL_GET_FEATURES:
30236d307336SEd Maste 		arg = *(caddr_t*)arg;
30246d307336SEd Maste 	case FSACTL_LNX_GET_FEATURES:
30256d307336SEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
30266d307336SEd Maste 		error = aac_supported_features(sc, arg);
30276d307336SEd Maste 		break;
302835863739SMike Smith 	default:
302931a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
303035863739SMike Smith 		error = EINVAL;
303135863739SMike Smith 		break;
303235863739SMike Smith 	}
303335863739SMike Smith 	return(error);
303435863739SMike Smith }
303535863739SMike Smith 
3036b3457b51SScott Long static int
303700b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td)
3038b3457b51SScott Long {
3039b3457b51SScott Long 	struct aac_softc *sc;
3040ef0b687cSEd Maste 	struct aac_fib_context *ctx;
3041b3457b51SScott Long 	int revents;
3042b3457b51SScott Long 
3043b3457b51SScott Long 	sc = dev->si_drv1;
3044b3457b51SScott Long 	revents = 0;
3045b3457b51SScott Long 
3046bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3047b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
3048ef0b687cSEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3049ef0b687cSEd Maste 			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
3050b3457b51SScott Long 				revents |= poll_events & (POLLIN | POLLRDNORM);
3051ef0b687cSEd Maste 				break;
3052ef0b687cSEd Maste 			}
3053ef0b687cSEd Maste 		}
3054b3457b51SScott Long 	}
3055bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
3056b3457b51SScott Long 
3057b3457b51SScott Long 	if (revents == 0) {
3058b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
3059b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
3060b3457b51SScott Long 	}
3061b3457b51SScott Long 
3062b3457b51SScott Long 	return (revents);
3063b3457b51SScott Long }
3064b3457b51SScott Long 
30657cb209f5SScott Long static void
30667cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
30677cb209f5SScott Long {
30687cb209f5SScott Long 
30697cb209f5SScott Long 	switch (event->ev_type) {
30707cb209f5SScott Long 	case AAC_EVENT_CMFREE:
30710c40d5beSEd Maste 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
30721a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
30737cb209f5SScott Long 			aac_add_event(sc, event);
30747cb209f5SScott Long 			return;
30757cb209f5SScott Long 		}
30767cb209f5SScott Long 		free(event, M_AACBUF);
30778eeb2ca6SScott Long 		wakeup(arg);
30787cb209f5SScott Long 		break;
30797cb209f5SScott Long 	default:
30807cb209f5SScott Long 		break;
30817cb209f5SScott Long 	}
30827cb209f5SScott Long }
30837cb209f5SScott Long 
3084914da7d0SScott Long /*
308535863739SMike Smith  * Send a FIB supplied from userspace
308635863739SMike Smith  */
308735863739SMike Smith static int
308835863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
308935863739SMike Smith {
309035863739SMike Smith 	struct aac_command *cm;
309135863739SMike Smith 	int size, error;
309235863739SMike Smith 
309331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
309435863739SMike Smith 
309535863739SMike Smith 	cm = NULL;
309635863739SMike Smith 
309735863739SMike Smith 	/*
309835863739SMike Smith 	 * Get a command
309935863739SMike Smith 	 */
3100bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
310135863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
31027cb209f5SScott Long 		struct aac_event *event;
31037cb209f5SScott Long 
31047cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
31057cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
31067cb209f5SScott Long 		if (event == NULL) {
310735863739SMike Smith 			error = EBUSY;
3108f16627aaSEd Maste 			mtx_unlock(&sc->aac_io_lock);
310935863739SMike Smith 			goto out;
311035863739SMike Smith 		}
31117cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
31127cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
31137cb209f5SScott Long 		event->ev_arg = &cm;
31147cb209f5SScott Long 		aac_add_event(sc, event);
31158eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
31167cb209f5SScott Long 	}
311793cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
311835863739SMike Smith 
311935863739SMike Smith 	/*
312035863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
312135863739SMike Smith 	 */
3122914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3123914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
312435863739SMike Smith 		goto out;
312535863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3126f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3127f355c0e0SEd Maste 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3128f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3129f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
313035863739SMike Smith 	}
313135863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
313235863739SMike Smith 		goto out;
313335863739SMike Smith 	cm->cm_fib->Header.Size = size;
31342b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
313535863739SMike Smith 
313635863739SMike Smith 	/*
313735863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
313835863739SMike Smith 	 */
313993cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3140f16627aaSEd Maste 	error = aac_wait_command(cm);
3141f16627aaSEd Maste 	mtx_unlock(&sc->aac_io_lock);
3142f16627aaSEd Maste 	if (error != 0) {
314370545d1aSScott Long 		device_printf(sc->aac_dev,
314470545d1aSScott Long 			      "aac_wait_command return %d\n", error);
314535863739SMike Smith 		goto out;
3146b3457b51SScott Long 	}
314735863739SMike Smith 
314835863739SMike Smith 	/*
314935863739SMike Smith 	 * Copy the FIB and data back out to the caller.
315035863739SMike Smith 	 */
315135863739SMike Smith 	size = cm->cm_fib->Header.Size;
3152f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3153f355c0e0SEd Maste 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3154f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3155f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
315635863739SMike Smith 	}
315735863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
315835863739SMike Smith 
315935863739SMike Smith out:
3160f6c4dd3fSScott Long 	if (cm != NULL) {
3161f16627aaSEd Maste 		mtx_lock(&sc->aac_io_lock);
316235863739SMike Smith 		aac_release_command(cm);
3163bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
3164f16627aaSEd Maste 	}
316535863739SMike Smith 	return(error);
316635863739SMike Smith }
316735863739SMike Smith 
3168914da7d0SScott Long /*
3169f355c0e0SEd Maste  * Send a passthrough FIB supplied from userspace
3170f355c0e0SEd Maste  */
3171f355c0e0SEd Maste static int
3172f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3173f355c0e0SEd Maste {
3174f355c0e0SEd Maste 	return (EINVAL);
3175f355c0e0SEd Maste }
3176f355c0e0SEd Maste 
3177f355c0e0SEd Maste /*
317835863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
317936e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
318035863739SMike Smith  */
318135863739SMike Smith static void
318236e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
318335863739SMike Smith {
318436e0bf6eSScott Long 	struct aac_aif_command *aif;
318536e0bf6eSScott Long 	struct aac_container *co, *co_next;
3186a723a548SEd Maste 	struct aac_fib_context *ctx;
318704f4d586SEd Maste 	struct aac_mntinforesp *mir;
3188a723a548SEd Maste 	int next, current, found;
3189795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
319035863739SMike Smith 
319131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
319235863739SMike Smith 
319336e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
319436e0bf6eSScott Long 	aac_print_aif(sc, aif);
319536e0bf6eSScott Long 
319636e0bf6eSScott Long 	/* Is it an event that we should care about? */
319736e0bf6eSScott Long 	switch (aif->command) {
319836e0bf6eSScott Long 	case AifCmdEventNotify:
319936e0bf6eSScott Long 		switch (aif->data.EN.type) {
320036e0bf6eSScott Long 		case AifEnAddContainer:
320136e0bf6eSScott Long 		case AifEnDeleteContainer:
320236e0bf6eSScott Long 			/*
3203914da7d0SScott Long 			 * A container was added or deleted, but the message
3204914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3205914da7d0SScott Long 			 * containers and sort things out.
320636e0bf6eSScott Long 			 */
320703b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
320836e0bf6eSScott Long 			do {
320936e0bf6eSScott Long 				/*
3210914da7d0SScott Long 				 * Ask the controller for its containers one at
3211914da7d0SScott Long 				 * a time.
3212914da7d0SScott Long 				 * XXX What if the controller's list changes
3213914da7d0SScott Long 				 * midway through this enumaration?
321436e0bf6eSScott Long 				 * XXX This should be done async.
321536e0bf6eSScott Long 				 */
321604f4d586SEd Maste 				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
321736e0bf6eSScott Long 					continue;
321804f4d586SEd Maste 				if (i == 0)
3219795d7dc0SScott Long 					count = mir->MntRespCount;
322036e0bf6eSScott Long 				/*
3221914da7d0SScott Long 				 * Check the container against our list.
3222914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3223914da7d0SScott Long 				 * previous run.
322436e0bf6eSScott Long 				 */
3225cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3226cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
322736e0bf6eSScott Long 					found = 0;
3228914da7d0SScott Long 					TAILQ_FOREACH(co,
3229914da7d0SScott Long 						      &sc->aac_container_tqh,
3230914da7d0SScott Long 						      co_link) {
323136e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3232cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
323336e0bf6eSScott Long 							co->co_found = 1;
323436e0bf6eSScott Long 							found = 1;
323536e0bf6eSScott Long 							break;
323636e0bf6eSScott Long 						}
323736e0bf6eSScott Long 					}
3238914da7d0SScott Long 					/*
3239914da7d0SScott Long 					 * If the container matched, continue
3240914da7d0SScott Long 					 * in the list.
3241914da7d0SScott Long 					 */
324236e0bf6eSScott Long 					if (found) {
324336e0bf6eSScott Long 						i++;
324436e0bf6eSScott Long 						continue;
324536e0bf6eSScott Long 					}
324636e0bf6eSScott Long 
324736e0bf6eSScott Long 					/*
3248914da7d0SScott Long 					 * This is a new container.  Do all the
324970545d1aSScott Long 					 * appropriate things to set it up.
325070545d1aSScott Long 					 */
3251cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
325236e0bf6eSScott Long 					added = 1;
325336e0bf6eSScott Long 				}
325436e0bf6eSScott Long 				i++;
3255795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3256cbfd045bSScott Long 			aac_release_sync_fib(sc);
325736e0bf6eSScott Long 
325836e0bf6eSScott Long 			/*
3259914da7d0SScott Long 			 * Go through our list of containers and see which ones
3260914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3261914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3262914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3263914da7d0SScott Long 			 * the co->co_found field.
326436e0bf6eSScott Long 			 */
326536e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
326636e0bf6eSScott Long 			while (co != NULL) {
326736e0bf6eSScott Long 				if (co->co_found == 0) {
32687cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
3269a56fe095SJohn Baldwin 					mtx_lock(&Giant);
3270914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3271914da7d0SScott Long 							    co->co_disk);
3272a56fe095SJohn Baldwin 					mtx_unlock(&Giant);
32737cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
327436e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3275bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3276914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3277914da7d0SScott Long 						     co_link);
3278bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3279ba1d57e7SScott Long 					free(co, M_AACBUF);
328036e0bf6eSScott Long 					co = co_next;
328136e0bf6eSScott Long 				} else {
328236e0bf6eSScott Long 					co->co_found = 0;
328336e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
328436e0bf6eSScott Long 				}
328536e0bf6eSScott Long 			}
328636e0bf6eSScott Long 
328736e0bf6eSScott Long 			/* Attach the newly created containers */
32887cb209f5SScott Long 			if (added) {
32897cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
3290a56fe095SJohn Baldwin 				mtx_lock(&Giant);
329136e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
3292a56fe095SJohn Baldwin 				mtx_unlock(&Giant);
32937cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
32947cb209f5SScott Long 			}
329536e0bf6eSScott Long 
329636e0bf6eSScott Long 			break;
329736e0bf6eSScott Long 
329836e0bf6eSScott Long 		default:
329936e0bf6eSScott Long 			break;
330036e0bf6eSScott Long 		}
330136e0bf6eSScott Long 
330236e0bf6eSScott Long 	default:
330336e0bf6eSScott Long 		break;
330436e0bf6eSScott Long 	}
330536e0bf6eSScott Long 
330636e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3307bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3308a723a548SEd Maste 	current = sc->aifq_idx;
3309a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3310a723a548SEd Maste 	if (next == 0)
3311a723a548SEd Maste 		sc->aifq_filled = 1;
3312a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3313a723a548SEd Maste 	/* modify AIF contexts */
3314a723a548SEd Maste 	if (sc->aifq_filled) {
3315a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3316a723a548SEd Maste 			if (next == ctx->ctx_idx)
3317a723a548SEd Maste 				ctx->ctx_wrap = 1;
3318a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3319a723a548SEd Maste 				ctx->ctx_idx = next;
3320a723a548SEd Maste 		}
3321a723a548SEd Maste 	}
3322a723a548SEd Maste 	sc->aifq_idx = next;
3323b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
332435863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
332535863739SMike Smith 		wakeup(sc->aac_aifq);
3326b3457b51SScott Long 	/* Wakeup any poll()ers */
3327512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3328bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
332936e0bf6eSScott Long 
333036e0bf6eSScott Long 	return;
333135863739SMike Smith }
333235863739SMike Smith 
3333914da7d0SScott Long /*
33340b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
333536e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
333636e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
333736e0bf6eSScott Long  * returning what the card reported.
333835863739SMike Smith  */
333935863739SMike Smith static int
3340fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
334135863739SMike Smith {
334235863739SMike Smith 	struct aac_rev_check rev_check;
334335863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
334435863739SMike Smith 	int error = 0;
334535863739SMike Smith 
334631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
334735863739SMike Smith 
334835863739SMike Smith 	/*
334935863739SMike Smith 	 * Copyin the revision struct from userspace
335035863739SMike Smith 	 */
3351c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3352c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
335335863739SMike Smith 		return error;
335435863739SMike Smith 	}
335535863739SMike Smith 
335631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3357914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
335835863739SMike Smith 
335935863739SMike Smith 	/*
336035863739SMike Smith 	 * Doctor up the response struct.
336135863739SMike Smith 	 */
336235863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3363914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3364914da7d0SScott Long 	    sc->aac_revision.external.ul;
3365914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3366914da7d0SScott Long 	    sc->aac_revision.buildNumber;
336735863739SMike Smith 
3368c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3369c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
337035863739SMike Smith }
337135863739SMike Smith 
3372914da7d0SScott Long /*
3373a723a548SEd Maste  * Pass the fib context to the caller
3374a723a548SEd Maste  */
3375a723a548SEd Maste static int
3376a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3377a723a548SEd Maste {
3378a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3379a723a548SEd Maste 	int error = 0;
3380a723a548SEd Maste 
338131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3382a723a548SEd Maste 
3383a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3384a723a548SEd Maste 	if (fibctx == NULL)
3385a723a548SEd Maste 		return (ENOMEM);
3386a723a548SEd Maste 
3387a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3388a723a548SEd Maste 	/* all elements are already 0, add to queue */
3389a723a548SEd Maste 	if (sc->fibctx == NULL)
3390a723a548SEd Maste 		sc->fibctx = fibctx;
3391a723a548SEd Maste 	else {
3392a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3393a723a548SEd Maste 			;
3394a723a548SEd Maste 		ctx->next = fibctx;
3395a723a548SEd Maste 		fibctx->prev = ctx;
3396a723a548SEd Maste 	}
3397a723a548SEd Maste 
3398a723a548SEd Maste 	/* evaluate unique value */
3399a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3400a723a548SEd Maste 	ctx = sc->fibctx;
3401a723a548SEd Maste 	while (ctx != fibctx) {
3402a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3403a723a548SEd Maste 			fibctx->unique++;
3404a723a548SEd Maste 			ctx = sc->fibctx;
3405a723a548SEd Maste 		} else {
3406a723a548SEd Maste 			ctx = ctx->next;
3407a723a548SEd Maste 		}
3408a723a548SEd Maste 	}
3409a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3410a723a548SEd Maste 
3411a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3412a723a548SEd Maste 	if (error)
3413a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3414a723a548SEd Maste 	return error;
3415a723a548SEd Maste }
3416a723a548SEd Maste 
3417a723a548SEd Maste /*
3418a723a548SEd Maste  * Close the caller's fib context
3419a723a548SEd Maste  */
3420a723a548SEd Maste static int
3421a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3422a723a548SEd Maste {
3423a723a548SEd Maste 	struct aac_fib_context *ctx;
3424a723a548SEd Maste 
342531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3426a723a548SEd Maste 
3427a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3428a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3429a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3430a723a548SEd Maste 			if (ctx == sc->fibctx)
3431a723a548SEd Maste 				sc->fibctx = NULL;
3432a723a548SEd Maste 			else {
3433a723a548SEd Maste 				ctx->prev->next = ctx->next;
3434a723a548SEd Maste 				if (ctx->next)
3435a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3436a723a548SEd Maste 			}
3437a723a548SEd Maste 			break;
3438a723a548SEd Maste 		}
3439a723a548SEd Maste 	}
3440a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3441a723a548SEd Maste 	if (ctx)
3442a723a548SEd Maste 		free(ctx, M_AACBUF);
3443a723a548SEd Maste 
3444a723a548SEd Maste 	return 0;
3445a723a548SEd Maste }
3446a723a548SEd Maste 
3447a723a548SEd Maste /*
344835863739SMike Smith  * Pass the caller the next AIF in their queue
344935863739SMike Smith  */
345035863739SMike Smith static int
3451fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
345235863739SMike Smith {
345335863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3454a723a548SEd Maste 	struct aac_fib_context *ctx;
34559e2e96d8SScott Long 	int error;
345635863739SMike Smith 
345731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
345835863739SMike Smith 
345935863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3460a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3461a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3462a723a548SEd Maste 				break;
3463a723a548SEd Maste 		}
3464a723a548SEd Maste 		if (!ctx)
3465a723a548SEd Maste 			return (EFAULT);
346635863739SMike Smith 
3467a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3468a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
346931a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
347035863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
347135863739SMike Smith 			while (error == EAGAIN) {
3472914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3473914da7d0SScott Long 					       PCATCH, "aacaif", 0);
347435863739SMike Smith 				if (error == 0)
3475a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
347635863739SMike Smith 			}
347735863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
347835863739SMike Smith 		}
347935863739SMike Smith 	}
348035863739SMike Smith 	return(error);
348135863739SMike Smith }
348235863739SMike Smith 
3483914da7d0SScott Long /*
34840b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
34850b94a66eSMike Smith  */
34860b94a66eSMike Smith static int
3487a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
34880b94a66eSMike Smith {
3489a723a548SEd Maste 	int current, error;
34900b94a66eSMike Smith 
349131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
34920b94a66eSMike Smith 
3493bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3494a723a548SEd Maste 	current = ctx->ctx_idx;
3495a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3496a723a548SEd Maste 		/* empty */
3497bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
34983df780cfSScott Long 		return (EAGAIN);
34993df780cfSScott Long 	}
3500a723a548SEd Maste 	error =
3501a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
350236e0bf6eSScott Long 	if (error)
350370545d1aSScott Long 		device_printf(sc->aac_dev,
350470545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3505a723a548SEd Maste 	else {
3506a723a548SEd Maste 		ctx->ctx_wrap = 0;
3507a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3508a723a548SEd Maste 	}
3509bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
35100b94a66eSMike Smith 	return(error);
35110b94a66eSMike Smith }
351236e0bf6eSScott Long 
35137cb209f5SScott Long static int
35147cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
35157cb209f5SScott Long {
35167cb209f5SScott Long 	struct aac_pci_info {
35177cb209f5SScott Long 		u_int32_t bus;
35187cb209f5SScott Long 		u_int32_t slot;
35197cb209f5SScott Long 	} pciinf;
35207cb209f5SScott Long 	int error;
35217cb209f5SScott Long 
352231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35237cb209f5SScott Long 
35247cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
35257cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
35267cb209f5SScott Long 
35277cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
35287cb209f5SScott Long 			sizeof(struct aac_pci_info));
35297cb209f5SScott Long 
35307cb209f5SScott Long 	return (error);
35317cb209f5SScott Long }
35327cb209f5SScott Long 
35336d307336SEd Maste static int
35346d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr)
35356d307336SEd Maste {
35366d307336SEd Maste 	struct aac_features f;
35376d307336SEd Maste 	int error;
35386d307336SEd Maste 
35396d307336SEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35406d307336SEd Maste 
35416d307336SEd Maste 	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
35426d307336SEd Maste 		return (error);
35436d307336SEd Maste 
35446d307336SEd Maste 	/*
35456d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35466d307336SEd Maste 	 * ALL zero in the featuresState, the driver will return the current
35476d307336SEd Maste 	 * state of all the supported features, the data field will not be
35486d307336SEd Maste 	 * valid.
35496d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35506d307336SEd Maste 	 * a specific bit set in the featuresState, the driver will return the
35516d307336SEd Maste 	 * current state of this specific feature and whatever data that are
35526d307336SEd Maste 	 * associated with the feature in the data field or perform whatever
35536d307336SEd Maste 	 * action needed indicates in the data field.
35546d307336SEd Maste 	 */
35556d307336SEd Maste 	if (f.feat.fValue == 0) {
35566d307336SEd Maste 		f.feat.fBits.largeLBA =
35576d307336SEd Maste 		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35586d307336SEd Maste 		/* TODO: In the future, add other features state here as well */
35596d307336SEd Maste 	} else {
35606d307336SEd Maste 		if (f.feat.fBits.largeLBA)
35616d307336SEd Maste 			f.feat.fBits.largeLBA =
35626d307336SEd Maste 			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35636d307336SEd Maste 		/* TODO: Add other features state and data in the future */
35646d307336SEd Maste 	}
35656d307336SEd Maste 
35666d307336SEd Maste 	error = copyout(&f, uptr, sizeof (f));
35676d307336SEd Maste 	return (error);
35686d307336SEd Maste }
35696d307336SEd Maste 
3570914da7d0SScott Long /*
357136e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
357236e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
357336e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
357436e0bf6eSScott Long  */
357536e0bf6eSScott Long static int
357636e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
357736e0bf6eSScott Long {
357836e0bf6eSScott Long 	struct aac_query_disk query_disk;
357936e0bf6eSScott Long 	struct aac_container *co;
3580914da7d0SScott Long 	struct aac_disk	*disk;
358136e0bf6eSScott Long 	int error, id;
358236e0bf6eSScott Long 
358331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
358436e0bf6eSScott Long 
3585914da7d0SScott Long 	disk = NULL;
3586914da7d0SScott Long 
3587914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3588914da7d0SScott Long 		       sizeof(struct aac_query_disk));
358936e0bf6eSScott Long 	if (error)
359036e0bf6eSScott Long 		return (error);
359136e0bf6eSScott Long 
359236e0bf6eSScott Long 	id = query_disk.ContainerNumber;
359336e0bf6eSScott Long 	if (id == -1)
359436e0bf6eSScott Long 		return (EINVAL);
359536e0bf6eSScott Long 
3596bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
359736e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
359836e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
359936e0bf6eSScott Long 			break;
360036e0bf6eSScott Long 		}
360136e0bf6eSScott Long 
360236e0bf6eSScott Long 	if (co == NULL) {
360336e0bf6eSScott Long 			query_disk.Valid = 0;
360436e0bf6eSScott Long 			query_disk.Locked = 0;
360536e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
360636e0bf6eSScott Long 	} else {
360736e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
360836e0bf6eSScott Long 		query_disk.Valid = 1;
3609914da7d0SScott Long 		query_disk.Locked =
3610914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
361136e0bf6eSScott Long 		query_disk.Deleted = 0;
3612b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
361336e0bf6eSScott Long 		query_disk.Target = disk->unit;
361436e0bf6eSScott Long 		query_disk.Lun = 0;
361536e0bf6eSScott Long 		query_disk.UnMapped = 0;
36167540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
36170b7ed341SPoul-Henning Kamp 			disk->ad_disk->d_name, disk->ad_disk->d_unit);
361836e0bf6eSScott Long 	}
3619bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
362036e0bf6eSScott Long 
3621914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3622914da7d0SScott Long 			sizeof(struct aac_query_disk));
362336e0bf6eSScott Long 
362436e0bf6eSScott Long 	return (error);
362536e0bf6eSScott Long }
362636e0bf6eSScott Long 
3627fe3cb0e1SScott Long static void
3628fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3629fe3cb0e1SScott Long {
3630fe3cb0e1SScott Long 	struct aac_fib *fib;
3631fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3632fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3633fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3634fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3635fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
363670545d1aSScott Long 	struct aac_sim *caminf;
3637fe3cb0e1SScott Long 	device_t child;
3638fe3cb0e1SScott Long 	int i, found, error;
3639fe3cb0e1SScott Long 
36401ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
364103b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3642fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
364339ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3644fe3cb0e1SScott Long 
3645fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3646fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3647fe3cb0e1SScott Long 	c_cmd->param = 0;
3648fe3cb0e1SScott Long 
3649fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3650fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3651fe3cb0e1SScott Long 	if (error) {
3652fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3653fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3654fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36551ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3656fe3cb0e1SScott Long 		return;
3657fe3cb0e1SScott Long 	}
3658fe3cb0e1SScott Long 
3659fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3660fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3661fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3662fe3cb0e1SScott Long 		    c_resp->Status);
3663fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36641ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3665fe3cb0e1SScott Long 		return;
3666fe3cb0e1SScott Long 	}
3667fe3cb0e1SScott Long 
3668fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3669fe3cb0e1SScott Long 
3670fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
367139ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
367239ee03c3SScott Long 
3673fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3674fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3675fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3676fe3cb0e1SScott Long 	vmi->ObjId = 0;
3677fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3678fe3cb0e1SScott Long 
3679fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
368042ef13a2SEd Maste 	    sizeof(struct aac_vmi_businf_resp));
3681fe3cb0e1SScott Long 	if (error) {
3682fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3683fe3cb0e1SScott Long 		    error);
3684fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36851ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3686fe3cb0e1SScott Long 		return;
3687fe3cb0e1SScott Long 	}
3688fe3cb0e1SScott Long 
3689fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3690fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3691fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3692fe3cb0e1SScott Long 		    vmi_resp->Status);
3693fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36941ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3695fe3cb0e1SScott Long 		return;
3696fe3cb0e1SScott Long 	}
3697fe3cb0e1SScott Long 
3698fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3699fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
37001ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3701fe3cb0e1SScott Long 
3702fe3cb0e1SScott Long 	found = 0;
3703fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3704fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3705fe3cb0e1SScott Long 			continue;
3706fe3cb0e1SScott Long 
3707a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3708a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3709b5f516cdSScott Long 		if (caminf == NULL) {
3710b5f516cdSScott Long 			device_printf(sc->aac_dev,
3711b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3712b5f516cdSScott Long 			break;
37137cb209f5SScott Long 		};
3714fe3cb0e1SScott Long 
3715fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3716fe3cb0e1SScott Long 		if (child == NULL) {
3717b5f516cdSScott Long 			device_printf(sc->aac_dev,
3718b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3719b5f516cdSScott Long 			    i);
3720b5f516cdSScott Long 			free(caminf, M_AACBUF);
3721b5f516cdSScott Long 			break;
3722fe3cb0e1SScott Long 		}
3723fe3cb0e1SScott Long 
3724fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3725fe3cb0e1SScott Long 		caminf->BusNumber = i;
3726fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3727fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3728ddb8683eSScott Long 		caminf->sim_dev = child;
3729fe3cb0e1SScott Long 
3730fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3731fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
373270545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3733fe3cb0e1SScott Long 
3734fe3cb0e1SScott Long 		found = 1;
3735fe3cb0e1SScott Long 	}
3736fe3cb0e1SScott Long 
3737fe3cb0e1SScott Long 	if (found)
3738fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3739fe3cb0e1SScott Long 
3740fe3cb0e1SScott Long 	return;
3741fe3cb0e1SScott Long }
3742