aac.c revision 151330
165793Smsmith/*-
265793Smsmith * Copyright (c) 2000 Michael Smith
381082Sscottl * Copyright (c) 2001 Scott Long
465793Smsmith * Copyright (c) 2000 BSDi
581082Sscottl * Copyright (c) 2001 Adaptec, Inc.
665793Smsmith * All rights reserved.
765793Smsmith *
865793Smsmith * Redistribution and use in source and binary forms, with or without
965793Smsmith * modification, are permitted provided that the following conditions
1065793Smsmith * are met:
1165793Smsmith * 1. Redistributions of source code must retain the above copyright
1265793Smsmith *    notice, this list of conditions and the following disclaimer.
1365793Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1465793Smsmith *    notice, this list of conditions and the following disclaimer in the
1565793Smsmith *    documentation and/or other materials provided with the distribution.
1665793Smsmith *
1765793Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1865793Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965793Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2065793Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2165793Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2265793Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2365793Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2465793Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2565793Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2665793Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2765793Smsmith * SUCH DAMAGE.
2865793Smsmith */
2965793Smsmith
30119418Sobrien#include <sys/cdefs.h>
31119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aac/aac.c 151330 2005-10-14 16:22:45Z scottl $");
32119418Sobrien
3365793Smsmith/*
3465793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3565793Smsmith */
36151086Sscottl#define AAC_DRIVER_VERSION		0x02000000
37151086Sscottl#define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
38151086Sscottl#define AAC_DRIVERNAME			"aac"
3965793Smsmith
4081151Sscottl#include "opt_aac.h"
4181151Sscottl
4282527Sscottl/* #include <stddef.h> */
4365793Smsmith#include <sys/param.h>
4465793Smsmith#include <sys/systm.h>
4565793Smsmith#include <sys/malloc.h>
4665793Smsmith#include <sys/kernel.h>
4782527Sscottl#include <sys/kthread.h>
4881154Sscottl#include <sys/sysctl.h>
4987183Sscottl#include <sys/poll.h>
50112946Sphk#include <sys/ioccom.h>
5165793Smsmith
5265793Smsmith#include <sys/bus.h>
5365793Smsmith#include <sys/conf.h>
5465793Smsmith#include <sys/signalvar.h>
5570393Smsmith#include <sys/time.h>
5682527Sscottl#include <sys/eventhandler.h>
57151086Sscottl#include <sys/rman.h>
5865793Smsmith
5965793Smsmith#include <machine/bus.h>
60143838Sscottl#include <sys/bus_dma.h>
6165793Smsmith#include <machine/resource.h>
6265793Smsmith
63151086Sscottl#include <dev/pci/pcireg.h>
64151086Sscottl#include <dev/pci/pcivar.h>
65151086Sscottl
6665793Smsmith#include <dev/aac/aacreg.h>
67138635Sscottl#include <sys/aac_ioctl.h>
6865793Smsmith#include <dev/aac/aacvar.h>
6965793Smsmith#include <dev/aac/aac_tables.h>
7065793Smsmith
7165793Smsmithstatic void	aac_startup(void *arg);
7283114Sscottlstatic void	aac_add_container(struct aac_softc *sc,
7395350Sscottl				  struct aac_mntinforesp *mir, int f);
7495536Sscottlstatic void	aac_get_bus_info(struct aac_softc *sc);
7565793Smsmith
7665793Smsmith/* Command Processing */
7770393Smsmithstatic void	aac_timeout(struct aac_softc *sc);
7865793Smsmithstatic void	aac_complete(void *context, int pending);
7965793Smsmithstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
8065793Smsmithstatic void	aac_bio_complete(struct aac_command *cm);
81128258Sscottlstatic int	aac_wait_command(struct aac_command *cm);
82110426Sscottlstatic void	aac_command_thread(struct aac_softc *sc);
8365793Smsmith
8465793Smsmith/* Command Buffer Management */
85117363Sscottlstatic void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
86117363Sscottl				   int nseg, int error);
8781082Sscottlstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
8881082Sscottl				       int nseg, int error);
8970393Smsmithstatic int	aac_alloc_commands(struct aac_softc *sc);
90111141Sscottlstatic void	aac_free_commands(struct aac_softc *sc);
9165793Smsmithstatic void	aac_unmap_command(struct aac_command *cm);
9265793Smsmith
9365793Smsmith/* Hardware Interface */
9481082Sscottlstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
9581082Sscottl			       int error);
9690275Sscottlstatic int	aac_check_firmware(struct aac_softc *sc);
9765793Smsmithstatic int	aac_init(struct aac_softc *sc);
9865793Smsmithstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
9981082Sscottl				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
10081082Sscottl				 u_int32_t arg3, u_int32_t *sp);
10181082Sscottlstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
10281151Sscottl				struct aac_command *cm);
10381082Sscottlstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
10483114Sscottl				u_int32_t *fib_size, struct aac_fib **fib_addr);
10582527Sscottlstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
10682527Sscottl				     struct aac_fib *fib);
10765793Smsmith
10887183Sscottl/* Falcon/PPC interface */
10987183Sscottlstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
11087183Sscottlstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
11187183Sscottlstatic int	aac_fa_get_istatus(struct aac_softc *sc);
11287183Sscottlstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
11387183Sscottlstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
11487183Sscottl				   u_int32_t arg0, u_int32_t arg1,
11587183Sscottl				   u_int32_t arg2, u_int32_t arg3);
116112679Sscottlstatic int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
11787183Sscottlstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
11887183Sscottl
11987183Sscottlstruct aac_interface aac_fa_interface = {
12087183Sscottl	aac_fa_get_fwstatus,
12187183Sscottl	aac_fa_qnotify,
12287183Sscottl	aac_fa_get_istatus,
12387183Sscottl	aac_fa_clear_istatus,
12487183Sscottl	aac_fa_set_mailbox,
125112679Sscottl	aac_fa_get_mailbox,
126151086Sscottl	aac_fa_set_interrupts,
127151086Sscottl	NULL, NULL, NULL
12887183Sscottl};
12987183Sscottl
13065793Smsmith/* StrongARM interface */
13165793Smsmithstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
13265793Smsmithstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13365793Smsmithstatic int	aac_sa_get_istatus(struct aac_softc *sc);
13465793Smsmithstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13565793Smsmithstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
13681082Sscottl				   u_int32_t arg0, u_int32_t arg1,
13781082Sscottl				   u_int32_t arg2, u_int32_t arg3);
138112679Sscottlstatic int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13965793Smsmithstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
14065793Smsmith
14165793Smsmithstruct aac_interface aac_sa_interface = {
14283114Sscottl	aac_sa_get_fwstatus,
14383114Sscottl	aac_sa_qnotify,
14483114Sscottl	aac_sa_get_istatus,
14583114Sscottl	aac_sa_clear_istatus,
14683114Sscottl	aac_sa_set_mailbox,
147112679Sscottl	aac_sa_get_mailbox,
148151086Sscottl	aac_sa_set_interrupts,
149151086Sscottl	NULL, NULL, NULL
15065793Smsmith};
15165793Smsmith
15283114Sscottl/* i960Rx interface */
15365793Smsmithstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
15465793Smsmithstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15565793Smsmithstatic int	aac_rx_get_istatus(struct aac_softc *sc);
15665793Smsmithstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15765793Smsmithstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
15881082Sscottl				   u_int32_t arg0, u_int32_t arg1,
15981082Sscottl				   u_int32_t arg2, u_int32_t arg3);
160112679Sscottlstatic int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16165793Smsmithstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
162151086Sscottlstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
163151086Sscottlstatic int aac_rx_get_outb_queue(struct aac_softc *sc);
164151086Sscottlstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16565793Smsmith
16665793Smsmithstruct aac_interface aac_rx_interface = {
16783114Sscottl	aac_rx_get_fwstatus,
16883114Sscottl	aac_rx_qnotify,
16983114Sscottl	aac_rx_get_istatus,
17083114Sscottl	aac_rx_clear_istatus,
17183114Sscottl	aac_rx_set_mailbox,
172112679Sscottl	aac_rx_get_mailbox,
173151086Sscottl	aac_rx_set_interrupts,
174151086Sscottl	aac_rx_send_command,
175151086Sscottl	aac_rx_get_outb_queue,
176151086Sscottl	aac_rx_set_outb_queue
17765793Smsmith};
17865793Smsmith
179133606Sscottl/* Rocket/MIPS interface */
180133606Sscottlstatic int	aac_rkt_get_fwstatus(struct aac_softc *sc);
181133606Sscottlstatic void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
182133606Sscottlstatic int	aac_rkt_get_istatus(struct aac_softc *sc);
183133606Sscottlstatic void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
184133606Sscottlstatic void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
185133606Sscottl				    u_int32_t arg0, u_int32_t arg1,
186133606Sscottl				    u_int32_t arg2, u_int32_t arg3);
187133606Sscottlstatic int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
188133606Sscottlstatic void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
189151086Sscottlstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
190151086Sscottlstatic int aac_rkt_get_outb_queue(struct aac_softc *sc);
191151086Sscottlstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
192133606Sscottl
193133606Sscottlstruct aac_interface aac_rkt_interface = {
194133606Sscottl	aac_rkt_get_fwstatus,
195133606Sscottl	aac_rkt_qnotify,
196133606Sscottl	aac_rkt_get_istatus,
197133606Sscottl	aac_rkt_clear_istatus,
198133606Sscottl	aac_rkt_set_mailbox,
199133606Sscottl	aac_rkt_get_mailbox,
200151086Sscottl	aac_rkt_set_interrupts,
201151086Sscottl	aac_rkt_send_command,
202151086Sscottl	aac_rkt_get_outb_queue,
203151086Sscottl	aac_rkt_set_outb_queue
204133606Sscottl};
205133606Sscottl
20665793Smsmith/* Debugging and Diagnostics */
20765793Smsmithstatic void	aac_describe_controller(struct aac_softc *sc);
20882567Sscottlstatic char	*aac_describe_code(struct aac_code_lookup *table,
20981082Sscottl				   u_int32_t code);
21065793Smsmith
21165793Smsmith/* Management Interface */
21265793Smsmithstatic d_open_t		aac_open;
21365793Smsmithstatic d_close_t	aac_close;
21465793Smsmithstatic d_ioctl_t	aac_ioctl;
21587183Sscottlstatic d_poll_t		aac_poll;
21681082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
21781082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
21883114Sscottl					   struct aac_fib *fib);
21981189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
22081189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
22181189Sscottlstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
22282527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
223151086Sscottlstatic int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
224151086Sscottlstatic void		aac_ioctl_event(struct aac_softc *sc,
225151086Sscottl				        struct aac_event *event, void *arg);
22665793Smsmith
22765793Smsmithstatic struct cdevsw aac_cdevsw = {
228126080Sphk	.d_version =	D_VERSION,
229126080Sphk	.d_flags =	D_NEEDGIANT,
230111815Sphk	.d_open =	aac_open,
231111815Sphk	.d_close =	aac_close,
232111815Sphk	.d_ioctl =	aac_ioctl,
233111815Sphk	.d_poll =	aac_poll,
234111815Sphk	.d_name =	"aac",
23565793Smsmith};
23665793Smsmith
23782527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
23882527Sscottl
23981154Sscottl/* sysctl node */
24081154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
24181154Sscottl
24283114Sscottl/*
24383114Sscottl * Device Interface
24483114Sscottl */
24565793Smsmith
24683114Sscottl/*
24765793Smsmith * Initialise the controller and softc
24865793Smsmith */
24965793Smsmithint
25065793Smsmithaac_attach(struct aac_softc *sc)
25165793Smsmith{
25283114Sscottl	int error, unit;
25365793Smsmith
25483114Sscottl	debug_called(1);
25565793Smsmith
25683114Sscottl	/*
25783114Sscottl	 * Initialise per-controller queues.
25883114Sscottl	 */
25983114Sscottl	aac_initq_free(sc);
26083114Sscottl	aac_initq_ready(sc);
26183114Sscottl	aac_initq_busy(sc);
26283114Sscottl	aac_initq_bio(sc);
26365793Smsmith
26483114Sscottl	/*
26583114Sscottl	 * Initialise command-completion task.
26683114Sscottl	 */
26783114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
26865793Smsmith
26983114Sscottl	/* mark controller as suspended until we get ourselves organised */
27083114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
27165793Smsmith
27283114Sscottl	/*
27390275Sscottl	 * Check that the firmware on the card is supported.
27490275Sscottl	 */
27590275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
27690275Sscottl		return(error);
27790275Sscottl
278117126Sscottl	/*
279117126Sscottl	 * Initialize locks
280117126Sscottl	 */
281133540Sscottl	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
282133540Sscottl	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
283133540Sscottl	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
284117126Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
28595350Sscottl
286121173Sscottl	/* Initialize the local AIF queue pointers */
287121173Sscottl	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
288117126Sscottl
28983114Sscottl	/*
29083114Sscottl	 * Initialise the adapter.
29183114Sscottl	 */
29283114Sscottl	if ((error = aac_init(sc)) != 0)
29383114Sscottl		return(error);
29465793Smsmith
29583114Sscottl	/*
296151086Sscottl	 * Allocate and connect our interrupt.
297151086Sscottl	 */
298151086Sscottl	sc->aac_irq_rid = 0;
299151086Sscottl	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
300151086Sscottl			   			  &sc->aac_irq_rid,
301151086Sscottl			   			  RF_SHAREABLE |
302151086Sscottl						  RF_ACTIVE)) == NULL) {
303151086Sscottl		device_printf(sc->aac_dev, "can't allocate interrupt\n");
304151086Sscottl		return (EINVAL);
305151086Sscottl	}
306151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
307151086Sscottl		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
308151086Sscottl				   INTR_MPSAFE|INTR_TYPE_BIO, aac_new_intr,
309151086Sscottl				   sc, &sc->aac_intr)) {
310151086Sscottl			device_printf(sc->aac_dev, "can't set up interrupt\n");
311151086Sscottl			return (EINVAL);
312151086Sscottl		}
313151086Sscottl	} else {
314151086Sscottl		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
315151086Sscottl				   INTR_FAST|INTR_TYPE_BIO, aac_fast_intr,
316151086Sscottl				   sc, &sc->aac_intr)) {
317151086Sscottl			device_printf(sc->aac_dev,
318151086Sscottl				      "can't set up FAST interrupt\n");
319151086Sscottl			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
320151086Sscottl					   INTR_MPSAFE|INTR_TYPE_BIO,
321151086Sscottl					   aac_fast_intr, sc, &sc->aac_intr)) {
322151086Sscottl				device_printf(sc->aac_dev,
323151086Sscottl					     "can't set up MPSAFE interrupt\n");
324151086Sscottl				return (EINVAL);
325151086Sscottl			}
326151086Sscottl		}
327151086Sscottl	}
328151086Sscottl
329151086Sscottl	/*
33083114Sscottl	 * Print a little information about the controller.
33183114Sscottl	 */
33283114Sscottl	aac_describe_controller(sc);
33365793Smsmith
33483114Sscottl	/*
335111532Sscottl	 * Register to probe our containers later.
33687183Sscottl	 */
33783114Sscottl	sc->aac_ich.ich_func = aac_startup;
33883114Sscottl	sc->aac_ich.ich_arg = sc;
33983114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
34083114Sscottl		device_printf(sc->aac_dev,
34183114Sscottl			      "can't establish configuration hook\n");
34283114Sscottl		return(ENXIO);
34383114Sscottl	}
34465793Smsmith
34583114Sscottl	/*
34683114Sscottl	 * Make the control device.
34783114Sscottl	 */
34883114Sscottl	unit = device_get_unit(sc->aac_dev);
349108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
350108329Srwatson				 0640, "aac%d", unit);
35183114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
35283114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
35383114Sscottl	sc->aac_dev_t->si_drv1 = sc;
35465793Smsmith
35583114Sscottl	/* Create the AIF thread */
356110426Sscottl	if (kthread_create((void(*)(void *))aac_command_thread, sc,
357151086Sscottl		   &sc->aifthread, 0, 0, "aac%daif", unit))
35883114Sscottl		panic("Could not create AIF thread\n");
35982527Sscottl
36083114Sscottl	/* Register the shutdown method to only be called post-dump */
361110427Sscottl	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
362110427Sscottl	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
363110427Sscottl		device_printf(sc->aac_dev,
364110427Sscottl			      "shutdown event registration failed\n");
36582527Sscottl
36695536Sscottl	/* Register with CAM for the non-DASD devices */
367112679Sscottl	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
368110426Sscottl		TAILQ_INIT(&sc->aac_sim_tqh);
36995536Sscottl		aac_get_bus_info(sc);
370110426Sscottl	}
37195536Sscottl
37283114Sscottl	return(0);
37365793Smsmith}
37465793Smsmith
375151086Sscottlvoid
376151086Sscottlaac_add_event(struct aac_softc *sc, struct aac_event *event)
377151086Sscottl{
378151086Sscottl
379151086Sscottl	switch (event->ev_type & AAC_EVENT_MASK) {
380151086Sscottl	case AAC_EVENT_CMFREE:
381151086Sscottl		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
382151086Sscottl		break;
383151086Sscottl	default:
384151086Sscottl		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
385151086Sscottl		    event->ev_type);
386151086Sscottl		break;
387151086Sscottl	}
388151086Sscottl
389151086Sscottl	return;
390151086Sscottl}
391151086Sscottl
39283114Sscottl/*
39365793Smsmith * Probe for containers, create disks.
39465793Smsmith */
39565793Smsmithstatic void
39665793Smsmithaac_startup(void *arg)
39765793Smsmith{
39883114Sscottl	struct aac_softc *sc;
39995350Sscottl	struct aac_fib *fib;
40095350Sscottl	struct aac_mntinfo *mi;
40195350Sscottl	struct aac_mntinforesp *mir = NULL;
402115760Sscottl	int count = 0, i = 0;
40365793Smsmith
40483114Sscottl	debug_called(1);
40565793Smsmith
40683114Sscottl	sc = (struct aac_softc *)arg;
40765793Smsmith
40883114Sscottl	/* disconnect ourselves from the intrhook chain */
40983114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
41065793Smsmith
411151086Sscottl	mtx_lock(&sc->aac_io_lock);
412130006Sscottl	aac_alloc_sync_fib(sc, &fib);
41395350Sscottl	mi = (struct aac_mntinfo *)&fib->data[0];
41495350Sscottl
41583114Sscottl	/* loop over possible containers */
41683114Sscottl	do {
41783114Sscottl		/* request information on this container */
41895966Sscottl		bzero(mi, sizeof(struct aac_mntinfo));
41995966Sscottl		mi->Command = VM_NameServe;
42095966Sscottl		mi->MntType = FT_FILESYS;
42195350Sscottl		mi->MntCount = i;
42295350Sscottl		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
42395350Sscottl				 sizeof(struct aac_mntinfo))) {
424115760Sscottl			printf("error probing container %d", i);
42583114Sscottl			continue;
42683114Sscottl		}
42765793Smsmith
42895350Sscottl		mir = (struct aac_mntinforesp *)&fib->data[0];
429115760Sscottl		/* XXX Need to check if count changed */
430115760Sscottl		count = mir->MntRespCount;
43195350Sscottl		aac_add_container(sc, mir, 0);
43283114Sscottl		i++;
433115760Sscottl	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
43465793Smsmith
43595350Sscottl	aac_release_sync_fib(sc);
436151086Sscottl	mtx_unlock(&sc->aac_io_lock);
43795350Sscottl
43883114Sscottl	/* poke the bus to actually attach the child devices */
43983114Sscottl	if (bus_generic_attach(sc->aac_dev))
44083114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
44165793Smsmith
44283114Sscottl	/* mark the controller up */
44383114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
44470393Smsmith
44583114Sscottl	/* enable interrupts now */
44683114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
44765793Smsmith}
44865793Smsmith
44983114Sscottl/*
45083114Sscottl * Create a device to respresent a new container
45183114Sscottl */
45283114Sscottlstatic void
45395350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
45483114Sscottl{
45583114Sscottl	struct aac_container *co;
45683114Sscottl	device_t child;
45783114Sscottl
45883114Sscottl	/*
45983114Sscottl	 * Check container volume type for validity.  Note that many of
46083114Sscottl	 * the possible types may never show up.
46183114Sscottl	 */
46283114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
463110428Sscottl		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
464110428Sscottl		       M_NOWAIT | M_ZERO);
46583114Sscottl		if (co == NULL)
46683114Sscottl			panic("Out of memory?!\n");
46783114Sscottl		debug(1, "id %x  name '%.16s'  size %u  type %d",
46883114Sscottl		      mir->MntTable[0].ObjectId,
46983114Sscottl		      mir->MntTable[0].FileSystemName,
47083114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
47183114Sscottl
47295536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
47383114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
47483114Sscottl		else
47583114Sscottl			device_set_ivars(child, co);
47683114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
47783114Sscottl				mir->MntTable[0].VolType));
47883114Sscottl		co->co_disk = child;
47983114Sscottl		co->co_found = f;
48083114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
48183114Sscottl		      sizeof(struct aac_mntobj));
482133540Sscottl		mtx_lock(&sc->aac_container_lock);
48383114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
484133540Sscottl		mtx_unlock(&sc->aac_container_lock);
48583114Sscottl	}
48683114Sscottl}
48783114Sscottl
48883114Sscottl/*
48965793Smsmith * Free all of the resources associated with (sc)
49065793Smsmith *
49165793Smsmith * Should not be called if the controller is active.
49265793Smsmith */
49365793Smsmithvoid
49465793Smsmithaac_free(struct aac_softc *sc)
49565793Smsmith{
496110604Sscottl
49783114Sscottl	debug_called(1);
49865793Smsmith
49983114Sscottl	/* remove the control device */
50083114Sscottl	if (sc->aac_dev_t != NULL)
50183114Sscottl		destroy_dev(sc->aac_dev_t);
50265793Smsmith
50383114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
504111141Sscottl	aac_free_commands(sc);
50583114Sscottl	if (sc->aac_fib_dmat)
50683114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
50765793Smsmith
508110604Sscottl	free(sc->aac_commands, M_AACBUF);
509110604Sscottl
51083114Sscottl	/* destroy the common area */
51183114Sscottl	if (sc->aac_common) {
51283114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
51383114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
51483114Sscottl				sc->aac_common_dmamap);
51583114Sscottl	}
51683114Sscottl	if (sc->aac_common_dmat)
51783114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
51865793Smsmith
51983114Sscottl	/* disconnect the interrupt handler */
52083114Sscottl	if (sc->aac_intr)
52183114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
52283114Sscottl	if (sc->aac_irq != NULL)
52383114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
52483114Sscottl				     sc->aac_irq);
52565793Smsmith
52683114Sscottl	/* destroy data-transfer DMA tag */
52783114Sscottl	if (sc->aac_buffer_dmat)
52883114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
52965793Smsmith
53083114Sscottl	/* destroy the parent DMA tag */
53183114Sscottl	if (sc->aac_parent_dmat)
53283114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
53365793Smsmith
53483114Sscottl	/* release the register window mapping */
53583114Sscottl	if (sc->aac_regs_resource != NULL)
53683114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
53783114Sscottl				     sc->aac_regs_rid, sc->aac_regs_resource);
53865793Smsmith}
53965793Smsmith
54083114Sscottl/*
54165793Smsmith * Disconnect from the controller completely, in preparation for unload.
54265793Smsmith */
54365793Smsmithint
54465793Smsmithaac_detach(device_t dev)
54565793Smsmith{
54683114Sscottl	struct aac_softc *sc;
547110426Sscottl	struct aac_container *co;
548110426Sscottl	struct aac_sim	*sim;
54983114Sscottl	int error;
55065793Smsmith
55183114Sscottl	debug_called(1);
55265793Smsmith
55383114Sscottl	sc = device_get_softc(dev);
55483114Sscottl
55583114Sscottl	if (sc->aac_state & AAC_STATE_OPEN)
556110426Sscottl		return(EBUSY);
55765793Smsmith
558110426Sscottl	/* Remove the child containers */
559110428Sscottl	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
560110426Sscottl		error = device_delete_child(dev, co->co_disk);
561110426Sscottl		if (error)
562110426Sscottl			return (error);
563111196Sscottl		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
564110428Sscottl		free(co, M_AACBUF);
565110426Sscottl	}
566110426Sscottl
567110426Sscottl	/* Remove the CAM SIMs */
568110428Sscottl	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
569110428Sscottl		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
570110426Sscottl		error = device_delete_child(dev, sim->sim_dev);
571110426Sscottl		if (error)
572110426Sscottl			return (error);
573110428Sscottl		free(sim, M_AACBUF);
574110426Sscottl	}
575110426Sscottl
57683114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
57783114Sscottl		sc->aifflags |= AAC_AIFFLAGS_EXIT;
57883114Sscottl		wakeup(sc->aifthread);
57983114Sscottl		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
58083114Sscottl	}
58182527Sscottl
58283114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
58383114Sscottl		panic("Cannot shutdown AIF thread\n");
58482527Sscottl
58583114Sscottl	if ((error = aac_shutdown(dev)))
58683114Sscottl		return(error);
58765793Smsmith
588110427Sscottl	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
589110427Sscottl
59083114Sscottl	aac_free(sc);
59165793Smsmith
592133542Sscottl	mtx_destroy(&sc->aac_aifq_lock);
593133542Sscottl	mtx_destroy(&sc->aac_io_lock);
594133542Sscottl	mtx_destroy(&sc->aac_container_lock);
595133542Sscottl
59683114Sscottl	return(0);
59765793Smsmith}
59865793Smsmith
59983114Sscottl/*
60065793Smsmith * Bring the controller down to a dormant state and detach all child devices.
60165793Smsmith *
60265793Smsmith * This function is called before detach or system shutdown.
60365793Smsmith *
60470393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
60565793Smsmith * allow shutdown if any device is open.
60665793Smsmith */
60765793Smsmithint
60865793Smsmithaac_shutdown(device_t dev)
60965793Smsmith{
61083114Sscottl	struct aac_softc *sc;
61195350Sscottl	struct aac_fib *fib;
61295350Sscottl	struct aac_close_command *cc;
61365793Smsmith
61483114Sscottl	debug_called(1);
61565793Smsmith
61683114Sscottl	sc = device_get_softc(dev);
61765793Smsmith
61883114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
61965793Smsmith
62083114Sscottl	/*
62183114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
62283114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
62383114Sscottl	 * We've been closed and all I/O completed already
62482527Sscottl	 */
62583114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
62683114Sscottl
627151086Sscottl	mtx_lock(&sc->aac_io_lock);
628130006Sscottl	aac_alloc_sync_fib(sc, &fib);
62995350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
63095350Sscottl
63195966Sscottl	bzero(cc, sizeof(struct aac_close_command));
63295350Sscottl	cc->Command = VM_CloseAll;
63395350Sscottl	cc->ContainerId = 0xffffffff;
63495350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
63595350Sscottl	    sizeof(struct aac_close_command)))
63683114Sscottl		printf("FAILED.\n");
637110426Sscottl	else
638110426Sscottl		printf("done\n");
639110426Sscottl#if 0
64083114Sscottl	else {
64195350Sscottl		fib->data[0] = 0;
64283114Sscottl		/*
64383114Sscottl		 * XXX Issuing this command to the controller makes it shut down
64483114Sscottl		 * but also keeps it from coming back up without a reset of the
64583114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
64683114Sscottl		 * driver module with the intent to reload it later.
64783114Sscottl		 */
64895350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
64995350Sscottl		    fib, 1)) {
65083114Sscottl			printf("FAILED.\n");
65183114Sscottl		} else {
65283114Sscottl			printf("done.\n");
65383114Sscottl		}
65465793Smsmith	}
655110426Sscottl#endif
65665793Smsmith
65783114Sscottl	AAC_MASK_INTERRUPTS(sc);
658133539Sscottl	aac_release_sync_fib(sc);
659151086Sscottl	mtx_unlock(&sc->aac_io_lock);
66065793Smsmith
66183114Sscottl	return(0);
66265793Smsmith}
66365793Smsmith
66483114Sscottl/*
66565793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
66665793Smsmith */
66765793Smsmithint
66865793Smsmithaac_suspend(device_t dev)
66965793Smsmith{
67083114Sscottl	struct aac_softc *sc;
67165793Smsmith
67283114Sscottl	debug_called(1);
67365793Smsmith
67483114Sscottl	sc = device_get_softc(dev);
67583114Sscottl
67683114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
67783114Sscottl
67883114Sscottl	AAC_MASK_INTERRUPTS(sc);
67983114Sscottl	return(0);
68065793Smsmith}
68165793Smsmith
68283114Sscottl/*
68365793Smsmith * Bring the controller back to a state ready for operation.
68465793Smsmith */
68565793Smsmithint
68665793Smsmithaac_resume(device_t dev)
68765793Smsmith{
68883114Sscottl	struct aac_softc *sc;
68965793Smsmith
69083114Sscottl	debug_called(1);
69183114Sscottl
69283114Sscottl	sc = device_get_softc(dev);
69383114Sscottl
69483114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
69583114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
69683114Sscottl	return(0);
69765793Smsmith}
69865793Smsmith
69983114Sscottl/*
700151086Sscottl * Interrupt handler for NEW_COMM interface.
70165793Smsmith */
70265793Smsmithvoid
703151086Sscottlaac_new_intr(void *arg)
70465793Smsmith{
70583114Sscottl	struct aac_softc *sc;
706151086Sscottl	u_int32_t index, fast;
707151086Sscottl	struct aac_command *cm;
708151086Sscottl	struct aac_fib *fib;
709151086Sscottl	int i;
710151086Sscottl
711151086Sscottl	debug_called(2);
712151086Sscottl
713151086Sscottl	sc = (struct aac_softc *)arg;
714151086Sscottl
715151086Sscottl	mtx_lock(&sc->aac_io_lock);
716151086Sscottl	while (1) {
717151086Sscottl		index = AAC_GET_OUTB_QUEUE(sc);
718151086Sscottl		if (index == 0xffffffff)
719151086Sscottl			index = AAC_GET_OUTB_QUEUE(sc);
720151086Sscottl		if (index == 0xffffffff)
721151086Sscottl			break;
722151086Sscottl		if (index & 2) {
723151086Sscottl			if (index == 0xfffffffe) {
724151086Sscottl				/* XXX This means that the controller wants
725151086Sscottl				 * more work.  Ignore it for now.
726151086Sscottl				 */
727151086Sscottl				continue;
728151086Sscottl			}
729151086Sscottl			/* AIF */
730151086Sscottl			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
731151086Sscottl				   M_NOWAIT | M_ZERO);
732151086Sscottl			if (fib == NULL) {
733151086Sscottl				/* If we're really this short on memory,
734151086Sscottl				 * hopefully breaking out of the handler will
735151086Sscottl				 * allow something to get freed.  This
736151086Sscottl				 * actually sucks a whole lot.
737151086Sscottl				 */
738151086Sscottl				break;
739151086Sscottl			}
740151086Sscottl			index &= ~2;
741151086Sscottl			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
742151086Sscottl				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
743151086Sscottl			aac_handle_aif(sc, fib);
744151086Sscottl			free(fib, M_AACBUF);
745151086Sscottl
746151086Sscottl			/*
747151086Sscottl			 * AIF memory is owned by the adapter, so let it
748151086Sscottl			 * know that we are done with it.
749151086Sscottl			 */
750151086Sscottl			AAC_SET_OUTB_QUEUE(sc, index);
751151086Sscottl			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
752151086Sscottl		} else {
753151086Sscottl			fast = index & 1;
754151086Sscottl			cm = sc->aac_commands + (index >> 2);
755151086Sscottl			fib = cm->cm_fib;
756151086Sscottl			if (fast) {
757151086Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
758151086Sscottl				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
759151086Sscottl			}
760151086Sscottl			aac_remove_busy(cm);
761151086Sscottl 			aac_unmap_command(cm);
762151086Sscottl			cm->cm_flags |= AAC_CMD_COMPLETED;
763151086Sscottl
764151086Sscottl			/* is there a completion handler? */
765151086Sscottl			if (cm->cm_complete != NULL) {
766151086Sscottl				cm->cm_complete(cm);
767151086Sscottl			} else {
768151086Sscottl				/* assume that someone is sleeping on this
769151086Sscottl				 * command
770151086Sscottl				 */
771151086Sscottl				wakeup(cm);
772151086Sscottl			}
773151086Sscottl			sc->flags &= ~AAC_QUEUE_FRZN;
774151086Sscottl		}
775151086Sscottl	}
776151086Sscottl	/* see if we can start some more I/O */
777151086Sscottl	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
778151086Sscottl		aac_startio(sc);
779151086Sscottl
780151086Sscottl	mtx_unlock(&sc->aac_io_lock);
781151086Sscottl}
782151086Sscottl
783151086Sscottlvoid
784151086Sscottlaac_fast_intr(void *arg)
785151086Sscottl{
786151086Sscottl	struct aac_softc *sc;
78783114Sscottl	u_int16_t reason;
78865793Smsmith
78983114Sscottl	debug_called(2);
79065793Smsmith
79183114Sscottl	sc = (struct aac_softc *)arg;
79265793Smsmith
793109088Sscottl	/*
794125225Sscottl	 * Read the status register directly.  This is faster than taking the
795125225Sscottl	 * driver lock and reading the queues directly.  It also saves having
796125225Sscottl	 * to turn parts of the driver lock into a spin mutex, which would be
797125225Sscottl	 * ugly.
798109088Sscottl	 */
799125225Sscottl	reason = AAC_GET_ISTATUS(sc);
800109088Sscottl	AAC_CLEAR_ISTATUS(sc, reason);
80165793Smsmith
802125225Sscottl	/* handle completion processing */
803109088Sscottl	if (reason & AAC_DB_RESPONSE_READY)
804125225Sscottl		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
805109088Sscottl
806125225Sscottl	/* controller wants to talk to us */
807125225Sscottl	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
808125225Sscottl		/*
809125225Sscottl		 * XXX Make sure that we don't get fooled by strange messages
810125225Sscottl		 * that start with a NULL.
811125225Sscottl		 */
812125225Sscottl		if ((reason & AAC_DB_PRINTF) &&
813151086Sscottl			(sc->aac_common->ac_printf[0] == 0))
814125225Sscottl			sc->aac_common->ac_printf[0] = 32;
81565793Smsmith
816125225Sscottl		/*
817125225Sscottl		 * This might miss doing the actual wakeup.  However, the
818125542Sscottl		 * msleep that this is waking up has a timeout, so it will
819125225Sscottl		 * wake up eventually.  AIFs and printfs are low enough
820125225Sscottl		 * priority that they can handle hanging out for a few seconds
821125225Sscottl		 * if needed.
822125225Sscottl		 */
823125225Sscottl		wakeup(sc->aifthread);
82483114Sscottl	}
825109088Sscottl}
82683114Sscottl
82783114Sscottl/*
82883114Sscottl * Command Processing
82983114Sscottl */
83065793Smsmith
83183114Sscottl/*
83265793Smsmith * Start as much queued I/O as possible on the controller
83365793Smsmith */
83495536Sscottlvoid
83565793Smsmithaac_startio(struct aac_softc *sc)
83665793Smsmith{
83783114Sscottl	struct aac_command *cm;
838129923Sscottl	int error;
83965793Smsmith
84083114Sscottl	debug_called(2);
84165793Smsmith
84283114Sscottl	for (;;) {
84383114Sscottl		/*
844129923Sscottl		 * This flag might be set if the card is out of resources.
845129923Sscottl		 * Checking it here prevents an infinite loop of deferrals.
846129923Sscottl		 */
847129923Sscottl		if (sc->flags & AAC_QUEUE_FRZN)
848129923Sscottl			break;
849129923Sscottl
850129923Sscottl		/*
85183114Sscottl		 * Try to get a command that's been put off for lack of
85283114Sscottl		 * resources
85383114Sscottl		 */
85483114Sscottl		cm = aac_dequeue_ready(sc);
85565793Smsmith
85683114Sscottl		/*
85783114Sscottl		 * Try to build a command off the bio queue (ignore error
85883114Sscottl		 * return)
85983114Sscottl		 */
86083114Sscottl		if (cm == NULL)
86183114Sscottl			aac_bio_command(sc, &cm);
86265793Smsmith
86383114Sscottl		/* nothing to do? */
86483114Sscottl		if (cm == NULL)
86583114Sscottl			break;
86665793Smsmith
867129923Sscottl		/* don't map more than once */
868129923Sscottl		if (cm->cm_flags & AAC_CMD_MAPPED)
869129923Sscottl			panic("aac: command %p already mapped", cm);
870129923Sscottl
871125559Sscottl		/*
872129923Sscottl		 * Set up the command to go to the controller.  If there are no
873129923Sscottl		 * data buffers associated with the command then it can bypass
874129923Sscottl		 * busdma.
875125559Sscottl		 */
876129923Sscottl		if (cm->cm_datalen != 0) {
877129923Sscottl			error = bus_dmamap_load(sc->aac_buffer_dmat,
878129923Sscottl						cm->cm_datamap, cm->cm_data,
879129923Sscottl						cm->cm_datalen,
880129923Sscottl						aac_map_command_sg, cm, 0);
881129923Sscottl			if (error == EINPROGRESS) {
882129923Sscottl				debug(1, "freezing queue\n");
883129923Sscottl				sc->flags |= AAC_QUEUE_FRZN;
884129923Sscottl				error = 0;
885129946Sscottl			} else if (error != 0)
886129923Sscottl				panic("aac_startio: unexpected error %d from "
887129923Sscottl				      "busdma\n", error);
888129923Sscottl		} else
889129923Sscottl			aac_map_command_sg(cm, NULL, 0, 0);
89065793Smsmith	}
89165793Smsmith}
89265793Smsmith
89383114Sscottl/*
89465793Smsmith * Handle notification of one or more FIBs coming from the controller.
89565793Smsmith */
89665793Smsmithstatic void
897110426Sscottlaac_command_thread(struct aac_softc *sc)
89865793Smsmith{
89983114Sscottl	struct aac_fib *fib;
90083114Sscottl	u_int32_t fib_size;
901125225Sscottl	int size, retval;
90265793Smsmith
90383114Sscottl	debug_called(2);
90465793Smsmith
905133540Sscottl	mtx_lock(&sc->aac_io_lock);
906125542Sscottl	sc->aifflags = AAC_AIFFLAGS_RUNNING;
90765793Smsmith
908125542Sscottl	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
90982527Sscottl
910125542Sscottl		retval = 0;
911125542Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
912125542Sscottl			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
913125542Sscottl					"aifthd", AAC_PERIODIC_INTERVAL * hz);
914125542Sscottl
915125225Sscottl		/*
916125225Sscottl		 * First see if any FIBs need to be allocated.  This needs
917125225Sscottl		 * to be called without the driver lock because contigmalloc
918125225Sscottl		 * will grab Giant, and would result in an LOR.
919125225Sscottl		 */
920125225Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
921133540Sscottl			mtx_unlock(&sc->aac_io_lock);
922125225Sscottl			aac_alloc_commands(sc);
923133540Sscottl			mtx_lock(&sc->aac_io_lock);
924125559Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
925125542Sscottl			aac_startio(sc);
926125225Sscottl		}
927125225Sscottl
928125225Sscottl		/*
929125225Sscottl		 * While we're here, check to see if any commands are stuck.
930125225Sscottl		 * This is pretty low-priority, so it's ok if it doesn't
931125225Sscottl		 * always fire.
932125225Sscottl		 */
933125225Sscottl		if (retval == EWOULDBLOCK)
934110426Sscottl			aac_timeout(sc);
935110426Sscottl
936110426Sscottl		/* Check the hardware printf message buffer */
937125225Sscottl		if (sc->aac_common->ac_printf[0] != 0)
938110426Sscottl			aac_print_printf(sc);
939110426Sscottl
940125225Sscottl		/* Also check to see if the adapter has a command for us. */
941151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
942151086Sscottl			continue;
943151086Sscottl		for (;;) {
944151086Sscottl			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
945151086Sscottl					   &fib_size, &fib))
946151086Sscottl				break;
94783114Sscottl
94883114Sscottl			AAC_PRINT_FIB(sc, fib);
94983114Sscottl
95083114Sscottl			switch (fib->Header.Command) {
95183114Sscottl			case AifRequest:
95283114Sscottl				aac_handle_aif(sc, fib);
95383114Sscottl				break;
95483114Sscottl			default:
95583114Sscottl				device_printf(sc->aac_dev, "unknown command "
95683114Sscottl					      "from controller\n");
95783114Sscottl				break;
95883114Sscottl			}
95982527Sscottl
96083114Sscottl			if ((fib->Header.XferState == 0) ||
961151086Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
96283114Sscottl				break;
963151086Sscottl			}
96482527Sscottl
965110426Sscottl			/* Return the AIF to the controller. */
96683114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
96783114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
96883114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
96982527Sscottl
97083114Sscottl				/* XXX Compute the Size field? */
97183114Sscottl				size = fib->Header.Size;
97283114Sscottl				if (size > sizeof(struct aac_fib)) {
97395536Sscottl					size = sizeof(struct aac_fib);
97483114Sscottl					fib->Header.Size = size;
97583114Sscottl				}
97683114Sscottl				/*
97783114Sscottl				 * Since we did not generate this command, it
97883114Sscottl				 * cannot go through the normal
97983114Sscottl				 * enqueue->startio chain.
98083114Sscottl				 */
98183114Sscottl				aac_enqueue_response(sc,
982151086Sscottl						 AAC_ADAP_NORM_RESP_QUEUE,
983151086Sscottl						 fib);
98483114Sscottl			}
98582527Sscottl		}
98665793Smsmith	}
98783114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
988133540Sscottl	mtx_unlock(&sc->aac_io_lock);
98983114Sscottl	wakeup(sc->aac_dev);
99065793Smsmith
99183114Sscottl	kthread_exit(0);
99265793Smsmith}
99365793Smsmith
99483114Sscottl/*
995111143Sscottl * Process completed commands.
99665793Smsmith */
99765793Smsmithstatic void
998111143Sscottlaac_complete(void *context, int pending)
99965793Smsmith{
1000111143Sscottl	struct aac_softc *sc;
100183114Sscottl	struct aac_command *cm;
100283114Sscottl	struct aac_fib *fib;
100383114Sscottl	u_int32_t fib_size;
100465793Smsmith
100583114Sscottl	debug_called(2);
100665793Smsmith
1007111143Sscottl	sc = (struct aac_softc *)context;
1008111143Sscottl
1009133540Sscottl	mtx_lock(&sc->aac_io_lock);
1010111532Sscottl
1011111143Sscottl	/* pull completed commands off the queue */
101283114Sscottl	for (;;) {
101383114Sscottl		/* look for completed FIBs on our queue */
101483114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1015151086Sscottl							&fib))
101683114Sscottl			break;	/* nothing to do */
1017111143Sscottl
1018125574Sscottl		/* get the command, unmap and hand off for processing */
1019111152Sscottl		cm = sc->aac_commands + fib->Header.SenderData;
102083114Sscottl		if (cm == NULL) {
102183114Sscottl			AAC_PRINT_FIB(sc, fib);
1022111143Sscottl			break;
102383114Sscottl		}
1024151086Sscottl		aac_remove_busy(cm);
102565793Smsmith
1026151086Sscottl 		aac_unmap_command(cm);
102783114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
102883114Sscottl
102983114Sscottl		/* is there a completion handler? */
103083114Sscottl		if (cm->cm_complete != NULL) {
103183114Sscottl			cm->cm_complete(cm);
103283114Sscottl		} else {
103383114Sscottl			/* assume that someone is sleeping on this command */
103483114Sscottl			wakeup(cm);
103583114Sscottl		}
103665793Smsmith	}
103770393Smsmith
103883114Sscottl	/* see if we can start some more I/O */
1039117363Sscottl	sc->flags &= ~AAC_QUEUE_FRZN;
104083114Sscottl	aac_startio(sc);
1041111532Sscottl
1042133540Sscottl	mtx_unlock(&sc->aac_io_lock);
104365793Smsmith}
104465793Smsmith
104583114Sscottl/*
104665793Smsmith * Handle a bio submitted from a disk device.
104765793Smsmith */
104865793Smsmithvoid
104965793Smsmithaac_submit_bio(struct bio *bp)
105065793Smsmith{
105183114Sscottl	struct aac_disk *ad;
105283114Sscottl	struct aac_softc *sc;
105365793Smsmith
105483114Sscottl	debug_called(2);
105565793Smsmith
1056111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
105783114Sscottl	sc = ad->ad_controller;
105883114Sscottl
105983114Sscottl	/* queue the BIO and try to get some work done */
106083114Sscottl	aac_enqueue_bio(sc, bp);
106183114Sscottl	aac_startio(sc);
106265793Smsmith}
106365793Smsmith
106483114Sscottl/*
106565793Smsmith * Get a bio and build a command to go with it.
106665793Smsmith */
106765793Smsmithstatic int
106865793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
106965793Smsmith{
107083114Sscottl	struct aac_command *cm;
107183114Sscottl	struct aac_fib *fib;
107283114Sscottl	struct aac_disk *ad;
107383114Sscottl	struct bio *bp;
107465793Smsmith
107583114Sscottl	debug_called(2);
107665793Smsmith
107783114Sscottl	/* get the resources we will need */
107883114Sscottl	cm = NULL;
1079125542Sscottl	bp = NULL;
1080125542Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
1081125542Sscottl		goto fail;
108283114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
108383114Sscottl		goto fail;
108465793Smsmith
108583114Sscottl	/* fill out the command */
108683114Sscottl	cm->cm_data = (void *)bp->bio_data;
108783114Sscottl	cm->cm_datalen = bp->bio_bcount;
108883114Sscottl	cm->cm_complete = aac_bio_complete;
108983114Sscottl	cm->cm_private = bp;
1090150119Sscottl	cm->cm_timestamp = time_uptime;
109183114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
109265793Smsmith
109383114Sscottl	/* build the FIB */
109483114Sscottl	fib = cm->cm_fib;
1095112856Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
109683114Sscottl	fib->Header.XferState =
1097109088Sscottl		AAC_FIBSTATE_HOSTOWNED   |
1098109088Sscottl		AAC_FIBSTATE_INITIALISED |
1099109088Sscottl		AAC_FIBSTATE_EMPTY	 |
1100109088Sscottl		AAC_FIBSTATE_FROMHOST	 |
1101109088Sscottl		AAC_FIBSTATE_REXPECTED   |
1102109088Sscottl		AAC_FIBSTATE_NORM	 |
1103109088Sscottl		AAC_FIBSTATE_ASYNC	 |
1104109088Sscottl		AAC_FIBSTATE_FAST_RESPONSE;
110565793Smsmith
110683114Sscottl	/* build the read/write request */
1107111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1108112856Sscottl
1109151086Sscottl	if (sc->flags & AAC_FLAGS_RAW_IO) {
1110151086Sscottl		struct aac_raw_io *raw;
1111151086Sscottl		raw = (struct aac_raw_io *)&fib->data[0];
1112151086Sscottl		fib->Header.Command = RawIo;
1113151086Sscottl		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
1114151086Sscottl		raw->ByteCount = bp->bio_bcount;
1115151086Sscottl		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1116151086Sscottl		raw->BpTotal = 0;
1117151086Sscottl		raw->BpComplete = 0;
1118151086Sscottl		fib->Header.Size += sizeof(struct aac_raw_io);
1119151086Sscottl		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
1120151086Sscottl		if (bp->bio_cmd == BIO_READ) {
1121151086Sscottl			raw->Flags = 1;
1122151086Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1123151086Sscottl		} else {
1124151086Sscottl			raw->Flags = 0;
1125151086Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1126151086Sscottl		}
1127151086Sscottl	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1128112856Sscottl		fib->Header.Command = ContainerCommand;
1129112856Sscottl		if (bp->bio_cmd == BIO_READ) {
1130112856Sscottl			struct aac_blockread *br;
1131112856Sscottl			br = (struct aac_blockread *)&fib->data[0];
1132112856Sscottl			br->Command = VM_CtBlockRead;
1133112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1134112856Sscottl			br->BlockNumber = bp->bio_pblkno;
1135112856Sscottl			br->ByteCount = bp->bio_bcount;
1136112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread);
1137112856Sscottl			cm->cm_sgtable = &br->SgMap;
1138112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1139112856Sscottl		} else {
1140112856Sscottl			struct aac_blockwrite *bw;
1141112856Sscottl			bw = (struct aac_blockwrite *)&fib->data[0];
1142112856Sscottl			bw->Command = VM_CtBlockWrite;
1143112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1144112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
1145112856Sscottl			bw->ByteCount = bp->bio_bcount;
1146112856Sscottl			bw->Stable = CUNSTABLE;
1147112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite);
1148112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1149112856Sscottl			cm->cm_sgtable = &bw->SgMap;
1150112856Sscottl		}
115183114Sscottl	} else {
1152112856Sscottl		fib->Header.Command = ContainerCommand64;
1153112856Sscottl		if (bp->bio_cmd == BIO_READ) {
1154112856Sscottl			struct aac_blockread64 *br;
1155112856Sscottl			br = (struct aac_blockread64 *)&fib->data[0];
1156112856Sscottl			br->Command = VM_CtHostRead64;
1157112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1158112856Sscottl			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1159112856Sscottl			br->BlockNumber = bp->bio_pblkno;
1160112856Sscottl			br->Pad = 0;
1161112856Sscottl			br->Flags = 0;
1162112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread64);
1163112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1164132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1165112856Sscottl		} else {
1166112856Sscottl			struct aac_blockwrite64 *bw;
1167112856Sscottl			bw = (struct aac_blockwrite64 *)&fib->data[0];
1168112856Sscottl			bw->Command = VM_CtHostWrite64;
1169112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1170112856Sscottl			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1171112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
1172112856Sscottl			bw->Pad = 0;
1173112856Sscottl			bw->Flags = 0;
1174112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite64);
1175112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1176132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1177112856Sscottl		}
117883114Sscottl	}
117965793Smsmith
118083114Sscottl	*cmp = cm;
118183114Sscottl	return(0);
118265793Smsmith
118365793Smsmithfail:
1184151086Sscottl	if (bp != NULL)
1185151086Sscottl		aac_enqueue_bio(sc, bp);
118683114Sscottl	if (cm != NULL)
118783114Sscottl		aac_release_command(cm);
118883114Sscottl	return(ENOMEM);
118965793Smsmith}
119065793Smsmith
119183114Sscottl/*
119265793Smsmith * Handle a bio-instigated command that has been completed.
119365793Smsmith */
119465793Smsmithstatic void
119565793Smsmithaac_bio_complete(struct aac_command *cm)
119665793Smsmith{
119783114Sscottl	struct aac_blockread_response *brr;
119883114Sscottl	struct aac_blockwrite_response *bwr;
119983114Sscottl	struct bio *bp;
120083114Sscottl	AAC_FSAStatus status;
120165793Smsmith
120283114Sscottl	/* fetch relevant status and then release the command */
120383114Sscottl	bp = (struct bio *)cm->cm_private;
1204111691Sscottl	if (bp->bio_cmd == BIO_READ) {
120583114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
120683114Sscottl		status = brr->Status;
120783114Sscottl	} else {
120883114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
120983114Sscottl		status = bwr->Status;
121083114Sscottl	}
121183114Sscottl	aac_release_command(cm);
121265793Smsmith
121383114Sscottl	/* fix up the bio based on status */
121483114Sscottl	if (status == ST_OK) {
121583114Sscottl		bp->bio_resid = 0;
121683114Sscottl	} else {
121783114Sscottl		bp->bio_error = EIO;
121883114Sscottl		bp->bio_flags |= BIO_ERROR;
121983114Sscottl		/* pass an error string out to the disk layer */
122083114Sscottl		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
122183114Sscottl						    status);
122283114Sscottl	}
122383114Sscottl	aac_biodone(bp);
122465793Smsmith}
122565793Smsmith
122683114Sscottl/*
122765793Smsmith * Submit a command to the controller, return when it completes.
122887183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
122987183Sscottl *     be stuck here forever.  At the same time, signals are not caught
1230128258Sscottl *     because there is a risk that a signal could wakeup the sleep before
1231128258Sscottl *     the card has a chance to complete the command.  Since there is no way
1232128258Sscottl *     to cancel a command that is in progress, we can't protect against the
1233128258Sscottl *     card completing a command late and spamming the command and data
1234128258Sscottl *     memory.  So, we are held hostage until the command completes.
123565793Smsmith */
123665793Smsmithstatic int
1237128258Sscottlaac_wait_command(struct aac_command *cm)
123865793Smsmith{
1239111532Sscottl	struct aac_softc *sc;
1240128258Sscottl	int error;
124165793Smsmith
124283114Sscottl	debug_called(2);
124365793Smsmith
1244111532Sscottl	sc = cm->cm_sc;
1245111532Sscottl
124683114Sscottl	/* Put the command on the ready queue and get things going */
124783114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
124883114Sscottl	aac_enqueue_ready(cm);
1249111532Sscottl	aac_startio(sc);
1250128258Sscottl	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
125183114Sscottl	return(error);
125265793Smsmith}
125365793Smsmith
125483114Sscottl/*
125583114Sscottl *Command Buffer Management
125683114Sscottl */
125765793Smsmith
125883114Sscottl/*
125965793Smsmith * Allocate a command.
126065793Smsmith */
126195536Sscottlint
126265793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
126365793Smsmith{
126483114Sscottl	struct aac_command *cm;
126565793Smsmith
126683114Sscottl	debug_called(3);
126765793Smsmith
1268110604Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL) {
1269112856Sscottl		if (sc->total_fibs < sc->aac_max_fibs) {
1270112856Sscottl			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1271112856Sscottl			wakeup(sc->aifthread);
1272112856Sscottl		}
1273111532Sscottl		return (EBUSY);
1274110604Sscottl	}
127565793Smsmith
127683114Sscottl	*cmp = cm;
127783114Sscottl	return(0);
127870393Smsmith}
127970393Smsmith
128083114Sscottl/*
128170393Smsmith * Release a command back to the freelist.
128270393Smsmith */
128395536Sscottlvoid
128470393Smsmithaac_release_command(struct aac_command *cm)
128570393Smsmith{
1286151086Sscottl	struct aac_event *event;
1287151086Sscottl	struct aac_softc *sc;
1288151086Sscottl
128983114Sscottl	debug_called(3);
129070393Smsmith
129183114Sscottl	/* (re)initialise the command/FIB */
129283114Sscottl	cm->cm_sgtable = NULL;
129383114Sscottl	cm->cm_flags = 0;
129483114Sscottl	cm->cm_complete = NULL;
129583114Sscottl	cm->cm_private = NULL;
129683114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
129783114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
129883114Sscottl	cm->cm_fib->Header.Flags = 0;
1299151086Sscottl	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
130065793Smsmith
130183114Sscottl	/*
130283114Sscottl	 * These are duplicated in aac_start to cover the case where an
130383114Sscottl	 * intermediate stage may have destroyed them.  They're left
130483114Sscottl	 * initialised here for debugging purposes only.
130583114Sscottl	 */
1306109088Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1307109088Sscottl	cm->cm_fib->Header.SenderData = 0;
130865793Smsmith
130983114Sscottl	aac_enqueue_free(cm);
1310151086Sscottl
1311151086Sscottl	sc = cm->cm_sc;
1312151086Sscottl	event = TAILQ_FIRST(&sc->aac_ev_cmfree);
1313151086Sscottl	if (event != NULL) {
1314151086Sscottl		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
1315151086Sscottl		event->ev_callback(sc, event, event->ev_arg);
1316151086Sscottl	}
131765793Smsmith}
131865793Smsmith
131983114Sscottl/*
132070393Smsmith * Map helper for command/FIB allocation.
132165793Smsmith */
132265793Smsmithstatic void
132370393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
132465793Smsmith{
1325151086Sscottl	uint64_t	*fibphys;
132665793Smsmith
1327151086Sscottl	fibphys = (uint64_t *)arg;
132865793Smsmith
132983114Sscottl	debug_called(3);
133083114Sscottl
1331110604Sscottl	*fibphys = segs[0].ds_addr;
133265793Smsmith}
133365793Smsmith
133483114Sscottl/*
133570393Smsmith * Allocate and initialise commands/FIBs for this adapter.
133665793Smsmith */
133770393Smsmithstatic int
133870393Smsmithaac_alloc_commands(struct aac_softc *sc)
133965793Smsmith{
134083114Sscottl	struct aac_command *cm;
1341110604Sscottl	struct aac_fibmap *fm;
1342151086Sscottl	uint64_t fibphys;
1343110604Sscottl	int i, error;
134465793Smsmith
1345112679Sscottl	debug_called(2);
134665793Smsmith
1347151086Sscottl	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1348110604Sscottl		return (ENOMEM);
1349110604Sscottl
1350111141Sscottl	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1351112679Sscottl	if (fm == NULL)
1352112679Sscottl		return (ENOMEM);
1353110604Sscottl
135483114Sscottl	/* allocate the FIBs in DMAable memory and load them */
1355110604Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1356110604Sscottl			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1357110426Sscottl		device_printf(sc->aac_dev,
1358110426Sscottl			      "Not enough contiguous memory available.\n");
1359111141Sscottl		free(fm, M_AACBUF);
1360102602Sscottl		return (ENOMEM);
136183114Sscottl	}
1362109716Sscottl
1363117363Sscottl	/* Ignore errors since this doesn't bounce */
1364117363Sscottl	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1365151086Sscottl			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1366117363Sscottl			      aac_map_command_helper, &fibphys, 0);
1367109716Sscottl
1368109716Sscottl	/* initialise constant fields in the command structure */
1369133540Sscottl	mtx_lock(&sc->aac_io_lock);
1370151086Sscottl	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
1371151086Sscottl	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
1372111141Sscottl		cm = sc->aac_commands + sc->total_fibs;
1373110604Sscottl		fm->aac_commands = cm;
137483114Sscottl		cm->cm_sc = sc;
1375151086Sscottl		cm->cm_fib = (struct aac_fib *)
1376151086Sscottl			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
1377151086Sscottl		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1378111152Sscottl		cm->cm_index = sc->total_fibs;
137965793Smsmith
1380110604Sscottl		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1381110604Sscottl					       &cm->cm_datamap)) == 0)
138283114Sscottl			aac_release_command(cm);
1383111141Sscottl		else
1384111141Sscottl			break;
1385111141Sscottl		sc->total_fibs++;
138683114Sscottl	}
1387110604Sscottl
1388111141Sscottl	if (i > 0) {
1389111141Sscottl		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1390112679Sscottl		debug(1, "total_fibs= %d\n", sc->total_fibs);
1391133540Sscottl		mtx_unlock(&sc->aac_io_lock);
1392111141Sscottl		return (0);
1393111141Sscottl	}
1394110604Sscottl
1395133540Sscottl	mtx_unlock(&sc->aac_io_lock);
1396111141Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1397111141Sscottl	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1398111141Sscottl	free(fm, M_AACBUF);
1399111141Sscottl	return (ENOMEM);
140065793Smsmith}
140165793Smsmith
140283114Sscottl/*
140370393Smsmith * Free FIBs owned by this adapter.
140465793Smsmith */
140565793Smsmithstatic void
1406111141Sscottlaac_free_commands(struct aac_softc *sc)
140765793Smsmith{
1408111141Sscottl	struct aac_fibmap *fm;
1409110604Sscottl	struct aac_command *cm;
141083114Sscottl	int i;
141165793Smsmith
141283114Sscottl	debug_called(1);
141365793Smsmith
1414111141Sscottl	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1415111141Sscottl
1416111141Sscottl		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1417111141Sscottl		/*
1418111141Sscottl		 * We check against total_fibs to handle partially
1419111141Sscottl		 * allocated blocks.
1420111141Sscottl		 */
1421151086Sscottl		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1422111141Sscottl			cm = fm->aac_commands + i;
1423111141Sscottl			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1424111141Sscottl		}
1425111141Sscottl		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1426111141Sscottl		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1427111141Sscottl		free(fm, M_AACBUF);
1428110604Sscottl	}
142965793Smsmith}
143065793Smsmith
143183114Sscottl/*
143265793Smsmith * Command-mapping helper function - populate this command's s/g table.
143365793Smsmith */
143465793Smsmithstatic void
143565793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
143665793Smsmith{
1437117363Sscottl	struct aac_softc *sc;
143883114Sscottl	struct aac_command *cm;
143983114Sscottl	struct aac_fib *fib;
144083114Sscottl	int i;
144165793Smsmith
144283114Sscottl	debug_called(3);
144365793Smsmith
144483114Sscottl	cm = (struct aac_command *)arg;
1445117363Sscottl	sc = cm->cm_sc;
144683114Sscottl	fib = cm->cm_fib;
144765793Smsmith
144883114Sscottl	/* copy into the FIB */
1449112856Sscottl	if (cm->cm_sgtable != NULL) {
1450151086Sscottl		if (fib->Header.Command == RawIo) {
1451151086Sscottl			struct aac_sg_tableraw *sg;
1452151086Sscottl			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
1453151086Sscottl			sg->SgCount = nseg;
1454151086Sscottl			for (i = 0; i < nseg; i++) {
1455151086Sscottl				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
1456151086Sscottl				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
1457151086Sscottl				sg->SgEntryRaw[i].Next = 0;
1458151086Sscottl				sg->SgEntryRaw[i].Prev = 0;
1459151086Sscottl				sg->SgEntryRaw[i].Flags = 0;
1460151086Sscottl			}
1461151086Sscottl			/* update the FIB size for the s/g count */
1462151086Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
1463151086Sscottl		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1464112856Sscottl			struct aac_sg_table *sg;
1465112856Sscottl			sg = cm->cm_sgtable;
1466112856Sscottl			sg->SgCount = nseg;
1467112856Sscottl			for (i = 0; i < nseg; i++) {
1468112856Sscottl				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1469112856Sscottl				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1470112856Sscottl			}
1471112856Sscottl			/* update the FIB size for the s/g count */
1472151086Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1473112856Sscottl		} else {
1474112856Sscottl			struct aac_sg_table64 *sg;
1475112856Sscottl			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1476112856Sscottl			sg->SgCount = nseg;
1477112856Sscottl			for (i = 0; i < nseg; i++) {
1478112856Sscottl				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1479112856Sscottl				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1480112856Sscottl			}
1481112856Sscottl			/* update the FIB size for the s/g count */
1482112856Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
148383114Sscottl		}
148465793Smsmith	}
148565793Smsmith
1486117363Sscottl	/* Fix up the address values in the FIB.  Use the command array index
1487117363Sscottl	 * instead of a pointer since these fields are only 32 bits.  Shift
1488151086Sscottl	 * the SenderFibAddress over to make room for the fast response bit
1489151086Sscottl	 * and for the AIF bit
1490117363Sscottl	 */
1491151086Sscottl	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
1492151086Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
149365793Smsmith
1494117363Sscottl	/* save a pointer to the command for speedy reverse-lookup */
1495117363Sscottl	cm->cm_fib->Header.SenderData = cm->cm_index;
149665793Smsmith
1497117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAIN)
1498117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1499117363Sscottl				BUS_DMASYNC_PREREAD);
1500117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAOUT)
1501117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1502117363Sscottl				BUS_DMASYNC_PREWRITE);
1503117363Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
150465793Smsmith
1505151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1506151086Sscottl		int count = 10000000L;
1507151086Sscottl		while (AAC_SEND_COMMAND(sc, cm) != 0) {
1508151086Sscottl			if (--count == 0) {
1509151086Sscottl				aac_unmap_command(cm);
1510151086Sscottl				sc->flags |= AAC_QUEUE_FRZN;
1511151086Sscottl				aac_requeue_ready(cm);
1512151086Sscottl			}
1513151086Sscottl			DELAY(5);			/* wait 5 usec. */
1514151086Sscottl		}
1515151086Sscottl	} else {
1516151086Sscottl		/* Put the FIB on the outbound queue */
1517151086Sscottl		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
1518151086Sscottl			aac_unmap_command(cm);
1519151086Sscottl			sc->flags |= AAC_QUEUE_FRZN;
1520151086Sscottl			aac_requeue_ready(cm);
1521151086Sscottl		}
1522125559Sscottl	}
152365793Smsmith
1524117363Sscottl	return;
152565793Smsmith}
152665793Smsmith
152783114Sscottl/*
152865793Smsmith * Unmap a command from controller-visible space.
152965793Smsmith */
153065793Smsmithstatic void
153165793Smsmithaac_unmap_command(struct aac_command *cm)
153265793Smsmith{
153383114Sscottl	struct aac_softc *sc;
153465793Smsmith
153583114Sscottl	debug_called(2);
153665793Smsmith
153783114Sscottl	sc = cm->cm_sc;
153865793Smsmith
153983114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
154083114Sscottl		return;
154165793Smsmith
154283114Sscottl	if (cm->cm_datalen != 0) {
154383114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
154483114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
154583114Sscottl					BUS_DMASYNC_POSTREAD);
154683114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
154783114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
154883114Sscottl					BUS_DMASYNC_POSTWRITE);
154983114Sscottl
155083114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
155183114Sscottl	}
155283114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
155365793Smsmith}
155465793Smsmith
155583114Sscottl/*
155683114Sscottl * Hardware Interface
155783114Sscottl */
155865793Smsmith
155983114Sscottl/*
156065793Smsmith * Initialise the adapter.
156165793Smsmith */
156265793Smsmithstatic void
156365793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
156465793Smsmith{
156583114Sscottl	struct aac_softc *sc;
156665793Smsmith
156783114Sscottl	debug_called(1);
156865793Smsmith
156983114Sscottl	sc = (struct aac_softc *)arg;
157083114Sscottl
157183114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
157265793Smsmith}
157365793Smsmith
157465793Smsmithstatic int
157590275Sscottlaac_check_firmware(struct aac_softc *sc)
157690275Sscottl{
1577151330Sscottl	u_int32_t major, minor, options = 0, atu_size = 0;
1578151330Sscottl	int status;
157990275Sscottl
158090275Sscottl	debug_called(1);
158190275Sscottl
1582112679Sscottl	/*
1583112679Sscottl	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1584112679Sscottl	 * firmware version 1.x are not compatible with this driver.
1585112679Sscottl	 */
1586112679Sscottl	if (sc->flags & AAC_FLAGS_PERC2QC) {
158790275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
158890275Sscottl				     NULL)) {
158990275Sscottl			device_printf(sc->aac_dev,
159090275Sscottl				      "Error reading firmware version\n");
159190275Sscottl			return (EIO);
159290275Sscottl		}
159390275Sscottl
159490275Sscottl		/* These numbers are stored as ASCII! */
1595112679Sscottl		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1596112679Sscottl		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
159790275Sscottl		if (major == 1) {
159890275Sscottl			device_printf(sc->aac_dev,
159990275Sscottl			    "Firmware version %d.%d is not supported.\n",
160090275Sscottl			    major, minor);
160190275Sscottl			return (EINVAL);
160290275Sscottl		}
160390275Sscottl	}
160490275Sscottl
1605112679Sscottl	/*
1606112679Sscottl	 * Retrieve the capabilities/supported options word so we know what
1607151330Sscottl	 * work-arounds to enable.  Some firmware revs don't support this
1608151330Sscottl	 * command.
1609112679Sscottl	 */
1610151330Sscottl	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1611151330Sscottl		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1612151330Sscottl			device_printf(sc->aac_dev,
1613151330Sscottl			     "RequestAdapterInfo failed\n");
1614151330Sscottl			return (EIO);
1615151330Sscottl		}
1616151330Sscottl	} else {
1617151330Sscottl		options = AAC_GET_MAILBOX(sc, 1);
1618151330Sscottl		atu_size = AAC_GET_MAILBOX(sc, 2);
1619151330Sscottl		sc->supported_options = options;
1620112679Sscottl
1621151330Sscottl		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1622151330Sscottl		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1623151330Sscottl			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1624151330Sscottl		if (options & AAC_SUPPORTED_NONDASD)
1625151330Sscottl			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1626151330Sscottl		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1627151330Sscottl		     && (sizeof(bus_addr_t) > 4)) {
1628151330Sscottl			device_printf(sc->aac_dev,
1629151330Sscottl			    "Enabling 64-bit address support\n");
1630151330Sscottl			sc->flags |= AAC_FLAGS_SG_64BIT;
1631151330Sscottl		}
1632151330Sscottl		if ((options & AAC_SUPPORTED_NEW_COMM)
1633151330Sscottl		 && sc->aac_if.aif_send_command)
1634151330Sscottl			sc->flags |= AAC_FLAGS_NEW_COMM;
1635151330Sscottl		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
1636151330Sscottl			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1637112679Sscottl	}
1638112679Sscottl
1639112679Sscottl	/* Check for broken hardware that does a lower number of commands */
1640151086Sscottl	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
1641151086Sscottl
1642151086Sscottl	/* Remap mem. resource, if required */
1643151086Sscottl	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1644151086Sscottl		atu_size > rman_get_size(sc->aac_regs_resource)) {
1645151086Sscottl		bus_release_resource(
1646151086Sscottl			sc->aac_dev, SYS_RES_MEMORY,
1647151086Sscottl			sc->aac_regs_rid, sc->aac_regs_resource);
1648151086Sscottl		sc->aac_regs_resource = bus_alloc_resource(
1649151086Sscottl			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
1650151086Sscottl			0ul, ~0ul, atu_size, RF_ACTIVE);
1651151086Sscottl		if (sc->aac_regs_resource == NULL) {
1652151086Sscottl			sc->aac_regs_resource = bus_alloc_resource_any(
1653151086Sscottl				sc->aac_dev, SYS_RES_MEMORY,
1654151086Sscottl				&sc->aac_regs_rid, RF_ACTIVE);
1655151086Sscottl			if (sc->aac_regs_resource == NULL) {
1656151086Sscottl				device_printf(sc->aac_dev,
1657151109Sscottl				    "couldn't allocate register window\n");
1658151086Sscottl				return (ENXIO);
1659151086Sscottl			}
1660151086Sscottl			sc->flags &= ~AAC_FLAGS_NEW_COMM;
1661151086Sscottl		}
1662151086Sscottl		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
1663151086Sscottl		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
1664151086Sscottl	}
1665151086Sscottl
1666151086Sscottl	/* Read preferred settings */
1667151086Sscottl	sc->aac_max_fib_size = sizeof(struct aac_fib);
1668151086Sscottl	sc->aac_max_sectors = 128;				/* 64KB */
1669151086Sscottl	if (sc->flags & AAC_FLAGS_SG_64BIT)
1670151330Sscottl		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1671151330Sscottl		 - sizeof(struct aac_blockwrite64)
1672151330Sscottl		 + sizeof(struct aac_sg_table64))
1673151330Sscottl		 / sizeof(struct aac_sg_table64);
1674112679Sscottl	else
1675151330Sscottl		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1676151330Sscottl		 - sizeof(struct aac_blockwrite)
1677151330Sscottl		 + sizeof(struct aac_sg_table))
1678151330Sscottl		 / sizeof(struct aac_sg_table);
1679151330Sscottl
1680151086Sscottl	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
1681151086Sscottl		options = AAC_GET_MAILBOX(sc, 1);
1682151086Sscottl		sc->aac_max_fib_size = (options & 0xFFFF);
1683151086Sscottl		sc->aac_max_sectors = (options >> 16) << 1;
1684151086Sscottl		options = AAC_GET_MAILBOX(sc, 2);
1685151086Sscottl		sc->aac_sg_tablesize = (options >> 16);
1686151086Sscottl		options = AAC_GET_MAILBOX(sc, 3);
1687151086Sscottl		sc->aac_max_fibs = (options & 0xFFFF);
1688151086Sscottl	}
1689151086Sscottl	if (sc->aac_max_fib_size > PAGE_SIZE)
1690151086Sscottl		sc->aac_max_fib_size = PAGE_SIZE;
1691151086Sscottl	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1692151086Sscottl
169390275Sscottl	return (0);
169490275Sscottl}
169590275Sscottl
169690275Sscottlstatic int
169765793Smsmithaac_init(struct aac_softc *sc)
169865793Smsmith{
169983114Sscottl	struct aac_adapter_init	*ip;
170083114Sscottl	time_t then;
1701119146Sscottl	u_int32_t code, qoffset;
1702112679Sscottl	int error;
170365793Smsmith
170483114Sscottl	debug_called(1);
170565793Smsmith
170683114Sscottl	/*
170783114Sscottl	 * First wait for the adapter to come ready.
170883114Sscottl	 */
1709150119Sscottl	then = time_uptime;
171083114Sscottl	do {
171183114Sscottl		code = AAC_GET_FWSTATUS(sc);
171283114Sscottl		if (code & AAC_SELF_TEST_FAILED) {
171383114Sscottl			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
171483114Sscottl			return(ENXIO);
171583114Sscottl		}
171683114Sscottl		if (code & AAC_KERNEL_PANIC) {
171783114Sscottl			device_printf(sc->aac_dev,
171883114Sscottl				      "FATAL: controller kernel panic\n");
171983114Sscottl			return(ENXIO);
172083114Sscottl		}
1721150119Sscottl		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
172283114Sscottl			device_printf(sc->aac_dev,
172383114Sscottl				      "FATAL: controller not coming ready, "
172483114Sscottl					   "status %x\n", code);
172583114Sscottl			return(ENXIO);
172683114Sscottl		}
172783114Sscottl	} while (!(code & AAC_UP_AND_RUNNING));
172883114Sscottl
1729112679Sscottl	error = ENOMEM;
173083114Sscottl	/*
1731112679Sscottl	 * Create DMA tag for mapping buffers into controller-addressable space.
1732112679Sscottl	 */
1733112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1734112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1735112679Sscottl			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1736112679Sscottl			       BUS_SPACE_MAXADDR :
1737112679Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1738112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1739112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1740112679Sscottl			       MAXBSIZE,		/* maxsize */
1741151086Sscottl			       sc->aac_sg_tablesize,	/* nsegments */
1742112679Sscottl			       MAXBSIZE,		/* maxsegsize */
1743112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1744117126Sscottl			       busdma_lock_mutex,	/* lockfunc */
1745117126Sscottl			       &sc->aac_io_lock,	/* lockfuncarg */
1746112679Sscottl			       &sc->aac_buffer_dmat)) {
1747112679Sscottl		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1748112679Sscottl		goto out;
1749112679Sscottl	}
1750112679Sscottl
1751112679Sscottl	/*
1752112679Sscottl	 * Create DMA tag for mapping FIBs into controller-addressable space..
1753112679Sscottl	 */
1754112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1755112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1756112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1757112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1758112679Sscottl			       0x7fffffff,		/* lowaddr */
1759112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1760112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1761151086Sscottl			       sc->aac_max_fibs_alloc *
1762151086Sscottl			       sc->aac_max_fib_size,  /* maxsize */
1763112679Sscottl			       1,			/* nsegments */
1764151086Sscottl			       sc->aac_max_fibs_alloc *
1765151086Sscottl			       sc->aac_max_fib_size,	/* maxsegsize */
1766137962Sscottl			       0,			/* flags */
1767117126Sscottl			       NULL, NULL,		/* No locking needed */
1768112679Sscottl			       &sc->aac_fib_dmat)) {
1769112679Sscottl		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1770112679Sscottl		goto out;
1771112679Sscottl	}
1772112679Sscottl
1773112679Sscottl	/*
177483114Sscottl	 * Create DMA tag for the common structure and allocate it.
177583114Sscottl	 */
177683114Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
177795536Sscottl			       1, 0,			/* algnmnt, boundary */
1778112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1779112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1780112679Sscottl			       0x7fffffff,		/* lowaddr */
178183114Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
178283114Sscottl			       NULL, NULL, 		/* filter, filterarg */
1783110604Sscottl			       8192 + sizeof(struct aac_common), /* maxsize */
178483114Sscottl			       1,			/* nsegments */
178583114Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1786137962Sscottl			       0,			/* flags */
1787117126Sscottl			       NULL, NULL,		/* No locking needed */
178883114Sscottl			       &sc->aac_common_dmat)) {
178983114Sscottl		device_printf(sc->aac_dev,
179083114Sscottl			      "can't allocate common structure DMA tag\n");
1791112679Sscottl		goto out;
179265793Smsmith	}
179383114Sscottl	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
179483114Sscottl			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
179583114Sscottl		device_printf(sc->aac_dev, "can't allocate common structure\n");
1796112679Sscottl		goto out;
179765793Smsmith	}
1798110604Sscottl
1799110604Sscottl	/*
1800110604Sscottl	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1801110604Sscottl	 * below address 8192 in physical memory.
1802110604Sscottl	 * XXX If the padding is not needed, can it be put to use instead
1803110604Sscottl	 * of ignored?
1804110604Sscottl	 */
1805117363Sscottl	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1806110604Sscottl			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1807110604Sscottl			aac_common_map, sc, 0);
1808110604Sscottl
1809110604Sscottl	if (sc->aac_common_busaddr < 8192) {
1810132771Skan		sc->aac_common = (struct aac_common *)
1811132771Skan		    ((uint8_t *)sc->aac_common + 8192);
1812110604Sscottl		sc->aac_common_busaddr += 8192;
1813110604Sscottl	}
181483114Sscottl	bzero(sc->aac_common, sizeof(*sc->aac_common));
1815110604Sscottl
1816110604Sscottl	/* Allocate some FIBs and associated command structs */
1817110604Sscottl	TAILQ_INIT(&sc->aac_fibmap_tqh);
1818151086Sscottl	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
1819111141Sscottl				  M_AACBUF, M_WAITOK|M_ZERO);
1820111141Sscottl	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1821110604Sscottl		if (aac_alloc_commands(sc) != 0)
1822110604Sscottl			break;
1823110604Sscottl	}
1824110604Sscottl	if (sc->total_fibs == 0)
1825112679Sscottl		goto out;
182683114Sscottl
182783114Sscottl	/*
182883114Sscottl	 * Fill in the init structure.  This tells the adapter about the
182983114Sscottl	 * physical location of various important shared data structures.
183083114Sscottl	 */
183183114Sscottl	ip = &sc->aac_common->ac_init;
183283114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1833151086Sscottl	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1834151086Sscottl		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
1835151086Sscottl		sc->flags |= AAC_FLAGS_RAW_IO;
1836151086Sscottl	}
1837109088Sscottl	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
183865793Smsmith
183983114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
184083114Sscottl					 offsetof(struct aac_common, ac_fibs);
1841114151Sscottl	ip->AdapterFibsVirtualAddress = 0;
184283114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
184383114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
184465793Smsmith
184583114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
184683114Sscottl				  offsetof(struct aac_common, ac_printf);
184783114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
184865793Smsmith
1849117361Sscottl	/*
1850117361Sscottl	 * The adapter assumes that pages are 4K in size, except on some
1851117361Sscottl 	 * broken firmware versions that do the page->byte conversion twice,
1852117361Sscottl	 * therefore 'assuming' that this value is in 16MB units (2^24).
1853117361Sscottl	 * Round up since the granularity is so high.
1854117361Sscottl	 */
1855109088Sscottl	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1856117361Sscottl	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1857117361Sscottl		ip->HostPhysMemPages =
1858117361Sscottl		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1859117362Sscottl	}
1860150119Sscottl	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
186165793Smsmith
1862151086Sscottl	ip->InitFlags = 0;
1863151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1864151086Sscottl		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
1865151086Sscottl		device_printf(sc->aac_dev, "New comm. interface enabled\n");
1866151086Sscottl	}
1867151086Sscottl
1868151086Sscottl	ip->MaxIoCommands = sc->aac_max_fibs;
1869151086Sscottl	ip->MaxIoSize = sc->aac_max_sectors << 9;
1870151086Sscottl	ip->MaxFibSize = sc->aac_max_fib_size;
1871151086Sscottl
187283114Sscottl	/*
187383114Sscottl	 * Initialise FIB queues.  Note that it appears that the layout of the
187483114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
187583114Sscottl	 * adapter, which is only told about the base of the queue index fields.
187683114Sscottl	 *
187783114Sscottl	 * The initial values of the indices are assumed to inform the adapter
187883114Sscottl	 * of the sizes of the respective queues, and theoretically it could
187983114Sscottl	 * work out the entire layout of the queue structures from this.  We
188083114Sscottl	 * take the easy route and just lay this area out like everyone else
188183114Sscottl	 * does.
188283114Sscottl	 *
188383114Sscottl	 * The Linux driver uses a much more complex scheme whereby several
188483114Sscottl	 * header records are kept for each queue.  We use a couple of generic
188583114Sscottl	 * list manipulation functions which 'know' the size of each list by
188683114Sscottl	 * virtue of a table.
188783114Sscottl	 */
1888119146Sscottl	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
1889119625Sscottl	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
1890119625Sscottl	sc->aac_queues =
1891119625Sscottl	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1892119146Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
189365793Smsmith
189483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
189581082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
189683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
189781082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
189883114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
189981082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
190083114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
190181082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
190283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
190381082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
190483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
190581082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
190683114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
190781082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
190883114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
190981082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
191083114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
191181082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
191283114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
191381082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
191483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
191581082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
191683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
191781082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
191883114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
191981082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
192083114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
192181082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
192283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
192381082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
192483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
192581082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
192683114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
192781082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
192883114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
192981082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
193083114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
193181082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
193283114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
193381082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
193483114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
193581082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
193683114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
193781082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
193883114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
193981082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
194083114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
194181082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
194265793Smsmith
194383114Sscottl	/*
194483114Sscottl	 * Do controller-type-specific initialisation
194583114Sscottl	 */
194683114Sscottl	switch (sc->aac_hwif) {
194783114Sscottl	case AAC_HWIF_I960RX:
194883114Sscottl		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
194983114Sscottl		break;
1950133606Sscottl	case AAC_HWIF_RKT:
1951133606Sscottl		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
1952133606Sscottl		break;
1953133606Sscottl	default:
1954133606Sscottl		break;
195583114Sscottl	}
195665793Smsmith
195783114Sscottl	/*
195883114Sscottl	 * Give the init structure to the controller.
195983114Sscottl	 */
196083114Sscottl	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
196183114Sscottl			     sc->aac_common_busaddr +
196283114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
196383114Sscottl			     NULL)) {
196483114Sscottl		device_printf(sc->aac_dev,
196583114Sscottl			      "error establishing init structure\n");
1966112679Sscottl		error = EIO;
1967112679Sscottl		goto out;
196883114Sscottl	}
196965793Smsmith
1970112679Sscottl	error = 0;
1971112679Sscottlout:
1972112679Sscottl	return(error);
197365793Smsmith}
197465793Smsmith
197583114Sscottl/*
197665793Smsmith * Send a synchronous command to the controller and wait for a result.
1977151086Sscottl * Indicate if the controller completed the command with an error status.
197865793Smsmith */
197965793Smsmithstatic int
198065793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
198170393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
198270393Smsmith		 u_int32_t *sp)
198365793Smsmith{
198483114Sscottl	time_t then;
198583114Sscottl	u_int32_t status;
198665793Smsmith
198783114Sscottl	debug_called(3);
198865793Smsmith
198983114Sscottl	/* populate the mailbox */
199083114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
199165793Smsmith
199283114Sscottl	/* ensure the sync command doorbell flag is cleared */
199383114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
199465793Smsmith
199583114Sscottl	/* then set it to signal the adapter */
199683114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
199765793Smsmith
199883114Sscottl	/* spin waiting for the command to complete */
1999150119Sscottl	then = time_uptime;
200083114Sscottl	do {
2001150119Sscottl		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
2002112679Sscottl			debug(1, "timed out");
200383114Sscottl			return(EIO);
200483114Sscottl		}
200583114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
200665793Smsmith
200783114Sscottl	/* clear the completion flag */
200883114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
200965793Smsmith
201083114Sscottl	/* get the command status */
2011112679Sscottl	status = AAC_GET_MAILBOX(sc, 0);
201283114Sscottl	if (sp != NULL)
201383114Sscottl		*sp = status;
2014151086Sscottl
2015151330Sscottl	if (status != AAC_SRB_STS_SUCCESS)
2016151086Sscottl		return (-1);
201783114Sscottl	return(0);
201865793Smsmith}
201965793Smsmith
202095350Sscottlint
202165793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
202295350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
202365793Smsmith{
202483114Sscottl	debug_called(3);
2025151086Sscottl	mtx_assert(&sc->aac_io_lock, MA_OWNED);
202665793Smsmith
202783114Sscottl	if (datasize > AAC_FIB_DATASIZE)
202883114Sscottl		return(EINVAL);
202965793Smsmith
203083114Sscottl	/*
203183114Sscottl	 * Set up the sync FIB
203283114Sscottl	 */
203383114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
203483114Sscottl				AAC_FIBSTATE_INITIALISED |
203583114Sscottl				AAC_FIBSTATE_EMPTY;
203683114Sscottl	fib->Header.XferState |= xferstate;
203783114Sscottl	fib->Header.Command = command;
203883114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
203983114Sscottl	fib->Header.Size = sizeof(struct aac_fib) + datasize;
204083114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
2041119146Sscottl	fib->Header.SenderFibAddress = 0;	/* Not needed */
204283114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
204383114Sscottl					 offsetof(struct aac_common,
204483114Sscottl						  ac_sync_fib);
204565793Smsmith
204683114Sscottl	/*
204783114Sscottl	 * Give the FIB to the controller, wait for a response.
204883114Sscottl	 */
204983114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
205083114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
205183114Sscottl		debug(2, "IO error");
205283114Sscottl		return(EIO);
205383114Sscottl	}
205481151Sscottl
205595350Sscottl	return (0);
205665793Smsmith}
205765793Smsmith
205883114Sscottl/*
205965793Smsmith * Adapter-space FIB queue manipulation
206065793Smsmith *
206165793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
206265793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
206365793Smsmith */
206465793Smsmithstatic struct {
206583114Sscottl	int		size;
206683114Sscottl	int		notify;
206765793Smsmith} aac_qinfo[] = {
206883114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
206983114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
207083114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
207183114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
207283114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
207383114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
207483114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
207583114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
207665793Smsmith};
207765793Smsmith
207865793Smsmith/*
207981082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
208081082Sscottl * EBUSY if the queue is full.
208165793Smsmith *
208270393Smsmith * Note: it would be more efficient to defer notifying the controller in
208383114Sscottl *	 the case where we may be inserting several entries in rapid succession,
208483114Sscottl *	 but implementing this usefully may be difficult (it would involve a
208583114Sscottl *	 separate queue/notify interface).
208665793Smsmith */
208765793Smsmithstatic int
208881151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
208965793Smsmith{
209083114Sscottl	u_int32_t pi, ci;
2091111691Sscottl	int error;
209283114Sscottl	u_int32_t fib_size;
209383114Sscottl	u_int32_t fib_addr;
209465793Smsmith
209583114Sscottl	debug_called(3);
209682527Sscottl
209783114Sscottl	fib_size = cm->cm_fib->Header.Size;
209883114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
209981151Sscottl
210083114Sscottl	/* get the producer/consumer indices */
210183114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
210283114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
210365793Smsmith
210483114Sscottl	/* wrap the queue? */
210583114Sscottl	if (pi >= aac_qinfo[queue].size)
210683114Sscottl		pi = 0;
210765793Smsmith
210883114Sscottl	/* check for queue full */
210983114Sscottl	if ((pi + 1) == ci) {
211083114Sscottl		error = EBUSY;
211183114Sscottl		goto out;
211283114Sscottl	}
211365793Smsmith
2114129946Sscottl	/*
2115129946Sscottl	 * To avoid a race with its completion interrupt, place this command on
2116129946Sscottl	 * the busy queue prior to advertising it to the controller.
2117129946Sscottl	 */
2118129946Sscottl	aac_enqueue_busy(cm);
2119129946Sscottl
212083114Sscottl	/* populate queue entry */
212183114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
212283114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
212365793Smsmith
212483114Sscottl	/* update producer index */
212583114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
212665793Smsmith
212783114Sscottl	/* notify the adapter if we know how */
212883114Sscottl	if (aac_qinfo[queue].notify != 0)
212983114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
213065793Smsmith
213183114Sscottl	error = 0;
213265793Smsmith
213365793Smsmithout:
213483114Sscottl	return(error);
213565793Smsmith}
213665793Smsmith
213765793Smsmith/*
213882527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
213982527Sscottl * success or ENOENT if the queue is empty.
214065793Smsmith */
214165793Smsmithstatic int
214281082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
214381082Sscottl		struct aac_fib **fib_addr)
214465793Smsmith{
214583114Sscottl	u_int32_t pi, ci;
2146114151Sscottl	u_int32_t fib_index;
2147111691Sscottl	int error;
214883114Sscottl	int notify;
214965793Smsmith
215083114Sscottl	debug_called(3);
215165793Smsmith
215283114Sscottl	/* get the producer/consumer indices */
215383114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
215483114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
215565793Smsmith
215683114Sscottl	/* check for queue empty */
215783114Sscottl	if (ci == pi) {
215883114Sscottl		error = ENOENT;
215983114Sscottl		goto out;
216083114Sscottl	}
2161120129Sscottl
2162120129Sscottl	/* wrap the pi so the following test works */
2163120129Sscottl	if (pi >= aac_qinfo[queue].size)
2164120129Sscottl		pi = 0;
2165120129Sscottl
216683114Sscottl	notify = 0;
216783114Sscottl	if (ci == pi + 1)
216883114Sscottl		notify++;
216981151Sscottl
217083114Sscottl	/* wrap the queue? */
217183114Sscottl	if (ci >= aac_qinfo[queue].size)
217283114Sscottl		ci = 0;
217365793Smsmith
217483114Sscottl	/* fetch the entry */
217583114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
217665793Smsmith
2177114151Sscottl	switch (queue) {
2178114151Sscottl	case AAC_HOST_NORM_CMD_QUEUE:
2179114151Sscottl	case AAC_HOST_HIGH_CMD_QUEUE:
2180114151Sscottl		/*
2181114151Sscottl		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2182114151Sscottl		 * on to hold an address.  For AIF's, the adapter assumes
2183114151Sscottl		 * that it's giving us an address into the array of AIF fibs.
2184114151Sscottl		 * Therefore, we have to convert it to an index.
2185114151Sscottl		 */
2186114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2187114151Sscottl			sizeof(struct aac_fib);
2188114151Sscottl		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2189114151Sscottl		break;
2190114151Sscottl
2191114151Sscottl	case AAC_HOST_NORM_RESP_QUEUE:
2192114151Sscottl	case AAC_HOST_HIGH_RESP_QUEUE:
2193114151Sscottl	{
2194114151Sscottl		struct aac_command *cm;
2195114151Sscottl
2196114151Sscottl		/*
2197114151Sscottl		 * As above, an index is used instead of an actual address.
2198114151Sscottl		 * Gotta shift the index to account for the fast response
2199114151Sscottl		 * bit.  No other correction is needed since this value was
2200114151Sscottl		 * originally provided by the driver via the SenderFibAddress
2201114151Sscottl		 * field.
2202114151Sscottl		 */
2203114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
2204151086Sscottl		cm = sc->aac_commands + (fib_index >> 2);
2205114151Sscottl		*fib_addr = cm->cm_fib;
2206114151Sscottl
2207114151Sscottl		/*
2208114151Sscottl		 * Is this a fast response? If it is, update the fib fields in
2209114151Sscottl		 * local memory since the whole fib isn't DMA'd back up.
2210114151Sscottl		 */
2211114151Sscottl		if (fib_index & 0x01) {
2212114151Sscottl			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2213114151Sscottl			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2214114151Sscottl		}
2215114151Sscottl		break;
2216109088Sscottl	}
2217114151Sscottl	default:
2218114151Sscottl		panic("Invalid queue in aac_dequeue_fib()");
2219114151Sscottl		break;
2220114151Sscottl	}
2221114151Sscottl
222283114Sscottl	/* update consumer index */
222383114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
222465793Smsmith
222583114Sscottl	/* if we have made the queue un-full, notify the adapter */
222683114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
222783114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
222883114Sscottl	error = 0;
222965793Smsmith
223065793Smsmithout:
223183114Sscottl	return(error);
223265793Smsmith}
223365793Smsmith
223483114Sscottl/*
223582527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
223682527Sscottl */
223782527Sscottlstatic int
223882527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
223982527Sscottl{
224083114Sscottl	u_int32_t pi, ci;
2241111691Sscottl	int error;
224283114Sscottl	u_int32_t fib_size;
224383114Sscottl	u_int32_t fib_addr;
224482527Sscottl
224583114Sscottl	debug_called(1);
224682527Sscottl
224783114Sscottl	/* Tell the adapter where the FIB is */
224883114Sscottl	fib_size = fib->Header.Size;
224983114Sscottl	fib_addr = fib->Header.SenderFibAddress;
225083114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
225182527Sscottl
225283114Sscottl	/* get the producer/consumer indices */
225383114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
225483114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
225582527Sscottl
225683114Sscottl	/* wrap the queue? */
225783114Sscottl	if (pi >= aac_qinfo[queue].size)
225883114Sscottl		pi = 0;
225982527Sscottl
226083114Sscottl	/* check for queue full */
226183114Sscottl	if ((pi + 1) == ci) {
226283114Sscottl		error = EBUSY;
226383114Sscottl		goto out;
226483114Sscottl	}
226582527Sscottl
226683114Sscottl	/* populate queue entry */
226783114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
226883114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
226982527Sscottl
227083114Sscottl	/* update producer index */
227183114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
227282527Sscottl
227383114Sscottl	/* notify the adapter if we know how */
227483114Sscottl	if (aac_qinfo[queue].notify != 0)
227583114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
227682527Sscottl
227783114Sscottl	error = 0;
227882527Sscottl
227982527Sscottlout:
228083114Sscottl	return(error);
228182527Sscottl}
228282527Sscottl
228383114Sscottl/*
228470393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
228570393Smsmith * and complain about them.
228670393Smsmith */
228770393Smsmithstatic void
228870393Smsmithaac_timeout(struct aac_softc *sc)
228970393Smsmith{
229083114Sscottl	struct aac_command *cm;
229183114Sscottl	time_t deadline;
2292135289Sscottl	int timedout, code;
229370393Smsmith
229483114Sscottl	/*
2295110426Sscottl	 * Traverse the busy command list, bitch about late commands once
229683114Sscottl	 * only.
229783114Sscottl	 */
2298135289Sscottl	timedout = 0;
2299150119Sscottl	deadline = time_uptime - AAC_CMD_TIMEOUT;
230083114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
230183114Sscottl		if ((cm->cm_timestamp  < deadline)
230283114Sscottl			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
230383114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
230483114Sscottl			device_printf(sc->aac_dev,
230583114Sscottl				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2306150119Sscottl				      cm, (int)(time_uptime-cm->cm_timestamp));
230783114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
2308135289Sscottl			timedout++;
230983114Sscottl		}
231070393Smsmith	}
231170393Smsmith
2312135289Sscottl	if (timedout) {
2313135289Sscottl		code = AAC_GET_FWSTATUS(sc);
2314135289Sscottl		if (code != AAC_UP_AND_RUNNING) {
2315135289Sscottl			device_printf(sc->aac_dev, "WARNING! Controller is no "
2316135289Sscottl				      "longer running! code= 0x%x\n", code);
2317135289Sscottl		}
2318135289Sscottl	}
231983114Sscottl	return;
232070393Smsmith}
232170393Smsmith
232283114Sscottl/*
232383114Sscottl * Interface Function Vectors
232483114Sscottl */
232565793Smsmith
232683114Sscottl/*
232765793Smsmith * Read the current firmware status word.
232865793Smsmith */
232965793Smsmithstatic int
233065793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
233165793Smsmith{
233283114Sscottl	debug_called(3);
233365793Smsmith
233483114Sscottl	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
233565793Smsmith}
233665793Smsmith
233765793Smsmithstatic int
233865793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
233965793Smsmith{
234083114Sscottl	debug_called(3);
234165793Smsmith
234283114Sscottl	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
234365793Smsmith}
234465793Smsmith
234587183Sscottlstatic int
234687183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc)
234787183Sscottl{
234887183Sscottl	int val;
234987183Sscottl
235087183Sscottl	debug_called(3);
235187183Sscottl
235287183Sscottl	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
235387183Sscottl	return (val);
235487183Sscottl}
235587183Sscottl
2356133606Sscottlstatic int
2357133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc)
2358133606Sscottl{
2359133606Sscottl	debug_called(3);
2360133606Sscottl
2361133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
2362133606Sscottl}
2363133606Sscottl
236483114Sscottl/*
236565793Smsmith * Notify the controller of a change in a given queue
236665793Smsmith */
236765793Smsmith
236865793Smsmithstatic void
236965793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
237065793Smsmith{
237183114Sscottl	debug_called(3);
237265793Smsmith
237383114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
237465793Smsmith}
237565793Smsmith
237665793Smsmithstatic void
237765793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
237865793Smsmith{
237983114Sscottl	debug_called(3);
238065793Smsmith
238183114Sscottl	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
238265793Smsmith}
238365793Smsmith
238487183Sscottlstatic void
238587183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit)
238687183Sscottl{
238787183Sscottl	debug_called(3);
238887183Sscottl
238987183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
239087183Sscottl	AAC_FA_HACK(sc);
239187183Sscottl}
239287183Sscottl
2393133606Sscottlstatic void
2394133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit)
2395133606Sscottl{
2396133606Sscottl	debug_called(3);
2397133606Sscottl
2398133606Sscottl	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
2399133606Sscottl}
2400133606Sscottl
240183114Sscottl/*
240265793Smsmith * Get the interrupt reason bits
240365793Smsmith */
240465793Smsmithstatic int
240565793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
240665793Smsmith{
240783114Sscottl	debug_called(3);
240865793Smsmith
240983114Sscottl	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
241065793Smsmith}
241165793Smsmith
241265793Smsmithstatic int
241365793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
241465793Smsmith{
241583114Sscottl	debug_called(3);
241665793Smsmith
241783114Sscottl	return(AAC_GETREG4(sc, AAC_RX_ODBR));
241865793Smsmith}
241965793Smsmith
242087183Sscottlstatic int
242187183Sscottlaac_fa_get_istatus(struct aac_softc *sc)
242287183Sscottl{
242387183Sscottl	int val;
242487183Sscottl
242587183Sscottl	debug_called(3);
242687183Sscottl
242787183Sscottl	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
242887183Sscottl	return (val);
242987183Sscottl}
243087183Sscottl
2431133606Sscottlstatic int
2432133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc)
2433133606Sscottl{
2434133606Sscottl	debug_called(3);
2435133606Sscottl
2436133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
2437133606Sscottl}
2438133606Sscottl
243983114Sscottl/*
244065793Smsmith * Clear some interrupt reason bits
244165793Smsmith */
244265793Smsmithstatic void
244365793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
244465793Smsmith{
244583114Sscottl	debug_called(3);
244665793Smsmith
244783114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
244865793Smsmith}
244965793Smsmith
245065793Smsmithstatic void
245165793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
245265793Smsmith{
245383114Sscottl	debug_called(3);
245465793Smsmith
245583114Sscottl	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
245665793Smsmith}
245765793Smsmith
245887183Sscottlstatic void
245987183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask)
246087183Sscottl{
246187183Sscottl	debug_called(3);
246287183Sscottl
246387183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
246487183Sscottl	AAC_FA_HACK(sc);
246587183Sscottl}
246687183Sscottl
2467133606Sscottlstatic void
2468133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask)
2469133606Sscottl{
2470133606Sscottl	debug_called(3);
2471133606Sscottl
2472133606Sscottl	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
2473133606Sscottl}
2474133606Sscottl
247583114Sscottl/*
247665793Smsmith * Populate the mailbox and set the command word
247765793Smsmith */
247865793Smsmithstatic void
247965793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
248065793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
248165793Smsmith{
248283114Sscottl	debug_called(4);
248365793Smsmith
248483114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
248583114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
248683114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
248783114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
248883114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
248965793Smsmith}
249065793Smsmith
249165793Smsmithstatic void
249265793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
249365793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249465793Smsmith{
249583114Sscottl	debug_called(4);
249665793Smsmith
249783114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
249883114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
249983114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
250083114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
250183114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
250265793Smsmith}
250365793Smsmith
250487183Sscottlstatic void
250587183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
250687183Sscottl		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
250787183Sscottl{
250887183Sscottl	debug_called(4);
250987183Sscottl
251087183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
251187183Sscottl	AAC_FA_HACK(sc);
251287183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
251387183Sscottl	AAC_FA_HACK(sc);
251487183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
251587183Sscottl	AAC_FA_HACK(sc);
251687183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
251787183Sscottl	AAC_FA_HACK(sc);
251887183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
251987183Sscottl	AAC_FA_HACK(sc);
252087183Sscottl}
252187183Sscottl
2522133606Sscottlstatic void
2523133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2524133606Sscottl		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2525133606Sscottl{
2526133606Sscottl	debug_called(4);
2527133606Sscottl
2528133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
2529133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2530133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2531133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2532133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
2533133606Sscottl}
2534133606Sscottl
253583114Sscottl/*
253665793Smsmith * Fetch the immediate command status word
253765793Smsmith */
253865793Smsmithstatic int
2539112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb)
254065793Smsmith{
254183114Sscottl	debug_called(4);
254265793Smsmith
2543112679Sscottl	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
254465793Smsmith}
254565793Smsmith
254665793Smsmithstatic int
2547112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb)
254865793Smsmith{
254983114Sscottl	debug_called(4);
255065793Smsmith
2551112679Sscottl	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
255265793Smsmith}
255365793Smsmith
255487183Sscottlstatic int
2555112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb)
255687183Sscottl{
255787183Sscottl	int val;
255887183Sscottl
255987183Sscottl	debug_called(4);
256087183Sscottl
2561112679Sscottl	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
256287183Sscottl	return (val);
256387183Sscottl}
256487183Sscottl
2565133606Sscottlstatic int
2566133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb)
2567133606Sscottl{
2568133606Sscottl	debug_called(4);
2569133606Sscottl
2570133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
2571133606Sscottl}
2572133606Sscottl
257383114Sscottl/*
257465793Smsmith * Set/clear interrupt masks
257565793Smsmith */
257665793Smsmithstatic void
257765793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
257865793Smsmith{
257983114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
258065793Smsmith
258183114Sscottl	if (enable) {
258283114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
258383114Sscottl	} else {
258483114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
258583114Sscottl	}
258665793Smsmith}
258765793Smsmith
258865793Smsmithstatic void
258965793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
259065793Smsmith{
259183114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
259265793Smsmith
259383114Sscottl	if (enable) {
2594151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
2595151086Sscottl			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
2596151086Sscottl		else
2597151086Sscottl			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
259883114Sscottl	} else {
259983114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
260083114Sscottl	}
260165793Smsmith}
260265793Smsmith
260387183Sscottlstatic void
260487183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable)
260587183Sscottl{
260687183Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
260787183Sscottl
260887183Sscottl	if (enable) {
260987183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
261087183Sscottl		AAC_FA_HACK(sc);
261187183Sscottl	} else {
261287183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
261387183Sscottl		AAC_FA_HACK(sc);
261487183Sscottl	}
261587183Sscottl}
261687183Sscottl
2617133606Sscottlstatic void
2618133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable)
2619133606Sscottl{
2620133606Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
2621133606Sscottl
2622133606Sscottl	if (enable) {
2623151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
2624151086Sscottl			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
2625151086Sscottl		else
2626151086Sscottl			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
2627133606Sscottl	} else {
2628133606Sscottl		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
2629133606Sscottl	}
2630133606Sscottl}
2631133606Sscottl
263283114Sscottl/*
2633151086Sscottl * New comm. interface: Send command functions
2634151086Sscottl */
2635151086Sscottlstatic int
2636151086Sscottlaac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
2637151086Sscottl{
2638151086Sscottl	u_int32_t index, device;
2639151086Sscottl
2640151086Sscottl	debug(2, "send command (new comm.)");
2641151086Sscottl
2642151086Sscottl	index = AAC_GETREG4(sc, AAC_RX_IQUE);
2643151086Sscottl	if (index == 0xffffffffL)
2644151086Sscottl		index = AAC_GETREG4(sc, AAC_RX_IQUE);
2645151086Sscottl	if (index == 0xffffffffL)
2646151086Sscottl		return index;
2647151086Sscottl	aac_enqueue_busy(cm);
2648151086Sscottl	device = index;
2649151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2650151086Sscottl	device += 4;
2651151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2652151086Sscottl	device += 4;
2653151086Sscottl	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
2654151086Sscottl	AAC_SETREG4(sc, AAC_RX_IQUE, index);
2655151086Sscottl	return 0;
2656151086Sscottl}
2657151086Sscottl
2658151086Sscottlstatic int
2659151086Sscottlaac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
2660151086Sscottl{
2661151086Sscottl	u_int32_t index, device;
2662151086Sscottl
2663151086Sscottl	debug(2, "send command (new comm.)");
2664151086Sscottl
2665151086Sscottl	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
2666151086Sscottl	if (index == 0xffffffffL)
2667151086Sscottl		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
2668151086Sscottl	if (index == 0xffffffffL)
2669151086Sscottl		return index;
2670151086Sscottl	aac_enqueue_busy(cm);
2671151086Sscottl	device = index;
2672151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2673151086Sscottl	device += 4;
2674151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2675151086Sscottl	device += 4;
2676151086Sscottl	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
2677151086Sscottl	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
2678151086Sscottl	return 0;
2679151086Sscottl}
2680151086Sscottl
2681151086Sscottl/*
2682151086Sscottl * New comm. interface: get, set outbound queue index
2683151086Sscottl */
2684151086Sscottlstatic int
2685151086Sscottlaac_rx_get_outb_queue(struct aac_softc *sc)
2686151086Sscottl{
2687151086Sscottl	debug_called(3);
2688151086Sscottl
2689151086Sscottl	return(AAC_GETREG4(sc, AAC_RX_OQUE));
2690151086Sscottl}
2691151086Sscottl
2692151086Sscottlstatic int
2693151086Sscottlaac_rkt_get_outb_queue(struct aac_softc *sc)
2694151086Sscottl{
2695151086Sscottl	debug_called(3);
2696151086Sscottl
2697151086Sscottl	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
2698151086Sscottl}
2699151086Sscottl
2700151086Sscottlstatic void
2701151086Sscottlaac_rx_set_outb_queue(struct aac_softc *sc, int index)
2702151086Sscottl{
2703151086Sscottl	debug_called(3);
2704151086Sscottl
2705151086Sscottl	AAC_SETREG4(sc, AAC_RX_OQUE, index);
2706151086Sscottl}
2707151086Sscottl
2708151086Sscottlstatic void
2709151086Sscottlaac_rkt_set_outb_queue(struct aac_softc *sc, int index)
2710151086Sscottl{
2711151086Sscottl	debug_called(3);
2712151086Sscottl
2713151086Sscottl	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
2714151086Sscottl}
2715151086Sscottl
2716151086Sscottl/*
271783114Sscottl * Debugging and Diagnostics
271883114Sscottl */
271965793Smsmith
272083114Sscottl/*
272165793Smsmith * Print some information about the controller.
272265793Smsmith */
272365793Smsmithstatic void
272465793Smsmithaac_describe_controller(struct aac_softc *sc)
272565793Smsmith{
272695350Sscottl	struct aac_fib *fib;
272783114Sscottl	struct aac_adapter_info	*info;
272865793Smsmith
272983114Sscottl	debug_called(2);
273065793Smsmith
2731151222Sscottl	mtx_lock(&sc->aac_io_lock);
2732130006Sscottl	aac_alloc_sync_fib(sc, &fib);
273395350Sscottl
273495350Sscottl	fib->data[0] = 0;
273595350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
273683114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
273795536Sscottl		aac_release_sync_fib(sc);
2738151222Sscottl		mtx_unlock(&sc->aac_io_lock);
273983114Sscottl		return;
274083114Sscottl	}
274165793Smsmith
274283114Sscottl	/* save the kernel revision structure for later use */
2743135095Sscottl	info = (struct aac_adapter_info *)&fib->data[0];
274483114Sscottl	sc->aac_revision = info->KernelRevision;
274595536Sscottl
2746151086Sscottl	device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n",
2747151086Sscottl		AAC_DRIVER_VERSION >> 24,
2748151086Sscottl		(AAC_DRIVER_VERSION >> 16) & 0xFF,
2749151086Sscottl		AAC_DRIVER_VERSION & 0xFF,
2750151086Sscottl		AAC_DRIVER_BUILD);
2751151086Sscottl
2752135095Sscottl	if (bootverbose) {
2753146851Sscottl		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2754146851Sscottl		    "(%dMB cache, %dMB execution), %s\n",
2755135095Sscottl		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2756146851Sscottl		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2757146851Sscottl		    info->BufferMem / (1024 * 1024),
2758146851Sscottl		    info->ExecutionMem / (1024 * 1024),
2759135095Sscottl		    aac_describe_code(aac_battery_platform,
2760135095Sscottl		    info->batteryPlatform));
2761112679Sscottl
2762135095Sscottl		device_printf(sc->aac_dev,
2763135095Sscottl		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2764135095Sscottl		    info->KernelRevision.external.comp.major,
2765135095Sscottl		    info->KernelRevision.external.comp.minor,
2766135095Sscottl		    info->KernelRevision.external.comp.dash,
2767135095Sscottl		    info->KernelRevision.buildNumber,
2768135095Sscottl		    (u_int32_t)(info->SerialNumber & 0xffffff));
2769135095Sscottl
2770112679Sscottl		device_printf(sc->aac_dev, "Supported Options=%b\n",
2771112679Sscottl			      sc->supported_options,
2772112679Sscottl			      "\20"
2773112679Sscottl			      "\1SNAPSHOT"
2774112679Sscottl			      "\2CLUSTERS"
2775112679Sscottl			      "\3WCACHE"
2776112679Sscottl			      "\4DATA64"
2777112679Sscottl			      "\5HOSTTIME"
2778112679Sscottl			      "\6RAID50"
2779112679Sscottl			      "\7WINDOW4GB"
2780112679Sscottl			      "\10SCSIUPGD"
2781112679Sscottl			      "\11SOFTERR"
2782112679Sscottl			      "\12NORECOND"
2783112679Sscottl			      "\13SGMAP64"
2784112679Sscottl			      "\14ALARM"
2785151086Sscottl			      "\15NONDASD"
2786151086Sscottl			      "\16SCSIMGT"
2787151086Sscottl			      "\17RAIDSCSI"
2788151086Sscottl			      "\21ADPTINFO"
2789151086Sscottl			      "\22NEWCOMM"
2790151086Sscottl			      "\23ARRAY64BIT"
2791151086Sscottl			      "\24HEATSENSOR");
2792112679Sscottl	}
2793135095Sscottl	aac_release_sync_fib(sc);
2794151222Sscottl	mtx_unlock(&sc->aac_io_lock);
279565793Smsmith}
279665793Smsmith
279783114Sscottl/*
279865793Smsmith * Look up a text description of a numeric error code and return a pointer to
279965793Smsmith * same.
280065793Smsmith */
280165793Smsmithstatic char *
280265793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code)
280365793Smsmith{
280483114Sscottl	int i;
280565793Smsmith
280683114Sscottl	for (i = 0; table[i].string != NULL; i++)
280783114Sscottl		if (table[i].code == code)
280883114Sscottl			return(table[i].string);
280983114Sscottl	return(table[i + 1].string);
281065793Smsmith}
281165793Smsmith
281283114Sscottl/*
281383114Sscottl * Management Interface
281483114Sscottl */
281565793Smsmith
281665793Smsmithstatic int
2817130585Sphkaac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
281865793Smsmith{
281983114Sscottl	struct aac_softc *sc;
282065793Smsmith
282183114Sscottl	debug_called(2);
282265793Smsmith
282383114Sscottl	sc = dev->si_drv1;
282465793Smsmith
282583114Sscottl	/* Check to make sure the device isn't already open */
282683114Sscottl	if (sc->aac_state & AAC_STATE_OPEN) {
282783114Sscottl		return EBUSY;
282883114Sscottl	}
282983114Sscottl	sc->aac_state |= AAC_STATE_OPEN;
283083114Sscottl
283183114Sscottl	return 0;
283265793Smsmith}
283365793Smsmith
283465793Smsmithstatic int
2835130585Sphkaac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
283665793Smsmith{
283783114Sscottl	struct aac_softc *sc;
283865793Smsmith
283983114Sscottl	debug_called(2);
284065793Smsmith
284183114Sscottl	sc = dev->si_drv1;
284265793Smsmith
284383114Sscottl	/* Mark this unit as no longer open  */
284483114Sscottl	sc->aac_state &= ~AAC_STATE_OPEN;
284583114Sscottl
284683114Sscottl	return 0;
284765793Smsmith}
284865793Smsmith
284965793Smsmithstatic int
2850130585Sphkaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
285165793Smsmith{
285283114Sscottl	union aac_statrequest *as;
285383114Sscottl	struct aac_softc *sc;
285483114Sscottl	int error = 0;
2855119146Sscottl	uint32_t cookie;
285665793Smsmith
285783114Sscottl	debug_called(2);
285865793Smsmith
285983114Sscottl	as = (union aac_statrequest *)arg;
286083114Sscottl	sc = dev->si_drv1;
286183114Sscottl
286283114Sscottl	switch (cmd) {
286383114Sscottl	case AACIO_STATS:
286483114Sscottl		switch (as->as_item) {
286583114Sscottl		case AACQ_FREE:
286683114Sscottl		case AACQ_BIO:
286783114Sscottl		case AACQ_READY:
286883114Sscottl		case AACQ_BUSY:
286983114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
287083114Sscottl			      sizeof(struct aac_qstat));
287183114Sscottl			break;
287283114Sscottl		default:
287383114Sscottl			error = ENOENT;
287483114Sscottl			break;
287583114Sscottl		}
287683114Sscottl	break;
287783114Sscottl
287883114Sscottl	case FSACTL_SENDFIB:
287983114Sscottl		arg = *(caddr_t*)arg;
288083114Sscottl	case FSACTL_LNX_SENDFIB:
288183114Sscottl		debug(1, "FSACTL_SENDFIB");
288283114Sscottl		error = aac_ioctl_sendfib(sc, arg);
288383114Sscottl		break;
288483114Sscottl	case FSACTL_AIF_THREAD:
288583114Sscottl	case FSACTL_LNX_AIF_THREAD:
288683114Sscottl		debug(1, "FSACTL_AIF_THREAD");
288783114Sscottl		error = EINVAL;
288883114Sscottl		break;
288983114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
289083114Sscottl		arg = *(caddr_t*)arg;
289187183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
289283114Sscottl		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
289383114Sscottl		/*
289483114Sscottl		 * Pass the caller out an AdapterFibContext.
289583114Sscottl		 *
289683114Sscottl		 * Note that because we only support one opener, we
289783114Sscottl		 * basically ignore this.  Set the caller's context to a magic
289883114Sscottl		 * number just in case.
289983114Sscottl		 *
290083114Sscottl		 * The Linux code hands the driver a pointer into kernel space,
290183114Sscottl		 * and then trusts it when the caller hands it back.  Aiee!
290283114Sscottl		 * Here, we give it the proc pointer of the per-adapter aif
290383114Sscottl		 * thread. It's only used as a sanity check in other calls.
290483114Sscottl		 */
2905119146Sscottl		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2906119146Sscottl		error = copyout(&cookie, arg, sizeof(cookie));
290783114Sscottl		break;
290883114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
290983114Sscottl		arg = *(caddr_t*)arg;
291083114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
291183114Sscottl		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
291283114Sscottl		error = aac_getnext_aif(sc, arg);
291383114Sscottl		break;
291483114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
291583114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
291683114Sscottl		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
291783114Sscottl		/* don't do anything here */
291883114Sscottl		break;
291983114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
292083114Sscottl		arg = *(caddr_t*)arg;
292183114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
292283114Sscottl		debug(1, "FSACTL_MINIPORT_REV_CHECK");
292383114Sscottl		error = aac_rev_check(sc, arg);
292483114Sscottl		break;
292583114Sscottl	case FSACTL_QUERY_DISK:
292683114Sscottl		arg = *(caddr_t*)arg;
292783114Sscottl	case FSACTL_LNX_QUERY_DISK:
292883114Sscottl		debug(1, "FSACTL_QUERY_DISK");
292983114Sscottl		error = aac_query_disk(sc, arg);
2930151086Sscottl		break;
293183114Sscottl	case FSACTL_DELETE_DISK:
293283114Sscottl	case FSACTL_LNX_DELETE_DISK:
293383114Sscottl		/*
293483114Sscottl		 * We don't trust the underland to tell us when to delete a
293583114Sscottl		 * container, rather we rely on an AIF coming from the
293683114Sscottl		 * controller
293783114Sscottl		 */
293883114Sscottl		error = 0;
293983114Sscottl		break;
2940151086Sscottl	case FSACTL_GET_PCI_INFO:
2941151086Sscottl		arg = *(caddr_t*)arg;
2942151086Sscottl	case FSACTL_LNX_GET_PCI_INFO:
2943151086Sscottl		debug(1, "FSACTL_GET_PCI_INFO");
2944151086Sscottl		error = aac_get_pci_info(sc, arg);
2945151086Sscottl		break;
294670393Smsmith	default:
294787183Sscottl		debug(1, "unsupported cmd 0x%lx\n", cmd);
294883114Sscottl		error = EINVAL;
294983114Sscottl		break;
295070393Smsmith	}
295183114Sscottl	return(error);
295265793Smsmith}
295365793Smsmith
295487183Sscottlstatic int
2955130585Sphkaac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
295687183Sscottl{
295787183Sscottl	struct aac_softc *sc;
295887183Sscottl	int revents;
295987183Sscottl
296087183Sscottl	sc = dev->si_drv1;
296187183Sscottl	revents = 0;
296287183Sscottl
2963133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
296487183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
296587183Sscottl		if (sc->aac_aifq_tail != sc->aac_aifq_head)
296687183Sscottl			revents |= poll_events & (POLLIN | POLLRDNORM);
296787183Sscottl	}
2968133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
296987183Sscottl
297087183Sscottl	if (revents == 0) {
297187183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
297287183Sscottl			selrecord(td, &sc->rcv_select);
297387183Sscottl	}
297487183Sscottl
297587183Sscottl	return (revents);
297687183Sscottl}
297787183Sscottl
2978151086Sscottlstatic void
2979151086Sscottlaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
2980151086Sscottl{
2981151086Sscottl
2982151086Sscottl	switch (event->ev_type) {
2983151086Sscottl	case AAC_EVENT_CMFREE:
2984151086Sscottl		mtx_lock(&sc->aac_io_lock);
2985151086Sscottl		if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) {
2986151086Sscottl			aac_add_event(sc, event);
2987151086Sscottl			mtx_unlock(&sc->aac_io_lock);
2988151086Sscottl			return;
2989151086Sscottl		}
2990151086Sscottl		free(event, M_AACBUF);
2991151109Sscottl		wakeup(arg);
2992151086Sscottl		mtx_unlock(&sc->aac_io_lock);
2993151086Sscottl		break;
2994151086Sscottl	default:
2995151086Sscottl		break;
2996151086Sscottl	}
2997151086Sscottl}
2998151086Sscottl
299983114Sscottl/*
300065793Smsmith * Send a FIB supplied from userspace
300165793Smsmith */
300265793Smsmithstatic int
300365793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
300465793Smsmith{
300583114Sscottl	struct aac_command *cm;
300683114Sscottl	int size, error;
300765793Smsmith
300883114Sscottl	debug_called(2);
300965793Smsmith
301083114Sscottl	cm = NULL;
301165793Smsmith
301283114Sscottl	/*
301383114Sscottl	 * Get a command
301483114Sscottl	 */
3015133540Sscottl	mtx_lock(&sc->aac_io_lock);
301683114Sscottl	if (aac_alloc_command(sc, &cm)) {
3017151086Sscottl		struct aac_event *event;
3018151086Sscottl
3019151086Sscottl		event = malloc(sizeof(struct aac_event), M_AACBUF,
3020151086Sscottl		    M_NOWAIT | M_ZERO);
3021151086Sscottl		if (event == NULL) {
3022151086Sscottl			error = EBUSY;
3023151086Sscottl			goto out;
3024151086Sscottl		}
3025151086Sscottl		event->ev_type = AAC_EVENT_CMFREE;
3026151086Sscottl		event->ev_callback = aac_ioctl_event;
3027151086Sscottl		event->ev_arg = &cm;
3028151086Sscottl		aac_add_event(sc, event);
3029151109Sscottl		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
303083114Sscottl	}
303165793Smsmith
303283114Sscottl	/*
303383114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
303483114Sscottl	 */
303583114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
303683114Sscottl			    sizeof(struct aac_fib_header))) != 0)
303783114Sscottl		goto out;
303883114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
303983114Sscottl	if (size > sizeof(struct aac_fib)) {
3040119146Sscottl		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
304183114Sscottl			      size, sizeof(struct aac_fib));
304283114Sscottl		size = sizeof(struct aac_fib);
304383114Sscottl	}
304483114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
304583114Sscottl		goto out;
304683114Sscottl	cm->cm_fib->Header.Size = size;
3047150119Sscottl	cm->cm_timestamp = time_uptime;
304865793Smsmith
304983114Sscottl	/*
305083114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
305183114Sscottl	 */
3052128258Sscottl	if ((error = aac_wait_command(cm)) != 0) {
3053110426Sscottl		device_printf(sc->aac_dev,
3054110426Sscottl			      "aac_wait_command return %d\n", error);
305583114Sscottl		goto out;
305687183Sscottl	}
305765793Smsmith
305883114Sscottl	/*
305983114Sscottl	 * Copy the FIB and data back out to the caller.
306083114Sscottl	 */
306183114Sscottl	size = cm->cm_fib->Header.Size;
306283114Sscottl	if (size > sizeof(struct aac_fib)) {
3063119146Sscottl		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
306483114Sscottl			      size, sizeof(struct aac_fib));
306583114Sscottl		size = sizeof(struct aac_fib);
306683114Sscottl	}
306783114Sscottl	error = copyout(cm->cm_fib, ufib, size);
306865793Smsmith
306965793Smsmithout:
307083114Sscottl	if (cm != NULL) {
307183114Sscottl		aac_release_command(cm);
307283114Sscottl	}
3073111532Sscottl
3074133540Sscottl	mtx_unlock(&sc->aac_io_lock);
307583114Sscottl	return(error);
307665793Smsmith}
307765793Smsmith
307883114Sscottl/*
307965793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
308082527Sscottl * If the queue fills up, then drop the older entries.
308165793Smsmith */
308265793Smsmithstatic void
308382527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
308465793Smsmith{
308583114Sscottl	struct aac_aif_command *aif;
308683114Sscottl	struct aac_container *co, *co_next;
308795350Sscottl	struct aac_mntinfo *mi;
308895350Sscottl	struct aac_mntinforesp *mir = NULL;
308983114Sscottl	u_int16_t rsize;
309087183Sscottl	int next, found;
3091115760Sscottl	int count = 0, added = 0, i = 0;
309265793Smsmith
309383114Sscottl	debug_called(2);
309465793Smsmith
309583114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
309683114Sscottl	aac_print_aif(sc, aif);
309782527Sscottl
309883114Sscottl	/* Is it an event that we should care about? */
309983114Sscottl	switch (aif->command) {
310083114Sscottl	case AifCmdEventNotify:
310183114Sscottl		switch (aif->data.EN.type) {
310283114Sscottl		case AifEnAddContainer:
310383114Sscottl		case AifEnDeleteContainer:
310483114Sscottl			/*
310583114Sscottl			 * A container was added or deleted, but the message
310683114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
310783114Sscottl			 * containers and sort things out.
310883114Sscottl			 */
3109130006Sscottl			aac_alloc_sync_fib(sc, &fib);
311095350Sscottl			mi = (struct aac_mntinfo *)&fib->data[0];
311183114Sscottl			do {
311283114Sscottl				/*
311383114Sscottl				 * Ask the controller for its containers one at
311483114Sscottl				 * a time.
311583114Sscottl				 * XXX What if the controller's list changes
311683114Sscottl				 * midway through this enumaration?
311783114Sscottl				 * XXX This should be done async.
311883114Sscottl				 */
311995966Sscottl				bzero(mi, sizeof(struct aac_mntinfo));
312095966Sscottl				mi->Command = VM_NameServe;
312195966Sscottl				mi->MntType = FT_FILESYS;
312295350Sscottl				mi->MntCount = i;
312383114Sscottl				rsize = sizeof(mir);
312495350Sscottl				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
312595350Sscottl						 sizeof(struct aac_mntinfo))) {
3126115760Sscottl					printf("Error probing container %d\n",
312783114Sscottl					      i);
312883114Sscottl					continue;
312983114Sscottl				}
313095350Sscottl				mir = (struct aac_mntinforesp *)&fib->data[0];
3131115760Sscottl				/* XXX Need to check if count changed */
3132115760Sscottl				count = mir->MntRespCount;
313383114Sscottl				/*
313483114Sscottl				 * Check the container against our list.
313583114Sscottl				 * co->co_found was already set to 0 in a
313683114Sscottl				 * previous run.
313783114Sscottl				 */
313895350Sscottl				if ((mir->Status == ST_OK) &&
313995350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
314083114Sscottl					found = 0;
314183114Sscottl					TAILQ_FOREACH(co,
314283114Sscottl						      &sc->aac_container_tqh,
314383114Sscottl						      co_link) {
314483114Sscottl						if (co->co_mntobj.ObjectId ==
314595350Sscottl						    mir->MntTable[0].ObjectId) {
314683114Sscottl							co->co_found = 1;
314783114Sscottl							found = 1;
314883114Sscottl							break;
314983114Sscottl						}
315083114Sscottl					}
315183114Sscottl					/*
315283114Sscottl					 * If the container matched, continue
315383114Sscottl					 * in the list.
315483114Sscottl					 */
315583114Sscottl					if (found) {
315683114Sscottl						i++;
315783114Sscottl						continue;
315883114Sscottl					}
315983114Sscottl
316083114Sscottl					/*
316183114Sscottl					 * This is a new container.  Do all the
3162110426Sscottl					 * appropriate things to set it up.
3163110426Sscottl					 */
316495350Sscottl					aac_add_container(sc, mir, 1);
316583114Sscottl					added = 1;
316683114Sscottl				}
316783114Sscottl				i++;
3168115760Sscottl			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
316995350Sscottl			aac_release_sync_fib(sc);
317083114Sscottl
317183114Sscottl			/*
317283114Sscottl			 * Go through our list of containers and see which ones
317383114Sscottl			 * were not marked 'found'.  Since the controller didn't
317483114Sscottl			 * list them they must have been deleted.  Do the
317583114Sscottl			 * appropriate steps to destroy the device.  Also reset
317683114Sscottl			 * the co->co_found field.
317783114Sscottl			 */
317883114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
317983114Sscottl			while (co != NULL) {
318083114Sscottl				if (co->co_found == 0) {
3181151086Sscottl					mtx_unlock(&sc->aac_io_lock);
3182151086Sscottl					mtx_lock(&Giant);
318383114Sscottl					device_delete_child(sc->aac_dev,
318483114Sscottl							    co->co_disk);
3185151086Sscottl					mtx_unlock(&Giant);
3186151086Sscottl					mtx_lock(&sc->aac_io_lock);
318783114Sscottl					co_next = TAILQ_NEXT(co, co_link);
3188133540Sscottl					mtx_lock(&sc->aac_container_lock);
318983114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
319083114Sscottl						     co_link);
3191133540Sscottl					mtx_unlock(&sc->aac_container_lock);
3192133541Sscottl					free(co, M_AACBUF);
319383114Sscottl					co = co_next;
319483114Sscottl				} else {
319583114Sscottl					co->co_found = 0;
319683114Sscottl					co = TAILQ_NEXT(co, co_link);
319783114Sscottl				}
319882527Sscottl			}
319982527Sscottl
320083114Sscottl			/* Attach the newly created containers */
3201151086Sscottl			if (added) {
3202151086Sscottl				mtx_unlock(&sc->aac_io_lock);
3203151086Sscottl				mtx_lock(&Giant);
320483114Sscottl				bus_generic_attach(sc->aac_dev);
3205151086Sscottl				mtx_unlock(&Giant);
3206151086Sscottl				mtx_lock(&sc->aac_io_lock);
3207151086Sscottl			}
320883114Sscottl
3209105528Sphk			break;
321082527Sscottl
321183114Sscottl		default:
321283114Sscottl			break;
321382527Sscottl		}
321482527Sscottl
321582527Sscottl	default:
321683114Sscottl		break;
321782527Sscottl	}
321882527Sscottl
321983114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3220133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
322183114Sscottl	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
322283114Sscottl	if (next != sc->aac_aifq_tail) {
322383114Sscottl		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
322487183Sscottl		sc->aac_aifq_head = next;
322587183Sscottl
322687183Sscottl		/* On the off chance that someone is sleeping for an aif... */
322787183Sscottl		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
322887183Sscottl			wakeup(sc->aac_aifq);
322987183Sscottl		/* Wakeup any poll()ers */
3230122352Stanimura		selwakeuppri(&sc->rcv_select, PRIBIO);
323183114Sscottl	}
3232133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
323382527Sscottl
323483114Sscottl	return;
323565793Smsmith}
323665793Smsmith
323783114Sscottl/*
323870393Smsmith * Return the Revision of the driver to userspace and check to see if the
323982527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
324082527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
324182527Sscottl * returning what the card reported.
324265793Smsmith */
324365793Smsmithstatic int
324481189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
324565793Smsmith{
324683114Sscottl	struct aac_rev_check rev_check;
324783114Sscottl	struct aac_rev_check_resp rev_check_resp;
324883114Sscottl	int error = 0;
324965793Smsmith
325083114Sscottl	debug_called(2);
325165793Smsmith
325283114Sscottl	/*
325383114Sscottl	 * Copyin the revision struct from userspace
325483114Sscottl	 */
325583114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
325681082Sscottl			sizeof(struct aac_rev_check))) != 0) {
325783114Sscottl		return error;
325883114Sscottl	}
325965793Smsmith
326083114Sscottl	debug(2, "Userland revision= %d\n",
326183114Sscottl	      rev_check.callingRevision.buildNumber);
326265793Smsmith
326383114Sscottl	/*
326483114Sscottl	 * Doctor up the response struct.
326583114Sscottl	 */
326683114Sscottl	rev_check_resp.possiblyCompatible = 1;
326783114Sscottl	rev_check_resp.adapterSWRevision.external.ul =
326883114Sscottl	    sc->aac_revision.external.ul;
326983114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
327083114Sscottl	    sc->aac_revision.buildNumber;
327165793Smsmith
327283114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
327383114Sscottl			sizeof(struct aac_rev_check_resp)));
327465793Smsmith}
327565793Smsmith
327683114Sscottl/*
327765793Smsmith * Pass the caller the next AIF in their queue
327865793Smsmith */
327965793Smsmithstatic int
328081189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
328165793Smsmith{
328283114Sscottl	struct get_adapter_fib_ioctl agf;
3283111691Sscottl	int error;
328465793Smsmith
328583114Sscottl	debug_called(2);
328665793Smsmith
328783114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
328865793Smsmith
328983114Sscottl		/*
329083114Sscottl		 * Check the magic number that we gave the caller.
329183114Sscottl		 */
3292119146Sscottl		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
329383114Sscottl			error = EFAULT;
329483114Sscottl		} else {
329581189Sscottl			error = aac_return_aif(sc, agf.AifFib);
329683114Sscottl			if ((error == EAGAIN) && (agf.Wait)) {
329783114Sscottl				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
329883114Sscottl				while (error == EAGAIN) {
329983114Sscottl					error = tsleep(sc->aac_aifq, PRIBIO |
330083114Sscottl						       PCATCH, "aacaif", 0);
330183114Sscottl					if (error == 0)
330283114Sscottl						error = aac_return_aif(sc,
330383114Sscottl						    agf.AifFib);
330483114Sscottl				}
330583114Sscottl				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
330683114Sscottl			}
330765793Smsmith		}
330865793Smsmith	}
330983114Sscottl	return(error);
331065793Smsmith}
331165793Smsmith
331283114Sscottl/*
331370393Smsmith * Hand the next AIF off the top of the queue out to userspace.
331470393Smsmith */
331570393Smsmithstatic int
331681189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr)
331770393Smsmith{
3318121173Sscottl	int next, error;
331970393Smsmith
332083114Sscottl	debug_called(2);
332170393Smsmith
3322133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
332383114Sscottl	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
3324133540Sscottl		mtx_unlock(&sc->aac_aifq_lock);
3325121173Sscottl		return (EAGAIN);
332683114Sscottl	}
3327121173Sscottl
3328121173Sscottl	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
3329121173Sscottl	error = copyout(&sc->aac_aifq[next], uptr,
3330121173Sscottl			sizeof(struct aac_aif_command));
3331121173Sscottl	if (error)
3332121173Sscottl		device_printf(sc->aac_dev,
3333121173Sscottl		    "aac_return_aif: copyout returned %d\n", error);
3334121173Sscottl	else
3335121173Sscottl		sc->aac_aifq_tail = next;
3336121173Sscottl
3337133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
333883114Sscottl	return(error);
333970393Smsmith}
334082527Sscottl
3341151086Sscottlstatic int
3342151086Sscottlaac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
3343151086Sscottl{
3344151086Sscottl	struct aac_pci_info {
3345151086Sscottl		u_int32_t bus;
3346151086Sscottl		u_int32_t slot;
3347151086Sscottl	} pciinf;
3348151086Sscottl	int error;
3349151086Sscottl
3350151086Sscottl	debug_called(2);
3351151086Sscottl
3352151086Sscottl	pciinf.bus = pci_get_bus(sc->aac_dev);
3353151086Sscottl	pciinf.slot = pci_get_slot(sc->aac_dev);
3354151086Sscottl
3355151086Sscottl	error = copyout((caddr_t)&pciinf, uptr,
3356151086Sscottl			sizeof(struct aac_pci_info));
3357151086Sscottl
3358151086Sscottl	return (error);
3359151086Sscottl}
3360151086Sscottl
336183114Sscottl/*
336282527Sscottl * Give the userland some information about the container.  The AAC arch
336382527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
336482527Sscottl * the containers to have b:t:l numbers.  Fake it.
336582527Sscottl */
336682527Sscottlstatic int
336782527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
336882527Sscottl{
336983114Sscottl	struct aac_query_disk query_disk;
337083114Sscottl	struct aac_container *co;
337183114Sscottl	struct aac_disk	*disk;
337283114Sscottl	int error, id;
337382527Sscottl
337483114Sscottl	debug_called(2);
337582527Sscottl
337683114Sscottl	disk = NULL;
337782527Sscottl
337883114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
337983114Sscottl		       sizeof(struct aac_query_disk));
338083114Sscottl	if (error)
338183114Sscottl		return (error);
338282527Sscottl
338383114Sscottl	id = query_disk.ContainerNumber;
338483114Sscottl	if (id == -1)
338583114Sscottl		return (EINVAL);
338682527Sscottl
3387133540Sscottl	mtx_lock(&sc->aac_container_lock);
338883114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
338983114Sscottl		if (co->co_mntobj.ObjectId == id)
339083114Sscottl			break;
339183114Sscottl		}
339282527Sscottl
3393105528Sphk	if (co == NULL) {
339483114Sscottl			query_disk.Valid = 0;
339583114Sscottl			query_disk.Locked = 0;
339683114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
3397105528Sphk	} else {
3398105528Sphk		disk = device_get_softc(co->co_disk);
3399105528Sphk		query_disk.Valid = 1;
3400105528Sphk		query_disk.Locked =
3401105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
3402105528Sphk		query_disk.Deleted = 0;
3403105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
3404105528Sphk		query_disk.Target = disk->unit;
3405105528Sphk		query_disk.Lun = 0;
3406105528Sphk		query_disk.UnMapped = 0;
3407111525Sscottl		sprintf(&query_disk.diskDeviceName[0], "%s%d",
3408125975Sphk		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
3409105528Sphk	}
3410133540Sscottl	mtx_unlock(&sc->aac_container_lock);
341182527Sscottl
341283114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
341383114Sscottl			sizeof(struct aac_query_disk));
341483114Sscottl
341583114Sscottl	return (error);
341682527Sscottl}
341782527Sscottl
341895536Sscottlstatic void
341995536Sscottlaac_get_bus_info(struct aac_softc *sc)
342095536Sscottl{
342195536Sscottl	struct aac_fib *fib;
342295536Sscottl	struct aac_ctcfg *c_cmd;
342395536Sscottl	struct aac_ctcfg_resp *c_resp;
342495536Sscottl	struct aac_vmioctl *vmi;
342595536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
342695536Sscottl	struct aac_getbusinf businfo;
3427110426Sscottl	struct aac_sim *caminf;
342895536Sscottl	device_t child;
342995536Sscottl	int i, found, error;
343095536Sscottl
3431130006Sscottl	aac_alloc_sync_fib(sc, &fib);
343295536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
343395966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
343495536Sscottl
343595536Sscottl	c_cmd->Command = VM_ContainerConfig;
343695536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
343795536Sscottl	c_cmd->param = 0;
343895536Sscottl
343995536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
344095536Sscottl	    sizeof(struct aac_ctcfg));
344195536Sscottl	if (error) {
344295536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
344395536Sscottl		    "VM_ContainerConfig command\n", error);
344495536Sscottl		aac_release_sync_fib(sc);
344595536Sscottl		return;
344695536Sscottl	}
344795536Sscottl
344895536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
344995536Sscottl	if (c_resp->Status != ST_OK) {
345095536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
345195536Sscottl		    c_resp->Status);
345295536Sscottl		aac_release_sync_fib(sc);
345395536Sscottl		return;
345495536Sscottl	}
345595536Sscottl
345695536Sscottl	sc->scsi_method_id = c_resp->param;
345795536Sscottl
345895536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
345995966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
346095966Sscottl
346195536Sscottl	vmi->Command = VM_Ioctl;
346295536Sscottl	vmi->ObjType = FT_DRIVE;
346395536Sscottl	vmi->MethId = sc->scsi_method_id;
346495536Sscottl	vmi->ObjId = 0;
346595536Sscottl	vmi->IoctlCmd = GetBusInfo;
346695536Sscottl
346795536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
346895536Sscottl	    sizeof(struct aac_vmioctl));
346995536Sscottl	if (error) {
347095536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
347195536Sscottl		    error);
347295536Sscottl		aac_release_sync_fib(sc);
347395536Sscottl		return;
347495536Sscottl	}
347595536Sscottl
347695536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
347795536Sscottl	if (vmi_resp->Status != ST_OK) {
347895536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
347995536Sscottl		    vmi_resp->Status);
348095536Sscottl		aac_release_sync_fib(sc);
348195536Sscottl		return;
348295536Sscottl	}
348395536Sscottl
348495536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
348595536Sscottl	aac_release_sync_fib(sc);
348695536Sscottl
348795536Sscottl	found = 0;
348895536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
348995536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
349095536Sscottl			continue;
349195536Sscottl
3492110428Sscottl		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3493110428Sscottl		    M_AACBUF, M_NOWAIT | M_ZERO);
3494143838Sscottl		if (caminf == NULL) {
3495143838Sscottl			device_printf(sc->aac_dev,
3496143838Sscottl			    "No memory to add passthrough bus %d\n", i);
3497143838Sscottl			break;
3498151086Sscottl		};
349995536Sscottl
350095536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
350195536Sscottl		if (child == NULL) {
3502143838Sscottl			device_printf(sc->aac_dev,
3503143838Sscottl			    "device_add_child failed for passthrough bus %d\n",
3504143838Sscottl			    i);
3505143838Sscottl			free(caminf, M_AACBUF);
3506151086Sscottl			break;
350795536Sscottl		}
350895536Sscottl
350995536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
351095536Sscottl		caminf->BusNumber = i;
351195536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
351295536Sscottl		caminf->aac_sc = sc;
3513110432Sscottl		caminf->sim_dev = child;
351495536Sscottl
351595536Sscottl		device_set_ivars(child, caminf);
351695536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
3517110426Sscottl		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
351895536Sscottl
351995536Sscottl		found = 1;
352095536Sscottl	}
352195536Sscottl
352295536Sscottl	if (found)
352395536Sscottl		bus_generic_attach(sc->aac_dev);
352495536Sscottl
352595536Sscottl	return;
352695536Sscottl}
3527