xref: /freebsd/sys/dev/aac/aac.c (revision ef0b687ced545c149c34ec171574138cbefc6c1c)
135863739SMike Smith /*-
235863739SMike Smith  * Copyright (c) 2000 Michael Smith
3c6eafcf2SScott Long  * Copyright (c) 2001 Scott Long
435863739SMike Smith  * Copyright (c) 2000 BSDi
5c6eafcf2SScott Long  * Copyright (c) 2001 Adaptec, Inc.
635863739SMike Smith  * All rights reserved.
735863739SMike Smith  *
835863739SMike Smith  * Redistribution and use in source and binary forms, with or without
935863739SMike Smith  * modification, are permitted provided that the following conditions
1035863739SMike Smith  * are met:
1135863739SMike Smith  * 1. Redistributions of source code must retain the above copyright
1235863739SMike Smith  *    notice, this list of conditions and the following disclaimer.
1335863739SMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1435863739SMike Smith  *    notice, this list of conditions and the following disclaimer in the
1535863739SMike Smith  *    documentation and/or other materials provided with the distribution.
1635863739SMike Smith  *
1735863739SMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1835863739SMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1935863739SMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2035863739SMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2135863739SMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2235863739SMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2335863739SMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2435863739SMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2535863739SMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2635863739SMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2735863739SMike Smith  * SUCH DAMAGE.
2835863739SMike Smith  */
2935863739SMike Smith 
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
32aad970f1SDavid E. O'Brien 
3335863739SMike Smith /*
3435863739SMike Smith  * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3535863739SMike Smith  */
367cb209f5SScott Long #define AAC_DRIVER_VERSION		0x02000000
377cb209f5SScott Long #define AAC_DRIVERNAME			"aac"
3835863739SMike Smith 
39f6c4dd3fSScott Long #include "opt_aac.h"
40f6c4dd3fSScott Long 
4136e0bf6eSScott Long /* #include <stddef.h> */
4235863739SMike Smith #include <sys/param.h>
4335863739SMike Smith #include <sys/systm.h>
4435863739SMike Smith #include <sys/malloc.h>
4535863739SMike Smith #include <sys/kernel.h>
4636e0bf6eSScott Long #include <sys/kthread.h>
473d04a9d7SScott Long #include <sys/sysctl.h>
48b3457b51SScott Long #include <sys/poll.h>
49891619a6SPoul-Henning Kamp #include <sys/ioccom.h>
5035863739SMike Smith 
5135863739SMike Smith #include <sys/bus.h>
5235863739SMike Smith #include <sys/conf.h>
5335863739SMike Smith #include <sys/signalvar.h>
540b94a66eSMike Smith #include <sys/time.h>
5536e0bf6eSScott Long #include <sys/eventhandler.h>
567cb209f5SScott Long #include <sys/rman.h>
5735863739SMike Smith 
5835863739SMike Smith #include <machine/bus.h>
59b5f516cdSScott Long #include <sys/bus_dma.h>
6035863739SMike Smith #include <machine/resource.h>
6135863739SMike Smith 
627cb209f5SScott Long #include <dev/pci/pcireg.h>
637cb209f5SScott Long #include <dev/pci/pcivar.h>
647cb209f5SScott Long 
6535863739SMike Smith #include <dev/aac/aacreg.h>
660b0594cdSScott Long #include <sys/aac_ioctl.h>
6735863739SMike Smith #include <dev/aac/aacvar.h>
6835863739SMike Smith #include <dev/aac/aac_tables.h>
6935863739SMike Smith 
7035863739SMike Smith static void	aac_startup(void *arg);
71914da7d0SScott Long static void	aac_add_container(struct aac_softc *sc,
72cbfd045bSScott Long 				  struct aac_mntinforesp *mir, int f);
73fe3cb0e1SScott Long static void	aac_get_bus_info(struct aac_softc *sc);
7435863739SMike Smith 
7535863739SMike Smith /* Command Processing */
760b94a66eSMike Smith static void	aac_timeout(struct aac_softc *sc);
7735863739SMike Smith static void	aac_complete(void *context, int pending);
7835863739SMike Smith static int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7935863739SMike Smith static void	aac_bio_complete(struct aac_command *cm);
80d8a0a473SScott Long static int	aac_wait_command(struct aac_command *cm);
8170545d1aSScott Long static void	aac_command_thread(struct aac_softc *sc);
8235863739SMike Smith 
8335863739SMike Smith /* Command Buffer Management */
84cd481291SScott Long static void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
85cd481291SScott Long 				   int nseg, int error);
86c6eafcf2SScott Long static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
87c6eafcf2SScott Long 				       int nseg, int error);
880b94a66eSMike Smith static int	aac_alloc_commands(struct aac_softc *sc);
898480cc63SScott Long static void	aac_free_commands(struct aac_softc *sc);
9035863739SMike Smith static void	aac_unmap_command(struct aac_command *cm);
9135863739SMike Smith 
9235863739SMike Smith /* Hardware Interface */
9304f4d586SEd Maste static int	aac_alloc(struct aac_softc *sc);
94c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
95c6eafcf2SScott Long 			       int error);
96fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9735863739SMike Smith static int	aac_init(struct aac_softc *sc);
9835863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
99c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
100c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
10104f4d586SEd Maste static int	aac_setup_intr(struct aac_softc *sc);
102c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
103f6c4dd3fSScott Long 				struct aac_command *cm);
104c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
105914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10636e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10736e0bf6eSScott Long 				     struct aac_fib *fib);
10835863739SMike Smith 
109b3457b51SScott Long /* Falcon/PPC interface */
110b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
111b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
112b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
113b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
114b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
115b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
116b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
117a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
118b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
119b3457b51SScott Long 
120b3457b51SScott Long struct aac_interface aac_fa_interface = {
121b3457b51SScott Long 	aac_fa_get_fwstatus,
122b3457b51SScott Long 	aac_fa_qnotify,
123b3457b51SScott Long 	aac_fa_get_istatus,
124b3457b51SScott Long 	aac_fa_clear_istatus,
125b3457b51SScott Long 	aac_fa_set_mailbox,
126a6d35632SScott Long 	aac_fa_get_mailbox,
1277cb209f5SScott Long 	aac_fa_set_interrupts,
1287cb209f5SScott Long 	NULL, NULL, NULL
129b3457b51SScott Long };
130b3457b51SScott Long 
13135863739SMike Smith /* StrongARM interface */
13235863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
13335863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13435863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
13535863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13635863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
137c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
138c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
139a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
14035863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
14135863739SMike Smith 
14235863739SMike Smith struct aac_interface aac_sa_interface = {
14335863739SMike Smith 	aac_sa_get_fwstatus,
14435863739SMike Smith 	aac_sa_qnotify,
14535863739SMike Smith 	aac_sa_get_istatus,
14635863739SMike Smith 	aac_sa_clear_istatus,
14735863739SMike Smith 	aac_sa_set_mailbox,
148a6d35632SScott Long 	aac_sa_get_mailbox,
1497cb209f5SScott Long 	aac_sa_set_interrupts,
1507cb209f5SScott Long 	NULL, NULL, NULL
15135863739SMike Smith };
15235863739SMike Smith 
15335863739SMike Smith /* i960Rx interface */
15435863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
15535863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15635863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
15735863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15835863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
159c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
160c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
161a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16235863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
1637cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
1647cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc);
1657cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16635863739SMike Smith 
16735863739SMike Smith struct aac_interface aac_rx_interface = {
16835863739SMike Smith 	aac_rx_get_fwstatus,
16935863739SMike Smith 	aac_rx_qnotify,
17035863739SMike Smith 	aac_rx_get_istatus,
17135863739SMike Smith 	aac_rx_clear_istatus,
17235863739SMike Smith 	aac_rx_set_mailbox,
173a6d35632SScott Long 	aac_rx_get_mailbox,
1747cb209f5SScott Long 	aac_rx_set_interrupts,
1757cb209f5SScott Long 	aac_rx_send_command,
1767cb209f5SScott Long 	aac_rx_get_outb_queue,
1777cb209f5SScott Long 	aac_rx_set_outb_queue
17835863739SMike Smith };
17935863739SMike Smith 
1804afedc31SScott Long /* Rocket/MIPS interface */
1814afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1824afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1834afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1844afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1854afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1864afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1874afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1884afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1894afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1907cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
1917cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc);
1927cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
1934afedc31SScott Long 
1944afedc31SScott Long struct aac_interface aac_rkt_interface = {
1954afedc31SScott Long 	aac_rkt_get_fwstatus,
1964afedc31SScott Long 	aac_rkt_qnotify,
1974afedc31SScott Long 	aac_rkt_get_istatus,
1984afedc31SScott Long 	aac_rkt_clear_istatus,
1994afedc31SScott Long 	aac_rkt_set_mailbox,
2004afedc31SScott Long 	aac_rkt_get_mailbox,
2017cb209f5SScott Long 	aac_rkt_set_interrupts,
2027cb209f5SScott Long 	aac_rkt_send_command,
2037cb209f5SScott Long 	aac_rkt_get_outb_queue,
2047cb209f5SScott Long 	aac_rkt_set_outb_queue
2054afedc31SScott Long };
2064afedc31SScott Long 
20735863739SMike Smith /* Debugging and Diagnostics */
20835863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
2096965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
210c6eafcf2SScott Long 				   u_int32_t code);
21135863739SMike Smith 
21235863739SMike Smith /* Management Interface */
21335863739SMike Smith static d_open_t		aac_open;
21435863739SMike Smith static d_close_t	aac_close;
21535863739SMike Smith static d_ioctl_t	aac_ioctl;
216b3457b51SScott Long static d_poll_t		aac_poll;
217c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
218f355c0e0SEd Maste static int		aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
219c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
22036e0bf6eSScott Long 					   struct aac_fib *fib);
221fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
222a723a548SEd Maste static int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
223a723a548SEd Maste static int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
224fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
225a723a548SEd Maste static int		aac_return_aif(struct aac_softc *sc,
226a723a548SEd Maste 					struct aac_fib_context *ctx, caddr_t uptr);
22736e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
2287cb209f5SScott Long static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
2296d307336SEd Maste static int		aac_supported_features(struct aac_softc *sc, caddr_t uptr);
2307cb209f5SScott Long static void		aac_ioctl_event(struct aac_softc *sc,
2317cb209f5SScott Long 				        struct aac_event *event, void *arg);
23204f4d586SEd Maste static struct aac_mntinforesp *
23304f4d586SEd Maste 	aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid);
23435863739SMike Smith 
23535863739SMike Smith static struct cdevsw aac_cdevsw = {
236dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
237dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2387ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2397ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2407ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2417ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2427ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
24335863739SMike Smith };
24435863739SMike Smith 
24536e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
24636e0bf6eSScott Long 
2473d04a9d7SScott Long /* sysctl node */
2483d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2493d04a9d7SScott Long 
250914da7d0SScott Long /*
251914da7d0SScott Long  * Device Interface
252914da7d0SScott Long  */
25335863739SMike Smith 
254914da7d0SScott Long /*
2554109ba51SEd Maste  * Initialize the controller and softc
25635863739SMike Smith  */
25735863739SMike Smith int
25835863739SMike Smith aac_attach(struct aac_softc *sc)
25935863739SMike Smith {
26035863739SMike Smith 	int error, unit;
26135863739SMike Smith 
26231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26335863739SMike Smith 
26435863739SMike Smith 	/*
2654109ba51SEd Maste 	 * Initialize per-controller queues.
26635863739SMike Smith 	 */
2670b94a66eSMike Smith 	aac_initq_free(sc);
2680b94a66eSMike Smith 	aac_initq_ready(sc);
2690b94a66eSMike Smith 	aac_initq_busy(sc);
2700b94a66eSMike Smith 	aac_initq_bio(sc);
27135863739SMike Smith 
27235863739SMike Smith 	/*
2734109ba51SEd Maste 	 * Initialize command-completion task.
27435863739SMike Smith 	 */
27535863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
27635863739SMike Smith 
27735863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
27835863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
27935863739SMike Smith 
28035863739SMike Smith 	/*
281fe94b852SScott Long 	 * Check that the firmware on the card is supported.
282fe94b852SScott Long 	 */
283fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
284fe94b852SScott Long 		return(error);
285fe94b852SScott Long 
286f6b1c44dSScott Long 	/*
287f6b1c44dSScott Long 	 * Initialize locks
288f6b1c44dSScott Long 	 */
289bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
290bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
291bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
292f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
293065dd78cSScott Long 	TAILQ_INIT(&sc->aac_ev_cmfree);
294f6b1c44dSScott Long 
2950b94a66eSMike Smith 	/*
2964109ba51SEd Maste 	 * Initialize the adapter.
29735863739SMike Smith 	 */
29804f4d586SEd Maste 	if ((error = aac_alloc(sc)) != 0)
29904f4d586SEd Maste 		return(error);
3000b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
30135863739SMike Smith 		return(error);
30235863739SMike Smith 
30335863739SMike Smith 	/*
3047cb209f5SScott Long 	 * Allocate and connect our interrupt.
3057cb209f5SScott Long 	 */
30604f4d586SEd Maste 	if ((error = aac_setup_intr(sc)) != 0)
30704f4d586SEd Maste 		return(error);
3087cb209f5SScott Long 
3097cb209f5SScott Long 	/*
31035863739SMike Smith 	 * Print a little information about the controller.
31135863739SMike Smith 	 */
31235863739SMike Smith 	aac_describe_controller(sc);
31335863739SMike Smith 
31435863739SMike Smith 	/*
315ae543596SScott Long 	 * Register to probe our containers later.
316ae543596SScott Long 	 */
31735863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
31835863739SMike Smith 	sc->aac_ich.ich_arg = sc;
31935863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
320914da7d0SScott Long 		device_printf(sc->aac_dev,
321914da7d0SScott Long 			      "can't establish configuration hook\n");
32235863739SMike Smith 		return(ENXIO);
32335863739SMike Smith 	}
32435863739SMike Smith 
32535863739SMike Smith 	/*
32635863739SMike Smith 	 * Make the control device.
32735863739SMike Smith 	 */
32835863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3299e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3309e9466baSRobert Watson 				 0640, "aac%d", unit);
331157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3324aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
33335863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
33435863739SMike Smith 
33536e0bf6eSScott Long 	/* Create the AIF thread */
3363745c395SJulian Elischer 	if (kproc_create((void(*)(void *))aac_command_thread, sc,
337316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
338a620bad0SEd Maste 		panic("Could not create AIF thread");
33936e0bf6eSScott Long 
34036e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3415f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3425f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3435f54d522SScott Long 		device_printf(sc->aac_dev,
3445f54d522SScott Long 			      "shutdown event registration failed\n");
34536e0bf6eSScott Long 
346fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
347a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
34870545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
349fe3cb0e1SScott Long 		aac_get_bus_info(sc);
35070545d1aSScott Long 	}
351fe3cb0e1SScott Long 
35235863739SMike Smith 	return(0);
35335863739SMike Smith }
35435863739SMike Smith 
3557cb209f5SScott Long void
3567cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3577cb209f5SScott Long {
3587cb209f5SScott Long 
3597cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3607cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3617cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3627cb209f5SScott Long 		break;
3637cb209f5SScott Long 	default:
3647cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3657cb209f5SScott Long 		    event->ev_type);
3667cb209f5SScott Long 		break;
3677cb209f5SScott Long 	}
3687cb209f5SScott Long 
3697cb209f5SScott Long 	return;
3707cb209f5SScott Long }
3717cb209f5SScott Long 
372914da7d0SScott Long /*
37304f4d586SEd Maste  * Request information of container #cid
37404f4d586SEd Maste  */
37504f4d586SEd Maste static struct aac_mntinforesp *
37604f4d586SEd Maste aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid)
37704f4d586SEd Maste {
37804f4d586SEd Maste 	struct aac_mntinfo *mi;
37904f4d586SEd Maste 
38004f4d586SEd Maste 	mi = (struct aac_mntinfo *)&fib->data[0];
381523da39bSEd Maste 	/* use 64-bit LBA if enabled */
382523da39bSEd Maste 	mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ?
383523da39bSEd Maste 	    VM_NameServe64 : VM_NameServe;
38404f4d586SEd Maste 	mi->MntType = FT_FILESYS;
38504f4d586SEd Maste 	mi->MntCount = cid;
38604f4d586SEd Maste 
38704f4d586SEd Maste 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
38804f4d586SEd Maste 			 sizeof(struct aac_mntinfo))) {
389a620bad0SEd Maste 		printf("Error probing container %d\n", cid);
39004f4d586SEd Maste 		return (NULL);
39104f4d586SEd Maste 	}
39204f4d586SEd Maste 
39304f4d586SEd Maste 	return ((struct aac_mntinforesp *)&fib->data[0]);
39404f4d586SEd Maste }
39504f4d586SEd Maste 
39604f4d586SEd Maste /*
39735863739SMike Smith  * Probe for containers, create disks.
39835863739SMike Smith  */
39935863739SMike Smith static void
40035863739SMike Smith aac_startup(void *arg)
40135863739SMike Smith {
402914da7d0SScott Long 	struct aac_softc *sc;
403cbfd045bSScott Long 	struct aac_fib *fib;
40404f4d586SEd Maste 	struct aac_mntinforesp *mir;
405795d7dc0SScott Long 	int count = 0, i = 0;
40635863739SMike Smith 
407914da7d0SScott Long 	sc = (struct aac_softc *)arg;
40831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
409914da7d0SScott Long 
41035863739SMike Smith 	/* disconnect ourselves from the intrhook chain */
41135863739SMike Smith 	config_intrhook_disestablish(&sc->aac_ich);
41235863739SMike Smith 
4137cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
41403b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
415cbfd045bSScott Long 
41635863739SMike Smith 	/* loop over possible containers */
41736e0bf6eSScott Long 	do {
41804f4d586SEd Maste 		if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
41935863739SMike Smith 			continue;
42004f4d586SEd Maste 		if (i == 0)
421795d7dc0SScott Long 			count = mir->MntRespCount;
422cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
42336e0bf6eSScott Long 		i++;
424795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
425cbfd045bSScott Long 
426cbfd045bSScott Long 	aac_release_sync_fib(sc);
4277cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
42835863739SMike Smith 
42935863739SMike Smith 	/* poke the bus to actually attach the child devices */
43035863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
43135863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
43235863739SMike Smith 
43335863739SMike Smith 	/* mark the controller up */
43435863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
43535863739SMike Smith 
43635863739SMike Smith 	/* enable interrupts now */
43735863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
43835863739SMike Smith }
43935863739SMike Smith 
440914da7d0SScott Long /*
4414109ba51SEd Maste  * Create a device to represent a new container
442914da7d0SScott Long  */
443914da7d0SScott Long static void
444cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
445914da7d0SScott Long {
446914da7d0SScott Long 	struct aac_container *co;
447914da7d0SScott Long 	device_t child;
448914da7d0SScott Long 
449914da7d0SScott Long 	/*
450914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
451914da7d0SScott Long 	 * the possible types may never show up.
452914da7d0SScott Long 	 */
453914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
454a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
455a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
456914da7d0SScott Long 		if (co == NULL)
457a620bad0SEd Maste 			panic("Out of memory?!");
45831a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x  name '%.16s'  size %u  type %d",
459914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
460914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
461914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
462914da7d0SScott Long 
463fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
464914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
465914da7d0SScott Long 		else
466914da7d0SScott Long 			device_set_ivars(child, co);
467914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
468914da7d0SScott Long 				mir->MntTable[0].VolType));
469914da7d0SScott Long 		co->co_disk = child;
470914da7d0SScott Long 		co->co_found = f;
471914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
472914da7d0SScott Long 		      sizeof(struct aac_mntobj));
473bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
474914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
475bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
476914da7d0SScott Long 	}
477914da7d0SScott Long }
478914da7d0SScott Long 
479914da7d0SScott Long /*
48004f4d586SEd Maste  * Allocate resources associated with (sc)
48104f4d586SEd Maste  */
48204f4d586SEd Maste static int
48304f4d586SEd Maste aac_alloc(struct aac_softc *sc)
48404f4d586SEd Maste {
48531a0399eSEd Maste 
48631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
48731a0399eSEd Maste 
48804f4d586SEd Maste 	/*
48904f4d586SEd Maste 	 * Create DMA tag for mapping buffers into controller-addressable space.
49004f4d586SEd Maste 	 */
49104f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
49204f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
49304f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
49404f4d586SEd Maste 			       BUS_SPACE_MAXADDR :
49504f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
49604f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
49704f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
49804f4d586SEd Maste 			       MAXBSIZE,		/* maxsize */
49904f4d586SEd Maste 			       sc->aac_sg_tablesize,	/* nsegments */
50004f4d586SEd Maste 			       MAXBSIZE,		/* maxsegsize */
50104f4d586SEd Maste 			       BUS_DMA_ALLOCNOW,	/* flags */
50204f4d586SEd Maste 			       busdma_lock_mutex,	/* lockfunc */
50304f4d586SEd Maste 			       &sc->aac_io_lock,	/* lockfuncarg */
50404f4d586SEd Maste 			       &sc->aac_buffer_dmat)) {
50504f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
50604f4d586SEd Maste 		return (ENOMEM);
50704f4d586SEd Maste 	}
50804f4d586SEd Maste 
50904f4d586SEd Maste 	/*
51004f4d586SEd Maste 	 * Create DMA tag for mapping FIBs into controller-addressable space..
51104f4d586SEd Maste 	 */
51204f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
51304f4d586SEd Maste 			       1, 0, 			/* algnmnt, boundary */
51404f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
51504f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
51604f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
51704f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
51804f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
51904f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
52004f4d586SEd Maste 			       sc->aac_max_fib_size,  /* maxsize */
52104f4d586SEd Maste 			       1,			/* nsegments */
52204f4d586SEd Maste 			       sc->aac_max_fibs_alloc *
52304f4d586SEd Maste 			       sc->aac_max_fib_size,	/* maxsize */
52404f4d586SEd Maste 			       0,			/* flags */
52504f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
52604f4d586SEd Maste 			       &sc->aac_fib_dmat)) {
52704f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
52804f4d586SEd Maste 		return (ENOMEM);
52904f4d586SEd Maste 	}
53004f4d586SEd Maste 
53104f4d586SEd Maste 	/*
53204f4d586SEd Maste 	 * Create DMA tag for the common structure and allocate it.
53304f4d586SEd Maste 	 */
53404f4d586SEd Maste 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
53504f4d586SEd Maste 			       1, 0,			/* algnmnt, boundary */
53604f4d586SEd Maste 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
53704f4d586SEd Maste 			       BUS_SPACE_MAXADDR_32BIT :
53804f4d586SEd Maste 			       0x7fffffff,		/* lowaddr */
53904f4d586SEd Maste 			       BUS_SPACE_MAXADDR, 	/* highaddr */
54004f4d586SEd Maste 			       NULL, NULL, 		/* filter, filterarg */
54104f4d586SEd Maste 			       8192 + sizeof(struct aac_common), /* maxsize */
54204f4d586SEd Maste 			       1,			/* nsegments */
54304f4d586SEd Maste 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
54404f4d586SEd Maste 			       0,			/* flags */
54504f4d586SEd Maste 			       NULL, NULL,		/* No locking needed */
54604f4d586SEd Maste 			       &sc->aac_common_dmat)) {
54704f4d586SEd Maste 		device_printf(sc->aac_dev,
54804f4d586SEd Maste 			      "can't allocate common structure DMA tag\n");
54904f4d586SEd Maste 		return (ENOMEM);
55004f4d586SEd Maste 	}
55104f4d586SEd Maste 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
55204f4d586SEd Maste 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
55304f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate common structure\n");
55404f4d586SEd Maste 		return (ENOMEM);
55504f4d586SEd Maste 	}
55604f4d586SEd Maste 
55704f4d586SEd Maste 	/*
55804f4d586SEd Maste 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
55904f4d586SEd Maste 	 * below address 8192 in physical memory.
56004f4d586SEd Maste 	 * XXX If the padding is not needed, can it be put to use instead
56104f4d586SEd Maste 	 * of ignored?
56204f4d586SEd Maste 	 */
56304f4d586SEd Maste 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
56404f4d586SEd Maste 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
56504f4d586SEd Maste 			aac_common_map, sc, 0);
56604f4d586SEd Maste 
56704f4d586SEd Maste 	if (sc->aac_common_busaddr < 8192) {
56804f4d586SEd Maste 		sc->aac_common = (struct aac_common *)
56904f4d586SEd Maste 		    ((uint8_t *)sc->aac_common + 8192);
57004f4d586SEd Maste 		sc->aac_common_busaddr += 8192;
57104f4d586SEd Maste 	}
57204f4d586SEd Maste 	bzero(sc->aac_common, sizeof(*sc->aac_common));
57304f4d586SEd Maste 
57404f4d586SEd Maste 	/* Allocate some FIBs and associated command structs */
57504f4d586SEd Maste 	TAILQ_INIT(&sc->aac_fibmap_tqh);
57604f4d586SEd Maste 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
57704f4d586SEd Maste 				  M_AACBUF, M_WAITOK|M_ZERO);
57804f4d586SEd Maste 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
57904f4d586SEd Maste 		if (aac_alloc_commands(sc) != 0)
58004f4d586SEd Maste 			break;
58104f4d586SEd Maste 	}
58204f4d586SEd Maste 	if (sc->total_fibs == 0)
58304f4d586SEd Maste 		return (ENOMEM);
58404f4d586SEd Maste 
58504f4d586SEd Maste 	return (0);
58604f4d586SEd Maste }
58704f4d586SEd Maste 
58804f4d586SEd Maste /*
58935863739SMike Smith  * Free all of the resources associated with (sc)
59035863739SMike Smith  *
59135863739SMike Smith  * Should not be called if the controller is active.
59235863739SMike Smith  */
59335863739SMike Smith void
59435863739SMike Smith aac_free(struct aac_softc *sc)
59535863739SMike Smith {
596ffb37f33SScott Long 
59731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
59835863739SMike Smith 
59935863739SMike Smith 	/* remove the control device */
60035863739SMike Smith 	if (sc->aac_dev_t != NULL)
60135863739SMike Smith 		destroy_dev(sc->aac_dev_t);
60235863739SMike Smith 
6030b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
6048480cc63SScott Long 	aac_free_commands(sc);
6050b94a66eSMike Smith 	if (sc->aac_fib_dmat)
6060b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
60735863739SMike Smith 
608ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
609ffb37f33SScott Long 
61035863739SMike Smith 	/* destroy the common area */
61135863739SMike Smith 	if (sc->aac_common) {
61235863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
613c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
614c6eafcf2SScott Long 				sc->aac_common_dmamap);
61535863739SMike Smith 	}
6160b94a66eSMike Smith 	if (sc->aac_common_dmat)
6170b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
61835863739SMike Smith 
61935863739SMike Smith 	/* disconnect the interrupt handler */
62035863739SMike Smith 	if (sc->aac_intr)
62135863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
62235863739SMike Smith 	if (sc->aac_irq != NULL)
623c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
624c6eafcf2SScott Long 				     sc->aac_irq);
62535863739SMike Smith 
62635863739SMike Smith 	/* destroy data-transfer DMA tag */
62735863739SMike Smith 	if (sc->aac_buffer_dmat)
62835863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
62935863739SMike Smith 
63035863739SMike Smith 	/* destroy the parent DMA tag */
63135863739SMike Smith 	if (sc->aac_parent_dmat)
63235863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
63335863739SMike Smith 
63435863739SMike Smith 	/* release the register window mapping */
63535863739SMike Smith 	if (sc->aac_regs_resource != NULL)
636914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
637914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
63835863739SMike Smith }
63935863739SMike Smith 
640914da7d0SScott Long /*
64135863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
64235863739SMike Smith  */
64335863739SMike Smith int
64435863739SMike Smith aac_detach(device_t dev)
64535863739SMike Smith {
646914da7d0SScott Long 	struct aac_softc *sc;
64770545d1aSScott Long 	struct aac_container *co;
64870545d1aSScott Long 	struct aac_sim	*sim;
64935863739SMike Smith 	int error;
65035863739SMike Smith 
651914da7d0SScott Long 	sc = device_get_softc(dev);
65231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
653914da7d0SScott Long 
65435863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
65535863739SMike Smith 		return(EBUSY);
65635863739SMike Smith 
65770545d1aSScott Long 	/* Remove the child containers */
658a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
65970545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
66070545d1aSScott Long 		if (error)
66170545d1aSScott Long 			return (error);
66265ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
663a761a1caSScott Long 		free(co, M_AACBUF);
66470545d1aSScott Long 	}
66570545d1aSScott Long 
66670545d1aSScott Long 	/* Remove the CAM SIMs */
667a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
668a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
66970545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
67070545d1aSScott Long 		if (error)
67170545d1aSScott Long 			return (error);
672a761a1caSScott Long 		free(sim, M_AACBUF);
67370545d1aSScott Long 	}
67470545d1aSScott Long 
67536e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
67636e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
67736e0bf6eSScott Long 		wakeup(sc->aifthread);
67836e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
67936e0bf6eSScott Long 	}
68036e0bf6eSScott Long 
68136e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
682a620bad0SEd Maste 		panic("Cannot shutdown AIF thread");
68336e0bf6eSScott Long 
68435863739SMike Smith 	if ((error = aac_shutdown(dev)))
68535863739SMike Smith 		return(error);
68635863739SMike Smith 
6875f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
6885f54d522SScott Long 
68935863739SMike Smith 	aac_free(sc);
69035863739SMike Smith 
691dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
692dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
693dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
694dc9efde5SScott Long 
69535863739SMike Smith 	return(0);
69635863739SMike Smith }
69735863739SMike Smith 
698914da7d0SScott Long /*
69935863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
70035863739SMike Smith  *
70135863739SMike Smith  * This function is called before detach or system shutdown.
70235863739SMike Smith  *
7030b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
70435863739SMike Smith  * allow shutdown if any device is open.
70535863739SMike Smith  */
70635863739SMike Smith int
70735863739SMike Smith aac_shutdown(device_t dev)
70835863739SMike Smith {
709914da7d0SScott Long 	struct aac_softc *sc;
710cbfd045bSScott Long 	struct aac_fib *fib;
711cbfd045bSScott Long 	struct aac_close_command *cc;
71235863739SMike Smith 
713914da7d0SScott Long 	sc = device_get_softc(dev);
71431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
715914da7d0SScott Long 
71635863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
71735863739SMike Smith 
71835863739SMike Smith 	/*
71935863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
72035863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
72135863739SMike Smith 	 * We've been closed and all I/O completed already
72235863739SMike Smith 	 */
72335863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
72435863739SMike Smith 
7257cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
72603b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
727cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
728cbfd045bSScott Long 
72939ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
730cbfd045bSScott Long 	cc->Command = VM_CloseAll;
731cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
732cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
733cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
73435863739SMike Smith 		printf("FAILED.\n");
73570545d1aSScott Long 	else
73670545d1aSScott Long 		printf("done\n");
73770545d1aSScott Long #if 0
738914da7d0SScott Long 	else {
739cbfd045bSScott Long 		fib->data[0] = 0;
74036e0bf6eSScott Long 		/*
741914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
74236e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
74336e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
74436e0bf6eSScott Long 		 * driver module with the intent to reload it later.
74536e0bf6eSScott Long 		 */
746cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
747cbfd045bSScott Long 		    fib, 1)) {
74835863739SMike Smith 			printf("FAILED.\n");
74935863739SMike Smith 		} else {
75035863739SMike Smith 			printf("done.\n");
75135863739SMike Smith 		}
75235863739SMike Smith 	}
75370545d1aSScott Long #endif
75435863739SMike Smith 
75535863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
7563576af8fSScott Long 	aac_release_sync_fib(sc);
7577cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
75835863739SMike Smith 
75935863739SMike Smith 	return(0);
76035863739SMike Smith }
76135863739SMike Smith 
762914da7d0SScott Long /*
76335863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
76435863739SMike Smith  */
76535863739SMike Smith int
76635863739SMike Smith aac_suspend(device_t dev)
76735863739SMike Smith {
768914da7d0SScott Long 	struct aac_softc *sc;
76935863739SMike Smith 
770914da7d0SScott Long 	sc = device_get_softc(dev);
771914da7d0SScott Long 
77231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
77335863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
77435863739SMike Smith 
77535863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
77635863739SMike Smith 	return(0);
77735863739SMike Smith }
77835863739SMike Smith 
779914da7d0SScott Long /*
78035863739SMike Smith  * Bring the controller back to a state ready for operation.
78135863739SMike Smith  */
78235863739SMike Smith int
78335863739SMike Smith aac_resume(device_t dev)
78435863739SMike Smith {
785914da7d0SScott Long 	struct aac_softc *sc;
78635863739SMike Smith 
787914da7d0SScott Long 	sc = device_get_softc(dev);
788914da7d0SScott Long 
78931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
79035863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
79135863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
79235863739SMike Smith 	return(0);
79335863739SMike Smith }
79435863739SMike Smith 
795914da7d0SScott Long /*
7967cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
79735863739SMike Smith  */
79835863739SMike Smith void
7997cb209f5SScott Long aac_new_intr(void *arg)
8007cb209f5SScott Long {
8017cb209f5SScott Long 	struct aac_softc *sc;
8027cb209f5SScott Long 	u_int32_t index, fast;
8037cb209f5SScott Long 	struct aac_command *cm;
8047cb209f5SScott Long 	struct aac_fib *fib;
8057cb209f5SScott Long 	int i;
8067cb209f5SScott Long 
8077cb209f5SScott Long 	sc = (struct aac_softc *)arg;
8087cb209f5SScott Long 
80931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
8107cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
8117cb209f5SScott Long 	while (1) {
8127cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
8137cb209f5SScott Long 		if (index == 0xffffffff)
8147cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
8157cb209f5SScott Long 		if (index == 0xffffffff)
8167cb209f5SScott Long 			break;
8177cb209f5SScott Long 		if (index & 2) {
8187cb209f5SScott Long 			if (index == 0xfffffffe) {
8197cb209f5SScott Long 				/* XXX This means that the controller wants
8207cb209f5SScott Long 				 * more work.  Ignore it for now.
8217cb209f5SScott Long 				 */
8227cb209f5SScott Long 				continue;
8237cb209f5SScott Long 			}
8247cb209f5SScott Long 			/* AIF */
8257cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
8267cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
8277cb209f5SScott Long 			if (fib == NULL) {
8287cb209f5SScott Long 				/* If we're really this short on memory,
8297cb209f5SScott Long 				 * hopefully breaking out of the handler will
8307cb209f5SScott Long 				 * allow something to get freed.  This
8317cb209f5SScott Long 				 * actually sucks a whole lot.
8327cb209f5SScott Long 				 */
8337cb209f5SScott Long 				break;
8347cb209f5SScott Long 			}
8357cb209f5SScott Long 			index &= ~2;
8367cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
8377cb209f5SScott Long 				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
8387cb209f5SScott Long 			aac_handle_aif(sc, fib);
8397cb209f5SScott Long 			free(fib, M_AACBUF);
8407cb209f5SScott Long 
8417cb209f5SScott Long 			/*
8427cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
8437cb209f5SScott Long 			 * know that we are done with it.
8447cb209f5SScott Long 			 */
8457cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
8467cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
8477cb209f5SScott Long 		} else {
8487cb209f5SScott Long 			fast = index & 1;
8497cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
8507cb209f5SScott Long 			fib = cm->cm_fib;
8517cb209f5SScott Long 			if (fast) {
8527cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
8537cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
8547cb209f5SScott Long 			}
8557cb209f5SScott Long 			aac_remove_busy(cm);
8567cb209f5SScott Long  			aac_unmap_command(cm);
8577cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
8587cb209f5SScott Long 
8597cb209f5SScott Long 			/* is there a completion handler? */
8607cb209f5SScott Long 			if (cm->cm_complete != NULL) {
8617cb209f5SScott Long 				cm->cm_complete(cm);
8627cb209f5SScott Long 			} else {
8637cb209f5SScott Long 				/* assume that someone is sleeping on this
8647cb209f5SScott Long 				 * command
8657cb209f5SScott Long 				 */
8667cb209f5SScott Long 				wakeup(cm);
8677cb209f5SScott Long 			}
8687cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
8697cb209f5SScott Long 		}
8707cb209f5SScott Long 	}
8717cb209f5SScott Long 	/* see if we can start some more I/O */
8727cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
8737cb209f5SScott Long 		aac_startio(sc);
8747cb209f5SScott Long 
8757cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
8767cb209f5SScott Long }
8777cb209f5SScott Long 
878ef544f63SPaolo Pisati int
8797cb209f5SScott Long aac_fast_intr(void *arg)
88035863739SMike Smith {
881914da7d0SScott Long 	struct aac_softc *sc;
88270545d1aSScott Long 	u_int16_t reason;
88335863739SMike Smith 
884914da7d0SScott Long 	sc = (struct aac_softc *)arg;
885914da7d0SScott Long 
88631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
887f30ac74cSScott Long 	/*
8889148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
8899148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
8909148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
8919148fa21SScott Long 	 * ugly.
892f30ac74cSScott Long 	 */
89335863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
894f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
895f30ac74cSScott Long 
8969c3a7fceSScott Long 	/* handle completion processing */
8979148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
8989148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
89935863739SMike Smith 
9009148fa21SScott Long 	/* controller wants to talk to us */
9019148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
90270545d1aSScott Long 		/*
9039148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
9049148fa21SScott Long 		 * that start with a NULL.
90570545d1aSScott Long 		 */
9069148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
9079148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
9089148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
90970545d1aSScott Long 
9109148fa21SScott Long 		/*
9119148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
912a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
9139148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
9149148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
9159148fa21SScott Long 		 * if needed.
9169148fa21SScott Long 		 */
91736e0bf6eSScott Long 		wakeup(sc->aifthread);
91836e0bf6eSScott Long 	}
919ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
9209148fa21SScott Long }
92135863739SMike Smith 
922c6eafcf2SScott Long /*
923914da7d0SScott Long  * Command Processing
924914da7d0SScott Long  */
92535863739SMike Smith 
926914da7d0SScott Long /*
92735863739SMike Smith  * Start as much queued I/O as possible on the controller
92835863739SMike Smith  */
929fe3cb0e1SScott Long void
93035863739SMike Smith aac_startio(struct aac_softc *sc)
93135863739SMike Smith {
93235863739SMike Smith 	struct aac_command *cm;
933397fa34fSScott Long 	int error;
93435863739SMike Smith 
93531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
93635863739SMike Smith 
93735863739SMike Smith 	for (;;) {
938914da7d0SScott Long 		/*
939397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
940397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
941397fa34fSScott Long 		 */
942397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
943397fa34fSScott Long 			break;
944397fa34fSScott Long 
945397fa34fSScott Long 		/*
946914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
947914da7d0SScott Long 		 * resources
948914da7d0SScott Long 		 */
94935863739SMike Smith 		cm = aac_dequeue_ready(sc);
95035863739SMike Smith 
951914da7d0SScott Long 		/*
952914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
953914da7d0SScott Long 		 * return)
954914da7d0SScott Long 		 */
9550b94a66eSMike Smith 		if (cm == NULL)
95635863739SMike Smith 			aac_bio_command(sc, &cm);
95735863739SMike Smith 
95835863739SMike Smith 		/* nothing to do? */
95935863739SMike Smith 		if (cm == NULL)
96035863739SMike Smith 			break;
96135863739SMike Smith 
962cd481291SScott Long 		/* don't map more than once */
963cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
9644102d44bSScott Long 			panic("aac: command %p already mapped", cm);
96535863739SMike Smith 
966397fa34fSScott Long 		/*
967397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
968397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
969397fa34fSScott Long 		 * busdma.
970397fa34fSScott Long 		 */
971cd481291SScott Long 		if (cm->cm_datalen != 0) {
972397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
973397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
974397fa34fSScott Long 						cm->cm_datalen,
975cd481291SScott Long 						aac_map_command_sg, cm, 0);
976cd481291SScott Long 			if (error == EINPROGRESS) {
97731a0399eSEd Maste 				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
978cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
979cd481291SScott Long 				error = 0;
980614c22b2SScott Long 			} else if (error != 0)
981397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
982a620bad0SEd Maste 				      "busdma", error);
983397fa34fSScott Long 		} else
9848778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
985cd481291SScott Long 	}
98635863739SMike Smith }
98735863739SMike Smith 
988914da7d0SScott Long /*
98935863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
99035863739SMike Smith  */
99135863739SMike Smith static void
99270545d1aSScott Long aac_command_thread(struct aac_softc *sc)
99335863739SMike Smith {
99435863739SMike Smith 	struct aac_fib *fib;
99535863739SMike Smith 	u_int32_t fib_size;
9969148fa21SScott Long 	int size, retval;
99735863739SMike Smith 
99831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
99935863739SMike Smith 
1000bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1001a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
100236e0bf6eSScott Long 
1003a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1004a32a982dSScott Long 
1005a32a982dSScott Long 		retval = 0;
1006a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1007a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1008a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
100936e0bf6eSScott Long 
10109148fa21SScott Long 		/*
10119148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
10129148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
10139148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
10149148fa21SScott Long 		 */
10159148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1016bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
1017a32a982dSScott Long 			aac_alloc_commands(sc);
1018bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
10194102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1020a32a982dSScott Long 			aac_startio(sc);
1021a32a982dSScott Long 		}
10229148fa21SScott Long 
10239148fa21SScott Long 		/*
10249148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
10259148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
10269148fa21SScott Long 		 * always fire.
10279148fa21SScott Long 		 */
10289148fa21SScott Long 		if (retval == EWOULDBLOCK)
102970545d1aSScott Long 			aac_timeout(sc);
103070545d1aSScott Long 
103170545d1aSScott Long 		/* Check the hardware printf message buffer */
10329148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
103370545d1aSScott Long 			aac_print_printf(sc);
103470545d1aSScott Long 
10359148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
10367cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
10377cb209f5SScott Long 			continue;
10387cb209f5SScott Long 		for (;;) {
10397cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
10407cb209f5SScott Long 					   &fib_size, &fib))
10417cb209f5SScott Long 				break;
104235863739SMike Smith 
104336e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
104436e0bf6eSScott Long 
104535863739SMike Smith 			switch (fib->Header.Command) {
104635863739SMike Smith 			case AifRequest:
104736e0bf6eSScott Long 				aac_handle_aif(sc, fib);
104835863739SMike Smith 				break;
104935863739SMike Smith 			default:
1050914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
1051914da7d0SScott Long 					      "from controller\n");
105235863739SMike Smith 				break;
105335863739SMike Smith 			}
105435863739SMike Smith 
105536e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
10567cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
105736e0bf6eSScott Long 				break;
10587cb209f5SScott Long 			}
105936e0bf6eSScott Long 
106070545d1aSScott Long 			/* Return the AIF to the controller. */
106136e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
106236e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
106336e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
106436e0bf6eSScott Long 
106536e0bf6eSScott Long 				/* XXX Compute the Size field? */
106636e0bf6eSScott Long 				size = fib->Header.Size;
106736e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
106836e0bf6eSScott Long 					size = sizeof(struct aac_fib);
106936e0bf6eSScott Long 					fib->Header.Size = size;
107036e0bf6eSScott Long 				}
107136e0bf6eSScott Long 				/*
1072914da7d0SScott Long 				 * Since we did not generate this command, it
1073914da7d0SScott Long 				 * cannot go through the normal
1074914da7d0SScott Long 				 * enqueue->startio chain.
107536e0bf6eSScott Long 				 */
1076914da7d0SScott Long 				aac_enqueue_response(sc,
1077914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
1078914da7d0SScott Long 						 fib);
107936e0bf6eSScott Long 			}
108036e0bf6eSScott Long 		}
108136e0bf6eSScott Long 	}
108236e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1083bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
108436e0bf6eSScott Long 	wakeup(sc->aac_dev);
108536e0bf6eSScott Long 
10863745c395SJulian Elischer 	kproc_exit(0);
108735863739SMike Smith }
108835863739SMike Smith 
1089914da7d0SScott Long /*
10909c3a7fceSScott Long  * Process completed commands.
109135863739SMike Smith  */
109235863739SMike Smith static void
10939c3a7fceSScott Long aac_complete(void *context, int pending)
109435863739SMike Smith {
10959c3a7fceSScott Long 	struct aac_softc *sc;
109635863739SMike Smith 	struct aac_command *cm;
109735863739SMike Smith 	struct aac_fib *fib;
109835863739SMike Smith 	u_int32_t fib_size;
109935863739SMike Smith 
11009c3a7fceSScott Long 	sc = (struct aac_softc *)context;
110131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
11029c3a7fceSScott Long 
1103bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1104ae543596SScott Long 
11059c3a7fceSScott Long 	/* pull completed commands off the queue */
110635863739SMike Smith 	for (;;) {
110735863739SMike Smith 		/* look for completed FIBs on our queue */
1108914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1109914da7d0SScott Long 							&fib))
111035863739SMike Smith 			break;	/* nothing to do */
111135863739SMike Smith 
1112ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1113cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
111435863739SMike Smith 		if (cm == NULL) {
111535863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
11169c3a7fceSScott Long 			break;
11179c3a7fceSScott Long 		}
11180b94a66eSMike Smith 		aac_remove_busy(cm);
11197cb209f5SScott Long 
1120ecd1c51fSScott Long  		aac_unmap_command(cm);
112135863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
112235863739SMike Smith 
112335863739SMike Smith 		/* is there a completion handler? */
112435863739SMike Smith 		if (cm->cm_complete != NULL) {
112535863739SMike Smith 			cm->cm_complete(cm);
112635863739SMike Smith 		} else {
112735863739SMike Smith 			/* assume that someone is sleeping on this command */
112835863739SMike Smith 			wakeup(cm);
112935863739SMike Smith 		}
113035863739SMike Smith 	}
11310b94a66eSMike Smith 
11320b94a66eSMike Smith 	/* see if we can start some more I/O */
1133cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
11340b94a66eSMike Smith 	aac_startio(sc);
1135ae543596SScott Long 
1136bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
113735863739SMike Smith }
113835863739SMike Smith 
1139914da7d0SScott Long /*
114035863739SMike Smith  * Handle a bio submitted from a disk device.
114135863739SMike Smith  */
114235863739SMike Smith void
114335863739SMike Smith aac_submit_bio(struct bio *bp)
114435863739SMike Smith {
1145914da7d0SScott Long 	struct aac_disk *ad;
1146914da7d0SScott Long 	struct aac_softc *sc;
114735863739SMike Smith 
11487540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1149914da7d0SScott Long 	sc = ad->ad_controller;
115031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1151914da7d0SScott Long 
115235863739SMike Smith 	/* queue the BIO and try to get some work done */
11530b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
115435863739SMike Smith 	aac_startio(sc);
115535863739SMike Smith }
115635863739SMike Smith 
1157914da7d0SScott Long /*
115835863739SMike Smith  * Get a bio and build a command to go with it.
115935863739SMike Smith  */
116035863739SMike Smith static int
116135863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
116235863739SMike Smith {
116335863739SMike Smith 	struct aac_command *cm;
116435863739SMike Smith 	struct aac_fib *fib;
116535863739SMike Smith 	struct aac_disk *ad;
116635863739SMike Smith 	struct bio *bp;
116735863739SMike Smith 
116831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
116935863739SMike Smith 
117035863739SMike Smith 	/* get the resources we will need */
117135863739SMike Smith 	cm = NULL;
1172a32a982dSScott Long 	bp = NULL;
117335863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
117435863739SMike Smith 		goto fail;
1175a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1176a32a982dSScott Long 		goto fail;
117735863739SMike Smith 
117835863739SMike Smith 	/* fill out the command */
11790b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
11800b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
11810b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
118235863739SMike Smith 	cm->cm_private = bp;
11832b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
118436e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
118535863739SMike Smith 
118635863739SMike Smith 	/* build the FIB */
118735863739SMike Smith 	fib = cm->cm_fib;
1188b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
118935863739SMike Smith 	fib->Header.XferState =
119035863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
119135863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1192f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
119335863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
119435863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1195f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1196f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1197f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
119835863739SMike Smith 
119935863739SMike Smith 	/* build the read/write request */
12007540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1201b85f5808SScott Long 
12027cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
12037cb209f5SScott Long 		struct aac_raw_io *raw;
12047cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
12057cb209f5SScott Long 		fib->Header.Command = RawIo;
12067cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
12077cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
12087cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
12097cb209f5SScott Long 		raw->BpTotal = 0;
12107cb209f5SScott Long 		raw->BpComplete = 0;
12117cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
12127cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
12137cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
12147cb209f5SScott Long 			raw->Flags = 1;
12157cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
12167cb209f5SScott Long 		} else {
12177cb209f5SScott Long 			raw->Flags = 0;
12187cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
12197cb209f5SScott Long 		}
12207cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1221b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
12229e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1223b85f5808SScott Long 			struct aac_blockread *br;
122435863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
122535863739SMike Smith 			br->Command = VM_CtBlockRead;
122635863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
122735863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
122835863739SMike Smith 			br->ByteCount = bp->bio_bcount;
122935863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
123035863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
123135863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
123235863739SMike Smith 		} else {
1233b85f5808SScott Long 			struct aac_blockwrite *bw;
123435863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
123535863739SMike Smith 			bw->Command = VM_CtBlockWrite;
123635863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
123735863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
123835863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1239b85f5808SScott Long 			bw->Stable = CUNSTABLE;
124035863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
124135863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
124235863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
124335863739SMike Smith 		}
1244b85f5808SScott Long 	} else {
1245b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1246b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1247b85f5808SScott Long 			struct aac_blockread64 *br;
1248b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1249b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1250b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1251b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1252b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1253b85f5808SScott Long 			br->Pad = 0;
1254b85f5808SScott Long 			br->Flags = 0;
1255b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
125654e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAIN;
1257eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1258b85f5808SScott Long 		} else {
1259b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1260b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1261b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1262b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1263b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1264b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1265b85f5808SScott Long 			bw->Pad = 0;
1266b85f5808SScott Long 			bw->Flags = 0;
1267b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
126854e2ebdfSEd Maste 			cm->cm_flags |= AAC_CMD_DATAOUT;
1269eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1270b85f5808SScott Long 		}
1271b85f5808SScott Long 	}
127235863739SMike Smith 
127335863739SMike Smith 	*cmp = cm;
127435863739SMike Smith 	return(0);
127535863739SMike Smith 
127635863739SMike Smith fail:
12777cb209f5SScott Long 	if (bp != NULL)
12787cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
127935863739SMike Smith 	if (cm != NULL)
128035863739SMike Smith 		aac_release_command(cm);
128135863739SMike Smith 	return(ENOMEM);
128235863739SMike Smith }
128335863739SMike Smith 
1284914da7d0SScott Long /*
128535863739SMike Smith  * Handle a bio-instigated command that has been completed.
128635863739SMike Smith  */
128735863739SMike Smith static void
128835863739SMike Smith aac_bio_complete(struct aac_command *cm)
128935863739SMike Smith {
129035863739SMike Smith 	struct aac_blockread_response *brr;
129135863739SMike Smith 	struct aac_blockwrite_response *bwr;
129235863739SMike Smith 	struct bio *bp;
129335863739SMike Smith 	AAC_FSAStatus status;
129435863739SMike Smith 
129535863739SMike Smith 	/* fetch relevant status and then release the command */
129635863739SMike Smith 	bp = (struct bio *)cm->cm_private;
12979e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
129835863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
129935863739SMike Smith 		status = brr->Status;
130035863739SMike Smith 	} else {
130135863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
130235863739SMike Smith 		status = bwr->Status;
130335863739SMike Smith 	}
130435863739SMike Smith 	aac_release_command(cm);
130535863739SMike Smith 
130635863739SMike Smith 	/* fix up the bio based on status */
130735863739SMike Smith 	if (status == ST_OK) {
130835863739SMike Smith 		bp->bio_resid = 0;
130935863739SMike Smith 	} else {
131035863739SMike Smith 		bp->bio_error = EIO;
131135863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
13120b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1313914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1314914da7d0SScott Long 						    status);
131535863739SMike Smith 	}
13160b94a66eSMike Smith 	aac_biodone(bp);
131735863739SMike Smith }
131835863739SMike Smith 
1319914da7d0SScott Long /*
132035863739SMike Smith  * Submit a command to the controller, return when it completes.
1321b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1322b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1323d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1324d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1325d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1326d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1327d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
132835863739SMike Smith  */
132935863739SMike Smith static int
1330d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
133135863739SMike Smith {
1332ae543596SScott Long 	struct aac_softc *sc;
1333d8a0a473SScott Long 	int error;
133435863739SMike Smith 
1335ae543596SScott Long 	sc = cm->cm_sc;
133631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1337ae543596SScott Long 
133835863739SMike Smith 	/* Put the command on the ready queue and get things going */
133936e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
134035863739SMike Smith 	aac_enqueue_ready(cm);
1341ae543596SScott Long 	aac_startio(sc);
1342ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
134335863739SMike Smith 	return(error);
134435863739SMike Smith }
134535863739SMike Smith 
1346914da7d0SScott Long /*
1347914da7d0SScott Long  *Command Buffer Management
1348914da7d0SScott Long  */
134935863739SMike Smith 
1350914da7d0SScott Long /*
135135863739SMike Smith  * Allocate a command.
135235863739SMike Smith  */
1353fe3cb0e1SScott Long int
135435863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
135535863739SMike Smith {
135635863739SMike Smith 	struct aac_command *cm;
135735863739SMike Smith 
135831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
135935863739SMike Smith 
1360ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1361b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1362ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1363ae543596SScott Long 			wakeup(sc->aifthread);
1364b85f5808SScott Long 		}
1365ae543596SScott Long 		return (EBUSY);
1366ffb37f33SScott Long 	}
136735863739SMike Smith 
13680b94a66eSMike Smith 	*cmp = cm;
13690b94a66eSMike Smith 	return(0);
13700b94a66eSMike Smith }
13710b94a66eSMike Smith 
1372914da7d0SScott Long /*
13730b94a66eSMike Smith  * Release a command back to the freelist.
13740b94a66eSMike Smith  */
1375fe3cb0e1SScott Long void
13760b94a66eSMike Smith aac_release_command(struct aac_command *cm)
13770b94a66eSMike Smith {
13787cb209f5SScott Long 	struct aac_event *event;
13797cb209f5SScott Long 	struct aac_softc *sc;
13807cb209f5SScott Long 
138131a0399eSEd Maste 	sc = cm->cm_sc;
138231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
13830b94a66eSMike Smith 
13844109ba51SEd Maste 	/* (re)initialize the command/FIB */
138535863739SMike Smith 	cm->cm_sgtable = NULL;
138635863739SMike Smith 	cm->cm_flags = 0;
138735863739SMike Smith 	cm->cm_complete = NULL;
138835863739SMike Smith 	cm->cm_private = NULL;
138935863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
139035863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
139135863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
13927cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
139335863739SMike Smith 
139435863739SMike Smith 	/*
139535863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
139635863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
13974109ba51SEd Maste 	 * initialized here for debugging purposes only.
139835863739SMike Smith 	 */
1399f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1400f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
140135863739SMike Smith 
140235863739SMike Smith 	aac_enqueue_free(cm);
14037cb209f5SScott Long 
1404eb5cbaa0SEd Maste 	/*
1405eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1406eb5cbaa0SEd Maste 	 * stranded.
1407eb5cbaa0SEd Maste 	 */
1408eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
14097cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
14107cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
14117cb209f5SScott Long 	}
141235863739SMike Smith }
141335863739SMike Smith 
1414914da7d0SScott Long /*
14150b94a66eSMike Smith  * Map helper for command/FIB allocation.
141635863739SMike Smith  */
141735863739SMike Smith static void
14180b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
141935863739SMike Smith {
14207cb209f5SScott Long 	uint64_t	*fibphys;
1421914da7d0SScott Long 
14227cb209f5SScott Long 	fibphys = (uint64_t *)arg;
142335863739SMike Smith 
1424ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
142535863739SMike Smith }
142635863739SMike Smith 
1427914da7d0SScott Long /*
14284109ba51SEd Maste  * Allocate and initialize commands/FIBs for this adapter.
142935863739SMike Smith  */
14300b94a66eSMike Smith static int
14310b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
143235863739SMike Smith {
143335863739SMike Smith 	struct aac_command *cm;
1434ffb37f33SScott Long 	struct aac_fibmap *fm;
14357cb209f5SScott Long 	uint64_t fibphys;
1436ffb37f33SScott Long 	int i, error;
143735863739SMike Smith 
143831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
143935863739SMike Smith 
14407cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1441ffb37f33SScott Long 		return (ENOMEM);
1442ffb37f33SScott Long 
14438480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1444a6d35632SScott Long 	if (fm == NULL)
1445a6d35632SScott Long 		return (ENOMEM);
1446ffb37f33SScott Long 
14470b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1448ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1449ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
145070545d1aSScott Long 		device_printf(sc->aac_dev,
145170545d1aSScott Long 			      "Not enough contiguous memory available.\n");
14528480cc63SScott Long 		free(fm, M_AACBUF);
14530b94a66eSMike Smith 		return (ENOMEM);
145435863739SMike Smith 	}
1455128aa5a0SScott Long 
1456cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1457cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
14587cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1459ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1460128aa5a0SScott Long 
14614109ba51SEd Maste 	/* initialize constant fields in the command structure */
14627cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
14637cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
14648480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1465ffb37f33SScott Long 		fm->aac_commands = cm;
146635863739SMike Smith 		cm->cm_sc = sc;
14677cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
14687cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
14697cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1470cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
147135863739SMike Smith 
1472ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
147393cfca22SScott Long 					       &cm->cm_datamap)) != 0)
14748480cc63SScott Long 			break;
147593cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
147693cfca22SScott Long 		aac_release_command(cm);
14778480cc63SScott Long 		sc->total_fibs++;
147893cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
147935863739SMike Smith 	}
1480ffb37f33SScott Long 
14818480cc63SScott Long 	if (i > 0) {
148293cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1483ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
148431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1485bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
14860b94a66eSMike Smith 		return (0);
148735863739SMike Smith 	}
148835863739SMike Smith 
14898480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
14908480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
14918480cc63SScott Long 	free(fm, M_AACBUF);
14928480cc63SScott Long 	return (ENOMEM);
14938480cc63SScott Long }
14948480cc63SScott Long 
1495914da7d0SScott Long /*
14960b94a66eSMike Smith  * Free FIBs owned by this adapter.
149735863739SMike Smith  */
149835863739SMike Smith static void
14998480cc63SScott Long aac_free_commands(struct aac_softc *sc)
150035863739SMike Smith {
15018480cc63SScott Long 	struct aac_fibmap *fm;
1502ffb37f33SScott Long 	struct aac_command *cm;
150335863739SMike Smith 	int i;
150435863739SMike Smith 
150531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
150635863739SMike Smith 
15078480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
15088480cc63SScott Long 
15098480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
15108480cc63SScott Long 		/*
15118480cc63SScott Long 		 * We check against total_fibs to handle partially
15128480cc63SScott Long 		 * allocated blocks.
15138480cc63SScott Long 		 */
15147cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1515ffb37f33SScott Long 			cm = fm->aac_commands + i;
1516ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1517ffb37f33SScott Long 		}
1518ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1519ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
15208480cc63SScott Long 		free(fm, M_AACBUF);
15218480cc63SScott Long 	}
152235863739SMike Smith }
152335863739SMike Smith 
1524914da7d0SScott Long /*
152535863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
152635863739SMike Smith  */
152735863739SMike Smith static void
152835863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
152935863739SMike Smith {
1530cd481291SScott Long 	struct aac_softc *sc;
1531914da7d0SScott Long 	struct aac_command *cm;
1532914da7d0SScott Long 	struct aac_fib *fib;
153335863739SMike Smith 	int i;
153435863739SMike Smith 
1535914da7d0SScott Long 	cm = (struct aac_command *)arg;
1536cd481291SScott Long 	sc = cm->cm_sc;
1537914da7d0SScott Long 	fib = cm->cm_fib;
153831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1539914da7d0SScott Long 
154035863739SMike Smith 	/* copy into the FIB */
1541b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
15427cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
15437cb209f5SScott Long 			struct aac_sg_tableraw *sg;
15447cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
15457cb209f5SScott Long 			sg->SgCount = nseg;
15467cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
15477cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
15487cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
15497cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
15507cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
15517cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
15527cb209f5SScott Long 			}
15537cb209f5SScott Long 			/* update the FIB size for the s/g count */
15547cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
15557cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1556b85f5808SScott Long 			struct aac_sg_table *sg;
1557b85f5808SScott Long 			sg = cm->cm_sgtable;
155835863739SMike Smith 			sg->SgCount = nseg;
155935863739SMike Smith 			for (i = 0; i < nseg; i++) {
156035863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
156135863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
156235863739SMike Smith 			}
156335863739SMike Smith 			/* update the FIB size for the s/g count */
156435863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1565b85f5808SScott Long 		} else {
1566b85f5808SScott Long 			struct aac_sg_table64 *sg;
1567b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1568b85f5808SScott Long 			sg->SgCount = nseg;
1569b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1570b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1571b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
157235863739SMike Smith 			}
1573b85f5808SScott Long 			/* update the FIB size for the s/g count */
1574b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1575b85f5808SScott Long 		}
1576b85f5808SScott Long 	}
157735863739SMike Smith 
1578cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1579cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
15807cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
15817cb209f5SScott Long 	 * and for the AIF bit
158235863739SMike Smith 	 */
15837cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
15847cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
158535863739SMike Smith 
1586cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1587cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
158835863739SMike Smith 
158935863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1590c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1591c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
159235863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1593c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1594c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
159535863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1596cd481291SScott Long 
15977cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
15987cb209f5SScott Long 		int count = 10000000L;
15997cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
16007cb209f5SScott Long 			if (--count == 0) {
16017cb209f5SScott Long 				aac_unmap_command(cm);
16027cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
16037cb209f5SScott Long 				aac_requeue_ready(cm);
16047cb209f5SScott Long 			}
16057cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
16067cb209f5SScott Long 		}
16077cb209f5SScott Long 	} else {
1608397fa34fSScott Long 		/* Put the FIB on the outbound queue */
16094102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
16104102d44bSScott Long 			aac_unmap_command(cm);
1611397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1612cd481291SScott Long 			aac_requeue_ready(cm);
16134102d44bSScott Long 		}
16147cb209f5SScott Long 	}
1615cd481291SScott Long 
1616cd481291SScott Long 	return;
161735863739SMike Smith }
161835863739SMike Smith 
1619914da7d0SScott Long /*
162035863739SMike Smith  * Unmap a command from controller-visible space.
162135863739SMike Smith  */
162235863739SMike Smith static void
162335863739SMike Smith aac_unmap_command(struct aac_command *cm)
162435863739SMike Smith {
1625914da7d0SScott Long 	struct aac_softc *sc;
162635863739SMike Smith 
1627914da7d0SScott Long 	sc = cm->cm_sc;
162831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1629914da7d0SScott Long 
163035863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
163135863739SMike Smith 		return;
163235863739SMike Smith 
163335863739SMike Smith 	if (cm->cm_datalen != 0) {
163435863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1635c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1636c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
163735863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1638c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1639c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
164035863739SMike Smith 
164135863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
164235863739SMike Smith 	}
164335863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
164435863739SMike Smith }
164535863739SMike Smith 
1646914da7d0SScott Long /*
1647914da7d0SScott Long  * Hardware Interface
1648914da7d0SScott Long  */
164935863739SMike Smith 
1650914da7d0SScott Long /*
16514109ba51SEd Maste  * Initialize the adapter.
165235863739SMike Smith  */
165335863739SMike Smith static void
165435863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
165535863739SMike Smith {
1656914da7d0SScott Long 	struct aac_softc *sc;
165735863739SMike Smith 
1658914da7d0SScott Long 	sc = (struct aac_softc *)arg;
165931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1660914da7d0SScott Long 
166135863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
166235863739SMike Smith }
166335863739SMike Smith 
1664a6d35632SScott Long static int
1665a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1666a6d35632SScott Long {
166704f4d586SEd Maste 	u_int32_t code, major, minor, options = 0, atu_size = 0;
1668a441b3fcSScott Long 	int status;
166904f4d586SEd Maste 	time_t then;
1670a6d35632SScott Long 
167131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
167204f4d586SEd Maste 	/*
167304f4d586SEd Maste 	 * Wait for the adapter to come ready.
167404f4d586SEd Maste 	 */
167504f4d586SEd Maste 	then = time_uptime;
167604f4d586SEd Maste 	do {
167704f4d586SEd Maste 		code = AAC_GET_FWSTATUS(sc);
167804f4d586SEd Maste 		if (code & AAC_SELF_TEST_FAILED) {
167904f4d586SEd Maste 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
168004f4d586SEd Maste 			return(ENXIO);
168104f4d586SEd Maste 		}
168204f4d586SEd Maste 		if (code & AAC_KERNEL_PANIC) {
168304f4d586SEd Maste 			device_printf(sc->aac_dev,
1684a620bad0SEd Maste 				      "FATAL: controller kernel panic");
168504f4d586SEd Maste 			return(ENXIO);
168604f4d586SEd Maste 		}
168704f4d586SEd Maste 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
168804f4d586SEd Maste 			device_printf(sc->aac_dev,
168904f4d586SEd Maste 				      "FATAL: controller not coming ready, "
169004f4d586SEd Maste 					   "status %x\n", code);
169104f4d586SEd Maste 			return(ENXIO);
169204f4d586SEd Maste 		}
169304f4d586SEd Maste 	} while (!(code & AAC_UP_AND_RUNNING));
1694a6d35632SScott Long 
1695fe94b852SScott Long 	/*
1696fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1697fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1698fe94b852SScott Long 	 */
1699a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1700fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1701fe94b852SScott Long 				     NULL)) {
1702fe94b852SScott Long 			device_printf(sc->aac_dev,
1703fe94b852SScott Long 				      "Error reading firmware version\n");
1704fe94b852SScott Long 			return (EIO);
1705fe94b852SScott Long 		}
1706fe94b852SScott Long 
1707fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1708a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1709a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1710fe94b852SScott Long 		if (major == 1) {
1711fe94b852SScott Long 			device_printf(sc->aac_dev,
1712fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1713fe94b852SScott Long 			    major, minor);
1714fe94b852SScott Long 			return (EINVAL);
1715fe94b852SScott Long 		}
1716fe94b852SScott Long 	}
1717fe94b852SScott Long 
1718a6d35632SScott Long 	/*
1719a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1720a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1721a441b3fcSScott Long 	 * command.
1722a6d35632SScott Long 	 */
1723a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1724a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1725a441b3fcSScott Long 			device_printf(sc->aac_dev,
1726a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1727a6d35632SScott Long 			return (EIO);
1728a6d35632SScott Long 		}
1729a441b3fcSScott Long 	} else {
1730a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
17317cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1732a6d35632SScott Long 		sc->supported_options = options;
1733a6d35632SScott Long 
1734a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1735a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1736a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1737a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1738a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1739cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1740cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1741a441b3fcSScott Long 			device_printf(sc->aac_dev,
1742a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1743a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1744a6d35632SScott Long 		}
1745a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1746a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
17477cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
17487cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
17497cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1750a441b3fcSScott Long 	}
1751a6d35632SScott Long 
1752a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
17537cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
17547cb209f5SScott Long 
17557cb209f5SScott Long 	/* Remap mem. resource, if required */
17567cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
17577cb209f5SScott Long 		atu_size > rman_get_size(sc->aac_regs_resource)) {
17587cb209f5SScott Long 		bus_release_resource(
17597cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
17607cb209f5SScott Long 			sc->aac_regs_rid, sc->aac_regs_resource);
17617cb209f5SScott Long 		sc->aac_regs_resource = bus_alloc_resource(
17627cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
17637cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
17647cb209f5SScott Long 		if (sc->aac_regs_resource == NULL) {
17657cb209f5SScott Long 			sc->aac_regs_resource = bus_alloc_resource_any(
17667cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
17677cb209f5SScott Long 				&sc->aac_regs_rid, RF_ACTIVE);
17687cb209f5SScott Long 			if (sc->aac_regs_resource == NULL) {
17697cb209f5SScott Long 				device_printf(sc->aac_dev,
17707cb209f5SScott Long 				    "couldn't allocate register window\n");
17717cb209f5SScott Long 				return (ENXIO);
17727cb209f5SScott Long 			}
17737cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
17747cb209f5SScott Long 		}
17757cb209f5SScott Long 		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
17767cb209f5SScott Long 		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
17777cb209f5SScott Long 	}
17787cb209f5SScott Long 
17797cb209f5SScott Long 	/* Read preferred settings */
17807cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
17817cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
17827cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1783a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
17847e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
17857e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1786a6d35632SScott Long 	else
1787a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
17887e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
17897e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1790a441b3fcSScott Long 
17917cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
17927cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
17937cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
17947cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
17957cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
17967cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
17977cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
17987cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
17997cb209f5SScott Long 	}
18007cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
18017cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
18027cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1803a6d35632SScott Long 
1804f355c0e0SEd Maste 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1805f355c0e0SEd Maste 		sc->flags |= AAC_FLAGS_RAW_IO;
1806f355c0e0SEd Maste 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1807f355c0e0SEd Maste 	}
1808523da39bSEd Maste 	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1809523da39bSEd Maste 	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1810523da39bSEd Maste 		sc->flags |= AAC_FLAGS_LBA_64BIT;
1811523da39bSEd Maste 		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1812523da39bSEd Maste 	}
1813f355c0e0SEd Maste 
1814fe94b852SScott Long 	return (0);
1815fe94b852SScott Long }
1816fe94b852SScott Long 
181735863739SMike Smith static int
181835863739SMike Smith aac_init(struct aac_softc *sc)
181935863739SMike Smith {
182035863739SMike Smith 	struct aac_adapter_init	*ip;
182104f4d586SEd Maste 	u_int32_t qoffset;
1822a6d35632SScott Long 	int error;
182335863739SMike Smith 
182431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1825ffb37f33SScott Long 
182635863739SMike Smith 	/*
1827914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1828914da7d0SScott Long 	 * physical location of various important shared data structures.
182935863739SMike Smith 	 */
183035863739SMike Smith 	ip = &sc->aac_common->ac_init;
183135863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18327cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18337cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18347cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18357cb209f5SScott Long 	}
1836f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
183735863739SMike Smith 
1838c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1839c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1840149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
184135863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
184235863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
184335863739SMike Smith 
1844c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1845c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
184635863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
184735863739SMike Smith 
18484b00f859SScott Long 	/*
18494b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18504b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18514b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18524b00f859SScott Long 	 * Round up since the granularity is so high.
18534b00f859SScott Long 	 */
1854f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18554b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18564b00f859SScott Long 		ip->HostPhysMemPages =
18574b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1858204c0befSScott Long 	}
18592b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
186035863739SMike Smith 
18617cb209f5SScott Long 	ip->InitFlags = 0;
18627cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
18637cb209f5SScott Long 		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
18647cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
18657cb209f5SScott Long 	}
18667cb209f5SScott Long 
18677cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
18687cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
18697cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
18707cb209f5SScott Long 
187135863739SMike Smith 	/*
18724109ba51SEd Maste 	 * Initialize FIB queues.  Note that it appears that the layout of the
1873c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1874c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
187535863739SMike Smith 	 *
187635863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1877914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1878914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1879914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1880914da7d0SScott Long 	 * does.
188135863739SMike Smith 	 *
1882914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1883914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1884914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1885914da7d0SScott Long 	 * virtue of a table.
188635863739SMike Smith 	 */
1887b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
18880bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
18890bcbebd6SScott Long 	sc->aac_queues =
18900bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1891b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
189235863739SMike Smith 
1893c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1894c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1895c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1896c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1897c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1898c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1899c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1900c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1901c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1902c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1903c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1904c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1905c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1906c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1907c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1908c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1909c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1910c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1911c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1912c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1913c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1914c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1915c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1916c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1917c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1918c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1919c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1920c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1921c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1922c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1923c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1924c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1925c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1926c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1927c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1928c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1929c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1930c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1931c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1932c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1933c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1934c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1935c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1936c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1937c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1938c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1939c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1940c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
194135863739SMike Smith 
194235863739SMike Smith 	/*
194335863739SMike Smith 	 * Do controller-type-specific initialisation
194435863739SMike Smith 	 */
194535863739SMike Smith 	switch (sc->aac_hwif) {
194635863739SMike Smith 	case AAC_HWIF_I960RX:
194735863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
194835863739SMike Smith 		break;
19494afedc31SScott Long 	case AAC_HWIF_RKT:
19504afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
19514afedc31SScott Long 		break;
19524afedc31SScott Long 	default:
19534afedc31SScott Long 		break;
195435863739SMike Smith 	}
195535863739SMike Smith 
195635863739SMike Smith 	/*
195735863739SMike Smith 	 * Give the init structure to the controller.
195835863739SMike Smith 	 */
195935863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1960914da7d0SScott Long 			     sc->aac_common_busaddr +
1961914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1962914da7d0SScott Long 			     NULL)) {
1963914da7d0SScott Long 		device_printf(sc->aac_dev,
1964914da7d0SScott Long 			      "error establishing init structure\n");
1965a6d35632SScott Long 		error = EIO;
1966a6d35632SScott Long 		goto out;
196735863739SMike Smith 	}
196835863739SMike Smith 
1969a6d35632SScott Long 	error = 0;
1970a6d35632SScott Long out:
1971a6d35632SScott Long 	return(error);
197235863739SMike Smith }
197335863739SMike Smith 
197404f4d586SEd Maste static int
197504f4d586SEd Maste aac_setup_intr(struct aac_softc *sc)
197604f4d586SEd Maste {
197704f4d586SEd Maste 	sc->aac_irq_rid = 0;
197804f4d586SEd Maste 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
197904f4d586SEd Maste 			   			  &sc->aac_irq_rid,
198004f4d586SEd Maste 			   			  RF_SHAREABLE |
198104f4d586SEd Maste 						  RF_ACTIVE)) == NULL) {
198204f4d586SEd Maste 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
198304f4d586SEd Maste 		return (EINVAL);
198404f4d586SEd Maste 	}
198504f4d586SEd Maste 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
198604f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
198704f4d586SEd Maste 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
198804f4d586SEd Maste 				   aac_new_intr, sc, &sc->aac_intr)) {
198904f4d586SEd Maste 			device_printf(sc->aac_dev, "can't set up interrupt\n");
199004f4d586SEd Maste 			return (EINVAL);
199104f4d586SEd Maste 		}
199204f4d586SEd Maste 	} else {
199304f4d586SEd Maste 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
199404f4d586SEd Maste 				   INTR_TYPE_BIO, aac_fast_intr, NULL,
199504f4d586SEd Maste 				   sc, &sc->aac_intr)) {
199604f4d586SEd Maste 			device_printf(sc->aac_dev,
199704f4d586SEd Maste 				      "can't set up FAST interrupt\n");
199804f4d586SEd Maste 			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
199904f4d586SEd Maste 					   INTR_MPSAFE|INTR_TYPE_BIO,
200004f4d586SEd Maste 					   NULL, (driver_intr_t *)aac_fast_intr,
200104f4d586SEd Maste 					   sc, &sc->aac_intr)) {
200204f4d586SEd Maste 				device_printf(sc->aac_dev,
200304f4d586SEd Maste 					     "can't set up MPSAFE interrupt\n");
200404f4d586SEd Maste 				return (EINVAL);
200504f4d586SEd Maste 			}
200604f4d586SEd Maste 		}
200704f4d586SEd Maste 	}
200804f4d586SEd Maste 	return (0);
200904f4d586SEd Maste }
201004f4d586SEd Maste 
2011914da7d0SScott Long /*
201235863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
20137cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
201435863739SMike Smith  */
201535863739SMike Smith static int
201635863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
201735863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
201835863739SMike Smith 		 u_int32_t *sp)
201935863739SMike Smith {
202035863739SMike Smith 	time_t then;
202135863739SMike Smith 	u_int32_t status;
202235863739SMike Smith 
202331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
202435863739SMike Smith 
202535863739SMike Smith 	/* populate the mailbox */
202635863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
202735863739SMike Smith 
202835863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
202935863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
203035863739SMike Smith 
203135863739SMike Smith 	/* then set it to signal the adapter */
203235863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
203335863739SMike Smith 
203435863739SMike Smith 	/* spin waiting for the command to complete */
20352b3b0f17SScott Long 	then = time_uptime;
203635863739SMike Smith 	do {
20372b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
203831a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
203935863739SMike Smith 			return(EIO);
204035863739SMike Smith 		}
204135863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
204235863739SMike Smith 
204335863739SMike Smith 	/* clear the completion flag */
204435863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
204535863739SMike Smith 
204635863739SMike Smith 	/* get the command status */
2047a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
204835863739SMike Smith 	if (sp != NULL)
204935863739SMike Smith 		*sp = status;
20507cb209f5SScott Long 
2051a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20527cb209f5SScott Long 		return (-1);
20530b94a66eSMike Smith 	return(0);
205435863739SMike Smith }
205535863739SMike Smith 
2056cbfd045bSScott Long int
205735863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2058cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
205935863739SMike Smith {
206031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
20617cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
206235863739SMike Smith 
206335863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
206435863739SMike Smith 		return(EINVAL);
206535863739SMike Smith 
206635863739SMike Smith 	/*
206735863739SMike Smith 	 * Set up the sync FIB
206835863739SMike Smith 	 */
2069914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2070914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2071c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
207235863739SMike Smith 	fib->Header.XferState |= xferstate;
207335863739SMike Smith 	fib->Header.Command = command;
207435863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
207542ef13a2SEd Maste 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
207635863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2077b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2078c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2079914da7d0SScott Long 					 offsetof(struct aac_common,
2080914da7d0SScott Long 						  ac_sync_fib);
208135863739SMike Smith 
208235863739SMike Smith 	/*
208335863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
208435863739SMike Smith 	 */
2085914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2086914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
208731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
208835863739SMike Smith 		return(EIO);
208935863739SMike Smith 	}
209035863739SMike Smith 
209135863739SMike Smith 	return (0);
209235863739SMike Smith }
209335863739SMike Smith 
2094914da7d0SScott Long /*
209535863739SMike Smith  * Adapter-space FIB queue manipulation
209635863739SMike Smith  *
209735863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
209835863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
209935863739SMike Smith  */
210035863739SMike Smith static struct {
210135863739SMike Smith 	int		size;
210235863739SMike Smith 	int		notify;
210335863739SMike Smith } aac_qinfo[] = {
210435863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
210535863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
210635863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
210735863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
210835863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
210935863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
211035863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
211135863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
211235863739SMike Smith };
211335863739SMike Smith 
211435863739SMike Smith /*
2115c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2116c6eafcf2SScott Long  * EBUSY if the queue is full.
211735863739SMike Smith  *
21180b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2119914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2120914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2121c6eafcf2SScott Long  *	 separate queue/notify interface).
212235863739SMike Smith  */
212335863739SMike Smith static int
2124f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
212535863739SMike Smith {
212635863739SMike Smith 	u_int32_t pi, ci;
21279e2e96d8SScott Long 	int error;
2128f6c4dd3fSScott Long 	u_int32_t fib_size;
2129f6c4dd3fSScott Long 	u_int32_t fib_addr;
2130f6c4dd3fSScott Long 
213131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
213236e0bf6eSScott Long 
2133f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2134f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
213535863739SMike Smith 
213635863739SMike Smith 	/* get the producer/consumer indices */
213735863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
213835863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
213935863739SMike Smith 
214035863739SMike Smith 	/* wrap the queue? */
214135863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
214235863739SMike Smith 		pi = 0;
214335863739SMike Smith 
214435863739SMike Smith 	/* check for queue full */
214535863739SMike Smith 	if ((pi + 1) == ci) {
214635863739SMike Smith 		error = EBUSY;
214735863739SMike Smith 		goto out;
214835863739SMike Smith 	}
214935863739SMike Smith 
2150614c22b2SScott Long 	/*
2151614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2152614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2153614c22b2SScott Long 	 */
2154614c22b2SScott Long 	aac_enqueue_busy(cm);
2155614c22b2SScott Long 
215635863739SMike Smith 	/* populate queue entry */
215735863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
215835863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
215935863739SMike Smith 
216035863739SMike Smith 	/* update producer index */
216135863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
216235863739SMike Smith 
216335863739SMike Smith 	/* notify the adapter if we know how */
216435863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
216535863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
216635863739SMike Smith 
216735863739SMike Smith 	error = 0;
216835863739SMike Smith 
216935863739SMike Smith out:
217035863739SMike Smith 	return(error);
217135863739SMike Smith }
217235863739SMike Smith 
217335863739SMike Smith /*
217436e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
217536e0bf6eSScott Long  * success or ENOENT if the queue is empty.
217635863739SMike Smith  */
217735863739SMike Smith static int
2178c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2179c6eafcf2SScott Long 		struct aac_fib **fib_addr)
218035863739SMike Smith {
218135863739SMike Smith 	u_int32_t pi, ci;
2182149af931SScott Long 	u_int32_t fib_index;
21839e2e96d8SScott Long 	int error;
2184f6c4dd3fSScott Long 	int notify;
218535863739SMike Smith 
218631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
218735863739SMike Smith 
218835863739SMike Smith 	/* get the producer/consumer indices */
218935863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
219035863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
219135863739SMike Smith 
219235863739SMike Smith 	/* check for queue empty */
219335863739SMike Smith 	if (ci == pi) {
219435863739SMike Smith 		error = ENOENT;
219535863739SMike Smith 		goto out;
219635863739SMike Smith 	}
219735863739SMike Smith 
21987753acd2SScott Long 	/* wrap the pi so the following test works */
21997753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
22007753acd2SScott Long 		pi = 0;
22017753acd2SScott Long 
2202f6c4dd3fSScott Long 	notify = 0;
2203f6c4dd3fSScott Long 	if (ci == pi + 1)
2204f6c4dd3fSScott Long 		notify++;
2205f6c4dd3fSScott Long 
220635863739SMike Smith 	/* wrap the queue? */
220735863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
220835863739SMike Smith 		ci = 0;
220935863739SMike Smith 
221035863739SMike Smith 	/* fetch the entry */
221135863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2212149af931SScott Long 
2213149af931SScott Long 	switch (queue) {
2214149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2215149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2216149af931SScott Long 		/*
2217149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2218149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2219149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2220149af931SScott Long 		 * Therefore, we have to convert it to an index.
2221149af931SScott Long 		 */
2222149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2223149af931SScott Long 			sizeof(struct aac_fib);
2224149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2225149af931SScott Long 		break;
2226149af931SScott Long 
2227149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2228149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2229149af931SScott Long 	{
2230149af931SScott Long 		struct aac_command *cm;
2231149af931SScott Long 
2232149af931SScott Long 		/*
2233149af931SScott Long 		 * As above, an index is used instead of an actual address.
2234149af931SScott Long 		 * Gotta shift the index to account for the fast response
2235149af931SScott Long 		 * bit.  No other correction is needed since this value was
2236149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2237149af931SScott Long 		 * field.
2238149af931SScott Long 		 */
2239149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22407cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2241149af931SScott Long 		*fib_addr = cm->cm_fib;
224235863739SMike Smith 
2243f30ac74cSScott Long 		/*
2244f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2245149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2246f30ac74cSScott Long 		 */
2247149af931SScott Long 		if (fib_index & 0x01) {
2248f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2249f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2250f30ac74cSScott Long 		}
2251149af931SScott Long 		break;
2252149af931SScott Long 	}
2253149af931SScott Long 	default:
2254149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2255149af931SScott Long 		break;
2256149af931SScott Long 	}
2257149af931SScott Long 
225835863739SMike Smith 	/* update consumer index */
225935863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
226035863739SMike Smith 
226135863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2262f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
226335863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
226435863739SMike Smith 	error = 0;
226535863739SMike Smith 
226635863739SMike Smith out:
226735863739SMike Smith 	return(error);
226835863739SMike Smith }
226935863739SMike Smith 
2270914da7d0SScott Long /*
227136e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
227236e0bf6eSScott Long  */
227336e0bf6eSScott Long static int
227436e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
227536e0bf6eSScott Long {
227636e0bf6eSScott Long 	u_int32_t pi, ci;
22779e2e96d8SScott Long 	int error;
227836e0bf6eSScott Long 	u_int32_t fib_size;
227936e0bf6eSScott Long 	u_int32_t fib_addr;
228036e0bf6eSScott Long 
228131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
228236e0bf6eSScott Long 
228336e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
228436e0bf6eSScott Long 	fib_size = fib->Header.Size;
228536e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
228636e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
228736e0bf6eSScott Long 
228836e0bf6eSScott Long 	/* get the producer/consumer indices */
228936e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
229036e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
229136e0bf6eSScott Long 
229236e0bf6eSScott Long 	/* wrap the queue? */
229336e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
229436e0bf6eSScott Long 		pi = 0;
229536e0bf6eSScott Long 
229636e0bf6eSScott Long 	/* check for queue full */
229736e0bf6eSScott Long 	if ((pi + 1) == ci) {
229836e0bf6eSScott Long 		error = EBUSY;
229936e0bf6eSScott Long 		goto out;
230036e0bf6eSScott Long 	}
230136e0bf6eSScott Long 
230236e0bf6eSScott Long 	/* populate queue entry */
230336e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
230436e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
230536e0bf6eSScott Long 
230636e0bf6eSScott Long 	/* update producer index */
230736e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
230836e0bf6eSScott Long 
230936e0bf6eSScott Long 	/* notify the adapter if we know how */
231036e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
231136e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
231236e0bf6eSScott Long 
231336e0bf6eSScott Long 	error = 0;
231436e0bf6eSScott Long 
231536e0bf6eSScott Long out:
231636e0bf6eSScott Long 	return(error);
231736e0bf6eSScott Long }
231836e0bf6eSScott Long 
2319914da7d0SScott Long /*
23200b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
23210b94a66eSMike Smith  * and complain about them.
23220b94a66eSMike Smith  */
23230b94a66eSMike Smith static void
23240b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
23250b94a66eSMike Smith {
23260b94a66eSMike Smith 	struct aac_command *cm;
23270b94a66eSMike Smith 	time_t deadline;
232815c37be0SScott Long 	int timedout, code;
23290b94a66eSMike Smith 
2330f6c4dd3fSScott Long 	/*
233170545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2332914da7d0SScott Long 	 * only.
2333914da7d0SScott Long 	 */
233415c37be0SScott Long 	timedout = 0;
23352b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23360b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2337f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2338f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
23390b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2340914da7d0SScott Long 			device_printf(sc->aac_dev,
2341914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
23422b3b0f17SScott Long 				      cm, (int)(time_uptime-cm->cm_timestamp));
23430b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
234415c37be0SScott Long 			timedout++;
23450b94a66eSMike Smith 		}
23460b94a66eSMike Smith 	}
23470b94a66eSMike Smith 
234815c37be0SScott Long 	if (timedout) {
234915c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
235015c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
235115c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
235215c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
235315c37be0SScott Long 		}
235415c37be0SScott Long 	}
23550b94a66eSMike Smith 	return;
23560b94a66eSMike Smith }
23570b94a66eSMike Smith 
2358914da7d0SScott Long /*
2359914da7d0SScott Long  * Interface Function Vectors
2360914da7d0SScott Long  */
236135863739SMike Smith 
2362914da7d0SScott Long /*
236335863739SMike Smith  * Read the current firmware status word.
236435863739SMike Smith  */
236535863739SMike Smith static int
236635863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
236735863739SMike Smith {
236831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
236935863739SMike Smith 
237035863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
237135863739SMike Smith }
237235863739SMike Smith 
237335863739SMike Smith static int
237435863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
237535863739SMike Smith {
237631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
237735863739SMike Smith 
237835863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
237935863739SMike Smith }
238035863739SMike Smith 
2381b3457b51SScott Long static int
2382b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2383b3457b51SScott Long {
2384b3457b51SScott Long 	int val;
2385b3457b51SScott Long 
238631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2387b3457b51SScott Long 
2388b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2389b3457b51SScott Long 	return (val);
2390b3457b51SScott Long }
2391b3457b51SScott Long 
23924afedc31SScott Long static int
23934afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
23944afedc31SScott Long {
239531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
23964afedc31SScott Long 
23974afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
23984afedc31SScott Long }
23994afedc31SScott Long 
2400914da7d0SScott Long /*
240135863739SMike Smith  * Notify the controller of a change in a given queue
240235863739SMike Smith  */
240335863739SMike Smith 
240435863739SMike Smith static void
240535863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
240635863739SMike Smith {
240731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
240835863739SMike Smith 
240935863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
241035863739SMike Smith }
241135863739SMike Smith 
241235863739SMike Smith static void
241335863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
241435863739SMike Smith {
241531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241635863739SMike Smith 
241735863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
241835863739SMike Smith }
241935863739SMike Smith 
2420b3457b51SScott Long static void
2421b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2422b3457b51SScott Long {
242331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2424b3457b51SScott Long 
2425b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2426b3457b51SScott Long 	AAC_FA_HACK(sc);
2427b3457b51SScott Long }
2428b3457b51SScott Long 
24294afedc31SScott Long static void
24304afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
24314afedc31SScott Long {
243231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24334afedc31SScott Long 
24344afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
24354afedc31SScott Long }
24364afedc31SScott Long 
2437914da7d0SScott Long /*
243835863739SMike Smith  * Get the interrupt reason bits
243935863739SMike Smith  */
244035863739SMike Smith static int
244135863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
244235863739SMike Smith {
244331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
244435863739SMike Smith 
244535863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
244635863739SMike Smith }
244735863739SMike Smith 
244835863739SMike Smith static int
244935863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
245035863739SMike Smith {
245131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
245235863739SMike Smith 
245335863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
245435863739SMike Smith }
245535863739SMike Smith 
2456b3457b51SScott Long static int
2457b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2458b3457b51SScott Long {
2459b3457b51SScott Long 	int val;
2460b3457b51SScott Long 
246131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2462b3457b51SScott Long 
2463b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2464b3457b51SScott Long 	return (val);
2465b3457b51SScott Long }
2466b3457b51SScott Long 
24674afedc31SScott Long static int
24684afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
24694afedc31SScott Long {
247031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24714afedc31SScott Long 
24724afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
24734afedc31SScott Long }
24744afedc31SScott Long 
2475914da7d0SScott Long /*
247635863739SMike Smith  * Clear some interrupt reason bits
247735863739SMike Smith  */
247835863739SMike Smith static void
247935863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
248035863739SMike Smith {
248131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
248235863739SMike Smith 
248335863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
248435863739SMike Smith }
248535863739SMike Smith 
248635863739SMike Smith static void
248735863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
248835863739SMike Smith {
248931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
249035863739SMike Smith 
249135863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
249235863739SMike Smith }
249335863739SMike Smith 
2494b3457b51SScott Long static void
2495b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2496b3457b51SScott Long {
249731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2498b3457b51SScott Long 
2499b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2500b3457b51SScott Long 	AAC_FA_HACK(sc);
2501b3457b51SScott Long }
2502b3457b51SScott Long 
25034afedc31SScott Long static void
25044afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
25054afedc31SScott Long {
250631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25074afedc31SScott Long 
25084afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
25094afedc31SScott Long }
25104afedc31SScott Long 
2511914da7d0SScott Long /*
251235863739SMike Smith  * Populate the mailbox and set the command word
251335863739SMike Smith  */
251435863739SMike Smith static void
251535863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
251635863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
251735863739SMike Smith {
251831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
251935863739SMike Smith 
252035863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
252135863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
252235863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
252335863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
252435863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
252535863739SMike Smith }
252635863739SMike Smith 
252735863739SMike Smith static void
252835863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
252935863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
253035863739SMike Smith {
253131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
253235863739SMike Smith 
253335863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
253435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
253535863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
253635863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
253735863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
253835863739SMike Smith }
253935863739SMike Smith 
2540b3457b51SScott Long static void
2541b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2542b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2543b3457b51SScott Long {
254431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2545b3457b51SScott Long 
2546b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2547b3457b51SScott Long 	AAC_FA_HACK(sc);
2548b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2549b3457b51SScott Long 	AAC_FA_HACK(sc);
2550b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2551b3457b51SScott Long 	AAC_FA_HACK(sc);
2552b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2553b3457b51SScott Long 	AAC_FA_HACK(sc);
2554b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2555b3457b51SScott Long 	AAC_FA_HACK(sc);
2556b3457b51SScott Long }
2557b3457b51SScott Long 
25584afedc31SScott Long static void
25594afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25604afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
25614afedc31SScott Long {
256231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
25634afedc31SScott Long 
25644afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
25654afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
25664afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
25674afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
25684afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
25694afedc31SScott Long }
25704afedc31SScott Long 
2571914da7d0SScott Long /*
257235863739SMike Smith  * Fetch the immediate command status word
257335863739SMike Smith  */
257435863739SMike Smith static int
2575a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
257635863739SMike Smith {
257731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
257835863739SMike Smith 
2579a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
258035863739SMike Smith }
258135863739SMike Smith 
258235863739SMike Smith static int
2583a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
258435863739SMike Smith {
258531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
258635863739SMike Smith 
2587a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
258835863739SMike Smith }
258935863739SMike Smith 
2590b3457b51SScott Long static int
2591a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2592b3457b51SScott Long {
2593b3457b51SScott Long 	int val;
2594b3457b51SScott Long 
259531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2596b3457b51SScott Long 
2597a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2598b3457b51SScott Long 	return (val);
2599b3457b51SScott Long }
2600b3457b51SScott Long 
26014afedc31SScott Long static int
26024afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
26034afedc31SScott Long {
260431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
26054afedc31SScott Long 
26064afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
26074afedc31SScott Long }
26084afedc31SScott Long 
2609914da7d0SScott Long /*
261035863739SMike Smith  * Set/clear interrupt masks
261135863739SMike Smith  */
261235863739SMike Smith static void
261335863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
261435863739SMike Smith {
261531a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
261635863739SMike Smith 
261735863739SMike Smith 	if (enable) {
261835863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
261935863739SMike Smith 	} else {
262035863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
262135863739SMike Smith 	}
262235863739SMike Smith }
262335863739SMike Smith 
262435863739SMike Smith static void
262535863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
262635863739SMike Smith {
262731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
262835863739SMike Smith 
262935863739SMike Smith 	if (enable) {
26307cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
26317cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
26327cb209f5SScott Long 		else
263335863739SMike Smith 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
263435863739SMike Smith 	} else {
263535863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
263635863739SMike Smith 	}
263735863739SMike Smith }
263835863739SMike Smith 
2639b3457b51SScott Long static void
2640b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2641b3457b51SScott Long {
264231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2643b3457b51SScott Long 
2644b3457b51SScott Long 	if (enable) {
2645b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2646b3457b51SScott Long 		AAC_FA_HACK(sc);
2647b3457b51SScott Long 	} else {
2648b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2649b3457b51SScott Long 		AAC_FA_HACK(sc);
2650b3457b51SScott Long 	}
2651b3457b51SScott Long }
2652b3457b51SScott Long 
26534afedc31SScott Long static void
26544afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
26554afedc31SScott Long {
265631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
26574afedc31SScott Long 
26584afedc31SScott Long 	if (enable) {
26597cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
26607cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
26617cb209f5SScott Long 		else
26624afedc31SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
26634afedc31SScott Long 	} else {
26644afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
26654afedc31SScott Long 	}
26664afedc31SScott Long }
26674afedc31SScott Long 
2668914da7d0SScott Long /*
26697cb209f5SScott Long  * New comm. interface: Send command functions
26707cb209f5SScott Long  */
26717cb209f5SScott Long static int
26727cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
26737cb209f5SScott Long {
26747cb209f5SScott Long 	u_int32_t index, device;
26757cb209f5SScott Long 
267631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
26777cb209f5SScott Long 
26787cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RX_IQUE);
26797cb209f5SScott Long 	if (index == 0xffffffffL)
26807cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RX_IQUE);
26817cb209f5SScott Long 	if (index == 0xffffffffL)
26827cb209f5SScott Long 		return index;
26837cb209f5SScott Long 	aac_enqueue_busy(cm);
26847cb209f5SScott Long 	device = index;
26857cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26867cb209f5SScott Long 	device += 4;
26877cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26887cb209f5SScott Long 	device += 4;
26897cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26907cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_IQUE, index);
26917cb209f5SScott Long 	return 0;
26927cb209f5SScott Long }
26937cb209f5SScott Long 
26947cb209f5SScott Long static int
26957cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
26967cb209f5SScott Long {
26977cb209f5SScott Long 	u_int32_t index, device;
26987cb209f5SScott Long 
269931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
27007cb209f5SScott Long 
27017cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
27027cb209f5SScott Long 	if (index == 0xffffffffL)
27037cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
27047cb209f5SScott Long 	if (index == 0xffffffffL)
27057cb209f5SScott Long 		return index;
27067cb209f5SScott Long 	aac_enqueue_busy(cm);
27077cb209f5SScott Long 	device = index;
27087cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
27097cb209f5SScott Long 	device += 4;
27107cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
27117cb209f5SScott Long 	device += 4;
27127cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
27137cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
27147cb209f5SScott Long 	return 0;
27157cb209f5SScott Long }
27167cb209f5SScott Long 
27177cb209f5SScott Long /*
27187cb209f5SScott Long  * New comm. interface: get, set outbound queue index
27197cb209f5SScott Long  */
27207cb209f5SScott Long static int
27217cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
27227cb209f5SScott Long {
272331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27247cb209f5SScott Long 
27257cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RX_OQUE));
27267cb209f5SScott Long }
27277cb209f5SScott Long 
27287cb209f5SScott Long static int
27297cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
27307cb209f5SScott Long {
273131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27327cb209f5SScott Long 
27337cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
27347cb209f5SScott Long }
27357cb209f5SScott Long 
27367cb209f5SScott Long static void
27377cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
27387cb209f5SScott Long {
273931a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27407cb209f5SScott Long 
27417cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_OQUE, index);
27427cb209f5SScott Long }
27437cb209f5SScott Long 
27447cb209f5SScott Long static void
27457cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
27467cb209f5SScott Long {
274731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
27487cb209f5SScott Long 
27497cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
27507cb209f5SScott Long }
27517cb209f5SScott Long 
27527cb209f5SScott Long /*
2753914da7d0SScott Long  * Debugging and Diagnostics
2754914da7d0SScott Long  */
275535863739SMike Smith 
2756914da7d0SScott Long /*
275735863739SMike Smith  * Print some information about the controller.
275835863739SMike Smith  */
275935863739SMike Smith static void
276035863739SMike Smith aac_describe_controller(struct aac_softc *sc)
276135863739SMike Smith {
2762cbfd045bSScott Long 	struct aac_fib *fib;
276335863739SMike Smith 	struct aac_adapter_info	*info;
27647ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
276535863739SMike Smith 
276631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
276735863739SMike Smith 
276881b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
276903b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2770cbfd045bSScott Long 
2771cbfd045bSScott Long 	fib->data[0] = 0;
2772cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
277335863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2774fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
277581b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
277635863739SMike Smith 		return;
277735863739SMike Smith 	}
277835863739SMike Smith 
2779bd971c49SScott Long 	/* save the kernel revision structure for later use */
2780bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2781bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2782bd971c49SScott Long 
2783bd971c49SScott Long 	if (bootverbose) {
2784b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2785b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2786c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2787b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2788b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2789b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2790914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2791914da7d0SScott Long 		    info->batteryPlatform));
279235863739SMike Smith 
2793bd971c49SScott Long 		device_printf(sc->aac_dev,
2794bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
279535863739SMike Smith 		    info->KernelRevision.external.comp.major,
279635863739SMike Smith 		    info->KernelRevision.external.comp.minor,
279735863739SMike Smith 		    info->KernelRevision.external.comp.dash,
279836e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
279936e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2800fe3cb0e1SScott Long 
2801a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2802a6d35632SScott Long 			      sc->supported_options,
2803a6d35632SScott Long 			      "\20"
2804a6d35632SScott Long 			      "\1SNAPSHOT"
2805a6d35632SScott Long 			      "\2CLUSTERS"
2806a6d35632SScott Long 			      "\3WCACHE"
2807a6d35632SScott Long 			      "\4DATA64"
2808a6d35632SScott Long 			      "\5HOSTTIME"
2809a6d35632SScott Long 			      "\6RAID50"
2810a6d35632SScott Long 			      "\7WINDOW4GB"
2811a6d35632SScott Long 			      "\10SCSIUPGD"
2812a6d35632SScott Long 			      "\11SOFTERR"
2813a6d35632SScott Long 			      "\12NORECOND"
2814a6d35632SScott Long 			      "\13SGMAP64"
2815a6d35632SScott Long 			      "\14ALARM"
28167cb209f5SScott Long 			      "\15NONDASD"
28177cb209f5SScott Long 			      "\16SCSIMGT"
28187cb209f5SScott Long 			      "\17RAIDSCSI"
28197cb209f5SScott Long 			      "\21ADPTINFO"
28207cb209f5SScott Long 			      "\22NEWCOMM"
28217cb209f5SScott Long 			      "\23ARRAY64BIT"
28227cb209f5SScott Long 			      "\24HEATSENSOR");
2823a6d35632SScott Long 	}
282455aa1136SEd Maste 
282555aa1136SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
282655aa1136SEd Maste 		fib->data[0] = 0;
282755aa1136SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
282855aa1136SEd Maste 			device_printf(sc->aac_dev,
282955aa1136SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
283055aa1136SEd Maste 		else
283155aa1136SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
283255aa1136SEd Maste 			    &fib->data[0])->AdapterTypeText;
283355aa1136SEd Maste 	}
283455aa1136SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
283555aa1136SEd Maste 		adapter_type,
283655aa1136SEd Maste 		AAC_DRIVER_VERSION >> 24,
283755aa1136SEd Maste 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
283855aa1136SEd Maste 		AAC_DRIVER_VERSION & 0xFF,
283955aa1136SEd Maste 		AAC_DRIVER_BUILD);
284055aa1136SEd Maste 
2841bd971c49SScott Long 	aac_release_sync_fib(sc);
284281b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
284335863739SMike Smith }
284435863739SMike Smith 
2845914da7d0SScott Long /*
284635863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
284735863739SMike Smith  * same.
284835863739SMike Smith  */
284935863739SMike Smith static char *
285035863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
285135863739SMike Smith {
285235863739SMike Smith 	int i;
285335863739SMike Smith 
285435863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
285535863739SMike Smith 		if (table[i].code == code)
285635863739SMike Smith 			return(table[i].string);
285735863739SMike Smith 	return(table[i + 1].string);
285835863739SMike Smith }
285935863739SMike Smith 
2860914da7d0SScott Long /*
2861914da7d0SScott Long  * Management Interface
2862914da7d0SScott Long  */
286335863739SMike Smith 
286435863739SMike Smith static int
286589c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
286635863739SMike Smith {
2867914da7d0SScott Long 	struct aac_softc *sc;
286835863739SMike Smith 
2869914da7d0SScott Long 	sc = dev->si_drv1;
287031a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2871a723a548SEd Maste 	sc->aac_open_cnt++;
287235863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
287335863739SMike Smith 
287435863739SMike Smith 	return 0;
287535863739SMike Smith }
287635863739SMike Smith 
287735863739SMike Smith static int
287889c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
287935863739SMike Smith {
2880914da7d0SScott Long 	struct aac_softc *sc;
288135863739SMike Smith 
2882914da7d0SScott Long 	sc = dev->si_drv1;
288331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2884a723a548SEd Maste 	sc->aac_open_cnt--;
288535863739SMike Smith 	/* Mark this unit as no longer open  */
2886a723a548SEd Maste 	if (sc->aac_open_cnt == 0)
288735863739SMike Smith 		sc->aac_state &= ~AAC_STATE_OPEN;
288835863739SMike Smith 
288935863739SMike Smith 	return 0;
289035863739SMike Smith }
289135863739SMike Smith 
289235863739SMike Smith static int
289389c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
289435863739SMike Smith {
2895914da7d0SScott Long 	union aac_statrequest *as;
2896914da7d0SScott Long 	struct aac_softc *sc;
28970b94a66eSMike Smith 	int error = 0;
289835863739SMike Smith 
2899914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2900914da7d0SScott Long 	sc = dev->si_drv1;
290131a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2902914da7d0SScott Long 
290335863739SMike Smith 	switch (cmd) {
29040b94a66eSMike Smith 	case AACIO_STATS:
29050b94a66eSMike Smith 		switch (as->as_item) {
29060b94a66eSMike Smith 		case AACQ_FREE:
29070b94a66eSMike Smith 		case AACQ_BIO:
29080b94a66eSMike Smith 		case AACQ_READY:
29090b94a66eSMike Smith 		case AACQ_BUSY:
2910c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2911c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
29120b94a66eSMike Smith 			break;
29130b94a66eSMike Smith 		default:
29140b94a66eSMike Smith 			error = ENOENT;
29150b94a66eSMike Smith 			break;
29160b94a66eSMike Smith 		}
29170b94a66eSMike Smith 	break;
29180b94a66eSMike Smith 
291935863739SMike Smith 	case FSACTL_SENDFIB:
2920f355c0e0SEd Maste 	case FSACTL_SEND_LARGE_FIB:
2921fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2922fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
2923f355c0e0SEd Maste 	case FSACTL_LNX_SEND_LARGE_FIB:
292431a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
292535863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
292635863739SMike Smith 		break;
2927f355c0e0SEd Maste 	case FSACTL_SEND_RAW_SRB:
2928f355c0e0SEd Maste 		arg = *(caddr_t*)arg;
2929f355c0e0SEd Maste 	case FSACTL_LNX_SEND_RAW_SRB:
293031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2931f355c0e0SEd Maste 		error = aac_ioctl_send_raw_srb(sc, arg);
2932f355c0e0SEd Maste 		break;
293335863739SMike Smith 	case FSACTL_AIF_THREAD:
2934fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
293531a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
293635863739SMike Smith 		error = EINVAL;
293735863739SMike Smith 		break;
293835863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2939fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2940fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
294131a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2942a723a548SEd Maste 		error = aac_open_aif(sc, arg);
294335863739SMike Smith 		break;
294435863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2945fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2946fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
294731a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2948fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
294935863739SMike Smith 		break;
295035863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2951a723a548SEd Maste 		arg = *(caddr_t*)arg;
2952fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
295331a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2954a723a548SEd Maste 		error = aac_close_aif(sc, arg);
295535863739SMike Smith 		break;
295635863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2957fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2958fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
295931a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
2960fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
296135863739SMike Smith 		break;
296236e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
296336e0bf6eSScott Long 		arg = *(caddr_t*)arg;
296436e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
296531a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
296636e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
296736e0bf6eSScott Long 		break;
296836e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
296936e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2970914da7d0SScott Long 		/*
2971914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2972914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2973914da7d0SScott Long 		 * controller
2974914da7d0SScott Long 		 */
297536e0bf6eSScott Long 		error = 0;
297636e0bf6eSScott Long 		break;
29777cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
29787cb209f5SScott Long 		arg = *(caddr_t*)arg;
29797cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
298031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
29817cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
29827cb209f5SScott Long 		break;
29836d307336SEd Maste 	case FSACTL_GET_FEATURES:
29846d307336SEd Maste 		arg = *(caddr_t*)arg;
29856d307336SEd Maste 	case FSACTL_LNX_GET_FEATURES:
29866d307336SEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
29876d307336SEd Maste 		error = aac_supported_features(sc, arg);
29886d307336SEd Maste 		break;
298935863739SMike Smith 	default:
299031a0399eSEd Maste 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
299135863739SMike Smith 		error = EINVAL;
299235863739SMike Smith 		break;
299335863739SMike Smith 	}
299435863739SMike Smith 	return(error);
299535863739SMike Smith }
299635863739SMike Smith 
2997b3457b51SScott Long static int
299889c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2999b3457b51SScott Long {
3000b3457b51SScott Long 	struct aac_softc *sc;
3001ef0b687cSEd Maste 	struct aac_fib_context *ctx;
3002b3457b51SScott Long 	int revents;
3003b3457b51SScott Long 
3004b3457b51SScott Long 	sc = dev->si_drv1;
3005b3457b51SScott Long 	revents = 0;
3006b3457b51SScott Long 
3007bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3008b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
3009ef0b687cSEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3010ef0b687cSEd Maste 			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
3011b3457b51SScott Long 				revents |= poll_events & (POLLIN | POLLRDNORM);
3012ef0b687cSEd Maste 				break;
3013ef0b687cSEd Maste 			}
3014ef0b687cSEd Maste 		}
3015b3457b51SScott Long 	}
3016bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
3017b3457b51SScott Long 
3018b3457b51SScott Long 	if (revents == 0) {
3019b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
3020b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
3021b3457b51SScott Long 	}
3022b3457b51SScott Long 
3023b3457b51SScott Long 	return (revents);
3024b3457b51SScott Long }
3025b3457b51SScott Long 
30267cb209f5SScott Long static void
30277cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
30287cb209f5SScott Long {
30297cb209f5SScott Long 
30307cb209f5SScott Long 	switch (event->ev_type) {
30317cb209f5SScott Long 	case AAC_EVENT_CMFREE:
30320c40d5beSEd Maste 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
30331a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
30347cb209f5SScott Long 			aac_add_event(sc, event);
30357cb209f5SScott Long 			return;
30367cb209f5SScott Long 		}
30377cb209f5SScott Long 		free(event, M_AACBUF);
30388eeb2ca6SScott Long 		wakeup(arg);
30397cb209f5SScott Long 		break;
30407cb209f5SScott Long 	default:
30417cb209f5SScott Long 		break;
30427cb209f5SScott Long 	}
30437cb209f5SScott Long }
30447cb209f5SScott Long 
3045914da7d0SScott Long /*
304635863739SMike Smith  * Send a FIB supplied from userspace
304735863739SMike Smith  */
304835863739SMike Smith static int
304935863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
305035863739SMike Smith {
305135863739SMike Smith 	struct aac_command *cm;
305235863739SMike Smith 	int size, error;
305335863739SMike Smith 
305431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
305535863739SMike Smith 
305635863739SMike Smith 	cm = NULL;
305735863739SMike Smith 
305835863739SMike Smith 	/*
305935863739SMike Smith 	 * Get a command
306035863739SMike Smith 	 */
3061bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
306235863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
30637cb209f5SScott Long 		struct aac_event *event;
30647cb209f5SScott Long 
30657cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
30667cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
30677cb209f5SScott Long 		if (event == NULL) {
306835863739SMike Smith 			error = EBUSY;
3069f16627aaSEd Maste 			mtx_unlock(&sc->aac_io_lock);
307035863739SMike Smith 			goto out;
307135863739SMike Smith 		}
30727cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
30737cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
30747cb209f5SScott Long 		event->ev_arg = &cm;
30757cb209f5SScott Long 		aac_add_event(sc, event);
30768eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
30777cb209f5SScott Long 	}
307893cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
307935863739SMike Smith 
308035863739SMike Smith 	/*
308135863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
308235863739SMike Smith 	 */
3083914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3084914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
308535863739SMike Smith 		goto out;
308635863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3087f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3088f355c0e0SEd Maste 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3089f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3090f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
309135863739SMike Smith 	}
309235863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
309335863739SMike Smith 		goto out;
309435863739SMike Smith 	cm->cm_fib->Header.Size = size;
30952b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
309635863739SMike Smith 
309735863739SMike Smith 	/*
309835863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
309935863739SMike Smith 	 */
310093cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3101f16627aaSEd Maste 	error = aac_wait_command(cm);
3102f16627aaSEd Maste 	mtx_unlock(&sc->aac_io_lock);
3103f16627aaSEd Maste 	if (error != 0) {
310470545d1aSScott Long 		device_printf(sc->aac_dev,
310570545d1aSScott Long 			      "aac_wait_command return %d\n", error);
310635863739SMike Smith 		goto out;
3107b3457b51SScott Long 	}
310835863739SMike Smith 
310935863739SMike Smith 	/*
311035863739SMike Smith 	 * Copy the FIB and data back out to the caller.
311135863739SMike Smith 	 */
311235863739SMike Smith 	size = cm->cm_fib->Header.Size;
3113f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3114f355c0e0SEd Maste 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3115f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3116f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
311735863739SMike Smith 	}
311835863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
311935863739SMike Smith 
312035863739SMike Smith out:
3121f6c4dd3fSScott Long 	if (cm != NULL) {
3122f16627aaSEd Maste 		mtx_lock(&sc->aac_io_lock);
312335863739SMike Smith 		aac_release_command(cm);
3124bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
3125f16627aaSEd Maste 	}
312635863739SMike Smith 	return(error);
312735863739SMike Smith }
312835863739SMike Smith 
3129914da7d0SScott Long /*
3130f355c0e0SEd Maste  * Send a passthrough FIB supplied from userspace
3131f355c0e0SEd Maste  */
3132f355c0e0SEd Maste static int
3133f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3134f355c0e0SEd Maste {
3135f355c0e0SEd Maste 	return (EINVAL);
3136f355c0e0SEd Maste }
3137f355c0e0SEd Maste 
3138f355c0e0SEd Maste /*
313935863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
314036e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
314135863739SMike Smith  */
314235863739SMike Smith static void
314336e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
314435863739SMike Smith {
314536e0bf6eSScott Long 	struct aac_aif_command *aif;
314636e0bf6eSScott Long 	struct aac_container *co, *co_next;
3147a723a548SEd Maste 	struct aac_fib_context *ctx;
314804f4d586SEd Maste 	struct aac_mntinforesp *mir;
3149a723a548SEd Maste 	int next, current, found;
3150795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
315135863739SMike Smith 
315231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
315335863739SMike Smith 
315436e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
315536e0bf6eSScott Long 	aac_print_aif(sc, aif);
315636e0bf6eSScott Long 
315736e0bf6eSScott Long 	/* Is it an event that we should care about? */
315836e0bf6eSScott Long 	switch (aif->command) {
315936e0bf6eSScott Long 	case AifCmdEventNotify:
316036e0bf6eSScott Long 		switch (aif->data.EN.type) {
316136e0bf6eSScott Long 		case AifEnAddContainer:
316236e0bf6eSScott Long 		case AifEnDeleteContainer:
316336e0bf6eSScott Long 			/*
3164914da7d0SScott Long 			 * A container was added or deleted, but the message
3165914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3166914da7d0SScott Long 			 * containers and sort things out.
316736e0bf6eSScott Long 			 */
316803b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
316936e0bf6eSScott Long 			do {
317036e0bf6eSScott Long 				/*
3171914da7d0SScott Long 				 * Ask the controller for its containers one at
3172914da7d0SScott Long 				 * a time.
3173914da7d0SScott Long 				 * XXX What if the controller's list changes
3174914da7d0SScott Long 				 * midway through this enumaration?
317536e0bf6eSScott Long 				 * XXX This should be done async.
317636e0bf6eSScott Long 				 */
317704f4d586SEd Maste 				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
317836e0bf6eSScott Long 					continue;
317904f4d586SEd Maste 				if (i == 0)
3180795d7dc0SScott Long 					count = mir->MntRespCount;
318136e0bf6eSScott Long 				/*
3182914da7d0SScott Long 				 * Check the container against our list.
3183914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3184914da7d0SScott Long 				 * previous run.
318536e0bf6eSScott Long 				 */
3186cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3187cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
318836e0bf6eSScott Long 					found = 0;
3189914da7d0SScott Long 					TAILQ_FOREACH(co,
3190914da7d0SScott Long 						      &sc->aac_container_tqh,
3191914da7d0SScott Long 						      co_link) {
319236e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3193cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
319436e0bf6eSScott Long 							co->co_found = 1;
319536e0bf6eSScott Long 							found = 1;
319636e0bf6eSScott Long 							break;
319736e0bf6eSScott Long 						}
319836e0bf6eSScott Long 					}
3199914da7d0SScott Long 					/*
3200914da7d0SScott Long 					 * If the container matched, continue
3201914da7d0SScott Long 					 * in the list.
3202914da7d0SScott Long 					 */
320336e0bf6eSScott Long 					if (found) {
320436e0bf6eSScott Long 						i++;
320536e0bf6eSScott Long 						continue;
320636e0bf6eSScott Long 					}
320736e0bf6eSScott Long 
320836e0bf6eSScott Long 					/*
3209914da7d0SScott Long 					 * This is a new container.  Do all the
321070545d1aSScott Long 					 * appropriate things to set it up.
321170545d1aSScott Long 					 */
3212cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
321336e0bf6eSScott Long 					added = 1;
321436e0bf6eSScott Long 				}
321536e0bf6eSScott Long 				i++;
3216795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3217cbfd045bSScott Long 			aac_release_sync_fib(sc);
321836e0bf6eSScott Long 
321936e0bf6eSScott Long 			/*
3220914da7d0SScott Long 			 * Go through our list of containers and see which ones
3221914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3222914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3223914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3224914da7d0SScott Long 			 * the co->co_found field.
322536e0bf6eSScott Long 			 */
322636e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
322736e0bf6eSScott Long 			while (co != NULL) {
322836e0bf6eSScott Long 				if (co->co_found == 0) {
32297cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
32307cb209f5SScott Long 					mtx_lock(&Giant);
3231914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3232914da7d0SScott Long 							    co->co_disk);
32337cb209f5SScott Long 					mtx_unlock(&Giant);
32347cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
323536e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3236bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3237914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3238914da7d0SScott Long 						     co_link);
3239bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3240ba1d57e7SScott Long 					free(co, M_AACBUF);
324136e0bf6eSScott Long 					co = co_next;
324236e0bf6eSScott Long 				} else {
324336e0bf6eSScott Long 					co->co_found = 0;
324436e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
324536e0bf6eSScott Long 				}
324636e0bf6eSScott Long 			}
324736e0bf6eSScott Long 
324836e0bf6eSScott Long 			/* Attach the newly created containers */
32497cb209f5SScott Long 			if (added) {
32507cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
32517cb209f5SScott Long 				mtx_lock(&Giant);
325236e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
32537cb209f5SScott Long 				mtx_unlock(&Giant);
32547cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
32557cb209f5SScott Long 			}
325636e0bf6eSScott Long 
325736e0bf6eSScott Long 			break;
325836e0bf6eSScott Long 
325936e0bf6eSScott Long 		default:
326036e0bf6eSScott Long 			break;
326136e0bf6eSScott Long 		}
326236e0bf6eSScott Long 
326336e0bf6eSScott Long 	default:
326436e0bf6eSScott Long 		break;
326536e0bf6eSScott Long 	}
326636e0bf6eSScott Long 
326736e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3268bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3269a723a548SEd Maste 	current = sc->aifq_idx;
3270a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3271a723a548SEd Maste 	if (next == 0)
3272a723a548SEd Maste 		sc->aifq_filled = 1;
3273a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3274a723a548SEd Maste 	/* modify AIF contexts */
3275a723a548SEd Maste 	if (sc->aifq_filled) {
3276a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3277a723a548SEd Maste 			if (next == ctx->ctx_idx)
3278a723a548SEd Maste 				ctx->ctx_wrap = 1;
3279a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3280a723a548SEd Maste 				ctx->ctx_idx = next;
3281a723a548SEd Maste 		}
3282a723a548SEd Maste 	}
3283a723a548SEd Maste 	sc->aifq_idx = next;
3284b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
328535863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
328635863739SMike Smith 		wakeup(sc->aac_aifq);
3287b3457b51SScott Long 	/* Wakeup any poll()ers */
3288512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3289bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
329036e0bf6eSScott Long 
329136e0bf6eSScott Long 	return;
329235863739SMike Smith }
329335863739SMike Smith 
3294914da7d0SScott Long /*
32950b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
329636e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
329736e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
329836e0bf6eSScott Long  * returning what the card reported.
329935863739SMike Smith  */
330035863739SMike Smith static int
3301fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
330235863739SMike Smith {
330335863739SMike Smith 	struct aac_rev_check rev_check;
330435863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
330535863739SMike Smith 	int error = 0;
330635863739SMike Smith 
330731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
330835863739SMike Smith 
330935863739SMike Smith 	/*
331035863739SMike Smith 	 * Copyin the revision struct from userspace
331135863739SMike Smith 	 */
3312c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3313c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
331435863739SMike Smith 		return error;
331535863739SMike Smith 	}
331635863739SMike Smith 
331731a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3318914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
331935863739SMike Smith 
332035863739SMike Smith 	/*
332135863739SMike Smith 	 * Doctor up the response struct.
332235863739SMike Smith 	 */
332335863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3324914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3325914da7d0SScott Long 	    sc->aac_revision.external.ul;
3326914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3327914da7d0SScott Long 	    sc->aac_revision.buildNumber;
332835863739SMike Smith 
3329c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3330c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
333135863739SMike Smith }
333235863739SMike Smith 
3333914da7d0SScott Long /*
3334a723a548SEd Maste  * Pass the fib context to the caller
3335a723a548SEd Maste  */
3336a723a548SEd Maste static int
3337a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3338a723a548SEd Maste {
3339a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3340a723a548SEd Maste 	int error = 0;
3341a723a548SEd Maste 
334231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3343a723a548SEd Maste 
3344a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3345a723a548SEd Maste 	if (fibctx == NULL)
3346a723a548SEd Maste 		return (ENOMEM);
3347a723a548SEd Maste 
3348a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3349a723a548SEd Maste 	/* all elements are already 0, add to queue */
3350a723a548SEd Maste 	if (sc->fibctx == NULL)
3351a723a548SEd Maste 		sc->fibctx = fibctx;
3352a723a548SEd Maste 	else {
3353a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3354a723a548SEd Maste 			;
3355a723a548SEd Maste 		ctx->next = fibctx;
3356a723a548SEd Maste 		fibctx->prev = ctx;
3357a723a548SEd Maste 	}
3358a723a548SEd Maste 
3359a723a548SEd Maste 	/* evaluate unique value */
3360a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3361a723a548SEd Maste 	ctx = sc->fibctx;
3362a723a548SEd Maste 	while (ctx != fibctx) {
3363a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3364a723a548SEd Maste 			fibctx->unique++;
3365a723a548SEd Maste 			ctx = sc->fibctx;
3366a723a548SEd Maste 		} else {
3367a723a548SEd Maste 			ctx = ctx->next;
3368a723a548SEd Maste 		}
3369a723a548SEd Maste 	}
3370a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3371a723a548SEd Maste 
3372a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3373a723a548SEd Maste 	if (error)
3374a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3375a723a548SEd Maste 	return error;
3376a723a548SEd Maste }
3377a723a548SEd Maste 
3378a723a548SEd Maste /*
3379a723a548SEd Maste  * Close the caller's fib context
3380a723a548SEd Maste  */
3381a723a548SEd Maste static int
3382a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3383a723a548SEd Maste {
3384a723a548SEd Maste 	struct aac_fib_context *ctx;
3385a723a548SEd Maste 
338631a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3387a723a548SEd Maste 
3388a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3389a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3390a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3391a723a548SEd Maste 			if (ctx == sc->fibctx)
3392a723a548SEd Maste 				sc->fibctx = NULL;
3393a723a548SEd Maste 			else {
3394a723a548SEd Maste 				ctx->prev->next = ctx->next;
3395a723a548SEd Maste 				if (ctx->next)
3396a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3397a723a548SEd Maste 			}
3398a723a548SEd Maste 			break;
3399a723a548SEd Maste 		}
3400a723a548SEd Maste 	}
3401a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3402a723a548SEd Maste 	if (ctx)
3403a723a548SEd Maste 		free(ctx, M_AACBUF);
3404a723a548SEd Maste 
3405a723a548SEd Maste 	return 0;
3406a723a548SEd Maste }
3407a723a548SEd Maste 
3408a723a548SEd Maste /*
340935863739SMike Smith  * Pass the caller the next AIF in their queue
341035863739SMike Smith  */
341135863739SMike Smith static int
3412fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
341335863739SMike Smith {
341435863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3415a723a548SEd Maste 	struct aac_fib_context *ctx;
34169e2e96d8SScott Long 	int error;
341735863739SMike Smith 
341831a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
341935863739SMike Smith 
342035863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3421a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3422a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3423a723a548SEd Maste 				break;
3424a723a548SEd Maste 		}
3425a723a548SEd Maste 		if (!ctx)
3426a723a548SEd Maste 			return (EFAULT);
342735863739SMike Smith 
3428a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3429a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
343031a0399eSEd Maste 			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
343135863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
343235863739SMike Smith 			while (error == EAGAIN) {
3433914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3434914da7d0SScott Long 					       PCATCH, "aacaif", 0);
343535863739SMike Smith 				if (error == 0)
3436a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
343735863739SMike Smith 			}
343835863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
343935863739SMike Smith 		}
344035863739SMike Smith 	}
344135863739SMike Smith 	return(error);
344235863739SMike Smith }
344335863739SMike Smith 
3444914da7d0SScott Long /*
34450b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
34460b94a66eSMike Smith  */
34470b94a66eSMike Smith static int
3448a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
34490b94a66eSMike Smith {
3450a723a548SEd Maste 	int current, error;
34510b94a66eSMike Smith 
345231a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
34530b94a66eSMike Smith 
3454bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3455a723a548SEd Maste 	current = ctx->ctx_idx;
3456a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3457a723a548SEd Maste 		/* empty */
3458bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
34593df780cfSScott Long 		return (EAGAIN);
34603df780cfSScott Long 	}
3461a723a548SEd Maste 	error =
3462a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
346336e0bf6eSScott Long 	if (error)
346470545d1aSScott Long 		device_printf(sc->aac_dev,
346570545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3466a723a548SEd Maste 	else {
3467a723a548SEd Maste 		ctx->ctx_wrap = 0;
3468a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3469a723a548SEd Maste 	}
3470bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
34710b94a66eSMike Smith 	return(error);
34720b94a66eSMike Smith }
347336e0bf6eSScott Long 
34747cb209f5SScott Long static int
34757cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
34767cb209f5SScott Long {
34777cb209f5SScott Long 	struct aac_pci_info {
34787cb209f5SScott Long 		u_int32_t bus;
34797cb209f5SScott Long 		u_int32_t slot;
34807cb209f5SScott Long 	} pciinf;
34817cb209f5SScott Long 	int error;
34827cb209f5SScott Long 
348331a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
34847cb209f5SScott Long 
34857cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
34867cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
34877cb209f5SScott Long 
34887cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
34897cb209f5SScott Long 			sizeof(struct aac_pci_info));
34907cb209f5SScott Long 
34917cb209f5SScott Long 	return (error);
34927cb209f5SScott Long }
34937cb209f5SScott Long 
34946d307336SEd Maste static int
34956d307336SEd Maste aac_supported_features(struct aac_softc *sc, caddr_t uptr)
34966d307336SEd Maste {
34976d307336SEd Maste 	struct aac_features f;
34986d307336SEd Maste 	int error;
34996d307336SEd Maste 
35006d307336SEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
35016d307336SEd Maste 
35026d307336SEd Maste 	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
35036d307336SEd Maste 		return (error);
35046d307336SEd Maste 
35056d307336SEd Maste 	/*
35066d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35076d307336SEd Maste 	 * ALL zero in the featuresState, the driver will return the current
35086d307336SEd Maste 	 * state of all the supported features, the data field will not be
35096d307336SEd Maste 	 * valid.
35106d307336SEd Maste 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
35116d307336SEd Maste 	 * a specific bit set in the featuresState, the driver will return the
35126d307336SEd Maste 	 * current state of this specific feature and whatever data that are
35136d307336SEd Maste 	 * associated with the feature in the data field or perform whatever
35146d307336SEd Maste 	 * action needed indicates in the data field.
35156d307336SEd Maste 	 */
35166d307336SEd Maste 	 if (f.feat.fValue == 0) {
35176d307336SEd Maste 		f.feat.fBits.largeLBA =
35186d307336SEd Maste 		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35196d307336SEd Maste 		/* TODO: In the future, add other features state here as well */
35206d307336SEd Maste 	} else {
35216d307336SEd Maste 		if (f.feat.fBits.largeLBA)
35226d307336SEd Maste 			f.feat.fBits.largeLBA =
35236d307336SEd Maste 			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
35246d307336SEd Maste 		/* TODO: Add other features state and data in the future */
35256d307336SEd Maste 	}
35266d307336SEd Maste 
35276d307336SEd Maste 	error = copyout(&f, uptr, sizeof (f));
35286d307336SEd Maste 	return (error);
35296d307336SEd Maste }
35306d307336SEd Maste 
3531914da7d0SScott Long /*
353236e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
353336e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
353436e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
353536e0bf6eSScott Long  */
353636e0bf6eSScott Long static int
353736e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
353836e0bf6eSScott Long {
353936e0bf6eSScott Long 	struct aac_query_disk query_disk;
354036e0bf6eSScott Long 	struct aac_container *co;
3541914da7d0SScott Long 	struct aac_disk	*disk;
354236e0bf6eSScott Long 	int error, id;
354336e0bf6eSScott Long 
354431a0399eSEd Maste 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
354536e0bf6eSScott Long 
3546914da7d0SScott Long 	disk = NULL;
3547914da7d0SScott Long 
3548914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3549914da7d0SScott Long 		       sizeof(struct aac_query_disk));
355036e0bf6eSScott Long 	if (error)
355136e0bf6eSScott Long 		return (error);
355236e0bf6eSScott Long 
355336e0bf6eSScott Long 	id = query_disk.ContainerNumber;
355436e0bf6eSScott Long 	if (id == -1)
355536e0bf6eSScott Long 		return (EINVAL);
355636e0bf6eSScott Long 
3557bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
355836e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
355936e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
356036e0bf6eSScott Long 			break;
356136e0bf6eSScott Long 		}
356236e0bf6eSScott Long 
356336e0bf6eSScott Long 	if (co == NULL) {
356436e0bf6eSScott Long 			query_disk.Valid = 0;
356536e0bf6eSScott Long 			query_disk.Locked = 0;
356636e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
356736e0bf6eSScott Long 	} else {
356836e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
356936e0bf6eSScott Long 		query_disk.Valid = 1;
3570914da7d0SScott Long 		query_disk.Locked =
3571914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
357236e0bf6eSScott Long 		query_disk.Deleted = 0;
3573b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
357436e0bf6eSScott Long 		query_disk.Target = disk->unit;
357536e0bf6eSScott Long 		query_disk.Lun = 0;
357636e0bf6eSScott Long 		query_disk.UnMapped = 0;
35777540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
35780b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
357936e0bf6eSScott Long 	}
3580bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
358136e0bf6eSScott Long 
3582914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3583914da7d0SScott Long 			sizeof(struct aac_query_disk));
358436e0bf6eSScott Long 
358536e0bf6eSScott Long 	return (error);
358636e0bf6eSScott Long }
358736e0bf6eSScott Long 
3588fe3cb0e1SScott Long static void
3589fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3590fe3cb0e1SScott Long {
3591fe3cb0e1SScott Long 	struct aac_fib *fib;
3592fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3593fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3594fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3595fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3596fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
359770545d1aSScott Long 	struct aac_sim *caminf;
3598fe3cb0e1SScott Long 	device_t child;
3599fe3cb0e1SScott Long 	int i, found, error;
3600fe3cb0e1SScott Long 
36011ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
360203b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3603fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
360439ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3605fe3cb0e1SScott Long 
3606fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3607fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3608fe3cb0e1SScott Long 	c_cmd->param = 0;
3609fe3cb0e1SScott Long 
3610fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3611fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3612fe3cb0e1SScott Long 	if (error) {
3613fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3614fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3615fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36161ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3617fe3cb0e1SScott Long 		return;
3618fe3cb0e1SScott Long 	}
3619fe3cb0e1SScott Long 
3620fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3621fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3622fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3623fe3cb0e1SScott Long 		    c_resp->Status);
3624fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36251ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3626fe3cb0e1SScott Long 		return;
3627fe3cb0e1SScott Long 	}
3628fe3cb0e1SScott Long 
3629fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3630fe3cb0e1SScott Long 
3631fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
363239ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
363339ee03c3SScott Long 
3634fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3635fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3636fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3637fe3cb0e1SScott Long 	vmi->ObjId = 0;
3638fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3639fe3cb0e1SScott Long 
3640fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
364142ef13a2SEd Maste 	    sizeof(struct aac_vmi_businf_resp));
3642fe3cb0e1SScott Long 	if (error) {
3643fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3644fe3cb0e1SScott Long 		    error);
3645fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36461ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3647fe3cb0e1SScott Long 		return;
3648fe3cb0e1SScott Long 	}
3649fe3cb0e1SScott Long 
3650fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3651fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3652fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3653fe3cb0e1SScott Long 		    vmi_resp->Status);
3654fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
36551ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3656fe3cb0e1SScott Long 		return;
3657fe3cb0e1SScott Long 	}
3658fe3cb0e1SScott Long 
3659fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3660fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
36611ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3662fe3cb0e1SScott Long 
3663fe3cb0e1SScott Long 	found = 0;
3664fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3665fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3666fe3cb0e1SScott Long 			continue;
3667fe3cb0e1SScott Long 
3668a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3669a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3670b5f516cdSScott Long 		if (caminf == NULL) {
3671b5f516cdSScott Long 			device_printf(sc->aac_dev,
3672b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3673b5f516cdSScott Long 			break;
36747cb209f5SScott Long 		};
3675fe3cb0e1SScott Long 
3676fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3677fe3cb0e1SScott Long 		if (child == NULL) {
3678b5f516cdSScott Long 			device_printf(sc->aac_dev,
3679b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3680b5f516cdSScott Long 			    i);
3681b5f516cdSScott Long 			free(caminf, M_AACBUF);
3682b5f516cdSScott Long 			break;
3683fe3cb0e1SScott Long 		}
3684fe3cb0e1SScott Long 
3685fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3686fe3cb0e1SScott Long 		caminf->BusNumber = i;
3687fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3688fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3689ddb8683eSScott Long 		caminf->sim_dev = child;
3690fe3cb0e1SScott Long 
3691fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3692fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
369370545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3694fe3cb0e1SScott Long 
3695fe3cb0e1SScott Long 		found = 1;
3696fe3cb0e1SScott Long 	}
3697fe3cb0e1SScott Long 
3698fe3cb0e1SScott Long 	if (found)
3699fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3700fe3cb0e1SScott Long 
3701fe3cb0e1SScott Long 	return;
3702fe3cb0e1SScott Long }
3703