xref: /freebsd/sys/dev/aac/aac.c (revision 42ef13a247221203f7eb77cfa5fe970291a2702c)
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 */
93c6eafcf2SScott Long static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
94c6eafcf2SScott Long 			       int error);
95fe94b852SScott Long static int	aac_check_firmware(struct aac_softc *sc);
9635863739SMike Smith static int	aac_init(struct aac_softc *sc);
9735863739SMike Smith static int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
98c6eafcf2SScott Long 				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
99c6eafcf2SScott Long 				 u_int32_t arg3, u_int32_t *sp);
100c6eafcf2SScott Long static int	aac_enqueue_fib(struct aac_softc *sc, int queue,
101f6c4dd3fSScott Long 				struct aac_command *cm);
102c6eafcf2SScott Long static int	aac_dequeue_fib(struct aac_softc *sc, int queue,
103914da7d0SScott Long 				u_int32_t *fib_size, struct aac_fib **fib_addr);
10436e0bf6eSScott Long static int	aac_enqueue_response(struct aac_softc *sc, int queue,
10536e0bf6eSScott Long 				     struct aac_fib *fib);
10635863739SMike Smith 
107b3457b51SScott Long /* Falcon/PPC interface */
108b3457b51SScott Long static int	aac_fa_get_fwstatus(struct aac_softc *sc);
109b3457b51SScott Long static void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
110b3457b51SScott Long static int	aac_fa_get_istatus(struct aac_softc *sc);
111b3457b51SScott Long static void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
112b3457b51SScott Long static void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
113b3457b51SScott Long 				   u_int32_t arg0, u_int32_t arg1,
114b3457b51SScott Long 				   u_int32_t arg2, u_int32_t arg3);
115a6d35632SScott Long static int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
116b3457b51SScott Long static void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
117b3457b51SScott Long 
118b3457b51SScott Long struct aac_interface aac_fa_interface = {
119b3457b51SScott Long 	aac_fa_get_fwstatus,
120b3457b51SScott Long 	aac_fa_qnotify,
121b3457b51SScott Long 	aac_fa_get_istatus,
122b3457b51SScott Long 	aac_fa_clear_istatus,
123b3457b51SScott Long 	aac_fa_set_mailbox,
124a6d35632SScott Long 	aac_fa_get_mailbox,
1257cb209f5SScott Long 	aac_fa_set_interrupts,
1267cb209f5SScott Long 	NULL, NULL, NULL
127b3457b51SScott Long };
128b3457b51SScott Long 
12935863739SMike Smith /* StrongARM interface */
13035863739SMike Smith static int	aac_sa_get_fwstatus(struct aac_softc *sc);
13135863739SMike Smith static void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13235863739SMike Smith static int	aac_sa_get_istatus(struct aac_softc *sc);
13335863739SMike Smith static void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13435863739SMike Smith static void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
135c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
136c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
137a6d35632SScott Long static int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13835863739SMike Smith static void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13935863739SMike Smith 
14035863739SMike Smith struct aac_interface aac_sa_interface = {
14135863739SMike Smith 	aac_sa_get_fwstatus,
14235863739SMike Smith 	aac_sa_qnotify,
14335863739SMike Smith 	aac_sa_get_istatus,
14435863739SMike Smith 	aac_sa_clear_istatus,
14535863739SMike Smith 	aac_sa_set_mailbox,
146a6d35632SScott Long 	aac_sa_get_mailbox,
1477cb209f5SScott Long 	aac_sa_set_interrupts,
1487cb209f5SScott Long 	NULL, NULL, NULL
14935863739SMike Smith };
15035863739SMike Smith 
15135863739SMike Smith /* i960Rx interface */
15235863739SMike Smith static int	aac_rx_get_fwstatus(struct aac_softc *sc);
15335863739SMike Smith static void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15435863739SMike Smith static int	aac_rx_get_istatus(struct aac_softc *sc);
15535863739SMike Smith static void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15635863739SMike Smith static void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
157c6eafcf2SScott Long 				   u_int32_t arg0, u_int32_t arg1,
158c6eafcf2SScott Long 				   u_int32_t arg2, u_int32_t arg3);
159a6d35632SScott Long static int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16035863739SMike Smith static void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
1617cb209f5SScott Long static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
1627cb209f5SScott Long static int aac_rx_get_outb_queue(struct aac_softc *sc);
1637cb209f5SScott Long static void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16435863739SMike Smith 
16535863739SMike Smith struct aac_interface aac_rx_interface = {
16635863739SMike Smith 	aac_rx_get_fwstatus,
16735863739SMike Smith 	aac_rx_qnotify,
16835863739SMike Smith 	aac_rx_get_istatus,
16935863739SMike Smith 	aac_rx_clear_istatus,
17035863739SMike Smith 	aac_rx_set_mailbox,
171a6d35632SScott Long 	aac_rx_get_mailbox,
1727cb209f5SScott Long 	aac_rx_set_interrupts,
1737cb209f5SScott Long 	aac_rx_send_command,
1747cb209f5SScott Long 	aac_rx_get_outb_queue,
1757cb209f5SScott Long 	aac_rx_set_outb_queue
17635863739SMike Smith };
17735863739SMike Smith 
1784afedc31SScott Long /* Rocket/MIPS interface */
1794afedc31SScott Long static int	aac_rkt_get_fwstatus(struct aac_softc *sc);
1804afedc31SScott Long static void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
1814afedc31SScott Long static int	aac_rkt_get_istatus(struct aac_softc *sc);
1824afedc31SScott Long static void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
1834afedc31SScott Long static void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
1844afedc31SScott Long 				    u_int32_t arg0, u_int32_t arg1,
1854afedc31SScott Long 				    u_int32_t arg2, u_int32_t arg3);
1864afedc31SScott Long static int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
1874afedc31SScott Long static void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
1887cb209f5SScott Long static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
1897cb209f5SScott Long static int aac_rkt_get_outb_queue(struct aac_softc *sc);
1907cb209f5SScott Long static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
1914afedc31SScott Long 
1924afedc31SScott Long struct aac_interface aac_rkt_interface = {
1934afedc31SScott Long 	aac_rkt_get_fwstatus,
1944afedc31SScott Long 	aac_rkt_qnotify,
1954afedc31SScott Long 	aac_rkt_get_istatus,
1964afedc31SScott Long 	aac_rkt_clear_istatus,
1974afedc31SScott Long 	aac_rkt_set_mailbox,
1984afedc31SScott Long 	aac_rkt_get_mailbox,
1997cb209f5SScott Long 	aac_rkt_set_interrupts,
2007cb209f5SScott Long 	aac_rkt_send_command,
2017cb209f5SScott Long 	aac_rkt_get_outb_queue,
2027cb209f5SScott Long 	aac_rkt_set_outb_queue
2034afedc31SScott Long };
2044afedc31SScott Long 
20535863739SMike Smith /* Debugging and Diagnostics */
20635863739SMike Smith static void	aac_describe_controller(struct aac_softc *sc);
2076965a493SScott Long static char	*aac_describe_code(struct aac_code_lookup *table,
208c6eafcf2SScott Long 				   u_int32_t code);
20935863739SMike Smith 
21035863739SMike Smith /* Management Interface */
21135863739SMike Smith static d_open_t		aac_open;
21235863739SMike Smith static d_close_t	aac_close;
21335863739SMike Smith static d_ioctl_t	aac_ioctl;
214b3457b51SScott Long static d_poll_t		aac_poll;
215c6eafcf2SScott Long static int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
216f355c0e0SEd Maste static int		aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
217c6eafcf2SScott Long static void		aac_handle_aif(struct aac_softc *sc,
21836e0bf6eSScott Long 					   struct aac_fib *fib);
219fb0c27d7SScott Long static int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
220a723a548SEd Maste static int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
221a723a548SEd Maste static int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
222fb0c27d7SScott Long static int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
223a723a548SEd Maste static int		aac_return_aif(struct aac_softc *sc,
224a723a548SEd Maste 					struct aac_fib_context *ctx, caddr_t uptr);
22536e0bf6eSScott Long static int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
2267cb209f5SScott Long static int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
2277cb209f5SScott Long static void		aac_ioctl_event(struct aac_softc *sc,
2287cb209f5SScott Long 				        struct aac_event *event, void *arg);
22935863739SMike Smith 
23035863739SMike Smith static struct cdevsw aac_cdevsw = {
231dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
232dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
2337ac40f5fSPoul-Henning Kamp 	.d_open =	aac_open,
2347ac40f5fSPoul-Henning Kamp 	.d_close =	aac_close,
2357ac40f5fSPoul-Henning Kamp 	.d_ioctl =	aac_ioctl,
2367ac40f5fSPoul-Henning Kamp 	.d_poll =	aac_poll,
2377ac40f5fSPoul-Henning Kamp 	.d_name =	"aac",
23835863739SMike Smith };
23935863739SMike Smith 
24036e0bf6eSScott Long MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
24136e0bf6eSScott Long 
2423d04a9d7SScott Long /* sysctl node */
2433d04a9d7SScott Long SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
2443d04a9d7SScott Long 
245914da7d0SScott Long /*
246914da7d0SScott Long  * Device Interface
247914da7d0SScott Long  */
24835863739SMike Smith 
249914da7d0SScott Long /*
2504109ba51SEd Maste  * Initialize the controller and softc
25135863739SMike Smith  */
25235863739SMike Smith int
25335863739SMike Smith aac_attach(struct aac_softc *sc)
25435863739SMike Smith {
25535863739SMike Smith 	int error, unit;
25635863739SMike Smith 
25735863739SMike Smith 	debug_called(1);
25835863739SMike Smith 
25935863739SMike Smith 	/*
2604109ba51SEd Maste 	 * Initialize per-controller queues.
26135863739SMike Smith 	 */
2620b94a66eSMike Smith 	aac_initq_free(sc);
2630b94a66eSMike Smith 	aac_initq_ready(sc);
2640b94a66eSMike Smith 	aac_initq_busy(sc);
2650b94a66eSMike Smith 	aac_initq_bio(sc);
26635863739SMike Smith 
26735863739SMike Smith 	/*
2684109ba51SEd Maste 	 * Initialize command-completion task.
26935863739SMike Smith 	 */
27035863739SMike Smith 	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
27135863739SMike Smith 
27235863739SMike Smith 	/* mark controller as suspended until we get ourselves organised */
27335863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
27435863739SMike Smith 
27535863739SMike Smith 	/*
276fe94b852SScott Long 	 * Check that the firmware on the card is supported.
277fe94b852SScott Long 	 */
278fe94b852SScott Long 	if ((error = aac_check_firmware(sc)) != 0)
279fe94b852SScott Long 		return(error);
280fe94b852SScott Long 
281f6b1c44dSScott Long 	/*
282f6b1c44dSScott Long 	 * Initialize locks
283f6b1c44dSScott Long 	 */
284bb6fe253SScott Long 	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
285bb6fe253SScott Long 	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
286bb6fe253SScott Long 	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
287f6b1c44dSScott Long 	TAILQ_INIT(&sc->aac_container_tqh);
288065dd78cSScott Long 	TAILQ_INIT(&sc->aac_ev_cmfree);
289f6b1c44dSScott Long 
2900b94a66eSMike Smith 	/*
2914109ba51SEd Maste 	 * Initialize the adapter.
29235863739SMike Smith 	 */
2930b94a66eSMike Smith 	if ((error = aac_init(sc)) != 0)
29435863739SMike Smith 		return(error);
29535863739SMike Smith 
29635863739SMike Smith 	/*
2977cb209f5SScott Long 	 * Allocate and connect our interrupt.
2987cb209f5SScott Long 	 */
2997cb209f5SScott Long 	sc->aac_irq_rid = 0;
3007cb209f5SScott Long 	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
3017cb209f5SScott Long 			   			  &sc->aac_irq_rid,
3027cb209f5SScott Long 			   			  RF_SHAREABLE |
3037cb209f5SScott Long 						  RF_ACTIVE)) == NULL) {
3047cb209f5SScott Long 		device_printf(sc->aac_dev, "can't allocate interrupt\n");
3057cb209f5SScott Long 		return (EINVAL);
3067cb209f5SScott Long 	}
3077cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
3087cb209f5SScott Long 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
309ef544f63SPaolo Pisati 				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
310ef544f63SPaolo Pisati 				   aac_new_intr, sc, &sc->aac_intr)) {
3117cb209f5SScott Long 			device_printf(sc->aac_dev, "can't set up interrupt\n");
3127cb209f5SScott Long 			return (EINVAL);
3137cb209f5SScott Long 		}
3147cb209f5SScott Long 	} else {
3157cb209f5SScott Long 		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
316ef544f63SPaolo Pisati 				   INTR_TYPE_BIO, aac_fast_intr, NULL,
3177cb209f5SScott Long 				   sc, &sc->aac_intr)) {
3187cb209f5SScott Long 			device_printf(sc->aac_dev,
3197cb209f5SScott Long 				      "can't set up FAST interrupt\n");
3207cb209f5SScott Long 			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
3217cb209f5SScott Long 					   INTR_MPSAFE|INTR_TYPE_BIO,
322ef544f63SPaolo Pisati 					   NULL, (driver_intr_t *)aac_fast_intr,
323ef544f63SPaolo Pisati 					   sc, &sc->aac_intr)) {
3247cb209f5SScott Long 				device_printf(sc->aac_dev,
3257cb209f5SScott Long 					     "can't set up MPSAFE interrupt\n");
3267cb209f5SScott Long 				return (EINVAL);
3277cb209f5SScott Long 			}
3287cb209f5SScott Long 		}
3297cb209f5SScott Long 	}
3307cb209f5SScott Long 
3317cb209f5SScott Long 	/*
33235863739SMike Smith 	 * Print a little information about the controller.
33335863739SMike Smith 	 */
33435863739SMike Smith 	aac_describe_controller(sc);
33535863739SMike Smith 
33635863739SMike Smith 	/*
337ae543596SScott Long 	 * Register to probe our containers later.
338ae543596SScott Long 	 */
33935863739SMike Smith 	sc->aac_ich.ich_func = aac_startup;
34035863739SMike Smith 	sc->aac_ich.ich_arg = sc;
34135863739SMike Smith 	if (config_intrhook_establish(&sc->aac_ich) != 0) {
342914da7d0SScott Long 		device_printf(sc->aac_dev,
343914da7d0SScott Long 			      "can't establish configuration hook\n");
34435863739SMike Smith 		return(ENXIO);
34535863739SMike Smith 	}
34635863739SMike Smith 
34735863739SMike Smith 	/*
34835863739SMike Smith 	 * Make the control device.
34935863739SMike Smith 	 */
35035863739SMike Smith 	unit = device_get_unit(sc->aac_dev);
3519e9466baSRobert Watson 	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
3529e9466baSRobert Watson 				 0640, "aac%d", unit);
353157fbb2eSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
3544aa620cdSScott Long 	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
35535863739SMike Smith 	sc->aac_dev_t->si_drv1 = sc;
35635863739SMike Smith 
35736e0bf6eSScott Long 	/* Create the AIF thread */
3583745c395SJulian Elischer 	if (kproc_create((void(*)(void *))aac_command_thread, sc,
359316ec49aSScott Long 		   &sc->aifthread, 0, 0, "aac%daif", unit))
36036e0bf6eSScott Long 		panic("Could not create AIF thread\n");
36136e0bf6eSScott Long 
36236e0bf6eSScott Long 	/* Register the shutdown method to only be called post-dump */
3635f54d522SScott Long 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
3645f54d522SScott Long 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
3655f54d522SScott Long 		device_printf(sc->aac_dev,
3665f54d522SScott Long 			      "shutdown event registration failed\n");
36736e0bf6eSScott Long 
368fe3cb0e1SScott Long 	/* Register with CAM for the non-DASD devices */
369a6d35632SScott Long 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
37070545d1aSScott Long 		TAILQ_INIT(&sc->aac_sim_tqh);
371fe3cb0e1SScott Long 		aac_get_bus_info(sc);
37270545d1aSScott Long 	}
373fe3cb0e1SScott Long 
37435863739SMike Smith 	return(0);
37535863739SMike Smith }
37635863739SMike Smith 
3777cb209f5SScott Long void
3787cb209f5SScott Long aac_add_event(struct aac_softc *sc, struct aac_event *event)
3797cb209f5SScott Long {
3807cb209f5SScott Long 
3817cb209f5SScott Long 	switch (event->ev_type & AAC_EVENT_MASK) {
3827cb209f5SScott Long 	case AAC_EVENT_CMFREE:
3837cb209f5SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
3847cb209f5SScott Long 		break;
3857cb209f5SScott Long 	default:
3867cb209f5SScott Long 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
3877cb209f5SScott Long 		    event->ev_type);
3887cb209f5SScott Long 		break;
3897cb209f5SScott Long 	}
3907cb209f5SScott Long 
3917cb209f5SScott Long 	return;
3927cb209f5SScott Long }
3937cb209f5SScott Long 
394914da7d0SScott Long /*
39535863739SMike Smith  * Probe for containers, create disks.
39635863739SMike Smith  */
39735863739SMike Smith static void
39835863739SMike Smith aac_startup(void *arg)
39935863739SMike Smith {
400914da7d0SScott Long 	struct aac_softc *sc;
401cbfd045bSScott Long 	struct aac_fib *fib;
402cbfd045bSScott Long 	struct aac_mntinfo *mi;
403cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
404795d7dc0SScott Long 	int count = 0, i = 0;
40535863739SMike Smith 
40635863739SMike Smith 	debug_called(1);
40735863739SMike Smith 
408914da7d0SScott Long 	sc = (struct aac_softc *)arg;
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 	mi = (struct aac_mntinfo *)&fib->data[0];
416cbfd045bSScott Long 
41735863739SMike Smith 	/* loop over possible containers */
41836e0bf6eSScott Long 	do {
41935863739SMike Smith 		/* request information on this container */
42039ee03c3SScott Long 		bzero(mi, sizeof(struct aac_mntinfo));
42139ee03c3SScott Long 		mi->Command = VM_NameServe;
42239ee03c3SScott Long 		mi->MntType = FT_FILESYS;
423cbfd045bSScott Long 		mi->MntCount = i;
424cbfd045bSScott Long 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
425cbfd045bSScott Long 				 sizeof(struct aac_mntinfo))) {
426795d7dc0SScott Long 			printf("error probing container %d", i);
42735863739SMike Smith 			continue;
42835863739SMike Smith 		}
42935863739SMike Smith 
430cbfd045bSScott Long 		mir = (struct aac_mntinforesp *)&fib->data[0];
431795d7dc0SScott Long 		/* XXX Need to check if count changed */
432795d7dc0SScott Long 		count = mir->MntRespCount;
433cbfd045bSScott Long 		aac_add_container(sc, mir, 0);
43436e0bf6eSScott Long 		i++;
435795d7dc0SScott Long 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
436cbfd045bSScott Long 
437cbfd045bSScott Long 	aac_release_sync_fib(sc);
4387cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
43935863739SMike Smith 
44035863739SMike Smith 	/* poke the bus to actually attach the child devices */
44135863739SMike Smith 	if (bus_generic_attach(sc->aac_dev))
44235863739SMike Smith 		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
44335863739SMike Smith 
44435863739SMike Smith 	/* mark the controller up */
44535863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
44635863739SMike Smith 
44735863739SMike Smith 	/* enable interrupts now */
44835863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
44935863739SMike Smith }
45035863739SMike Smith 
451914da7d0SScott Long /*
4524109ba51SEd Maste  * Create a device to represent a new container
453914da7d0SScott Long  */
454914da7d0SScott Long static void
455cbfd045bSScott Long aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
456914da7d0SScott Long {
457914da7d0SScott Long 	struct aac_container *co;
458914da7d0SScott Long 	device_t child;
459914da7d0SScott Long 
460914da7d0SScott Long 	/*
461914da7d0SScott Long 	 * Check container volume type for validity.  Note that many of
462914da7d0SScott Long 	 * the possible types may never show up.
463914da7d0SScott Long 	 */
464914da7d0SScott Long 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
465a761a1caSScott Long 		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
466a761a1caSScott Long 		       M_NOWAIT | M_ZERO);
467914da7d0SScott Long 		if (co == NULL)
468914da7d0SScott Long 			panic("Out of memory?!\n");
469914da7d0SScott Long 		debug(1, "id %x  name '%.16s'  size %u  type %d",
470914da7d0SScott Long 		      mir->MntTable[0].ObjectId,
471914da7d0SScott Long 		      mir->MntTable[0].FileSystemName,
472914da7d0SScott Long 		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
473914da7d0SScott Long 
474fe3cb0e1SScott Long 		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
475914da7d0SScott Long 			device_printf(sc->aac_dev, "device_add_child failed\n");
476914da7d0SScott Long 		else
477914da7d0SScott Long 			device_set_ivars(child, co);
478914da7d0SScott Long 		device_set_desc(child, aac_describe_code(aac_container_types,
479914da7d0SScott Long 				mir->MntTable[0].VolType));
480914da7d0SScott Long 		co->co_disk = child;
481914da7d0SScott Long 		co->co_found = f;
482914da7d0SScott Long 		bcopy(&mir->MntTable[0], &co->co_mntobj,
483914da7d0SScott Long 		      sizeof(struct aac_mntobj));
484bb6fe253SScott Long 		mtx_lock(&sc->aac_container_lock);
485914da7d0SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
486bb6fe253SScott Long 		mtx_unlock(&sc->aac_container_lock);
487914da7d0SScott Long 	}
488914da7d0SScott Long }
489914da7d0SScott Long 
490914da7d0SScott Long /*
49135863739SMike Smith  * Free all of the resources associated with (sc)
49235863739SMike Smith  *
49335863739SMike Smith  * Should not be called if the controller is active.
49435863739SMike Smith  */
49535863739SMike Smith void
49635863739SMike Smith aac_free(struct aac_softc *sc)
49735863739SMike Smith {
498ffb37f33SScott Long 
49935863739SMike Smith 	debug_called(1);
50035863739SMike Smith 
50135863739SMike Smith 	/* remove the control device */
50235863739SMike Smith 	if (sc->aac_dev_t != NULL)
50335863739SMike Smith 		destroy_dev(sc->aac_dev_t);
50435863739SMike Smith 
5050b94a66eSMike Smith 	/* throw away any FIB buffers, discard the FIB DMA tag */
5068480cc63SScott Long 	aac_free_commands(sc);
5070b94a66eSMike Smith 	if (sc->aac_fib_dmat)
5080b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_fib_dmat);
50935863739SMike Smith 
510ffb37f33SScott Long 	free(sc->aac_commands, M_AACBUF);
511ffb37f33SScott Long 
51235863739SMike Smith 	/* destroy the common area */
51335863739SMike Smith 	if (sc->aac_common) {
51435863739SMike Smith 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
515c6eafcf2SScott Long 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
516c6eafcf2SScott Long 				sc->aac_common_dmamap);
51735863739SMike Smith 	}
5180b94a66eSMike Smith 	if (sc->aac_common_dmat)
5190b94a66eSMike Smith 		bus_dma_tag_destroy(sc->aac_common_dmat);
52035863739SMike Smith 
52135863739SMike Smith 	/* disconnect the interrupt handler */
52235863739SMike Smith 	if (sc->aac_intr)
52335863739SMike Smith 		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
52435863739SMike Smith 	if (sc->aac_irq != NULL)
525c6eafcf2SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
526c6eafcf2SScott Long 				     sc->aac_irq);
52735863739SMike Smith 
52835863739SMike Smith 	/* destroy data-transfer DMA tag */
52935863739SMike Smith 	if (sc->aac_buffer_dmat)
53035863739SMike Smith 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
53135863739SMike Smith 
53235863739SMike Smith 	/* destroy the parent DMA tag */
53335863739SMike Smith 	if (sc->aac_parent_dmat)
53435863739SMike Smith 		bus_dma_tag_destroy(sc->aac_parent_dmat);
53535863739SMike Smith 
53635863739SMike Smith 	/* release the register window mapping */
53735863739SMike Smith 	if (sc->aac_regs_resource != NULL)
538914da7d0SScott Long 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
539914da7d0SScott Long 				     sc->aac_regs_rid, sc->aac_regs_resource);
54035863739SMike Smith }
54135863739SMike Smith 
542914da7d0SScott Long /*
54335863739SMike Smith  * Disconnect from the controller completely, in preparation for unload.
54435863739SMike Smith  */
54535863739SMike Smith int
54635863739SMike Smith aac_detach(device_t dev)
54735863739SMike Smith {
548914da7d0SScott Long 	struct aac_softc *sc;
54970545d1aSScott Long 	struct aac_container *co;
55070545d1aSScott Long 	struct aac_sim	*sim;
55135863739SMike Smith 	int error;
55235863739SMike Smith 
55335863739SMike Smith 	debug_called(1);
55435863739SMike Smith 
555914da7d0SScott Long 	sc = device_get_softc(dev);
556914da7d0SScott Long 
55735863739SMike Smith 	if (sc->aac_state & AAC_STATE_OPEN)
55835863739SMike Smith 		return(EBUSY);
55935863739SMike Smith 
56070545d1aSScott Long 	/* Remove the child containers */
561a761a1caSScott Long 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
56270545d1aSScott Long 		error = device_delete_child(dev, co->co_disk);
56370545d1aSScott Long 		if (error)
56470545d1aSScott Long 			return (error);
56565ac4ed6SScott Long 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
566a761a1caSScott Long 		free(co, M_AACBUF);
56770545d1aSScott Long 	}
56870545d1aSScott Long 
56970545d1aSScott Long 	/* Remove the CAM SIMs */
570a761a1caSScott Long 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
571a761a1caSScott Long 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
57270545d1aSScott Long 		error = device_delete_child(dev, sim->sim_dev);
57370545d1aSScott Long 		if (error)
57470545d1aSScott Long 			return (error);
575a761a1caSScott Long 		free(sim, M_AACBUF);
57670545d1aSScott Long 	}
57770545d1aSScott Long 
57836e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
57936e0bf6eSScott Long 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
58036e0bf6eSScott Long 		wakeup(sc->aifthread);
58136e0bf6eSScott Long 		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
58236e0bf6eSScott Long 	}
58336e0bf6eSScott Long 
58436e0bf6eSScott Long 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
58536e0bf6eSScott Long 		panic("Cannot shutdown AIF thread\n");
58636e0bf6eSScott Long 
58735863739SMike Smith 	if ((error = aac_shutdown(dev)))
58835863739SMike Smith 		return(error);
58935863739SMike Smith 
5905f54d522SScott Long 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
5915f54d522SScott Long 
59235863739SMike Smith 	aac_free(sc);
59335863739SMike Smith 
594dc9efde5SScott Long 	mtx_destroy(&sc->aac_aifq_lock);
595dc9efde5SScott Long 	mtx_destroy(&sc->aac_io_lock);
596dc9efde5SScott Long 	mtx_destroy(&sc->aac_container_lock);
597dc9efde5SScott Long 
59835863739SMike Smith 	return(0);
59935863739SMike Smith }
60035863739SMike Smith 
601914da7d0SScott Long /*
60235863739SMike Smith  * Bring the controller down to a dormant state and detach all child devices.
60335863739SMike Smith  *
60435863739SMike Smith  * This function is called before detach or system shutdown.
60535863739SMike Smith  *
6060b94a66eSMike Smith  * Note that we can assume that the bioq on the controller is empty, as we won't
60735863739SMike Smith  * allow shutdown if any device is open.
60835863739SMike Smith  */
60935863739SMike Smith int
61035863739SMike Smith aac_shutdown(device_t dev)
61135863739SMike Smith {
612914da7d0SScott Long 	struct aac_softc *sc;
613cbfd045bSScott Long 	struct aac_fib *fib;
614cbfd045bSScott Long 	struct aac_close_command *cc;
61535863739SMike Smith 
61635863739SMike Smith 	debug_called(1);
61735863739SMike Smith 
618914da7d0SScott Long 	sc = device_get_softc(dev);
619914da7d0SScott Long 
62035863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
62135863739SMike Smith 
62235863739SMike Smith 	/*
62335863739SMike Smith 	 * Send a Container shutdown followed by a HostShutdown FIB to the
62435863739SMike Smith 	 * controller to convince it that we don't want to talk to it anymore.
62535863739SMike Smith 	 * We've been closed and all I/O completed already
62635863739SMike Smith 	 */
62735863739SMike Smith 	device_printf(sc->aac_dev, "shutting down controller...");
62835863739SMike Smith 
6297cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
63003b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
631cbfd045bSScott Long 	cc = (struct aac_close_command *)&fib->data[0];
632cbfd045bSScott Long 
63339ee03c3SScott Long 	bzero(cc, sizeof(struct aac_close_command));
634cbfd045bSScott Long 	cc->Command = VM_CloseAll;
635cbfd045bSScott Long 	cc->ContainerId = 0xffffffff;
636cbfd045bSScott Long 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
637cbfd045bSScott Long 	    sizeof(struct aac_close_command)))
63835863739SMike Smith 		printf("FAILED.\n");
63970545d1aSScott Long 	else
64070545d1aSScott Long 		printf("done\n");
64170545d1aSScott Long #if 0
642914da7d0SScott Long 	else {
643cbfd045bSScott Long 		fib->data[0] = 0;
64436e0bf6eSScott Long 		/*
645914da7d0SScott Long 		 * XXX Issuing this command to the controller makes it shut down
64636e0bf6eSScott Long 		 * but also keeps it from coming back up without a reset of the
64736e0bf6eSScott Long 		 * PCI bus.  This is not desirable if you are just unloading the
64836e0bf6eSScott Long 		 * driver module with the intent to reload it later.
64936e0bf6eSScott Long 		 */
650cbfd045bSScott Long 		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
651cbfd045bSScott Long 		    fib, 1)) {
65235863739SMike Smith 			printf("FAILED.\n");
65335863739SMike Smith 		} else {
65435863739SMike Smith 			printf("done.\n");
65535863739SMike Smith 		}
65635863739SMike Smith 	}
65770545d1aSScott Long #endif
65835863739SMike Smith 
65935863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
6603576af8fSScott Long 	aac_release_sync_fib(sc);
6617cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
66235863739SMike Smith 
66335863739SMike Smith 	return(0);
66435863739SMike Smith }
66535863739SMike Smith 
666914da7d0SScott Long /*
66735863739SMike Smith  * Bring the controller to a quiescent state, ready for system suspend.
66835863739SMike Smith  */
66935863739SMike Smith int
67035863739SMike Smith aac_suspend(device_t dev)
67135863739SMike Smith {
672914da7d0SScott Long 	struct aac_softc *sc;
67335863739SMike Smith 
67435863739SMike Smith 	debug_called(1);
675914da7d0SScott Long 
676914da7d0SScott Long 	sc = device_get_softc(dev);
677914da7d0SScott Long 
67835863739SMike Smith 	sc->aac_state |= AAC_STATE_SUSPEND;
67935863739SMike Smith 
68035863739SMike Smith 	AAC_MASK_INTERRUPTS(sc);
68135863739SMike Smith 	return(0);
68235863739SMike Smith }
68335863739SMike Smith 
684914da7d0SScott Long /*
68535863739SMike Smith  * Bring the controller back to a state ready for operation.
68635863739SMike Smith  */
68735863739SMike Smith int
68835863739SMike Smith aac_resume(device_t dev)
68935863739SMike Smith {
690914da7d0SScott Long 	struct aac_softc *sc;
69135863739SMike Smith 
69235863739SMike Smith 	debug_called(1);
693914da7d0SScott Long 
694914da7d0SScott Long 	sc = device_get_softc(dev);
695914da7d0SScott Long 
69635863739SMike Smith 	sc->aac_state &= ~AAC_STATE_SUSPEND;
69735863739SMike Smith 	AAC_UNMASK_INTERRUPTS(sc);
69835863739SMike Smith 	return(0);
69935863739SMike Smith }
70035863739SMike Smith 
701914da7d0SScott Long /*
7027cb209f5SScott Long  * Interrupt handler for NEW_COMM interface.
70335863739SMike Smith  */
70435863739SMike Smith void
7057cb209f5SScott Long aac_new_intr(void *arg)
7067cb209f5SScott Long {
7077cb209f5SScott Long 	struct aac_softc *sc;
7087cb209f5SScott Long 	u_int32_t index, fast;
7097cb209f5SScott Long 	struct aac_command *cm;
7107cb209f5SScott Long 	struct aac_fib *fib;
7117cb209f5SScott Long 	int i;
7127cb209f5SScott Long 
7137cb209f5SScott Long 	debug_called(2);
7147cb209f5SScott Long 
7157cb209f5SScott Long 	sc = (struct aac_softc *)arg;
7167cb209f5SScott Long 
7177cb209f5SScott Long 	mtx_lock(&sc->aac_io_lock);
7187cb209f5SScott Long 	while (1) {
7197cb209f5SScott Long 		index = AAC_GET_OUTB_QUEUE(sc);
7207cb209f5SScott Long 		if (index == 0xffffffff)
7217cb209f5SScott Long 			index = AAC_GET_OUTB_QUEUE(sc);
7227cb209f5SScott Long 		if (index == 0xffffffff)
7237cb209f5SScott Long 			break;
7247cb209f5SScott Long 		if (index & 2) {
7257cb209f5SScott Long 			if (index == 0xfffffffe) {
7267cb209f5SScott Long 				/* XXX This means that the controller wants
7277cb209f5SScott Long 				 * more work.  Ignore it for now.
7287cb209f5SScott Long 				 */
7297cb209f5SScott Long 				continue;
7307cb209f5SScott Long 			}
7317cb209f5SScott Long 			/* AIF */
7327cb209f5SScott Long 			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
7337cb209f5SScott Long 				   M_NOWAIT | M_ZERO);
7347cb209f5SScott Long 			if (fib == NULL) {
7357cb209f5SScott Long 				/* If we're really this short on memory,
7367cb209f5SScott Long 				 * hopefully breaking out of the handler will
7377cb209f5SScott Long 				 * allow something to get freed.  This
7387cb209f5SScott Long 				 * actually sucks a whole lot.
7397cb209f5SScott Long 				 */
7407cb209f5SScott Long 				break;
7417cb209f5SScott Long 			}
7427cb209f5SScott Long 			index &= ~2;
7437cb209f5SScott Long 			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
7447cb209f5SScott Long 				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
7457cb209f5SScott Long 			aac_handle_aif(sc, fib);
7467cb209f5SScott Long 			free(fib, M_AACBUF);
7477cb209f5SScott Long 
7487cb209f5SScott Long 			/*
7497cb209f5SScott Long 			 * AIF memory is owned by the adapter, so let it
7507cb209f5SScott Long 			 * know that we are done with it.
7517cb209f5SScott Long 			 */
7527cb209f5SScott Long 			AAC_SET_OUTB_QUEUE(sc, index);
7537cb209f5SScott Long 			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
7547cb209f5SScott Long 		} else {
7557cb209f5SScott Long 			fast = index & 1;
7567cb209f5SScott Long 			cm = sc->aac_commands + (index >> 2);
7577cb209f5SScott Long 			fib = cm->cm_fib;
7587cb209f5SScott Long 			if (fast) {
7597cb209f5SScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
7607cb209f5SScott Long 				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
7617cb209f5SScott Long 			}
7627cb209f5SScott Long 			aac_remove_busy(cm);
7637cb209f5SScott Long  			aac_unmap_command(cm);
7647cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_COMPLETED;
7657cb209f5SScott Long 
7667cb209f5SScott Long 			/* is there a completion handler? */
7677cb209f5SScott Long 			if (cm->cm_complete != NULL) {
7687cb209f5SScott Long 				cm->cm_complete(cm);
7697cb209f5SScott Long 			} else {
7707cb209f5SScott Long 				/* assume that someone is sleeping on this
7717cb209f5SScott Long 				 * command
7727cb209f5SScott Long 				 */
7737cb209f5SScott Long 				wakeup(cm);
7747cb209f5SScott Long 			}
7757cb209f5SScott Long 			sc->flags &= ~AAC_QUEUE_FRZN;
7767cb209f5SScott Long 		}
7777cb209f5SScott Long 	}
7787cb209f5SScott Long 	/* see if we can start some more I/O */
7797cb209f5SScott Long 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
7807cb209f5SScott Long 		aac_startio(sc);
7817cb209f5SScott Long 
7827cb209f5SScott Long 	mtx_unlock(&sc->aac_io_lock);
7837cb209f5SScott Long }
7847cb209f5SScott Long 
785ef544f63SPaolo Pisati int
7867cb209f5SScott Long aac_fast_intr(void *arg)
78735863739SMike Smith {
788914da7d0SScott Long 	struct aac_softc *sc;
78970545d1aSScott Long 	u_int16_t reason;
79035863739SMike Smith 
79135863739SMike Smith 	debug_called(2);
79235863739SMike Smith 
793914da7d0SScott Long 	sc = (struct aac_softc *)arg;
794914da7d0SScott Long 
795f30ac74cSScott Long 	/*
7969148fa21SScott Long 	 * Read the status register directly.  This is faster than taking the
7979148fa21SScott Long 	 * driver lock and reading the queues directly.  It also saves having
7989148fa21SScott Long 	 * to turn parts of the driver lock into a spin mutex, which would be
7999148fa21SScott Long 	 * ugly.
800f30ac74cSScott Long 	 */
80135863739SMike Smith 	reason = AAC_GET_ISTATUS(sc);
802f30ac74cSScott Long 	AAC_CLEAR_ISTATUS(sc, reason);
803f30ac74cSScott Long 
8049c3a7fceSScott Long 	/* handle completion processing */
8059148fa21SScott Long 	if (reason & AAC_DB_RESPONSE_READY)
8069148fa21SScott Long 		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
80735863739SMike Smith 
8089148fa21SScott Long 	/* controller wants to talk to us */
8099148fa21SScott Long 	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
81070545d1aSScott Long 		/*
8119148fa21SScott Long 		 * XXX Make sure that we don't get fooled by strange messages
8129148fa21SScott Long 		 * that start with a NULL.
81370545d1aSScott Long 		 */
8149148fa21SScott Long 		if ((reason & AAC_DB_PRINTF) &&
8159148fa21SScott Long 			(sc->aac_common->ac_printf[0] == 0))
8169148fa21SScott Long 			sc->aac_common->ac_printf[0] = 32;
81770545d1aSScott Long 
8189148fa21SScott Long 		/*
8199148fa21SScott Long 		 * This might miss doing the actual wakeup.  However, the
820a32a982dSScott Long 		 * msleep that this is waking up has a timeout, so it will
8219148fa21SScott Long 		 * wake up eventually.  AIFs and printfs are low enough
8229148fa21SScott Long 		 * priority that they can handle hanging out for a few seconds
8239148fa21SScott Long 		 * if needed.
8249148fa21SScott Long 		 */
82536e0bf6eSScott Long 		wakeup(sc->aifthread);
82636e0bf6eSScott Long 	}
827ef544f63SPaolo Pisati 	return (FILTER_HANDLED);
8289148fa21SScott Long }
82935863739SMike Smith 
830c6eafcf2SScott Long /*
831914da7d0SScott Long  * Command Processing
832914da7d0SScott Long  */
83335863739SMike Smith 
834914da7d0SScott Long /*
83535863739SMike Smith  * Start as much queued I/O as possible on the controller
83635863739SMike Smith  */
837fe3cb0e1SScott Long void
83835863739SMike Smith aac_startio(struct aac_softc *sc)
83935863739SMike Smith {
84035863739SMike Smith 	struct aac_command *cm;
841397fa34fSScott Long 	int error;
84235863739SMike Smith 
84335863739SMike Smith 	debug_called(2);
84435863739SMike Smith 
84535863739SMike Smith 	for (;;) {
846914da7d0SScott Long 		/*
847397fa34fSScott Long 		 * This flag might be set if the card is out of resources.
848397fa34fSScott Long 		 * Checking it here prevents an infinite loop of deferrals.
849397fa34fSScott Long 		 */
850397fa34fSScott Long 		if (sc->flags & AAC_QUEUE_FRZN)
851397fa34fSScott Long 			break;
852397fa34fSScott Long 
853397fa34fSScott Long 		/*
854914da7d0SScott Long 		 * Try to get a command that's been put off for lack of
855914da7d0SScott Long 		 * resources
856914da7d0SScott Long 		 */
85735863739SMike Smith 		cm = aac_dequeue_ready(sc);
85835863739SMike Smith 
859914da7d0SScott Long 		/*
860914da7d0SScott Long 		 * Try to build a command off the bio queue (ignore error
861914da7d0SScott Long 		 * return)
862914da7d0SScott Long 		 */
8630b94a66eSMike Smith 		if (cm == NULL)
86435863739SMike Smith 			aac_bio_command(sc, &cm);
86535863739SMike Smith 
86635863739SMike Smith 		/* nothing to do? */
86735863739SMike Smith 		if (cm == NULL)
86835863739SMike Smith 			break;
86935863739SMike Smith 
870cd481291SScott Long 		/* don't map more than once */
871cd481291SScott Long 		if (cm->cm_flags & AAC_CMD_MAPPED)
8724102d44bSScott Long 			panic("aac: command %p already mapped", cm);
87335863739SMike Smith 
874397fa34fSScott Long 		/*
875397fa34fSScott Long 		 * Set up the command to go to the controller.  If there are no
876397fa34fSScott Long 		 * data buffers associated with the command then it can bypass
877397fa34fSScott Long 		 * busdma.
878397fa34fSScott Long 		 */
879cd481291SScott Long 		if (cm->cm_datalen != 0) {
880397fa34fSScott Long 			error = bus_dmamap_load(sc->aac_buffer_dmat,
881397fa34fSScott Long 						cm->cm_datamap, cm->cm_data,
882397fa34fSScott Long 						cm->cm_datalen,
883cd481291SScott Long 						aac_map_command_sg, cm, 0);
884cd481291SScott Long 			if (error == EINPROGRESS) {
885cd481291SScott Long 				debug(1, "freezing queue\n");
886cd481291SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
887cd481291SScott Long 				error = 0;
888614c22b2SScott Long 			} else if (error != 0)
889397fa34fSScott Long 				panic("aac_startio: unexpected error %d from "
890397fa34fSScott Long 				      "busdma\n", error);
891397fa34fSScott Long 		} else
8928778f63dSScott Long 			aac_map_command_sg(cm, NULL, 0, 0);
893cd481291SScott Long 	}
89435863739SMike Smith }
89535863739SMike Smith 
896914da7d0SScott Long /*
89735863739SMike Smith  * Handle notification of one or more FIBs coming from the controller.
89835863739SMike Smith  */
89935863739SMike Smith static void
90070545d1aSScott Long aac_command_thread(struct aac_softc *sc)
90135863739SMike Smith {
90235863739SMike Smith 	struct aac_fib *fib;
90335863739SMike Smith 	u_int32_t fib_size;
9049148fa21SScott Long 	int size, retval;
90535863739SMike Smith 
90636e0bf6eSScott Long 	debug_called(2);
90735863739SMike Smith 
908bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
909a32a982dSScott Long 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
91036e0bf6eSScott Long 
911a32a982dSScott Long 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
912a32a982dSScott Long 
913a32a982dSScott Long 		retval = 0;
914a32a982dSScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
915a32a982dSScott Long 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
916a32a982dSScott Long 					"aifthd", AAC_PERIODIC_INTERVAL * hz);
91736e0bf6eSScott Long 
9189148fa21SScott Long 		/*
9199148fa21SScott Long 		 * First see if any FIBs need to be allocated.  This needs
9209148fa21SScott Long 		 * to be called without the driver lock because contigmalloc
9219148fa21SScott Long 		 * will grab Giant, and would result in an LOR.
9229148fa21SScott Long 		 */
9239148fa21SScott Long 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
924bb6fe253SScott Long 			mtx_unlock(&sc->aac_io_lock);
925a32a982dSScott Long 			aac_alloc_commands(sc);
926bb6fe253SScott Long 			mtx_lock(&sc->aac_io_lock);
9274102d44bSScott Long 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
928a32a982dSScott Long 			aac_startio(sc);
929a32a982dSScott Long 		}
9309148fa21SScott Long 
9319148fa21SScott Long 		/*
9329148fa21SScott Long 		 * While we're here, check to see if any commands are stuck.
9339148fa21SScott Long 		 * This is pretty low-priority, so it's ok if it doesn't
9349148fa21SScott Long 		 * always fire.
9359148fa21SScott Long 		 */
9369148fa21SScott Long 		if (retval == EWOULDBLOCK)
93770545d1aSScott Long 			aac_timeout(sc);
93870545d1aSScott Long 
93970545d1aSScott Long 		/* Check the hardware printf message buffer */
9409148fa21SScott Long 		if (sc->aac_common->ac_printf[0] != 0)
94170545d1aSScott Long 			aac_print_printf(sc);
94270545d1aSScott Long 
9439148fa21SScott Long 		/* Also check to see if the adapter has a command for us. */
9447cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
9457cb209f5SScott Long 			continue;
9467cb209f5SScott Long 		for (;;) {
9477cb209f5SScott Long 			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
9487cb209f5SScott Long 					   &fib_size, &fib))
9497cb209f5SScott Long 				break;
95035863739SMike Smith 
95136e0bf6eSScott Long 			AAC_PRINT_FIB(sc, fib);
95236e0bf6eSScott Long 
95335863739SMike Smith 			switch (fib->Header.Command) {
95435863739SMike Smith 			case AifRequest:
95536e0bf6eSScott Long 				aac_handle_aif(sc, fib);
95635863739SMike Smith 				break;
95735863739SMike Smith 			default:
958914da7d0SScott Long 				device_printf(sc->aac_dev, "unknown command "
959914da7d0SScott Long 					      "from controller\n");
96035863739SMike Smith 				break;
96135863739SMike Smith 			}
96235863739SMike Smith 
96336e0bf6eSScott Long 			if ((fib->Header.XferState == 0) ||
9647cb209f5SScott Long 			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
96536e0bf6eSScott Long 				break;
9667cb209f5SScott Long 			}
96736e0bf6eSScott Long 
96870545d1aSScott Long 			/* Return the AIF to the controller. */
96936e0bf6eSScott Long 			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
97036e0bf6eSScott Long 				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
97136e0bf6eSScott Long 				*(AAC_FSAStatus*)fib->data = ST_OK;
97236e0bf6eSScott Long 
97336e0bf6eSScott Long 				/* XXX Compute the Size field? */
97436e0bf6eSScott Long 				size = fib->Header.Size;
97536e0bf6eSScott Long 				if (size > sizeof(struct aac_fib)) {
97636e0bf6eSScott Long 					size = sizeof(struct aac_fib);
97736e0bf6eSScott Long 					fib->Header.Size = size;
97836e0bf6eSScott Long 				}
97936e0bf6eSScott Long 				/*
980914da7d0SScott Long 				 * Since we did not generate this command, it
981914da7d0SScott Long 				 * cannot go through the normal
982914da7d0SScott Long 				 * enqueue->startio chain.
98336e0bf6eSScott Long 				 */
984914da7d0SScott Long 				aac_enqueue_response(sc,
985914da7d0SScott Long 						 AAC_ADAP_NORM_RESP_QUEUE,
986914da7d0SScott Long 						 fib);
98736e0bf6eSScott Long 			}
98836e0bf6eSScott Long 		}
98936e0bf6eSScott Long 	}
99036e0bf6eSScott Long 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
991bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
99236e0bf6eSScott Long 	wakeup(sc->aac_dev);
99336e0bf6eSScott Long 
9943745c395SJulian Elischer 	kproc_exit(0);
99535863739SMike Smith }
99635863739SMike Smith 
997914da7d0SScott Long /*
9989c3a7fceSScott Long  * Process completed commands.
99935863739SMike Smith  */
100035863739SMike Smith static void
10019c3a7fceSScott Long aac_complete(void *context, int pending)
100235863739SMike Smith {
10039c3a7fceSScott Long 	struct aac_softc *sc;
100435863739SMike Smith 	struct aac_command *cm;
100535863739SMike Smith 	struct aac_fib *fib;
100635863739SMike Smith 	u_int32_t fib_size;
100735863739SMike Smith 
100835863739SMike Smith 	debug_called(2);
100935863739SMike Smith 
10109c3a7fceSScott Long 	sc = (struct aac_softc *)context;
10119c3a7fceSScott Long 
1012bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
1013ae543596SScott Long 
10149c3a7fceSScott Long 	/* pull completed commands off the queue */
101535863739SMike Smith 	for (;;) {
101635863739SMike Smith 		/* look for completed FIBs on our queue */
1017914da7d0SScott Long 		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1018914da7d0SScott Long 							&fib))
101935863739SMike Smith 			break;	/* nothing to do */
102035863739SMike Smith 
1021ecd1c51fSScott Long 		/* get the command, unmap and hand off for processing */
1022cb0d64b9SScott Long 		cm = sc->aac_commands + fib->Header.SenderData;
102335863739SMike Smith 		if (cm == NULL) {
102435863739SMike Smith 			AAC_PRINT_FIB(sc, fib);
10259c3a7fceSScott Long 			break;
10269c3a7fceSScott Long 		}
10270b94a66eSMike Smith 		aac_remove_busy(cm);
10287cb209f5SScott Long 
1029ecd1c51fSScott Long  		aac_unmap_command(cm);
103035863739SMike Smith 		cm->cm_flags |= AAC_CMD_COMPLETED;
103135863739SMike Smith 
103235863739SMike Smith 		/* is there a completion handler? */
103335863739SMike Smith 		if (cm->cm_complete != NULL) {
103435863739SMike Smith 			cm->cm_complete(cm);
103535863739SMike Smith 		} else {
103635863739SMike Smith 			/* assume that someone is sleeping on this command */
103735863739SMike Smith 			wakeup(cm);
103835863739SMike Smith 		}
103935863739SMike Smith 	}
10400b94a66eSMike Smith 
10410b94a66eSMike Smith 	/* see if we can start some more I/O */
1042cd481291SScott Long 	sc->flags &= ~AAC_QUEUE_FRZN;
10430b94a66eSMike Smith 	aac_startio(sc);
1044ae543596SScott Long 
1045bb6fe253SScott Long 	mtx_unlock(&sc->aac_io_lock);
104635863739SMike Smith }
104735863739SMike Smith 
1048914da7d0SScott Long /*
104935863739SMike Smith  * Handle a bio submitted from a disk device.
105035863739SMike Smith  */
105135863739SMike Smith void
105235863739SMike Smith aac_submit_bio(struct bio *bp)
105335863739SMike Smith {
1054914da7d0SScott Long 	struct aac_disk *ad;
1055914da7d0SScott Long 	struct aac_softc *sc;
105635863739SMike Smith 
105735863739SMike Smith 	debug_called(2);
105835863739SMike Smith 
10597540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1060914da7d0SScott Long 	sc = ad->ad_controller;
1061914da7d0SScott Long 
106235863739SMike Smith 	/* queue the BIO and try to get some work done */
10630b94a66eSMike Smith 	aac_enqueue_bio(sc, bp);
106435863739SMike Smith 	aac_startio(sc);
106535863739SMike Smith }
106635863739SMike Smith 
1067914da7d0SScott Long /*
106835863739SMike Smith  * Get a bio and build a command to go with it.
106935863739SMike Smith  */
107035863739SMike Smith static int
107135863739SMike Smith aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
107235863739SMike Smith {
107335863739SMike Smith 	struct aac_command *cm;
107435863739SMike Smith 	struct aac_fib *fib;
107535863739SMike Smith 	struct aac_disk *ad;
107635863739SMike Smith 	struct bio *bp;
107735863739SMike Smith 
107835863739SMike Smith 	debug_called(2);
107935863739SMike Smith 
108035863739SMike Smith 	/* get the resources we will need */
108135863739SMike Smith 	cm = NULL;
1082a32a982dSScott Long 	bp = NULL;
108335863739SMike Smith 	if (aac_alloc_command(sc, &cm))	/* get a command */
108435863739SMike Smith 		goto fail;
1085a32a982dSScott Long 	if ((bp = aac_dequeue_bio(sc)) == NULL)
1086a32a982dSScott Long 		goto fail;
108735863739SMike Smith 
108835863739SMike Smith 	/* fill out the command */
10890b94a66eSMike Smith 	cm->cm_data = (void *)bp->bio_data;
10900b94a66eSMike Smith 	cm->cm_datalen = bp->bio_bcount;
10910b94a66eSMike Smith 	cm->cm_complete = aac_bio_complete;
109235863739SMike Smith 	cm->cm_private = bp;
10932b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
109436e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
109535863739SMike Smith 
109635863739SMike Smith 	/* build the FIB */
109735863739SMike Smith 	fib = cm->cm_fib;
1098b85f5808SScott Long 	fib->Header.Size = sizeof(struct aac_fib_header);
109935863739SMike Smith 	fib->Header.XferState =
110035863739SMike Smith 		AAC_FIBSTATE_HOSTOWNED   |
110135863739SMike Smith 		AAC_FIBSTATE_INITIALISED |
1102f30ac74cSScott Long 		AAC_FIBSTATE_EMPTY	 |
110335863739SMike Smith 		AAC_FIBSTATE_FROMHOST	 |
110435863739SMike Smith 		AAC_FIBSTATE_REXPECTED   |
1105f30ac74cSScott Long 		AAC_FIBSTATE_NORM	 |
1106f30ac74cSScott Long 		AAC_FIBSTATE_ASYNC	 |
1107f30ac74cSScott Long 		AAC_FIBSTATE_FAST_RESPONSE;
110835863739SMike Smith 
110935863739SMike Smith 	/* build the read/write request */
11107540e65eSScott Long 	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1111b85f5808SScott Long 
11127cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_RAW_IO) {
11137cb209f5SScott Long 		struct aac_raw_io *raw;
11147cb209f5SScott Long 		raw = (struct aac_raw_io *)&fib->data[0];
11157cb209f5SScott Long 		fib->Header.Command = RawIo;
11167cb209f5SScott Long 		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
11177cb209f5SScott Long 		raw->ByteCount = bp->bio_bcount;
11187cb209f5SScott Long 		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
11197cb209f5SScott Long 		raw->BpTotal = 0;
11207cb209f5SScott Long 		raw->BpComplete = 0;
11217cb209f5SScott Long 		fib->Header.Size += sizeof(struct aac_raw_io);
11227cb209f5SScott Long 		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
11237cb209f5SScott Long 		if (bp->bio_cmd == BIO_READ) {
11247cb209f5SScott Long 			raw->Flags = 1;
11257cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
11267cb209f5SScott Long 		} else {
11277cb209f5SScott Long 			raw->Flags = 0;
11287cb209f5SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
11297cb209f5SScott Long 		}
11307cb209f5SScott Long 	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1131b85f5808SScott Long 		fib->Header.Command = ContainerCommand;
11329e2e96d8SScott Long 		if (bp->bio_cmd == BIO_READ) {
1133b85f5808SScott Long 			struct aac_blockread *br;
113435863739SMike Smith 			br = (struct aac_blockread *)&fib->data[0];
113535863739SMike Smith 			br->Command = VM_CtBlockRead;
113635863739SMike Smith 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
113735863739SMike Smith 			br->BlockNumber = bp->bio_pblkno;
113835863739SMike Smith 			br->ByteCount = bp->bio_bcount;
113935863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockread);
114035863739SMike Smith 			cm->cm_sgtable = &br->SgMap;
114135863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAIN;
114235863739SMike Smith 		} else {
1143b85f5808SScott Long 			struct aac_blockwrite *bw;
114435863739SMike Smith 			bw = (struct aac_blockwrite *)&fib->data[0];
114535863739SMike Smith 			bw->Command = VM_CtBlockWrite;
114635863739SMike Smith 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
114735863739SMike Smith 			bw->BlockNumber = bp->bio_pblkno;
114835863739SMike Smith 			bw->ByteCount = bp->bio_bcount;
1149b85f5808SScott Long 			bw->Stable = CUNSTABLE;
115035863739SMike Smith 			fib->Header.Size += sizeof(struct aac_blockwrite);
115135863739SMike Smith 			cm->cm_flags |= AAC_CMD_DATAOUT;
115235863739SMike Smith 			cm->cm_sgtable = &bw->SgMap;
115335863739SMike Smith 		}
1154b85f5808SScott Long 	} else {
1155b85f5808SScott Long 		fib->Header.Command = ContainerCommand64;
1156b85f5808SScott Long 		if (bp->bio_cmd == BIO_READ) {
1157b85f5808SScott Long 			struct aac_blockread64 *br;
1158b85f5808SScott Long 			br = (struct aac_blockread64 *)&fib->data[0];
1159b85f5808SScott Long 			br->Command = VM_CtHostRead64;
1160b85f5808SScott Long 			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1161b85f5808SScott Long 			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1162b85f5808SScott Long 			br->BlockNumber = bp->bio_pblkno;
1163b85f5808SScott Long 			br->Pad = 0;
1164b85f5808SScott Long 			br->Flags = 0;
1165b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockread64);
1166b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAOUT;
1167eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1168b85f5808SScott Long 		} else {
1169b85f5808SScott Long 			struct aac_blockwrite64 *bw;
1170b85f5808SScott Long 			bw = (struct aac_blockwrite64 *)&fib->data[0];
1171b85f5808SScott Long 			bw->Command = VM_CtHostWrite64;
1172b85f5808SScott Long 			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1173b85f5808SScott Long 			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1174b85f5808SScott Long 			bw->BlockNumber = bp->bio_pblkno;
1175b85f5808SScott Long 			bw->Pad = 0;
1176b85f5808SScott Long 			bw->Flags = 0;
1177b85f5808SScott Long 			fib->Header.Size += sizeof(struct aac_blockwrite64);
1178b85f5808SScott Long 			cm->cm_flags |= AAC_CMD_DATAIN;
1179eec256deSAlexander Kabaev 			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1180b85f5808SScott Long 		}
1181b85f5808SScott Long 	}
118235863739SMike Smith 
118335863739SMike Smith 	*cmp = cm;
118435863739SMike Smith 	return(0);
118535863739SMike Smith 
118635863739SMike Smith fail:
11877cb209f5SScott Long 	if (bp != NULL)
11887cb209f5SScott Long 		aac_enqueue_bio(sc, bp);
118935863739SMike Smith 	if (cm != NULL)
119035863739SMike Smith 		aac_release_command(cm);
119135863739SMike Smith 	return(ENOMEM);
119235863739SMike Smith }
119335863739SMike Smith 
1194914da7d0SScott Long /*
119535863739SMike Smith  * Handle a bio-instigated command that has been completed.
119635863739SMike Smith  */
119735863739SMike Smith static void
119835863739SMike Smith aac_bio_complete(struct aac_command *cm)
119935863739SMike Smith {
120035863739SMike Smith 	struct aac_blockread_response *brr;
120135863739SMike Smith 	struct aac_blockwrite_response *bwr;
120235863739SMike Smith 	struct bio *bp;
120335863739SMike Smith 	AAC_FSAStatus status;
120435863739SMike Smith 
120535863739SMike Smith 	/* fetch relevant status and then release the command */
120635863739SMike Smith 	bp = (struct bio *)cm->cm_private;
12079e2e96d8SScott Long 	if (bp->bio_cmd == BIO_READ) {
120835863739SMike Smith 		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
120935863739SMike Smith 		status = brr->Status;
121035863739SMike Smith 	} else {
121135863739SMike Smith 		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
121235863739SMike Smith 		status = bwr->Status;
121335863739SMike Smith 	}
121435863739SMike Smith 	aac_release_command(cm);
121535863739SMike Smith 
121635863739SMike Smith 	/* fix up the bio based on status */
121735863739SMike Smith 	if (status == ST_OK) {
121835863739SMike Smith 		bp->bio_resid = 0;
121935863739SMike Smith 	} else {
122035863739SMike Smith 		bp->bio_error = EIO;
122135863739SMike Smith 		bp->bio_flags |= BIO_ERROR;
12220b94a66eSMike Smith 		/* pass an error string out to the disk layer */
1223914da7d0SScott Long 		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1224914da7d0SScott Long 						    status);
122535863739SMike Smith 	}
12260b94a66eSMike Smith 	aac_biodone(bp);
122735863739SMike Smith }
122835863739SMike Smith 
1229914da7d0SScott Long /*
123035863739SMike Smith  * Submit a command to the controller, return when it completes.
1231b3457b51SScott Long  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1232b3457b51SScott Long  *     be stuck here forever.  At the same time, signals are not caught
1233d8a0a473SScott Long  *     because there is a risk that a signal could wakeup the sleep before
1234d8a0a473SScott Long  *     the card has a chance to complete the command.  Since there is no way
1235d8a0a473SScott Long  *     to cancel a command that is in progress, we can't protect against the
1236d8a0a473SScott Long  *     card completing a command late and spamming the command and data
1237d8a0a473SScott Long  *     memory.  So, we are held hostage until the command completes.
123835863739SMike Smith  */
123935863739SMike Smith static int
1240d8a0a473SScott Long aac_wait_command(struct aac_command *cm)
124135863739SMike Smith {
1242ae543596SScott Long 	struct aac_softc *sc;
1243d8a0a473SScott Long 	int error;
124435863739SMike Smith 
124535863739SMike Smith 	debug_called(2);
124635863739SMike Smith 
1247ae543596SScott Long 	sc = cm->cm_sc;
1248ae543596SScott Long 
124935863739SMike Smith 	/* Put the command on the ready queue and get things going */
125036e0bf6eSScott Long 	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
125135863739SMike Smith 	aac_enqueue_ready(cm);
1252ae543596SScott Long 	aac_startio(sc);
1253ae543596SScott Long 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
125435863739SMike Smith 	return(error);
125535863739SMike Smith }
125635863739SMike Smith 
1257914da7d0SScott Long /*
1258914da7d0SScott Long  *Command Buffer Management
1259914da7d0SScott Long  */
126035863739SMike Smith 
1261914da7d0SScott Long /*
126235863739SMike Smith  * Allocate a command.
126335863739SMike Smith  */
1264fe3cb0e1SScott Long int
126535863739SMike Smith aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
126635863739SMike Smith {
126735863739SMike Smith 	struct aac_command *cm;
126835863739SMike Smith 
126935863739SMike Smith 	debug_called(3);
127035863739SMike Smith 
1271ffb37f33SScott Long 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1272b85f5808SScott Long 		if (sc->total_fibs < sc->aac_max_fibs) {
1273ae543596SScott Long 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1274ae543596SScott Long 			wakeup(sc->aifthread);
1275b85f5808SScott Long 		}
1276ae543596SScott Long 		return (EBUSY);
1277ffb37f33SScott Long 	}
127835863739SMike Smith 
12790b94a66eSMike Smith 	*cmp = cm;
12800b94a66eSMike Smith 	return(0);
12810b94a66eSMike Smith }
12820b94a66eSMike Smith 
1283914da7d0SScott Long /*
12840b94a66eSMike Smith  * Release a command back to the freelist.
12850b94a66eSMike Smith  */
1286fe3cb0e1SScott Long void
12870b94a66eSMike Smith aac_release_command(struct aac_command *cm)
12880b94a66eSMike Smith {
12897cb209f5SScott Long 	struct aac_event *event;
12907cb209f5SScott Long 	struct aac_softc *sc;
12917cb209f5SScott Long 
12920b94a66eSMike Smith 	debug_called(3);
12930b94a66eSMike Smith 
12944109ba51SEd Maste 	/* (re)initialize the command/FIB */
129535863739SMike Smith 	cm->cm_sgtable = NULL;
129635863739SMike Smith 	cm->cm_flags = 0;
129735863739SMike Smith 	cm->cm_complete = NULL;
129835863739SMike Smith 	cm->cm_private = NULL;
129935863739SMike Smith 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
130035863739SMike Smith 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
130135863739SMike Smith 	cm->cm_fib->Header.Flags = 0;
13027cb209f5SScott Long 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
130335863739SMike Smith 
130435863739SMike Smith 	/*
130535863739SMike Smith 	 * These are duplicated in aac_start to cover the case where an
130635863739SMike Smith 	 * intermediate stage may have destroyed them.  They're left
13074109ba51SEd Maste 	 * initialized here for debugging purposes only.
130835863739SMike Smith 	 */
1309f30ac74cSScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1310f30ac74cSScott Long 	cm->cm_fib->Header.SenderData = 0;
131135863739SMike Smith 
131235863739SMike Smith 	aac_enqueue_free(cm);
13137cb209f5SScott Long 
1314eb5cbaa0SEd Maste 	/*
1315eb5cbaa0SEd Maste 	 * Dequeue all events so that there's no risk of events getting
1316eb5cbaa0SEd Maste 	 * stranded.
1317eb5cbaa0SEd Maste 	 */
13187cb209f5SScott Long 	sc = cm->cm_sc;
1319eb5cbaa0SEd Maste 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
13207cb209f5SScott Long 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
13217cb209f5SScott Long 		event->ev_callback(sc, event, event->ev_arg);
13227cb209f5SScott Long 	}
132335863739SMike Smith }
132435863739SMike Smith 
1325914da7d0SScott Long /*
13260b94a66eSMike Smith  * Map helper for command/FIB allocation.
132735863739SMike Smith  */
132835863739SMike Smith static void
13290b94a66eSMike Smith aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
133035863739SMike Smith {
13317cb209f5SScott Long 	uint64_t	*fibphys;
1332914da7d0SScott Long 
13337cb209f5SScott Long 	fibphys = (uint64_t *)arg;
133435863739SMike Smith 
133535863739SMike Smith 	debug_called(3);
133635863739SMike Smith 
1337ffb37f33SScott Long 	*fibphys = segs[0].ds_addr;
133835863739SMike Smith }
133935863739SMike Smith 
1340914da7d0SScott Long /*
13414109ba51SEd Maste  * Allocate and initialize commands/FIBs for this adapter.
134235863739SMike Smith  */
13430b94a66eSMike Smith static int
13440b94a66eSMike Smith aac_alloc_commands(struct aac_softc *sc)
134535863739SMike Smith {
134635863739SMike Smith 	struct aac_command *cm;
1347ffb37f33SScott Long 	struct aac_fibmap *fm;
13487cb209f5SScott Long 	uint64_t fibphys;
1349ffb37f33SScott Long 	int i, error;
135035863739SMike Smith 
1351a6d35632SScott Long 	debug_called(2);
135235863739SMike Smith 
13537cb209f5SScott Long 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1354ffb37f33SScott Long 		return (ENOMEM);
1355ffb37f33SScott Long 
13568480cc63SScott Long 	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1357a6d35632SScott Long 	if (fm == NULL)
1358a6d35632SScott Long 		return (ENOMEM);
1359ffb37f33SScott Long 
13600b94a66eSMike Smith 	/* allocate the FIBs in DMAable memory and load them */
1361ffb37f33SScott Long 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1362ffb37f33SScott Long 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
136370545d1aSScott Long 		device_printf(sc->aac_dev,
136470545d1aSScott Long 			      "Not enough contiguous memory available.\n");
13658480cc63SScott Long 		free(fm, M_AACBUF);
13660b94a66eSMike Smith 		return (ENOMEM);
136735863739SMike Smith 	}
1368128aa5a0SScott Long 
1369cd481291SScott Long 	/* Ignore errors since this doesn't bounce */
1370cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
13717cb209f5SScott Long 			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1372ffb37f33SScott Long 			      aac_map_command_helper, &fibphys, 0);
1373128aa5a0SScott Long 
13744109ba51SEd Maste 	/* initialize constant fields in the command structure */
13757cb209f5SScott Long 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
13767cb209f5SScott Long 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
13778480cc63SScott Long 		cm = sc->aac_commands + sc->total_fibs;
1378ffb37f33SScott Long 		fm->aac_commands = cm;
137935863739SMike Smith 		cm->cm_sc = sc;
13807cb209f5SScott Long 		cm->cm_fib = (struct aac_fib *)
13817cb209f5SScott Long 			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
13827cb209f5SScott Long 		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1383cb0d64b9SScott Long 		cm->cm_index = sc->total_fibs;
138435863739SMike Smith 
1385ffb37f33SScott Long 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
138693cfca22SScott Long 					       &cm->cm_datamap)) != 0)
13878480cc63SScott Long 			break;
138893cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
138993cfca22SScott Long 		aac_release_command(cm);
13908480cc63SScott Long 		sc->total_fibs++;
139193cfca22SScott Long 		mtx_unlock(&sc->aac_io_lock);
139235863739SMike Smith 	}
1393ffb37f33SScott Long 
13948480cc63SScott Long 	if (i > 0) {
139593cfca22SScott Long 		mtx_lock(&sc->aac_io_lock);
1396ffb37f33SScott Long 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1397a6d35632SScott Long 		debug(1, "total_fibs= %d\n", sc->total_fibs);
1398bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
13990b94a66eSMike Smith 		return (0);
140035863739SMike Smith 	}
140135863739SMike Smith 
14028480cc63SScott Long 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
14038480cc63SScott Long 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
14048480cc63SScott Long 	free(fm, M_AACBUF);
14058480cc63SScott Long 	return (ENOMEM);
14068480cc63SScott Long }
14078480cc63SScott Long 
1408914da7d0SScott Long /*
14090b94a66eSMike Smith  * Free FIBs owned by this adapter.
141035863739SMike Smith  */
141135863739SMike Smith static void
14128480cc63SScott Long aac_free_commands(struct aac_softc *sc)
141335863739SMike Smith {
14148480cc63SScott Long 	struct aac_fibmap *fm;
1415ffb37f33SScott Long 	struct aac_command *cm;
141635863739SMike Smith 	int i;
141735863739SMike Smith 
141835863739SMike Smith 	debug_called(1);
141935863739SMike Smith 
14208480cc63SScott Long 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
14218480cc63SScott Long 
14228480cc63SScott Long 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
14238480cc63SScott Long 		/*
14248480cc63SScott Long 		 * We check against total_fibs to handle partially
14258480cc63SScott Long 		 * allocated blocks.
14268480cc63SScott Long 		 */
14277cb209f5SScott Long 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1428ffb37f33SScott Long 			cm = fm->aac_commands + i;
1429ffb37f33SScott Long 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1430ffb37f33SScott Long 		}
1431ffb37f33SScott Long 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1432ffb37f33SScott Long 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
14338480cc63SScott Long 		free(fm, M_AACBUF);
14348480cc63SScott Long 	}
143535863739SMike Smith }
143635863739SMike Smith 
1437914da7d0SScott Long /*
143835863739SMike Smith  * Command-mapping helper function - populate this command's s/g table.
143935863739SMike Smith  */
144035863739SMike Smith static void
144135863739SMike Smith aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
144235863739SMike Smith {
1443cd481291SScott Long 	struct aac_softc *sc;
1444914da7d0SScott Long 	struct aac_command *cm;
1445914da7d0SScott Long 	struct aac_fib *fib;
144635863739SMike Smith 	int i;
144735863739SMike Smith 
144835863739SMike Smith 	debug_called(3);
144935863739SMike Smith 
1450914da7d0SScott Long 	cm = (struct aac_command *)arg;
1451cd481291SScott Long 	sc = cm->cm_sc;
1452914da7d0SScott Long 	fib = cm->cm_fib;
1453914da7d0SScott Long 
145435863739SMike Smith 	/* copy into the FIB */
1455b85f5808SScott Long 	if (cm->cm_sgtable != NULL) {
14567cb209f5SScott Long 		if (fib->Header.Command == RawIo) {
14577cb209f5SScott Long 			struct aac_sg_tableraw *sg;
14587cb209f5SScott Long 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
14597cb209f5SScott Long 			sg->SgCount = nseg;
14607cb209f5SScott Long 			for (i = 0; i < nseg; i++) {
14617cb209f5SScott Long 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
14627cb209f5SScott Long 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
14637cb209f5SScott Long 				sg->SgEntryRaw[i].Next = 0;
14647cb209f5SScott Long 				sg->SgEntryRaw[i].Prev = 0;
14657cb209f5SScott Long 				sg->SgEntryRaw[i].Flags = 0;
14667cb209f5SScott Long 			}
14677cb209f5SScott Long 			/* update the FIB size for the s/g count */
14687cb209f5SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
14697cb209f5SScott Long 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1470b85f5808SScott Long 			struct aac_sg_table *sg;
1471b85f5808SScott Long 			sg = cm->cm_sgtable;
147235863739SMike Smith 			sg->SgCount = nseg;
147335863739SMike Smith 			for (i = 0; i < nseg; i++) {
147435863739SMike Smith 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
147535863739SMike Smith 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
147635863739SMike Smith 			}
147735863739SMike Smith 			/* update the FIB size for the s/g count */
147835863739SMike Smith 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1479b85f5808SScott Long 		} else {
1480b85f5808SScott Long 			struct aac_sg_table64 *sg;
1481b85f5808SScott Long 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1482b85f5808SScott Long 			sg->SgCount = nseg;
1483b85f5808SScott Long 			for (i = 0; i < nseg; i++) {
1484b85f5808SScott Long 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1485b85f5808SScott Long 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
148635863739SMike Smith 			}
1487b85f5808SScott Long 			/* update the FIB size for the s/g count */
1488b85f5808SScott Long 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1489b85f5808SScott Long 		}
1490b85f5808SScott Long 	}
149135863739SMike Smith 
1492cd481291SScott Long 	/* Fix up the address values in the FIB.  Use the command array index
1493cd481291SScott Long 	 * instead of a pointer since these fields are only 32 bits.  Shift
14947cb209f5SScott Long 	 * the SenderFibAddress over to make room for the fast response bit
14957cb209f5SScott Long 	 * and for the AIF bit
149635863739SMike Smith 	 */
14977cb209f5SScott Long 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
14987cb209f5SScott Long 	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
149935863739SMike Smith 
1500cd481291SScott Long 	/* save a pointer to the command for speedy reverse-lookup */
1501cd481291SScott Long 	cm->cm_fib->Header.SenderData = cm->cm_index;
150235863739SMike Smith 
150335863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAIN)
1504c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1505c6eafcf2SScott Long 				BUS_DMASYNC_PREREAD);
150635863739SMike Smith 	if (cm->cm_flags & AAC_CMD_DATAOUT)
1507c6eafcf2SScott Long 		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1508c6eafcf2SScott Long 				BUS_DMASYNC_PREWRITE);
150935863739SMike Smith 	cm->cm_flags |= AAC_CMD_MAPPED;
1510cd481291SScott Long 
15117cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
15127cb209f5SScott Long 		int count = 10000000L;
15137cb209f5SScott Long 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
15147cb209f5SScott Long 			if (--count == 0) {
15157cb209f5SScott Long 				aac_unmap_command(cm);
15167cb209f5SScott Long 				sc->flags |= AAC_QUEUE_FRZN;
15177cb209f5SScott Long 				aac_requeue_ready(cm);
15187cb209f5SScott Long 			}
15197cb209f5SScott Long 			DELAY(5);			/* wait 5 usec. */
15207cb209f5SScott Long 		}
15217cb209f5SScott Long 	} else {
1522397fa34fSScott Long 		/* Put the FIB on the outbound queue */
15234102d44bSScott Long 		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
15244102d44bSScott Long 			aac_unmap_command(cm);
1525397fa34fSScott Long 			sc->flags |= AAC_QUEUE_FRZN;
1526cd481291SScott Long 			aac_requeue_ready(cm);
15274102d44bSScott Long 		}
15287cb209f5SScott Long 	}
1529cd481291SScott Long 
1530cd481291SScott Long 	return;
153135863739SMike Smith }
153235863739SMike Smith 
1533914da7d0SScott Long /*
153435863739SMike Smith  * Unmap a command from controller-visible space.
153535863739SMike Smith  */
153635863739SMike Smith static void
153735863739SMike Smith aac_unmap_command(struct aac_command *cm)
153835863739SMike Smith {
1539914da7d0SScott Long 	struct aac_softc *sc;
154035863739SMike Smith 
154135863739SMike Smith 	debug_called(2);
154235863739SMike Smith 
1543914da7d0SScott Long 	sc = cm->cm_sc;
1544914da7d0SScott Long 
154535863739SMike Smith 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
154635863739SMike Smith 		return;
154735863739SMike Smith 
154835863739SMike Smith 	if (cm->cm_datalen != 0) {
154935863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAIN)
1550c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1551c6eafcf2SScott Long 					BUS_DMASYNC_POSTREAD);
155235863739SMike Smith 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1553c6eafcf2SScott Long 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1554c6eafcf2SScott Long 					BUS_DMASYNC_POSTWRITE);
155535863739SMike Smith 
155635863739SMike Smith 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
155735863739SMike Smith 	}
155835863739SMike Smith 	cm->cm_flags &= ~AAC_CMD_MAPPED;
155935863739SMike Smith }
156035863739SMike Smith 
1561914da7d0SScott Long /*
1562914da7d0SScott Long  * Hardware Interface
1563914da7d0SScott Long  */
156435863739SMike Smith 
1565914da7d0SScott Long /*
15664109ba51SEd Maste  * Initialize the adapter.
156735863739SMike Smith  */
156835863739SMike Smith static void
156935863739SMike Smith aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
157035863739SMike Smith {
1571914da7d0SScott Long 	struct aac_softc *sc;
157235863739SMike Smith 
157335863739SMike Smith 	debug_called(1);
157435863739SMike Smith 
1575914da7d0SScott Long 	sc = (struct aac_softc *)arg;
1576914da7d0SScott Long 
157735863739SMike Smith 	sc->aac_common_busaddr = segs[0].ds_addr;
157835863739SMike Smith }
157935863739SMike Smith 
1580a6d35632SScott Long static int
1581a6d35632SScott Long aac_check_firmware(struct aac_softc *sc)
1582a6d35632SScott Long {
1583a441b3fcSScott Long 	u_int32_t major, minor, options = 0, atu_size = 0;
1584a441b3fcSScott Long 	int status;
1585a6d35632SScott Long 
1586a6d35632SScott Long 	debug_called(1);
1587a6d35632SScott Long 
1588fe94b852SScott Long 	/*
1589fe94b852SScott Long 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1590fe94b852SScott Long 	 * firmware version 1.x are not compatible with this driver.
1591fe94b852SScott Long 	 */
1592a6d35632SScott Long 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1593fe94b852SScott Long 		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1594fe94b852SScott Long 				     NULL)) {
1595fe94b852SScott Long 			device_printf(sc->aac_dev,
1596fe94b852SScott Long 				      "Error reading firmware version\n");
1597fe94b852SScott Long 			return (EIO);
1598fe94b852SScott Long 		}
1599fe94b852SScott Long 
1600fe94b852SScott Long 		/* These numbers are stored as ASCII! */
1601a6d35632SScott Long 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1602a6d35632SScott Long 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1603fe94b852SScott Long 		if (major == 1) {
1604fe94b852SScott Long 			device_printf(sc->aac_dev,
1605fe94b852SScott Long 			    "Firmware version %d.%d is not supported.\n",
1606fe94b852SScott Long 			    major, minor);
1607fe94b852SScott Long 			return (EINVAL);
1608fe94b852SScott Long 		}
1609fe94b852SScott Long 	}
1610fe94b852SScott Long 
1611a6d35632SScott Long 	/*
1612a6d35632SScott Long 	 * Retrieve the capabilities/supported options word so we know what
1613a441b3fcSScott Long 	 * work-arounds to enable.  Some firmware revs don't support this
1614a441b3fcSScott Long 	 * command.
1615a6d35632SScott Long 	 */
1616a441b3fcSScott Long 	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1617a441b3fcSScott Long 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1618a441b3fcSScott Long 			device_printf(sc->aac_dev,
1619a441b3fcSScott Long 			     "RequestAdapterInfo failed\n");
1620a6d35632SScott Long 			return (EIO);
1621a6d35632SScott Long 		}
1622a441b3fcSScott Long 	} else {
1623a6d35632SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
16247cb209f5SScott Long 		atu_size = AAC_GET_MAILBOX(sc, 2);
1625a6d35632SScott Long 		sc->supported_options = options;
1626a6d35632SScott Long 
1627a6d35632SScott Long 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1628a6d35632SScott Long 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1629a6d35632SScott Long 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1630a6d35632SScott Long 		if (options & AAC_SUPPORTED_NONDASD)
1631a6d35632SScott Long 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1632cd481291SScott Long 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1633cd481291SScott Long 		     && (sizeof(bus_addr_t) > 4)) {
1634a441b3fcSScott Long 			device_printf(sc->aac_dev,
1635a441b3fcSScott Long 			    "Enabling 64-bit address support\n");
1636a6d35632SScott Long 			sc->flags |= AAC_FLAGS_SG_64BIT;
1637a6d35632SScott Long 		}
1638a441b3fcSScott Long 		if ((options & AAC_SUPPORTED_NEW_COMM)
1639a441b3fcSScott Long 		 && sc->aac_if.aif_send_command)
16407cb209f5SScott Long 			sc->flags |= AAC_FLAGS_NEW_COMM;
16417cb209f5SScott Long 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
16427cb209f5SScott Long 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1643a441b3fcSScott Long 	}
1644a6d35632SScott Long 
1645a6d35632SScott Long 	/* Check for broken hardware that does a lower number of commands */
16467cb209f5SScott Long 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
16477cb209f5SScott Long 
16487cb209f5SScott Long 	/* Remap mem. resource, if required */
16497cb209f5SScott Long 	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
16507cb209f5SScott Long 		atu_size > rman_get_size(sc->aac_regs_resource)) {
16517cb209f5SScott Long 		bus_release_resource(
16527cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY,
16537cb209f5SScott Long 			sc->aac_regs_rid, sc->aac_regs_resource);
16547cb209f5SScott Long 		sc->aac_regs_resource = bus_alloc_resource(
16557cb209f5SScott Long 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
16567cb209f5SScott Long 			0ul, ~0ul, atu_size, RF_ACTIVE);
16577cb209f5SScott Long 		if (sc->aac_regs_resource == NULL) {
16587cb209f5SScott Long 			sc->aac_regs_resource = bus_alloc_resource_any(
16597cb209f5SScott Long 				sc->aac_dev, SYS_RES_MEMORY,
16607cb209f5SScott Long 				&sc->aac_regs_rid, RF_ACTIVE);
16617cb209f5SScott Long 			if (sc->aac_regs_resource == NULL) {
16627cb209f5SScott Long 				device_printf(sc->aac_dev,
16637cb209f5SScott Long 				    "couldn't allocate register window\n");
16647cb209f5SScott Long 				return (ENXIO);
16657cb209f5SScott Long 			}
16667cb209f5SScott Long 			sc->flags &= ~AAC_FLAGS_NEW_COMM;
16677cb209f5SScott Long 		}
16687cb209f5SScott Long 		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
16697cb209f5SScott Long 		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
16707cb209f5SScott Long 	}
16717cb209f5SScott Long 
16727cb209f5SScott Long 	/* Read preferred settings */
16737cb209f5SScott Long 	sc->aac_max_fib_size = sizeof(struct aac_fib);
16747cb209f5SScott Long 	sc->aac_max_sectors = 128;				/* 64KB */
16757cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1676a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
16777e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite64))
16787e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry64);
1679a6d35632SScott Long 	else
1680a441b3fcSScott Long 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
16817e7a458eSEd Maste 		 - sizeof(struct aac_blockwrite))
16827e7a458eSEd Maste 		 / sizeof(struct aac_sg_entry);
1683a441b3fcSScott Long 
16847cb209f5SScott Long 	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
16857cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 1);
16867cb209f5SScott Long 		sc->aac_max_fib_size = (options & 0xFFFF);
16877cb209f5SScott Long 		sc->aac_max_sectors = (options >> 16) << 1;
16887cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 2);
16897cb209f5SScott Long 		sc->aac_sg_tablesize = (options >> 16);
16907cb209f5SScott Long 		options = AAC_GET_MAILBOX(sc, 3);
16917cb209f5SScott Long 		sc->aac_max_fibs = (options & 0xFFFF);
16927cb209f5SScott Long 	}
16937cb209f5SScott Long 	if (sc->aac_max_fib_size > PAGE_SIZE)
16947cb209f5SScott Long 		sc->aac_max_fib_size = PAGE_SIZE;
16957cb209f5SScott Long 	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1696a6d35632SScott Long 
1697f355c0e0SEd Maste 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1698f355c0e0SEd Maste 		sc->flags |= AAC_FLAGS_RAW_IO;
1699f355c0e0SEd Maste 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1700f355c0e0SEd Maste 	}
1701f355c0e0SEd Maste 
1702fe94b852SScott Long 	return (0);
1703fe94b852SScott Long }
1704fe94b852SScott Long 
170535863739SMike Smith static int
170635863739SMike Smith aac_init(struct aac_softc *sc)
170735863739SMike Smith {
170835863739SMike Smith 	struct aac_adapter_init	*ip;
170935863739SMike Smith 	time_t then;
1710b88ffdc8SScott Long 	u_int32_t code, qoffset;
1711a6d35632SScott Long 	int error;
171235863739SMike Smith 
171335863739SMike Smith 	debug_called(1);
171435863739SMike Smith 
171535863739SMike Smith 	/*
171635863739SMike Smith 	 * First wait for the adapter to come ready.
171735863739SMike Smith 	 */
17182b3b0f17SScott Long 	then = time_uptime;
171935863739SMike Smith 	do {
172035863739SMike Smith 		code = AAC_GET_FWSTATUS(sc);
172135863739SMike Smith 		if (code & AAC_SELF_TEST_FAILED) {
172235863739SMike Smith 			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
172335863739SMike Smith 			return(ENXIO);
172435863739SMike Smith 		}
172535863739SMike Smith 		if (code & AAC_KERNEL_PANIC) {
1726914da7d0SScott Long 			device_printf(sc->aac_dev,
1727914da7d0SScott Long 				      "FATAL: controller kernel panic\n");
172835863739SMike Smith 			return(ENXIO);
172935863739SMike Smith 		}
17302b3b0f17SScott Long 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
1731914da7d0SScott Long 			device_printf(sc->aac_dev,
1732914da7d0SScott Long 				      "FATAL: controller not coming ready, "
1733c6eafcf2SScott Long 					   "status %x\n", code);
173435863739SMike Smith 			return(ENXIO);
173535863739SMike Smith 		}
173635863739SMike Smith 	} while (!(code & AAC_UP_AND_RUNNING));
173735863739SMike Smith 
1738a6d35632SScott Long 	error = ENOMEM;
1739a6d35632SScott Long 	/*
1740a6d35632SScott Long 	 * Create DMA tag for mapping buffers into controller-addressable space.
1741a6d35632SScott Long 	 */
1742a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1743a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1744a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1745a6d35632SScott Long 			       BUS_SPACE_MAXADDR :
1746a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1747a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1748a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
1749a6d35632SScott Long 			       MAXBSIZE,		/* maxsize */
17507cb209f5SScott Long 			       sc->aac_sg_tablesize,	/* nsegments */
1751a6d35632SScott Long 			       MAXBSIZE,		/* maxsegsize */
1752a6d35632SScott Long 			       BUS_DMA_ALLOCNOW,	/* flags */
1753f6b1c44dSScott Long 			       busdma_lock_mutex,	/* lockfunc */
1754f6b1c44dSScott Long 			       &sc->aac_io_lock,	/* lockfuncarg */
1755a6d35632SScott Long 			       &sc->aac_buffer_dmat)) {
1756a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1757a6d35632SScott Long 		goto out;
1758a6d35632SScott Long 	}
1759a6d35632SScott Long 
1760a6d35632SScott Long 	/*
1761a6d35632SScott Long 	 * Create DMA tag for mapping FIBs into controller-addressable space..
1762a6d35632SScott Long 	 */
1763a6d35632SScott Long 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1764a6d35632SScott Long 			       1, 0, 			/* algnmnt, boundary */
1765a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1766a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1767a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
1768a6d35632SScott Long 			       BUS_SPACE_MAXADDR, 	/* highaddr */
1769a6d35632SScott Long 			       NULL, NULL, 		/* filter, filterarg */
17707cb209f5SScott Long 			       sc->aac_max_fibs_alloc *
17717cb209f5SScott Long 			       sc->aac_max_fib_size,  /* maxsize */
1772a6d35632SScott Long 			       1,			/* nsegments */
17737cb209f5SScott Long 			       sc->aac_max_fibs_alloc *
17747cb209f5SScott Long 			       sc->aac_max_fib_size,	/* maxsegsize */
17751248408dSScott Long 			       0,			/* flags */
1776f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
1777a6d35632SScott Long 			       &sc->aac_fib_dmat)) {
1778a6d35632SScott Long 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1779a6d35632SScott Long 		goto out;
1780a6d35632SScott Long 	}
1781a6d35632SScott Long 
178235863739SMike Smith 	/*
178335863739SMike Smith 	 * Create DMA tag for the common structure and allocate it.
178435863739SMike Smith 	 */
178535863739SMike Smith 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1786c6eafcf2SScott Long 			       1, 0,			/* algnmnt, boundary */
1787a6d35632SScott Long 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1788a6d35632SScott Long 			       BUS_SPACE_MAXADDR_32BIT :
1789a6d35632SScott Long 			       0x7fffffff,		/* lowaddr */
179035863739SMike Smith 			       BUS_SPACE_MAXADDR, 	/* highaddr */
179135863739SMike Smith 			       NULL, NULL, 		/* filter, filterarg */
1792ffb37f33SScott Long 			       8192 + sizeof(struct aac_common), /* maxsize */
1793914da7d0SScott Long 			       1,			/* nsegments */
179435863739SMike Smith 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
17951248408dSScott Long 			       0,			/* flags */
1796f6b1c44dSScott Long 			       NULL, NULL,		/* No locking needed */
179735863739SMike Smith 			       &sc->aac_common_dmat)) {
1798914da7d0SScott Long 		device_printf(sc->aac_dev,
1799914da7d0SScott Long 			      "can't allocate common structure DMA tag\n");
1800a6d35632SScott Long 		goto out;
180135863739SMike Smith 	}
1802c6eafcf2SScott Long 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
1803c6eafcf2SScott Long 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
180435863739SMike Smith 		device_printf(sc->aac_dev, "can't allocate common structure\n");
1805a6d35632SScott Long 		goto out;
180635863739SMike Smith 	}
1807ffb37f33SScott Long 
1808ffb37f33SScott Long 	/*
1809ffb37f33SScott Long 	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1810ffb37f33SScott Long 	 * below address 8192 in physical memory.
1811ffb37f33SScott Long 	 * XXX If the padding is not needed, can it be put to use instead
1812ffb37f33SScott Long 	 * of ignored?
1813ffb37f33SScott Long 	 */
1814cd481291SScott Long 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1815ffb37f33SScott Long 			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1816ffb37f33SScott Long 			aac_common_map, sc, 0);
1817ffb37f33SScott Long 
1818ffb37f33SScott Long 	if (sc->aac_common_busaddr < 8192) {
1819eec256deSAlexander Kabaev 		sc->aac_common = (struct aac_common *)
1820eec256deSAlexander Kabaev 		    ((uint8_t *)sc->aac_common + 8192);
1821ffb37f33SScott Long 		sc->aac_common_busaddr += 8192;
1822ffb37f33SScott Long 	}
182335863739SMike Smith 	bzero(sc->aac_common, sizeof(*sc->aac_common));
182435863739SMike Smith 
1825ffb37f33SScott Long 	/* Allocate some FIBs and associated command structs */
1826ffb37f33SScott Long 	TAILQ_INIT(&sc->aac_fibmap_tqh);
18277cb209f5SScott Long 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
18288480cc63SScott Long 				  M_AACBUF, M_WAITOK|M_ZERO);
18298480cc63SScott Long 	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1830ffb37f33SScott Long 		if (aac_alloc_commands(sc) != 0)
1831ffb37f33SScott Long 			break;
1832ffb37f33SScott Long 	}
1833ffb37f33SScott Long 	if (sc->total_fibs == 0)
1834a6d35632SScott Long 		goto out;
1835ffb37f33SScott Long 
183635863739SMike Smith 	/*
1837914da7d0SScott Long 	 * Fill in the init structure.  This tells the adapter about the
1838914da7d0SScott Long 	 * physical location of various important shared data structures.
183935863739SMike Smith 	 */
184035863739SMike Smith 	ip = &sc->aac_common->ac_init;
184135863739SMike Smith 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
18427cb209f5SScott Long 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
18437cb209f5SScott Long 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
18447cb209f5SScott Long 		sc->flags |= AAC_FLAGS_RAW_IO;
18457cb209f5SScott Long 	}
1846f30ac74cSScott Long 	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
184735863739SMike Smith 
1848c6eafcf2SScott Long 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1849c6eafcf2SScott Long 					 offsetof(struct aac_common, ac_fibs);
1850149af931SScott Long 	ip->AdapterFibsVirtualAddress = 0;
185135863739SMike Smith 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
185235863739SMike Smith 	ip->AdapterFibAlign = sizeof(struct aac_fib);
185335863739SMike Smith 
1854c6eafcf2SScott Long 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1855c6eafcf2SScott Long 				  offsetof(struct aac_common, ac_printf);
185635863739SMike Smith 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
185735863739SMike Smith 
18584b00f859SScott Long 	/*
18594b00f859SScott Long 	 * The adapter assumes that pages are 4K in size, except on some
18604b00f859SScott Long  	 * broken firmware versions that do the page->byte conversion twice,
18614b00f859SScott Long 	 * therefore 'assuming' that this value is in 16MB units (2^24).
18624b00f859SScott Long 	 * Round up since the granularity is so high.
18634b00f859SScott Long 	 */
1864f30ac74cSScott Long 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
18654b00f859SScott Long 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
18664b00f859SScott Long 		ip->HostPhysMemPages =
18674b00f859SScott Long 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1868204c0befSScott Long 	}
18692b3b0f17SScott Long 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
187035863739SMike Smith 
18717cb209f5SScott Long 	ip->InitFlags = 0;
18727cb209f5SScott Long 	if (sc->flags & AAC_FLAGS_NEW_COMM) {
18737cb209f5SScott Long 		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
18747cb209f5SScott Long 		device_printf(sc->aac_dev, "New comm. interface enabled\n");
18757cb209f5SScott Long 	}
18767cb209f5SScott Long 
18777cb209f5SScott Long 	ip->MaxIoCommands = sc->aac_max_fibs;
18787cb209f5SScott Long 	ip->MaxIoSize = sc->aac_max_sectors << 9;
18797cb209f5SScott Long 	ip->MaxFibSize = sc->aac_max_fib_size;
18807cb209f5SScott Long 
188135863739SMike Smith 	/*
18824109ba51SEd Maste 	 * Initialize FIB queues.  Note that it appears that the layout of the
1883c6eafcf2SScott Long 	 * indexes and the segmentation of the entries may be mandated by the
1884c6eafcf2SScott Long 	 * adapter, which is only told about the base of the queue index fields.
188535863739SMike Smith 	 *
188635863739SMike Smith 	 * The initial values of the indices are assumed to inform the adapter
1887914da7d0SScott Long 	 * of the sizes of the respective queues, and theoretically it could
1888914da7d0SScott Long 	 * work out the entire layout of the queue structures from this.  We
1889914da7d0SScott Long 	 * take the easy route and just lay this area out like everyone else
1890914da7d0SScott Long 	 * does.
189135863739SMike Smith 	 *
1892914da7d0SScott Long 	 * The Linux driver uses a much more complex scheme whereby several
1893914da7d0SScott Long 	 * header records are kept for each queue.  We use a couple of generic
1894914da7d0SScott Long 	 * list manipulation functions which 'know' the size of each list by
1895914da7d0SScott Long 	 * virtue of a table.
189635863739SMike Smith 	 */
1897b88ffdc8SScott Long 	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
18980bcbebd6SScott Long 	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
18990bcbebd6SScott Long 	sc->aac_queues =
19000bcbebd6SScott Long 	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1901b88ffdc8SScott Long 	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
190235863739SMike Smith 
1903c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1904c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1905c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1906c6eafcf2SScott Long 		AAC_HOST_NORM_CMD_ENTRIES;
1907c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1908c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1909c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1910c6eafcf2SScott Long 		AAC_HOST_HIGH_CMD_ENTRIES;
1911c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1912c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1913c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1914c6eafcf2SScott Long 		AAC_ADAP_NORM_CMD_ENTRIES;
1915c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1916c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1917c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1918c6eafcf2SScott Long 		AAC_ADAP_HIGH_CMD_ENTRIES;
1919c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1920c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1921c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1922c6eafcf2SScott Long 		AAC_HOST_NORM_RESP_ENTRIES;
1923c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1924c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1925c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1926c6eafcf2SScott Long 		AAC_HOST_HIGH_RESP_ENTRIES;
1927c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1928c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1929c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1930c6eafcf2SScott Long 		AAC_ADAP_NORM_RESP_ENTRIES;
1931c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1932c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1933c6eafcf2SScott Long 	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1934c6eafcf2SScott Long 		AAC_ADAP_HIGH_RESP_ENTRIES;
1935c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1936c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormCmdQueue[0];
1937c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1938c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighCmdQueue[0];
1939c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1940c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1941c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1942c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1943c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1944c6eafcf2SScott Long 		&sc->aac_queues->qt_HostNormRespQueue[0];
1945c6eafcf2SScott Long 	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1946c6eafcf2SScott Long 		&sc->aac_queues->qt_HostHighRespQueue[0];
1947c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1948c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapNormRespQueue[0];
1949c6eafcf2SScott Long 	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1950c6eafcf2SScott Long 		&sc->aac_queues->qt_AdapHighRespQueue[0];
195135863739SMike Smith 
195235863739SMike Smith 	/*
195335863739SMike Smith 	 * Do controller-type-specific initialisation
195435863739SMike Smith 	 */
195535863739SMike Smith 	switch (sc->aac_hwif) {
195635863739SMike Smith 	case AAC_HWIF_I960RX:
195735863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
195835863739SMike Smith 		break;
19594afedc31SScott Long 	case AAC_HWIF_RKT:
19604afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
19614afedc31SScott Long 		break;
19624afedc31SScott Long 	default:
19634afedc31SScott Long 		break;
196435863739SMike Smith 	}
196535863739SMike Smith 
196635863739SMike Smith 	/*
196735863739SMike Smith 	 * Give the init structure to the controller.
196835863739SMike Smith 	 */
196935863739SMike Smith 	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
1970914da7d0SScott Long 			     sc->aac_common_busaddr +
1971914da7d0SScott Long 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1972914da7d0SScott Long 			     NULL)) {
1973914da7d0SScott Long 		device_printf(sc->aac_dev,
1974914da7d0SScott Long 			      "error establishing init structure\n");
1975a6d35632SScott Long 		error = EIO;
1976a6d35632SScott Long 		goto out;
197735863739SMike Smith 	}
197835863739SMike Smith 
1979a6d35632SScott Long 	error = 0;
1980a6d35632SScott Long out:
1981a6d35632SScott Long 	return(error);
198235863739SMike Smith }
198335863739SMike Smith 
1984914da7d0SScott Long /*
198535863739SMike Smith  * Send a synchronous command to the controller and wait for a result.
19867cb209f5SScott Long  * Indicate if the controller completed the command with an error status.
198735863739SMike Smith  */
198835863739SMike Smith static int
198935863739SMike Smith aac_sync_command(struct aac_softc *sc, u_int32_t command,
199035863739SMike Smith 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
199135863739SMike Smith 		 u_int32_t *sp)
199235863739SMike Smith {
199335863739SMike Smith 	time_t then;
199435863739SMike Smith 	u_int32_t status;
199535863739SMike Smith 
199635863739SMike Smith 	debug_called(3);
199735863739SMike Smith 
199835863739SMike Smith 	/* populate the mailbox */
199935863739SMike Smith 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
200035863739SMike Smith 
200135863739SMike Smith 	/* ensure the sync command doorbell flag is cleared */
200235863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
200335863739SMike Smith 
200435863739SMike Smith 	/* then set it to signal the adapter */
200535863739SMike Smith 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
200635863739SMike Smith 
200735863739SMike Smith 	/* spin waiting for the command to complete */
20082b3b0f17SScott Long 	then = time_uptime;
200935863739SMike Smith 	do {
20102b3b0f17SScott Long 		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
2011a6d35632SScott Long 			debug(1, "timed out");
201235863739SMike Smith 			return(EIO);
201335863739SMike Smith 		}
201435863739SMike Smith 	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
201535863739SMike Smith 
201635863739SMike Smith 	/* clear the completion flag */
201735863739SMike Smith 	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
201835863739SMike Smith 
201935863739SMike Smith 	/* get the command status */
2020a6d35632SScott Long 	status = AAC_GET_MAILBOX(sc, 0);
202135863739SMike Smith 	if (sp != NULL)
202235863739SMike Smith 		*sp = status;
20237cb209f5SScott Long 
2024a441b3fcSScott Long 	if (status != AAC_SRB_STS_SUCCESS)
20257cb209f5SScott Long 		return (-1);
20260b94a66eSMike Smith 	return(0);
202735863739SMike Smith }
202835863739SMike Smith 
2029cbfd045bSScott Long int
203035863739SMike Smith aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2031cbfd045bSScott Long 		 struct aac_fib *fib, u_int16_t datasize)
203235863739SMike Smith {
203335863739SMike Smith 	debug_called(3);
20347cb209f5SScott Long 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
203535863739SMike Smith 
203635863739SMike Smith 	if (datasize > AAC_FIB_DATASIZE)
203735863739SMike Smith 		return(EINVAL);
203835863739SMike Smith 
203935863739SMike Smith 	/*
204035863739SMike Smith 	 * Set up the sync FIB
204135863739SMike Smith 	 */
2042914da7d0SScott Long 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2043914da7d0SScott Long 				AAC_FIBSTATE_INITIALISED |
2044c6eafcf2SScott Long 				AAC_FIBSTATE_EMPTY;
204535863739SMike Smith 	fib->Header.XferState |= xferstate;
204635863739SMike Smith 	fib->Header.Command = command;
204735863739SMike Smith 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
204842ef13a2SEd Maste 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
204935863739SMike Smith 	fib->Header.SenderSize = sizeof(struct aac_fib);
2050b88ffdc8SScott Long 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2051c6eafcf2SScott Long 	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2052914da7d0SScott Long 					 offsetof(struct aac_common,
2053914da7d0SScott Long 						  ac_sync_fib);
205435863739SMike Smith 
205535863739SMike Smith 	/*
205635863739SMike Smith 	 * Give the FIB to the controller, wait for a response.
205735863739SMike Smith 	 */
2058914da7d0SScott Long 	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2059914da7d0SScott Long 			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
206035863739SMike Smith 		debug(2, "IO error");
206135863739SMike Smith 		return(EIO);
206235863739SMike Smith 	}
206335863739SMike Smith 
206435863739SMike Smith 	return (0);
206535863739SMike Smith }
206635863739SMike Smith 
2067914da7d0SScott Long /*
206835863739SMike Smith  * Adapter-space FIB queue manipulation
206935863739SMike Smith  *
207035863739SMike Smith  * Note that the queue implementation here is a little funky; neither the PI or
207135863739SMike Smith  * CI will ever be zero.  This behaviour is a controller feature.
207235863739SMike Smith  */
207335863739SMike Smith static struct {
207435863739SMike Smith 	int		size;
207535863739SMike Smith 	int		notify;
207635863739SMike Smith } aac_qinfo[] = {
207735863739SMike Smith 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
207835863739SMike Smith 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
207935863739SMike Smith 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
208035863739SMike Smith 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
208135863739SMike Smith 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
208235863739SMike Smith 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
208335863739SMike Smith 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
208435863739SMike Smith 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
208535863739SMike Smith };
208635863739SMike Smith 
208735863739SMike Smith /*
2088c6eafcf2SScott Long  * Atomically insert an entry into the nominated queue, returns 0 on success or
2089c6eafcf2SScott Long  * EBUSY if the queue is full.
209035863739SMike Smith  *
20910b94a66eSMike Smith  * Note: it would be more efficient to defer notifying the controller in
2092914da7d0SScott Long  *	 the case where we may be inserting several entries in rapid succession,
2093914da7d0SScott Long  *	 but implementing this usefully may be difficult (it would involve a
2094c6eafcf2SScott Long  *	 separate queue/notify interface).
209535863739SMike Smith  */
209635863739SMike Smith static int
2097f6c4dd3fSScott Long aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
209835863739SMike Smith {
209935863739SMike Smith 	u_int32_t pi, ci;
21009e2e96d8SScott Long 	int error;
2101f6c4dd3fSScott Long 	u_int32_t fib_size;
2102f6c4dd3fSScott Long 	u_int32_t fib_addr;
2103f6c4dd3fSScott Long 
210436e0bf6eSScott Long 	debug_called(3);
210536e0bf6eSScott Long 
2106f6c4dd3fSScott Long 	fib_size = cm->cm_fib->Header.Size;
2107f6c4dd3fSScott Long 	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
210835863739SMike Smith 
210935863739SMike Smith 	/* get the producer/consumer indices */
211035863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
211135863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
211235863739SMike Smith 
211335863739SMike Smith 	/* wrap the queue? */
211435863739SMike Smith 	if (pi >= aac_qinfo[queue].size)
211535863739SMike Smith 		pi = 0;
211635863739SMike Smith 
211735863739SMike Smith 	/* check for queue full */
211835863739SMike Smith 	if ((pi + 1) == ci) {
211935863739SMike Smith 		error = EBUSY;
212035863739SMike Smith 		goto out;
212135863739SMike Smith 	}
212235863739SMike Smith 
2123614c22b2SScott Long 	/*
2124614c22b2SScott Long 	 * To avoid a race with its completion interrupt, place this command on
2125614c22b2SScott Long 	 * the busy queue prior to advertising it to the controller.
2126614c22b2SScott Long 	 */
2127614c22b2SScott Long 	aac_enqueue_busy(cm);
2128614c22b2SScott Long 
212935863739SMike Smith 	/* populate queue entry */
213035863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
213135863739SMike Smith 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
213235863739SMike Smith 
213335863739SMike Smith 	/* update producer index */
213435863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
213535863739SMike Smith 
213635863739SMike Smith 	/* notify the adapter if we know how */
213735863739SMike Smith 	if (aac_qinfo[queue].notify != 0)
213835863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
213935863739SMike Smith 
214035863739SMike Smith 	error = 0;
214135863739SMike Smith 
214235863739SMike Smith out:
214335863739SMike Smith 	return(error);
214435863739SMike Smith }
214535863739SMike Smith 
214635863739SMike Smith /*
214736e0bf6eSScott Long  * Atomically remove one entry from the nominated queue, returns 0 on
214836e0bf6eSScott Long  * success or ENOENT if the queue is empty.
214935863739SMike Smith  */
215035863739SMike Smith static int
2151c6eafcf2SScott Long aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2152c6eafcf2SScott Long 		struct aac_fib **fib_addr)
215335863739SMike Smith {
215435863739SMike Smith 	u_int32_t pi, ci;
2155149af931SScott Long 	u_int32_t fib_index;
21569e2e96d8SScott Long 	int error;
2157f6c4dd3fSScott Long 	int notify;
215835863739SMike Smith 
215935863739SMike Smith 	debug_called(3);
216035863739SMike Smith 
216135863739SMike Smith 	/* get the producer/consumer indices */
216235863739SMike Smith 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
216335863739SMike Smith 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
216435863739SMike Smith 
216535863739SMike Smith 	/* check for queue empty */
216635863739SMike Smith 	if (ci == pi) {
216735863739SMike Smith 		error = ENOENT;
216835863739SMike Smith 		goto out;
216935863739SMike Smith 	}
217035863739SMike Smith 
21717753acd2SScott Long 	/* wrap the pi so the following test works */
21727753acd2SScott Long 	if (pi >= aac_qinfo[queue].size)
21737753acd2SScott Long 		pi = 0;
21747753acd2SScott Long 
2175f6c4dd3fSScott Long 	notify = 0;
2176f6c4dd3fSScott Long 	if (ci == pi + 1)
2177f6c4dd3fSScott Long 		notify++;
2178f6c4dd3fSScott Long 
217935863739SMike Smith 	/* wrap the queue? */
218035863739SMike Smith 	if (ci >= aac_qinfo[queue].size)
218135863739SMike Smith 		ci = 0;
218235863739SMike Smith 
218335863739SMike Smith 	/* fetch the entry */
218435863739SMike Smith 	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2185149af931SScott Long 
2186149af931SScott Long 	switch (queue) {
2187149af931SScott Long 	case AAC_HOST_NORM_CMD_QUEUE:
2188149af931SScott Long 	case AAC_HOST_HIGH_CMD_QUEUE:
2189149af931SScott Long 		/*
2190149af931SScott Long 		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2191149af931SScott Long 		 * on to hold an address.  For AIF's, the adapter assumes
2192149af931SScott Long 		 * that it's giving us an address into the array of AIF fibs.
2193149af931SScott Long 		 * Therefore, we have to convert it to an index.
2194149af931SScott Long 		 */
2195149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2196149af931SScott Long 			sizeof(struct aac_fib);
2197149af931SScott Long 		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2198149af931SScott Long 		break;
2199149af931SScott Long 
2200149af931SScott Long 	case AAC_HOST_NORM_RESP_QUEUE:
2201149af931SScott Long 	case AAC_HOST_HIGH_RESP_QUEUE:
2202149af931SScott Long 	{
2203149af931SScott Long 		struct aac_command *cm;
2204149af931SScott Long 
2205149af931SScott Long 		/*
2206149af931SScott Long 		 * As above, an index is used instead of an actual address.
2207149af931SScott Long 		 * Gotta shift the index to account for the fast response
2208149af931SScott Long 		 * bit.  No other correction is needed since this value was
2209149af931SScott Long 		 * originally provided by the driver via the SenderFibAddress
2210149af931SScott Long 		 * field.
2211149af931SScott Long 		 */
2212149af931SScott Long 		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
22137cb209f5SScott Long 		cm = sc->aac_commands + (fib_index >> 2);
2214149af931SScott Long 		*fib_addr = cm->cm_fib;
221535863739SMike Smith 
2216f30ac74cSScott Long 		/*
2217f30ac74cSScott Long 		 * Is this a fast response? If it is, update the fib fields in
2218149af931SScott Long 		 * local memory since the whole fib isn't DMA'd back up.
2219f30ac74cSScott Long 		 */
2220149af931SScott Long 		if (fib_index & 0x01) {
2221f30ac74cSScott Long 			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2222f30ac74cSScott Long 			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2223f30ac74cSScott Long 		}
2224149af931SScott Long 		break;
2225149af931SScott Long 	}
2226149af931SScott Long 	default:
2227149af931SScott Long 		panic("Invalid queue in aac_dequeue_fib()");
2228149af931SScott Long 		break;
2229149af931SScott Long 	}
2230149af931SScott Long 
223135863739SMike Smith 	/* update consumer index */
223235863739SMike Smith 	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
223335863739SMike Smith 
223435863739SMike Smith 	/* if we have made the queue un-full, notify the adapter */
2235f6c4dd3fSScott Long 	if (notify && (aac_qinfo[queue].notify != 0))
223635863739SMike Smith 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
223735863739SMike Smith 	error = 0;
223835863739SMike Smith 
223935863739SMike Smith out:
224035863739SMike Smith 	return(error);
224135863739SMike Smith }
224235863739SMike Smith 
2243914da7d0SScott Long /*
224436e0bf6eSScott Long  * Put our response to an Adapter Initialed Fib on the response queue
224536e0bf6eSScott Long  */
224636e0bf6eSScott Long static int
224736e0bf6eSScott Long aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
224836e0bf6eSScott Long {
224936e0bf6eSScott Long 	u_int32_t pi, ci;
22509e2e96d8SScott Long 	int error;
225136e0bf6eSScott Long 	u_int32_t fib_size;
225236e0bf6eSScott Long 	u_int32_t fib_addr;
225336e0bf6eSScott Long 
225436e0bf6eSScott Long 	debug_called(1);
225536e0bf6eSScott Long 
225636e0bf6eSScott Long 	/* Tell the adapter where the FIB is */
225736e0bf6eSScott Long 	fib_size = fib->Header.Size;
225836e0bf6eSScott Long 	fib_addr = fib->Header.SenderFibAddress;
225936e0bf6eSScott Long 	fib->Header.ReceiverFibAddress = fib_addr;
226036e0bf6eSScott Long 
226136e0bf6eSScott Long 	/* get the producer/consumer indices */
226236e0bf6eSScott Long 	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
226336e0bf6eSScott Long 	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
226436e0bf6eSScott Long 
226536e0bf6eSScott Long 	/* wrap the queue? */
226636e0bf6eSScott Long 	if (pi >= aac_qinfo[queue].size)
226736e0bf6eSScott Long 		pi = 0;
226836e0bf6eSScott Long 
226936e0bf6eSScott Long 	/* check for queue full */
227036e0bf6eSScott Long 	if ((pi + 1) == ci) {
227136e0bf6eSScott Long 		error = EBUSY;
227236e0bf6eSScott Long 		goto out;
227336e0bf6eSScott Long 	}
227436e0bf6eSScott Long 
227536e0bf6eSScott Long 	/* populate queue entry */
227636e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
227736e0bf6eSScott Long 	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
227836e0bf6eSScott Long 
227936e0bf6eSScott Long 	/* update producer index */
228036e0bf6eSScott Long 	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
228136e0bf6eSScott Long 
228236e0bf6eSScott Long 	/* notify the adapter if we know how */
228336e0bf6eSScott Long 	if (aac_qinfo[queue].notify != 0)
228436e0bf6eSScott Long 		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
228536e0bf6eSScott Long 
228636e0bf6eSScott Long 	error = 0;
228736e0bf6eSScott Long 
228836e0bf6eSScott Long out:
228936e0bf6eSScott Long 	return(error);
229036e0bf6eSScott Long }
229136e0bf6eSScott Long 
2292914da7d0SScott Long /*
22930b94a66eSMike Smith  * Check for commands that have been outstanding for a suspiciously long time,
22940b94a66eSMike Smith  * and complain about them.
22950b94a66eSMike Smith  */
22960b94a66eSMike Smith static void
22970b94a66eSMike Smith aac_timeout(struct aac_softc *sc)
22980b94a66eSMike Smith {
22990b94a66eSMike Smith 	struct aac_command *cm;
23000b94a66eSMike Smith 	time_t deadline;
230115c37be0SScott Long 	int timedout, code;
23020b94a66eSMike Smith 
2303f6c4dd3fSScott Long 	/*
230470545d1aSScott Long 	 * Traverse the busy command list, bitch about late commands once
2305914da7d0SScott Long 	 * only.
2306914da7d0SScott Long 	 */
230715c37be0SScott Long 	timedout = 0;
23082b3b0f17SScott Long 	deadline = time_uptime - AAC_CMD_TIMEOUT;
23090b94a66eSMike Smith 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2310f6c4dd3fSScott Long 		if ((cm->cm_timestamp  < deadline)
2311f6c4dd3fSScott Long 			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
23120b94a66eSMike Smith 			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2313914da7d0SScott Long 			device_printf(sc->aac_dev,
2314914da7d0SScott Long 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
23152b3b0f17SScott Long 				      cm, (int)(time_uptime-cm->cm_timestamp));
23160b94a66eSMike Smith 			AAC_PRINT_FIB(sc, cm->cm_fib);
231715c37be0SScott Long 			timedout++;
23180b94a66eSMike Smith 		}
23190b94a66eSMike Smith 	}
23200b94a66eSMike Smith 
232115c37be0SScott Long 	if (timedout) {
232215c37be0SScott Long 		code = AAC_GET_FWSTATUS(sc);
232315c37be0SScott Long 		if (code != AAC_UP_AND_RUNNING) {
232415c37be0SScott Long 			device_printf(sc->aac_dev, "WARNING! Controller is no "
232515c37be0SScott Long 				      "longer running! code= 0x%x\n", code);
232615c37be0SScott Long 		}
232715c37be0SScott Long 	}
23280b94a66eSMike Smith 	return;
23290b94a66eSMike Smith }
23300b94a66eSMike Smith 
2331914da7d0SScott Long /*
2332914da7d0SScott Long  * Interface Function Vectors
2333914da7d0SScott Long  */
233435863739SMike Smith 
2335914da7d0SScott Long /*
233635863739SMike Smith  * Read the current firmware status word.
233735863739SMike Smith  */
233835863739SMike Smith static int
233935863739SMike Smith aac_sa_get_fwstatus(struct aac_softc *sc)
234035863739SMike Smith {
234135863739SMike Smith 	debug_called(3);
234235863739SMike Smith 
234335863739SMike Smith 	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
234435863739SMike Smith }
234535863739SMike Smith 
234635863739SMike Smith static int
234735863739SMike Smith aac_rx_get_fwstatus(struct aac_softc *sc)
234835863739SMike Smith {
234935863739SMike Smith 	debug_called(3);
235035863739SMike Smith 
235135863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
235235863739SMike Smith }
235335863739SMike Smith 
2354b3457b51SScott Long static int
2355b3457b51SScott Long aac_fa_get_fwstatus(struct aac_softc *sc)
2356b3457b51SScott Long {
2357b3457b51SScott Long 	int val;
2358b3457b51SScott Long 
2359b3457b51SScott Long 	debug_called(3);
2360b3457b51SScott Long 
2361b3457b51SScott Long 	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
2362b3457b51SScott Long 	return (val);
2363b3457b51SScott Long }
2364b3457b51SScott Long 
23654afedc31SScott Long static int
23664afedc31SScott Long aac_rkt_get_fwstatus(struct aac_softc *sc)
23674afedc31SScott Long {
23684afedc31SScott Long 	debug_called(3);
23694afedc31SScott Long 
23704afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
23714afedc31SScott Long }
23724afedc31SScott Long 
2373914da7d0SScott Long /*
237435863739SMike Smith  * Notify the controller of a change in a given queue
237535863739SMike Smith  */
237635863739SMike Smith 
237735863739SMike Smith static void
237835863739SMike Smith aac_sa_qnotify(struct aac_softc *sc, int qbit)
237935863739SMike Smith {
238035863739SMike Smith 	debug_called(3);
238135863739SMike Smith 
238235863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
238335863739SMike Smith }
238435863739SMike Smith 
238535863739SMike Smith static void
238635863739SMike Smith aac_rx_qnotify(struct aac_softc *sc, int qbit)
238735863739SMike Smith {
238835863739SMike Smith 	debug_called(3);
238935863739SMike Smith 
239035863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
239135863739SMike Smith }
239235863739SMike Smith 
2393b3457b51SScott Long static void
2394b3457b51SScott Long aac_fa_qnotify(struct aac_softc *sc, int qbit)
2395b3457b51SScott Long {
2396b3457b51SScott Long 	debug_called(3);
2397b3457b51SScott Long 
2398b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2399b3457b51SScott Long 	AAC_FA_HACK(sc);
2400b3457b51SScott Long }
2401b3457b51SScott Long 
24024afedc31SScott Long static void
24034afedc31SScott Long aac_rkt_qnotify(struct aac_softc *sc, int qbit)
24044afedc31SScott Long {
24054afedc31SScott Long 	debug_called(3);
24064afedc31SScott Long 
24074afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
24084afedc31SScott Long }
24094afedc31SScott Long 
2410914da7d0SScott Long /*
241135863739SMike Smith  * Get the interrupt reason bits
241235863739SMike Smith  */
241335863739SMike Smith static int
241435863739SMike Smith aac_sa_get_istatus(struct aac_softc *sc)
241535863739SMike Smith {
241635863739SMike Smith 	debug_called(3);
241735863739SMike Smith 
241835863739SMike Smith 	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
241935863739SMike Smith }
242035863739SMike Smith 
242135863739SMike Smith static int
242235863739SMike Smith aac_rx_get_istatus(struct aac_softc *sc)
242335863739SMike Smith {
242435863739SMike Smith 	debug_called(3);
242535863739SMike Smith 
242635863739SMike Smith 	return(AAC_GETREG4(sc, AAC_RX_ODBR));
242735863739SMike Smith }
242835863739SMike Smith 
2429b3457b51SScott Long static int
2430b3457b51SScott Long aac_fa_get_istatus(struct aac_softc *sc)
2431b3457b51SScott Long {
2432b3457b51SScott Long 	int val;
2433b3457b51SScott Long 
2434b3457b51SScott Long 	debug_called(3);
2435b3457b51SScott Long 
2436b3457b51SScott Long 	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2437b3457b51SScott Long 	return (val);
2438b3457b51SScott Long }
2439b3457b51SScott Long 
24404afedc31SScott Long static int
24414afedc31SScott Long aac_rkt_get_istatus(struct aac_softc *sc)
24424afedc31SScott Long {
24434afedc31SScott Long 	debug_called(3);
24444afedc31SScott Long 
24454afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
24464afedc31SScott Long }
24474afedc31SScott Long 
2448914da7d0SScott Long /*
244935863739SMike Smith  * Clear some interrupt reason bits
245035863739SMike Smith  */
245135863739SMike Smith static void
245235863739SMike Smith aac_sa_clear_istatus(struct aac_softc *sc, int mask)
245335863739SMike Smith {
245435863739SMike Smith 	debug_called(3);
245535863739SMike Smith 
245635863739SMike Smith 	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
245735863739SMike Smith }
245835863739SMike Smith 
245935863739SMike Smith static void
246035863739SMike Smith aac_rx_clear_istatus(struct aac_softc *sc, int mask)
246135863739SMike Smith {
246235863739SMike Smith 	debug_called(3);
246335863739SMike Smith 
246435863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
246535863739SMike Smith }
246635863739SMike Smith 
2467b3457b51SScott Long static void
2468b3457b51SScott Long aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2469b3457b51SScott Long {
2470b3457b51SScott Long 	debug_called(3);
2471b3457b51SScott Long 
2472b3457b51SScott Long 	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2473b3457b51SScott Long 	AAC_FA_HACK(sc);
2474b3457b51SScott Long }
2475b3457b51SScott Long 
24764afedc31SScott Long static void
24774afedc31SScott Long aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
24784afedc31SScott Long {
24794afedc31SScott Long 	debug_called(3);
24804afedc31SScott Long 
24814afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
24824afedc31SScott Long }
24834afedc31SScott Long 
2484914da7d0SScott Long /*
248535863739SMike Smith  * Populate the mailbox and set the command word
248635863739SMike Smith  */
248735863739SMike Smith static void
248835863739SMike Smith aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
248935863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249035863739SMike Smith {
249135863739SMike Smith 	debug_called(4);
249235863739SMike Smith 
249335863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
249435863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
249535863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
249635863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
249735863739SMike Smith 	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
249835863739SMike Smith }
249935863739SMike Smith 
250035863739SMike Smith static void
250135863739SMike Smith aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
250235863739SMike Smith 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
250335863739SMike Smith {
250435863739SMike Smith 	debug_called(4);
250535863739SMike Smith 
250635863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
250735863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
250835863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
250935863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
251035863739SMike Smith 	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
251135863739SMike Smith }
251235863739SMike Smith 
2513b3457b51SScott Long static void
2514b3457b51SScott Long aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2515b3457b51SScott Long 		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2516b3457b51SScott Long {
2517b3457b51SScott Long 	debug_called(4);
2518b3457b51SScott Long 
2519b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2520b3457b51SScott Long 	AAC_FA_HACK(sc);
2521b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2522b3457b51SScott Long 	AAC_FA_HACK(sc);
2523b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2524b3457b51SScott Long 	AAC_FA_HACK(sc);
2525b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2526b3457b51SScott Long 	AAC_FA_HACK(sc);
2527b3457b51SScott Long 	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2528b3457b51SScott Long 	AAC_FA_HACK(sc);
2529b3457b51SScott Long }
2530b3457b51SScott Long 
25314afedc31SScott Long static void
25324afedc31SScott Long aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
25334afedc31SScott Long 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
25344afedc31SScott Long {
25354afedc31SScott Long 	debug_called(4);
25364afedc31SScott Long 
25374afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
25384afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
25394afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
25404afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
25414afedc31SScott Long 	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
25424afedc31SScott Long }
25434afedc31SScott Long 
2544914da7d0SScott Long /*
254535863739SMike Smith  * Fetch the immediate command status word
254635863739SMike Smith  */
254735863739SMike Smith static int
2548a6d35632SScott Long aac_sa_get_mailbox(struct aac_softc *sc, int mb)
254935863739SMike Smith {
255035863739SMike Smith 	debug_called(4);
255135863739SMike Smith 
2552a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
255335863739SMike Smith }
255435863739SMike Smith 
255535863739SMike Smith static int
2556a6d35632SScott Long aac_rx_get_mailbox(struct aac_softc *sc, int mb)
255735863739SMike Smith {
255835863739SMike Smith 	debug_called(4);
255935863739SMike Smith 
2560a6d35632SScott Long 	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
256135863739SMike Smith }
256235863739SMike Smith 
2563b3457b51SScott Long static int
2564a6d35632SScott Long aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2565b3457b51SScott Long {
2566b3457b51SScott Long 	int val;
2567b3457b51SScott Long 
2568b3457b51SScott Long 	debug_called(4);
2569b3457b51SScott Long 
2570a6d35632SScott Long 	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2571b3457b51SScott Long 	return (val);
2572b3457b51SScott Long }
2573b3457b51SScott Long 
25744afedc31SScott Long static int
25754afedc31SScott Long aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
25764afedc31SScott Long {
25774afedc31SScott Long 	debug_called(4);
25784afedc31SScott Long 
25794afedc31SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
25804afedc31SScott Long }
25814afedc31SScott Long 
2582914da7d0SScott Long /*
258335863739SMike Smith  * Set/clear interrupt masks
258435863739SMike Smith  */
258535863739SMike Smith static void
258635863739SMike Smith aac_sa_set_interrupts(struct aac_softc *sc, int enable)
258735863739SMike Smith {
258835863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
258935863739SMike Smith 
259035863739SMike Smith 	if (enable) {
259135863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
259235863739SMike Smith 	} else {
259335863739SMike Smith 		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
259435863739SMike Smith 	}
259535863739SMike Smith }
259635863739SMike Smith 
259735863739SMike Smith static void
259835863739SMike Smith aac_rx_set_interrupts(struct aac_softc *sc, int enable)
259935863739SMike Smith {
260035863739SMike Smith 	debug(2, "%sable interrupts", enable ? "en" : "dis");
260135863739SMike Smith 
260235863739SMike Smith 	if (enable) {
26037cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
26047cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
26057cb209f5SScott Long 		else
260635863739SMike Smith 			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
260735863739SMike Smith 	} else {
260835863739SMike Smith 		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
260935863739SMike Smith 	}
261035863739SMike Smith }
261135863739SMike Smith 
2612b3457b51SScott Long static void
2613b3457b51SScott Long aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2614b3457b51SScott Long {
2615b3457b51SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
2616b3457b51SScott Long 
2617b3457b51SScott Long 	if (enable) {
2618b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2619b3457b51SScott Long 		AAC_FA_HACK(sc);
2620b3457b51SScott Long 	} else {
2621b3457b51SScott Long 		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2622b3457b51SScott Long 		AAC_FA_HACK(sc);
2623b3457b51SScott Long 	}
2624b3457b51SScott Long }
2625b3457b51SScott Long 
26264afedc31SScott Long static void
26274afedc31SScott Long aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
26284afedc31SScott Long {
26294afedc31SScott Long 	debug(2, "%sable interrupts", enable ? "en" : "dis");
26304afedc31SScott Long 
26314afedc31SScott Long 	if (enable) {
26327cb209f5SScott Long 		if (sc->flags & AAC_FLAGS_NEW_COMM)
26337cb209f5SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
26347cb209f5SScott Long 		else
26354afedc31SScott Long 			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
26364afedc31SScott Long 	} else {
26374afedc31SScott Long 		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
26384afedc31SScott Long 	}
26394afedc31SScott Long }
26404afedc31SScott Long 
2641914da7d0SScott Long /*
26427cb209f5SScott Long  * New comm. interface: Send command functions
26437cb209f5SScott Long  */
26447cb209f5SScott Long static int
26457cb209f5SScott Long aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
26467cb209f5SScott Long {
26477cb209f5SScott Long 	u_int32_t index, device;
26487cb209f5SScott Long 
26497cb209f5SScott Long 	debug(2, "send command (new comm.)");
26507cb209f5SScott Long 
26517cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RX_IQUE);
26527cb209f5SScott Long 	if (index == 0xffffffffL)
26537cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RX_IQUE);
26547cb209f5SScott Long 	if (index == 0xffffffffL)
26557cb209f5SScott Long 		return index;
26567cb209f5SScott Long 	aac_enqueue_busy(cm);
26577cb209f5SScott Long 	device = index;
26587cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26597cb209f5SScott Long 	device += 4;
26607cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26617cb209f5SScott Long 	device += 4;
26627cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26637cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_IQUE, index);
26647cb209f5SScott Long 	return 0;
26657cb209f5SScott Long }
26667cb209f5SScott Long 
26677cb209f5SScott Long static int
26687cb209f5SScott Long aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
26697cb209f5SScott Long {
26707cb209f5SScott Long 	u_int32_t index, device;
26717cb209f5SScott Long 
26727cb209f5SScott Long 	debug(2, "send command (new comm.)");
26737cb209f5SScott Long 
26747cb209f5SScott Long 	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
26757cb209f5SScott Long 	if (index == 0xffffffffL)
26767cb209f5SScott Long 		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
26777cb209f5SScott Long 	if (index == 0xffffffffL)
26787cb209f5SScott Long 		return index;
26797cb209f5SScott Long 	aac_enqueue_busy(cm);
26807cb209f5SScott Long 	device = index;
26817cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
26827cb209f5SScott Long 	device += 4;
26837cb209f5SScott Long 	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
26847cb209f5SScott Long 	device += 4;
26857cb209f5SScott Long 	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
26867cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
26877cb209f5SScott Long 	return 0;
26887cb209f5SScott Long }
26897cb209f5SScott Long 
26907cb209f5SScott Long /*
26917cb209f5SScott Long  * New comm. interface: get, set outbound queue index
26927cb209f5SScott Long  */
26937cb209f5SScott Long static int
26947cb209f5SScott Long aac_rx_get_outb_queue(struct aac_softc *sc)
26957cb209f5SScott Long {
26967cb209f5SScott Long 	debug_called(3);
26977cb209f5SScott Long 
26987cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RX_OQUE));
26997cb209f5SScott Long }
27007cb209f5SScott Long 
27017cb209f5SScott Long static int
27027cb209f5SScott Long aac_rkt_get_outb_queue(struct aac_softc *sc)
27037cb209f5SScott Long {
27047cb209f5SScott Long 	debug_called(3);
27057cb209f5SScott Long 
27067cb209f5SScott Long 	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
27077cb209f5SScott Long }
27087cb209f5SScott Long 
27097cb209f5SScott Long static void
27107cb209f5SScott Long aac_rx_set_outb_queue(struct aac_softc *sc, int index)
27117cb209f5SScott Long {
27127cb209f5SScott Long 	debug_called(3);
27137cb209f5SScott Long 
27147cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RX_OQUE, index);
27157cb209f5SScott Long }
27167cb209f5SScott Long 
27177cb209f5SScott Long static void
27187cb209f5SScott Long aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
27197cb209f5SScott Long {
27207cb209f5SScott Long 	debug_called(3);
27217cb209f5SScott Long 
27227cb209f5SScott Long 	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
27237cb209f5SScott Long }
27247cb209f5SScott Long 
27257cb209f5SScott Long /*
2726914da7d0SScott Long  * Debugging and Diagnostics
2727914da7d0SScott Long  */
272835863739SMike Smith 
2729914da7d0SScott Long /*
273035863739SMike Smith  * Print some information about the controller.
273135863739SMike Smith  */
273235863739SMike Smith static void
273335863739SMike Smith aac_describe_controller(struct aac_softc *sc)
273435863739SMike Smith {
2735cbfd045bSScott Long 	struct aac_fib *fib;
273635863739SMike Smith 	struct aac_adapter_info	*info;
27377ea2d558SEd Maste 	char *adapter_type = "Adaptec RAID controller";
273835863739SMike Smith 
273935863739SMike Smith 	debug_called(2);
274035863739SMike Smith 
274181b3da08SScott Long 	mtx_lock(&sc->aac_io_lock);
274203b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
2743cbfd045bSScott Long 
27447ea2d558SEd Maste 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
27457ea2d558SEd Maste 		fib->data[0] = 0;
27467ea2d558SEd Maste 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
27477ea2d558SEd Maste 			device_printf(sc->aac_dev,
27487ea2d558SEd Maste 			    "RequestSupplementAdapterInfo failed\n");
27497ea2d558SEd Maste 		else
27507ea2d558SEd Maste 			adapter_type = ((struct aac_supplement_adapter_info *)
27517ea2d558SEd Maste 			    &fib->data[0])->AdapterTypeText;
27527ea2d558SEd Maste 	}
27537ea2d558SEd Maste 	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
27547ea2d558SEd Maste 		adapter_type,
27557ea2d558SEd Maste 		AAC_DRIVER_VERSION >> 24,
27567ea2d558SEd Maste 		(AAC_DRIVER_VERSION >> 16) & 0xFF,
27577ea2d558SEd Maste 		AAC_DRIVER_VERSION & 0xFF,
27587ea2d558SEd Maste 		AAC_DRIVER_BUILD);
27597ea2d558SEd Maste 
2760cbfd045bSScott Long 	fib->data[0] = 0;
2761cbfd045bSScott Long 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
276235863739SMike Smith 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2763fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
276481b3da08SScott Long 		mtx_unlock(&sc->aac_io_lock);
276535863739SMike Smith 		return;
276635863739SMike Smith 	}
276735863739SMike Smith 
2768bd971c49SScott Long 	/* save the kernel revision structure for later use */
2769bd971c49SScott Long 	info = (struct aac_adapter_info *)&fib->data[0];
2770bd971c49SScott Long 	sc->aac_revision = info->KernelRevision;
2771bd971c49SScott Long 
27727cb209f5SScott Long 
2773bd971c49SScott Long 	if (bootverbose) {
2774b1c56c68SScott Long 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2775b1c56c68SScott Long 		    "(%dMB cache, %dMB execution), %s\n",
2776c6eafcf2SScott Long 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2777b1c56c68SScott Long 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2778b1c56c68SScott Long 		    info->BufferMem / (1024 * 1024),
2779b1c56c68SScott Long 		    info->ExecutionMem / (1024 * 1024),
2780914da7d0SScott Long 		    aac_describe_code(aac_battery_platform,
2781914da7d0SScott Long 		    info->batteryPlatform));
278235863739SMike Smith 
2783bd971c49SScott Long 		device_printf(sc->aac_dev,
2784bd971c49SScott Long 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
278535863739SMike Smith 		    info->KernelRevision.external.comp.major,
278635863739SMike Smith 		    info->KernelRevision.external.comp.minor,
278735863739SMike Smith 		    info->KernelRevision.external.comp.dash,
278836e0bf6eSScott Long 		    info->KernelRevision.buildNumber,
278936e0bf6eSScott Long 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2790fe3cb0e1SScott Long 
2791a6d35632SScott Long 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2792a6d35632SScott Long 			      sc->supported_options,
2793a6d35632SScott Long 			      "\20"
2794a6d35632SScott Long 			      "\1SNAPSHOT"
2795a6d35632SScott Long 			      "\2CLUSTERS"
2796a6d35632SScott Long 			      "\3WCACHE"
2797a6d35632SScott Long 			      "\4DATA64"
2798a6d35632SScott Long 			      "\5HOSTTIME"
2799a6d35632SScott Long 			      "\6RAID50"
2800a6d35632SScott Long 			      "\7WINDOW4GB"
2801a6d35632SScott Long 			      "\10SCSIUPGD"
2802a6d35632SScott Long 			      "\11SOFTERR"
2803a6d35632SScott Long 			      "\12NORECOND"
2804a6d35632SScott Long 			      "\13SGMAP64"
2805a6d35632SScott Long 			      "\14ALARM"
28067cb209f5SScott Long 			      "\15NONDASD"
28077cb209f5SScott Long 			      "\16SCSIMGT"
28087cb209f5SScott Long 			      "\17RAIDSCSI"
28097cb209f5SScott Long 			      "\21ADPTINFO"
28107cb209f5SScott Long 			      "\22NEWCOMM"
28117cb209f5SScott Long 			      "\23ARRAY64BIT"
28127cb209f5SScott Long 			      "\24HEATSENSOR");
2813a6d35632SScott Long 	}
2814bd971c49SScott Long 	aac_release_sync_fib(sc);
281581b3da08SScott Long 	mtx_unlock(&sc->aac_io_lock);
281635863739SMike Smith }
281735863739SMike Smith 
2818914da7d0SScott Long /*
281935863739SMike Smith  * Look up a text description of a numeric error code and return a pointer to
282035863739SMike Smith  * same.
282135863739SMike Smith  */
282235863739SMike Smith static char *
282335863739SMike Smith aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
282435863739SMike Smith {
282535863739SMike Smith 	int i;
282635863739SMike Smith 
282735863739SMike Smith 	for (i = 0; table[i].string != NULL; i++)
282835863739SMike Smith 		if (table[i].code == code)
282935863739SMike Smith 			return(table[i].string);
283035863739SMike Smith 	return(table[i + 1].string);
283135863739SMike Smith }
283235863739SMike Smith 
2833914da7d0SScott Long /*
2834914da7d0SScott Long  * Management Interface
2835914da7d0SScott Long  */
283635863739SMike Smith 
283735863739SMike Smith static int
283889c9c53dSPoul-Henning Kamp aac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
283935863739SMike Smith {
2840914da7d0SScott Long 	struct aac_softc *sc;
284135863739SMike Smith 
284235863739SMike Smith 	debug_called(2);
284335863739SMike Smith 
2844914da7d0SScott Long 	sc = dev->si_drv1;
2845a723a548SEd Maste 	sc->aac_open_cnt++;
284635863739SMike Smith 	sc->aac_state |= AAC_STATE_OPEN;
284735863739SMike Smith 
284835863739SMike Smith 	return 0;
284935863739SMike Smith }
285035863739SMike Smith 
285135863739SMike Smith static int
285289c9c53dSPoul-Henning Kamp aac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
285335863739SMike Smith {
2854914da7d0SScott Long 	struct aac_softc *sc;
285535863739SMike Smith 
285635863739SMike Smith 	debug_called(2);
285735863739SMike Smith 
2858914da7d0SScott Long 	sc = dev->si_drv1;
2859a723a548SEd Maste 	sc->aac_open_cnt--;
286035863739SMike Smith 	/* Mark this unit as no longer open  */
2861a723a548SEd Maste 	if (sc->aac_open_cnt == 0)
286235863739SMike Smith 		sc->aac_state &= ~AAC_STATE_OPEN;
286335863739SMike Smith 
286435863739SMike Smith 	return 0;
286535863739SMike Smith }
286635863739SMike Smith 
286735863739SMike Smith static int
286889c9c53dSPoul-Henning Kamp aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
286935863739SMike Smith {
2870914da7d0SScott Long 	union aac_statrequest *as;
2871914da7d0SScott Long 	struct aac_softc *sc;
28720b94a66eSMike Smith 	int error = 0;
287335863739SMike Smith 
287435863739SMike Smith 	debug_called(2);
287535863739SMike Smith 
2876914da7d0SScott Long 	as = (union aac_statrequest *)arg;
2877914da7d0SScott Long 	sc = dev->si_drv1;
2878914da7d0SScott Long 
287935863739SMike Smith 	switch (cmd) {
28800b94a66eSMike Smith 	case AACIO_STATS:
28810b94a66eSMike Smith 		switch (as->as_item) {
28820b94a66eSMike Smith 		case AACQ_FREE:
28830b94a66eSMike Smith 		case AACQ_BIO:
28840b94a66eSMike Smith 		case AACQ_READY:
28850b94a66eSMike Smith 		case AACQ_BUSY:
2886c6eafcf2SScott Long 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2887c6eafcf2SScott Long 			      sizeof(struct aac_qstat));
28880b94a66eSMike Smith 			break;
28890b94a66eSMike Smith 		default:
28900b94a66eSMike Smith 			error = ENOENT;
28910b94a66eSMike Smith 			break;
28920b94a66eSMike Smith 		}
28930b94a66eSMike Smith 	break;
28940b94a66eSMike Smith 
289535863739SMike Smith 	case FSACTL_SENDFIB:
2896f355c0e0SEd Maste 	case FSACTL_SEND_LARGE_FIB:
2897fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2898fb0c27d7SScott Long 	case FSACTL_LNX_SENDFIB:
2899f355c0e0SEd Maste 	case FSACTL_LNX_SEND_LARGE_FIB:
29000b94a66eSMike Smith 		debug(1, "FSACTL_SENDFIB");
290135863739SMike Smith 		error = aac_ioctl_sendfib(sc, arg);
290235863739SMike Smith 		break;
2903f355c0e0SEd Maste 	case FSACTL_SEND_RAW_SRB:
2904f355c0e0SEd Maste 		arg = *(caddr_t*)arg;
2905f355c0e0SEd Maste 	case FSACTL_LNX_SEND_RAW_SRB:
2906f355c0e0SEd Maste 		debug(1, "FSACTL_SEND_RAW_SRB");
2907f355c0e0SEd Maste 		error = aac_ioctl_send_raw_srb(sc, arg);
2908f355c0e0SEd Maste 		break;
290935863739SMike Smith 	case FSACTL_AIF_THREAD:
2910fb0c27d7SScott Long 	case FSACTL_LNX_AIF_THREAD:
29110b94a66eSMike Smith 		debug(1, "FSACTL_AIF_THREAD");
291235863739SMike Smith 		error = EINVAL;
291335863739SMike Smith 		break;
291435863739SMike Smith 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2915fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2916fb0c27d7SScott Long 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
29170b94a66eSMike Smith 		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
2918a723a548SEd Maste 		error = aac_open_aif(sc, arg);
291935863739SMike Smith 		break;
292035863739SMike Smith 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2921fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2922fb0c27d7SScott Long 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
29230b94a66eSMike Smith 		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2924fb0c27d7SScott Long 		error = aac_getnext_aif(sc, arg);
292535863739SMike Smith 		break;
292635863739SMike Smith 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2927a723a548SEd Maste 		arg = *(caddr_t*)arg;
2928fb0c27d7SScott Long 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
29290b94a66eSMike Smith 		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2930a723a548SEd Maste 		error = aac_close_aif(sc, arg);
293135863739SMike Smith 		break;
293235863739SMike Smith 	case FSACTL_MINIPORT_REV_CHECK:
2933fb0c27d7SScott Long 		arg = *(caddr_t*)arg;
2934fb0c27d7SScott Long 	case FSACTL_LNX_MINIPORT_REV_CHECK:
29350b94a66eSMike Smith 		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2936fb0c27d7SScott Long 		error = aac_rev_check(sc, arg);
293735863739SMike Smith 		break;
293836e0bf6eSScott Long 	case FSACTL_QUERY_DISK:
293936e0bf6eSScott Long 		arg = *(caddr_t*)arg;
294036e0bf6eSScott Long 	case FSACTL_LNX_QUERY_DISK:
294136e0bf6eSScott Long 		debug(1, "FSACTL_QUERY_DISK");
294236e0bf6eSScott Long 		error = aac_query_disk(sc, arg);
294336e0bf6eSScott Long 		break;
294436e0bf6eSScott Long 	case FSACTL_DELETE_DISK:
294536e0bf6eSScott Long 	case FSACTL_LNX_DELETE_DISK:
2946914da7d0SScott Long 		/*
2947914da7d0SScott Long 		 * We don't trust the underland to tell us when to delete a
2948914da7d0SScott Long 		 * container, rather we rely on an AIF coming from the
2949914da7d0SScott Long 		 * controller
2950914da7d0SScott Long 		 */
295136e0bf6eSScott Long 		error = 0;
295236e0bf6eSScott Long 		break;
29537cb209f5SScott Long 	case FSACTL_GET_PCI_INFO:
29547cb209f5SScott Long 		arg = *(caddr_t*)arg;
29557cb209f5SScott Long 	case FSACTL_LNX_GET_PCI_INFO:
29567cb209f5SScott Long 		debug(1, "FSACTL_GET_PCI_INFO");
29577cb209f5SScott Long 		error = aac_get_pci_info(sc, arg);
29587cb209f5SScott Long 		break;
295935863739SMike Smith 	default:
2960b3457b51SScott Long 		debug(1, "unsupported cmd 0x%lx\n", cmd);
296135863739SMike Smith 		error = EINVAL;
296235863739SMike Smith 		break;
296335863739SMike Smith 	}
296435863739SMike Smith 	return(error);
296535863739SMike Smith }
296635863739SMike Smith 
2967b3457b51SScott Long static int
296889c9c53dSPoul-Henning Kamp aac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
2969b3457b51SScott Long {
2970b3457b51SScott Long 	struct aac_softc *sc;
2971b3457b51SScott Long 	int revents;
2972b3457b51SScott Long 
2973b3457b51SScott Long 	sc = dev->si_drv1;
2974b3457b51SScott Long 	revents = 0;
2975b3457b51SScott Long 
2976bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
2977b3457b51SScott Long 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2978a723a548SEd Maste 		if (sc->aifq_idx != 0 || sc->aifq_filled)
2979b3457b51SScott Long 			revents |= poll_events & (POLLIN | POLLRDNORM);
2980b3457b51SScott Long 	}
2981bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
2982b3457b51SScott Long 
2983b3457b51SScott Long 	if (revents == 0) {
2984b3457b51SScott Long 		if (poll_events & (POLLIN | POLLRDNORM))
2985b3457b51SScott Long 			selrecord(td, &sc->rcv_select);
2986b3457b51SScott Long 	}
2987b3457b51SScott Long 
2988b3457b51SScott Long 	return (revents);
2989b3457b51SScott Long }
2990b3457b51SScott Long 
29917cb209f5SScott Long static void
29927cb209f5SScott Long aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
29937cb209f5SScott Long {
29947cb209f5SScott Long 
29957cb209f5SScott Long 	switch (event->ev_type) {
29967cb209f5SScott Long 	case AAC_EVENT_CMFREE:
29970c40d5beSEd Maste 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
29981a681311SLuoqi Chen 		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
29997cb209f5SScott Long 			aac_add_event(sc, event);
30007cb209f5SScott Long 			return;
30017cb209f5SScott Long 		}
30027cb209f5SScott Long 		free(event, M_AACBUF);
30038eeb2ca6SScott Long 		wakeup(arg);
30047cb209f5SScott Long 		break;
30057cb209f5SScott Long 	default:
30067cb209f5SScott Long 		break;
30077cb209f5SScott Long 	}
30087cb209f5SScott Long }
30097cb209f5SScott Long 
3010914da7d0SScott Long /*
301135863739SMike Smith  * Send a FIB supplied from userspace
301235863739SMike Smith  */
301335863739SMike Smith static int
301435863739SMike Smith aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
301535863739SMike Smith {
301635863739SMike Smith 	struct aac_command *cm;
301735863739SMike Smith 	int size, error;
301835863739SMike Smith 
301935863739SMike Smith 	debug_called(2);
302035863739SMike Smith 
302135863739SMike Smith 	cm = NULL;
302235863739SMike Smith 
302335863739SMike Smith 	/*
302435863739SMike Smith 	 * Get a command
302535863739SMike Smith 	 */
3026bb6fe253SScott Long 	mtx_lock(&sc->aac_io_lock);
302735863739SMike Smith 	if (aac_alloc_command(sc, &cm)) {
30287cb209f5SScott Long 		struct aac_event *event;
30297cb209f5SScott Long 
30307cb209f5SScott Long 		event = malloc(sizeof(struct aac_event), M_AACBUF,
30317cb209f5SScott Long 		    M_NOWAIT | M_ZERO);
30327cb209f5SScott Long 		if (event == NULL) {
303335863739SMike Smith 			error = EBUSY;
3034f16627aaSEd Maste 			mtx_unlock(&sc->aac_io_lock);
303535863739SMike Smith 			goto out;
303635863739SMike Smith 		}
30377cb209f5SScott Long 		event->ev_type = AAC_EVENT_CMFREE;
30387cb209f5SScott Long 		event->ev_callback = aac_ioctl_event;
30397cb209f5SScott Long 		event->ev_arg = &cm;
30407cb209f5SScott Long 		aac_add_event(sc, event);
30418eeb2ca6SScott Long 		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
30427cb209f5SScott Long 	}
304393cfca22SScott Long 	mtx_unlock(&sc->aac_io_lock);
304435863739SMike Smith 
304535863739SMike Smith 	/*
304635863739SMike Smith 	 * Fetch the FIB header, then re-copy to get data as well.
304735863739SMike Smith 	 */
3048914da7d0SScott Long 	if ((error = copyin(ufib, cm->cm_fib,
3049914da7d0SScott Long 			    sizeof(struct aac_fib_header))) != 0)
305035863739SMike Smith 		goto out;
305135863739SMike Smith 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3052f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3053f355c0e0SEd Maste 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3054f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3055f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
305635863739SMike Smith 	}
305735863739SMike Smith 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
305835863739SMike Smith 		goto out;
305935863739SMike Smith 	cm->cm_fib->Header.Size = size;
30602b3b0f17SScott Long 	cm->cm_timestamp = time_uptime;
306135863739SMike Smith 
306235863739SMike Smith 	/*
306335863739SMike Smith 	 * Pass the FIB to the controller, wait for it to complete.
306435863739SMike Smith 	 */
306593cfca22SScott Long 	mtx_lock(&sc->aac_io_lock);
3066f16627aaSEd Maste 	error = aac_wait_command(cm);
3067f16627aaSEd Maste 	mtx_unlock(&sc->aac_io_lock);
3068f16627aaSEd Maste 	if (error != 0) {
306970545d1aSScott Long 		device_printf(sc->aac_dev,
307070545d1aSScott Long 			      "aac_wait_command return %d\n", error);
307135863739SMike Smith 		goto out;
3072b3457b51SScott Long 	}
307335863739SMike Smith 
307435863739SMike Smith 	/*
307535863739SMike Smith 	 * Copy the FIB and data back out to the caller.
307635863739SMike Smith 	 */
307735863739SMike Smith 	size = cm->cm_fib->Header.Size;
3078f355c0e0SEd Maste 	if (size > sc->aac_max_fib_size) {
3079f355c0e0SEd Maste 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3080f355c0e0SEd Maste 			      size, sc->aac_max_fib_size);
3081f355c0e0SEd Maste 		size = sc->aac_max_fib_size;
308235863739SMike Smith 	}
308335863739SMike Smith 	error = copyout(cm->cm_fib, ufib, size);
308435863739SMike Smith 
308535863739SMike Smith out:
3086f6c4dd3fSScott Long 	if (cm != NULL) {
3087f16627aaSEd Maste 		mtx_lock(&sc->aac_io_lock);
308835863739SMike Smith 		aac_release_command(cm);
3089bb6fe253SScott Long 		mtx_unlock(&sc->aac_io_lock);
3090f16627aaSEd Maste 	}
309135863739SMike Smith 	return(error);
309235863739SMike Smith }
309335863739SMike Smith 
3094914da7d0SScott Long /*
3095f355c0e0SEd Maste  * Send a passthrough FIB supplied from userspace
3096f355c0e0SEd Maste  */
3097f355c0e0SEd Maste static int
3098f355c0e0SEd Maste aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3099f355c0e0SEd Maste {
3100f355c0e0SEd Maste 	return (EINVAL);
3101f355c0e0SEd Maste }
3102f355c0e0SEd Maste 
3103f355c0e0SEd Maste /*
310435863739SMike Smith  * Handle an AIF sent to us by the controller; queue it for later reference.
310536e0bf6eSScott Long  * If the queue fills up, then drop the older entries.
310635863739SMike Smith  */
310735863739SMike Smith static void
310836e0bf6eSScott Long aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
310935863739SMike Smith {
311036e0bf6eSScott Long 	struct aac_aif_command *aif;
311136e0bf6eSScott Long 	struct aac_container *co, *co_next;
3112a723a548SEd Maste 	struct aac_fib_context *ctx;
3113cbfd045bSScott Long 	struct aac_mntinfo *mi;
3114cbfd045bSScott Long 	struct aac_mntinforesp *mir = NULL;
311536e0bf6eSScott Long 	u_int16_t rsize;
3116a723a548SEd Maste 	int next, current, found;
3117795d7dc0SScott Long 	int count = 0, added = 0, i = 0;
311835863739SMike Smith 
311935863739SMike Smith 	debug_called(2);
312035863739SMike Smith 
312136e0bf6eSScott Long 	aif = (struct aac_aif_command*)&fib->data[0];
312236e0bf6eSScott Long 	aac_print_aif(sc, aif);
312336e0bf6eSScott Long 
312436e0bf6eSScott Long 	/* Is it an event that we should care about? */
312536e0bf6eSScott Long 	switch (aif->command) {
312636e0bf6eSScott Long 	case AifCmdEventNotify:
312736e0bf6eSScott Long 		switch (aif->data.EN.type) {
312836e0bf6eSScott Long 		case AifEnAddContainer:
312936e0bf6eSScott Long 		case AifEnDeleteContainer:
313036e0bf6eSScott Long 			/*
3131914da7d0SScott Long 			 * A container was added or deleted, but the message
3132914da7d0SScott Long 			 * doesn't tell us anything else!  Re-enumerate the
3133914da7d0SScott Long 			 * containers and sort things out.
313436e0bf6eSScott Long 			 */
313503b5fe51SScott Long 			aac_alloc_sync_fib(sc, &fib);
3136cbfd045bSScott Long 			mi = (struct aac_mntinfo *)&fib->data[0];
313736e0bf6eSScott Long 			do {
313836e0bf6eSScott Long 				/*
3139914da7d0SScott Long 				 * Ask the controller for its containers one at
3140914da7d0SScott Long 				 * a time.
3141914da7d0SScott Long 				 * XXX What if the controller's list changes
3142914da7d0SScott Long 				 * midway through this enumaration?
314336e0bf6eSScott Long 				 * XXX This should be done async.
314436e0bf6eSScott Long 				 */
314539ee03c3SScott Long 				bzero(mi, sizeof(struct aac_mntinfo));
314639ee03c3SScott Long 				mi->Command = VM_NameServe;
314739ee03c3SScott Long 				mi->MntType = FT_FILESYS;
3148cbfd045bSScott Long 				mi->MntCount = i;
314936e0bf6eSScott Long 				rsize = sizeof(mir);
3150cbfd045bSScott Long 				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
3151cbfd045bSScott Long 						 sizeof(struct aac_mntinfo))) {
3152795d7dc0SScott Long 					printf("Error probing container %d\n",
3153914da7d0SScott Long 					      i);
315436e0bf6eSScott Long 					continue;
315536e0bf6eSScott Long 				}
3156cbfd045bSScott Long 				mir = (struct aac_mntinforesp *)&fib->data[0];
3157795d7dc0SScott Long 				/* XXX Need to check if count changed */
3158795d7dc0SScott Long 				count = mir->MntRespCount;
315936e0bf6eSScott Long 				/*
3160914da7d0SScott Long 				 * Check the container against our list.
3161914da7d0SScott Long 				 * co->co_found was already set to 0 in a
3162914da7d0SScott Long 				 * previous run.
316336e0bf6eSScott Long 				 */
3164cbfd045bSScott Long 				if ((mir->Status == ST_OK) &&
3165cbfd045bSScott Long 				    (mir->MntTable[0].VolType != CT_NONE)) {
316636e0bf6eSScott Long 					found = 0;
3167914da7d0SScott Long 					TAILQ_FOREACH(co,
3168914da7d0SScott Long 						      &sc->aac_container_tqh,
3169914da7d0SScott Long 						      co_link) {
317036e0bf6eSScott Long 						if (co->co_mntobj.ObjectId ==
3171cbfd045bSScott Long 						    mir->MntTable[0].ObjectId) {
317236e0bf6eSScott Long 							co->co_found = 1;
317336e0bf6eSScott Long 							found = 1;
317436e0bf6eSScott Long 							break;
317536e0bf6eSScott Long 						}
317636e0bf6eSScott Long 					}
3177914da7d0SScott Long 					/*
3178914da7d0SScott Long 					 * If the container matched, continue
3179914da7d0SScott Long 					 * in the list.
3180914da7d0SScott Long 					 */
318136e0bf6eSScott Long 					if (found) {
318236e0bf6eSScott Long 						i++;
318336e0bf6eSScott Long 						continue;
318436e0bf6eSScott Long 					}
318536e0bf6eSScott Long 
318636e0bf6eSScott Long 					/*
3187914da7d0SScott Long 					 * This is a new container.  Do all the
318870545d1aSScott Long 					 * appropriate things to set it up.
318970545d1aSScott Long 					 */
3190cbfd045bSScott Long 					aac_add_container(sc, mir, 1);
319136e0bf6eSScott Long 					added = 1;
319236e0bf6eSScott Long 				}
319336e0bf6eSScott Long 				i++;
3194795d7dc0SScott Long 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3195cbfd045bSScott Long 			aac_release_sync_fib(sc);
319636e0bf6eSScott Long 
319736e0bf6eSScott Long 			/*
3198914da7d0SScott Long 			 * Go through our list of containers and see which ones
3199914da7d0SScott Long 			 * were not marked 'found'.  Since the controller didn't
3200914da7d0SScott Long 			 * list them they must have been deleted.  Do the
3201914da7d0SScott Long 			 * appropriate steps to destroy the device.  Also reset
3202914da7d0SScott Long 			 * the co->co_found field.
320336e0bf6eSScott Long 			 */
320436e0bf6eSScott Long 			co = TAILQ_FIRST(&sc->aac_container_tqh);
320536e0bf6eSScott Long 			while (co != NULL) {
320636e0bf6eSScott Long 				if (co->co_found == 0) {
32077cb209f5SScott Long 					mtx_unlock(&sc->aac_io_lock);
32087cb209f5SScott Long 					mtx_lock(&Giant);
3209914da7d0SScott Long 					device_delete_child(sc->aac_dev,
3210914da7d0SScott Long 							    co->co_disk);
32117cb209f5SScott Long 					mtx_unlock(&Giant);
32127cb209f5SScott Long 					mtx_lock(&sc->aac_io_lock);
321336e0bf6eSScott Long 					co_next = TAILQ_NEXT(co, co_link);
3214bb6fe253SScott Long 					mtx_lock(&sc->aac_container_lock);
3215914da7d0SScott Long 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3216914da7d0SScott Long 						     co_link);
3217bb6fe253SScott Long 					mtx_unlock(&sc->aac_container_lock);
3218ba1d57e7SScott Long 					free(co, M_AACBUF);
321936e0bf6eSScott Long 					co = co_next;
322036e0bf6eSScott Long 				} else {
322136e0bf6eSScott Long 					co->co_found = 0;
322236e0bf6eSScott Long 					co = TAILQ_NEXT(co, co_link);
322336e0bf6eSScott Long 				}
322436e0bf6eSScott Long 			}
322536e0bf6eSScott Long 
322636e0bf6eSScott Long 			/* Attach the newly created containers */
32277cb209f5SScott Long 			if (added) {
32287cb209f5SScott Long 				mtx_unlock(&sc->aac_io_lock);
32297cb209f5SScott Long 				mtx_lock(&Giant);
323036e0bf6eSScott Long 				bus_generic_attach(sc->aac_dev);
32317cb209f5SScott Long 				mtx_unlock(&Giant);
32327cb209f5SScott Long 				mtx_lock(&sc->aac_io_lock);
32337cb209f5SScott Long 			}
323436e0bf6eSScott Long 
323536e0bf6eSScott Long 			break;
323636e0bf6eSScott Long 
323736e0bf6eSScott Long 		default:
323836e0bf6eSScott Long 			break;
323936e0bf6eSScott Long 		}
324036e0bf6eSScott Long 
324136e0bf6eSScott Long 	default:
324236e0bf6eSScott Long 		break;
324336e0bf6eSScott Long 	}
324436e0bf6eSScott Long 
324536e0bf6eSScott Long 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3246bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3247a723a548SEd Maste 	current = sc->aifq_idx;
3248a723a548SEd Maste 	next = (current + 1) % AAC_AIFQ_LENGTH;
3249a723a548SEd Maste 	if (next == 0)
3250a723a548SEd Maste 		sc->aifq_filled = 1;
3251a723a548SEd Maste 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3252a723a548SEd Maste 	/* modify AIF contexts */
3253a723a548SEd Maste 	if (sc->aifq_filled) {
3254a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3255a723a548SEd Maste 			if (next == ctx->ctx_idx)
3256a723a548SEd Maste 				ctx->ctx_wrap = 1;
3257a723a548SEd Maste 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3258a723a548SEd Maste 				ctx->ctx_idx = next;
3259a723a548SEd Maste 		}
3260a723a548SEd Maste 	}
3261a723a548SEd Maste 	sc->aifq_idx = next;
3262b3457b51SScott Long 	/* On the off chance that someone is sleeping for an aif... */
326335863739SMike Smith 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
326435863739SMike Smith 		wakeup(sc->aac_aifq);
3265b3457b51SScott Long 	/* Wakeup any poll()ers */
3266512824f8SSeigo Tanimura 	selwakeuppri(&sc->rcv_select, PRIBIO);
3267bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
326836e0bf6eSScott Long 
326936e0bf6eSScott Long 	return;
327035863739SMike Smith }
327135863739SMike Smith 
3272914da7d0SScott Long /*
32730b94a66eSMike Smith  * Return the Revision of the driver to userspace and check to see if the
327436e0bf6eSScott Long  * userspace app is possibly compatible.  This is extremely bogus since
327536e0bf6eSScott Long  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
327636e0bf6eSScott Long  * returning what the card reported.
327735863739SMike Smith  */
327835863739SMike Smith static int
3279fb0c27d7SScott Long aac_rev_check(struct aac_softc *sc, caddr_t udata)
328035863739SMike Smith {
328135863739SMike Smith 	struct aac_rev_check rev_check;
328235863739SMike Smith 	struct aac_rev_check_resp rev_check_resp;
328335863739SMike Smith 	int error = 0;
328435863739SMike Smith 
328535863739SMike Smith 	debug_called(2);
328635863739SMike Smith 
328735863739SMike Smith 	/*
328835863739SMike Smith 	 * Copyin the revision struct from userspace
328935863739SMike Smith 	 */
3290c6eafcf2SScott Long 	if ((error = copyin(udata, (caddr_t)&rev_check,
3291c6eafcf2SScott Long 			sizeof(struct aac_rev_check))) != 0) {
329235863739SMike Smith 		return error;
329335863739SMike Smith 	}
329435863739SMike Smith 
3295914da7d0SScott Long 	debug(2, "Userland revision= %d\n",
3296914da7d0SScott Long 	      rev_check.callingRevision.buildNumber);
329735863739SMike Smith 
329835863739SMike Smith 	/*
329935863739SMike Smith 	 * Doctor up the response struct.
330035863739SMike Smith 	 */
330135863739SMike Smith 	rev_check_resp.possiblyCompatible = 1;
3302914da7d0SScott Long 	rev_check_resp.adapterSWRevision.external.ul =
3303914da7d0SScott Long 	    sc->aac_revision.external.ul;
3304914da7d0SScott Long 	rev_check_resp.adapterSWRevision.buildNumber =
3305914da7d0SScott Long 	    sc->aac_revision.buildNumber;
330635863739SMike Smith 
3307c6eafcf2SScott Long 	return(copyout((caddr_t)&rev_check_resp, udata,
3308c6eafcf2SScott Long 			sizeof(struct aac_rev_check_resp)));
330935863739SMike Smith }
331035863739SMike Smith 
3311914da7d0SScott Long /*
3312a723a548SEd Maste  * Pass the fib context to the caller
3313a723a548SEd Maste  */
3314a723a548SEd Maste static int
3315a723a548SEd Maste aac_open_aif(struct aac_softc *sc, caddr_t arg)
3316a723a548SEd Maste {
3317a723a548SEd Maste 	struct aac_fib_context *fibctx, *ctx;
3318a723a548SEd Maste 	int error = 0;
3319a723a548SEd Maste 
3320a723a548SEd Maste 	debug_called(2);
3321a723a548SEd Maste 
3322a723a548SEd Maste 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3323a723a548SEd Maste 	if (fibctx == NULL)
3324a723a548SEd Maste 		return (ENOMEM);
3325a723a548SEd Maste 
3326a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3327a723a548SEd Maste 	/* all elements are already 0, add to queue */
3328a723a548SEd Maste 	if (sc->fibctx == NULL)
3329a723a548SEd Maste 		sc->fibctx = fibctx;
3330a723a548SEd Maste 	else {
3331a723a548SEd Maste 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3332a723a548SEd Maste 			;
3333a723a548SEd Maste 		ctx->next = fibctx;
3334a723a548SEd Maste 		fibctx->prev = ctx;
3335a723a548SEd Maste 	}
3336a723a548SEd Maste 
3337a723a548SEd Maste 	/* evaluate unique value */
3338a723a548SEd Maste 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3339a723a548SEd Maste 	ctx = sc->fibctx;
3340a723a548SEd Maste 	while (ctx != fibctx) {
3341a723a548SEd Maste 		if (ctx->unique == fibctx->unique) {
3342a723a548SEd Maste 			fibctx->unique++;
3343a723a548SEd Maste 			ctx = sc->fibctx;
3344a723a548SEd Maste 		} else {
3345a723a548SEd Maste 			ctx = ctx->next;
3346a723a548SEd Maste 		}
3347a723a548SEd Maste 	}
3348a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3349a723a548SEd Maste 
3350a723a548SEd Maste 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3351a723a548SEd Maste 	if (error)
3352a723a548SEd Maste 		aac_close_aif(sc, (caddr_t)ctx);
3353a723a548SEd Maste 	return error;
3354a723a548SEd Maste }
3355a723a548SEd Maste 
3356a723a548SEd Maste /*
3357a723a548SEd Maste  * Close the caller's fib context
3358a723a548SEd Maste  */
3359a723a548SEd Maste static int
3360a723a548SEd Maste aac_close_aif(struct aac_softc *sc, caddr_t arg)
3361a723a548SEd Maste {
3362a723a548SEd Maste 	struct aac_fib_context *ctx;
3363a723a548SEd Maste 
3364a723a548SEd Maste 	debug_called(2);
3365a723a548SEd Maste 
3366a723a548SEd Maste 	mtx_lock(&sc->aac_aifq_lock);
3367a723a548SEd Maste 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3368a723a548SEd Maste 		if (ctx->unique == *(uint32_t *)&arg) {
3369a723a548SEd Maste 			if (ctx == sc->fibctx)
3370a723a548SEd Maste 				sc->fibctx = NULL;
3371a723a548SEd Maste 			else {
3372a723a548SEd Maste 				ctx->prev->next = ctx->next;
3373a723a548SEd Maste 				if (ctx->next)
3374a723a548SEd Maste 					ctx->next->prev = ctx->prev;
3375a723a548SEd Maste 			}
3376a723a548SEd Maste 			break;
3377a723a548SEd Maste 		}
3378a723a548SEd Maste 	}
3379a723a548SEd Maste 	mtx_unlock(&sc->aac_aifq_lock);
3380a723a548SEd Maste 	if (ctx)
3381a723a548SEd Maste 		free(ctx, M_AACBUF);
3382a723a548SEd Maste 
3383a723a548SEd Maste 	return 0;
3384a723a548SEd Maste }
3385a723a548SEd Maste 
3386a723a548SEd Maste /*
338735863739SMike Smith  * Pass the caller the next AIF in their queue
338835863739SMike Smith  */
338935863739SMike Smith static int
3390fb0c27d7SScott Long aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
339135863739SMike Smith {
339235863739SMike Smith 	struct get_adapter_fib_ioctl agf;
3393a723a548SEd Maste 	struct aac_fib_context *ctx;
33949e2e96d8SScott Long 	int error;
339535863739SMike Smith 
339635863739SMike Smith 	debug_called(2);
339735863739SMike Smith 
339835863739SMike Smith 	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3399a723a548SEd Maste 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3400a723a548SEd Maste 			if (agf.AdapterFibContext == ctx->unique)
3401a723a548SEd Maste 				break;
3402a723a548SEd Maste 		}
3403a723a548SEd Maste 		if (!ctx)
3404a723a548SEd Maste 			return (EFAULT);
340535863739SMike Smith 
3406a723a548SEd Maste 		error = aac_return_aif(sc, ctx, agf.AifFib);
3407a723a548SEd Maste 		if (error == EAGAIN && agf.Wait) {
3408a723a548SEd Maste 			debug(2, "aac_getnext_aif(): waiting for AIF");
340935863739SMike Smith 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
341035863739SMike Smith 			while (error == EAGAIN) {
3411914da7d0SScott Long 				error = tsleep(sc->aac_aifq, PRIBIO |
3412914da7d0SScott Long 					       PCATCH, "aacaif", 0);
341335863739SMike Smith 				if (error == 0)
3414a723a548SEd Maste 					error = aac_return_aif(sc, ctx, agf.AifFib);
341535863739SMike Smith 			}
341635863739SMike Smith 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
341735863739SMike Smith 		}
341835863739SMike Smith 	}
341935863739SMike Smith 	return(error);
342035863739SMike Smith }
342135863739SMike Smith 
3422914da7d0SScott Long /*
34230b94a66eSMike Smith  * Hand the next AIF off the top of the queue out to userspace.
34240b94a66eSMike Smith  */
34250b94a66eSMike Smith static int
3426a723a548SEd Maste aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
34270b94a66eSMike Smith {
3428a723a548SEd Maste 	int current, error;
34290b94a66eSMike Smith 
34300b94a66eSMike Smith 	debug_called(2);
34310b94a66eSMike Smith 
3432bb6fe253SScott Long 	mtx_lock(&sc->aac_aifq_lock);
3433a723a548SEd Maste 	current = ctx->ctx_idx;
3434a723a548SEd Maste 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3435a723a548SEd Maste 		/* empty */
3436bb6fe253SScott Long 		mtx_unlock(&sc->aac_aifq_lock);
34373df780cfSScott Long 		return (EAGAIN);
34383df780cfSScott Long 	}
3439a723a548SEd Maste 	error =
3440a723a548SEd Maste 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
344136e0bf6eSScott Long 	if (error)
344270545d1aSScott Long 		device_printf(sc->aac_dev,
344370545d1aSScott Long 		    "aac_return_aif: copyout returned %d\n", error);
3444a723a548SEd Maste 	else {
3445a723a548SEd Maste 		ctx->ctx_wrap = 0;
3446a723a548SEd Maste 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3447a723a548SEd Maste 	}
3448bb6fe253SScott Long 	mtx_unlock(&sc->aac_aifq_lock);
34490b94a66eSMike Smith 	return(error);
34500b94a66eSMike Smith }
345136e0bf6eSScott Long 
34527cb209f5SScott Long static int
34537cb209f5SScott Long aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
34547cb209f5SScott Long {
34557cb209f5SScott Long 	struct aac_pci_info {
34567cb209f5SScott Long 		u_int32_t bus;
34577cb209f5SScott Long 		u_int32_t slot;
34587cb209f5SScott Long 	} pciinf;
34597cb209f5SScott Long 	int error;
34607cb209f5SScott Long 
34617cb209f5SScott Long 	debug_called(2);
34627cb209f5SScott Long 
34637cb209f5SScott Long 	pciinf.bus = pci_get_bus(sc->aac_dev);
34647cb209f5SScott Long 	pciinf.slot = pci_get_slot(sc->aac_dev);
34657cb209f5SScott Long 
34667cb209f5SScott Long 	error = copyout((caddr_t)&pciinf, uptr,
34677cb209f5SScott Long 			sizeof(struct aac_pci_info));
34687cb209f5SScott Long 
34697cb209f5SScott Long 	return (error);
34707cb209f5SScott Long }
34717cb209f5SScott Long 
3472914da7d0SScott Long /*
347336e0bf6eSScott Long  * Give the userland some information about the container.  The AAC arch
347436e0bf6eSScott Long  * expects the driver to be a SCSI passthrough type driver, so it expects
347536e0bf6eSScott Long  * the containers to have b:t:l numbers.  Fake it.
347636e0bf6eSScott Long  */
347736e0bf6eSScott Long static int
347836e0bf6eSScott Long aac_query_disk(struct aac_softc *sc, caddr_t uptr)
347936e0bf6eSScott Long {
348036e0bf6eSScott Long 	struct aac_query_disk query_disk;
348136e0bf6eSScott Long 	struct aac_container *co;
3482914da7d0SScott Long 	struct aac_disk	*disk;
348336e0bf6eSScott Long 	int error, id;
348436e0bf6eSScott Long 
348536e0bf6eSScott Long 	debug_called(2);
348636e0bf6eSScott Long 
3487914da7d0SScott Long 	disk = NULL;
3488914da7d0SScott Long 
3489914da7d0SScott Long 	error = copyin(uptr, (caddr_t)&query_disk,
3490914da7d0SScott Long 		       sizeof(struct aac_query_disk));
349136e0bf6eSScott Long 	if (error)
349236e0bf6eSScott Long 		return (error);
349336e0bf6eSScott Long 
349436e0bf6eSScott Long 	id = query_disk.ContainerNumber;
349536e0bf6eSScott Long 	if (id == -1)
349636e0bf6eSScott Long 		return (EINVAL);
349736e0bf6eSScott Long 
3498bb6fe253SScott Long 	mtx_lock(&sc->aac_container_lock);
349936e0bf6eSScott Long 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
350036e0bf6eSScott Long 		if (co->co_mntobj.ObjectId == id)
350136e0bf6eSScott Long 			break;
350236e0bf6eSScott Long 		}
350336e0bf6eSScott Long 
350436e0bf6eSScott Long 	if (co == NULL) {
350536e0bf6eSScott Long 			query_disk.Valid = 0;
350636e0bf6eSScott Long 			query_disk.Locked = 0;
350736e0bf6eSScott Long 			query_disk.Deleted = 1;		/* XXX is this right? */
350836e0bf6eSScott Long 	} else {
350936e0bf6eSScott Long 		disk = device_get_softc(co->co_disk);
351036e0bf6eSScott Long 		query_disk.Valid = 1;
3511914da7d0SScott Long 		query_disk.Locked =
3512914da7d0SScott Long 		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
351336e0bf6eSScott Long 		query_disk.Deleted = 0;
3514b3457b51SScott Long 		query_disk.Bus = device_get_unit(sc->aac_dev);
351536e0bf6eSScott Long 		query_disk.Target = disk->unit;
351636e0bf6eSScott Long 		query_disk.Lun = 0;
351736e0bf6eSScott Long 		query_disk.UnMapped = 0;
35187540e65eSScott Long 		sprintf(&query_disk.diskDeviceName[0], "%s%d",
35190b7ed341SPoul-Henning Kamp 		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
352036e0bf6eSScott Long 	}
3521bb6fe253SScott Long 	mtx_unlock(&sc->aac_container_lock);
352236e0bf6eSScott Long 
3523914da7d0SScott Long 	error = copyout((caddr_t)&query_disk, uptr,
3524914da7d0SScott Long 			sizeof(struct aac_query_disk));
352536e0bf6eSScott Long 
352636e0bf6eSScott Long 	return (error);
352736e0bf6eSScott Long }
352836e0bf6eSScott Long 
3529fe3cb0e1SScott Long static void
3530fe3cb0e1SScott Long aac_get_bus_info(struct aac_softc *sc)
3531fe3cb0e1SScott Long {
3532fe3cb0e1SScott Long 	struct aac_fib *fib;
3533fe3cb0e1SScott Long 	struct aac_ctcfg *c_cmd;
3534fe3cb0e1SScott Long 	struct aac_ctcfg_resp *c_resp;
3535fe3cb0e1SScott Long 	struct aac_vmioctl *vmi;
3536fe3cb0e1SScott Long 	struct aac_vmi_businf_resp *vmi_resp;
3537fe3cb0e1SScott Long 	struct aac_getbusinf businfo;
353870545d1aSScott Long 	struct aac_sim *caminf;
3539fe3cb0e1SScott Long 	device_t child;
3540fe3cb0e1SScott Long 	int i, found, error;
3541fe3cb0e1SScott Long 
35421ffe41c1SChristian S.J. Peron 	mtx_lock(&sc->aac_io_lock);
354303b5fe51SScott Long 	aac_alloc_sync_fib(sc, &fib);
3544fe3cb0e1SScott Long 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
354539ee03c3SScott Long 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3546fe3cb0e1SScott Long 
3547fe3cb0e1SScott Long 	c_cmd->Command = VM_ContainerConfig;
3548fe3cb0e1SScott Long 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3549fe3cb0e1SScott Long 	c_cmd->param = 0;
3550fe3cb0e1SScott Long 
3551fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3552fe3cb0e1SScott Long 	    sizeof(struct aac_ctcfg));
3553fe3cb0e1SScott Long 	if (error) {
3554fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending "
3555fe3cb0e1SScott Long 		    "VM_ContainerConfig command\n", error);
3556fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35571ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3558fe3cb0e1SScott Long 		return;
3559fe3cb0e1SScott Long 	}
3560fe3cb0e1SScott Long 
3561fe3cb0e1SScott Long 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3562fe3cb0e1SScott Long 	if (c_resp->Status != ST_OK) {
3563fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3564fe3cb0e1SScott Long 		    c_resp->Status);
3565fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35661ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3567fe3cb0e1SScott Long 		return;
3568fe3cb0e1SScott Long 	}
3569fe3cb0e1SScott Long 
3570fe3cb0e1SScott Long 	sc->scsi_method_id = c_resp->param;
3571fe3cb0e1SScott Long 
3572fe3cb0e1SScott Long 	vmi = (struct aac_vmioctl *)&fib->data[0];
357339ee03c3SScott Long 	bzero(vmi, sizeof(struct aac_vmioctl));
357439ee03c3SScott Long 
3575fe3cb0e1SScott Long 	vmi->Command = VM_Ioctl;
3576fe3cb0e1SScott Long 	vmi->ObjType = FT_DRIVE;
3577fe3cb0e1SScott Long 	vmi->MethId = sc->scsi_method_id;
3578fe3cb0e1SScott Long 	vmi->ObjId = 0;
3579fe3cb0e1SScott Long 	vmi->IoctlCmd = GetBusInfo;
3580fe3cb0e1SScott Long 
3581fe3cb0e1SScott Long 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
358242ef13a2SEd Maste 	    sizeof(struct aac_vmi_businf_resp));
3583fe3cb0e1SScott Long 	if (error) {
3584fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3585fe3cb0e1SScott Long 		    error);
3586fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35871ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3588fe3cb0e1SScott Long 		return;
3589fe3cb0e1SScott Long 	}
3590fe3cb0e1SScott Long 
3591fe3cb0e1SScott Long 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3592fe3cb0e1SScott Long 	if (vmi_resp->Status != ST_OK) {
3593fe3cb0e1SScott Long 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3594fe3cb0e1SScott Long 		    vmi_resp->Status);
3595fe3cb0e1SScott Long 		aac_release_sync_fib(sc);
35961ffe41c1SChristian S.J. Peron 		mtx_unlock(&sc->aac_io_lock);
3597fe3cb0e1SScott Long 		return;
3598fe3cb0e1SScott Long 	}
3599fe3cb0e1SScott Long 
3600fe3cb0e1SScott Long 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3601fe3cb0e1SScott Long 	aac_release_sync_fib(sc);
36021ffe41c1SChristian S.J. Peron 	mtx_unlock(&sc->aac_io_lock);
3603fe3cb0e1SScott Long 
3604fe3cb0e1SScott Long 	found = 0;
3605fe3cb0e1SScott Long 	for (i = 0; i < businfo.BusCount; i++) {
3606fe3cb0e1SScott Long 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3607fe3cb0e1SScott Long 			continue;
3608fe3cb0e1SScott Long 
3609a761a1caSScott Long 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3610a761a1caSScott Long 		    M_AACBUF, M_NOWAIT | M_ZERO);
3611b5f516cdSScott Long 		if (caminf == NULL) {
3612b5f516cdSScott Long 			device_printf(sc->aac_dev,
3613b5f516cdSScott Long 			    "No memory to add passthrough bus %d\n", i);
3614b5f516cdSScott Long 			break;
36157cb209f5SScott Long 		};
3616fe3cb0e1SScott Long 
3617fe3cb0e1SScott Long 		child = device_add_child(sc->aac_dev, "aacp", -1);
3618fe3cb0e1SScott Long 		if (child == NULL) {
3619b5f516cdSScott Long 			device_printf(sc->aac_dev,
3620b5f516cdSScott Long 			    "device_add_child failed for passthrough bus %d\n",
3621b5f516cdSScott Long 			    i);
3622b5f516cdSScott Long 			free(caminf, M_AACBUF);
3623b5f516cdSScott Long 			break;
3624fe3cb0e1SScott Long 		}
3625fe3cb0e1SScott Long 
3626fe3cb0e1SScott Long 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3627fe3cb0e1SScott Long 		caminf->BusNumber = i;
3628fe3cb0e1SScott Long 		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3629fe3cb0e1SScott Long 		caminf->aac_sc = sc;
3630ddb8683eSScott Long 		caminf->sim_dev = child;
3631fe3cb0e1SScott Long 
3632fe3cb0e1SScott Long 		device_set_ivars(child, caminf);
3633fe3cb0e1SScott Long 		device_set_desc(child, "SCSI Passthrough Bus");
363470545d1aSScott Long 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3635fe3cb0e1SScott Long 
3636fe3cb0e1SScott Long 		found = 1;
3637fe3cb0e1SScott Long 	}
3638fe3cb0e1SScott Long 
3639fe3cb0e1SScott Long 	if (found)
3640fe3cb0e1SScott Long 		bus_generic_attach(sc->aac_dev);
3641fe3cb0e1SScott Long 
3642fe3cb0e1SScott Long 	return;
3643fe3cb0e1SScott Long }
3644