xref: /freebsd/sys/dev/aac/aac.c (revision 867b1d3431b4b7502abc23c03fda8c4891b8d55e)
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 
912ef544f63SPaolo Pisati int
9137cb209f5SScott Long aac_fast_intr(void *arg)
91435863739SMike Smith {
915914da7d0SScott Long 	struct aac_softc *sc;
91670545d1aSScott Long 	u_int16_t reason;
91735863739SMike Smith 
918914da7d0SScott Long 	sc = (struct aac_softc *)arg;
919914da7d0SScott Long 
92031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
921f30ac74cSScott Long 	/*
9229148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
9239148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
9249148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
9259148fa21SScott Long 	 * ugly.
926f30ac74cSScott Long 	 */
92735863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
928f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
929f30ac74cSScott Long 
9309c3a7fceSScott Long 	/* handle completion processing */
9319148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
9329148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
93335863739SMike Smith 
9349148fa21SScott Long 	/* controller wants to talk to us */
9359148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
93670545d1aSScott Long 		/*
9379148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
9389148fa21SScott Long 		 * that start with a NULL.
93970545d1aSScott Long 		 */
9409148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
9419148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
9429148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
94370545d1aSScott Long 
9449148fa21SScott Long 		/*
9459148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
946a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
9479148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
9489148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
9499148fa21SScott Long 		 * if needed.
9509148fa21SScott Long 		 */
95136e0bf6eSScott Long 		wakeup(sc->aifthread);
95236e0bf6eSScott Long 	}
953ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
9549148fa21SScott Long }
95535863739SMike Smith 
956c6eafcf2SScott Long /*
957914da7d0SScott Long  * Command Processing
958914da7d0SScott Long  */
95935863739SMike Smith 
960914da7d0SScott Long /*
96135863739SMike Smith  * Start as much queued I/O as possible on the controller
96235863739SMike Smith  */
963fe3cb0e1SScott Long void
96435863739SMike Smith aac_startio(struct aac_softc *sc)
96535863739SMike Smith {
96635863739SMike Smith 	struct aac_command *cm;
967397fa34fSScott Long 	int error;
96835863739SMike Smith 
96931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
97035863739SMike Smith 
97135863739SMike Smith 	for (;;) {
972914da7d0SScott Long 		/*
973397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
974397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
975397fa34fSScott Long 		 */
976397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
977397fa34fSScott Long 			break;
978397fa34fSScott Long 
979397fa34fSScott Long 		/*
980914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
981914da7d0SScott Long 		 * resources
982914da7d0SScott Long 		 */
98335863739SMike Smith 		cm = aac_dequeue_ready(sc);
98435863739SMike Smith 
985914da7d0SScott Long 		/*
986914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
987914da7d0SScott Long 		 * return)
988914da7d0SScott Long 		 */
9890b94a66eSMike Smith 		if (cm == NULL)
99035863739SMike Smith 			aac_bio_command(sc, &cm);
99135863739SMike Smith 
99235863739SMike Smith 		/* nothing to do? */
99335863739SMike Smith 		if (cm == NULL)
99435863739SMike Smith 			break;
99535863739SMike Smith 
996cd481291SScott Long 		/* don't map more than once */
997cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
9984102d44bSScott Long 			panic("aac: command %p already mapped", cm);
99935863739SMike Smith 
1000397fa34fSScott Long 		/*
1001397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
1002397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
1003397fa34fSScott Long 		 * busdma.
1004397fa34fSScott Long 		 */
1005cd481291SScott Long 		if (cm->cm_datalen != 0) {
1006397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
1007397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
1008397fa34fSScott Long 						cm->cm_datalen,
1009cd481291SScott Long 						aac_map_command_sg, cm, 0);
1010cd481291SScott Long 			if (error == EINPROGRESS) {
101131a0399eSEd Maste 				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
1012cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
1013cd481291SScott Long 				error = 0;
1014614c22b2SScott Long 			} else if (error != 0)
1015397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
1016a620bad0SEd Maste 				      "busdma", error);
1017397fa34fSScott Long 		} else
10188778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
1019cd481291SScott Long 	}
102035863739SMike Smith }
102135863739SMike Smith 
1022914da7d0SScott Long /*
102335863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
102435863739SMike Smith  */
102535863739SMike Smith static void
102670545d1aSScott Long aac_command_thread(struct aac_softc *sc)
102735863739SMike Smith {
102835863739SMike Smith 	struct aac_fib *fib;
102935863739SMike Smith 	u_int32_t fib_size;
10309148fa21SScott Long 	int size, retval;
103135863739SMike Smith 
103231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
103335863739SMike Smith 
1034bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1035a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
103636e0bf6eSScott Long 
1037a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1038a32a982dSScott Long 
1039a32a982dSScott Long 		retval = 0;
1040a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1041a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1042a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
104336e0bf6eSScott Long 
10449148fa21SScott Long 		/*
10459148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
10469148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
10479148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
10489148fa21SScott Long 		 */
10499148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1050bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
1051a32a982dSScott Long 			aac_alloc_commands(sc);
1052bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
10534102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1054a32a982dSScott Long 			aac_startio(sc);
1055a32a982dSScott Long 		}
10569148fa21SScott Long 
10579148fa21SScott Long 		/*
10589148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
10599148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
10609148fa21SScott Long 		 * always fire.
10619148fa21SScott Long 		 */
10629148fa21SScott Long 		if (retval == EWOULDBLOCK)
106370545d1aSScott Long 			aac_timeout(sc);
106470545d1aSScott Long 
106570545d1aSScott Long 		/* Check the hardware printf message buffer */
10669148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
106770545d1aSScott Long 			aac_print_printf(sc);
106870545d1aSScott Long 
10699148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
10707cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
10717cb209f5SScott Long 			continue;
10727cb209f5SScott Long 		for (;;) {
10737cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
10747cb209f5SScott Long 					   &fib_size, &fib))
10757cb209f5SScott Long 				break;
107635863739SMike Smith 
107736e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
107836e0bf6eSScott Long 
107935863739SMike Smith 			switch (fib->Header.Command) {
108035863739SMike Smith 			case AifRequest:
108136e0bf6eSScott Long 				aac_handle_aif(sc, fib);
108235863739SMike Smith 				break;
108335863739SMike Smith 			default:
1084914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
1085914da7d0SScott Long 					      "from controller\n");
108635863739SMike Smith 				break;
108735863739SMike Smith 			}
108835863739SMike Smith 
108936e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
10907cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
109136e0bf6eSScott Long 				break;
10927cb209f5SScott Long 			}
109336e0bf6eSScott Long 
109470545d1aSScott Long 			/* Return the AIF to the controller. */
109536e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
109636e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
109736e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
109836e0bf6eSScott Long 
109936e0bf6eSScott Long 				/* XXX Compute the Size field? */
110036e0bf6eSScott Long 				size = fib->Header.Size;
110136e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
110236e0bf6eSScott Long 					size = sizeof(struct aac_fib);
110336e0bf6eSScott Long 					fib->Header.Size = size;
110436e0bf6eSScott Long 				}
110536e0bf6eSScott Long 				/*
1106914da7d0SScott Long 				 * Since we did not generate this command, it
1107914da7d0SScott Long 				 * cannot go through the normal
1108914da7d0SScott Long 				 * enqueue->startio chain.
110936e0bf6eSScott Long 				 */
1110914da7d0SScott Long 				aac_enqueue_response(sc,
1111914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
1112914da7d0SScott Long 						 fib);
111336e0bf6eSScott Long 			}
111436e0bf6eSScott Long 		}
111536e0bf6eSScott Long 	}
111636e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1117bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
111836e0bf6eSScott Long 	wakeup(sc->aac_dev);
111936e0bf6eSScott Long 
11203745c395SJulian Elischer 	kproc_exit(0);
112135863739SMike Smith }
112235863739SMike Smith 
1123914da7d0SScott Long /*
11249c3a7fceSScott Long  * Process completed commands.
112535863739SMike Smith  */
112635863739SMike Smith static void
11279c3a7fceSScott Long aac_complete(void *context, int pending)
112835863739SMike Smith {
11299c3a7fceSScott Long 	struct aac_softc *sc;
113035863739SMike Smith 	struct aac_command *cm;
113135863739SMike Smith 	struct aac_fib *fib;
113235863739SMike Smith 	u_int32_t fib_size;
113335863739SMike Smith 
11349c3a7fceSScott Long 	sc = (struct aac_softc *)context;
113531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
11369c3a7fceSScott Long 
1137bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1138ae543596SScott Long 
11399c3a7fceSScott Long 	/* pull completed commands off the queue */
114035863739SMike Smith 	for (;;) {
114135863739SMike Smith 		/* look for completed FIBs on our queue */
1142914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1143914da7d0SScott Long 							&fib))
114435863739SMike Smith 			break;	/* nothing to do */
114535863739SMike Smith 
1146ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1147cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
114835863739SMike Smith 		if (cm == NULL) {
114935863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
11509c3a7fceSScott Long 			break;
11519c3a7fceSScott Long 		}
11520b94a66eSMike Smith 		aac_remove_busy(cm);
11537cb209f5SScott Long 
1154ecd1c51fSScott Long  		aac_unmap_command(cm);
115535863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
115635863739SMike Smith 
115735863739SMike Smith 		/* is there a completion handler? */
115835863739SMike Smith 		if (cm->cm_complete != NULL) {
115935863739SMike Smith 			cm->cm_complete(cm);
116035863739SMike Smith 		} else {
116135863739SMike Smith 			/* assume that someone is sleeping on this command */
116235863739SMike Smith 			wakeup(cm);
116335863739SMike Smith 		}
116435863739SMike Smith 	}
11650b94a66eSMike Smith 
11660b94a66eSMike Smith 	/* see if we can start some more I/O */
1167cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
11680b94a66eSMike Smith 	aac_startio(sc);
1169ae543596SScott Long 
1170bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
117135863739SMike Smith }
117235863739SMike Smith 
1173914da7d0SScott Long /*
117435863739SMike Smith  * Handle a bio submitted from a disk device.
117535863739SMike Smith  */
117635863739SMike Smith void
117735863739SMike Smith aac_submit_bio(struct bio *bp)
117835863739SMike Smith {
1179914da7d0SScott Long 	struct aac_disk *ad;
1180914da7d0SScott Long 	struct aac_softc *sc;
118135863739SMike Smith 
11827540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1183914da7d0SScott Long 	sc = ad->ad_controller;
118431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1185914da7d0SScott Long 
118635863739SMike Smith 	/* queue the BIO and try to get some work done */
11870b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
118835863739SMike Smith 	aac_startio(sc);
118935863739SMike Smith }
119035863739SMike Smith 
1191914da7d0SScott Long /*
119235863739SMike Smith  * Get a bio and build a command to go with it.
119335863739SMike Smith  */
119435863739SMike Smith static int
119535863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
119635863739SMike Smith {
119735863739SMike Smith 	struct aac_command *cm;
119835863739SMike Smith 	struct aac_fib *fib;
119935863739SMike Smith 	struct aac_disk *ad;
120035863739SMike Smith 	struct bio *bp;
120135863739SMike Smith 
120231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
120335863739SMike Smith 
120435863739SMike Smith 	/* get the resources we will need */
120535863739SMike Smith 	cm = NULL;
1206a32a982dSScott Long 	bp = NULL;
120735863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
120835863739SMike Smith 		goto fail;
1209a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1210a32a982dSScott Long 		goto fail;
121135863739SMike Smith 
121235863739SMike Smith 	/* fill out the command */
12130b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
12140b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
12150b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
121635863739SMike Smith 	cm->cm_private = bp;
12172b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
121836e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
121935863739SMike Smith 
122035863739SMike Smith 	/* build the FIB */
122135863739SMike Smith 	fib = cm->cm_fib;
1222b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
122335863739SMike Smith 	fib->Header.XferState =
122435863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
122535863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1226f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
122735863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
122835863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1229f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1230f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1231f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
123235863739SMike Smith 
123335863739SMike Smith 	/* build the read/write request */
12347540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1235b85f5808SScott Long 
12367cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
12377cb209f5SScott Long 		struct aac_raw_io *raw;
12387cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
12397cb209f5SScott Long 		fib->Header.Command = RawIo;
12407cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
12417cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
12427cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
12437cb209f5SScott Long 		raw->BpTotal = 0;
12447cb209f5SScott Long 		raw->BpComplete = 0;
12457cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
12467cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
12477cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
12487cb209f5SScott Long 			raw->Flags = 1;
12497cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
12507cb209f5SScott Long 		} else {
12517cb209f5SScott Long 			raw->Flags = 0;
12527cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
12537cb209f5SScott Long 		}
12547cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1255b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
12569e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1257b85f5808SScott Long 			struct aac_blockread *br;
125835863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
125935863739SMike Smith 			br->Command = VM_CtBlockRead;
126035863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
126135863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
126235863739SMike Smith 			br->ByteCount = bp->bio_bcount;
126335863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
126435863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
126535863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
126635863739SMike Smith 		} else {
1267b85f5808SScott Long 			struct aac_blockwrite *bw;
126835863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
126935863739SMike Smith 			bw->Command = VM_CtBlockWrite;
127035863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
127135863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
127235863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1273b85f5808SScott Long 			bw->Stable = CUNSTABLE;
127435863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
127535863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
127635863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
127735863739SMike Smith 		}
1278b85f5808SScott Long 	} else {
1279b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1280b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1281b85f5808SScott Long 			struct aac_blockread64 *br;
1282b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1283b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1284b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1285b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1286b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1287b85f5808SScott Long 			br->Pad = 0;
1288b85f5808SScott Long 			br->Flags = 0;
1289b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
129054e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAIN;
1291eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1292b85f5808SScott Long 		} else {
1293b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1294b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1295b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1296b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1297b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1298b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1299b85f5808SScott Long 			bw->Pad = 0;
1300b85f5808SScott Long 			bw->Flags = 0;
1301b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
130254e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAOUT;
1303eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1304b85f5808SScott Long 		}
1305b85f5808SScott Long 	}
130635863739SMike Smith 
130735863739SMike Smith 	*cmp = cm;
130835863739SMike Smith 	return(0);
130935863739SMike Smith 
131035863739SMike Smith fail:
13117cb209f5SScott Long 	if (bp != NULL)
13127cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
131335863739SMike Smith 	if (cm != NULL)
131435863739SMike Smith 		aac_release_command(cm);
131535863739SMike Smith 	return(ENOMEM);
131635863739SMike Smith }
131735863739SMike Smith 
1318914da7d0SScott Long /*
131935863739SMike Smith  * Handle a bio-instigated command that has been completed.
132035863739SMike Smith  */
132135863739SMike Smith static void
132235863739SMike Smith aac_bio_complete(struct aac_command *cm)
132335863739SMike Smith {
132435863739SMike Smith 	struct aac_blockread_response *brr;
132535863739SMike Smith 	struct aac_blockwrite_response *bwr;
132635863739SMike Smith 	struct bio *bp;
132735863739SMike Smith 	AAC_FSAStatus status;
132835863739SMike Smith 
132935863739SMike Smith 	/* fetch relevant status and then release the command */
133035863739SMike Smith 	bp = (struct bio *)cm->cm_private;
13319e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
133235863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
133335863739SMike Smith 		status = brr->Status;
133435863739SMike Smith 	} else {
133535863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
133635863739SMike Smith 		status = bwr->Status;
133735863739SMike Smith 	}
133835863739SMike Smith 	aac_release_command(cm);
133935863739SMike Smith 
134035863739SMike Smith 	/* fix up the bio based on status */
134135863739SMike Smith 	if (status == ST_OK) {
134235863739SMike Smith 		bp->bio_resid = 0;
134335863739SMike Smith 	} else {
134435863739SMike Smith 		bp->bio_error = EIO;
134535863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
13460b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1347914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1348914da7d0SScott Long 						    status);
134935863739SMike Smith 	}
13500b94a66eSMike Smith 	aac_biodone(bp);
135135863739SMike Smith }
135235863739SMike Smith 
1353914da7d0SScott Long /*
135435863739SMike Smith  * Submit a command to the controller, return when it completes.
1355b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1356b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1357d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1358d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1359d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1360d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1361d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
136235863739SMike Smith  */
136335863739SMike Smith static int
1364d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
136535863739SMike Smith {
1366ae543596SScott Long 	struct aac_softc *sc;
1367d8a0a473SScott Long 	int error;
136835863739SMike Smith 
1369ae543596SScott Long 	sc = cm->cm_sc;
137031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1371ae543596SScott Long 
137235863739SMike Smith 	/* Put the command on the ready queue and get things going */
137336e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
137435863739SMike Smith 	aac_enqueue_ready(cm);
1375ae543596SScott Long 	aac_startio(sc);
1376ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
137735863739SMike Smith 	return(error);
137835863739SMike Smith }
137935863739SMike Smith 
1380914da7d0SScott Long /*
1381914da7d0SScott Long  *Command Buffer Management
1382914da7d0SScott Long  */
138335863739SMike Smith 
1384914da7d0SScott Long /*
138535863739SMike Smith  * Allocate a command.
138635863739SMike Smith  */
1387fe3cb0e1SScott Long int
138835863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
138935863739SMike Smith {
139035863739SMike Smith 	struct aac_command *cm;
139135863739SMike Smith 
139231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
139335863739SMike Smith 
1394ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1395b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1396ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1397ae543596SScott Long 			wakeup(sc->aifthread);
1398b85f5808SScott Long 		}
1399ae543596SScott Long 		return (EBUSY);
1400ffb37f33SScott Long 	}
140135863739SMike Smith 
14020b94a66eSMike Smith 	*cmp = cm;
14030b94a66eSMike Smith 	return(0);
14040b94a66eSMike Smith }
14050b94a66eSMike Smith 
1406914da7d0SScott Long /*
14070b94a66eSMike Smith  * Release a command back to the freelist.
14080b94a66eSMike Smith  */
1409fe3cb0e1SScott Long void
14100b94a66eSMike Smith aac_release_command(struct aac_command *cm)
14110b94a66eSMike Smith {
14127cb209f5SScott Long 	struct aac_event *event;
14137cb209f5SScott Long 	struct aac_softc *sc;
14147cb209f5SScott Long 
141531a0399eSEd Maste 	sc = cm->cm_sc;
141631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
14170b94a66eSMike Smith 
14184109ba51SEd Maste 	/* (re)initialize the command/FIB */
141935863739SMike Smith 	cm->cm_sgtable = NULL;
142035863739SMike Smith 	cm->cm_flags = 0;
142135863739SMike Smith 	cm->cm_complete = NULL;
142235863739SMike Smith 	cm->cm_private = NULL;
142335863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
142435863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
142535863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
14267cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
142735863739SMike Smith 
142835863739SMike Smith 	/*
142935863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
143035863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
14314109ba51SEd Maste 	 * initialized here for debugging purposes only.
143235863739SMike Smith 	 */
1433f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1434f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
143535863739SMike Smith 
143635863739SMike Smith 	aac_enqueue_free(cm);
14377cb209f5SScott Long 
1438eb5cbaa0SEd Maste 	/*
1439eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1440eb5cbaa0SEd Maste 	 * stranded.
1441eb5cbaa0SEd Maste 	 */
1442eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
14437cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
14447cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
14457cb209f5SScott Long 	}
144635863739SMike Smith }
144735863739SMike Smith 
1448914da7d0SScott Long /*
14490b94a66eSMike Smith  * Map helper for command/FIB allocation.
145035863739SMike Smith  */
145135863739SMike Smith static void
14520b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
145335863739SMike Smith {
14547cb209f5SScott Long 	uint64_t	*fibphys;
1455914da7d0SScott Long 
14567cb209f5SScott Long 	fibphys = (uint64_t *)arg;
145735863739SMike Smith 
1458ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
145935863739SMike Smith }
146035863739SMike Smith 
1461914da7d0SScott Long /*
14624109ba51SEd Maste  * Allocate and initialize commands/FIBs for this adapter.
146335863739SMike Smith  */
14640b94a66eSMike Smith static int
14650b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
146635863739SMike Smith {
146735863739SMike Smith 	struct aac_command *cm;
1468ffb37f33SScott Long 	struct aac_fibmap *fm;
14697cb209f5SScott Long 	uint64_t fibphys;
1470ffb37f33SScott Long 	int i, error;
147135863739SMike Smith 
147231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
147335863739SMike Smith 
14747cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1475ffb37f33SScott Long 		return (ENOMEM);
1476ffb37f33SScott Long 
14778480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1478a6d35632SScott Long 	if (fm == NULL)
1479a6d35632SScott Long 		return (ENOMEM);
1480ffb37f33SScott Long 
14810b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1482ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1483ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
148470545d1aSScott Long 		device_printf(sc->aac_dev,
148570545d1aSScott Long 			      "Not enough contiguous memory available.\n");
14868480cc63SScott Long 		free(fm, M_AACBUF);
14870b94a66eSMike Smith 		return (ENOMEM);
148835863739SMike Smith 	}
1489128aa5a0SScott Long 
1490cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1491cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
14927cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1493ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1494128aa5a0SScott Long 
14954109ba51SEd Maste 	/* initialize constant fields in the command structure */
14967cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
14977cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
14988480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1499ffb37f33SScott Long 		fm->aac_commands = cm;
150035863739SMike Smith 		cm->cm_sc = sc;
15017cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
15027cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
15037cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1504cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
150535863739SMike Smith 
1506ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
150793cfca22SScott Long 					       &cm->cm_datamap)) != 0)
15088480cc63SScott Long 			break;
150993cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
151093cfca22SScott Long 		aac_release_command(cm);
15118480cc63SScott Long 		sc->total_fibs++;
151293cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
151335863739SMike Smith 	}
1514ffb37f33SScott Long 
15158480cc63SScott Long 	if (i > 0) {
151693cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1517ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
151831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1519bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
15200b94a66eSMike Smith 		return (0);
152135863739SMike Smith 	}
152235863739SMike Smith 
15238480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
15248480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15258480cc63SScott Long 	free(fm, M_AACBUF);
15268480cc63SScott Long 	return (ENOMEM);
15278480cc63SScott Long }
15288480cc63SScott Long 
1529914da7d0SScott Long /*
15300b94a66eSMike Smith  * Free FIBs owned by this adapter.
153135863739SMike Smith  */
153235863739SMike Smith static void
15338480cc63SScott Long aac_free_commands(struct aac_softc *sc)
153435863739SMike Smith {
15358480cc63SScott Long 	struct aac_fibmap *fm;
1536ffb37f33SScott Long 	struct aac_command *cm;
153735863739SMike Smith 	int i;
153835863739SMike Smith 
153931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
154035863739SMike Smith 
15418480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
15428480cc63SScott Long 
15438480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
15448480cc63SScott Long 		/*
15458480cc63SScott Long 		 * We check against total_fibs to handle partially
15468480cc63SScott Long 		 * allocated blocks.
15478480cc63SScott Long 		 */
15487cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1549ffb37f33SScott Long 			cm = fm->aac_commands + i;
1550ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1551ffb37f33SScott Long 		}
1552ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1553ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15548480cc63SScott Long 		free(fm, M_AACBUF);
15558480cc63SScott Long 	}
155635863739SMike Smith }
155735863739SMike Smith 
1558914da7d0SScott Long /*
155935863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
156035863739SMike Smith  */
156135863739SMike Smith static void
156235863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
156335863739SMike Smith {
1564cd481291SScott Long 	struct aac_softc *sc;
1565914da7d0SScott Long 	struct aac_command *cm;
1566914da7d0SScott Long 	struct aac_fib *fib;
156735863739SMike Smith 	int i;
156835863739SMike Smith 
1569914da7d0SScott Long 	cm = (struct aac_command *)arg;
1570cd481291SScott Long 	sc = cm->cm_sc;
1571914da7d0SScott Long 	fib = cm->cm_fib;
157231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1573914da7d0SScott Long 
157435863739SMike Smith 	/* copy into the FIB */
1575b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
15767cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
15777cb209f5SScott Long 			struct aac_sg_tableraw *sg;
15787cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
15797cb209f5SScott Long 			sg->SgCount = nseg;
15807cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
15817cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
15827cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
15837cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
15847cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
15857cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
15867cb209f5SScott Long 			}
15877cb209f5SScott Long 			/* update the FIB size for the s/g count */
15887cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
15897cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1590b85f5808SScott Long 			struct aac_sg_table *sg;
1591b85f5808SScott Long 			sg = cm->cm_sgtable;
159235863739SMike Smith 			sg->SgCount = nseg;
159335863739SMike Smith 			for (i = 0; i < nseg; i++) {
159435863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
159535863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
159635863739SMike Smith 			}
159735863739SMike Smith 			/* update the FIB size for the s/g count */
159835863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1599b85f5808SScott Long 		} else {
1600b85f5808SScott Long 			struct aac_sg_table64 *sg;
1601b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1602b85f5808SScott Long 			sg->SgCount = nseg;
1603b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1604b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1605b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
160635863739SMike Smith 			}
1607b85f5808SScott Long 			/* update the FIB size for the s/g count */
1608b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1609b85f5808SScott Long 		}
1610b85f5808SScott Long 	}
161135863739SMike Smith 
1612cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1613cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
16147cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
16157cb209f5SScott Long 	 * and for the AIF bit
161635863739SMike Smith 	 */
16177cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
16187cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
161935863739SMike Smith 
1620cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1621cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
162235863739SMike Smith 
162335863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1624c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1625c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
162635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1627c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1628c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
162935863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1630cd481291SScott Long 
16317cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
16327cb209f5SScott Long 		int count = 10000000L;
16337cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
16347cb209f5SScott Long 			if (--count == 0) {
16357cb209f5SScott Long 				aac_unmap_command(cm);
16367cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
16377cb209f5SScott Long 				aac_requeue_ready(cm);
16387cb209f5SScott Long 			}
16397cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
16407cb209f5SScott Long 		}
16417cb209f5SScott Long 	} else {
1642397fa34fSScott Long 		/* Put the FIB on the outbound queue */
16434102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
16444102d44bSScott Long 			aac_unmap_command(cm);
1645397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1646cd481291SScott Long 			aac_requeue_ready(cm);
16474102d44bSScott Long 		}
16487cb209f5SScott Long 	}
1649cd481291SScott Long 
1650cd481291SScott Long 	return;
165135863739SMike Smith }
165235863739SMike Smith 
1653914da7d0SScott Long /*
165435863739SMike Smith  * Unmap a command from controller-visible space.
165535863739SMike Smith  */
165635863739SMike Smith static void
165735863739SMike Smith aac_unmap_command(struct aac_command *cm)
165835863739SMike Smith {
1659914da7d0SScott Long 	struct aac_softc *sc;
166035863739SMike Smith 
1661914da7d0SScott Long 	sc = cm->cm_sc;
166231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1663914da7d0SScott Long 
166435863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
166535863739SMike Smith 		return;
166635863739SMike Smith 
166735863739SMike Smith 	if (cm->cm_datalen != 0) {
166835863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1669c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1670c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
167135863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1672c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1673c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
167435863739SMike Smith 
167535863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
167635863739SMike Smith 	}
167735863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
167835863739SMike Smith }
167935863739SMike Smith 
1680914da7d0SScott Long /*
1681914da7d0SScott Long  * Hardware Interface
1682914da7d0SScott Long  */
168335863739SMike Smith 
1684914da7d0SScott Long /*
16854109ba51SEd Maste  * Initialize the adapter.
168635863739SMike Smith  */
168735863739SMike Smith static void
168835863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
168935863739SMike Smith {
1690914da7d0SScott Long 	struct aac_softc *sc;
169135863739SMike Smith 
1692914da7d0SScott Long 	sc = (struct aac_softc *)arg;
169331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1694914da7d0SScott Long 
169535863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
169635863739SMike Smith }
169735863739SMike Smith 
1698a6d35632SScott Long static int
1699a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1700a6d35632SScott Long {
170104f4d586SEd Maste 	u_int32_t code, major, minor, options = 0, atu_size = 0;
1702a441b3fcSScott Long 	int status;
170304f4d586SEd Maste 	time_t then;
1704a6d35632SScott Long 
170531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
170604f4d586SEd Maste 	/*
170704f4d586SEd Maste 	 * Wait for the adapter to come ready.
170804f4d586SEd Maste 	 */
170904f4d586SEd Maste 	then = time_uptime;
171004f4d586SEd Maste 	do {
171104f4d586SEd Maste 		code = AAC_GET_FWSTATUS(sc);
171204f4d586SEd Maste 		if (code & AAC_SELF_TEST_FAILED) {
171304f4d586SEd Maste 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
171404f4d586SEd Maste 			return(ENXIO);
171504f4d586SEd Maste 		}
171604f4d586SEd Maste 		if (code & AAC_KERNEL_PANIC) {
171704f4d586SEd Maste 			device_printf(sc->aac_dev,
1718a620bad0SEd Maste 				      "FATAL: controller kernel panic");
171904f4d586SEd Maste 			return(ENXIO);
172004f4d586SEd Maste 		}
172104f4d586SEd Maste 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
172204f4d586SEd Maste 			device_printf(sc->aac_dev,
172304f4d586SEd Maste 				      "FATAL: controller not coming ready, "
172404f4d586SEd Maste 					   "status %x\n", code);
172504f4d586SEd Maste 			return(ENXIO);
172604f4d586SEd Maste 		}
172704f4d586SEd Maste 	} while (!(code & AAC_UP_AND_RUNNING));
1728a6d35632SScott Long 
1729fe94b852SScott Long 	/*
1730fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1731fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1732fe94b852SScott Long 	 */
1733a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1734fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1735fe94b852SScott Long 				     NULL)) {
1736fe94b852SScott Long 			device_printf(sc->aac_dev,
1737fe94b852SScott Long 				      "Error reading firmware version\n");
1738fe94b852SScott Long 			return (EIO);
1739fe94b852SScott Long 		}
1740fe94b852SScott Long 
1741fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1742a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1743a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1744fe94b852SScott Long 		if (major == 1) {
1745fe94b852SScott Long 			device_printf(sc->aac_dev,
1746fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1747fe94b852SScott Long 			    major, minor);
1748fe94b852SScott Long 			return (EINVAL);
1749fe94b852SScott Long 		}
1750fe94b852SScott Long 	}
1751fe94b852SScott Long 
1752a6d35632SScott Long 	/*
1753a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1754a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1755a441b3fcSScott Long 	 * command.
1756a6d35632SScott Long 	 */
1757a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1758a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1759a441b3fcSScott Long 			device_printf(sc->aac_dev,
1760a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1761a6d35632SScott Long 			return (EIO);
1762a6d35632SScott Long 		}
1763a441b3fcSScott Long 	} else {
1764a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
17657cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1766a6d35632SScott Long 		sc->supported_options = options;
1767a6d35632SScott Long 
1768a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1769a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1770a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1771a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1772a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1773cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1774cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1775a441b3fcSScott Long 			device_printf(sc->aac_dev,
1776a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1777a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1778a6d35632SScott Long 		}
1779a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1780a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
17817cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
17827cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
17837cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1784a441b3fcSScott Long 	}
1785a6d35632SScott Long 
1786a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
17877cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
17887cb209f5SScott Long 
17897cb209f5SScott Long 	/* Remap mem. resource, if required */
17907cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1791ff0991c4SAttilio Rao 		atu_size > rman_get_size(sc->aac_regs_res1)) {
17927cb209f5SScott Long 		bus_release_resource(
17937cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
1794ff0991c4SAttilio Rao 			sc->aac_regs_rid1, sc->aac_regs_res1);
1795ff0991c4SAttilio Rao 		sc->aac_regs_res1 = bus_alloc_resource(
1796ff0991c4SAttilio Rao 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1,
17977cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
1798ff0991c4SAttilio Rao 		if (sc->aac_regs_res1 == NULL) {
1799ff0991c4SAttilio Rao 			sc->aac_regs_res1 = bus_alloc_resource_any(
18007cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
1801ff0991c4SAttilio Rao 				&sc->aac_regs_rid1, RF_ACTIVE);
1802ff0991c4SAttilio Rao 			if (sc->aac_regs_res1 == NULL) {
18037cb209f5SScott Long 				device_printf(sc->aac_dev,
18047cb209f5SScott Long 				    "couldn't allocate register window\n");
18057cb209f5SScott Long 				return (ENXIO);
18067cb209f5SScott Long 			}
18077cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
18087cb209f5SScott Long 		}
1809ff0991c4SAttilio Rao 		sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1);
1810ff0991c4SAttilio Rao 		sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1);
1811ff0991c4SAttilio Rao 
1812ff0991c4SAttilio Rao 		if (sc->aac_hwif == AAC_HWIF_NARK) {
1813ff0991c4SAttilio Rao 			sc->aac_regs_res0 = sc->aac_regs_res1;
1814ff0991c4SAttilio Rao 			sc->aac_regs_rid0 = sc->aac_regs_rid1;
1815ff0991c4SAttilio Rao 			sc->aac_btag0 = sc->aac_btag1;
1816ff0991c4SAttilio Rao 			sc->aac_bhandle0 = sc->aac_bhandle1;
1817ff0991c4SAttilio Rao 		}
18187cb209f5SScott Long 	}
18197cb209f5SScott Long 
18207cb209f5SScott Long 	/* Read preferred settings */
18217cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
18227cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
18237cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1824a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18257e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
18267e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1827a6d35632SScott Long 	else
1828a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
18297e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
18307e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1831a441b3fcSScott Long 
18327cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
18337cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
18347cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
18357cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
18367cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
18377cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
18387cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
18397cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
18407cb209f5SScott Long 	}
18417cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
18427cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
18437cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1844a6d35632SScott Long 
1845f355c0e0SEd Maste 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1846f355c0e0SEd Maste 		sc->flags |= AAC_FLAGS_RAW_IO;
1847f355c0e0SEd Maste 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1848f355c0e0SEd Maste 	}
1849523da39bSEd Maste 	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1850523da39bSEd Maste 	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1851523da39bSEd Maste 		sc->flags |= AAC_FLAGS_LBA_64BIT;
1852523da39bSEd Maste 		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1853523da39bSEd Maste 	}
1854f355c0e0SEd Maste 
1855fe94b852SScott Long 	return (0);
1856fe94b852SScott Long }
1857fe94b852SScott Long 
185835863739SMike Smith static int
185935863739SMike Smith aac_init(struct aac_softc *sc)
186035863739SMike Smith {
186135863739SMike Smith 	struct aac_adapter_init	*ip;
186204f4d586SEd Maste 	u_int32_t qoffset;
1863a6d35632SScott Long 	int error;
186435863739SMike Smith 
186531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1866ffb37f33SScott Long 
186735863739SMike Smith 	/*
1868914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1869914da7d0SScott Long 	 * physical location of various important shared data structures.
187035863739SMike Smith 	 */
187135863739SMike Smith 	ip = &sc->aac_common->ac_init;
187235863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18737cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18747cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18757cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18767cb209f5SScott Long 	}
1877f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
187835863739SMike Smith 
1879c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1880c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1881149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
188235863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
188335863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
188435863739SMike Smith 
1885c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1886c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
188735863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
188835863739SMike Smith 
18894b00f859SScott Long 	/*
18904b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18914b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18924b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18934b00f859SScott Long 	 * Round up since the granularity is so high.
18944b00f859SScott Long 	 */
1895f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18964b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18974b00f859SScott Long 		ip->HostPhysMemPages =
18984b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1899204c0befSScott Long 	}
19002b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
190135863739SMike Smith 
19027cb209f5SScott Long 	ip->InitFlags = 0;
19037cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
19047cb209f5SScott Long 		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
19057cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
19067cb209f5SScott Long 	}
19077cb209f5SScott Long 
19087cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
19097cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
19107cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
19117cb209f5SScott Long 
191235863739SMike Smith 	/*
19134109ba51SEd Maste 	 * Initialize FIB queues.  Note that it appears that the layout of the
1914c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1915c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
191635863739SMike Smith 	 *
191735863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1918914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1919914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1920914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1921914da7d0SScott Long 	 * does.
192235863739SMike Smith 	 *
1923914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1924914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1925914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1926914da7d0SScott Long 	 * virtue of a table.
192735863739SMike Smith 	 */
1928b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
19290bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
19300bcbebd6SScott Long 	sc->aac_queues =
19310bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1932b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
193335863739SMike Smith 
1934c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1935c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1936c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1937c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1938c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1939c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1940c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1941c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1942c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1943c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1944c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1945c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1946c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1947c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1948c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1949c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1950c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1951c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1952c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1953c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1954c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1955c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1956c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1957c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1958c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1959c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1960c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1961c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1962c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1963c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1964c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1965c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1966c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1967c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1968c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1969c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1970c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1971c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1972c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1973c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1974c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1975c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1976c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1977c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1978c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1979c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1980c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1981c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
198235863739SMike Smith 
198335863739SMike Smith 	/*
198435863739SMike Smith 	 * Do controller-type-specific initialisation
198535863739SMike Smith 	 */
198635863739SMike Smith 	switch (sc->aac_hwif) {
198735863739SMike Smith 	case AAC_HWIF_I960RX:
1988ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0);
198935863739SMike Smith 		break;
19904afedc31SScott Long 	case AAC_HWIF_RKT:
1991ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0);
19924afedc31SScott Long 		break;
19934afedc31SScott Long 	default:
19944afedc31SScott Long 		break;
199535863739SMike Smith 	}
199635863739SMike Smith 
199735863739SMike Smith 	/*
199835863739SMike Smith 	 * Give the init structure to the controller.
199935863739SMike Smith 	 */
200035863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
2001914da7d0SScott Long 			     sc->aac_common_busaddr +
2002914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
2003914da7d0SScott Long 			     NULL)) {
2004914da7d0SScott Long 		device_printf(sc->aac_dev,
2005914da7d0SScott Long 			      "error establishing init structure\n");
2006a6d35632SScott Long 		error = EIO;
2007a6d35632SScott Long 		goto out;
200835863739SMike Smith 	}
200935863739SMike Smith 
2010a6d35632SScott Long 	error = 0;
2011a6d35632SScott Long out:
2012a6d35632SScott Long 	return(error);
201335863739SMike Smith }
201435863739SMike Smith 
201504f4d586SEd Maste static int
201604f4d586SEd Maste aac_setup_intr(struct aac_softc *sc)
201704f4d586SEd Maste {
201804f4d586SEd Maste 	sc->aac_irq_rid = 0;
201904f4d586SEd Maste 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
202004f4d586SEd Maste 			   			  &sc->aac_irq_rid,
202104f4d586SEd Maste 			   			  RF_SHAREABLE |
202204f4d586SEd Maste 						  RF_ACTIVE)) == NULL) {
202304f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
202404f4d586SEd Maste 		return (EINVAL);
202504f4d586SEd Maste 	}
202604f4d586SEd Maste 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
202704f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
202804f4d586SEd Maste 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
202904f4d586SEd Maste 				   aac_new_intr, sc, &sc->aac_intr)) {
203004f4d586SEd Maste 			device_printf(sc->aac_dev, "can't set up interrupt\n");
203104f4d586SEd Maste 			return (EINVAL);
203204f4d586SEd Maste 		}
203304f4d586SEd Maste 	} else {
203404f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
203504f4d586SEd Maste 				   INTR_TYPE_BIO, aac_fast_intr, NULL,
203604f4d586SEd Maste 				   sc, &sc->aac_intr)) {
203704f4d586SEd Maste 			device_printf(sc->aac_dev,
203804f4d586SEd Maste 				      "can't set up FAST interrupt\n");
203904f4d586SEd Maste 			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
204004f4d586SEd Maste 					   INTR_MPSAFE|INTR_TYPE_BIO,
204104f4d586SEd Maste 					   NULL, (driver_intr_t *)aac_fast_intr,
204204f4d586SEd Maste 					   sc, &sc->aac_intr)) {
204304f4d586SEd Maste 				device_printf(sc->aac_dev,
204404f4d586SEd Maste 					     "can't set up MPSAFE interrupt\n");
204504f4d586SEd Maste 				return (EINVAL);
204604f4d586SEd Maste 			}
204704f4d586SEd Maste 		}
204804f4d586SEd Maste 	}
204904f4d586SEd Maste 	return (0);
205004f4d586SEd Maste }
205104f4d586SEd Maste 
2052914da7d0SScott Long /*
205335863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
20547cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
205535863739SMike Smith  */
205635863739SMike Smith static int
205735863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
205835863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
205935863739SMike Smith 		 u_int32_t *sp)
206035863739SMike Smith {
206135863739SMike Smith 	time_t then;
206235863739SMike Smith 	u_int32_t status;
206335863739SMike Smith 
206431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
206535863739SMike Smith 
206635863739SMike Smith 	/* populate the mailbox */
206735863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
206835863739SMike Smith 
206935863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
207035863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
207135863739SMike Smith 
207235863739SMike Smith 	/* then set it to signal the adapter */
207335863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
207435863739SMike Smith 
207535863739SMike Smith 	/* spin waiting for the command to complete */
20762b3b0f17SScott Long 	then = time_uptime;
207735863739SMike Smith 	do {
20782b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
207931a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
208035863739SMike Smith 			return(EIO);
208135863739SMike Smith 		}
208235863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
208335863739SMike Smith 
208435863739SMike Smith 	/* clear the completion flag */
208535863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
208635863739SMike Smith 
208735863739SMike Smith 	/* get the command status */
2088a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
208935863739SMike Smith 	if (sp != NULL)
209035863739SMike Smith 		*sp = status;
20917cb209f5SScott Long 
2092a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20937cb209f5SScott Long 		return (-1);
20940b94a66eSMike Smith 	return(0);
209535863739SMike Smith }
209635863739SMike Smith 
2097cbfd045bSScott Long int
209835863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2099cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
210035863739SMike Smith {
210131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
21027cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
210335863739SMike Smith 
210435863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
210535863739SMike Smith 		return(EINVAL);
210635863739SMike Smith 
210735863739SMike Smith 	/*
210835863739SMike Smith 	 * Set up the sync FIB
210935863739SMike Smith 	 */
2110914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2111914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2112c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
211335863739SMike Smith 	fib->Header.XferState |= xferstate;
211435863739SMike Smith 	fib->Header.Command = command;
211535863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
211642ef13a2SEd Maste 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
211735863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2118b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2119c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2120914da7d0SScott Long 					 offsetof(struct aac_common,
2121914da7d0SScott Long 						  ac_sync_fib);
212235863739SMike Smith 
212335863739SMike Smith 	/*
212435863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
212535863739SMike Smith 	 */
2126914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2127914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
212831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
212935863739SMike Smith 		return(EIO);
213035863739SMike Smith 	}
213135863739SMike Smith 
213235863739SMike Smith 	return (0);
213335863739SMike Smith }
213435863739SMike Smith 
2135914da7d0SScott Long /*
213635863739SMike Smith  * Adapter-space FIB queue manipulation
213735863739SMike Smith  *
213835863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
213935863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
214035863739SMike Smith  */
214135863739SMike Smith static struct {
214235863739SMike Smith 	int		size;
214335863739SMike Smith 	int		notify;
214435863739SMike Smith } aac_qinfo[] = {
214535863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
214635863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
214735863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
214835863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
214935863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
215035863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
215135863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
215235863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
215335863739SMike Smith };
215435863739SMike Smith 
215535863739SMike Smith /*
2156c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2157c6eafcf2SScott Long  * EBUSY if the queue is full.
215835863739SMike Smith  *
21590b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2160914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2161914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2162c6eafcf2SScott Long  *	 separate queue/notify interface).
216335863739SMike Smith  */
216435863739SMike Smith static int
2165f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
216635863739SMike Smith {
216735863739SMike Smith 	u_int32_t pi, ci;
21689e2e96d8SScott Long 	int error;
2169f6c4dd3fSScott Long 	u_int32_t fib_size;
2170f6c4dd3fSScott Long 	u_int32_t fib_addr;
2171f6c4dd3fSScott Long 
217231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
217336e0bf6eSScott Long 
2174f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2175f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
217635863739SMike Smith 
217735863739SMike Smith 	/* get the producer/consumer indices */
217835863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
217935863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
218035863739SMike Smith 
218135863739SMike Smith 	/* wrap the queue? */
218235863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
218335863739SMike Smith 		pi = 0;
218435863739SMike Smith 
218535863739SMike Smith 	/* check for queue full */
218635863739SMike Smith 	if ((pi + 1) == ci) {
218735863739SMike Smith 		error = EBUSY;
218835863739SMike Smith 		goto out;
218935863739SMike Smith 	}
219035863739SMike Smith 
2191614c22b2SScott Long 	/*
2192614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2193614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2194614c22b2SScott Long 	 */
2195614c22b2SScott Long 	aac_enqueue_busy(cm);
2196614c22b2SScott Long 
219735863739SMike Smith 	/* populate queue entry */
219835863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
219935863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
220035863739SMike Smith 
220135863739SMike Smith 	/* update producer index */
220235863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
220335863739SMike Smith 
220435863739SMike Smith 	/* notify the adapter if we know how */
220535863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
220635863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
220735863739SMike Smith 
220835863739SMike Smith 	error = 0;
220935863739SMike Smith 
221035863739SMike Smith out:
221135863739SMike Smith 	return(error);
221235863739SMike Smith }
221335863739SMike Smith 
221435863739SMike Smith /*
221536e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
221636e0bf6eSScott Long  * success or ENOENT if the queue is empty.
221735863739SMike Smith  */
221835863739SMike Smith static int
2219c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2220c6eafcf2SScott Long 		struct aac_fib **fib_addr)
222135863739SMike Smith {
222235863739SMike Smith 	u_int32_t pi, ci;
2223149af931SScott Long 	u_int32_t fib_index;
22249e2e96d8SScott Long 	int error;
2225f6c4dd3fSScott Long 	int notify;
222635863739SMike Smith 
222731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
222835863739SMike Smith 
222935863739SMike Smith 	/* get the producer/consumer indices */
223035863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
223135863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
223235863739SMike Smith 
223335863739SMike Smith 	/* check for queue empty */
223435863739SMike Smith 	if (ci == pi) {
223535863739SMike Smith 		error = ENOENT;
223635863739SMike Smith 		goto out;
223735863739SMike Smith 	}
223835863739SMike Smith 
22397753acd2SScott Long 	/* wrap the pi so the following test works */
22407753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
22417753acd2SScott Long 		pi = 0;
22427753acd2SScott Long 
2243f6c4dd3fSScott Long 	notify = 0;
2244f6c4dd3fSScott Long 	if (ci == pi + 1)
2245f6c4dd3fSScott Long 		notify++;
2246f6c4dd3fSScott Long 
224735863739SMike Smith 	/* wrap the queue? */
224835863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
224935863739SMike Smith 		ci = 0;
225035863739SMike Smith 
225135863739SMike Smith 	/* fetch the entry */
225235863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2253149af931SScott Long 
2254149af931SScott Long 	switch (queue) {
2255149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2256149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2257149af931SScott Long 		/*
2258149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2259149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2260149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2261149af931SScott Long 		 * Therefore, we have to convert it to an index.
2262149af931SScott Long 		 */
2263149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2264149af931SScott Long 			sizeof(struct aac_fib);
2265149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2266149af931SScott Long 		break;
2267149af931SScott Long 
2268149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2269149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2270149af931SScott Long 	{
2271149af931SScott Long 		struct aac_command *cm;
2272149af931SScott Long 
2273149af931SScott Long 		/*
2274149af931SScott Long 		 * As above, an index is used instead of an actual address.
2275149af931SScott Long 		 * Gotta shift the index to account for the fast response
2276149af931SScott Long 		 * bit.  No other correction is needed since this value was
2277149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2278149af931SScott Long 		 * field.
2279149af931SScott Long 		 */
2280149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22817cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2282149af931SScott Long 		*fib_addr = cm->cm_fib;
228335863739SMike Smith 
2284f30ac74cSScott Long 		/*
2285f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2286149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2287f30ac74cSScott Long 		 */
2288149af931SScott Long 		if (fib_index & 0x01) {
2289f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2290f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2291f30ac74cSScott Long 		}
2292149af931SScott Long 		break;
2293149af931SScott Long 	}
2294149af931SScott Long 	default:
2295149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2296149af931SScott Long 		break;
2297149af931SScott Long 	}
2298149af931SScott Long 
229935863739SMike Smith 	/* update consumer index */
230035863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
230135863739SMike Smith 
230235863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2303f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
230435863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
230535863739SMike Smith 	error = 0;
230635863739SMike Smith 
230735863739SMike Smith out:
230835863739SMike Smith 	return(error);
230935863739SMike Smith }
231035863739SMike Smith 
2311914da7d0SScott Long /*
231236e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
231336e0bf6eSScott Long  */
231436e0bf6eSScott Long static int
231536e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
231636e0bf6eSScott Long {
231736e0bf6eSScott Long 	u_int32_t pi, ci;
23189e2e96d8SScott Long 	int error;
231936e0bf6eSScott Long 	u_int32_t fib_size;
232036e0bf6eSScott Long 	u_int32_t fib_addr;
232136e0bf6eSScott Long 
232231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
232336e0bf6eSScott Long 
232436e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
232536e0bf6eSScott Long 	fib_size = fib->Header.Size;
232636e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
232736e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
232836e0bf6eSScott Long 
232936e0bf6eSScott Long 	/* get the producer/consumer indices */
233036e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
233136e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
233236e0bf6eSScott Long 
233336e0bf6eSScott Long 	/* wrap the queue? */
233436e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
233536e0bf6eSScott Long 		pi = 0;
233636e0bf6eSScott Long 
233736e0bf6eSScott Long 	/* check for queue full */
233836e0bf6eSScott Long 	if ((pi + 1) == ci) {
233936e0bf6eSScott Long 		error = EBUSY;
234036e0bf6eSScott Long 		goto out;
234136e0bf6eSScott Long 	}
234236e0bf6eSScott Long 
234336e0bf6eSScott Long 	/* populate queue entry */
234436e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
234536e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
234636e0bf6eSScott Long 
234736e0bf6eSScott Long 	/* update producer index */
234836e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
234936e0bf6eSScott Long 
235036e0bf6eSScott Long 	/* notify the adapter if we know how */
235136e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
235236e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
235336e0bf6eSScott Long 
235436e0bf6eSScott Long 	error = 0;
235536e0bf6eSScott Long 
235636e0bf6eSScott Long out:
235736e0bf6eSScott Long 	return(error);
235836e0bf6eSScott Long }
235936e0bf6eSScott Long 
2360914da7d0SScott Long /*
23610b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
23620b94a66eSMike Smith  * and complain about them.
23630b94a66eSMike Smith  */
23640b94a66eSMike Smith static void
23650b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
23660b94a66eSMike Smith {
23670b94a66eSMike Smith 	struct aac_command *cm;
23680b94a66eSMike Smith 	time_t deadline;
236915c37be0SScott Long 	int timedout, code;
23700b94a66eSMike Smith 
2371f6c4dd3fSScott Long 	/*
237270545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2373914da7d0SScott Long 	 * only.
2374914da7d0SScott Long 	 */
237515c37be0SScott Long 	timedout = 0;
23762b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23770b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2378f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2379f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
23800b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2381914da7d0SScott Long 			device_printf(sc->aac_dev,
2382914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
23832b3b0f17SScott Long 				      cm, (int)(time_uptime-cm->cm_timestamp));
23840b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
238515c37be0SScott Long 			timedout++;
23860b94a66eSMike Smith 		}
23870b94a66eSMike Smith 	}
23880b94a66eSMike Smith 
238915c37be0SScott Long 	if (timedout) {
239015c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
239115c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
239215c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
239315c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
239415c37be0SScott Long 		}
239515c37be0SScott Long 	}
23960b94a66eSMike Smith 	return;
23970b94a66eSMike Smith }
23980b94a66eSMike Smith 
2399914da7d0SScott Long /*
2400914da7d0SScott Long  * Interface Function Vectors
2401914da7d0SScott Long  */
240235863739SMike Smith 
2403914da7d0SScott Long /*
240435863739SMike Smith  * Read the current firmware status word.
240535863739SMike Smith  */
240635863739SMike Smith static int
240735863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
240835863739SMike Smith {
240931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241035863739SMike Smith 
2411ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS));
241235863739SMike Smith }
241335863739SMike Smith 
241435863739SMike Smith static int
241535863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
241635863739SMike Smith {
241731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241835863739SMike Smith 
24194824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
24204824be88SEd Maste 	    AAC_RX_OMR0 : AAC_RX_FWSTATUS));
242135863739SMike Smith }
242235863739SMike Smith 
2423b3457b51SScott Long static int
2424b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2425b3457b51SScott Long {
2426b3457b51SScott Long 	int val;
2427b3457b51SScott Long 
242831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2429b3457b51SScott Long 
2430ff0991c4SAttilio Rao 	val = AAC_MEM0_GETREG4(sc, AAC_FA_FWSTATUS);
2431b3457b51SScott Long 	return (val);
2432b3457b51SScott Long }
2433b3457b51SScott Long 
24344afedc31SScott Long static int
24354afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
24364afedc31SScott Long {
243731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24384afedc31SScott Long 
24394824be88SEd Maste 	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
24404824be88SEd Maste 	    AAC_RKT_OMR0 : AAC_RKT_FWSTATUS));
24414afedc31SScott Long }
24424afedc31SScott Long 
2443914da7d0SScott Long /*
244435863739SMike Smith  * Notify the controller of a change in a given queue
244535863739SMike Smith  */
244635863739SMike Smith 
244735863739SMike Smith static void
244835863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
244935863739SMike Smith {
245031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
245135863739SMike Smith 
2452ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
245335863739SMike Smith }
245435863739SMike Smith 
245535863739SMike Smith static void
245635863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
245735863739SMike Smith {
245831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
245935863739SMike Smith 
2460ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit);
246135863739SMike Smith }
246235863739SMike Smith 
2463b3457b51SScott Long static void
2464b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2465b3457b51SScott Long {
246631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2467b3457b51SScott Long 
2468ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2469b3457b51SScott Long 	AAC_FA_HACK(sc);
2470b3457b51SScott Long }
2471b3457b51SScott Long 
24724afedc31SScott Long static void
24734afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
24744afedc31SScott Long {
247531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24764afedc31SScott Long 
2477ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit);
24784afedc31SScott Long }
24794afedc31SScott Long 
2480914da7d0SScott Long /*
248135863739SMike Smith  * Get the interrupt reason bits
248235863739SMike Smith  */
248335863739SMike Smith static int
248435863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
248535863739SMike Smith {
248631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
248735863739SMike Smith 
2488ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0));
248935863739SMike Smith }
249035863739SMike Smith 
249135863739SMike Smith static int
249235863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
249335863739SMike Smith {
249431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
249535863739SMike Smith 
2496ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR));
249735863739SMike Smith }
249835863739SMike Smith 
2499b3457b51SScott Long static int
2500b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2501b3457b51SScott Long {
2502b3457b51SScott Long 	int val;
2503b3457b51SScott Long 
250431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2505b3457b51SScott Long 
2506ff0991c4SAttilio Rao 	val = AAC_MEM0_GETREG2(sc, AAC_FA_DOORBELL0);
2507b3457b51SScott Long 	return (val);
2508b3457b51SScott Long }
2509b3457b51SScott Long 
25104afedc31SScott Long static int
25114afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
25124afedc31SScott Long {
251331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25144afedc31SScott Long 
2515ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR));
25164afedc31SScott Long }
25174afedc31SScott Long 
2518914da7d0SScott Long /*
251935863739SMike Smith  * Clear some interrupt reason bits
252035863739SMike Smith  */
252135863739SMike Smith static void
252235863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
252335863739SMike Smith {
252431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
252535863739SMike Smith 
2526ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
252735863739SMike Smith }
252835863739SMike Smith 
252935863739SMike Smith static void
253035863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
253135863739SMike Smith {
253231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
253335863739SMike Smith 
2534ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask);
253535863739SMike Smith }
253635863739SMike Smith 
2537b3457b51SScott Long static void
2538b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2539b3457b51SScott Long {
254031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2541b3457b51SScott Long 
2542ff0991c4SAttilio Rao 	AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2543b3457b51SScott Long 	AAC_FA_HACK(sc);
2544b3457b51SScott Long }
2545b3457b51SScott Long 
25464afedc31SScott Long static void
25474afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
25484afedc31SScott Long {
254931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25504afedc31SScott Long 
2551ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask);
25524afedc31SScott Long }
25534afedc31SScott Long 
2554914da7d0SScott Long /*
255535863739SMike Smith  * Populate the mailbox and set the command word
255635863739SMike Smith  */
255735863739SMike Smith static void
255835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
255935863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
256035863739SMike Smith {
256131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
256235863739SMike Smith 
2563ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command);
2564ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2565ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2566ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2567ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
256835863739SMike Smith }
256935863739SMike Smith 
257035863739SMike Smith static void
257135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
257235863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
257335863739SMike Smith {
257431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
257535863739SMike Smith 
2576ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command);
2577ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2578ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2579ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2580ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
258135863739SMike Smith }
258235863739SMike Smith 
2583b3457b51SScott Long static void
2584b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2585b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2586b3457b51SScott Long {
258731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2588b3457b51SScott Long 
2589ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX, command);
2590b3457b51SScott Long 	AAC_FA_HACK(sc);
2591ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2592b3457b51SScott Long 	AAC_FA_HACK(sc);
2593ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2594b3457b51SScott Long 	AAC_FA_HACK(sc);
2595ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2596b3457b51SScott Long 	AAC_FA_HACK(sc);
2597ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2598b3457b51SScott Long 	AAC_FA_HACK(sc);
2599b3457b51SScott Long }
2600b3457b51SScott Long 
26014afedc31SScott Long static void
26024afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
26034afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
26044afedc31SScott Long {
260531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26064afedc31SScott Long 
2607ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command);
2608ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2609ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2610ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2611ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
26124afedc31SScott Long }
26134afedc31SScott Long 
2614914da7d0SScott Long /*
261535863739SMike Smith  * Fetch the immediate command status word
261635863739SMike Smith  */
261735863739SMike Smith static int
2618a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
261935863739SMike Smith {
262031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
262135863739SMike Smith 
2622ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
262335863739SMike Smith }
262435863739SMike Smith 
262535863739SMike Smith static int
2626a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
262735863739SMike Smith {
262831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
262935863739SMike Smith 
2630ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
263135863739SMike Smith }
263235863739SMike Smith 
2633b3457b51SScott Long static int
2634a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2635b3457b51SScott Long {
2636b3457b51SScott Long 	int val;
2637b3457b51SScott Long 
263831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2639b3457b51SScott Long 
2640ff0991c4SAttilio Rao 	val = AAC_MEM1_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2641b3457b51SScott Long 	return (val);
2642b3457b51SScott Long }
2643b3457b51SScott Long 
26444afedc31SScott Long static int
26454afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
26464afedc31SScott Long {
264731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26484afedc31SScott Long 
2649ff0991c4SAttilio Rao 	return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
26504afedc31SScott Long }
26514afedc31SScott Long 
2652914da7d0SScott Long /*
265335863739SMike Smith  * Set/clear interrupt masks
265435863739SMike Smith  */
265535863739SMike Smith static void
265635863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
265735863739SMike Smith {
265831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
265935863739SMike Smith 
266035863739SMike Smith 	if (enable) {
2661ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
266235863739SMike Smith 	} else {
2663ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
266435863739SMike Smith 	}
266535863739SMike Smith }
266635863739SMike Smith 
266735863739SMike Smith static void
266835863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
266935863739SMike Smith {
267031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
267135863739SMike Smith 
267235863739SMike Smith 	if (enable) {
26737cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2674ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
26757cb209f5SScott Long 		else
2676ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
267735863739SMike Smith 	} else {
2678ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0);
267935863739SMike Smith 	}
268035863739SMike Smith }
268135863739SMike Smith 
2682b3457b51SScott Long static void
2683b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2684b3457b51SScott Long {
268531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2686b3457b51SScott Long 
2687b3457b51SScott Long 	if (enable) {
2688ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2689b3457b51SScott Long 		AAC_FA_HACK(sc);
2690b3457b51SScott Long 	} else {
2691ff0991c4SAttilio Rao 		AAC_MEM0_SETREG2((sc), AAC_FA_MASK0, ~0);
2692b3457b51SScott Long 		AAC_FA_HACK(sc);
2693b3457b51SScott Long 	}
2694b3457b51SScott Long }
2695b3457b51SScott Long 
26964afedc31SScott Long static void
26974afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
26984afedc31SScott Long {
269931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
27004afedc31SScott Long 
27014afedc31SScott Long 	if (enable) {
27027cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
2703ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
27047cb209f5SScott Long 		else
2705ff0991c4SAttilio Rao 			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
27064afedc31SScott Long 	} else {
2707ff0991c4SAttilio Rao 		AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0);
27084afedc31SScott Long 	}
27094afedc31SScott Long }
27104afedc31SScott Long 
2711914da7d0SScott Long /*
27127cb209f5SScott Long  * New comm. interface: Send command functions
27137cb209f5SScott Long  */
27147cb209f5SScott Long static int
27157cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
27167cb209f5SScott Long {
27177cb209f5SScott Long 	u_int32_t index, device;
27187cb209f5SScott Long 
271931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
27207cb209f5SScott Long 
2721ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
27227cb209f5SScott Long 	if (index == 0xffffffffL)
2723ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
27247cb209f5SScott Long 	if (index == 0xffffffffL)
27257cb209f5SScott Long 		return index;
27267cb209f5SScott Long 	aac_enqueue_busy(cm);
27277cb209f5SScott Long 	device = index;
2728ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
27297cb209f5SScott Long 	device += 4;
2730ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
27317cb209f5SScott Long 	device += 4;
2732ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2733ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index);
27347cb209f5SScott Long 	return 0;
27357cb209f5SScott Long }
27367cb209f5SScott Long 
27377cb209f5SScott Long static int
27387cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
27397cb209f5SScott Long {
27407cb209f5SScott Long 	u_int32_t index, device;
27417cb209f5SScott Long 
274231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
27437cb209f5SScott Long 
2744ff0991c4SAttilio Rao 	index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
27457cb209f5SScott Long 	if (index == 0xffffffffL)
2746ff0991c4SAttilio Rao 		index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
27477cb209f5SScott Long 	if (index == 0xffffffffL)
27487cb209f5SScott Long 		return index;
27497cb209f5SScott Long 	aac_enqueue_busy(cm);
27507cb209f5SScott Long 	device = index;
2751ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
27527cb209f5SScott Long 	device += 4;
2753ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
27547cb209f5SScott Long 	device += 4;
2755ff0991c4SAttilio Rao 	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2756ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index);
27577cb209f5SScott Long 	return 0;
27587cb209f5SScott Long }
27597cb209f5SScott Long 
27607cb209f5SScott Long /*
27617cb209f5SScott Long  * New comm. interface: get, set outbound queue index
27627cb209f5SScott Long  */
27637cb209f5SScott Long static int
27647cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
27657cb209f5SScott Long {
276631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27677cb209f5SScott Long 
2768ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE));
27697cb209f5SScott Long }
27707cb209f5SScott Long 
27717cb209f5SScott Long static int
27727cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
27737cb209f5SScott Long {
277431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27757cb209f5SScott Long 
2776ff0991c4SAttilio Rao 	return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE));
27777cb209f5SScott Long }
27787cb209f5SScott Long 
27797cb209f5SScott Long static void
27807cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
27817cb209f5SScott Long {
278231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27837cb209f5SScott Long 
2784ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index);
27857cb209f5SScott Long }
27867cb209f5SScott Long 
27877cb209f5SScott Long static void
27887cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
27897cb209f5SScott Long {
279031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27917cb209f5SScott Long 
2792ff0991c4SAttilio Rao 	AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index);
27937cb209f5SScott Long }
27947cb209f5SScott Long 
27957cb209f5SScott Long /*
2796914da7d0SScott Long  * Debugging and Diagnostics
2797914da7d0SScott Long  */
279835863739SMike Smith 
2799914da7d0SScott Long /*
280035863739SMike Smith  * Print some information about the controller.
280135863739SMike Smith  */
280235863739SMike Smith static void
280335863739SMike Smith aac_describe_controller(struct aac_softc *sc)
280435863739SMike Smith {
2805cbfd045bSScott Long 	struct aac_fib *fib;
280635863739SMike Smith 	struct aac_adapter_info	*info;
28077ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
280835863739SMike Smith 
280931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
281035863739SMike Smith 
281181b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
281203b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2813cbfd045bSScott Long 
2814cbfd045bSScott Long 	fib->data[0] = 0;
2815cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
281635863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2817fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
281881b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
281935863739SMike Smith 		return;
282035863739SMike Smith 	}
282135863739SMike Smith 
2822bd971c49SScott Long 	/* save the kernel revision structure for later use */
2823bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2824bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2825bd971c49SScott Long 
2826bd971c49SScott Long 	if (bootverbose) {
2827b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2828b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2829c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2830b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2831b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2832b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2833914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2834914da7d0SScott Long 		    info->batteryPlatform));
283535863739SMike Smith 
2836bd971c49SScott Long 		device_printf(sc->aac_dev,
2837bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
283835863739SMike Smith 		    info->KernelRevision.external.comp.major,
283935863739SMike Smith 		    info->KernelRevision.external.comp.minor,
284035863739SMike Smith 		    info->KernelRevision.external.comp.dash,
284136e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
284236e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2843fe3cb0e1SScott Long 
2844a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2845a6d35632SScott Long 			      sc->supported_options,
2846a6d35632SScott Long 			      "\20"
2847a6d35632SScott Long 			      "\1SNAPSHOT"
2848a6d35632SScott Long 			      "\2CLUSTERS"
2849a6d35632SScott Long 			      "\3WCACHE"
2850a6d35632SScott Long 			      "\4DATA64"
2851a6d35632SScott Long 			      "\5HOSTTIME"
2852a6d35632SScott Long 			      "\6RAID50"
2853a6d35632SScott Long 			      "\7WINDOW4GB"
2854a6d35632SScott Long 			      "\10SCSIUPGD"
2855a6d35632SScott Long 			      "\11SOFTERR"
2856a6d35632SScott Long 			      "\12NORECOND"
2857a6d35632SScott Long 			      "\13SGMAP64"
2858a6d35632SScott Long 			      "\14ALARM"
28597cb209f5SScott Long 			      "\15NONDASD"
28607cb209f5SScott Long 			      "\16SCSIMGT"
28617cb209f5SScott Long 			      "\17RAIDSCSI"
28627cb209f5SScott Long 			      "\21ADPTINFO"
28637cb209f5SScott Long 			      "\22NEWCOMM"
28647cb209f5SScott Long 			      "\23ARRAY64BIT"
28657cb209f5SScott Long 			      "\24HEATSENSOR");
2866a6d35632SScott Long 	}
286755aa1136SEd Maste 
286855aa1136SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
286955aa1136SEd Maste 		fib->data[0] = 0;
287055aa1136SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
287155aa1136SEd Maste 			device_printf(sc->aac_dev,
287255aa1136SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
287355aa1136SEd Maste 		else
287455aa1136SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
287555aa1136SEd Maste 			    &fib->data[0])->AdapterTypeText;
287655aa1136SEd Maste 	}
287755aa1136SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
287855aa1136SEd Maste 		adapter_type,
287955aa1136SEd Maste 		AAC_DRIVER_VERSION >> 24,
288055aa1136SEd Maste 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
288155aa1136SEd Maste 		AAC_DRIVER_VERSION & 0xFF,
288255aa1136SEd Maste 		AAC_DRIVER_BUILD);
288355aa1136SEd Maste 
2884bd971c49SScott Long 	aac_release_sync_fib(sc);
288581b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
288635863739SMike Smith }
288735863739SMike Smith 
2888914da7d0SScott Long /*
288935863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
289035863739SMike Smith  * same.
289135863739SMike Smith  */
289235863739SMike Smith static char *
289335863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
289435863739SMike Smith {
289535863739SMike Smith 	int i;
289635863739SMike Smith 
289735863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
289835863739SMike Smith 		if (table[i].code == code)
289935863739SMike Smith 			return(table[i].string);
290035863739SMike Smith 	return(table[i + 1].string);
290135863739SMike Smith }
290235863739SMike Smith 
2903914da7d0SScott Long /*
2904914da7d0SScott Long  * Management Interface
2905914da7d0SScott Long  */
290635863739SMike Smith 
290735863739SMike Smith static int
290800b4e54aSWarner Losh aac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
290935863739SMike Smith {
2910914da7d0SScott Long 	struct aac_softc *sc;
291135863739SMike Smith 
2912914da7d0SScott Long 	sc = dev->si_drv1;
291331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2914a723a548SEd Maste 	sc->aac_open_cnt++;
291535863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
291635863739SMike Smith 
291735863739SMike Smith 	return 0;
291835863739SMike Smith }
291935863739SMike Smith 
292035863739SMike Smith static int
292100b4e54aSWarner Losh aac_close(struct cdev *dev, int flags, int fmt, struct thread *td)
292235863739SMike Smith {
2923914da7d0SScott Long 	struct aac_softc *sc;
292435863739SMike Smith 
2925914da7d0SScott Long 	sc = dev->si_drv1;
292631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2927a723a548SEd Maste 	sc->aac_open_cnt--;
292835863739SMike Smith 	/* Mark this unit as no longer open  */
2929a723a548SEd Maste 	if (sc->aac_open_cnt == 0)
293035863739SMike Smith 		sc->aac_state &= ~AAC_STATE_OPEN;
293135863739SMike Smith 
293235863739SMike Smith 	return 0;
293335863739SMike Smith }
293435863739SMike Smith 
293535863739SMike Smith static int
293600b4e54aSWarner Losh aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
293735863739SMike Smith {
2938914da7d0SScott Long 	union aac_statrequest *as;
2939914da7d0SScott Long 	struct aac_softc *sc;
29400b94a66eSMike Smith 	int error = 0;
294135863739SMike Smith 
2942914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2943914da7d0SScott Long 	sc = dev->si_drv1;
294431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2945914da7d0SScott Long 
294635863739SMike Smith 	switch (cmd) {
29470b94a66eSMike Smith 	case AACIO_STATS:
29480b94a66eSMike Smith 		switch (as->as_item) {
29490b94a66eSMike Smith 		case AACQ_FREE:
29500b94a66eSMike Smith 		case AACQ_BIO:
29510b94a66eSMike Smith 		case AACQ_READY:
29520b94a66eSMike Smith 		case AACQ_BUSY:
2953c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2954c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
29550b94a66eSMike Smith 			break;
29560b94a66eSMike Smith 		default:
29570b94a66eSMike Smith 			error = ENOENT;
29580b94a66eSMike Smith 			break;
29590b94a66eSMike Smith 		}
29600b94a66eSMike Smith 	break;
29610b94a66eSMike Smith 
296235863739SMike Smith 	case FSACTL_SENDFIB:
2963f355c0e0SEd Maste 	case FSACTL_SEND_LARGE_FIB:
2964fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2965fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
2966f355c0e0SEd Maste 	case FSACTL_LNX_SEND_LARGE_FIB:
296731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
296835863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
296935863739SMike Smith 		break;
2970f355c0e0SEd Maste 	case FSACTL_SEND_RAW_SRB:
2971f355c0e0SEd Maste 		arg = *(caddr_t*)arg;
2972f355c0e0SEd Maste 	case FSACTL_LNX_SEND_RAW_SRB:
297331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2974f355c0e0SEd Maste 		error = aac_ioctl_send_raw_srb(sc, arg);
2975f355c0e0SEd Maste 		break;
297635863739SMike Smith 	case FSACTL_AIF_THREAD:
2977fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
297831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
297935863739SMike Smith 		error = EINVAL;
298035863739SMike Smith 		break;
298135863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2982fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2983fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
298431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2985a723a548SEd Maste 		error = aac_open_aif(sc, arg);
298635863739SMike Smith 		break;
298735863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2988fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2989fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
299031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2991fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
299235863739SMike Smith 		break;
299335863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2994a723a548SEd Maste 		arg = *(caddr_t*)arg;
2995fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
299631a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2997a723a548SEd Maste 		error = aac_close_aif(sc, arg);
299835863739SMike Smith 		break;
299935863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
3000fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
3001fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
300231a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
3003fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
300435863739SMike Smith 		break;
300536e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
300636e0bf6eSScott Long 		arg = *(caddr_t*)arg;
300736e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
300831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
300936e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
301036e0bf6eSScott Long 		break;
301136e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
301236e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
3013914da7d0SScott Long 		/*
3014914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
3015914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
3016914da7d0SScott Long 		 * controller
3017914da7d0SScott Long 		 */
301836e0bf6eSScott Long 		error = 0;
301936e0bf6eSScott Long 		break;
30207cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
30217cb209f5SScott Long 		arg = *(caddr_t*)arg;
30227cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
302331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
30247cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
30257cb209f5SScott Long 		break;
30266d307336SEd Maste 	case FSACTL_GET_FEATURES:
30276d307336SEd Maste 		arg = *(caddr_t*)arg;
30286d307336SEd Maste 	case FSACTL_LNX_GET_FEATURES:
30296d307336SEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
30306d307336SEd Maste 		error = aac_supported_features(sc, arg);
30316d307336SEd Maste 		break;
303235863739SMike Smith 	default:
303331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
303435863739SMike Smith 		error = EINVAL;
303535863739SMike Smith 		break;
303635863739SMike Smith 	}
303735863739SMike Smith 	return(error);
303835863739SMike Smith }
303935863739SMike Smith 
3040b3457b51SScott Long static int
304100b4e54aSWarner Losh aac_poll(struct cdev *dev, int poll_events, struct thread *td)
3042b3457b51SScott Long {
3043b3457b51SScott Long 	struct aac_softc *sc;
3044ef0b687cSEd Maste 	struct aac_fib_context *ctx;
3045b3457b51SScott Long 	int revents;
3046b3457b51SScott Long 
3047b3457b51SScott Long 	sc = dev->si_drv1;
3048b3457b51SScott Long 	revents = 0;
3049b3457b51SScott Long 
3050bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3051b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
3052ef0b687cSEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3053ef0b687cSEd Maste 			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
3054b3457b51SScott Long 				revents |= poll_events & (POLLIN | POLLRDNORM);
3055ef0b687cSEd Maste 				break;
3056ef0b687cSEd Maste 			}
3057ef0b687cSEd Maste 		}
3058b3457b51SScott Long 	}
3059bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
3060b3457b51SScott Long 
3061b3457b51SScott Long 	if (revents == 0) {
3062b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
3063b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
3064b3457b51SScott Long 	}
3065b3457b51SScott Long 
3066b3457b51SScott Long 	return (revents);
3067b3457b51SScott Long }
3068b3457b51SScott Long 
30697cb209f5SScott Long static void
30707cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
30717cb209f5SScott Long {
30727cb209f5SScott Long 
30737cb209f5SScott Long 	switch (event->ev_type) {
30747cb209f5SScott Long 	case AAC_EVENT_CMFREE:
30750c40d5beSEd Maste 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
30761a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
30777cb209f5SScott Long 			aac_add_event(sc, event);
30787cb209f5SScott Long 			return;
30797cb209f5SScott Long 		}
30807cb209f5SScott Long 		free(event, M_AACBUF);
30818eeb2ca6SScott Long 		wakeup(arg);
30827cb209f5SScott Long 		break;
30837cb209f5SScott Long 	default:
30847cb209f5SScott Long 		break;
30857cb209f5SScott Long 	}
30867cb209f5SScott Long }
30877cb209f5SScott Long 
3088914da7d0SScott Long /*
308935863739SMike Smith  * Send a FIB supplied from userspace
309035863739SMike Smith  */
309135863739SMike Smith static int
309235863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
309335863739SMike Smith {
309435863739SMike Smith 	struct aac_command *cm;
309535863739SMike Smith 	int size, error;
309635863739SMike Smith 
309731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
309835863739SMike Smith 
309935863739SMike Smith 	cm = NULL;
310035863739SMike Smith 
310135863739SMike Smith 	/*
310235863739SMike Smith 	 * Get a command
310335863739SMike Smith 	 */
3104bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
310535863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
31067cb209f5SScott Long 		struct aac_event *event;
31077cb209f5SScott Long 
31087cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
31097cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
31107cb209f5SScott Long 		if (event == NULL) {
311135863739SMike Smith 			error = EBUSY;
3112f16627aaSEd Maste 			mtx_unlock(&sc->aac_io_lock);
311335863739SMike Smith 			goto out;
311435863739SMike Smith 		}
31157cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
31167cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
31177cb209f5SScott Long 		event->ev_arg = &cm;
31187cb209f5SScott Long 		aac_add_event(sc, event);
31198eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
31207cb209f5SScott Long 	}
312193cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
312235863739SMike Smith 
312335863739SMike Smith 	/*
312435863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
312535863739SMike Smith 	 */
3126914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3127914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
312835863739SMike Smith 		goto out;
312935863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3130f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3131f355c0e0SEd Maste 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3132f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3133f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
313435863739SMike Smith 	}
313535863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
313635863739SMike Smith 		goto out;
313735863739SMike Smith 	cm->cm_fib->Header.Size = size;
31382b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
313935863739SMike Smith 
314035863739SMike Smith 	/*
314135863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
314235863739SMike Smith 	 */
314393cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3144f16627aaSEd Maste 	error = aac_wait_command(cm);
3145f16627aaSEd Maste 	mtx_unlock(&sc->aac_io_lock);
3146f16627aaSEd Maste 	if (error != 0) {
314770545d1aSScott Long 		device_printf(sc->aac_dev,
314870545d1aSScott Long 			      "aac_wait_command return %d\n", error);
314935863739SMike Smith 		goto out;
3150b3457b51SScott Long 	}
315135863739SMike Smith 
315235863739SMike Smith 	/*
315335863739SMike Smith 	 * Copy the FIB and data back out to the caller.
315435863739SMike Smith 	 */
315535863739SMike Smith 	size = cm->cm_fib->Header.Size;
3156f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3157f355c0e0SEd Maste 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3158f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3159f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
316035863739SMike Smith 	}
316135863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
316235863739SMike Smith 
316335863739SMike Smith out:
3164f6c4dd3fSScott Long 	if (cm != NULL) {
3165f16627aaSEd Maste 		mtx_lock(&sc->aac_io_lock);
316635863739SMike Smith 		aac_release_command(cm);
3167bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
3168f16627aaSEd Maste 	}
316935863739SMike Smith 	return(error);
317035863739SMike Smith }
317135863739SMike Smith 
3172914da7d0SScott Long /*
3173f355c0e0SEd Maste  * Send a passthrough FIB supplied from userspace
3174f355c0e0SEd Maste  */
3175f355c0e0SEd Maste static int
3176f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3177f355c0e0SEd Maste {
3178f355c0e0SEd Maste 	return (EINVAL);
3179f355c0e0SEd Maste }
3180f355c0e0SEd Maste 
3181f355c0e0SEd Maste /*
318235863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
318336e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
318435863739SMike Smith  */
318535863739SMike Smith static void
318636e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
318735863739SMike Smith {
318836e0bf6eSScott Long 	struct aac_aif_command *aif;
318936e0bf6eSScott Long 	struct aac_container *co, *co_next;
3190a723a548SEd Maste 	struct aac_fib_context *ctx;
319104f4d586SEd Maste 	struct aac_mntinforesp *mir;
3192a723a548SEd Maste 	int next, current, found;
3193795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
319435863739SMike Smith 
319531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
319635863739SMike Smith 
319736e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
319836e0bf6eSScott Long 	aac_print_aif(sc, aif);
319936e0bf6eSScott Long 
320036e0bf6eSScott Long 	/* Is it an event that we should care about? */
320136e0bf6eSScott Long 	switch (aif->command) {
320236e0bf6eSScott Long 	case AifCmdEventNotify:
320336e0bf6eSScott Long 		switch (aif->data.EN.type) {
320436e0bf6eSScott Long 		case AifEnAddContainer:
320536e0bf6eSScott Long 		case AifEnDeleteContainer:
320636e0bf6eSScott Long 			/*
3207914da7d0SScott Long 			 * A container was added or deleted, but the message
3208914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3209914da7d0SScott Long 			 * containers and sort things out.
321036e0bf6eSScott Long 			 */
321103b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
321236e0bf6eSScott Long 			do {
321336e0bf6eSScott Long 				/*
3214914da7d0SScott Long 				 * Ask the controller for its containers one at
3215914da7d0SScott Long 				 * a time.
3216914da7d0SScott Long 				 * XXX What if the controller's list changes
3217914da7d0SScott Long 				 * midway through this enumaration?
321836e0bf6eSScott Long 				 * XXX This should be done async.
321936e0bf6eSScott Long 				 */
322004f4d586SEd Maste 				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
322136e0bf6eSScott Long 					continue;
322204f4d586SEd Maste 				if (i == 0)
3223795d7dc0SScott Long 					count = mir->MntRespCount;
322436e0bf6eSScott Long 				/*
3225914da7d0SScott Long 				 * Check the container against our list.
3226914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3227914da7d0SScott Long 				 * previous run.
322836e0bf6eSScott Long 				 */
3229cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3230cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
323136e0bf6eSScott Long 					found = 0;
3232914da7d0SScott Long 					TAILQ_FOREACH(co,
3233914da7d0SScott Long 						      &sc->aac_container_tqh,
3234914da7d0SScott Long 						      co_link) {
323536e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3236cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
323736e0bf6eSScott Long 							co->co_found = 1;
323836e0bf6eSScott Long 							found = 1;
323936e0bf6eSScott Long 							break;
324036e0bf6eSScott Long 						}
324136e0bf6eSScott Long 					}
3242914da7d0SScott Long 					/*
3243914da7d0SScott Long 					 * If the container matched, continue
3244914da7d0SScott Long 					 * in the list.
3245914da7d0SScott Long 					 */
324636e0bf6eSScott Long 					if (found) {
324736e0bf6eSScott Long 						i++;
324836e0bf6eSScott Long 						continue;
324936e0bf6eSScott Long 					}
325036e0bf6eSScott Long 
325136e0bf6eSScott Long 					/*
3252914da7d0SScott Long 					 * This is a new container.  Do all the
325370545d1aSScott Long 					 * appropriate things to set it up.
325470545d1aSScott Long 					 */
3255cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
325636e0bf6eSScott Long 					added = 1;
325736e0bf6eSScott Long 				}
325836e0bf6eSScott Long 				i++;
3259795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3260cbfd045bSScott Long 			aac_release_sync_fib(sc);
326136e0bf6eSScott Long 
326236e0bf6eSScott Long 			/*
3263914da7d0SScott Long 			 * Go through our list of containers and see which ones
3264914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3265914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3266914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3267914da7d0SScott Long 			 * the co->co_found field.
326836e0bf6eSScott Long 			 */
326936e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
327036e0bf6eSScott Long 			while (co != NULL) {
327136e0bf6eSScott Long 				if (co->co_found == 0) {
32727cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
3273a56fe095SJohn Baldwin 					mtx_lock(&Giant);
3274914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3275914da7d0SScott Long 							    co->co_disk);
3276a56fe095SJohn Baldwin 					mtx_unlock(&Giant);
32777cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
327836e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3279bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3280914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3281914da7d0SScott Long 						     co_link);
3282bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3283ba1d57e7SScott Long 					free(co, M_AACBUF);
328436e0bf6eSScott Long 					co = co_next;
328536e0bf6eSScott Long 				} else {
328636e0bf6eSScott Long 					co->co_found = 0;
328736e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
328836e0bf6eSScott Long 				}
328936e0bf6eSScott Long 			}
329036e0bf6eSScott Long 
329136e0bf6eSScott Long 			/* Attach the newly created containers */
32927cb209f5SScott Long 			if (added) {
32937cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
3294a56fe095SJohn Baldwin 				mtx_lock(&Giant);
329536e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
3296a56fe095SJohn Baldwin 				mtx_unlock(&Giant);
32977cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
32987cb209f5SScott Long 			}
329936e0bf6eSScott Long 
330036e0bf6eSScott Long 			break;
330136e0bf6eSScott Long 
330236e0bf6eSScott Long 		default:
330336e0bf6eSScott Long 			break;
330436e0bf6eSScott Long 		}
330536e0bf6eSScott Long 
330636e0bf6eSScott Long 	default:
330736e0bf6eSScott Long 		break;
330836e0bf6eSScott Long 	}
330936e0bf6eSScott Long 
331036e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3311bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3312a723a548SEd Maste 	current = sc->aifq_idx;
3313a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3314a723a548SEd Maste 	if (next == 0)
3315a723a548SEd Maste 		sc->aifq_filled = 1;
3316a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3317a723a548SEd Maste 	/* modify AIF contexts */
3318a723a548SEd Maste 	if (sc->aifq_filled) {
3319a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3320a723a548SEd Maste 			if (next == ctx->ctx_idx)
3321a723a548SEd Maste 				ctx->ctx_wrap = 1;
3322a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3323a723a548SEd Maste 				ctx->ctx_idx = next;
3324a723a548SEd Maste 		}
3325a723a548SEd Maste 	}
3326a723a548SEd Maste 	sc->aifq_idx = next;
3327b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
332835863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
332935863739SMike Smith 		wakeup(sc->aac_aifq);
3330b3457b51SScott Long 	/* Wakeup any poll()ers */
3331512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3332bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
333336e0bf6eSScott Long 
333436e0bf6eSScott Long 	return;
333535863739SMike Smith }
333635863739SMike Smith 
3337914da7d0SScott Long /*
33380b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
333936e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
334036e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
334136e0bf6eSScott Long  * returning what the card reported.
334235863739SMike Smith  */
334335863739SMike Smith static int
3344fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
334535863739SMike Smith {
334635863739SMike Smith 	struct aac_rev_check rev_check;
334735863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
334835863739SMike Smith 	int error = 0;
334935863739SMike Smith 
335031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
335135863739SMike Smith 
335235863739SMike Smith 	/*
335335863739SMike Smith 	 * Copyin the revision struct from userspace
335435863739SMike Smith 	 */
3355c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3356c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
335735863739SMike Smith 		return error;
335835863739SMike Smith 	}
335935863739SMike Smith 
336031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3361914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
336235863739SMike Smith 
336335863739SMike Smith 	/*
336435863739SMike Smith 	 * Doctor up the response struct.
336535863739SMike Smith 	 */
336635863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3367914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3368914da7d0SScott Long 	    sc->aac_revision.external.ul;
3369914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3370914da7d0SScott Long 	    sc->aac_revision.buildNumber;
337135863739SMike Smith 
3372c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3373c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
337435863739SMike Smith }
337535863739SMike Smith 
3376914da7d0SScott Long /*
3377a723a548SEd Maste  * Pass the fib context to the caller
3378a723a548SEd Maste  */
3379a723a548SEd Maste static int
3380a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3381a723a548SEd Maste {
3382a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3383a723a548SEd Maste 	int error = 0;
3384a723a548SEd Maste 
338531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3386a723a548SEd Maste 
3387a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3388a723a548SEd Maste 	if (fibctx == NULL)
3389a723a548SEd Maste 		return (ENOMEM);
3390a723a548SEd Maste 
3391a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3392a723a548SEd Maste 	/* all elements are already 0, add to queue */
3393a723a548SEd Maste 	if (sc->fibctx == NULL)
3394a723a548SEd Maste 		sc->fibctx = fibctx;
3395a723a548SEd Maste 	else {
3396a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3397a723a548SEd Maste 			;
3398a723a548SEd Maste 		ctx->next = fibctx;
3399a723a548SEd Maste 		fibctx->prev = ctx;
3400a723a548SEd Maste 	}
3401a723a548SEd Maste 
3402a723a548SEd Maste 	/* evaluate unique value */
3403a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3404a723a548SEd Maste 	ctx = sc->fibctx;
3405a723a548SEd Maste 	while (ctx != fibctx) {
3406a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3407a723a548SEd Maste 			fibctx->unique++;
3408a723a548SEd Maste 			ctx = sc->fibctx;
3409a723a548SEd Maste 		} else {
3410a723a548SEd Maste 			ctx = ctx->next;
3411a723a548SEd Maste 		}
3412a723a548SEd Maste 	}
3413a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3414a723a548SEd Maste 
3415a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3416a723a548SEd Maste 	if (error)
3417a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3418a723a548SEd Maste 	return error;
3419a723a548SEd Maste }
3420a723a548SEd Maste 
3421a723a548SEd Maste /*
3422a723a548SEd Maste  * Close the caller's fib context
3423a723a548SEd Maste  */
3424a723a548SEd Maste static int
3425a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3426a723a548SEd Maste {
3427a723a548SEd Maste 	struct aac_fib_context *ctx;
3428a723a548SEd Maste 
342931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3430a723a548SEd Maste 
3431a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3432a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3433a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3434a723a548SEd Maste 			if (ctx == sc->fibctx)
3435a723a548SEd Maste 				sc->fibctx = NULL;
3436a723a548SEd Maste 			else {
3437a723a548SEd Maste 				ctx->prev->next = ctx->next;
3438a723a548SEd Maste 				if (ctx->next)
3439a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3440a723a548SEd Maste 			}
3441a723a548SEd Maste 			break;
3442a723a548SEd Maste 		}
3443a723a548SEd Maste 	}
3444a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3445a723a548SEd Maste 	if (ctx)
3446a723a548SEd Maste 		free(ctx, M_AACBUF);
3447a723a548SEd Maste 
3448a723a548SEd Maste 	return 0;
3449a723a548SEd Maste }
3450a723a548SEd Maste 
3451a723a548SEd Maste /*
345235863739SMike Smith  * Pass the caller the next AIF in their queue
345335863739SMike Smith  */
345435863739SMike Smith static int
3455fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
345635863739SMike Smith {
345735863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3458a723a548SEd Maste 	struct aac_fib_context *ctx;
34599e2e96d8SScott Long 	int error;
346035863739SMike Smith 
346131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
346235863739SMike Smith 
346335863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3464a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3465a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3466a723a548SEd Maste 				break;
3467a723a548SEd Maste 		}
3468a723a548SEd Maste 		if (!ctx)
3469a723a548SEd Maste 			return (EFAULT);
347035863739SMike Smith 
3471a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3472a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
347331a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
347435863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
347535863739SMike Smith 			while (error == EAGAIN) {
3476914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3477914da7d0SScott Long 					       PCATCH, "aacaif", 0);
347835863739SMike Smith 				if (error == 0)
3479a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
348035863739SMike Smith 			}
348135863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
348235863739SMike Smith 		}
348335863739SMike Smith 	}
348435863739SMike Smith 	return(error);
348535863739SMike Smith }
348635863739SMike Smith 
3487914da7d0SScott Long /*
34880b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
34890b94a66eSMike Smith  */
34900b94a66eSMike Smith static int
3491a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
34920b94a66eSMike Smith {
3493a723a548SEd Maste 	int current, error;
34940b94a66eSMike Smith 
349531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
34960b94a66eSMike Smith 
3497bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3498a723a548SEd Maste 	current = ctx->ctx_idx;
3499a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3500a723a548SEd Maste 		/* empty */
3501bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
35023df780cfSScott Long 		return (EAGAIN);
35033df780cfSScott Long 	}
3504a723a548SEd Maste 	error =
3505a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
350636e0bf6eSScott Long 	if (error)
350770545d1aSScott Long 		device_printf(sc->aac_dev,
350870545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3509a723a548SEd Maste 	else {
3510a723a548SEd Maste 		ctx->ctx_wrap = 0;
3511a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3512a723a548SEd Maste 	}
3513bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
35140b94a66eSMike Smith 	return(error);
35150b94a66eSMike Smith }
351636e0bf6eSScott Long 
35177cb209f5SScott Long static int
35187cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
35197cb209f5SScott Long {
35207cb209f5SScott Long 	struct aac_pci_info {
35217cb209f5SScott Long 		u_int32_t bus;
35227cb209f5SScott Long 		u_int32_t slot;
35237cb209f5SScott Long 	} pciinf;
35247cb209f5SScott Long 	int error;
35257cb209f5SScott Long 
352631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35277cb209f5SScott Long 
35287cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
35297cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
35307cb209f5SScott Long 
35317cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
35327cb209f5SScott Long 			sizeof(struct aac_pci_info));
35337cb209f5SScott Long 
35347cb209f5SScott Long 	return (error);
35357cb209f5SScott Long }
35367cb209f5SScott Long 
35376d307336SEd Maste static int
35386d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr)
35396d307336SEd Maste {
35406d307336SEd Maste 	struct aac_features f;
35416d307336SEd Maste 	int error;
35426d307336SEd Maste 
35436d307336SEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35446d307336SEd Maste 
35456d307336SEd Maste 	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
35466d307336SEd Maste 		return (error);
35476d307336SEd Maste 
35486d307336SEd Maste 	/*
35496d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35506d307336SEd Maste 	 * ALL zero in the featuresState, the driver will return the current
35516d307336SEd Maste 	 * state of all the supported features, the data field will not be
35526d307336SEd Maste 	 * valid.
35536d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35546d307336SEd Maste 	 * a specific bit set in the featuresState, the driver will return the
35556d307336SEd Maste 	 * current state of this specific feature and whatever data that are
35566d307336SEd Maste 	 * associated with the feature in the data field or perform whatever
35576d307336SEd Maste 	 * action needed indicates in the data field.
35586d307336SEd Maste 	 */
35596d307336SEd Maste 	if (f.feat.fValue == 0) {
35606d307336SEd Maste 		f.feat.fBits.largeLBA =
35616d307336SEd Maste 		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35626d307336SEd Maste 		/* TODO: In the future, add other features state here as well */
35636d307336SEd Maste 	} else {
35646d307336SEd Maste 		if (f.feat.fBits.largeLBA)
35656d307336SEd Maste 			f.feat.fBits.largeLBA =
35666d307336SEd Maste 			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35676d307336SEd Maste 		/* TODO: Add other features state and data in the future */
35686d307336SEd Maste 	}
35696d307336SEd Maste 
35706d307336SEd Maste 	error = copyout(&f, uptr, sizeof (f));
35716d307336SEd Maste 	return (error);
35726d307336SEd Maste }
35736d307336SEd Maste 
3574914da7d0SScott Long /*
357536e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
357636e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
357736e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
357836e0bf6eSScott Long  */
357936e0bf6eSScott Long static int
358036e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
358136e0bf6eSScott Long {
358236e0bf6eSScott Long 	struct aac_query_disk query_disk;
358336e0bf6eSScott Long 	struct aac_container *co;
3584914da7d0SScott Long 	struct aac_disk	*disk;
358536e0bf6eSScott Long 	int error, id;
358636e0bf6eSScott Long 
358731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
358836e0bf6eSScott Long 
3589914da7d0SScott Long 	disk = NULL;
3590914da7d0SScott Long 
3591914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3592914da7d0SScott Long 		       sizeof(struct aac_query_disk));
359336e0bf6eSScott Long 	if (error)
359436e0bf6eSScott Long 		return (error);
359536e0bf6eSScott Long 
359636e0bf6eSScott Long 	id = query_disk.ContainerNumber;
359736e0bf6eSScott Long 	if (id == -1)
359836e0bf6eSScott Long 		return (EINVAL);
359936e0bf6eSScott Long 
3600bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
360136e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
360236e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
360336e0bf6eSScott Long 			break;
360436e0bf6eSScott Long 		}
360536e0bf6eSScott Long 
360636e0bf6eSScott Long 	if (co == NULL) {
360736e0bf6eSScott Long 			query_disk.Valid = 0;
360836e0bf6eSScott Long 			query_disk.Locked = 0;
360936e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
361036e0bf6eSScott Long 	} else {
361136e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
361236e0bf6eSScott Long 		query_disk.Valid = 1;
3613914da7d0SScott Long 		query_disk.Locked =
3614914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
361536e0bf6eSScott Long 		query_disk.Deleted = 0;
3616b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
361736e0bf6eSScott Long 		query_disk.Target = disk->unit;
361836e0bf6eSScott Long 		query_disk.Lun = 0;
361936e0bf6eSScott Long 		query_disk.UnMapped = 0;
36207540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
36210b7ed341SPoul-Henning Kamp 			disk->ad_disk->d_name, disk->ad_disk->d_unit);
362236e0bf6eSScott Long 	}
3623bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
362436e0bf6eSScott Long 
3625914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3626914da7d0SScott Long 			sizeof(struct aac_query_disk));
362736e0bf6eSScott Long 
362836e0bf6eSScott Long 	return (error);
362936e0bf6eSScott Long }
363036e0bf6eSScott Long 
3631fe3cb0e1SScott Long static void
3632fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3633fe3cb0e1SScott Long {
3634fe3cb0e1SScott Long 	struct aac_fib *fib;
3635fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3636fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3637fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3638fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3639fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
364070545d1aSScott Long 	struct aac_sim *caminf;
3641fe3cb0e1SScott Long 	device_t child;
3642fe3cb0e1SScott Long 	int i, found, error;
3643fe3cb0e1SScott Long 
36441ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
364503b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3646fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
364739ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3648fe3cb0e1SScott Long 
3649fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3650fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3651fe3cb0e1SScott Long 	c_cmd->param = 0;
3652fe3cb0e1SScott Long 
3653fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3654fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3655fe3cb0e1SScott Long 	if (error) {
3656fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3657fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3658fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36591ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3660fe3cb0e1SScott Long 		return;
3661fe3cb0e1SScott Long 	}
3662fe3cb0e1SScott Long 
3663fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3664fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3665fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3666fe3cb0e1SScott Long 		    c_resp->Status);
3667fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36681ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3669fe3cb0e1SScott Long 		return;
3670fe3cb0e1SScott Long 	}
3671fe3cb0e1SScott Long 
3672fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3673fe3cb0e1SScott Long 
3674fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
367539ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
367639ee03c3SScott Long 
3677fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3678fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3679fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3680fe3cb0e1SScott Long 	vmi->ObjId = 0;
3681fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3682fe3cb0e1SScott Long 
3683fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
368442ef13a2SEd Maste 	    sizeof(struct aac_vmi_businf_resp));
3685fe3cb0e1SScott Long 	if (error) {
3686fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3687fe3cb0e1SScott Long 		    error);
3688fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36891ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3690fe3cb0e1SScott Long 		return;
3691fe3cb0e1SScott Long 	}
3692fe3cb0e1SScott Long 
3693fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3694fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3695fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3696fe3cb0e1SScott Long 		    vmi_resp->Status);
3697fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36981ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3699fe3cb0e1SScott Long 		return;
3700fe3cb0e1SScott Long 	}
3701fe3cb0e1SScott Long 
3702fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3703fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
37041ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3705fe3cb0e1SScott Long 
3706fe3cb0e1SScott Long 	found = 0;
3707fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3708fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3709fe3cb0e1SScott Long 			continue;
3710fe3cb0e1SScott Long 
3711a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3712a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3713b5f516cdSScott Long 		if (caminf == NULL) {
3714b5f516cdSScott Long 			device_printf(sc->aac_dev,
3715b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3716b5f516cdSScott Long 			break;
37177cb209f5SScott Long 		};
3718fe3cb0e1SScott Long 
3719fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3720fe3cb0e1SScott Long 		if (child == NULL) {
3721b5f516cdSScott Long 			device_printf(sc->aac_dev,
3722b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3723b5f516cdSScott Long 			    i);
3724b5f516cdSScott Long 			free(caminf, M_AACBUF);
3725b5f516cdSScott Long 			break;
3726fe3cb0e1SScott Long 		}
3727fe3cb0e1SScott Long 
3728fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3729fe3cb0e1SScott Long 		caminf->BusNumber = i;
3730fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3731fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3732ddb8683eSScott Long 		caminf->sim_dev = child;
3733fe3cb0e1SScott Long 
3734fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3735fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
373670545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3737fe3cb0e1SScott Long 
3738fe3cb0e1SScott Long 		found = 1;
3739fe3cb0e1SScott Long 	}
3740fe3cb0e1SScott Long 
3741fe3cb0e1SScott Long 	if (found)
3742fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3743fe3cb0e1SScott Long 
3744fe3cb0e1SScott Long 	return;
3745fe3cb0e1SScott Long }
3746