aac.c revision 114151
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 *	$FreeBSD: head/sys/dev/aac/aac.c 114151 2003-04-28 06:16:20Z scottl $
3065793Smsmith */
3165793Smsmith
3265793Smsmith/*
3365793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3465793Smsmith */
3565793Smsmith
3681151Sscottl#include "opt_aac.h"
3781151Sscottl
3882527Sscottl/* #include <stddef.h> */
3965793Smsmith#include <sys/param.h>
4065793Smsmith#include <sys/systm.h>
4165793Smsmith#include <sys/malloc.h>
4265793Smsmith#include <sys/kernel.h>
4382527Sscottl#include <sys/kthread.h>
4481154Sscottl#include <sys/sysctl.h>
4587183Sscottl#include <sys/poll.h>
46112946Sphk#include <sys/ioccom.h>
4765793Smsmith
4865793Smsmith#include <sys/bus.h>
4965793Smsmith#include <sys/conf.h>
5065793Smsmith#include <sys/signalvar.h>
5170393Smsmith#include <sys/time.h>
5282527Sscottl#include <sys/eventhandler.h>
5365793Smsmith
5465793Smsmith#include <machine/bus_memio.h>
5565793Smsmith#include <machine/bus.h>
5665793Smsmith#include <machine/resource.h>
5765793Smsmith
5865793Smsmith#include <dev/aac/aacreg.h>
5970393Smsmith#include <dev/aac/aac_ioctl.h>
6065793Smsmith#include <dev/aac/aacvar.h>
6165793Smsmith#include <dev/aac/aac_tables.h>
6265793Smsmith
6365793Smsmithstatic void	aac_startup(void *arg);
6483114Sscottlstatic void	aac_add_container(struct aac_softc *sc,
6595350Sscottl				  struct aac_mntinforesp *mir, int f);
6695536Sscottlstatic void	aac_get_bus_info(struct aac_softc *sc);
6765793Smsmith
6865793Smsmith/* Command Processing */
6970393Smsmithstatic void	aac_timeout(struct aac_softc *sc);
7065793Smsmithstatic int	aac_start(struct aac_command *cm);
7165793Smsmithstatic void	aac_complete(void *context, int pending);
7265793Smsmithstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7365793Smsmithstatic void	aac_bio_complete(struct aac_command *cm);
7465793Smsmithstatic int	aac_wait_command(struct aac_command *cm, int timeout);
75110426Sscottlstatic void	aac_command_thread(struct aac_softc *sc);
7665793Smsmith
7765793Smsmith/* Command Buffer Management */
7881082Sscottlstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
7981082Sscottl				       int nseg, int error);
8070393Smsmithstatic int	aac_alloc_commands(struct aac_softc *sc);
81111141Sscottlstatic void	aac_free_commands(struct aac_softc *sc);
8265793Smsmithstatic void	aac_map_command(struct aac_command *cm);
8365793Smsmithstatic void	aac_unmap_command(struct aac_command *cm);
8465793Smsmith
8565793Smsmith/* Hardware Interface */
8681082Sscottlstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
8781082Sscottl			       int error);
8890275Sscottlstatic int	aac_check_firmware(struct aac_softc *sc);
8965793Smsmithstatic int	aac_init(struct aac_softc *sc);
9065793Smsmithstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
9181082Sscottl				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
9281082Sscottl				 u_int32_t arg3, u_int32_t *sp);
9381082Sscottlstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
9481151Sscottl				struct aac_command *cm);
9581082Sscottlstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
9683114Sscottl				u_int32_t *fib_size, struct aac_fib **fib_addr);
9782527Sscottlstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
9882527Sscottl				     struct aac_fib *fib);
9965793Smsmith
10087183Sscottl/* Falcon/PPC interface */
10187183Sscottlstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
10287183Sscottlstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
10387183Sscottlstatic int	aac_fa_get_istatus(struct aac_softc *sc);
10487183Sscottlstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
10587183Sscottlstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
10687183Sscottl				   u_int32_t arg0, u_int32_t arg1,
10787183Sscottl				   u_int32_t arg2, u_int32_t arg3);
108112679Sscottlstatic int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
10987183Sscottlstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
11087183Sscottl
11187183Sscottlstruct aac_interface aac_fa_interface = {
11287183Sscottl	aac_fa_get_fwstatus,
11387183Sscottl	aac_fa_qnotify,
11487183Sscottl	aac_fa_get_istatus,
11587183Sscottl	aac_fa_clear_istatus,
11687183Sscottl	aac_fa_set_mailbox,
117112679Sscottl	aac_fa_get_mailbox,
11887183Sscottl	aac_fa_set_interrupts
11987183Sscottl};
12087183Sscottl
12165793Smsmith/* StrongARM interface */
12265793Smsmithstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
12365793Smsmithstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
12465793Smsmithstatic int	aac_sa_get_istatus(struct aac_softc *sc);
12565793Smsmithstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
12665793Smsmithstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
12781082Sscottl				   u_int32_t arg0, u_int32_t arg1,
12881082Sscottl				   u_int32_t arg2, u_int32_t arg3);
129112679Sscottlstatic int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13065793Smsmithstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13165793Smsmith
13265793Smsmithstruct aac_interface aac_sa_interface = {
13383114Sscottl	aac_sa_get_fwstatus,
13483114Sscottl	aac_sa_qnotify,
13583114Sscottl	aac_sa_get_istatus,
13683114Sscottl	aac_sa_clear_istatus,
13783114Sscottl	aac_sa_set_mailbox,
138112679Sscottl	aac_sa_get_mailbox,
13983114Sscottl	aac_sa_set_interrupts
14065793Smsmith};
14165793Smsmith
14283114Sscottl/* i960Rx interface */
14365793Smsmithstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
14465793Smsmithstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
14565793Smsmithstatic int	aac_rx_get_istatus(struct aac_softc *sc);
14665793Smsmithstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
14765793Smsmithstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
14881082Sscottl				   u_int32_t arg0, u_int32_t arg1,
14981082Sscottl				   u_int32_t arg2, u_int32_t arg3);
150112679Sscottlstatic int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
15165793Smsmithstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
15265793Smsmith
15365793Smsmithstruct aac_interface aac_rx_interface = {
15483114Sscottl	aac_rx_get_fwstatus,
15583114Sscottl	aac_rx_qnotify,
15683114Sscottl	aac_rx_get_istatus,
15783114Sscottl	aac_rx_clear_istatus,
15883114Sscottl	aac_rx_set_mailbox,
159112679Sscottl	aac_rx_get_mailbox,
16083114Sscottl	aac_rx_set_interrupts
16165793Smsmith};
16265793Smsmith
16365793Smsmith/* Debugging and Diagnostics */
16465793Smsmithstatic void	aac_describe_controller(struct aac_softc *sc);
16582567Sscottlstatic char	*aac_describe_code(struct aac_code_lookup *table,
16681082Sscottl				   u_int32_t code);
16765793Smsmith
16865793Smsmith/* Management Interface */
16965793Smsmithstatic d_open_t		aac_open;
17065793Smsmithstatic d_close_t	aac_close;
17165793Smsmithstatic d_ioctl_t	aac_ioctl;
17287183Sscottlstatic d_poll_t		aac_poll;
17381082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
17481082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
17583114Sscottl					   struct aac_fib *fib);
17681189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
17781189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
17881189Sscottlstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
17982527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
18065793Smsmith
18165793Smsmith#define AAC_CDEV_MAJOR	150
18265793Smsmith
18365793Smsmithstatic struct cdevsw aac_cdevsw = {
184111815Sphk	.d_open =	aac_open,
185111815Sphk	.d_close =	aac_close,
186111815Sphk	.d_ioctl =	aac_ioctl,
187111815Sphk	.d_poll =	aac_poll,
188111815Sphk	.d_name =	"aac",
189111815Sphk	.d_maj =	AAC_CDEV_MAJOR,
19065793Smsmith};
19165793Smsmith
19282527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
19382527Sscottl
19481154Sscottl/* sysctl node */
19581154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
19681154Sscottl
19783114Sscottl/*
19883114Sscottl * Device Interface
19983114Sscottl */
20065793Smsmith
20183114Sscottl/*
20265793Smsmith * Initialise the controller and softc
20365793Smsmith */
20465793Smsmithint
20565793Smsmithaac_attach(struct aac_softc *sc)
20665793Smsmith{
20783114Sscottl	int error, unit;
20865793Smsmith
20983114Sscottl	debug_called(1);
21065793Smsmith
21183114Sscottl	/*
21283114Sscottl	 * Initialise per-controller queues.
21383114Sscottl	 */
21483114Sscottl	aac_initq_free(sc);
21583114Sscottl	aac_initq_ready(sc);
21683114Sscottl	aac_initq_busy(sc);
21783114Sscottl	aac_initq_bio(sc);
21865793Smsmith
21983114Sscottl	/*
22083114Sscottl	 * Initialise command-completion task.
22183114Sscottl	 */
22283114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
22365793Smsmith
22483114Sscottl	/* disable interrupts before we enable anything */
22583114Sscottl	AAC_MASK_INTERRUPTS(sc);
22665793Smsmith
22783114Sscottl	/* mark controller as suspended until we get ourselves organised */
22883114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
22965793Smsmith
23083114Sscottl	/*
23190275Sscottl	 * Check that the firmware on the card is supported.
23290275Sscottl	 */
23390275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
23490275Sscottl		return(error);
23590275Sscottl
23695350Sscottl	/* Init the sync fib lock */
23795350Sscottl	AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock");
23895350Sscottl
23983114Sscottl	/*
24083114Sscottl	 * Initialise the adapter.
24183114Sscottl	 */
24283114Sscottl	if ((error = aac_init(sc)) != 0)
24383114Sscottl		return(error);
24465793Smsmith
24583114Sscottl	/*
24683114Sscottl	 * Print a little information about the controller.
24783114Sscottl	 */
24883114Sscottl	aac_describe_controller(sc);
24965793Smsmith
25083114Sscottl	/*
251111532Sscottl	 * Initialize locks
25283114Sscottl	 */
253111532Sscottl	AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
25483114Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
25587183Sscottl	AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
256111532Sscottl	AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock");
25782527Sscottl
25887183Sscottl	/*
259111532Sscottl	 * Register to probe our containers later.
26087183Sscottl	 */
26183114Sscottl	sc->aac_ich.ich_func = aac_startup;
26283114Sscottl	sc->aac_ich.ich_arg = sc;
26383114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
26483114Sscottl		device_printf(sc->aac_dev,
26583114Sscottl			      "can't establish configuration hook\n");
26683114Sscottl		return(ENXIO);
26783114Sscottl	}
26865793Smsmith
26983114Sscottl	/*
27083114Sscottl	 * Make the control device.
27183114Sscottl	 */
27283114Sscottl	unit = device_get_unit(sc->aac_dev);
273108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
274108329Srwatson				 0640, "aac%d", unit);
27583114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
27683114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
27783114Sscottl	sc->aac_dev_t->si_drv1 = sc;
27865793Smsmith
27983114Sscottl	/* Create the AIF thread */
280110426Sscottl	if (kthread_create((void(*)(void *))aac_command_thread, sc,
281104354Sscottl			   &sc->aifthread, 0, 0, "aac%daif", unit))
28283114Sscottl		panic("Could not create AIF thread\n");
28382527Sscottl
28483114Sscottl	/* Register the shutdown method to only be called post-dump */
285110427Sscottl	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
286110427Sscottl	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
287110427Sscottl		device_printf(sc->aac_dev,
288110427Sscottl			      "shutdown event registration failed\n");
28982527Sscottl
29095536Sscottl	/* Register with CAM for the non-DASD devices */
291112679Sscottl	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
292110426Sscottl		TAILQ_INIT(&sc->aac_sim_tqh);
29395536Sscottl		aac_get_bus_info(sc);
294110426Sscottl	}
29595536Sscottl
29683114Sscottl	return(0);
29765793Smsmith}
29865793Smsmith
29983114Sscottl/*
30065793Smsmith * Probe for containers, create disks.
30165793Smsmith */
30265793Smsmithstatic void
30365793Smsmithaac_startup(void *arg)
30465793Smsmith{
30583114Sscottl	struct aac_softc *sc;
30695350Sscottl	struct aac_fib *fib;
30795350Sscottl	struct aac_mntinfo *mi;
30895350Sscottl	struct aac_mntinforesp *mir = NULL;
30983114Sscottl	int i = 0;
31065793Smsmith
31183114Sscottl	debug_called(1);
31265793Smsmith
31383114Sscottl	sc = (struct aac_softc *)arg;
31465793Smsmith
31583114Sscottl	/* disconnect ourselves from the intrhook chain */
31683114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
31765793Smsmith
31895536Sscottl	aac_alloc_sync_fib(sc, &fib, 0);
31995350Sscottl	mi = (struct aac_mntinfo *)&fib->data[0];
32095350Sscottl
32183114Sscottl	/* loop over possible containers */
32283114Sscottl	do {
32383114Sscottl		/* request information on this container */
32495966Sscottl		bzero(mi, sizeof(struct aac_mntinfo));
32595966Sscottl		mi->Command = VM_NameServe;
32695966Sscottl		mi->MntType = FT_FILESYS;
32795350Sscottl		mi->MntCount = i;
32895350Sscottl		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
32995350Sscottl				 sizeof(struct aac_mntinfo))) {
33083114Sscottl			debug(2, "error probing container %d", i);
33183114Sscottl			continue;
33283114Sscottl		}
33365793Smsmith
33495350Sscottl		mir = (struct aac_mntinforesp *)&fib->data[0];
33595350Sscottl		aac_add_container(sc, mir, 0);
33683114Sscottl		i++;
33795350Sscottl	} while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS));
33865793Smsmith
33995350Sscottl	aac_release_sync_fib(sc);
34095350Sscottl
34183114Sscottl	/* poke the bus to actually attach the child devices */
34283114Sscottl	if (bus_generic_attach(sc->aac_dev))
34383114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
34465793Smsmith
34583114Sscottl	/* mark the controller up */
34683114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
34770393Smsmith
34883114Sscottl	/* enable interrupts now */
34983114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
35065793Smsmith}
35165793Smsmith
35283114Sscottl/*
35383114Sscottl * Create a device to respresent a new container
35483114Sscottl */
35583114Sscottlstatic void
35695350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
35783114Sscottl{
35883114Sscottl	struct aac_container *co;
35983114Sscottl	device_t child;
36083114Sscottl
36183114Sscottl	/*
36283114Sscottl	 * Check container volume type for validity.  Note that many of
36383114Sscottl	 * the possible types may never show up.
36483114Sscottl	 */
36583114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
366110428Sscottl		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
367110428Sscottl		       M_NOWAIT | M_ZERO);
36883114Sscottl		if (co == NULL)
36983114Sscottl			panic("Out of memory?!\n");
37083114Sscottl		debug(1, "id %x  name '%.16s'  size %u  type %d",
37183114Sscottl		      mir->MntTable[0].ObjectId,
37283114Sscottl		      mir->MntTable[0].FileSystemName,
37383114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
37483114Sscottl
37595536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
37683114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
37783114Sscottl		else
37883114Sscottl			device_set_ivars(child, co);
37983114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
38083114Sscottl				mir->MntTable[0].VolType));
38183114Sscottl		co->co_disk = child;
38283114Sscottl		co->co_found = f;
38383114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
38483114Sscottl		      sizeof(struct aac_mntobj));
38587310Sscottl		AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
38683114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
38783114Sscottl		AAC_LOCK_RELEASE(&sc->aac_container_lock);
38883114Sscottl	}
38983114Sscottl}
39083114Sscottl
39183114Sscottl/*
39265793Smsmith * Free all of the resources associated with (sc)
39365793Smsmith *
39465793Smsmith * Should not be called if the controller is active.
39565793Smsmith */
39665793Smsmithvoid
39765793Smsmithaac_free(struct aac_softc *sc)
39865793Smsmith{
399110604Sscottl
40083114Sscottl	debug_called(1);
40165793Smsmith
40283114Sscottl	/* remove the control device */
40383114Sscottl	if (sc->aac_dev_t != NULL)
40483114Sscottl		destroy_dev(sc->aac_dev_t);
40565793Smsmith
40683114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
407111141Sscottl	aac_free_commands(sc);
40883114Sscottl	if (sc->aac_fib_dmat)
40983114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
41065793Smsmith
411110604Sscottl	free(sc->aac_commands, M_AACBUF);
412110604Sscottl
41383114Sscottl	/* destroy the common area */
41483114Sscottl	if (sc->aac_common) {
41583114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
41683114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
41783114Sscottl				sc->aac_common_dmamap);
41883114Sscottl	}
41983114Sscottl	if (sc->aac_common_dmat)
42083114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
42165793Smsmith
42283114Sscottl	/* disconnect the interrupt handler */
42383114Sscottl	if (sc->aac_intr)
42483114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
42583114Sscottl	if (sc->aac_irq != NULL)
42683114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
42783114Sscottl				     sc->aac_irq);
42865793Smsmith
42983114Sscottl	/* destroy data-transfer DMA tag */
43083114Sscottl	if (sc->aac_buffer_dmat)
43183114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
43265793Smsmith
43383114Sscottl	/* destroy the parent DMA tag */
43483114Sscottl	if (sc->aac_parent_dmat)
43583114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
43665793Smsmith
43783114Sscottl	/* release the register window mapping */
43883114Sscottl	if (sc->aac_regs_resource != NULL)
43983114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
44083114Sscottl				     sc->aac_regs_rid, sc->aac_regs_resource);
44165793Smsmith}
44265793Smsmith
44383114Sscottl/*
44465793Smsmith * Disconnect from the controller completely, in preparation for unload.
44565793Smsmith */
44665793Smsmithint
44765793Smsmithaac_detach(device_t dev)
44865793Smsmith{
44983114Sscottl	struct aac_softc *sc;
450110426Sscottl	struct aac_container *co;
451110426Sscottl	struct aac_sim	*sim;
45283114Sscottl	int error;
45365793Smsmith
45483114Sscottl	debug_called(1);
45565793Smsmith
45683114Sscottl	sc = device_get_softc(dev);
45783114Sscottl
45883114Sscottl	if (sc->aac_state & AAC_STATE_OPEN)
459110426Sscottl		return(EBUSY);
46065793Smsmith
461110426Sscottl	/* Remove the child containers */
462110428Sscottl	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
463110426Sscottl		error = device_delete_child(dev, co->co_disk);
464110426Sscottl		if (error)
465110426Sscottl			return (error);
466111196Sscottl		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
467110428Sscottl		free(co, M_AACBUF);
468110426Sscottl	}
469110426Sscottl
470110426Sscottl	/* Remove the CAM SIMs */
471110428Sscottl	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
472110428Sscottl		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
473110426Sscottl		error = device_delete_child(dev, sim->sim_dev);
474110426Sscottl		if (error)
475110426Sscottl			return (error);
476110428Sscottl		free(sim, M_AACBUF);
477110426Sscottl	}
478110426Sscottl
47983114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
48083114Sscottl		sc->aifflags |= AAC_AIFFLAGS_EXIT;
48183114Sscottl		wakeup(sc->aifthread);
48283114Sscottl		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
48383114Sscottl	}
48482527Sscottl
48583114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
48683114Sscottl		panic("Cannot shutdown AIF thread\n");
48782527Sscottl
48883114Sscottl	if ((error = aac_shutdown(dev)))
48983114Sscottl		return(error);
49065793Smsmith
491110427Sscottl	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
492110427Sscottl
49383114Sscottl	aac_free(sc);
49465793Smsmith
49583114Sscottl	return(0);
49665793Smsmith}
49765793Smsmith
49883114Sscottl/*
49965793Smsmith * Bring the controller down to a dormant state and detach all child devices.
50065793Smsmith *
50165793Smsmith * This function is called before detach or system shutdown.
50265793Smsmith *
50370393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
50465793Smsmith * allow shutdown if any device is open.
50565793Smsmith */
50665793Smsmithint
50765793Smsmithaac_shutdown(device_t dev)
50865793Smsmith{
50983114Sscottl	struct aac_softc *sc;
51095350Sscottl	struct aac_fib *fib;
51195350Sscottl	struct aac_close_command *cc;
51265793Smsmith
51383114Sscottl	debug_called(1);
51465793Smsmith
51583114Sscottl	sc = device_get_softc(dev);
51665793Smsmith
51783114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
51865793Smsmith
51983114Sscottl	/*
52083114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
52183114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
52283114Sscottl	 * We've been closed and all I/O completed already
52382527Sscottl	 */
52483114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
52583114Sscottl
52695536Sscottl	aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
52795350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
52895350Sscottl
52995966Sscottl	bzero(cc, sizeof(struct aac_close_command));
53095350Sscottl	cc->Command = VM_CloseAll;
53195350Sscottl	cc->ContainerId = 0xffffffff;
53295350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
53395350Sscottl	    sizeof(struct aac_close_command)))
53483114Sscottl		printf("FAILED.\n");
535110426Sscottl	else
536110426Sscottl		printf("done\n");
537110426Sscottl#if 0
53883114Sscottl	else {
53995350Sscottl		fib->data[0] = 0;
54083114Sscottl		/*
54183114Sscottl		 * XXX Issuing this command to the controller makes it shut down
54283114Sscottl		 * but also keeps it from coming back up without a reset of the
54383114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
54483114Sscottl		 * driver module with the intent to reload it later.
54583114Sscottl		 */
54695350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
54795350Sscottl		    fib, 1)) {
54883114Sscottl			printf("FAILED.\n");
54983114Sscottl		} else {
55083114Sscottl			printf("done.\n");
55183114Sscottl		}
55265793Smsmith	}
553110426Sscottl#endif
55465793Smsmith
55583114Sscottl	AAC_MASK_INTERRUPTS(sc);
55665793Smsmith
55783114Sscottl	return(0);
55865793Smsmith}
55965793Smsmith
56083114Sscottl/*
56165793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
56265793Smsmith */
56365793Smsmithint
56465793Smsmithaac_suspend(device_t dev)
56565793Smsmith{
56683114Sscottl	struct aac_softc *sc;
56765793Smsmith
56883114Sscottl	debug_called(1);
56965793Smsmith
57083114Sscottl	sc = device_get_softc(dev);
57183114Sscottl
57283114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
57383114Sscottl
57483114Sscottl	AAC_MASK_INTERRUPTS(sc);
57583114Sscottl	return(0);
57665793Smsmith}
57765793Smsmith
57883114Sscottl/*
57965793Smsmith * Bring the controller back to a state ready for operation.
58065793Smsmith */
58165793Smsmithint
58265793Smsmithaac_resume(device_t dev)
58365793Smsmith{
58483114Sscottl	struct aac_softc *sc;
58565793Smsmith
58683114Sscottl	debug_called(1);
58783114Sscottl
58883114Sscottl	sc = device_get_softc(dev);
58983114Sscottl
59083114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
59183114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
59283114Sscottl	return(0);
59365793Smsmith}
59465793Smsmith
59583114Sscottl/*
59665793Smsmith * Take an interrupt.
59765793Smsmith */
59865793Smsmithvoid
59965793Smsmithaac_intr(void *arg)
60065793Smsmith{
60183114Sscottl	struct aac_softc *sc;
602110426Sscottl	u_int32_t *resp_queue;
60383114Sscottl	u_int16_t reason;
60465793Smsmith
60583114Sscottl	debug_called(2);
60665793Smsmith
60783114Sscottl	sc = (struct aac_softc *)arg;
60865793Smsmith
609109088Sscottl	/*
610109088Sscottl	 * Optimize the common case of adapter response interrupts.
611109088Sscottl	 * We must read from the card prior to processing the responses
612109088Sscottl	 * to ensure the clear is flushed prior to accessing the queues.
613109088Sscottl	 * Reading the queues from local memory might save us a PCI read.
614109088Sscottl	 */
615109088Sscottl	resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE];
616109088Sscottl	if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX])
617109088Sscottl		reason = AAC_DB_RESPONSE_READY;
618109088Sscottl	else
619109088Sscottl		reason = AAC_GET_ISTATUS(sc);
620109088Sscottl	AAC_CLEAR_ISTATUS(sc, reason);
621109088Sscottl	(void)AAC_GET_ISTATUS(sc);
62265793Smsmith
623109088Sscottl	/* It's not ok to return here because of races with the previous step */
624109088Sscottl	if (reason & AAC_DB_RESPONSE_READY)
625111143Sscottl		/* handle completion processing */
626111532Sscottl		taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
627109088Sscottl
62887183Sscottl	/* controller wants to talk to the log */
629110426Sscottl	if (reason & AAC_DB_PRINTF) {
630110426Sscottl		if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
631110426Sscottl			sc->aifflags |= AAC_AIFFLAGS_PRINTF;
632110426Sscottl		} else
633110426Sscottl			aac_print_printf(sc);
634110426Sscottl	}
63565793Smsmith
63683114Sscottl	/* controller has a message for us? */
63783114Sscottl	if (reason & AAC_DB_COMMAND_READY) {
63883114Sscottl		if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
639110426Sscottl			sc->aifflags |= AAC_AIFFLAGS_AIF;
640110426Sscottl		} else {
641110426Sscottl			/*
642110426Sscottl			 * XXX If the kthread is dead and we're at this point,
643110426Sscottl			 * there are bigger problems than just figuring out
644110426Sscottl			 * what to do with an AIF.
645110426Sscottl			 */
64683114Sscottl		}
647110426Sscottl
64883114Sscottl	}
649110426Sscottl
650110426Sscottl	if ((sc->aifflags & AAC_AIFFLAGS_PENDING) != 0)
651110426Sscottl		/* XXX Should this be done with cv_signal? */
652110426Sscottl		wakeup(sc->aifthread);
653109088Sscottl}
65483114Sscottl
65583114Sscottl/*
65683114Sscottl * Command Processing
65783114Sscottl */
65865793Smsmith
65983114Sscottl/*
66065793Smsmith * Start as much queued I/O as possible on the controller
66165793Smsmith */
66295536Sscottlvoid
66365793Smsmithaac_startio(struct aac_softc *sc)
66465793Smsmith{
66583114Sscottl	struct aac_command *cm;
66665793Smsmith
66783114Sscottl	debug_called(2);
66865793Smsmith
66983114Sscottl	for (;;) {
67083114Sscottl		/*
67183114Sscottl		 * Try to get a command that's been put off for lack of
67283114Sscottl		 * resources
67383114Sscottl		 */
67483114Sscottl		cm = aac_dequeue_ready(sc);
67565793Smsmith
67683114Sscottl		/*
67783114Sscottl		 * Try to build a command off the bio queue (ignore error
67883114Sscottl		 * return)
67983114Sscottl		 */
68083114Sscottl		if (cm == NULL)
68183114Sscottl			aac_bio_command(sc, &cm);
68265793Smsmith
68383114Sscottl		/* nothing to do? */
68483114Sscottl		if (cm == NULL)
68583114Sscottl			break;
68665793Smsmith
68783114Sscottl		/* try to give the command to the controller */
68883114Sscottl		if (aac_start(cm) == EBUSY) {
68983114Sscottl			/* put it on the ready queue for later */
69083114Sscottl			aac_requeue_ready(cm);
69183114Sscottl			break;
69283114Sscottl		}
69365793Smsmith	}
69465793Smsmith}
69565793Smsmith
69683114Sscottl/*
69765793Smsmith * Deliver a command to the controller; allocate controller resources at the
69865793Smsmith * last moment when possible.
69965793Smsmith */
70065793Smsmithstatic int
70165793Smsmithaac_start(struct aac_command *cm)
70265793Smsmith{
70383114Sscottl	struct aac_softc *sc;
70483114Sscottl	int error;
70565793Smsmith
70683114Sscottl	debug_called(2);
70765793Smsmith
70883114Sscottl	sc = cm->cm_sc;
70965793Smsmith
71083114Sscottl	/* get the command mapped */
71183114Sscottl	aac_map_command(cm);
71265793Smsmith
713114151Sscottl	/* Fix up the address values in the FIB.  Use the command array index
714114151Sscottl	 * instead of a pointer since these fields are only 32 bits.  Shift
715114151Sscottl	 * the SenderFibAddress over to make room for the fast response bit.
716114151Sscottl	 */
717114151Sscottl	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
71883114Sscottl	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
71983114Sscottl
72083114Sscottl	/* save a pointer to the command for speedy reverse-lookup */
721111152Sscottl	cm->cm_fib->Header.SenderData = cm->cm_index;
72283114Sscottl	/* put the FIB on the outbound queue */
72383114Sscottl	error = aac_enqueue_fib(sc, cm->cm_queue, cm);
72483114Sscottl	return(error);
72565793Smsmith}
72665793Smsmith
72783114Sscottl/*
72865793Smsmith * Handle notification of one or more FIBs coming from the controller.
72965793Smsmith */
73065793Smsmithstatic void
731110426Sscottlaac_command_thread(struct aac_softc *sc)
73265793Smsmith{
73383114Sscottl	struct aac_fib *fib;
73483114Sscottl	u_int32_t fib_size;
73583114Sscottl	int size;
73665793Smsmith
73783114Sscottl	debug_called(2);
73865793Smsmith
73983114Sscottl	sc->aifflags |= AAC_AIFFLAGS_RUNNING;
74065793Smsmith
74183114Sscottl	while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) {
742110426Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
743110426Sscottl			tsleep(sc->aifthread, PRIBIO, "aifthd",
744110426Sscottl			       AAC_PERIODIC_INTERVAL * hz);
74582527Sscottl
746110426Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
747110426Sscottl			aac_timeout(sc);
748110426Sscottl
749110426Sscottl		/* Check the hardware printf message buffer */
750110426Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PRINTF) != 0) {
751110426Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_PRINTF;
752110426Sscottl			aac_print_printf(sc);
753110426Sscottl		}
754110426Sscottl
755111532Sscottl		/* See if any FIBs need to be allocated */
756111532Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
757111532Sscottl			AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
758111532Sscottl			aac_alloc_commands(sc);
759111532Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
760111532Sscottl			AAC_LOCK_RELEASE(&sc->aac_io_lock);
761111532Sscottl		}
762111532Sscottl
763111532Sscottl		/* While we're here, check to see if any commands are stuck */
764110426Sscottl		while (sc->aifflags & AAC_AIFFLAGS_AIF) {
76583114Sscottl			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
766110426Sscottl					    &fib_size, &fib)) {
767110426Sscottl				sc->aifflags &= ~AAC_AIFFLAGS_AIF;
76883114Sscottl				break;	/* nothing to do */
769110426Sscottl			}
77083114Sscottl
77183114Sscottl			AAC_PRINT_FIB(sc, fib);
77283114Sscottl
77383114Sscottl			switch (fib->Header.Command) {
77483114Sscottl			case AifRequest:
77583114Sscottl				aac_handle_aif(sc, fib);
77683114Sscottl				break;
77783114Sscottl			default:
77883114Sscottl				device_printf(sc->aac_dev, "unknown command "
77983114Sscottl					      "from controller\n");
78083114Sscottl				break;
78183114Sscottl			}
78282527Sscottl
78383114Sscottl			if ((fib->Header.XferState == 0) ||
78483114Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
78583114Sscottl				break;
78682527Sscottl
787110426Sscottl			/* Return the AIF to the controller. */
78883114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
78983114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
79083114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
79182527Sscottl
79283114Sscottl				/* XXX Compute the Size field? */
79383114Sscottl				size = fib->Header.Size;
79483114Sscottl				if (size > sizeof(struct aac_fib)) {
79595536Sscottl					size = sizeof(struct aac_fib);
79683114Sscottl					fib->Header.Size = size;
79783114Sscottl				}
79883114Sscottl				/*
79983114Sscottl				 * Since we did not generate this command, it
80083114Sscottl				 * cannot go through the normal
80183114Sscottl				 * enqueue->startio chain.
80283114Sscottl				 */
80383114Sscottl				aac_enqueue_response(sc,
80483114Sscottl						     AAC_ADAP_NORM_RESP_QUEUE,
80583114Sscottl						     fib);
80683114Sscottl			}
80782527Sscottl		}
80865793Smsmith	}
80983114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
81083114Sscottl	wakeup(sc->aac_dev);
81165793Smsmith
81283114Sscottl	mtx_lock(&Giant);
81383114Sscottl	kthread_exit(0);
81465793Smsmith}
81565793Smsmith
81683114Sscottl/*
817111143Sscottl * Process completed commands.
81865793Smsmith */
81965793Smsmithstatic void
820111143Sscottlaac_complete(void *context, int pending)
82165793Smsmith{
822111143Sscottl	struct aac_softc *sc;
82383114Sscottl	struct aac_command *cm;
82483114Sscottl	struct aac_fib *fib;
82583114Sscottl	u_int32_t fib_size;
82665793Smsmith
82783114Sscottl	debug_called(2);
82865793Smsmith
829111143Sscottl	sc = (struct aac_softc *)context;
830111143Sscottl
831111532Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
832111532Sscottl
833111143Sscottl	/* pull completed commands off the queue */
83483114Sscottl	for (;;) {
83583114Sscottl		/* look for completed FIBs on our queue */
83683114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
83783114Sscottl				    &fib))
83883114Sscottl			break;	/* nothing to do */
839111143Sscottl
84083114Sscottl		/* get the command, unmap and queue for later processing */
841111152Sscottl		cm = sc->aac_commands + fib->Header.SenderData;
84283114Sscottl		if (cm == NULL) {
84383114Sscottl			AAC_PRINT_FIB(sc, fib);
844111143Sscottl			break;
84583114Sscottl		}
84665793Smsmith
847111143Sscottl		aac_remove_busy(cm);
848111143Sscottl		aac_unmap_command(cm);		/* XXX defer? */
84983114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
85083114Sscottl
85183114Sscottl		/* is there a completion handler? */
85283114Sscottl		if (cm->cm_complete != NULL) {
85383114Sscottl			cm->cm_complete(cm);
85483114Sscottl		} else {
85583114Sscottl			/* assume that someone is sleeping on this command */
85683114Sscottl			wakeup(cm);
85783114Sscottl		}
85865793Smsmith	}
85970393Smsmith
86083114Sscottl	/* see if we can start some more I/O */
86183114Sscottl	aac_startio(sc);
862111532Sscottl
863111532Sscottl	AAC_LOCK_RELEASE(&sc->aac_io_lock);
86465793Smsmith}
86565793Smsmith
86683114Sscottl/*
86765793Smsmith * Handle a bio submitted from a disk device.
86865793Smsmith */
86965793Smsmithvoid
87065793Smsmithaac_submit_bio(struct bio *bp)
87165793Smsmith{
87283114Sscottl	struct aac_disk *ad;
87383114Sscottl	struct aac_softc *sc;
87465793Smsmith
87583114Sscottl	debug_called(2);
87665793Smsmith
877111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
87883114Sscottl	sc = ad->ad_controller;
87983114Sscottl
88083114Sscottl	/* queue the BIO and try to get some work done */
88183114Sscottl	aac_enqueue_bio(sc, bp);
88283114Sscottl	aac_startio(sc);
88365793Smsmith}
88465793Smsmith
88583114Sscottl/*
88665793Smsmith * Get a bio and build a command to go with it.
88765793Smsmith */
88865793Smsmithstatic int
88965793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
89065793Smsmith{
89183114Sscottl	struct aac_command *cm;
89283114Sscottl	struct aac_fib *fib;
89383114Sscottl	struct aac_disk *ad;
89483114Sscottl	struct bio *bp;
89565793Smsmith
89683114Sscottl	debug_called(2);
89765793Smsmith
89883114Sscottl	/* get the resources we will need */
89983114Sscottl	cm = NULL;
90083114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
90183114Sscottl		goto fail;
90283114Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
90383114Sscottl		goto fail;
90465793Smsmith
90583114Sscottl	/* fill out the command */
90683114Sscottl	cm->cm_data = (void *)bp->bio_data;
90783114Sscottl	cm->cm_datalen = bp->bio_bcount;
90883114Sscottl	cm->cm_complete = aac_bio_complete;
90983114Sscottl	cm->cm_private = bp;
91083114Sscottl	cm->cm_timestamp = time_second;
91183114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
91265793Smsmith
91383114Sscottl	/* build the FIB */
91483114Sscottl	fib = cm->cm_fib;
915112856Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
91683114Sscottl	fib->Header.XferState =
917109088Sscottl		AAC_FIBSTATE_HOSTOWNED   |
918109088Sscottl		AAC_FIBSTATE_INITIALISED |
919109088Sscottl		AAC_FIBSTATE_EMPTY	 |
920109088Sscottl		AAC_FIBSTATE_FROMHOST	 |
921109088Sscottl		AAC_FIBSTATE_REXPECTED   |
922109088Sscottl		AAC_FIBSTATE_NORM	 |
923109088Sscottl		AAC_FIBSTATE_ASYNC	 |
924109088Sscottl		AAC_FIBSTATE_FAST_RESPONSE;
92565793Smsmith
92683114Sscottl	/* build the read/write request */
927111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
928112856Sscottl
929112856Sscottl	if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
930112856Sscottl		fib->Header.Command = ContainerCommand;
931112856Sscottl		if (bp->bio_cmd == BIO_READ) {
932112856Sscottl			struct aac_blockread *br;
933112856Sscottl			br = (struct aac_blockread *)&fib->data[0];
934112856Sscottl			br->Command = VM_CtBlockRead;
935112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
936112856Sscottl			br->BlockNumber = bp->bio_pblkno;
937112856Sscottl			br->ByteCount = bp->bio_bcount;
938112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread);
939112856Sscottl			cm->cm_sgtable = &br->SgMap;
940112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
941112856Sscottl		} else {
942112856Sscottl			struct aac_blockwrite *bw;
943112856Sscottl			bw = (struct aac_blockwrite *)&fib->data[0];
944112856Sscottl			bw->Command = VM_CtBlockWrite;
945112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
946112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
947112856Sscottl			bw->ByteCount = bp->bio_bcount;
948112856Sscottl			bw->Stable = CUNSTABLE;
949112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite);
950112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
951112856Sscottl			cm->cm_sgtable = &bw->SgMap;
952112856Sscottl		}
95383114Sscottl	} else {
954112856Sscottl		fib->Header.Command = ContainerCommand64;
955112856Sscottl		if (bp->bio_cmd == BIO_READ) {
956112856Sscottl			struct aac_blockread64 *br;
957112856Sscottl			br = (struct aac_blockread64 *)&fib->data[0];
958112856Sscottl			br->Command = VM_CtHostRead64;
959112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
960112856Sscottl			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
961112856Sscottl			br->BlockNumber = bp->bio_pblkno;
962112856Sscottl			br->Pad = 0;
963112856Sscottl			br->Flags = 0;
964112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread64);
965112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
966112856Sscottl			(struct aac_sg_table64 *)cm->cm_sgtable = &br->SgMap64;
967112856Sscottl		} else {
968112856Sscottl			struct aac_blockwrite64 *bw;
969112856Sscottl			bw = (struct aac_blockwrite64 *)&fib->data[0];
970112856Sscottl			bw->Command = VM_CtHostWrite64;
971112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
972112856Sscottl			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
973112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
974112856Sscottl			bw->Pad = 0;
975112856Sscottl			bw->Flags = 0;
976112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite64);
977112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
978112856Sscottl			(struct aac_sg_table64 *)cm->cm_sgtable = &bw->SgMap64;
979112856Sscottl		}
98083114Sscottl	}
98165793Smsmith
98283114Sscottl	*cmp = cm;
98383114Sscottl	return(0);
98465793Smsmith
98565793Smsmithfail:
98683114Sscottl	if (bp != NULL)
98783114Sscottl		aac_enqueue_bio(sc, bp);
98883114Sscottl	if (cm != NULL)
98983114Sscottl		aac_release_command(cm);
99083114Sscottl	return(ENOMEM);
99165793Smsmith}
99265793Smsmith
99383114Sscottl/*
99465793Smsmith * Handle a bio-instigated command that has been completed.
99565793Smsmith */
99665793Smsmithstatic void
99765793Smsmithaac_bio_complete(struct aac_command *cm)
99865793Smsmith{
99983114Sscottl	struct aac_blockread_response *brr;
100083114Sscottl	struct aac_blockwrite_response *bwr;
100183114Sscottl	struct bio *bp;
100283114Sscottl	AAC_FSAStatus status;
100365793Smsmith
100483114Sscottl	/* fetch relevant status and then release the command */
100583114Sscottl	bp = (struct bio *)cm->cm_private;
1006111691Sscottl	if (bp->bio_cmd == BIO_READ) {
100783114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
100883114Sscottl		status = brr->Status;
100983114Sscottl	} else {
101083114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
101183114Sscottl		status = bwr->Status;
101283114Sscottl	}
101383114Sscottl	aac_release_command(cm);
101465793Smsmith
101583114Sscottl	/* fix up the bio based on status */
101683114Sscottl	if (status == ST_OK) {
101783114Sscottl		bp->bio_resid = 0;
101883114Sscottl	} else {
101983114Sscottl		bp->bio_error = EIO;
102083114Sscottl		bp->bio_flags |= BIO_ERROR;
102183114Sscottl		/* pass an error string out to the disk layer */
102283114Sscottl		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
102383114Sscottl						    status);
102483114Sscottl	}
102583114Sscottl	aac_biodone(bp);
102665793Smsmith}
102765793Smsmith
102883114Sscottl/*
102965793Smsmith * Submit a command to the controller, return when it completes.
103087183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
103187183Sscottl *     be stuck here forever.  At the same time, signals are not caught
103287183Sscottl *     because there is a risk that a signal could wakeup the tsleep before
103387183Sscottl *     the card has a chance to complete the command.  The passed in timeout
103487183Sscottl *     is ignored for the same reason.  Since there is no way to cancel a
103587183Sscottl *     command in progress, we should probably create a 'dead' queue where
103687183Sscottl *     commands go that have been interrupted/timed-out/etc, that keeps them
103787183Sscottl *     out of the free pool.  That way, if the card is just slow, it won't
103887183Sscottl *     spam the memory of a command that has been recycled.
103965793Smsmith */
104065793Smsmithstatic int
104165793Smsmithaac_wait_command(struct aac_command *cm, int timeout)
104265793Smsmith{
1043111532Sscottl	struct aac_softc *sc;
1044111532Sscottl	int error = 0;
104565793Smsmith
104683114Sscottl	debug_called(2);
104765793Smsmith
1048111532Sscottl	sc = cm->cm_sc;
1049111532Sscottl
105083114Sscottl	/* Put the command on the ready queue and get things going */
105183114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
105283114Sscottl	aac_enqueue_ready(cm);
1053111532Sscottl	aac_startio(sc);
105483114Sscottl	while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
1055111532Sscottl		error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
105683114Sscottl	}
105783114Sscottl	return(error);
105865793Smsmith}
105965793Smsmith
106083114Sscottl/*
106183114Sscottl *Command Buffer Management
106283114Sscottl */
106365793Smsmith
106483114Sscottl/*
106565793Smsmith * Allocate a command.
106665793Smsmith */
106795536Sscottlint
106865793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
106965793Smsmith{
107083114Sscottl	struct aac_command *cm;
107165793Smsmith
107283114Sscottl	debug_called(3);
107365793Smsmith
1074110604Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL) {
1075112856Sscottl		if (sc->total_fibs < sc->aac_max_fibs) {
1076112856Sscottl			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1077112856Sscottl			wakeup(sc->aifthread);
1078112856Sscottl		}
1079111532Sscottl		return (EBUSY);
1080110604Sscottl	}
108165793Smsmith
108283114Sscottl	*cmp = cm;
108383114Sscottl	return(0);
108470393Smsmith}
108570393Smsmith
108683114Sscottl/*
108770393Smsmith * Release a command back to the freelist.
108870393Smsmith */
108995536Sscottlvoid
109070393Smsmithaac_release_command(struct aac_command *cm)
109170393Smsmith{
109283114Sscottl	debug_called(3);
109370393Smsmith
109483114Sscottl	/* (re)initialise the command/FIB */
109583114Sscottl	cm->cm_sgtable = NULL;
109683114Sscottl	cm->cm_flags = 0;
109783114Sscottl	cm->cm_complete = NULL;
109883114Sscottl	cm->cm_private = NULL;
109983114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
110083114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
110183114Sscottl	cm->cm_fib->Header.Flags = 0;
110283114Sscottl	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
110365793Smsmith
110483114Sscottl	/*
110583114Sscottl	 * These are duplicated in aac_start to cover the case where an
110683114Sscottl	 * intermediate stage may have destroyed them.  They're left
110783114Sscottl	 * initialised here for debugging purposes only.
110883114Sscottl	 */
110983114Sscottl	cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
1110109088Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1111109088Sscottl	cm->cm_fib->Header.SenderData = 0;
111265793Smsmith
111383114Sscottl	aac_enqueue_free(cm);
111465793Smsmith}
111565793Smsmith
111683114Sscottl/*
111770393Smsmith * Map helper for command/FIB allocation.
111865793Smsmith */
111965793Smsmithstatic void
112070393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
112165793Smsmith{
1122111141Sscottl	uint32_t	*fibphys;
112365793Smsmith
1124111141Sscottl	fibphys = (uint32_t *)arg;
112565793Smsmith
112683114Sscottl	debug_called(3);
112783114Sscottl
1128110604Sscottl	*fibphys = segs[0].ds_addr;
112965793Smsmith}
113065793Smsmith
113183114Sscottl/*
113270393Smsmith * Allocate and initialise commands/FIBs for this adapter.
113365793Smsmith */
113470393Smsmithstatic int
113570393Smsmithaac_alloc_commands(struct aac_softc *sc)
113665793Smsmith{
113783114Sscottl	struct aac_command *cm;
1138110604Sscottl	struct aac_fibmap *fm;
1139111141Sscottl	uint32_t fibphys;
1140110604Sscottl	int i, error;
114165793Smsmith
1142112679Sscottl	debug_called(2);
114365793Smsmith
1144112679Sscottl	if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
1145110604Sscottl		return (ENOMEM);
1146110604Sscottl
1147111141Sscottl	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1148112679Sscottl	if (fm == NULL)
1149112679Sscottl		return (ENOMEM);
1150110604Sscottl
115183114Sscottl	/* allocate the FIBs in DMAable memory and load them */
1152110604Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1153110604Sscottl			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1154110426Sscottl		device_printf(sc->aac_dev,
1155110426Sscottl			      "Not enough contiguous memory available.\n");
1156111141Sscottl		free(fm, M_AACBUF);
1157102602Sscottl		return (ENOMEM);
115883114Sscottl	}
1159109716Sscottl
1160110604Sscottl	bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1161110604Sscottl			AAC_FIB_COUNT * sizeof(struct aac_fib),
1162110604Sscottl			aac_map_command_helper, &fibphys, 0);
1163109716Sscottl
1164109716Sscottl	/* initialise constant fields in the command structure */
1165110604Sscottl	bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
116683114Sscottl	for (i = 0; i < AAC_FIB_COUNT; i++) {
1167111141Sscottl		cm = sc->aac_commands + sc->total_fibs;
1168110604Sscottl		fm->aac_commands = cm;
116983114Sscottl		cm->cm_sc = sc;
1170110604Sscottl		cm->cm_fib = fm->aac_fibs + i;
1171111141Sscottl		cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib));
1172111152Sscottl		cm->cm_index = sc->total_fibs;
117365793Smsmith
1174110604Sscottl		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1175110604Sscottl					       &cm->cm_datamap)) == 0)
117683114Sscottl			aac_release_command(cm);
1177111141Sscottl		else
1178111141Sscottl			break;
1179111141Sscottl		sc->total_fibs++;
118083114Sscottl	}
1181110604Sscottl
1182111141Sscottl	if (i > 0) {
1183111141Sscottl		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1184112679Sscottl		debug(1, "total_fibs= %d\n", sc->total_fibs);
1185111141Sscottl		return (0);
1186111141Sscottl	}
1187110604Sscottl
1188111141Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1189111141Sscottl	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1190111141Sscottl	free(fm, M_AACBUF);
1191111141Sscottl	return (ENOMEM);
119265793Smsmith}
119365793Smsmith
119483114Sscottl/*
119570393Smsmith * Free FIBs owned by this adapter.
119665793Smsmith */
119765793Smsmithstatic void
1198111141Sscottlaac_free_commands(struct aac_softc *sc)
119965793Smsmith{
1200111141Sscottl	struct aac_fibmap *fm;
1201110604Sscottl	struct aac_command *cm;
120283114Sscottl	int i;
120365793Smsmith
120483114Sscottl	debug_called(1);
120565793Smsmith
1206111141Sscottl	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1207111141Sscottl
1208111141Sscottl		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1209111141Sscottl		/*
1210111141Sscottl		 * We check against total_fibs to handle partially
1211111141Sscottl		 * allocated blocks.
1212111141Sscottl		 */
1213111141Sscottl		for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
1214111141Sscottl			cm = fm->aac_commands + i;
1215111141Sscottl			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1216111141Sscottl		}
1217111141Sscottl		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1218111141Sscottl		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1219111141Sscottl		free(fm, M_AACBUF);
1220110604Sscottl	}
122165793Smsmith}
122265793Smsmith
122383114Sscottl/*
122465793Smsmith * Command-mapping helper function - populate this command's s/g table.
122565793Smsmith */
122665793Smsmithstatic void
122765793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
122865793Smsmith{
122983114Sscottl	struct aac_command *cm;
123083114Sscottl	struct aac_fib *fib;
123183114Sscottl	int i;
123265793Smsmith
123383114Sscottl	debug_called(3);
123465793Smsmith
123583114Sscottl	cm = (struct aac_command *)arg;
123683114Sscottl	fib = cm->cm_fib;
123765793Smsmith
123883114Sscottl	/* copy into the FIB */
1239112856Sscottl	if (cm->cm_sgtable != NULL) {
1240112856Sscottl		if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1241112856Sscottl			struct aac_sg_table *sg;
1242112856Sscottl			sg = cm->cm_sgtable;
1243112856Sscottl			sg->SgCount = nseg;
1244112856Sscottl			for (i = 0; i < nseg; i++) {
1245112856Sscottl				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1246112856Sscottl				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1247112856Sscottl			}
1248112856Sscottl			/* update the FIB size for the s/g count */
1249112856Sscottl			fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
1250112856Sscottl		} else {
1251112856Sscottl			struct aac_sg_table64 *sg;
1252112856Sscottl			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1253112856Sscottl			sg->SgCount = nseg;
1254112856Sscottl			for (i = 0; i < nseg; i++) {
1255112856Sscottl				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1256112856Sscottl				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1257112856Sscottl			}
1258112856Sscottl			/* update the FIB size for the s/g count */
1259112856Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
126083114Sscottl		}
126165793Smsmith	}
126265793Smsmith}
126365793Smsmith
126483114Sscottl/*
126565793Smsmith * Map a command into controller-visible space.
126665793Smsmith */
126765793Smsmithstatic void
126865793Smsmithaac_map_command(struct aac_command *cm)
126965793Smsmith{
127083114Sscottl	struct aac_softc *sc;
127165793Smsmith
127283114Sscottl	debug_called(2);
127365793Smsmith
127483114Sscottl	sc = cm->cm_sc;
127565793Smsmith
127683114Sscottl	/* don't map more than once */
127783114Sscottl	if (cm->cm_flags & AAC_CMD_MAPPED)
127883114Sscottl		return;
127965793Smsmith
128083114Sscottl	if (cm->cm_datalen != 0) {
128183114Sscottl		bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap,
128283114Sscottl				cm->cm_data, cm->cm_datalen,
128383114Sscottl				aac_map_command_sg, cm, 0);
128483114Sscottl
1285109088Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
1286109088Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1287109088Sscottl					BUS_DMASYNC_PREREAD);
1288109088Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
1289109088Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1290109088Sscottl					BUS_DMASYNC_PREWRITE);
129183114Sscottl	}
129283114Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
129365793Smsmith}
129465793Smsmith
129583114Sscottl/*
129665793Smsmith * Unmap a command from controller-visible space.
129765793Smsmith */
129865793Smsmithstatic void
129965793Smsmithaac_unmap_command(struct aac_command *cm)
130065793Smsmith{
130183114Sscottl	struct aac_softc *sc;
130265793Smsmith
130383114Sscottl	debug_called(2);
130465793Smsmith
130583114Sscottl	sc = cm->cm_sc;
130665793Smsmith
130783114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
130883114Sscottl		return;
130965793Smsmith
131083114Sscottl	if (cm->cm_datalen != 0) {
131183114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
131283114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
131383114Sscottl					BUS_DMASYNC_POSTREAD);
131483114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
131583114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
131683114Sscottl					BUS_DMASYNC_POSTWRITE);
131783114Sscottl
131883114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
131983114Sscottl	}
132083114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
132165793Smsmith}
132265793Smsmith
132383114Sscottl/*
132483114Sscottl * Hardware Interface
132583114Sscottl */
132665793Smsmith
132783114Sscottl/*
132865793Smsmith * Initialise the adapter.
132965793Smsmith */
133065793Smsmithstatic void
133165793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
133265793Smsmith{
133383114Sscottl	struct aac_softc *sc;
133465793Smsmith
133583114Sscottl	debug_called(1);
133665793Smsmith
133783114Sscottl	sc = (struct aac_softc *)arg;
133883114Sscottl
133983114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
134065793Smsmith}
134165793Smsmith
134265793Smsmithstatic int
134390275Sscottlaac_check_firmware(struct aac_softc *sc)
134490275Sscottl{
1345112679Sscottl	u_int32_t major, minor, options;
134690275Sscottl
134790275Sscottl	debug_called(1);
134890275Sscottl
1349112679Sscottl	/*
1350112679Sscottl	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1351112679Sscottl	 * firmware version 1.x are not compatible with this driver.
1352112679Sscottl	 */
1353112679Sscottl	if (sc->flags & AAC_FLAGS_PERC2QC) {
135490275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
135590275Sscottl				     NULL)) {
135690275Sscottl			device_printf(sc->aac_dev,
135790275Sscottl				      "Error reading firmware version\n");
135890275Sscottl			return (EIO);
135990275Sscottl		}
136090275Sscottl
136190275Sscottl		/* These numbers are stored as ASCII! */
1362112679Sscottl		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1363112679Sscottl		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
136490275Sscottl		if (major == 1) {
136590275Sscottl			device_printf(sc->aac_dev,
136690275Sscottl			    "Firmware version %d.%d is not supported.\n",
136790275Sscottl			    major, minor);
136890275Sscottl			return (EINVAL);
136990275Sscottl		}
137090275Sscottl	}
137190275Sscottl
1372112679Sscottl	/*
1373112679Sscottl	 * Retrieve the capabilities/supported options word so we know what
1374112679Sscottl	 * work-arounds to enable.
1375112679Sscottl	 */
1376112679Sscottl	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1377112679Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1378112679Sscottl		return (EIO);
1379112679Sscottl	}
1380112679Sscottl	options = AAC_GET_MAILBOX(sc, 1);
1381112679Sscottl	sc->supported_options = options;
1382112679Sscottl
1383112679Sscottl	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1384112679Sscottl	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1385112679Sscottl		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1386112679Sscottl	if (options & AAC_SUPPORTED_NONDASD)
1387112679Sscottl		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1388112856Sscottl	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 && (sizeof(bus_addr_t) > 4)) {
1389112679Sscottl		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1390112679Sscottl		sc->flags |= AAC_FLAGS_SG_64BIT;
1391112679Sscottl	}
1392112679Sscottl
1393112679Sscottl	/* Check for broken hardware that does a lower number of commands */
1394112679Sscottl	if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
1395112679Sscottl		sc->aac_max_fibs = AAC_MAX_FIBS;
1396112679Sscottl	else
1397112679Sscottl		sc->aac_max_fibs = 256;
1398112679Sscottl
139990275Sscottl	return (0);
140090275Sscottl}
140190275Sscottl
140290275Sscottlstatic int
140365793Smsmithaac_init(struct aac_softc *sc)
140465793Smsmith{
140583114Sscottl	struct aac_adapter_init	*ip;
140683114Sscottl	time_t then;
140783114Sscottl	u_int32_t code;
140883114Sscottl	u_int8_t *qaddr;
1409112679Sscottl	int error;
141065793Smsmith
141183114Sscottl	debug_called(1);
141265793Smsmith
141383114Sscottl	/*
141483114Sscottl	 * First wait for the adapter to come ready.
141583114Sscottl	 */
141683114Sscottl	then = time_second;
141783114Sscottl	do {
141883114Sscottl		code = AAC_GET_FWSTATUS(sc);
141983114Sscottl		if (code & AAC_SELF_TEST_FAILED) {
142083114Sscottl			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
142183114Sscottl			return(ENXIO);
142283114Sscottl		}
142383114Sscottl		if (code & AAC_KERNEL_PANIC) {
142483114Sscottl			device_printf(sc->aac_dev,
142583114Sscottl				      "FATAL: controller kernel panic\n");
142683114Sscottl			return(ENXIO);
142783114Sscottl		}
142883114Sscottl		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
142983114Sscottl			device_printf(sc->aac_dev,
143083114Sscottl				      "FATAL: controller not coming ready, "
143183114Sscottl					   "status %x\n", code);
143283114Sscottl			return(ENXIO);
143383114Sscottl		}
143483114Sscottl	} while (!(code & AAC_UP_AND_RUNNING));
143583114Sscottl
1436112679Sscottl	error = ENOMEM;
143783114Sscottl	/*
1438112679Sscottl	 * Create DMA tag for mapping buffers into controller-addressable space.
1439112679Sscottl	 */
1440112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1441112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1442112679Sscottl			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1443112679Sscottl			       BUS_SPACE_MAXADDR :
1444112679Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1445112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1446112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1447112679Sscottl			       MAXBSIZE,		/* maxsize */
1448112679Sscottl			       AAC_MAXSGENTRIES,	/* nsegments */
1449112679Sscottl			       MAXBSIZE,		/* maxsegsize */
1450112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1451112679Sscottl			       &sc->aac_buffer_dmat)) {
1452112679Sscottl		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1453112679Sscottl		goto out;
1454112679Sscottl	}
1455112679Sscottl
1456112679Sscottl	/*
1457112679Sscottl	 * Create DMA tag for mapping FIBs into controller-addressable space..
1458112679Sscottl	 */
1459112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1460112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1461112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1462112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1463112679Sscottl			       0x7fffffff,		/* lowaddr */
1464112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1465112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1466112679Sscottl			       AAC_FIB_COUNT *
1467112679Sscottl			       sizeof(struct aac_fib),  /* maxsize */
1468112679Sscottl			       1,			/* nsegments */
1469112679Sscottl			       AAC_FIB_COUNT *
1470112679Sscottl			       sizeof(struct aac_fib),	/* maxsegsize */
1471112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1472112679Sscottl			       &sc->aac_fib_dmat)) {
1473112679Sscottl		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1474112679Sscottl		goto out;
1475112679Sscottl	}
1476112679Sscottl
1477112679Sscottl	/*
147883114Sscottl	 * Create DMA tag for the common structure and allocate it.
147983114Sscottl	 */
148083114Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
148195536Sscottl			       1, 0,			/* algnmnt, boundary */
1482112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1483112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1484112679Sscottl			       0x7fffffff,		/* lowaddr */
148583114Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
148683114Sscottl			       NULL, NULL, 		/* filter, filterarg */
1487110604Sscottl			       8192 + sizeof(struct aac_common), /* maxsize */
148883114Sscottl			       1,			/* nsegments */
148983114Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1490112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
149183114Sscottl			       &sc->aac_common_dmat)) {
149283114Sscottl		device_printf(sc->aac_dev,
149383114Sscottl			      "can't allocate common structure DMA tag\n");
1494112679Sscottl		goto out;
149565793Smsmith	}
149683114Sscottl	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
149783114Sscottl			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
149883114Sscottl		device_printf(sc->aac_dev, "can't allocate common structure\n");
1499112679Sscottl		goto out;
150065793Smsmith	}
1501110604Sscottl
1502110604Sscottl	/*
1503110604Sscottl	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1504110604Sscottl	 * below address 8192 in physical memory.
1505110604Sscottl	 * XXX If the padding is not needed, can it be put to use instead
1506110604Sscottl	 * of ignored?
1507110604Sscottl	 */
150883114Sscottl	bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1509110604Sscottl			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1510110604Sscottl			aac_common_map, sc, 0);
1511110604Sscottl
1512110604Sscottl	if (sc->aac_common_busaddr < 8192) {
1513110604Sscottl		(uint8_t *)sc->aac_common += 8192;
1514110604Sscottl		sc->aac_common_busaddr += 8192;
1515110604Sscottl	}
151683114Sscottl	bzero(sc->aac_common, sizeof(*sc->aac_common));
1517110604Sscottl
1518110604Sscottl	/* Allocate some FIBs and associated command structs */
1519110604Sscottl	TAILQ_INIT(&sc->aac_fibmap_tqh);
1520110604Sscottl	sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
1521111141Sscottl				  M_AACBUF, M_WAITOK|M_ZERO);
1522111141Sscottl	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1523110604Sscottl		if (aac_alloc_commands(sc) != 0)
1524110604Sscottl			break;
1525110604Sscottl	}
1526110604Sscottl	if (sc->total_fibs == 0)
1527112679Sscottl		goto out;
152883114Sscottl
152983114Sscottl	/*
153083114Sscottl	 * Fill in the init structure.  This tells the adapter about the
153183114Sscottl	 * physical location of various important shared data structures.
153283114Sscottl	 */
153383114Sscottl	ip = &sc->aac_common->ac_init;
153483114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1535109088Sscottl	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
153665793Smsmith
153783114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
153883114Sscottl					 offsetof(struct aac_common, ac_fibs);
1539114151Sscottl	ip->AdapterFibsVirtualAddress = 0;
154083114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
154183114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
154265793Smsmith
154383114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
154483114Sscottl				  offsetof(struct aac_common, ac_printf);
154583114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
154665793Smsmith
1547109088Sscottl	/* The adapter assumes that pages are 4K in size */
1548109088Sscottl	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
154983114Sscottl	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
155065793Smsmith
155183114Sscottl	/*
155283114Sscottl	 * Initialise FIB queues.  Note that it appears that the layout of the
155383114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
155483114Sscottl	 * adapter, which is only told about the base of the queue index fields.
155583114Sscottl	 *
155683114Sscottl	 * The initial values of the indices are assumed to inform the adapter
155783114Sscottl	 * of the sizes of the respective queues, and theoretically it could
155883114Sscottl	 * work out the entire layout of the queue structures from this.  We
155983114Sscottl	 * take the easy route and just lay this area out like everyone else
156083114Sscottl	 * does.
156183114Sscottl	 *
156283114Sscottl	 * The Linux driver uses a much more complex scheme whereby several
156383114Sscottl	 * header records are kept for each queue.  We use a couple of generic
156483114Sscottl	 * list manipulation functions which 'know' the size of each list by
156583114Sscottl	 * virtue of a table.
156683114Sscottl	 */
156783114Sscottl	qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
156883114Sscottl	qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
156983114Sscottl	sc->aac_queues = (struct aac_queue_table *)qaddr;
157083114Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr +
157183114Sscottl				((u_int32_t)sc->aac_queues -
157283114Sscottl				(u_int32_t)sc->aac_common);
157365793Smsmith
157483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
157581082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
157683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
157781082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
157883114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
157981082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
158083114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
158181082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
158283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
158381082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
158483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
158581082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
158683114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
158781082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
158883114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
158981082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
159083114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
159181082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
159283114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
159381082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
159483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
159581082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
159683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
159781082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
159883114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
159981082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
160083114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
160181082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
160283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
160381082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
160483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
160581082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
160683114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
160781082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
160883114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
160981082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
161083114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
161181082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
161283114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
161381082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
161483114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
161581082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
161683114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
161781082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
161883114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
161981082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
162083114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
162181082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
162265793Smsmith
162383114Sscottl	/*
162483114Sscottl	 * Do controller-type-specific initialisation
162583114Sscottl	 */
162683114Sscottl	switch (sc->aac_hwif) {
162783114Sscottl	case AAC_HWIF_I960RX:
162883114Sscottl		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
162983114Sscottl		break;
163083114Sscottl	}
163165793Smsmith
163283114Sscottl	/*
163383114Sscottl	 * Give the init structure to the controller.
163483114Sscottl	 */
163583114Sscottl	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
163683114Sscottl			     sc->aac_common_busaddr +
163783114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
163883114Sscottl			     NULL)) {
163983114Sscottl		device_printf(sc->aac_dev,
164083114Sscottl			      "error establishing init structure\n");
1641112679Sscottl		error = EIO;
1642112679Sscottl		goto out;
164383114Sscottl	}
164465793Smsmith
1645112679Sscottl	error = 0;
1646112679Sscottlout:
1647112679Sscottl	return(error);
164865793Smsmith}
164965793Smsmith
165083114Sscottl/*
165165793Smsmith * Send a synchronous command to the controller and wait for a result.
165265793Smsmith */
165365793Smsmithstatic int
165465793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
165570393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
165670393Smsmith		 u_int32_t *sp)
165765793Smsmith{
165883114Sscottl	time_t then;
165983114Sscottl	u_int32_t status;
166065793Smsmith
166183114Sscottl	debug_called(3);
166265793Smsmith
166383114Sscottl	/* populate the mailbox */
166483114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
166565793Smsmith
166683114Sscottl	/* ensure the sync command doorbell flag is cleared */
166783114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
166865793Smsmith
166983114Sscottl	/* then set it to signal the adapter */
167083114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
167165793Smsmith
167283114Sscottl	/* spin waiting for the command to complete */
167383114Sscottl	then = time_second;
167483114Sscottl	do {
167583114Sscottl		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1676112679Sscottl			debug(1, "timed out");
167783114Sscottl			return(EIO);
167883114Sscottl		}
167983114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
168065793Smsmith
168183114Sscottl	/* clear the completion flag */
168283114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
168365793Smsmith
168483114Sscottl	/* get the command status */
1685112679Sscottl	status = AAC_GET_MAILBOX(sc, 0);
168683114Sscottl	if (sp != NULL)
168783114Sscottl		*sp = status;
168883114Sscottl	return(0);
168965793Smsmith}
169065793Smsmith
169183114Sscottl/*
169295350Sscottl * Grab the sync fib area.
169395350Sscottl */
169495350Sscottlint
169595536Sscottlaac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags)
169695350Sscottl{
169795350Sscottl
169895350Sscottl	/*
169995350Sscottl	 * If the force flag is set, the system is shutting down, or in
170095350Sscottl	 * trouble.  Ignore the mutex.
170195350Sscottl	 */
170295350Sscottl	if (!(flags & AAC_SYNC_LOCK_FORCE))
170395350Sscottl		AAC_LOCK_ACQUIRE(&sc->aac_sync_lock);
170495350Sscottl
170595350Sscottl	*fib = &sc->aac_common->ac_sync_fib;
170695350Sscottl
170795350Sscottl	return (1);
170895350Sscottl}
170995350Sscottl
171095350Sscottl/*
171195350Sscottl * Release the sync fib area.
171295350Sscottl */
171395350Sscottlvoid
171495350Sscottlaac_release_sync_fib(struct aac_softc *sc)
171595350Sscottl{
171695350Sscottl
171795350Sscottl	AAC_LOCK_RELEASE(&sc->aac_sync_lock);
171895350Sscottl}
171995350Sscottl
172095350Sscottl/*
172165793Smsmith * Send a synchronous FIB to the controller and wait for a result.
172265793Smsmith */
172395350Sscottlint
172465793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
172595350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
172665793Smsmith{
172783114Sscottl	debug_called(3);
172865793Smsmith
172983114Sscottl	if (datasize > AAC_FIB_DATASIZE)
173083114Sscottl		return(EINVAL);
173165793Smsmith
173283114Sscottl	/*
173383114Sscottl	 * Set up the sync FIB
173483114Sscottl	 */
173583114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
173683114Sscottl				AAC_FIBSTATE_INITIALISED |
173783114Sscottl				AAC_FIBSTATE_EMPTY;
173883114Sscottl	fib->Header.XferState |= xferstate;
173983114Sscottl	fib->Header.Command = command;
174083114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
174183114Sscottl	fib->Header.Size = sizeof(struct aac_fib) + datasize;
174283114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
174383114Sscottl	fib->Header.SenderFibAddress = (u_int32_t)fib;
174483114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
174583114Sscottl					 offsetof(struct aac_common,
174683114Sscottl						  ac_sync_fib);
174765793Smsmith
174883114Sscottl	/*
174983114Sscottl	 * Give the FIB to the controller, wait for a response.
175083114Sscottl	 */
175183114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
175283114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
175383114Sscottl		debug(2, "IO error");
175483114Sscottl		return(EIO);
175583114Sscottl	}
175681151Sscottl
175795350Sscottl	return (0);
175865793Smsmith}
175965793Smsmith
176083114Sscottl/*
176165793Smsmith * Adapter-space FIB queue manipulation
176265793Smsmith *
176365793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
176465793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
176565793Smsmith */
176665793Smsmithstatic struct {
176783114Sscottl	int		size;
176883114Sscottl	int		notify;
176965793Smsmith} aac_qinfo[] = {
177083114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
177183114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
177283114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
177383114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
177483114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
177583114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
177683114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
177783114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
177865793Smsmith};
177965793Smsmith
178065793Smsmith/*
178181082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
178281082Sscottl * EBUSY if the queue is full.
178365793Smsmith *
178470393Smsmith * Note: it would be more efficient to defer notifying the controller in
178583114Sscottl *	 the case where we may be inserting several entries in rapid succession,
178683114Sscottl *	 but implementing this usefully may be difficult (it would involve a
178783114Sscottl *	 separate queue/notify interface).
178865793Smsmith */
178965793Smsmithstatic int
179081151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
179165793Smsmith{
179283114Sscottl	u_int32_t pi, ci;
1793111691Sscottl	int error;
179483114Sscottl	u_int32_t fib_size;
179583114Sscottl	u_int32_t fib_addr;
179665793Smsmith
179783114Sscottl	debug_called(3);
179882527Sscottl
179983114Sscottl	fib_size = cm->cm_fib->Header.Size;
180083114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
180181151Sscottl
180283114Sscottl	/* get the producer/consumer indices */
180383114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
180483114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
180565793Smsmith
180683114Sscottl	/* wrap the queue? */
180783114Sscottl	if (pi >= aac_qinfo[queue].size)
180883114Sscottl		pi = 0;
180965793Smsmith
181083114Sscottl	/* check for queue full */
181183114Sscottl	if ((pi + 1) == ci) {
181283114Sscottl		error = EBUSY;
181383114Sscottl		goto out;
181483114Sscottl	}
181565793Smsmith
181683114Sscottl	/* populate queue entry */
181783114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
181883114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
181965793Smsmith
182083114Sscottl	/* update producer index */
182183114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
182265793Smsmith
182383114Sscottl	/*
182483114Sscottl	 * To avoid a race with its completion interrupt, place this command on
182583114Sscottl	 * the busy queue prior to advertising it to the controller.
182683114Sscottl	 */
182783114Sscottl	aac_enqueue_busy(cm);
182881151Sscottl
182983114Sscottl	/* notify the adapter if we know how */
183083114Sscottl	if (aac_qinfo[queue].notify != 0)
183183114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
183265793Smsmith
183383114Sscottl	error = 0;
183465793Smsmith
183565793Smsmithout:
183683114Sscottl	return(error);
183765793Smsmith}
183865793Smsmith
183965793Smsmith/*
184082527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
184182527Sscottl * success or ENOENT if the queue is empty.
184265793Smsmith */
184365793Smsmithstatic int
184481082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
184581082Sscottl		struct aac_fib **fib_addr)
184665793Smsmith{
184783114Sscottl	u_int32_t pi, ci;
1848114151Sscottl	u_int32_t fib_index;
1849111691Sscottl	int error;
185083114Sscottl	int notify;
185165793Smsmith
185283114Sscottl	debug_called(3);
185365793Smsmith
185483114Sscottl	/* get the producer/consumer indices */
185583114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
185683114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
185765793Smsmith
185883114Sscottl	/* check for queue empty */
185983114Sscottl	if (ci == pi) {
186083114Sscottl		error = ENOENT;
186183114Sscottl		goto out;
186283114Sscottl	}
186383114Sscottl
186483114Sscottl	notify = 0;
186583114Sscottl	if (ci == pi + 1)
186683114Sscottl		notify++;
186781151Sscottl
186883114Sscottl	/* wrap the queue? */
186983114Sscottl	if (ci >= aac_qinfo[queue].size)
187083114Sscottl		ci = 0;
187165793Smsmith
187283114Sscottl	/* fetch the entry */
187383114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
187465793Smsmith
1875114151Sscottl	switch (queue) {
1876114151Sscottl	case AAC_HOST_NORM_CMD_QUEUE:
1877114151Sscottl	case AAC_HOST_HIGH_CMD_QUEUE:
1878114151Sscottl		/*
1879114151Sscottl		 * The aq_fib_addr is only 32 bits wide so it can't be counted
1880114151Sscottl		 * on to hold an address.  For AIF's, the adapter assumes
1881114151Sscottl		 * that it's giving us an address into the array of AIF fibs.
1882114151Sscottl		 * Therefore, we have to convert it to an index.
1883114151Sscottl		 */
1884114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
1885114151Sscottl			sizeof(struct aac_fib);
1886114151Sscottl		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
1887114151Sscottl		break;
1888114151Sscottl
1889114151Sscottl	case AAC_HOST_NORM_RESP_QUEUE:
1890114151Sscottl	case AAC_HOST_HIGH_RESP_QUEUE:
1891114151Sscottl	{
1892114151Sscottl		struct aac_command *cm;
1893114151Sscottl
1894114151Sscottl		/*
1895114151Sscottl		 * As above, an index is used instead of an actual address.
1896114151Sscottl		 * Gotta shift the index to account for the fast response
1897114151Sscottl		 * bit.  No other correction is needed since this value was
1898114151Sscottl		 * originally provided by the driver via the SenderFibAddress
1899114151Sscottl		 * field.
1900114151Sscottl		 */
1901114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
1902114151Sscottl		cm = sc->aac_commands + (fib_index >> 1);
1903114151Sscottl		*fib_addr = cm->cm_fib;
1904114151Sscottl
1905114151Sscottl		/*
1906114151Sscottl		 * Is this a fast response? If it is, update the fib fields in
1907114151Sscottl		 * local memory since the whole fib isn't DMA'd back up.
1908114151Sscottl		 */
1909114151Sscottl		if (fib_index & 0x01) {
1910114151Sscottl			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
1911114151Sscottl			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
1912114151Sscottl		}
1913114151Sscottl		break;
1914109088Sscottl	}
1915114151Sscottl	default:
1916114151Sscottl		panic("Invalid queue in aac_dequeue_fib()");
1917114151Sscottl		break;
1918114151Sscottl	}
1919114151Sscottl
192083114Sscottl	/* update consumer index */
192183114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
192265793Smsmith
192383114Sscottl	/* if we have made the queue un-full, notify the adapter */
192483114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
192583114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
192683114Sscottl	error = 0;
192765793Smsmith
192865793Smsmithout:
192983114Sscottl	return(error);
193065793Smsmith}
193165793Smsmith
193283114Sscottl/*
193382527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
193482527Sscottl */
193582527Sscottlstatic int
193682527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
193782527Sscottl{
193883114Sscottl	u_int32_t pi, ci;
1939111691Sscottl	int error;
194083114Sscottl	u_int32_t fib_size;
194183114Sscottl	u_int32_t fib_addr;
194282527Sscottl
194383114Sscottl	debug_called(1);
194482527Sscottl
194583114Sscottl	/* Tell the adapter where the FIB is */
194683114Sscottl	fib_size = fib->Header.Size;
194783114Sscottl	fib_addr = fib->Header.SenderFibAddress;
194883114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
194982527Sscottl
195083114Sscottl	/* get the producer/consumer indices */
195183114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
195283114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
195382527Sscottl
195483114Sscottl	/* wrap the queue? */
195583114Sscottl	if (pi >= aac_qinfo[queue].size)
195683114Sscottl		pi = 0;
195782527Sscottl
195883114Sscottl	/* check for queue full */
195983114Sscottl	if ((pi + 1) == ci) {
196083114Sscottl		error = EBUSY;
196183114Sscottl		goto out;
196283114Sscottl	}
196382527Sscottl
196483114Sscottl	/* populate queue entry */
196583114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
196683114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
196782527Sscottl
196883114Sscottl	/* update producer index */
196983114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
197082527Sscottl
197183114Sscottl	/* notify the adapter if we know how */
197283114Sscottl	if (aac_qinfo[queue].notify != 0)
197383114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
197482527Sscottl
197583114Sscottl	error = 0;
197682527Sscottl
197782527Sscottlout:
197883114Sscottl	return(error);
197982527Sscottl}
198082527Sscottl
198183114Sscottl/*
198270393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
198370393Smsmith * and complain about them.
198470393Smsmith */
198570393Smsmithstatic void
198670393Smsmithaac_timeout(struct aac_softc *sc)
198770393Smsmith{
198883114Sscottl	struct aac_command *cm;
198983114Sscottl	time_t deadline;
199070393Smsmith
199183114Sscottl	/*
1992110426Sscottl	 * Traverse the busy command list, bitch about late commands once
199383114Sscottl	 * only.
199483114Sscottl	 */
199583114Sscottl	deadline = time_second - AAC_CMD_TIMEOUT;
199683114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
199783114Sscottl		if ((cm->cm_timestamp  < deadline)
199883114Sscottl			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
199983114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
200083114Sscottl			device_printf(sc->aac_dev,
200183114Sscottl				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
200283114Sscottl				      cm, (int)(time_second-cm->cm_timestamp));
200383114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
200483114Sscottl		}
200570393Smsmith	}
200670393Smsmith
200783114Sscottl	return;
200870393Smsmith}
200970393Smsmith
201083114Sscottl/*
201183114Sscottl * Interface Function Vectors
201283114Sscottl */
201365793Smsmith
201483114Sscottl/*
201565793Smsmith * Read the current firmware status word.
201665793Smsmith */
201765793Smsmithstatic int
201865793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
201965793Smsmith{
202083114Sscottl	debug_called(3);
202165793Smsmith
202283114Sscottl	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
202365793Smsmith}
202465793Smsmith
202565793Smsmithstatic int
202665793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
202765793Smsmith{
202883114Sscottl	debug_called(3);
202965793Smsmith
203083114Sscottl	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
203165793Smsmith}
203265793Smsmith
203387183Sscottlstatic int
203487183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc)
203587183Sscottl{
203687183Sscottl	int val;
203787183Sscottl
203887183Sscottl	debug_called(3);
203987183Sscottl
204087183Sscottl	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
204187183Sscottl	return (val);
204287183Sscottl}
204387183Sscottl
204483114Sscottl/*
204565793Smsmith * Notify the controller of a change in a given queue
204665793Smsmith */
204765793Smsmith
204865793Smsmithstatic void
204965793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
205065793Smsmith{
205183114Sscottl	debug_called(3);
205265793Smsmith
205383114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
205465793Smsmith}
205565793Smsmith
205665793Smsmithstatic void
205765793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
205865793Smsmith{
205983114Sscottl	debug_called(3);
206065793Smsmith
206183114Sscottl	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
206265793Smsmith}
206365793Smsmith
206487183Sscottlstatic void
206587183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit)
206687183Sscottl{
206787183Sscottl	debug_called(3);
206887183Sscottl
206987183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
207087183Sscottl	AAC_FA_HACK(sc);
207187183Sscottl}
207287183Sscottl
207383114Sscottl/*
207465793Smsmith * Get the interrupt reason bits
207565793Smsmith */
207665793Smsmithstatic int
207765793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
207865793Smsmith{
207983114Sscottl	debug_called(3);
208065793Smsmith
208183114Sscottl	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
208265793Smsmith}
208365793Smsmith
208465793Smsmithstatic int
208565793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
208665793Smsmith{
208783114Sscottl	debug_called(3);
208865793Smsmith
208983114Sscottl	return(AAC_GETREG4(sc, AAC_RX_ODBR));
209065793Smsmith}
209165793Smsmith
209287183Sscottlstatic int
209387183Sscottlaac_fa_get_istatus(struct aac_softc *sc)
209487183Sscottl{
209587183Sscottl	int val;
209687183Sscottl
209787183Sscottl	debug_called(3);
209887183Sscottl
209987183Sscottl	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
210087183Sscottl	return (val);
210187183Sscottl}
210287183Sscottl
210383114Sscottl/*
210465793Smsmith * Clear some interrupt reason bits
210565793Smsmith */
210665793Smsmithstatic void
210765793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
210865793Smsmith{
210983114Sscottl	debug_called(3);
211065793Smsmith
211183114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
211265793Smsmith}
211365793Smsmith
211465793Smsmithstatic void
211565793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
211665793Smsmith{
211783114Sscottl	debug_called(3);
211865793Smsmith
211983114Sscottl	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
212065793Smsmith}
212165793Smsmith
212287183Sscottlstatic void
212387183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask)
212487183Sscottl{
212587183Sscottl	debug_called(3);
212687183Sscottl
212787183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
212887183Sscottl	AAC_FA_HACK(sc);
212987183Sscottl}
213087183Sscottl
213183114Sscottl/*
213265793Smsmith * Populate the mailbox and set the command word
213365793Smsmith */
213465793Smsmithstatic void
213565793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
213665793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
213765793Smsmith{
213883114Sscottl	debug_called(4);
213965793Smsmith
214083114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
214183114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
214283114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
214383114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
214483114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
214565793Smsmith}
214665793Smsmith
214765793Smsmithstatic void
214865793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
214965793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
215065793Smsmith{
215183114Sscottl	debug_called(4);
215265793Smsmith
215383114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
215483114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
215583114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
215683114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
215783114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
215865793Smsmith}
215965793Smsmith
216087183Sscottlstatic void
216187183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
216287183Sscottl		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
216387183Sscottl{
216487183Sscottl	debug_called(4);
216587183Sscottl
216687183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
216787183Sscottl	AAC_FA_HACK(sc);
216887183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
216987183Sscottl	AAC_FA_HACK(sc);
217087183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
217187183Sscottl	AAC_FA_HACK(sc);
217287183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
217387183Sscottl	AAC_FA_HACK(sc);
217487183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
217587183Sscottl	AAC_FA_HACK(sc);
217687183Sscottl}
217787183Sscottl
217883114Sscottl/*
217965793Smsmith * Fetch the immediate command status word
218065793Smsmith */
218165793Smsmithstatic int
2182112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb)
218365793Smsmith{
218483114Sscottl	debug_called(4);
218565793Smsmith
2186112679Sscottl	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
218765793Smsmith}
218865793Smsmith
218965793Smsmithstatic int
2190112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb)
219165793Smsmith{
219283114Sscottl	debug_called(4);
219365793Smsmith
2194112679Sscottl	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
219565793Smsmith}
219665793Smsmith
219787183Sscottlstatic int
2198112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb)
219987183Sscottl{
220087183Sscottl	int val;
220187183Sscottl
220287183Sscottl	debug_called(4);
220387183Sscottl
2204112679Sscottl	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
220587183Sscottl	return (val);
220687183Sscottl}
220787183Sscottl
220883114Sscottl/*
220965793Smsmith * Set/clear interrupt masks
221065793Smsmith */
221165793Smsmithstatic void
221265793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
221365793Smsmith{
221483114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
221565793Smsmith
221683114Sscottl	if (enable) {
221783114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
221883114Sscottl	} else {
221983114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
222083114Sscottl	}
222165793Smsmith}
222265793Smsmith
222365793Smsmithstatic void
222465793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
222565793Smsmith{
222683114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
222765793Smsmith
222883114Sscottl	if (enable) {
222983114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
223083114Sscottl	} else {
223183114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
223283114Sscottl	}
223365793Smsmith}
223465793Smsmith
223587183Sscottlstatic void
223687183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable)
223787183Sscottl{
223887183Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
223987183Sscottl
224087183Sscottl	if (enable) {
224187183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
224287183Sscottl		AAC_FA_HACK(sc);
224387183Sscottl	} else {
224487183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
224587183Sscottl		AAC_FA_HACK(sc);
224687183Sscottl	}
224787183Sscottl}
224887183Sscottl
224983114Sscottl/*
225083114Sscottl * Debugging and Diagnostics
225183114Sscottl */
225265793Smsmith
225383114Sscottl/*
225465793Smsmith * Print some information about the controller.
225565793Smsmith */
225665793Smsmithstatic void
225765793Smsmithaac_describe_controller(struct aac_softc *sc)
225865793Smsmith{
225995350Sscottl	struct aac_fib *fib;
226083114Sscottl	struct aac_adapter_info	*info;
226165793Smsmith
226283114Sscottl	debug_called(2);
226365793Smsmith
226495536Sscottl	aac_alloc_sync_fib(sc, &fib, 0);
226595350Sscottl
226695350Sscottl	fib->data[0] = 0;
226795350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
226883114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
226995536Sscottl		aac_release_sync_fib(sc);
227083114Sscottl		return;
227183114Sscottl	}
2272112679Sscottl	info = (struct aac_adapter_info *)&fib->data[0];
227365793Smsmith
227483114Sscottl	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
227583114Sscottl		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
227683114Sscottl		      info->ClockSpeed, info->BufferMem / (1024 * 1024),
227783114Sscottl		      aac_describe_code(aac_battery_platform,
227883114Sscottl					info->batteryPlatform));
227965793Smsmith
228083114Sscottl	/* save the kernel revision structure for later use */
228183114Sscottl	sc->aac_revision = info->KernelRevision;
228283114Sscottl	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
228383114Sscottl		      info->KernelRevision.external.comp.major,
228483114Sscottl		      info->KernelRevision.external.comp.minor,
228583114Sscottl		      info->KernelRevision.external.comp.dash,
228683114Sscottl		      info->KernelRevision.buildNumber,
228783114Sscottl		      (u_int32_t)(info->SerialNumber & 0xffffff));
228895536Sscottl
228995536Sscottl	aac_release_sync_fib(sc);
2290112679Sscottl
2291112679Sscottl	if (1 || bootverbose) {
2292112679Sscottl		device_printf(sc->aac_dev, "Supported Options=%b\n",
2293112679Sscottl			      sc->supported_options,
2294112679Sscottl			      "\20"
2295112679Sscottl			      "\1SNAPSHOT"
2296112679Sscottl			      "\2CLUSTERS"
2297112679Sscottl			      "\3WCACHE"
2298112679Sscottl			      "\4DATA64"
2299112679Sscottl			      "\5HOSTTIME"
2300112679Sscottl			      "\6RAID50"
2301112679Sscottl			      "\7WINDOW4GB"
2302112679Sscottl			      "\10SCSIUPGD"
2303112679Sscottl			      "\11SOFTERR"
2304112679Sscottl			      "\12NORECOND"
2305112679Sscottl			      "\13SGMAP64"
2306112679Sscottl			      "\14ALARM"
2307112679Sscottl			      "\15NONDASD");
2308112679Sscottl	}
230965793Smsmith}
231065793Smsmith
231183114Sscottl/*
231265793Smsmith * Look up a text description of a numeric error code and return a pointer to
231365793Smsmith * same.
231465793Smsmith */
231565793Smsmithstatic char *
231665793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code)
231765793Smsmith{
231883114Sscottl	int i;
231965793Smsmith
232083114Sscottl	for (i = 0; table[i].string != NULL; i++)
232183114Sscottl		if (table[i].code == code)
232283114Sscottl			return(table[i].string);
232383114Sscottl	return(table[i + 1].string);
232465793Smsmith}
232565793Smsmith
232683114Sscottl/*
232783114Sscottl * Management Interface
232883114Sscottl */
232965793Smsmith
233065793Smsmithstatic int
233187310Sscottlaac_open(dev_t dev, int flags, int fmt, d_thread_t *td)
233265793Smsmith{
233383114Sscottl	struct aac_softc *sc;
233465793Smsmith
233583114Sscottl	debug_called(2);
233665793Smsmith
233783114Sscottl	sc = dev->si_drv1;
233865793Smsmith
233983114Sscottl	/* Check to make sure the device isn't already open */
234083114Sscottl	if (sc->aac_state & AAC_STATE_OPEN) {
234183114Sscottl		return EBUSY;
234283114Sscottl	}
234383114Sscottl	sc->aac_state |= AAC_STATE_OPEN;
234483114Sscottl
234583114Sscottl	return 0;
234665793Smsmith}
234765793Smsmith
234865793Smsmithstatic int
234987310Sscottlaac_close(dev_t dev, int flags, int fmt, d_thread_t *td)
235065793Smsmith{
235183114Sscottl	struct aac_softc *sc;
235265793Smsmith
235383114Sscottl	debug_called(2);
235465793Smsmith
235583114Sscottl	sc = dev->si_drv1;
235665793Smsmith
235783114Sscottl	/* Mark this unit as no longer open  */
235883114Sscottl	sc->aac_state &= ~AAC_STATE_OPEN;
235983114Sscottl
236083114Sscottl	return 0;
236165793Smsmith}
236265793Smsmith
236365793Smsmithstatic int
236487310Sscottlaac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
236565793Smsmith{
236683114Sscottl	union aac_statrequest *as;
236783114Sscottl	struct aac_softc *sc;
236883114Sscottl	int error = 0;
236983114Sscottl	int i;
237065793Smsmith
237183114Sscottl	debug_called(2);
237265793Smsmith
237383114Sscottl	as = (union aac_statrequest *)arg;
237483114Sscottl	sc = dev->si_drv1;
237583114Sscottl
237683114Sscottl	switch (cmd) {
237783114Sscottl	case AACIO_STATS:
237883114Sscottl		switch (as->as_item) {
237983114Sscottl		case AACQ_FREE:
238083114Sscottl		case AACQ_BIO:
238183114Sscottl		case AACQ_READY:
238283114Sscottl		case AACQ_BUSY:
238383114Sscottl		case AACQ_COMPLETE:
238483114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
238583114Sscottl			      sizeof(struct aac_qstat));
238683114Sscottl			break;
238783114Sscottl		default:
238883114Sscottl			error = ENOENT;
238983114Sscottl			break;
239083114Sscottl		}
239183114Sscottl	break;
239283114Sscottl
239383114Sscottl	case FSACTL_SENDFIB:
239483114Sscottl		arg = *(caddr_t*)arg;
239583114Sscottl	case FSACTL_LNX_SENDFIB:
239683114Sscottl		debug(1, "FSACTL_SENDFIB");
239783114Sscottl		error = aac_ioctl_sendfib(sc, arg);
239883114Sscottl		break;
239983114Sscottl	case FSACTL_AIF_THREAD:
240083114Sscottl	case FSACTL_LNX_AIF_THREAD:
240183114Sscottl		debug(1, "FSACTL_AIF_THREAD");
240283114Sscottl		error = EINVAL;
240383114Sscottl		break;
240483114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
240583114Sscottl		arg = *(caddr_t*)arg;
240687183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
240783114Sscottl		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
240883114Sscottl		/*
240983114Sscottl		 * Pass the caller out an AdapterFibContext.
241083114Sscottl		 *
241183114Sscottl		 * Note that because we only support one opener, we
241283114Sscottl		 * basically ignore this.  Set the caller's context to a magic
241383114Sscottl		 * number just in case.
241483114Sscottl		 *
241583114Sscottl		 * The Linux code hands the driver a pointer into kernel space,
241683114Sscottl		 * and then trusts it when the caller hands it back.  Aiee!
241783114Sscottl		 * Here, we give it the proc pointer of the per-adapter aif
241883114Sscottl		 * thread. It's only used as a sanity check in other calls.
241983114Sscottl		 */
242083114Sscottl		i = (int)sc->aifthread;
242183114Sscottl		error = copyout(&i, arg, sizeof(i));
242283114Sscottl		break;
242383114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
242483114Sscottl		arg = *(caddr_t*)arg;
242583114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
242683114Sscottl		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
242783114Sscottl		error = aac_getnext_aif(sc, arg);
242883114Sscottl		break;
242983114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
243083114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
243183114Sscottl		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
243283114Sscottl		/* don't do anything here */
243383114Sscottl		break;
243483114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
243583114Sscottl		arg = *(caddr_t*)arg;
243683114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
243783114Sscottl		debug(1, "FSACTL_MINIPORT_REV_CHECK");
243883114Sscottl		error = aac_rev_check(sc, arg);
243983114Sscottl		break;
244083114Sscottl	case FSACTL_QUERY_DISK:
244183114Sscottl		arg = *(caddr_t*)arg;
244283114Sscottl	case FSACTL_LNX_QUERY_DISK:
244383114Sscottl		debug(1, "FSACTL_QUERY_DISK");
244483114Sscottl		error = aac_query_disk(sc, arg);
244583114Sscottl			break;
244683114Sscottl	case FSACTL_DELETE_DISK:
244783114Sscottl	case FSACTL_LNX_DELETE_DISK:
244883114Sscottl		/*
244983114Sscottl		 * We don't trust the underland to tell us when to delete a
245083114Sscottl		 * container, rather we rely on an AIF coming from the
245183114Sscottl		 * controller
245283114Sscottl		 */
245383114Sscottl		error = 0;
245483114Sscottl		break;
245570393Smsmith	default:
245687183Sscottl		debug(1, "unsupported cmd 0x%lx\n", cmd);
245783114Sscottl		error = EINVAL;
245883114Sscottl		break;
245970393Smsmith	}
246083114Sscottl	return(error);
246165793Smsmith}
246265793Smsmith
246387183Sscottlstatic int
246487310Sscottlaac_poll(dev_t dev, int poll_events, d_thread_t *td)
246587183Sscottl{
246687183Sscottl	struct aac_softc *sc;
246787183Sscottl	int revents;
246887183Sscottl
246987183Sscottl	sc = dev->si_drv1;
247087183Sscottl	revents = 0;
247187183Sscottl
247287310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
247387183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
247487183Sscottl		if (sc->aac_aifq_tail != sc->aac_aifq_head)
247587183Sscottl			revents |= poll_events & (POLLIN | POLLRDNORM);
247687183Sscottl	}
247787183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
247887183Sscottl
247987183Sscottl	if (revents == 0) {
248087183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
248187183Sscottl			selrecord(td, &sc->rcv_select);
248287183Sscottl	}
248387183Sscottl
248487183Sscottl	return (revents);
248587183Sscottl}
248687183Sscottl
248783114Sscottl/*
248865793Smsmith * Send a FIB supplied from userspace
248965793Smsmith */
249065793Smsmithstatic int
249165793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
249265793Smsmith{
249383114Sscottl	struct aac_command *cm;
249483114Sscottl	int size, error;
249565793Smsmith
249683114Sscottl	debug_called(2);
249765793Smsmith
249883114Sscottl	cm = NULL;
249965793Smsmith
250083114Sscottl	/*
250183114Sscottl	 * Get a command
250283114Sscottl	 */
2503111532Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
250483114Sscottl	if (aac_alloc_command(sc, &cm)) {
250583114Sscottl		error = EBUSY;
250683114Sscottl		goto out;
250783114Sscottl	}
250865793Smsmith
250983114Sscottl	/*
251083114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
251183114Sscottl	 */
251283114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
251383114Sscottl			    sizeof(struct aac_fib_header))) != 0)
251483114Sscottl		goto out;
251583114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
251683114Sscottl	if (size > sizeof(struct aac_fib)) {
251783114Sscottl		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
251883114Sscottl			      size, sizeof(struct aac_fib));
251983114Sscottl		size = sizeof(struct aac_fib);
252083114Sscottl	}
252183114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
252283114Sscottl		goto out;
252383114Sscottl	cm->cm_fib->Header.Size = size;
252483114Sscottl	cm->cm_timestamp = time_second;
252565793Smsmith
252683114Sscottl	/*
252783114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
252883114Sscottl	 */
252987183Sscottl	if ((error = aac_wait_command(cm, 30)) != 0) {	/* XXX user timeout? */
2530110426Sscottl		device_printf(sc->aac_dev,
2531110426Sscottl			      "aac_wait_command return %d\n", error);
253283114Sscottl		goto out;
253387183Sscottl	}
253465793Smsmith
253583114Sscottl	/*
253683114Sscottl	 * Copy the FIB and data back out to the caller.
253783114Sscottl	 */
253883114Sscottl	size = cm->cm_fib->Header.Size;
253983114Sscottl	if (size > sizeof(struct aac_fib)) {
254083114Sscottl		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
254183114Sscottl			      size, sizeof(struct aac_fib));
254283114Sscottl		size = sizeof(struct aac_fib);
254383114Sscottl	}
254483114Sscottl	error = copyout(cm->cm_fib, ufib, size);
254565793Smsmith
254665793Smsmithout:
254783114Sscottl	if (cm != NULL) {
254883114Sscottl		aac_release_command(cm);
254983114Sscottl	}
2550111532Sscottl
2551111532Sscottl	AAC_LOCK_RELEASE(&sc->aac_io_lock);
255283114Sscottl	return(error);
255365793Smsmith}
255465793Smsmith
255583114Sscottl/*
255665793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
255782527Sscottl * If the queue fills up, then drop the older entries.
255865793Smsmith */
255965793Smsmithstatic void
256082527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
256165793Smsmith{
256283114Sscottl	struct aac_aif_command *aif;
256383114Sscottl	struct aac_container *co, *co_next;
256495350Sscottl	struct aac_mntinfo *mi;
256595350Sscottl	struct aac_mntinforesp *mir = NULL;
256683114Sscottl	u_int16_t rsize;
256787183Sscottl	int next, found;
256883114Sscottl	int added = 0, i = 0;
256965793Smsmith
257083114Sscottl	debug_called(2);
257165793Smsmith
257283114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
257383114Sscottl	aac_print_aif(sc, aif);
257482527Sscottl
257583114Sscottl	/* Is it an event that we should care about? */
257683114Sscottl	switch (aif->command) {
257783114Sscottl	case AifCmdEventNotify:
257883114Sscottl		switch (aif->data.EN.type) {
257983114Sscottl		case AifEnAddContainer:
258083114Sscottl		case AifEnDeleteContainer:
258183114Sscottl			/*
258283114Sscottl			 * A container was added or deleted, but the message
258383114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
258483114Sscottl			 * containers and sort things out.
258583114Sscottl			 */
258695536Sscottl			aac_alloc_sync_fib(sc, &fib, 0);
258795350Sscottl			mi = (struct aac_mntinfo *)&fib->data[0];
258883114Sscottl			do {
258983114Sscottl				/*
259083114Sscottl				 * Ask the controller for its containers one at
259183114Sscottl				 * a time.
259283114Sscottl				 * XXX What if the controller's list changes
259383114Sscottl				 * midway through this enumaration?
259483114Sscottl				 * XXX This should be done async.
259583114Sscottl				 */
259695966Sscottl				bzero(mi, sizeof(struct aac_mntinfo));
259795966Sscottl				mi->Command = VM_NameServe;
259895966Sscottl				mi->MntType = FT_FILESYS;
259995350Sscottl				mi->MntCount = i;
260083114Sscottl				rsize = sizeof(mir);
260195350Sscottl				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
260295350Sscottl						 sizeof(struct aac_mntinfo))) {
260383114Sscottl					debug(2, "Error probing container %d\n",
260483114Sscottl					      i);
260583114Sscottl					continue;
260683114Sscottl				}
260795350Sscottl				mir = (struct aac_mntinforesp *)&fib->data[0];
260883114Sscottl				/*
260983114Sscottl				 * Check the container against our list.
261083114Sscottl				 * co->co_found was already set to 0 in a
261183114Sscottl				 * previous run.
261283114Sscottl				 */
261395350Sscottl				if ((mir->Status == ST_OK) &&
261495350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
261583114Sscottl					found = 0;
261683114Sscottl					TAILQ_FOREACH(co,
261783114Sscottl						      &sc->aac_container_tqh,
261883114Sscottl						      co_link) {
261983114Sscottl						if (co->co_mntobj.ObjectId ==
262095350Sscottl						    mir->MntTable[0].ObjectId) {
262183114Sscottl							co->co_found = 1;
262283114Sscottl							found = 1;
262383114Sscottl							break;
262483114Sscottl						}
262583114Sscottl					}
262683114Sscottl					/*
262783114Sscottl					 * If the container matched, continue
262883114Sscottl					 * in the list.
262983114Sscottl					 */
263083114Sscottl					if (found) {
263183114Sscottl						i++;
263283114Sscottl						continue;
263383114Sscottl					}
263483114Sscottl
263583114Sscottl					/*
263683114Sscottl					 * This is a new container.  Do all the
2637110426Sscottl					 * appropriate things to set it up.
2638110426Sscottl					 */
263995350Sscottl					aac_add_container(sc, mir, 1);
264083114Sscottl					added = 1;
264183114Sscottl				}
264283114Sscottl				i++;
264395350Sscottl			} while ((i < mir->MntRespCount) &&
264483114Sscottl				 (i < AAC_MAX_CONTAINERS));
264595350Sscottl			aac_release_sync_fib(sc);
264683114Sscottl
264783114Sscottl			/*
264883114Sscottl			 * Go through our list of containers and see which ones
264983114Sscottl			 * were not marked 'found'.  Since the controller didn't
265083114Sscottl			 * list them they must have been deleted.  Do the
265183114Sscottl			 * appropriate steps to destroy the device.  Also reset
265283114Sscottl			 * the co->co_found field.
265383114Sscottl			 */
265483114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
265583114Sscottl			while (co != NULL) {
265683114Sscottl				if (co->co_found == 0) {
265783114Sscottl					device_delete_child(sc->aac_dev,
265883114Sscottl							    co->co_disk);
265983114Sscottl					co_next = TAILQ_NEXT(co, co_link);
266087310Sscottl					AAC_LOCK_ACQUIRE(&sc->
266183114Sscottl							aac_container_lock);
266283114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
266383114Sscottl						     co_link);
266483114Sscottl					AAC_LOCK_RELEASE(&sc->
266583114Sscottl							 aac_container_lock);
266683114Sscottl					FREE(co, M_AACBUF);
266783114Sscottl					co = co_next;
266883114Sscottl				} else {
266983114Sscottl					co->co_found = 0;
267083114Sscottl					co = TAILQ_NEXT(co, co_link);
267183114Sscottl				}
267282527Sscottl			}
267382527Sscottl
267483114Sscottl			/* Attach the newly created containers */
267583114Sscottl			if (added)
267683114Sscottl				bus_generic_attach(sc->aac_dev);
267783114Sscottl
2678105528Sphk			break;
267982527Sscottl
268083114Sscottl		default:
268183114Sscottl			break;
268282527Sscottl		}
268382527Sscottl
268482527Sscottl	default:
268583114Sscottl		break;
268682527Sscottl	}
268782527Sscottl
268883114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
268987310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
269083114Sscottl	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
269183114Sscottl	if (next != sc->aac_aifq_tail) {
269283114Sscottl		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
269387183Sscottl		sc->aac_aifq_head = next;
269487183Sscottl
269587183Sscottl		/* On the off chance that someone is sleeping for an aif... */
269687183Sscottl		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
269787183Sscottl			wakeup(sc->aac_aifq);
269887183Sscottl		/* Wakeup any poll()ers */
269987183Sscottl		selwakeup(&sc->rcv_select);
270083114Sscottl	}
270187183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
270282527Sscottl
270383114Sscottl	return;
270465793Smsmith}
270565793Smsmith
270683114Sscottl/*
270770393Smsmith * Return the Revision of the driver to userspace and check to see if the
270882527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
270982527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
271082527Sscottl * returning what the card reported.
271165793Smsmith */
271265793Smsmithstatic int
271381189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
271465793Smsmith{
271583114Sscottl	struct aac_rev_check rev_check;
271683114Sscottl	struct aac_rev_check_resp rev_check_resp;
271783114Sscottl	int error = 0;
271865793Smsmith
271983114Sscottl	debug_called(2);
272065793Smsmith
272183114Sscottl	/*
272283114Sscottl	 * Copyin the revision struct from userspace
272383114Sscottl	 */
272483114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
272581082Sscottl			sizeof(struct aac_rev_check))) != 0) {
272683114Sscottl		return error;
272783114Sscottl	}
272865793Smsmith
272983114Sscottl	debug(2, "Userland revision= %d\n",
273083114Sscottl	      rev_check.callingRevision.buildNumber);
273165793Smsmith
273283114Sscottl	/*
273383114Sscottl	 * Doctor up the response struct.
273483114Sscottl	 */
273583114Sscottl	rev_check_resp.possiblyCompatible = 1;
273683114Sscottl	rev_check_resp.adapterSWRevision.external.ul =
273783114Sscottl	    sc->aac_revision.external.ul;
273883114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
273983114Sscottl	    sc->aac_revision.buildNumber;
274065793Smsmith
274183114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
274283114Sscottl			sizeof(struct aac_rev_check_resp)));
274365793Smsmith}
274465793Smsmith
274583114Sscottl/*
274665793Smsmith * Pass the caller the next AIF in their queue
274765793Smsmith */
274865793Smsmithstatic int
274981189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
275065793Smsmith{
275183114Sscottl	struct get_adapter_fib_ioctl agf;
2752111691Sscottl	int error;
275365793Smsmith
275483114Sscottl	debug_called(2);
275565793Smsmith
275683114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
275765793Smsmith
275883114Sscottl		/*
275983114Sscottl		 * Check the magic number that we gave the caller.
276083114Sscottl		 */
276183114Sscottl		if (agf.AdapterFibContext != (int)sc->aifthread) {
276283114Sscottl			error = EFAULT;
276383114Sscottl		} else {
276481189Sscottl			error = aac_return_aif(sc, agf.AifFib);
276583114Sscottl			if ((error == EAGAIN) && (agf.Wait)) {
276683114Sscottl				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
276783114Sscottl				while (error == EAGAIN) {
276883114Sscottl					error = tsleep(sc->aac_aifq, PRIBIO |
276983114Sscottl						       PCATCH, "aacaif", 0);
277083114Sscottl					if (error == 0)
277183114Sscottl						error = aac_return_aif(sc,
277283114Sscottl						    agf.AifFib);
277383114Sscottl				}
277483114Sscottl				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
277583114Sscottl			}
277665793Smsmith		}
277765793Smsmith	}
277883114Sscottl	return(error);
277965793Smsmith}
278065793Smsmith
278183114Sscottl/*
278270393Smsmith * Hand the next AIF off the top of the queue out to userspace.
278370393Smsmith */
278470393Smsmithstatic int
278581189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr)
278670393Smsmith{
278787183Sscottl	int error;
278870393Smsmith
278983114Sscottl	debug_called(2);
279070393Smsmith
279187310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
279283114Sscottl	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
279383114Sscottl		error = EAGAIN;
279483114Sscottl	} else {
279583114Sscottl		error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
279683114Sscottl				sizeof(struct aac_aif_command));
279783114Sscottl		if (error)
2798110426Sscottl			device_printf(sc->aac_dev,
2799110426Sscottl			    "aac_return_aif: copyout returned %d\n", error);
280083114Sscottl		if (!error)
280183114Sscottl			sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) %
280283114Sscottl					    AAC_AIFQ_LENGTH;
280383114Sscottl	}
280487183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
280583114Sscottl	return(error);
280670393Smsmith}
280782527Sscottl
280883114Sscottl/*
280982527Sscottl * Give the userland some information about the container.  The AAC arch
281082527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
281182527Sscottl * the containers to have b:t:l numbers.  Fake it.
281282527Sscottl */
281382527Sscottlstatic int
281482527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
281582527Sscottl{
281683114Sscottl	struct aac_query_disk query_disk;
281783114Sscottl	struct aac_container *co;
281883114Sscottl	struct aac_disk	*disk;
281983114Sscottl	int error, id;
282082527Sscottl
282183114Sscottl	debug_called(2);
282282527Sscottl
282383114Sscottl	disk = NULL;
282482527Sscottl
282583114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
282683114Sscottl		       sizeof(struct aac_query_disk));
282783114Sscottl	if (error)
282883114Sscottl		return (error);
282982527Sscottl
283083114Sscottl	id = query_disk.ContainerNumber;
283183114Sscottl	if (id == -1)
283283114Sscottl		return (EINVAL);
283382527Sscottl
283487310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
283583114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
283683114Sscottl		if (co->co_mntobj.ObjectId == id)
283783114Sscottl			break;
283883114Sscottl		}
283982527Sscottl
2840105528Sphk	if (co == NULL) {
284183114Sscottl			query_disk.Valid = 0;
284283114Sscottl			query_disk.Locked = 0;
284383114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
2844105528Sphk	} else {
2845105528Sphk		disk = device_get_softc(co->co_disk);
2846105528Sphk		query_disk.Valid = 1;
2847105528Sphk		query_disk.Locked =
2848105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
2849105528Sphk		query_disk.Deleted = 0;
2850105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
2851105528Sphk		query_disk.Target = disk->unit;
2852105528Sphk		query_disk.Lun = 0;
2853105528Sphk		query_disk.UnMapped = 0;
2854111525Sscottl		sprintf(&query_disk.diskDeviceName[0], "%s%d",
2855111525Sscottl		        disk->ad_disk.d_name, disk->ad_disk.d_unit);
2856105528Sphk	}
285783114Sscottl	AAC_LOCK_RELEASE(&sc->aac_container_lock);
285882527Sscottl
285983114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
286083114Sscottl			sizeof(struct aac_query_disk));
286183114Sscottl
286283114Sscottl	return (error);
286382527Sscottl}
286482527Sscottl
286595536Sscottlstatic void
286695536Sscottlaac_get_bus_info(struct aac_softc *sc)
286795536Sscottl{
286895536Sscottl	struct aac_fib *fib;
286995536Sscottl	struct aac_ctcfg *c_cmd;
287095536Sscottl	struct aac_ctcfg_resp *c_resp;
287195536Sscottl	struct aac_vmioctl *vmi;
287295536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
287395536Sscottl	struct aac_getbusinf businfo;
2874110426Sscottl	struct aac_sim *caminf;
287595536Sscottl	device_t child;
287695536Sscottl	int i, found, error;
287795536Sscottl
287895536Sscottl	aac_alloc_sync_fib(sc, &fib, 0);
287995536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
288095966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
288195536Sscottl
288295536Sscottl	c_cmd->Command = VM_ContainerConfig;
288395536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
288495536Sscottl	c_cmd->param = 0;
288595536Sscottl
288695536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
288795536Sscottl	    sizeof(struct aac_ctcfg));
288895536Sscottl	if (error) {
288995536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
289095536Sscottl		    "VM_ContainerConfig command\n", error);
289195536Sscottl		aac_release_sync_fib(sc);
289295536Sscottl		return;
289395536Sscottl	}
289495536Sscottl
289595536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
289695536Sscottl	if (c_resp->Status != ST_OK) {
289795536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
289895536Sscottl		    c_resp->Status);
289995536Sscottl		aac_release_sync_fib(sc);
290095536Sscottl		return;
290195536Sscottl	}
290295536Sscottl
290395536Sscottl	sc->scsi_method_id = c_resp->param;
290495536Sscottl
290595536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
290695966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
290795966Sscottl
290895536Sscottl	vmi->Command = VM_Ioctl;
290995536Sscottl	vmi->ObjType = FT_DRIVE;
291095536Sscottl	vmi->MethId = sc->scsi_method_id;
291195536Sscottl	vmi->ObjId = 0;
291295536Sscottl	vmi->IoctlCmd = GetBusInfo;
291395536Sscottl
291495536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
291595536Sscottl	    sizeof(struct aac_vmioctl));
291695536Sscottl	if (error) {
291795536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
291895536Sscottl		    error);
291995536Sscottl		aac_release_sync_fib(sc);
292095536Sscottl		return;
292195536Sscottl	}
292295536Sscottl
292395536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
292495536Sscottl	if (vmi_resp->Status != ST_OK) {
292595536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
292695536Sscottl		    vmi_resp->Status);
292795536Sscottl		aac_release_sync_fib(sc);
292895536Sscottl		return;
292995536Sscottl	}
293095536Sscottl
293195536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
293295536Sscottl	aac_release_sync_fib(sc);
293395536Sscottl
293495536Sscottl	found = 0;
293595536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
293695536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
293795536Sscottl			continue;
293895536Sscottl
2939110428Sscottl		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
2940110428Sscottl		    M_AACBUF, M_NOWAIT | M_ZERO);
294195536Sscottl		if (caminf == NULL)
294295536Sscottl			continue;
294395536Sscottl
294495536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
294595536Sscottl		if (child == NULL) {
294695536Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
294795536Sscottl			continue;
294895536Sscottl		}
294995536Sscottl
295095536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
295195536Sscottl		caminf->BusNumber = i;
295295536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
295395536Sscottl		caminf->aac_sc = sc;
2954110432Sscottl		caminf->sim_dev = child;
295595536Sscottl
295695536Sscottl		device_set_ivars(child, caminf);
295795536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
2958110426Sscottl		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
295995536Sscottl
296095536Sscottl		found = 1;
296195536Sscottl	}
296295536Sscottl
296395536Sscottl	if (found)
296495536Sscottl		bus_generic_attach(sc->aac_dev);
296595536Sscottl
296695536Sscottl	return;
296795536Sscottl}
2968