aac.c revision 108329
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 108329 2002-12-27 17:52:16Z rwatson $
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>
4489316Salfred#include <sys/lock.h>
4589316Salfred#include <sys/mutex.h>
4681154Sscottl#include <sys/sysctl.h>
4787183Sscottl#include <sys/poll.h>
4887310Sscottl#if __FreeBSD_version >= 500005
4987183Sscottl#include <sys/selinfo.h>
5087310Sscottl#else
5187310Sscottl#include <sys/select.h>
5287310Sscottl#endif
5365793Smsmith
5465793Smsmith#include <dev/aac/aac_compat.h>
5565793Smsmith
5665793Smsmith#include <sys/bus.h>
5765793Smsmith#include <sys/conf.h>
5865793Smsmith#include <sys/devicestat.h>
5965793Smsmith#include <sys/disk.h>
6065793Smsmith#include <sys/signalvar.h>
6170393Smsmith#include <sys/time.h>
6282527Sscottl#include <sys/eventhandler.h>
6365793Smsmith
6465793Smsmith#include <machine/bus_memio.h>
6565793Smsmith#include <machine/bus.h>
6665793Smsmith#include <machine/resource.h>
6765793Smsmith
6865793Smsmith#include <dev/aac/aacreg.h>
6970393Smsmith#include <dev/aac/aac_ioctl.h>
7065793Smsmith#include <dev/aac/aacvar.h>
7165793Smsmith#include <dev/aac/aac_tables.h>
7295536Sscottl#include <dev/aac/aac_cam.h>
7365793Smsmith
7465793Smsmithstatic void	aac_startup(void *arg);
7583114Sscottlstatic void	aac_add_container(struct aac_softc *sc,
7695350Sscottl				  struct aac_mntinforesp *mir, int f);
7795536Sscottlstatic void	aac_get_bus_info(struct aac_softc *sc);
7865793Smsmith
7965793Smsmith/* Command Processing */
8070393Smsmithstatic void	aac_timeout(struct aac_softc *sc);
8165793Smsmithstatic int	aac_start(struct aac_command *cm);
8265793Smsmithstatic void	aac_complete(void *context, int pending);
8365793Smsmithstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
8465793Smsmithstatic void	aac_bio_complete(struct aac_command *cm);
8565793Smsmithstatic int	aac_wait_command(struct aac_command *cm, int timeout);
8665793Smsmithstatic void	aac_host_command(struct aac_softc *sc);
8765793Smsmithstatic void	aac_host_response(struct aac_softc *sc);
8865793Smsmith
8965793Smsmith/* Command Buffer Management */
9081082Sscottlstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
9181082Sscottl				       int nseg, int error);
9270393Smsmithstatic int	aac_alloc_commands(struct aac_softc *sc);
9370393Smsmithstatic void	aac_free_commands(struct aac_softc *sc);
9465793Smsmithstatic void	aac_map_command(struct aac_command *cm);
9565793Smsmithstatic void	aac_unmap_command(struct aac_command *cm);
9665793Smsmith
9765793Smsmith/* Hardware Interface */
9881082Sscottlstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
9981082Sscottl			       int error);
10090275Sscottlstatic int	aac_check_firmware(struct aac_softc *sc);
10165793Smsmithstatic int	aac_init(struct aac_softc *sc);
10265793Smsmithstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
10381082Sscottl				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
10481082Sscottl				 u_int32_t arg3, u_int32_t *sp);
10581082Sscottlstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
10681151Sscottl				struct aac_command *cm);
10781082Sscottlstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
10883114Sscottl				u_int32_t *fib_size, struct aac_fib **fib_addr);
10982527Sscottlstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
11082527Sscottl				     struct aac_fib *fib);
11165793Smsmith
11287183Sscottl/* Falcon/PPC interface */
11387183Sscottlstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
11487183Sscottlstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
11587183Sscottlstatic int	aac_fa_get_istatus(struct aac_softc *sc);
11687183Sscottlstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
11787183Sscottlstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
11887183Sscottl				   u_int32_t arg0, u_int32_t arg1,
11987183Sscottl				   u_int32_t arg2, u_int32_t arg3);
12087183Sscottlstatic int	aac_fa_get_mailboxstatus(struct aac_softc *sc);
12187183Sscottlstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
12287183Sscottl
12387183Sscottlstruct aac_interface aac_fa_interface = {
12487183Sscottl	aac_fa_get_fwstatus,
12587183Sscottl	aac_fa_qnotify,
12687183Sscottl	aac_fa_get_istatus,
12787183Sscottl	aac_fa_clear_istatus,
12887183Sscottl	aac_fa_set_mailbox,
12987183Sscottl	aac_fa_get_mailboxstatus,
13087183Sscottl	aac_fa_set_interrupts
13187183Sscottl};
13287183Sscottl
13365793Smsmith/* StrongARM interface */
13465793Smsmithstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
13565793Smsmithstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13665793Smsmithstatic int	aac_sa_get_istatus(struct aac_softc *sc);
13765793Smsmithstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13865793Smsmithstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
13981082Sscottl				   u_int32_t arg0, u_int32_t arg1,
14081082Sscottl				   u_int32_t arg2, u_int32_t arg3);
14165793Smsmithstatic int	aac_sa_get_mailboxstatus(struct aac_softc *sc);
14265793Smsmithstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
14365793Smsmith
14465793Smsmithstruct aac_interface aac_sa_interface = {
14583114Sscottl	aac_sa_get_fwstatus,
14683114Sscottl	aac_sa_qnotify,
14783114Sscottl	aac_sa_get_istatus,
14883114Sscottl	aac_sa_clear_istatus,
14983114Sscottl	aac_sa_set_mailbox,
15083114Sscottl	aac_sa_get_mailboxstatus,
15183114Sscottl	aac_sa_set_interrupts
15265793Smsmith};
15365793Smsmith
15483114Sscottl/* i960Rx interface */
15565793Smsmithstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
15665793Smsmithstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15765793Smsmithstatic int	aac_rx_get_istatus(struct aac_softc *sc);
15865793Smsmithstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15965793Smsmithstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
16081082Sscottl				   u_int32_t arg0, u_int32_t arg1,
16181082Sscottl				   u_int32_t arg2, u_int32_t arg3);
16265793Smsmithstatic int	aac_rx_get_mailboxstatus(struct aac_softc *sc);
16365793Smsmithstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
16465793Smsmith
16565793Smsmithstruct aac_interface aac_rx_interface = {
16683114Sscottl	aac_rx_get_fwstatus,
16783114Sscottl	aac_rx_qnotify,
16883114Sscottl	aac_rx_get_istatus,
16983114Sscottl	aac_rx_clear_istatus,
17083114Sscottl	aac_rx_set_mailbox,
17183114Sscottl	aac_rx_get_mailboxstatus,
17283114Sscottl	aac_rx_set_interrupts
17365793Smsmith};
17465793Smsmith
17565793Smsmith/* Debugging and Diagnostics */
17665793Smsmithstatic void	aac_describe_controller(struct aac_softc *sc);
17782567Sscottlstatic char	*aac_describe_code(struct aac_code_lookup *table,
17881082Sscottl				   u_int32_t code);
17965793Smsmith
18065793Smsmith/* Management Interface */
18165793Smsmithstatic d_open_t		aac_open;
18265793Smsmithstatic d_close_t	aac_close;
18365793Smsmithstatic d_ioctl_t	aac_ioctl;
18487183Sscottlstatic d_poll_t		aac_poll;
18581082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
18681082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
18783114Sscottl					   struct aac_fib *fib);
18881189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
18981189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
19081189Sscottlstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
19182527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
19265793Smsmith
19365793Smsmith#define AAC_CDEV_MAJOR	150
19465793Smsmith
19565793Smsmithstatic struct cdevsw aac_cdevsw = {
19683114Sscottl	aac_open,		/* open */
19783114Sscottl	aac_close,		/* close */
19883114Sscottl	noread,			/* read */
19983114Sscottl	nowrite,		/* write */
20083114Sscottl	aac_ioctl,		/* ioctl */
20187183Sscottl	aac_poll,		/* poll */
20283114Sscottl	nommap,			/* mmap */
20383114Sscottl	nostrategy,		/* strategy */
20483114Sscottl	"aac",			/* name */
20583114Sscottl	AAC_CDEV_MAJOR,		/* major */
20683114Sscottl	nodump,			/* dump */
20783114Sscottl	nopsize,		/* psize */
20883114Sscottl	0,			/* flags */
20982527Sscottl#if __FreeBSD_version < 500005
21083114Sscottl	-1,			/* bmaj */
21182527Sscottl#endif
21265793Smsmith};
21365793Smsmith
21482527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
21582527Sscottl
21681154Sscottl/* sysctl node */
21781154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
21881154Sscottl
21983114Sscottl/*
22083114Sscottl * Device Interface
22183114Sscottl */
22265793Smsmith
22383114Sscottl/*
22465793Smsmith * Initialise the controller and softc
22565793Smsmith */
22665793Smsmithint
22765793Smsmithaac_attach(struct aac_softc *sc)
22865793Smsmith{
22983114Sscottl	int error, unit;
23065793Smsmith
23183114Sscottl	debug_called(1);
23265793Smsmith
23383114Sscottl	/*
23483114Sscottl	 * Initialise per-controller queues.
23583114Sscottl	 */
23683114Sscottl	aac_initq_free(sc);
23783114Sscottl	aac_initq_ready(sc);
23883114Sscottl	aac_initq_busy(sc);
23983114Sscottl	aac_initq_complete(sc);
24083114Sscottl	aac_initq_bio(sc);
24165793Smsmith
24265793Smsmith#if __FreeBSD_version >= 500005
24383114Sscottl	/*
24483114Sscottl	 * Initialise command-completion task.
24583114Sscottl	 */
24683114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
24765793Smsmith#endif
24865793Smsmith
24983114Sscottl	/* disable interrupts before we enable anything */
25083114Sscottl	AAC_MASK_INTERRUPTS(sc);
25165793Smsmith
25283114Sscottl	/* mark controller as suspended until we get ourselves organised */
25383114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
25465793Smsmith
25583114Sscottl	/*
25690275Sscottl	 * Check that the firmware on the card is supported.
25790275Sscottl	 */
25890275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
25990275Sscottl		return(error);
26090275Sscottl
26190275Sscottl	/*
26283114Sscottl	 * Allocate command structures.
26383114Sscottl	 */
26483114Sscottl	if ((error = aac_alloc_commands(sc)) != 0)
26583114Sscottl		return(error);
26670393Smsmith
26795350Sscottl	/* Init the sync fib lock */
26895350Sscottl	AAC_LOCK_INIT(&sc->aac_sync_lock, "AAC sync FIB lock");
26995350Sscottl
27083114Sscottl	/*
27183114Sscottl	 * Initialise the adapter.
27283114Sscottl	 */
27383114Sscottl	if ((error = aac_init(sc)) != 0)
27483114Sscottl		return(error);
27565793Smsmith
27683114Sscottl	/*
27783114Sscottl	 * Print a little information about the controller.
27883114Sscottl	 */
27983114Sscottl	aac_describe_controller(sc);
28065793Smsmith
28183114Sscottl	/*
28283114Sscottl	 * Register to probe our containers later.
28383114Sscottl	 */
28483114Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
28587183Sscottl	AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
28682527Sscottl
28787183Sscottl	/*
28887183Sscottl	 * Lock for the AIF queue
28987183Sscottl	 */
29087183Sscottl	AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
29187183Sscottl
29283114Sscottl	sc->aac_ich.ich_func = aac_startup;
29383114Sscottl	sc->aac_ich.ich_arg = sc;
29483114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
29583114Sscottl		device_printf(sc->aac_dev,
29683114Sscottl			      "can't establish configuration hook\n");
29783114Sscottl		return(ENXIO);
29883114Sscottl	}
29965793Smsmith
30083114Sscottl	/*
30183114Sscottl	 * Make the control device.
30283114Sscottl	 */
30383114Sscottl	unit = device_get_unit(sc->aac_dev);
304108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
305108329Srwatson				 0640, "aac%d", unit);
30682527Sscottl#if __FreeBSD_version > 500005
30783114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
30883114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
30982527Sscottl#endif
31083114Sscottl	sc->aac_dev_t->si_drv1 = sc;
31165793Smsmith
31283114Sscottl	/* Create the AIF thread */
31382527Sscottl#if __FreeBSD_version > 500005
31483114Sscottl	if (kthread_create((void(*)(void *))aac_host_command, sc,
315104354Sscottl			   &sc->aifthread, 0, 0, "aac%daif", unit))
31682527Sscottl#else
31783114Sscottl	if (kthread_create((void(*)(void *))aac_host_command, sc,
31883114Sscottl			   &sc->aifthread, "aac%daif", unit))
31982527Sscottl#endif
32083114Sscottl		panic("Could not create AIF thread\n");
32182527Sscottl
32283114Sscottl	/* Register the shutdown method to only be called post-dump */
32383114Sscottl	if ((EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, sc->aac_dev,
32483114Sscottl				   SHUTDOWN_PRI_DEFAULT)) == NULL)
32582527Sscottl	device_printf(sc->aac_dev, "shutdown event registration failed\n");
32682527Sscottl
32795536Sscottl	/* Register with CAM for the non-DASD devices */
32895536Sscottl	if (!(sc->quirks & AAC_QUIRK_NOCAM))
32995536Sscottl		aac_get_bus_info(sc);
33095536Sscottl
33183114Sscottl	return(0);
33265793Smsmith}
33365793Smsmith
33483114Sscottl/*
33565793Smsmith * Probe for containers, create disks.
33665793Smsmith */
33765793Smsmithstatic void
33865793Smsmithaac_startup(void *arg)
33965793Smsmith{
34083114Sscottl	struct aac_softc *sc;
34195350Sscottl	struct aac_fib *fib;
34295350Sscottl	struct aac_mntinfo *mi;
34395350Sscottl	struct aac_mntinforesp *mir = NULL;
34483114Sscottl	int i = 0;
34565793Smsmith
34683114Sscottl	debug_called(1);
34765793Smsmith
34883114Sscottl	sc = (struct aac_softc *)arg;
34965793Smsmith
35083114Sscottl	/* disconnect ourselves from the intrhook chain */
35183114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
35265793Smsmith
35395536Sscottl	aac_alloc_sync_fib(sc, &fib, 0);
35495350Sscottl	mi = (struct aac_mntinfo *)&fib->data[0];
35595350Sscottl
35683114Sscottl	/* loop over possible containers */
35783114Sscottl	do {
35883114Sscottl		/* request information on this container */
35995966Sscottl		bzero(mi, sizeof(struct aac_mntinfo));
36095966Sscottl		mi->Command = VM_NameServe;
36195966Sscottl		mi->MntType = FT_FILESYS;
36295350Sscottl		mi->MntCount = i;
36395350Sscottl		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
36495350Sscottl				 sizeof(struct aac_mntinfo))) {
36583114Sscottl			debug(2, "error probing container %d", i);
36683114Sscottl			continue;
36783114Sscottl		}
36865793Smsmith
36995350Sscottl		mir = (struct aac_mntinforesp *)&fib->data[0];
37095350Sscottl		aac_add_container(sc, mir, 0);
37183114Sscottl		i++;
37295350Sscottl	} while ((i < mir->MntRespCount) && (i < AAC_MAX_CONTAINERS));
37365793Smsmith
37495350Sscottl	aac_release_sync_fib(sc);
37595350Sscottl
37683114Sscottl	/* poke the bus to actually attach the child devices */
37783114Sscottl	if (bus_generic_attach(sc->aac_dev))
37883114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
37965793Smsmith
38083114Sscottl	/* mark the controller up */
38183114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
38270393Smsmith
38383114Sscottl	/* enable interrupts now */
38483114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
38583114Sscottl
38683114Sscottl	/* enable the timeout watchdog */
38783114Sscottl	timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
38865793Smsmith}
38965793Smsmith
39083114Sscottl/*
39183114Sscottl * Create a device to respresent a new container
39283114Sscottl */
39383114Sscottlstatic void
39495350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
39583114Sscottl{
39683114Sscottl	struct aac_container *co;
39783114Sscottl	device_t child;
39883114Sscottl
39983114Sscottl	/*
40083114Sscottl	 * Check container volume type for validity.  Note that many of
40183114Sscottl	 * the possible types may never show up.
40283114Sscottl	 */
40383114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
40483114Sscottl		MALLOC(co, struct aac_container *, sizeof *co, M_AACBUF,
40583114Sscottl		       M_NOWAIT);
40683114Sscottl		if (co == NULL)
40783114Sscottl			panic("Out of memory?!\n");
40883114Sscottl		debug(1, "id %x  name '%.16s'  size %u  type %d",
40983114Sscottl		      mir->MntTable[0].ObjectId,
41083114Sscottl		      mir->MntTable[0].FileSystemName,
41183114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
41283114Sscottl
41395536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
41483114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
41583114Sscottl		else
41683114Sscottl			device_set_ivars(child, co);
41783114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
41883114Sscottl				mir->MntTable[0].VolType));
41983114Sscottl		co->co_disk = child;
42083114Sscottl		co->co_found = f;
42183114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
42283114Sscottl		      sizeof(struct aac_mntobj));
42387310Sscottl		AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
42483114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
42583114Sscottl		AAC_LOCK_RELEASE(&sc->aac_container_lock);
42683114Sscottl	}
42783114Sscottl}
42883114Sscottl
42983114Sscottl/*
43065793Smsmith * Free all of the resources associated with (sc)
43165793Smsmith *
43265793Smsmith * Should not be called if the controller is active.
43365793Smsmith */
43465793Smsmithvoid
43565793Smsmithaac_free(struct aac_softc *sc)
43665793Smsmith{
43783114Sscottl	debug_called(1);
43865793Smsmith
43983114Sscottl	/* remove the control device */
44083114Sscottl	if (sc->aac_dev_t != NULL)
44183114Sscottl		destroy_dev(sc->aac_dev_t);
44265793Smsmith
44383114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
44483114Sscottl	if (sc->aac_fibs != NULL)
44583114Sscottl		aac_free_commands(sc);
44683114Sscottl	if (sc->aac_fib_dmat)
44783114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
44865793Smsmith
44983114Sscottl	/* destroy the common area */
45083114Sscottl	if (sc->aac_common) {
45183114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
45283114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
45383114Sscottl				sc->aac_common_dmamap);
45483114Sscottl	}
45583114Sscottl	if (sc->aac_common_dmat)
45683114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
45765793Smsmith
45883114Sscottl	/* disconnect the interrupt handler */
45983114Sscottl	if (sc->aac_intr)
46083114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
46183114Sscottl	if (sc->aac_irq != NULL)
46283114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
46383114Sscottl				     sc->aac_irq);
46465793Smsmith
46583114Sscottl	/* destroy data-transfer DMA tag */
46683114Sscottl	if (sc->aac_buffer_dmat)
46783114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
46865793Smsmith
46983114Sscottl	/* destroy the parent DMA tag */
47083114Sscottl	if (sc->aac_parent_dmat)
47183114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
47265793Smsmith
47383114Sscottl	/* release the register window mapping */
47483114Sscottl	if (sc->aac_regs_resource != NULL)
47583114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
47683114Sscottl				     sc->aac_regs_rid, sc->aac_regs_resource);
47765793Smsmith}
47865793Smsmith
47983114Sscottl/*
48065793Smsmith * Disconnect from the controller completely, in preparation for unload.
48165793Smsmith */
48265793Smsmithint
48365793Smsmithaac_detach(device_t dev)
48465793Smsmith{
48583114Sscottl	struct aac_softc *sc;
48682527Sscottl#if AAC_BROKEN
48783114Sscottl	int error;
48882527Sscottl#endif
48965793Smsmith
49083114Sscottl	debug_called(1);
49165793Smsmith
49283114Sscottl	sc = device_get_softc(dev);
49383114Sscottl
49483114Sscottl	if (sc->aac_state & AAC_STATE_OPEN)
49565793Smsmith	return(EBUSY);
49665793Smsmith
49782527Sscottl#if AAC_BROKEN
49883114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
49983114Sscottl		sc->aifflags |= AAC_AIFFLAGS_EXIT;
50083114Sscottl		wakeup(sc->aifthread);
50183114Sscottl		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
50283114Sscottl	}
50382527Sscottl
50483114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
50583114Sscottl		panic("Cannot shutdown AIF thread\n");
50682527Sscottl
50783114Sscottl	if ((error = aac_shutdown(dev)))
50883114Sscottl		return(error);
50965793Smsmith
51083114Sscottl	aac_free(sc);
51165793Smsmith
51283114Sscottl	return(0);
51382527Sscottl#else
51483114Sscottl	return (EBUSY);
51582527Sscottl#endif
51665793Smsmith}
51765793Smsmith
51883114Sscottl/*
51965793Smsmith * Bring the controller down to a dormant state and detach all child devices.
52065793Smsmith *
52165793Smsmith * This function is called before detach or system shutdown.
52265793Smsmith *
52370393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
52465793Smsmith * allow shutdown if any device is open.
52565793Smsmith */
52665793Smsmithint
52765793Smsmithaac_shutdown(device_t dev)
52865793Smsmith{
52983114Sscottl	struct aac_softc *sc;
53095350Sscottl	struct aac_fib *fib;
53195350Sscottl	struct aac_close_command *cc;
53295350Sscottl	int s;
53365793Smsmith
53483114Sscottl	debug_called(1);
53565793Smsmith
53683114Sscottl	sc = device_get_softc(dev);
53765793Smsmith
53883114Sscottl	s = splbio();
53965793Smsmith
54083114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
54165793Smsmith
54283114Sscottl	/*
54383114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
54483114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
54583114Sscottl	 * We've been closed and all I/O completed already
54682527Sscottl	 */
54783114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
54883114Sscottl
54995536Sscottl	aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
55095350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
55195350Sscottl
55295966Sscottl	bzero(cc, sizeof(struct aac_close_command));
55395350Sscottl	cc->Command = VM_CloseAll;
55495350Sscottl	cc->ContainerId = 0xffffffff;
55595350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
55695350Sscottl	    sizeof(struct aac_close_command)))
55783114Sscottl		printf("FAILED.\n");
55883114Sscottl	else {
55995350Sscottl		fib->data[0] = 0;
56083114Sscottl		/*
56183114Sscottl		 * XXX Issuing this command to the controller makes it shut down
56283114Sscottl		 * but also keeps it from coming back up without a reset of the
56383114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
56483114Sscottl		 * driver module with the intent to reload it later.
56583114Sscottl		 */
56695350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
56795350Sscottl		    fib, 1)) {
56883114Sscottl			printf("FAILED.\n");
56983114Sscottl		} else {
57083114Sscottl			printf("done.\n");
57183114Sscottl		}
57265793Smsmith	}
57365793Smsmith
57483114Sscottl	AAC_MASK_INTERRUPTS(sc);
57565793Smsmith
57683114Sscottl	splx(s);
57783114Sscottl	return(0);
57865793Smsmith}
57965793Smsmith
58083114Sscottl/*
58165793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
58265793Smsmith */
58365793Smsmithint
58465793Smsmithaac_suspend(device_t dev)
58565793Smsmith{
58683114Sscottl	struct aac_softc *sc;
58783114Sscottl	int s;
58865793Smsmith
58983114Sscottl	debug_called(1);
59065793Smsmith
59183114Sscottl	sc = device_get_softc(dev);
59283114Sscottl
59383114Sscottl	s = splbio();
59483114Sscottl
59583114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
59683114Sscottl
59783114Sscottl	AAC_MASK_INTERRUPTS(sc);
59883114Sscottl	splx(s);
59983114Sscottl	return(0);
60065793Smsmith}
60165793Smsmith
60283114Sscottl/*
60365793Smsmith * Bring the controller back to a state ready for operation.
60465793Smsmith */
60565793Smsmithint
60665793Smsmithaac_resume(device_t dev)
60765793Smsmith{
60883114Sscottl	struct aac_softc *sc;
60965793Smsmith
61083114Sscottl	debug_called(1);
61183114Sscottl
61283114Sscottl	sc = device_get_softc(dev);
61383114Sscottl
61483114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
61583114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
61683114Sscottl	return(0);
61765793Smsmith}
61865793Smsmith
61983114Sscottl/*
62065793Smsmith * Take an interrupt.
62165793Smsmith */
62265793Smsmithvoid
62365793Smsmithaac_intr(void *arg)
62465793Smsmith{
62583114Sscottl	struct aac_softc *sc;
62683114Sscottl	u_int16_t reason;
62765793Smsmith
62883114Sscottl	debug_called(2);
62965793Smsmith
63083114Sscottl	sc = (struct aac_softc *)arg;
63165793Smsmith
63283114Sscottl	reason = AAC_GET_ISTATUS(sc);
63365793Smsmith
63487183Sscottl	/* controller wants to talk to the log */
63583114Sscottl	if (reason & AAC_DB_PRINTF) {
63683114Sscottl		AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
63787183Sscottl		aac_print_printf(sc);
63882527Sscottl	}
63965793Smsmith
64083114Sscottl	/* controller has a message for us? */
64183114Sscottl	if (reason & AAC_DB_COMMAND_READY) {
64283114Sscottl		AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
64383114Sscottl		/* XXX What happens if the thread is already awake? */
64483114Sscottl		if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
64583114Sscottl			sc->aifflags |= AAC_AIFFLAGS_PENDING;
64683114Sscottl			wakeup(sc->aifthread);
64783114Sscottl		}
64883114Sscottl	}
64983114Sscottl
65083114Sscottl	/* controller has a response for us? */
65183114Sscottl	if (reason & AAC_DB_RESPONSE_READY) {
65283114Sscottl		AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
65383114Sscottl		aac_host_response(sc);
65483114Sscottl	}
65583114Sscottl
65683114Sscottl	/*
65783114Sscottl	 * spurious interrupts that we don't use - reset the mask and clear the
65883114Sscottl	 * interrupts
65983114Sscottl	 */
66083114Sscottl	if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
66183114Sscottl		AAC_UNMASK_INTERRUPTS(sc);
66283114Sscottl		AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL |
66383114Sscottl				  AAC_DB_RESPONSE_NOT_FULL);
66483114Sscottl	}
66565793Smsmith};
66665793Smsmith
66783114Sscottl/*
66883114Sscottl * Command Processing
66983114Sscottl */
67065793Smsmith
67183114Sscottl/*
67265793Smsmith * Start as much queued I/O as possible on the controller
67365793Smsmith */
67495536Sscottlvoid
67565793Smsmithaac_startio(struct aac_softc *sc)
67665793Smsmith{
67783114Sscottl	struct aac_command *cm;
67865793Smsmith
67983114Sscottl	debug_called(2);
68065793Smsmith
68183114Sscottl	for (;;) {
68283114Sscottl		/*
68383114Sscottl		 * Try to get a command that's been put off for lack of
68483114Sscottl		 * resources
68583114Sscottl		 */
68683114Sscottl		cm = aac_dequeue_ready(sc);
68765793Smsmith
68883114Sscottl		/*
68983114Sscottl		 * Try to build a command off the bio queue (ignore error
69083114Sscottl		 * return)
69183114Sscottl		 */
69283114Sscottl		if (cm == NULL)
69383114Sscottl			aac_bio_command(sc, &cm);
69465793Smsmith
69583114Sscottl		/* nothing to do? */
69683114Sscottl		if (cm == NULL)
69783114Sscottl			break;
69865793Smsmith
69983114Sscottl		/* try to give the command to the controller */
70083114Sscottl		if (aac_start(cm) == EBUSY) {
70183114Sscottl			/* put it on the ready queue for later */
70283114Sscottl			aac_requeue_ready(cm);
70383114Sscottl			break;
70483114Sscottl		}
70565793Smsmith	}
70665793Smsmith}
70765793Smsmith
70883114Sscottl/*
70965793Smsmith * Deliver a command to the controller; allocate controller resources at the
71065793Smsmith * last moment when possible.
71165793Smsmith */
71265793Smsmithstatic int
71365793Smsmithaac_start(struct aac_command *cm)
71465793Smsmith{
71583114Sscottl	struct aac_softc *sc;
71683114Sscottl	int error;
71765793Smsmith
71883114Sscottl	debug_called(2);
71965793Smsmith
72083114Sscottl	sc = cm->cm_sc;
72165793Smsmith
72283114Sscottl	/* get the command mapped */
72383114Sscottl	aac_map_command(cm);
72465793Smsmith
72583114Sscottl	/* fix up the address values in the FIB */
72683114Sscottl	cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
72783114Sscottl	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
72883114Sscottl
72983114Sscottl	/* save a pointer to the command for speedy reverse-lookup */
73083114Sscottl	cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical
73181082Sscottl							 * address issue */
73265793Smsmith
73383114Sscottl	/* put the FIB on the outbound queue */
73483114Sscottl	error = aac_enqueue_fib(sc, cm->cm_queue, cm);
73583114Sscottl	return(error);
73665793Smsmith}
73765793Smsmith
73883114Sscottl/*
73965793Smsmith * Handle notification of one or more FIBs coming from the controller.
74065793Smsmith */
74165793Smsmithstatic void
74265793Smsmithaac_host_command(struct aac_softc *sc)
74365793Smsmith{
74483114Sscottl	struct aac_fib *fib;
74583114Sscottl	u_int32_t fib_size;
74683114Sscottl	int size;
74765793Smsmith
74883114Sscottl	debug_called(2);
74965793Smsmith
75083114Sscottl	sc->aifflags |= AAC_AIFFLAGS_RUNNING;
75165793Smsmith
75283114Sscottl	while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) {
75383114Sscottl		if (!(sc->aifflags & AAC_AIFFLAGS_PENDING))
75483114Sscottl			tsleep(sc->aifthread, PRIBIO, "aifthd", 15 * hz);
75582527Sscottl
75683114Sscottl		sc->aifflags &= ~AAC_AIFFLAGS_PENDING;
75783114Sscottl		for (;;) {
75883114Sscottl			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
75983114Sscottl					    &fib_size, &fib))
76083114Sscottl				break;	/* nothing to do */
76183114Sscottl
76283114Sscottl			AAC_PRINT_FIB(sc, fib);
76383114Sscottl
76483114Sscottl			switch (fib->Header.Command) {
76583114Sscottl			case AifRequest:
76683114Sscottl				aac_handle_aif(sc, fib);
76783114Sscottl				break;
76883114Sscottl			default:
76983114Sscottl				device_printf(sc->aac_dev, "unknown command "
77083114Sscottl					      "from controller\n");
77183114Sscottl				break;
77283114Sscottl			}
77382527Sscottl
77483114Sscottl			/* Return the AIF to the controller. */
77583114Sscottl			if ((fib->Header.XferState == 0) ||
77683114Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
77783114Sscottl				break;
77882527Sscottl
77983114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
78083114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
78183114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
78282527Sscottl
78383114Sscottl				/* XXX Compute the Size field? */
78483114Sscottl				size = fib->Header.Size;
78583114Sscottl				if (size > sizeof(struct aac_fib)) {
78695536Sscottl					size = sizeof(struct aac_fib);
78783114Sscottl					fib->Header.Size = size;
78883114Sscottl				}
78983114Sscottl				/*
79083114Sscottl				 * Since we did not generate this command, it
79183114Sscottl				 * cannot go through the normal
79283114Sscottl				 * enqueue->startio chain.
79383114Sscottl				 */
79483114Sscottl				aac_enqueue_response(sc,
79583114Sscottl						     AAC_ADAP_NORM_RESP_QUEUE,
79683114Sscottl						     fib);
79783114Sscottl			}
79882527Sscottl		}
79965793Smsmith	}
80083114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
80183114Sscottl	wakeup(sc->aac_dev);
80265793Smsmith
80382527Sscottl#if __FreeBSD_version > 500005
80483114Sscottl	mtx_lock(&Giant);
80582527Sscottl#endif
80683114Sscottl	kthread_exit(0);
80765793Smsmith}
80865793Smsmith
80983114Sscottl/*
81065793Smsmith * Handle notification of one or more FIBs completed by the controller
81165793Smsmith */
81265793Smsmithstatic void
81365793Smsmithaac_host_response(struct aac_softc *sc)
81465793Smsmith{
81583114Sscottl	struct aac_command *cm;
81683114Sscottl	struct aac_fib *fib;
81783114Sscottl	u_int32_t fib_size;
81865793Smsmith
81983114Sscottl	debug_called(2);
82065793Smsmith
82183114Sscottl	for (;;) {
82283114Sscottl		/* look for completed FIBs on our queue */
82383114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
82483114Sscottl				    &fib))
82583114Sscottl			break;	/* nothing to do */
82665793Smsmith
82783114Sscottl		/* get the command, unmap and queue for later processing */
82883114Sscottl		cm = (struct aac_command *)fib->Header.SenderData;
82983114Sscottl		if (cm == NULL) {
83083114Sscottl			AAC_PRINT_FIB(sc, fib);
83183114Sscottl		} else {
83283114Sscottl			aac_remove_busy(cm);
83383114Sscottl			aac_unmap_command(cm);		/* XXX defer? */
83483114Sscottl			aac_enqueue_complete(cm);
83583114Sscottl		}
83665793Smsmith	}
83765793Smsmith
83883114Sscottl	/* handle completion processing */
83965793Smsmith#if __FreeBSD_version >= 500005
84083114Sscottl	taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
84165793Smsmith#else
84283114Sscottl	aac_complete(sc, 0);
84365793Smsmith#endif
84465793Smsmith}
84565793Smsmith
84683114Sscottl/*
84765793Smsmith * Process completed commands.
84865793Smsmith */
84965793Smsmithstatic void
85065793Smsmithaac_complete(void *context, int pending)
85165793Smsmith{
85283114Sscottl	struct aac_softc *sc;
85383114Sscottl	struct aac_command *cm;
85483114Sscottl
85583114Sscottl	debug_called(2);
85665793Smsmith
85783114Sscottl	sc = (struct aac_softc *)context;
85865793Smsmith
85983114Sscottl	/* pull completed commands off the queue */
86083114Sscottl	for (;;) {
86183114Sscottl		cm = aac_dequeue_complete(sc);
86283114Sscottl		if (cm == NULL)
86383114Sscottl			break;
86483114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
86583114Sscottl
86683114Sscottl		/* is there a completion handler? */
86783114Sscottl		if (cm->cm_complete != NULL) {
86883114Sscottl			cm->cm_complete(cm);
86983114Sscottl		} else {
87083114Sscottl			/* assume that someone is sleeping on this command */
87183114Sscottl			wakeup(cm);
87283114Sscottl		}
87365793Smsmith	}
87470393Smsmith
87583114Sscottl	/* see if we can start some more I/O */
87683114Sscottl	aac_startio(sc);
87765793Smsmith}
87865793Smsmith
87983114Sscottl/*
88065793Smsmith * Handle a bio submitted from a disk device.
88165793Smsmith */
88265793Smsmithvoid
88365793Smsmithaac_submit_bio(struct bio *bp)
88465793Smsmith{
88583114Sscottl	struct aac_disk *ad;
88683114Sscottl	struct aac_softc *sc;
88765793Smsmith
88883114Sscottl	debug_called(2);
88965793Smsmith
89083114Sscottl	ad = (struct aac_disk *)bp->bio_dev->si_drv1;
89183114Sscottl	sc = ad->ad_controller;
89283114Sscottl
89383114Sscottl	/* queue the BIO and try to get some work done */
89483114Sscottl	aac_enqueue_bio(sc, bp);
89583114Sscottl	aac_startio(sc);
89665793Smsmith}
89765793Smsmith
89883114Sscottl/*
89965793Smsmith * Get a bio and build a command to go with it.
90065793Smsmith */
90165793Smsmithstatic int
90265793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
90365793Smsmith{
90483114Sscottl	struct aac_command *cm;
90583114Sscottl	struct aac_fib *fib;
90683114Sscottl	struct aac_blockread *br;
90783114Sscottl	struct aac_blockwrite *bw;
90883114Sscottl	struct aac_disk *ad;
90983114Sscottl	struct bio *bp;
91065793Smsmith
91183114Sscottl	debug_called(2);
91265793Smsmith
91383114Sscottl	/* get the resources we will need */
91483114Sscottl	cm = NULL;
91583114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
91683114Sscottl		goto fail;
91783114Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
91883114Sscottl		goto fail;
91965793Smsmith
92083114Sscottl	/* fill out the command */
92183114Sscottl	cm->cm_data = (void *)bp->bio_data;
92283114Sscottl	cm->cm_datalen = bp->bio_bcount;
92383114Sscottl	cm->cm_complete = aac_bio_complete;
92483114Sscottl	cm->cm_private = bp;
92583114Sscottl	cm->cm_timestamp = time_second;
92683114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
92765793Smsmith
92883114Sscottl	/* build the FIB */
92983114Sscottl	fib = cm->cm_fib;
93083114Sscottl	fib->Header.XferState =
93165793Smsmith	AAC_FIBSTATE_HOSTOWNED   |
93265793Smsmith	AAC_FIBSTATE_INITIALISED |
93383114Sscottl	AAC_FIBSTATE_FROMHOST	 |
93465793Smsmith	AAC_FIBSTATE_REXPECTED   |
93565793Smsmith	AAC_FIBSTATE_NORM;
93683114Sscottl	fib->Header.Command = ContainerCommand;
93783114Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
93865793Smsmith
93983114Sscottl	/* build the read/write request */
94083114Sscottl	ad = (struct aac_disk *)bp->bio_dev->si_drv1;
94183114Sscottl	if (BIO_IS_READ(bp)) {
94283114Sscottl		br = (struct aac_blockread *)&fib->data[0];
94383114Sscottl		br->Command = VM_CtBlockRead;
94483114Sscottl		br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
94583114Sscottl		br->BlockNumber = bp->bio_pblkno;
94683114Sscottl		br->ByteCount = bp->bio_bcount;
94783114Sscottl		fib->Header.Size += sizeof(struct aac_blockread);
94883114Sscottl		cm->cm_sgtable = &br->SgMap;
94983114Sscottl		cm->cm_flags |= AAC_CMD_DATAIN;
95083114Sscottl	} else {
95183114Sscottl		bw = (struct aac_blockwrite *)&fib->data[0];
95283114Sscottl		bw->Command = VM_CtBlockWrite;
95383114Sscottl		bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
95483114Sscottl		bw->BlockNumber = bp->bio_pblkno;
95583114Sscottl		bw->ByteCount = bp->bio_bcount;
95683114Sscottl		bw->Stable = CUNSTABLE;	/* XXX what's appropriate here? */
95783114Sscottl		fib->Header.Size += sizeof(struct aac_blockwrite);
95883114Sscottl		cm->cm_flags |= AAC_CMD_DATAOUT;
95983114Sscottl		cm->cm_sgtable = &bw->SgMap;
96083114Sscottl	}
96165793Smsmith
96283114Sscottl	*cmp = cm;
96383114Sscottl	return(0);
96465793Smsmith
96565793Smsmithfail:
96683114Sscottl	if (bp != NULL)
96783114Sscottl		aac_enqueue_bio(sc, bp);
96883114Sscottl	if (cm != NULL)
96983114Sscottl		aac_release_command(cm);
97083114Sscottl	return(ENOMEM);
97165793Smsmith}
97265793Smsmith
97383114Sscottl/*
97465793Smsmith * Handle a bio-instigated command that has been completed.
97565793Smsmith */
97665793Smsmithstatic void
97765793Smsmithaac_bio_complete(struct aac_command *cm)
97865793Smsmith{
97983114Sscottl	struct aac_blockread_response *brr;
98083114Sscottl	struct aac_blockwrite_response *bwr;
98183114Sscottl	struct bio *bp;
98283114Sscottl	AAC_FSAStatus status;
98365793Smsmith
98483114Sscottl	/* fetch relevant status and then release the command */
98583114Sscottl	bp = (struct bio *)cm->cm_private;
98683114Sscottl	if (BIO_IS_READ(bp)) {
98783114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
98883114Sscottl		status = brr->Status;
98983114Sscottl	} else {
99083114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
99183114Sscottl		status = bwr->Status;
99283114Sscottl	}
99383114Sscottl	aac_release_command(cm);
99465793Smsmith
99583114Sscottl	/* fix up the bio based on status */
99683114Sscottl	if (status == ST_OK) {
99783114Sscottl		bp->bio_resid = 0;
99883114Sscottl	} else {
99983114Sscottl		bp->bio_error = EIO;
100083114Sscottl		bp->bio_flags |= BIO_ERROR;
100183114Sscottl		/* pass an error string out to the disk layer */
100283114Sscottl		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
100383114Sscottl						    status);
100483114Sscottl	}
100583114Sscottl	aac_biodone(bp);
100665793Smsmith}
100765793Smsmith
100883114Sscottl/*
100965793Smsmith * Submit a command to the controller, return when it completes.
101087183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
101187183Sscottl *     be stuck here forever.  At the same time, signals are not caught
101287183Sscottl *     because there is a risk that a signal could wakeup the tsleep before
101387183Sscottl *     the card has a chance to complete the command.  The passed in timeout
101487183Sscottl *     is ignored for the same reason.  Since there is no way to cancel a
101587183Sscottl *     command in progress, we should probably create a 'dead' queue where
101687183Sscottl *     commands go that have been interrupted/timed-out/etc, that keeps them
101787183Sscottl *     out of the free pool.  That way, if the card is just slow, it won't
101887183Sscottl *     spam the memory of a command that has been recycled.
101965793Smsmith */
102065793Smsmithstatic int
102165793Smsmithaac_wait_command(struct aac_command *cm, int timeout)
102265793Smsmith{
102383114Sscottl	int s, error = 0;
102465793Smsmith
102583114Sscottl	debug_called(2);
102665793Smsmith
102783114Sscottl	/* Put the command on the ready queue and get things going */
102883114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
102983114Sscottl	aac_enqueue_ready(cm);
103083114Sscottl	aac_startio(cm->cm_sc);
103183114Sscottl	s = splbio();
103283114Sscottl	while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
103387183Sscottl		error = tsleep(cm, PRIBIO, "aacwait", 0);
103483114Sscottl	}
103583114Sscottl	splx(s);
103683114Sscottl	return(error);
103765793Smsmith}
103865793Smsmith
103983114Sscottl/*
104083114Sscottl *Command Buffer Management
104183114Sscottl */
104265793Smsmith
104383114Sscottl/*
104465793Smsmith * Allocate a command.
104565793Smsmith */
104695536Sscottlint
104765793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
104865793Smsmith{
104983114Sscottl	struct aac_command *cm;
105065793Smsmith
105183114Sscottl	debug_called(3);
105265793Smsmith
105383114Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL)
105483114Sscottl		return(ENOMEM);
105565793Smsmith
105683114Sscottl	*cmp = cm;
105783114Sscottl	return(0);
105870393Smsmith}
105970393Smsmith
106083114Sscottl/*
106170393Smsmith * Release a command back to the freelist.
106270393Smsmith */
106395536Sscottlvoid
106470393Smsmithaac_release_command(struct aac_command *cm)
106570393Smsmith{
106683114Sscottl	debug_called(3);
106770393Smsmith
106883114Sscottl	/* (re)initialise the command/FIB */
106983114Sscottl	cm->cm_sgtable = NULL;
107083114Sscottl	cm->cm_flags = 0;
107183114Sscottl	cm->cm_complete = NULL;
107283114Sscottl	cm->cm_private = NULL;
107383114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
107483114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
107583114Sscottl	cm->cm_fib->Header.Flags = 0;
107683114Sscottl	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
107765793Smsmith
107883114Sscottl	/*
107983114Sscottl	 * These are duplicated in aac_start to cover the case where an
108083114Sscottl	 * intermediate stage may have destroyed them.  They're left
108183114Sscottl	 * initialised here for debugging purposes only.
108283114Sscottl	 */
108383114Sscottl	cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
108483114Sscottl	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
108565793Smsmith
108683114Sscottl	aac_enqueue_free(cm);
108765793Smsmith}
108865793Smsmith
108983114Sscottl/*
109070393Smsmith * Map helper for command/FIB allocation.
109165793Smsmith */
109265793Smsmithstatic void
109370393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
109465793Smsmith{
109583114Sscottl	struct aac_softc *sc;
109665793Smsmith
109783114Sscottl	sc = (struct aac_softc *)arg;
109865793Smsmith
109983114Sscottl	debug_called(3);
110083114Sscottl
110183114Sscottl	sc->aac_fibphys = segs[0].ds_addr;
110265793Smsmith}
110365793Smsmith
110483114Sscottl/*
110570393Smsmith * Allocate and initialise commands/FIBs for this adapter.
110665793Smsmith */
110770393Smsmithstatic int
110870393Smsmithaac_alloc_commands(struct aac_softc *sc)
110965793Smsmith{
111083114Sscottl	struct aac_command *cm;
111183114Sscottl	int i;
111265793Smsmith
111383114Sscottl	debug_called(1);
111465793Smsmith
111583114Sscottl	/* allocate the FIBs in DMAable memory and load them */
111683114Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs,
1117102602Sscottl			     BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
1118102602Sscottl		printf("Not enough contiguous memory available.\n");
1119102602Sscottl		return (ENOMEM);
112083114Sscottl	}
112183114Sscottl	bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
112283114Sscottl			AAC_FIB_COUNT * sizeof(struct aac_fib),
112383114Sscottl			aac_map_command_helper, sc, 0);
112465793Smsmith
112583114Sscottl	/* initialise constant fields in the command structure */
112683114Sscottl	for (i = 0; i < AAC_FIB_COUNT; i++) {
112783114Sscottl		cm = &sc->aac_command[i];
112883114Sscottl		cm->cm_sc = sc;
112983114Sscottl		cm->cm_fib = sc->aac_fibs + i;
113083114Sscottl		cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
113165793Smsmith
113283114Sscottl		if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
113383114Sscottl			aac_release_command(cm);
113483114Sscottl	}
1135102602Sscottl	return (0);
113665793Smsmith}
113765793Smsmith
113883114Sscottl/*
113970393Smsmith * Free FIBs owned by this adapter.
114065793Smsmith */
114165793Smsmithstatic void
114270393Smsmithaac_free_commands(struct aac_softc *sc)
114365793Smsmith{
114483114Sscottl	int i;
114565793Smsmith
114683114Sscottl	debug_called(1);
114765793Smsmith
114883114Sscottl	for (i = 0; i < AAC_FIB_COUNT; i++)
114983114Sscottl		bus_dmamap_destroy(sc->aac_buffer_dmat,
115083114Sscottl				   sc->aac_command[i].cm_datamap);
115183114Sscottl
115283114Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
115383114Sscottl	bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
115465793Smsmith}
115565793Smsmith
115683114Sscottl/*
115765793Smsmith * Command-mapping helper function - populate this command's s/g table.
115865793Smsmith */
115965793Smsmithstatic void
116065793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
116165793Smsmith{
116283114Sscottl	struct aac_command *cm;
116383114Sscottl	struct aac_fib *fib;
116483114Sscottl	struct aac_sg_table *sg;
116583114Sscottl	int i;
116665793Smsmith
116783114Sscottl	debug_called(3);
116865793Smsmith
116983114Sscottl	cm = (struct aac_command *)arg;
117083114Sscottl	fib = cm->cm_fib;
117165793Smsmith
117283114Sscottl	/* find the s/g table */
117383114Sscottl	sg = cm->cm_sgtable;
117483114Sscottl
117583114Sscottl	/* copy into the FIB */
117683114Sscottl	if (sg != NULL) {
117783114Sscottl		sg->SgCount = nseg;
117883114Sscottl		for (i = 0; i < nseg; i++) {
117983114Sscottl			sg->SgEntry[i].SgAddress = segs[i].ds_addr;
118083114Sscottl			sg->SgEntry[i].SgByteCount = segs[i].ds_len;
118183114Sscottl		}
118283114Sscottl		/* update the FIB size for the s/g count */
118383114Sscottl		fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
118465793Smsmith	}
118565793Smsmith
118665793Smsmith}
118765793Smsmith
118883114Sscottl/*
118965793Smsmith * Map a command into controller-visible space.
119065793Smsmith */
119165793Smsmithstatic void
119265793Smsmithaac_map_command(struct aac_command *cm)
119365793Smsmith{
119483114Sscottl	struct aac_softc *sc;
119565793Smsmith
119683114Sscottl	debug_called(2);
119765793Smsmith
119883114Sscottl	sc = cm->cm_sc;
119965793Smsmith
120083114Sscottl	/* don't map more than once */
120183114Sscottl	if (cm->cm_flags & AAC_CMD_MAPPED)
120283114Sscottl		return;
120365793Smsmith
120483114Sscottl	if (cm->cm_datalen != 0) {
120583114Sscottl		bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap,
120683114Sscottl				cm->cm_data, cm->cm_datalen,
120783114Sscottl				aac_map_command_sg, cm, 0);
120883114Sscottl
120965793Smsmith	if (cm->cm_flags & AAC_CMD_DATAIN)
121083114Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
121183114Sscottl				BUS_DMASYNC_PREREAD);
121265793Smsmith	if (cm->cm_flags & AAC_CMD_DATAOUT)
121383114Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
121483114Sscottl				BUS_DMASYNC_PREWRITE);
121583114Sscottl	}
121683114Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
121765793Smsmith}
121865793Smsmith
121983114Sscottl/*
122065793Smsmith * Unmap a command from controller-visible space.
122165793Smsmith */
122265793Smsmithstatic void
122365793Smsmithaac_unmap_command(struct aac_command *cm)
122465793Smsmith{
122583114Sscottl	struct aac_softc *sc;
122665793Smsmith
122783114Sscottl	debug_called(2);
122865793Smsmith
122983114Sscottl	sc = cm->cm_sc;
123065793Smsmith
123183114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
123283114Sscottl		return;
123365793Smsmith
123483114Sscottl	if (cm->cm_datalen != 0) {
123583114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
123683114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
123783114Sscottl					BUS_DMASYNC_POSTREAD);
123883114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
123983114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
124083114Sscottl					BUS_DMASYNC_POSTWRITE);
124183114Sscottl
124283114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
124383114Sscottl	}
124483114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
124565793Smsmith}
124665793Smsmith
124783114Sscottl/*
124883114Sscottl * Hardware Interface
124983114Sscottl */
125065793Smsmith
125183114Sscottl/*
125265793Smsmith * Initialise the adapter.
125365793Smsmith */
125465793Smsmithstatic void
125565793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
125665793Smsmith{
125783114Sscottl	struct aac_softc *sc;
125865793Smsmith
125983114Sscottl	debug_called(1);
126065793Smsmith
126183114Sscottl	sc = (struct aac_softc *)arg;
126283114Sscottl
126383114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
126465793Smsmith}
126565793Smsmith
126690275Sscottl/*
126790275Sscottl * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
126890275Sscottl * firmware version 1.x are not compatible with this driver.
126990275Sscottl */
127065793Smsmithstatic int
127190275Sscottlaac_check_firmware(struct aac_softc *sc)
127290275Sscottl{
127390275Sscottl	u_int32_t major, minor;
127490275Sscottl
127590275Sscottl	debug_called(1);
127690275Sscottl
127790275Sscottl	if (sc->quirks & AAC_QUIRK_PERC2QC) {
127890275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
127990275Sscottl				     NULL)) {
128090275Sscottl			device_printf(sc->aac_dev,
128190275Sscottl				      "Error reading firmware version\n");
128290275Sscottl			return (EIO);
128390275Sscottl		}
128490275Sscottl
128590275Sscottl		/* These numbers are stored as ASCII! */
128690275Sscottl		major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30;
128790275Sscottl		minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30;
128890275Sscottl		if (major == 1) {
128990275Sscottl			device_printf(sc->aac_dev,
129090275Sscottl			    "Firmware version %d.%d is not supported.\n",
129190275Sscottl			    major, minor);
129290275Sscottl			return (EINVAL);
129390275Sscottl		}
129490275Sscottl	}
129590275Sscottl
129690275Sscottl	return (0);
129790275Sscottl}
129890275Sscottl
129990275Sscottlstatic int
130065793Smsmithaac_init(struct aac_softc *sc)
130165793Smsmith{
130283114Sscottl	struct aac_adapter_init	*ip;
130383114Sscottl	time_t then;
130483114Sscottl	u_int32_t code;
130583114Sscottl	u_int8_t *qaddr;
130665793Smsmith
130783114Sscottl	debug_called(1);
130865793Smsmith
130983114Sscottl	/*
131083114Sscottl	 * First wait for the adapter to come ready.
131183114Sscottl	 */
131283114Sscottl	then = time_second;
131383114Sscottl	do {
131483114Sscottl		code = AAC_GET_FWSTATUS(sc);
131583114Sscottl		if (code & AAC_SELF_TEST_FAILED) {
131683114Sscottl			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
131783114Sscottl			return(ENXIO);
131883114Sscottl		}
131983114Sscottl		if (code & AAC_KERNEL_PANIC) {
132083114Sscottl			device_printf(sc->aac_dev,
132183114Sscottl				      "FATAL: controller kernel panic\n");
132283114Sscottl			return(ENXIO);
132383114Sscottl		}
132483114Sscottl		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
132583114Sscottl			device_printf(sc->aac_dev,
132683114Sscottl				      "FATAL: controller not coming ready, "
132783114Sscottl					   "status %x\n", code);
132883114Sscottl			return(ENXIO);
132983114Sscottl		}
133083114Sscottl	} while (!(code & AAC_UP_AND_RUNNING));
133183114Sscottl
133283114Sscottl	/*
133383114Sscottl	 * Create DMA tag for the common structure and allocate it.
133483114Sscottl	 */
133583114Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
133695536Sscottl			       1, 0,			/* algnmnt, boundary */
133795536Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
133883114Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
133983114Sscottl			       NULL, NULL, 		/* filter, filterarg */
134083114Sscottl			       sizeof(struct aac_common), /* maxsize */
134183114Sscottl			       1,			/* nsegments */
134283114Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
134383114Sscottl			       0,			/* flags */
134483114Sscottl			       &sc->aac_common_dmat)) {
134583114Sscottl		device_printf(sc->aac_dev,
134683114Sscottl			      "can't allocate common structure DMA tag\n");
134783114Sscottl		return(ENOMEM);
134865793Smsmith	}
134983114Sscottl	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
135083114Sscottl			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
135183114Sscottl		device_printf(sc->aac_dev, "can't allocate common structure\n");
135283114Sscottl		return(ENOMEM);
135365793Smsmith	}
135483114Sscottl	bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
135583114Sscottl			sc->aac_common, sizeof(*sc->aac_common), aac_common_map,
135695536Sscottl			sc, 0);
135783114Sscottl	bzero(sc->aac_common, sizeof(*sc->aac_common));
135883114Sscottl
135983114Sscottl	/*
136083114Sscottl	 * Fill in the init structure.  This tells the adapter about the
136183114Sscottl	 * physical location of various important shared data structures.
136283114Sscottl	 */
136383114Sscottl	ip = &sc->aac_common->ac_init;
136483114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
136565793Smsmith
136683114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
136783114Sscottl					 offsetof(struct aac_common, ac_fibs);
136883114Sscottl	ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
136983114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
137083114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
137165793Smsmith
137283114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
137383114Sscottl				  offsetof(struct aac_common, ac_printf);
137483114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
137565793Smsmith
137683114Sscottl	ip->HostPhysMemPages = 0;		/* not used? */
137783114Sscottl	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
137865793Smsmith
137983114Sscottl	/*
138083114Sscottl	 * Initialise FIB queues.  Note that it appears that the layout of the
138183114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
138283114Sscottl	 * adapter, which is only told about the base of the queue index fields.
138383114Sscottl	 *
138483114Sscottl	 * The initial values of the indices are assumed to inform the adapter
138583114Sscottl	 * of the sizes of the respective queues, and theoretically it could
138683114Sscottl	 * work out the entire layout of the queue structures from this.  We
138783114Sscottl	 * take the easy route and just lay this area out like everyone else
138883114Sscottl	 * does.
138983114Sscottl	 *
139083114Sscottl	 * The Linux driver uses a much more complex scheme whereby several
139183114Sscottl	 * header records are kept for each queue.  We use a couple of generic
139283114Sscottl	 * list manipulation functions which 'know' the size of each list by
139383114Sscottl	 * virtue of a table.
139483114Sscottl	 */
139583114Sscottl	qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
139683114Sscottl	qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
139783114Sscottl	sc->aac_queues = (struct aac_queue_table *)qaddr;
139883114Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr +
139983114Sscottl				((u_int32_t)sc->aac_queues -
140083114Sscottl				(u_int32_t)sc->aac_common);
140183114Sscottl	bzero(sc->aac_queues, sizeof(struct aac_queue_table));
140265793Smsmith
140383114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
140481082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
140583114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
140681082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
140783114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
140881082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
140983114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
141081082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
141183114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
141281082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
141383114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
141481082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
141583114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
141681082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
141783114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
141881082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
141983114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
142081082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
142183114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
142281082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
142383114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
142481082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
142583114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
142681082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
142783114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
142881082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
142983114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
143081082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
143183114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
143281082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
143383114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
143481082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
143583114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
143681082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
143783114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
143881082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
143983114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
144081082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
144183114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
144281082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
144383114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
144481082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
144583114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
144681082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
144783114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
144881082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
144983114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
145081082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
145165793Smsmith
145283114Sscottl	/*
145383114Sscottl	 * Do controller-type-specific initialisation
145483114Sscottl	 */
145583114Sscottl	switch (sc->aac_hwif) {
145683114Sscottl	case AAC_HWIF_I960RX:
145783114Sscottl		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
145883114Sscottl		break;
145983114Sscottl	}
146065793Smsmith
146183114Sscottl	/*
146283114Sscottl	 * Give the init structure to the controller.
146383114Sscottl	 */
146483114Sscottl	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
146583114Sscottl			     sc->aac_common_busaddr +
146683114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
146783114Sscottl			     NULL)) {
146883114Sscottl		device_printf(sc->aac_dev,
146983114Sscottl			      "error establishing init structure\n");
147083114Sscottl		return(EIO);
147183114Sscottl	}
147265793Smsmith
147383114Sscottl	return(0);
147465793Smsmith}
147565793Smsmith
147683114Sscottl/*
147765793Smsmith * Send a synchronous command to the controller and wait for a result.
147865793Smsmith */
147965793Smsmithstatic int
148065793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
148170393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
148270393Smsmith		 u_int32_t *sp)
148365793Smsmith{
148483114Sscottl	time_t then;
148583114Sscottl	u_int32_t status;
148665793Smsmith
148783114Sscottl	debug_called(3);
148865793Smsmith
148983114Sscottl	/* populate the mailbox */
149083114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
149165793Smsmith
149283114Sscottl	/* ensure the sync command doorbell flag is cleared */
149383114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
149465793Smsmith
149583114Sscottl	/* then set it to signal the adapter */
149683114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
149765793Smsmith
149883114Sscottl	/* spin waiting for the command to complete */
149983114Sscottl	then = time_second;
150083114Sscottl	do {
150183114Sscottl		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
150283114Sscottl			debug(2, "timed out");
150383114Sscottl			return(EIO);
150483114Sscottl		}
150583114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
150665793Smsmith
150783114Sscottl	/* clear the completion flag */
150883114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
150965793Smsmith
151083114Sscottl	/* get the command status */
151183114Sscottl	status = AAC_GET_MAILBOXSTATUS(sc);
151283114Sscottl	if (sp != NULL)
151383114Sscottl		*sp = status;
151483114Sscottl	return(0);
151565793Smsmith}
151665793Smsmith
151783114Sscottl/*
151895350Sscottl * Grab the sync fib area.
151995350Sscottl */
152095350Sscottlint
152195536Sscottlaac_alloc_sync_fib(struct aac_softc *sc, struct aac_fib **fib, int flags)
152295350Sscottl{
152395350Sscottl
152495350Sscottl	/*
152595350Sscottl	 * If the force flag is set, the system is shutting down, or in
152695350Sscottl	 * trouble.  Ignore the mutex.
152795350Sscottl	 */
152895350Sscottl	if (!(flags & AAC_SYNC_LOCK_FORCE))
152995350Sscottl		AAC_LOCK_ACQUIRE(&sc->aac_sync_lock);
153095350Sscottl
153195350Sscottl	*fib = &sc->aac_common->ac_sync_fib;
153295350Sscottl
153395350Sscottl	return (1);
153495350Sscottl}
153595350Sscottl
153695350Sscottl/*
153795350Sscottl * Release the sync fib area.
153895350Sscottl */
153995350Sscottlvoid
154095350Sscottlaac_release_sync_fib(struct aac_softc *sc)
154195350Sscottl{
154295350Sscottl
154395350Sscottl	AAC_LOCK_RELEASE(&sc->aac_sync_lock);
154495350Sscottl}
154595350Sscottl
154695350Sscottl/*
154765793Smsmith * Send a synchronous FIB to the controller and wait for a result.
154865793Smsmith */
154995350Sscottlint
155065793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
155195350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
155265793Smsmith{
155383114Sscottl	debug_called(3);
155465793Smsmith
155583114Sscottl	if (datasize > AAC_FIB_DATASIZE)
155683114Sscottl		return(EINVAL);
155765793Smsmith
155883114Sscottl	/*
155983114Sscottl	 * Set up the sync FIB
156083114Sscottl	 */
156183114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
156283114Sscottl				AAC_FIBSTATE_INITIALISED |
156383114Sscottl				AAC_FIBSTATE_EMPTY;
156483114Sscottl	fib->Header.XferState |= xferstate;
156583114Sscottl	fib->Header.Command = command;
156683114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
156783114Sscottl	fib->Header.Size = sizeof(struct aac_fib) + datasize;
156883114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
156983114Sscottl	fib->Header.SenderFibAddress = (u_int32_t)fib;
157083114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
157183114Sscottl					 offsetof(struct aac_common,
157283114Sscottl						  ac_sync_fib);
157365793Smsmith
157483114Sscottl	/*
157583114Sscottl	 * Give the FIB to the controller, wait for a response.
157683114Sscottl	 */
157783114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
157883114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
157983114Sscottl		debug(2, "IO error");
158083114Sscottl		return(EIO);
158183114Sscottl	}
158281151Sscottl
158395350Sscottl	return (0);
158465793Smsmith}
158565793Smsmith
158683114Sscottl/*
158765793Smsmith * Adapter-space FIB queue manipulation
158865793Smsmith *
158965793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
159065793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
159165793Smsmith */
159265793Smsmithstatic struct {
159383114Sscottl	int		size;
159483114Sscottl	int		notify;
159565793Smsmith} aac_qinfo[] = {
159683114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
159783114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
159883114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
159983114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
160083114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
160183114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
160283114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
160383114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
160465793Smsmith};
160565793Smsmith
160665793Smsmith/*
160781082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
160881082Sscottl * EBUSY if the queue is full.
160965793Smsmith *
161070393Smsmith * Note: it would be more efficient to defer notifying the controller in
161183114Sscottl *	 the case where we may be inserting several entries in rapid succession,
161283114Sscottl *	 but implementing this usefully may be difficult (it would involve a
161383114Sscottl *	 separate queue/notify interface).
161465793Smsmith */
161565793Smsmithstatic int
161681151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
161765793Smsmith{
161883114Sscottl	u_int32_t pi, ci;
161983114Sscottl	int s, error;
162083114Sscottl	u_int32_t fib_size;
162183114Sscottl	u_int32_t fib_addr;
162265793Smsmith
162383114Sscottl	debug_called(3);
162482527Sscottl
162583114Sscottl	fib_size = cm->cm_fib->Header.Size;
162683114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
162781151Sscottl
162883114Sscottl	s = splbio();
162965793Smsmith
163083114Sscottl	/* get the producer/consumer indices */
163183114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
163283114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
163365793Smsmith
163483114Sscottl	/* wrap the queue? */
163583114Sscottl	if (pi >= aac_qinfo[queue].size)
163683114Sscottl		pi = 0;
163765793Smsmith
163883114Sscottl	/* check for queue full */
163983114Sscottl	if ((pi + 1) == ci) {
164083114Sscottl		error = EBUSY;
164183114Sscottl		goto out;
164283114Sscottl	}
164365793Smsmith
164483114Sscottl	/* populate queue entry */
164583114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
164683114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
164765793Smsmith
164883114Sscottl	/* update producer index */
164983114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
165065793Smsmith
165183114Sscottl	/*
165283114Sscottl	 * To avoid a race with its completion interrupt, place this command on
165383114Sscottl	 * the busy queue prior to advertising it to the controller.
165483114Sscottl	 */
165583114Sscottl	aac_enqueue_busy(cm);
165681151Sscottl
165783114Sscottl	/* notify the adapter if we know how */
165883114Sscottl	if (aac_qinfo[queue].notify != 0)
165983114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
166065793Smsmith
166183114Sscottl	error = 0;
166265793Smsmith
166365793Smsmithout:
166483114Sscottl	splx(s);
166583114Sscottl	return(error);
166665793Smsmith}
166765793Smsmith
166865793Smsmith/*
166982527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
167082527Sscottl * success or ENOENT if the queue is empty.
167165793Smsmith */
167265793Smsmithstatic int
167381082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
167481082Sscottl		struct aac_fib **fib_addr)
167565793Smsmith{
167683114Sscottl	u_int32_t pi, ci;
167783114Sscottl	int s, error;
167883114Sscottl	int notify;
167965793Smsmith
168083114Sscottl	debug_called(3);
168165793Smsmith
168283114Sscottl	s = splbio();
168365793Smsmith
168483114Sscottl	/* get the producer/consumer indices */
168583114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
168683114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
168765793Smsmith
168883114Sscottl	/* check for queue empty */
168983114Sscottl	if (ci == pi) {
169083114Sscottl		error = ENOENT;
169183114Sscottl		goto out;
169283114Sscottl	}
169383114Sscottl
169483114Sscottl	notify = 0;
169583114Sscottl	if (ci == pi + 1)
169683114Sscottl		notify++;
169781151Sscottl
169883114Sscottl	/* wrap the queue? */
169983114Sscottl	if (ci >= aac_qinfo[queue].size)
170083114Sscottl		ci = 0;
170165793Smsmith
170283114Sscottl	/* fetch the entry */
170383114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
170483114Sscottl	*fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] +
170583114Sscottl				       ci)->aq_fib_addr;
170665793Smsmith
170783114Sscottl	/* update consumer index */
170883114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
170965793Smsmith
171083114Sscottl	/* if we have made the queue un-full, notify the adapter */
171183114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
171283114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
171383114Sscottl	error = 0;
171465793Smsmith
171565793Smsmithout:
171683114Sscottl	splx(s);
171783114Sscottl	return(error);
171865793Smsmith}
171965793Smsmith
172083114Sscottl/*
172182527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
172282527Sscottl */
172382527Sscottlstatic int
172482527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
172582527Sscottl{
172683114Sscottl	u_int32_t pi, ci;
172783114Sscottl	int s, error;
172883114Sscottl	u_int32_t fib_size;
172983114Sscottl	u_int32_t fib_addr;
173082527Sscottl
173183114Sscottl	debug_called(1);
173282527Sscottl
173383114Sscottl	/* Tell the adapter where the FIB is */
173483114Sscottl	fib_size = fib->Header.Size;
173583114Sscottl	fib_addr = fib->Header.SenderFibAddress;
173683114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
173782527Sscottl
173883114Sscottl	s = splbio();
173982527Sscottl
174083114Sscottl	/* get the producer/consumer indices */
174183114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
174283114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
174382527Sscottl
174483114Sscottl	/* wrap the queue? */
174583114Sscottl	if (pi >= aac_qinfo[queue].size)
174683114Sscottl		pi = 0;
174782527Sscottl
174883114Sscottl	/* check for queue full */
174983114Sscottl	if ((pi + 1) == ci) {
175083114Sscottl		error = EBUSY;
175183114Sscottl		goto out;
175283114Sscottl	}
175382527Sscottl
175483114Sscottl	/* populate queue entry */
175583114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
175683114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
175782527Sscottl
175883114Sscottl	/* update producer index */
175983114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
176082527Sscottl
176183114Sscottl	/* notify the adapter if we know how */
176283114Sscottl	if (aac_qinfo[queue].notify != 0)
176383114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
176482527Sscottl
176583114Sscottl	error = 0;
176682527Sscottl
176782527Sscottlout:
176883114Sscottl	splx(s);
176983114Sscottl	return(error);
177082527Sscottl}
177182527Sscottl
177283114Sscottl/*
177370393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
177470393Smsmith * and complain about them.
177570393Smsmith */
177670393Smsmithstatic void
177770393Smsmithaac_timeout(struct aac_softc *sc)
177870393Smsmith{
177983114Sscottl	int s;
178083114Sscottl	struct aac_command *cm;
178183114Sscottl	time_t deadline;
178270393Smsmith
178381151Sscottl#if 0
178483114Sscottl	/* simulate an interrupt to handle possibly-missed interrupts */
178583114Sscottl	/*
178683114Sscottl	 * XXX This was done to work around another bug which has since been
178783114Sscottl	 * fixed.  It is dangerous anyways because you don't want multiple
178883114Sscottl	 * threads in the interrupt handler at the same time!  If calling
178983114Sscottl	 * is deamed neccesary in the future, proper mutexes must be used.
179083114Sscottl	 */
179183114Sscottl	s = splbio();
179283114Sscottl	aac_intr(sc);
179383114Sscottl	splx(s);
179470393Smsmith
179583114Sscottl	/* kick the I/O queue to restart it in the case of deadlock */
179683114Sscottl	aac_startio(sc);
179782527Sscottl#endif
179870393Smsmith
179983114Sscottl	/*
180083114Sscottl	 * traverse the busy command list, bitch about late commands once
180183114Sscottl	 * only.
180283114Sscottl	 */
180383114Sscottl	deadline = time_second - AAC_CMD_TIMEOUT;
180483114Sscottl	s = splbio();
180583114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
180683114Sscottl		if ((cm->cm_timestamp  < deadline)
180783114Sscottl			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
180883114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
180983114Sscottl			device_printf(sc->aac_dev,
181083114Sscottl				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
181183114Sscottl				      cm, (int)(time_second-cm->cm_timestamp));
181283114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
181383114Sscottl		}
181470393Smsmith	}
181583114Sscottl	splx(s);
181670393Smsmith
181783114Sscottl	/* reset the timer for next time */
181883114Sscottl	timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
181983114Sscottl	return;
182070393Smsmith}
182170393Smsmith
182283114Sscottl/*
182383114Sscottl * Interface Function Vectors
182483114Sscottl */
182565793Smsmith
182683114Sscottl/*
182765793Smsmith * Read the current firmware status word.
182865793Smsmith */
182965793Smsmithstatic int
183065793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
183165793Smsmith{
183283114Sscottl	debug_called(3);
183365793Smsmith
183483114Sscottl	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
183565793Smsmith}
183665793Smsmith
183765793Smsmithstatic int
183865793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
183965793Smsmith{
184083114Sscottl	debug_called(3);
184165793Smsmith
184283114Sscottl	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
184365793Smsmith}
184465793Smsmith
184587183Sscottlstatic int
184687183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc)
184787183Sscottl{
184887183Sscottl	int val;
184987183Sscottl
185087183Sscottl	debug_called(3);
185187183Sscottl
185287183Sscottl	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
185387183Sscottl	return (val);
185487183Sscottl}
185587183Sscottl
185683114Sscottl/*
185765793Smsmith * Notify the controller of a change in a given queue
185865793Smsmith */
185965793Smsmith
186065793Smsmithstatic void
186165793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
186265793Smsmith{
186383114Sscottl	debug_called(3);
186465793Smsmith
186583114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
186665793Smsmith}
186765793Smsmith
186865793Smsmithstatic void
186965793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
187065793Smsmith{
187183114Sscottl	debug_called(3);
187265793Smsmith
187383114Sscottl	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
187465793Smsmith}
187565793Smsmith
187687183Sscottlstatic void
187787183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit)
187887183Sscottl{
187987183Sscottl	debug_called(3);
188087183Sscottl
188187183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
188287183Sscottl	AAC_FA_HACK(sc);
188387183Sscottl}
188487183Sscottl
188583114Sscottl/*
188665793Smsmith * Get the interrupt reason bits
188765793Smsmith */
188865793Smsmithstatic int
188965793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
189065793Smsmith{
189183114Sscottl	debug_called(3);
189265793Smsmith
189383114Sscottl	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
189465793Smsmith}
189565793Smsmith
189665793Smsmithstatic int
189765793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
189865793Smsmith{
189983114Sscottl	debug_called(3);
190065793Smsmith
190183114Sscottl	return(AAC_GETREG4(sc, AAC_RX_ODBR));
190265793Smsmith}
190365793Smsmith
190487183Sscottlstatic int
190587183Sscottlaac_fa_get_istatus(struct aac_softc *sc)
190687183Sscottl{
190787183Sscottl	int val;
190887183Sscottl
190987183Sscottl	debug_called(3);
191087183Sscottl
191187183Sscottl	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
191287183Sscottl	return (val);
191387183Sscottl}
191487183Sscottl
191583114Sscottl/*
191665793Smsmith * Clear some interrupt reason bits
191765793Smsmith */
191865793Smsmithstatic void
191965793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
192065793Smsmith{
192183114Sscottl	debug_called(3);
192265793Smsmith
192383114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
192465793Smsmith}
192565793Smsmith
192665793Smsmithstatic void
192765793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
192865793Smsmith{
192983114Sscottl	debug_called(3);
193065793Smsmith
193183114Sscottl	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
193265793Smsmith}
193365793Smsmith
193487183Sscottlstatic void
193587183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask)
193687183Sscottl{
193787183Sscottl	debug_called(3);
193887183Sscottl
193987183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
194087183Sscottl	AAC_FA_HACK(sc);
194187183Sscottl}
194287183Sscottl
194383114Sscottl/*
194465793Smsmith * Populate the mailbox and set the command word
194565793Smsmith */
194665793Smsmithstatic void
194765793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
194865793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
194965793Smsmith{
195083114Sscottl	debug_called(4);
195165793Smsmith
195283114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
195383114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
195483114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
195583114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
195683114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
195765793Smsmith}
195865793Smsmith
195965793Smsmithstatic void
196065793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
196165793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
196265793Smsmith{
196383114Sscottl	debug_called(4);
196465793Smsmith
196583114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
196683114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
196783114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
196883114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
196983114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
197065793Smsmith}
197165793Smsmith
197287183Sscottlstatic void
197387183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
197487183Sscottl		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
197587183Sscottl{
197687183Sscottl	debug_called(4);
197787183Sscottl
197887183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
197987183Sscottl	AAC_FA_HACK(sc);
198087183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
198187183Sscottl	AAC_FA_HACK(sc);
198287183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
198387183Sscottl	AAC_FA_HACK(sc);
198487183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
198587183Sscottl	AAC_FA_HACK(sc);
198687183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
198787183Sscottl	AAC_FA_HACK(sc);
198887183Sscottl}
198987183Sscottl
199083114Sscottl/*
199165793Smsmith * Fetch the immediate command status word
199265793Smsmith */
199365793Smsmithstatic int
199465793Smsmithaac_sa_get_mailboxstatus(struct aac_softc *sc)
199565793Smsmith{
199683114Sscottl	debug_called(4);
199765793Smsmith
199883114Sscottl	return(AAC_GETREG4(sc, AAC_SA_MAILBOX));
199965793Smsmith}
200065793Smsmith
200165793Smsmithstatic int
200265793Smsmithaac_rx_get_mailboxstatus(struct aac_softc *sc)
200365793Smsmith{
200483114Sscottl	debug_called(4);
200565793Smsmith
200683114Sscottl	return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
200765793Smsmith}
200865793Smsmith
200987183Sscottlstatic int
201087183Sscottlaac_fa_get_mailboxstatus(struct aac_softc *sc)
201187183Sscottl{
201287183Sscottl	int val;
201387183Sscottl
201487183Sscottl	debug_called(4);
201587183Sscottl
201687183Sscottl	val = AAC_GETREG4(sc, AAC_FA_MAILBOX);
201787183Sscottl	return (val);
201887183Sscottl}
201987183Sscottl
202083114Sscottl/*
202165793Smsmith * Set/clear interrupt masks
202265793Smsmith */
202365793Smsmithstatic void
202465793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
202565793Smsmith{
202683114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
202765793Smsmith
202883114Sscottl	if (enable) {
202983114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
203083114Sscottl	} else {
203183114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
203283114Sscottl	}
203365793Smsmith}
203465793Smsmith
203565793Smsmithstatic void
203665793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
203765793Smsmith{
203883114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
203965793Smsmith
204083114Sscottl	if (enable) {
204183114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
204283114Sscottl	} else {
204383114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
204483114Sscottl	}
204565793Smsmith}
204665793Smsmith
204787183Sscottlstatic void
204887183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable)
204987183Sscottl{
205087183Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
205187183Sscottl
205287183Sscottl	if (enable) {
205387183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
205487183Sscottl		AAC_FA_HACK(sc);
205587183Sscottl	} else {
205687183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
205787183Sscottl		AAC_FA_HACK(sc);
205887183Sscottl	}
205987183Sscottl}
206087183Sscottl
206183114Sscottl/*
206283114Sscottl * Debugging and Diagnostics
206383114Sscottl */
206465793Smsmith
206583114Sscottl/*
206665793Smsmith * Print some information about the controller.
206765793Smsmith */
206865793Smsmithstatic void
206965793Smsmithaac_describe_controller(struct aac_softc *sc)
207065793Smsmith{
207195350Sscottl	struct aac_fib *fib;
207283114Sscottl	struct aac_adapter_info	*info;
207365793Smsmith
207483114Sscottl	debug_called(2);
207565793Smsmith
207695536Sscottl	aac_alloc_sync_fib(sc, &fib, 0);
207795350Sscottl
207895350Sscottl	fib->data[0] = 0;
207995350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
208083114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
208195536Sscottl		aac_release_sync_fib(sc);
208283114Sscottl		return;
208383114Sscottl	}
208495350Sscottl	info = (struct aac_adapter_info *)&fib->data[0];
208565793Smsmith
208683114Sscottl	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
208783114Sscottl		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
208883114Sscottl		      info->ClockSpeed, info->BufferMem / (1024 * 1024),
208983114Sscottl		      aac_describe_code(aac_battery_platform,
209083114Sscottl					info->batteryPlatform));
209165793Smsmith
209283114Sscottl	/* save the kernel revision structure for later use */
209383114Sscottl	sc->aac_revision = info->KernelRevision;
209483114Sscottl	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
209583114Sscottl		      info->KernelRevision.external.comp.major,
209683114Sscottl		      info->KernelRevision.external.comp.minor,
209783114Sscottl		      info->KernelRevision.external.comp.dash,
209883114Sscottl		      info->KernelRevision.buildNumber,
209983114Sscottl		      (u_int32_t)(info->SerialNumber & 0xffffff));
210095536Sscottl
210195536Sscottl	aac_release_sync_fib(sc);
210265793Smsmith}
210365793Smsmith
210483114Sscottl/*
210565793Smsmith * Look up a text description of a numeric error code and return a pointer to
210665793Smsmith * same.
210765793Smsmith */
210865793Smsmithstatic char *
210965793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code)
211065793Smsmith{
211183114Sscottl	int i;
211265793Smsmith
211383114Sscottl	for (i = 0; table[i].string != NULL; i++)
211483114Sscottl		if (table[i].code == code)
211583114Sscottl			return(table[i].string);
211683114Sscottl	return(table[i + 1].string);
211765793Smsmith}
211865793Smsmith
211983114Sscottl/*
212083114Sscottl * Management Interface
212183114Sscottl */
212265793Smsmith
212365793Smsmithstatic int
212487310Sscottlaac_open(dev_t dev, int flags, int fmt, d_thread_t *td)
212565793Smsmith{
212683114Sscottl	struct aac_softc *sc;
212765793Smsmith
212883114Sscottl	debug_called(2);
212965793Smsmith
213083114Sscottl	sc = dev->si_drv1;
213165793Smsmith
213283114Sscottl	/* Check to make sure the device isn't already open */
213383114Sscottl	if (sc->aac_state & AAC_STATE_OPEN) {
213483114Sscottl		return EBUSY;
213583114Sscottl	}
213683114Sscottl	sc->aac_state |= AAC_STATE_OPEN;
213783114Sscottl
213883114Sscottl	return 0;
213965793Smsmith}
214065793Smsmith
214165793Smsmithstatic int
214287310Sscottlaac_close(dev_t dev, int flags, int fmt, d_thread_t *td)
214365793Smsmith{
214483114Sscottl	struct aac_softc *sc;
214565793Smsmith
214683114Sscottl	debug_called(2);
214765793Smsmith
214883114Sscottl	sc = dev->si_drv1;
214965793Smsmith
215083114Sscottl	/* Mark this unit as no longer open  */
215183114Sscottl	sc->aac_state &= ~AAC_STATE_OPEN;
215283114Sscottl
215383114Sscottl	return 0;
215465793Smsmith}
215565793Smsmith
215665793Smsmithstatic int
215787310Sscottlaac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
215865793Smsmith{
215983114Sscottl	union aac_statrequest *as;
216083114Sscottl	struct aac_softc *sc;
216183114Sscottl	int error = 0;
216283114Sscottl	int i;
216365793Smsmith
216483114Sscottl	debug_called(2);
216565793Smsmith
216683114Sscottl	as = (union aac_statrequest *)arg;
216783114Sscottl	sc = dev->si_drv1;
216883114Sscottl
216983114Sscottl	switch (cmd) {
217083114Sscottl	case AACIO_STATS:
217183114Sscottl		switch (as->as_item) {
217283114Sscottl		case AACQ_FREE:
217383114Sscottl		case AACQ_BIO:
217483114Sscottl		case AACQ_READY:
217583114Sscottl		case AACQ_BUSY:
217683114Sscottl		case AACQ_COMPLETE:
217783114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
217883114Sscottl			      sizeof(struct aac_qstat));
217983114Sscottl			break;
218083114Sscottl		default:
218183114Sscottl			error = ENOENT;
218283114Sscottl			break;
218383114Sscottl		}
218483114Sscottl	break;
218583114Sscottl
218683114Sscottl	case FSACTL_SENDFIB:
218783114Sscottl		arg = *(caddr_t*)arg;
218883114Sscottl	case FSACTL_LNX_SENDFIB:
218983114Sscottl		debug(1, "FSACTL_SENDFIB");
219083114Sscottl		error = aac_ioctl_sendfib(sc, arg);
219183114Sscottl		break;
219283114Sscottl	case FSACTL_AIF_THREAD:
219383114Sscottl	case FSACTL_LNX_AIF_THREAD:
219483114Sscottl		debug(1, "FSACTL_AIF_THREAD");
219583114Sscottl		error = EINVAL;
219683114Sscottl		break;
219783114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
219883114Sscottl		arg = *(caddr_t*)arg;
219987183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
220083114Sscottl		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
220183114Sscottl		/*
220283114Sscottl		 * Pass the caller out an AdapterFibContext.
220383114Sscottl		 *
220483114Sscottl		 * Note that because we only support one opener, we
220583114Sscottl		 * basically ignore this.  Set the caller's context to a magic
220683114Sscottl		 * number just in case.
220783114Sscottl		 *
220883114Sscottl		 * The Linux code hands the driver a pointer into kernel space,
220983114Sscottl		 * and then trusts it when the caller hands it back.  Aiee!
221083114Sscottl		 * Here, we give it the proc pointer of the per-adapter aif
221183114Sscottl		 * thread. It's only used as a sanity check in other calls.
221283114Sscottl		 */
221383114Sscottl		i = (int)sc->aifthread;
221483114Sscottl		error = copyout(&i, arg, sizeof(i));
221583114Sscottl		break;
221683114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
221783114Sscottl		arg = *(caddr_t*)arg;
221883114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
221983114Sscottl		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
222083114Sscottl		error = aac_getnext_aif(sc, arg);
222183114Sscottl		break;
222283114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
222383114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
222483114Sscottl		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
222583114Sscottl		/* don't do anything here */
222683114Sscottl		break;
222783114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
222883114Sscottl		arg = *(caddr_t*)arg;
222983114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
223083114Sscottl		debug(1, "FSACTL_MINIPORT_REV_CHECK");
223183114Sscottl		error = aac_rev_check(sc, arg);
223283114Sscottl		break;
223383114Sscottl	case FSACTL_QUERY_DISK:
223483114Sscottl		arg = *(caddr_t*)arg;
223583114Sscottl	case FSACTL_LNX_QUERY_DISK:
223683114Sscottl		debug(1, "FSACTL_QUERY_DISK");
223783114Sscottl		error = aac_query_disk(sc, arg);
223883114Sscottl			break;
223983114Sscottl	case FSACTL_DELETE_DISK:
224083114Sscottl	case FSACTL_LNX_DELETE_DISK:
224183114Sscottl		/*
224283114Sscottl		 * We don't trust the underland to tell us when to delete a
224383114Sscottl		 * container, rather we rely on an AIF coming from the
224483114Sscottl		 * controller
224583114Sscottl		 */
224683114Sscottl		error = 0;
224783114Sscottl		break;
224870393Smsmith	default:
224987183Sscottl		debug(1, "unsupported cmd 0x%lx\n", cmd);
225083114Sscottl		error = EINVAL;
225183114Sscottl		break;
225270393Smsmith	}
225383114Sscottl	return(error);
225465793Smsmith}
225565793Smsmith
225687183Sscottlstatic int
225787310Sscottlaac_poll(dev_t dev, int poll_events, d_thread_t *td)
225887183Sscottl{
225987183Sscottl	struct aac_softc *sc;
226087183Sscottl	int revents;
226187183Sscottl
226287183Sscottl	sc = dev->si_drv1;
226387183Sscottl	revents = 0;
226487183Sscottl
226587310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
226687183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
226787183Sscottl		if (sc->aac_aifq_tail != sc->aac_aifq_head)
226887183Sscottl			revents |= poll_events & (POLLIN | POLLRDNORM);
226987183Sscottl	}
227087183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
227187183Sscottl
227287183Sscottl	if (revents == 0) {
227387183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
227487183Sscottl			selrecord(td, &sc->rcv_select);
227587183Sscottl	}
227687183Sscottl
227787183Sscottl	return (revents);
227887183Sscottl}
227987183Sscottl
228083114Sscottl/*
228165793Smsmith * Send a FIB supplied from userspace
228265793Smsmith */
228365793Smsmithstatic int
228465793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
228565793Smsmith{
228683114Sscottl	struct aac_command *cm;
228783114Sscottl	int size, error;
228865793Smsmith
228983114Sscottl	debug_called(2);
229065793Smsmith
229183114Sscottl	cm = NULL;
229265793Smsmith
229383114Sscottl	/*
229483114Sscottl	 * Get a command
229583114Sscottl	 */
229683114Sscottl	if (aac_alloc_command(sc, &cm)) {
229783114Sscottl		error = EBUSY;
229883114Sscottl		goto out;
229983114Sscottl	}
230065793Smsmith
230183114Sscottl	/*
230283114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
230383114Sscottl	 */
230483114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
230583114Sscottl			    sizeof(struct aac_fib_header))) != 0)
230683114Sscottl		goto out;
230783114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
230883114Sscottl	if (size > sizeof(struct aac_fib)) {
230983114Sscottl		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
231083114Sscottl			      size, sizeof(struct aac_fib));
231183114Sscottl		size = sizeof(struct aac_fib);
231283114Sscottl	}
231383114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
231483114Sscottl		goto out;
231583114Sscottl	cm->cm_fib->Header.Size = size;
231683114Sscottl	cm->cm_timestamp = time_second;
231765793Smsmith
231883114Sscottl	/*
231983114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
232083114Sscottl	 */
232187183Sscottl	if ((error = aac_wait_command(cm, 30)) != 0) {	/* XXX user timeout? */
232287183Sscottl		printf("aac_wait_command return %d\n", error);
232383114Sscottl		goto out;
232487183Sscottl	}
232565793Smsmith
232683114Sscottl	/*
232783114Sscottl	 * Copy the FIB and data back out to the caller.
232883114Sscottl	 */
232983114Sscottl	size = cm->cm_fib->Header.Size;
233083114Sscottl	if (size > sizeof(struct aac_fib)) {
233183114Sscottl		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
233283114Sscottl			      size, sizeof(struct aac_fib));
233383114Sscottl		size = sizeof(struct aac_fib);
233483114Sscottl	}
233583114Sscottl	error = copyout(cm->cm_fib, ufib, size);
233665793Smsmith
233765793Smsmithout:
233883114Sscottl	if (cm != NULL) {
233983114Sscottl		aac_release_command(cm);
234083114Sscottl	}
234183114Sscottl	return(error);
234265793Smsmith}
234365793Smsmith
234483114Sscottl/*
234565793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
234682527Sscottl * If the queue fills up, then drop the older entries.
234765793Smsmith */
234865793Smsmithstatic void
234982527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
235065793Smsmith{
235183114Sscottl	struct aac_aif_command *aif;
235283114Sscottl	struct aac_container *co, *co_next;
235395350Sscottl	struct aac_mntinfo *mi;
235495350Sscottl	struct aac_mntinforesp *mir = NULL;
235583114Sscottl	u_int16_t rsize;
235687183Sscottl	int next, found;
235783114Sscottl	int added = 0, i = 0;
235865793Smsmith
235983114Sscottl	debug_called(2);
236065793Smsmith
236183114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
236283114Sscottl	aac_print_aif(sc, aif);
236382527Sscottl
236483114Sscottl	/* Is it an event that we should care about? */
236583114Sscottl	switch (aif->command) {
236683114Sscottl	case AifCmdEventNotify:
236783114Sscottl		switch (aif->data.EN.type) {
236883114Sscottl		case AifEnAddContainer:
236983114Sscottl		case AifEnDeleteContainer:
237083114Sscottl			/*
237183114Sscottl			 * A container was added or deleted, but the message
237283114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
237383114Sscottl			 * containers and sort things out.
237483114Sscottl			 */
237595536Sscottl			aac_alloc_sync_fib(sc, &fib, 0);
237695350Sscottl			mi = (struct aac_mntinfo *)&fib->data[0];
237783114Sscottl			do {
237883114Sscottl				/*
237983114Sscottl				 * Ask the controller for its containers one at
238083114Sscottl				 * a time.
238183114Sscottl				 * XXX What if the controller's list changes
238283114Sscottl				 * midway through this enumaration?
238383114Sscottl				 * XXX This should be done async.
238483114Sscottl				 */
238595966Sscottl				bzero(mi, sizeof(struct aac_mntinfo));
238695966Sscottl				mi->Command = VM_NameServe;
238795966Sscottl				mi->MntType = FT_FILESYS;
238895350Sscottl				mi->MntCount = i;
238983114Sscottl				rsize = sizeof(mir);
239095350Sscottl				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
239195350Sscottl						 sizeof(struct aac_mntinfo))) {
239283114Sscottl					debug(2, "Error probing container %d\n",
239383114Sscottl					      i);
239483114Sscottl					continue;
239583114Sscottl				}
239695350Sscottl				mir = (struct aac_mntinforesp *)&fib->data[0];
239783114Sscottl				/*
239883114Sscottl				 * Check the container against our list.
239983114Sscottl				 * co->co_found was already set to 0 in a
240083114Sscottl				 * previous run.
240183114Sscottl				 */
240295350Sscottl				if ((mir->Status == ST_OK) &&
240395350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
240483114Sscottl					found = 0;
240583114Sscottl					TAILQ_FOREACH(co,
240683114Sscottl						      &sc->aac_container_tqh,
240783114Sscottl						      co_link) {
240883114Sscottl						if (co->co_mntobj.ObjectId ==
240995350Sscottl						    mir->MntTable[0].ObjectId) {
241083114Sscottl							co->co_found = 1;
241183114Sscottl							found = 1;
241283114Sscottl							break;
241383114Sscottl						}
241483114Sscottl					}
241583114Sscottl					/*
241683114Sscottl					 * If the container matched, continue
241783114Sscottl					 * in the list.
241883114Sscottl					 */
241983114Sscottl					if (found) {
242083114Sscottl						i++;
242183114Sscottl						continue;
242283114Sscottl					}
242383114Sscottl
242483114Sscottl					/*
242583114Sscottl					 * This is a new container.  Do all the
242683114Sscottl					 * appropriate things to set it up.						 */
242795350Sscottl					aac_add_container(sc, mir, 1);
242883114Sscottl					added = 1;
242983114Sscottl				}
243083114Sscottl				i++;
243195350Sscottl			} while ((i < mir->MntRespCount) &&
243283114Sscottl				 (i < AAC_MAX_CONTAINERS));
243395350Sscottl			aac_release_sync_fib(sc);
243483114Sscottl
243583114Sscottl			/*
243683114Sscottl			 * Go through our list of containers and see which ones
243783114Sscottl			 * were not marked 'found'.  Since the controller didn't
243883114Sscottl			 * list them they must have been deleted.  Do the
243983114Sscottl			 * appropriate steps to destroy the device.  Also reset
244083114Sscottl			 * the co->co_found field.
244183114Sscottl			 */
244283114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
244383114Sscottl			while (co != NULL) {
244483114Sscottl				if (co->co_found == 0) {
244583114Sscottl					device_delete_child(sc->aac_dev,
244683114Sscottl							    co->co_disk);
244783114Sscottl					co_next = TAILQ_NEXT(co, co_link);
244887310Sscottl					AAC_LOCK_ACQUIRE(&sc->
244983114Sscottl							aac_container_lock);
245083114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
245183114Sscottl						     co_link);
245283114Sscottl					AAC_LOCK_RELEASE(&sc->
245383114Sscottl							 aac_container_lock);
245483114Sscottl					FREE(co, M_AACBUF);
245583114Sscottl					co = co_next;
245683114Sscottl				} else {
245783114Sscottl					co->co_found = 0;
245883114Sscottl					co = TAILQ_NEXT(co, co_link);
245983114Sscottl				}
246082527Sscottl			}
246182527Sscottl
246283114Sscottl			/* Attach the newly created containers */
246383114Sscottl			if (added)
246483114Sscottl				bus_generic_attach(sc->aac_dev);
246583114Sscottl
2466105528Sphk			break;
246782527Sscottl
246883114Sscottl		default:
246983114Sscottl			break;
247082527Sscottl		}
247182527Sscottl
247282527Sscottl	default:
247383114Sscottl		break;
247482527Sscottl	}
247582527Sscottl
247683114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
247787310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
247883114Sscottl	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
247983114Sscottl	if (next != sc->aac_aifq_tail) {
248083114Sscottl		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
248187183Sscottl		sc->aac_aifq_head = next;
248287183Sscottl
248387183Sscottl		/* On the off chance that someone is sleeping for an aif... */
248487183Sscottl		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
248587183Sscottl			wakeup(sc->aac_aifq);
248687183Sscottl		/* Wakeup any poll()ers */
248787183Sscottl		selwakeup(&sc->rcv_select);
248883114Sscottl	}
248987183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
249082527Sscottl
249183114Sscottl	return;
249265793Smsmith}
249365793Smsmith
249483114Sscottl/*
249570393Smsmith * Return the Revision of the driver to userspace and check to see if the
249682527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
249782527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
249882527Sscottl * returning what the card reported.
249965793Smsmith */
250065793Smsmithstatic int
250181189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
250265793Smsmith{
250383114Sscottl	struct aac_rev_check rev_check;
250483114Sscottl	struct aac_rev_check_resp rev_check_resp;
250583114Sscottl	int error = 0;
250665793Smsmith
250783114Sscottl	debug_called(2);
250865793Smsmith
250983114Sscottl	/*
251083114Sscottl	 * Copyin the revision struct from userspace
251183114Sscottl	 */
251283114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
251381082Sscottl			sizeof(struct aac_rev_check))) != 0) {
251483114Sscottl		return error;
251583114Sscottl	}
251665793Smsmith
251783114Sscottl	debug(2, "Userland revision= %d\n",
251883114Sscottl	      rev_check.callingRevision.buildNumber);
251965793Smsmith
252083114Sscottl	/*
252183114Sscottl	 * Doctor up the response struct.
252283114Sscottl	 */
252383114Sscottl	rev_check_resp.possiblyCompatible = 1;
252483114Sscottl	rev_check_resp.adapterSWRevision.external.ul =
252583114Sscottl	    sc->aac_revision.external.ul;
252683114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
252783114Sscottl	    sc->aac_revision.buildNumber;
252865793Smsmith
252983114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
253083114Sscottl			sizeof(struct aac_rev_check_resp)));
253165793Smsmith}
253265793Smsmith
253383114Sscottl/*
253465793Smsmith * Pass the caller the next AIF in their queue
253565793Smsmith */
253665793Smsmithstatic int
253781189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
253865793Smsmith{
253983114Sscottl	struct get_adapter_fib_ioctl agf;
254083114Sscottl	int error, s;
254165793Smsmith
254283114Sscottl	debug_called(2);
254365793Smsmith
254483114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
254565793Smsmith
254683114Sscottl		/*
254783114Sscottl		 * Check the magic number that we gave the caller.
254883114Sscottl		 */
254983114Sscottl		if (agf.AdapterFibContext != (int)sc->aifthread) {
255083114Sscottl			error = EFAULT;
255183114Sscottl		} else {
255283114Sscottl
255383114Sscottl			s = splbio();
255481189Sscottl			error = aac_return_aif(sc, agf.AifFib);
255583114Sscottl
255683114Sscottl			if ((error == EAGAIN) && (agf.Wait)) {
255783114Sscottl				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
255883114Sscottl				while (error == EAGAIN) {
255983114Sscottl					error = tsleep(sc->aac_aifq, PRIBIO |
256083114Sscottl						       PCATCH, "aacaif", 0);
256183114Sscottl					if (error == 0)
256283114Sscottl						error = aac_return_aif(sc,
256383114Sscottl						    agf.AifFib);
256483114Sscottl				}
256583114Sscottl				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
256683114Sscottl			}
256783114Sscottl		splx(s);
256865793Smsmith		}
256965793Smsmith	}
257083114Sscottl	return(error);
257165793Smsmith}
257265793Smsmith
257383114Sscottl/*
257470393Smsmith * Hand the next AIF off the top of the queue out to userspace.
257570393Smsmith */
257670393Smsmithstatic int
257781189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr)
257870393Smsmith{
257987183Sscottl	int error;
258070393Smsmith
258183114Sscottl	debug_called(2);
258270393Smsmith
258387310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
258483114Sscottl	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
258583114Sscottl		error = EAGAIN;
258683114Sscottl	} else {
258783114Sscottl		error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
258883114Sscottl				sizeof(struct aac_aif_command));
258983114Sscottl		if (error)
259083114Sscottl			printf("aac_return_aif: copyout returned %d\n", error);
259183114Sscottl		if (!error)
259283114Sscottl			sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) %
259383114Sscottl					    AAC_AIFQ_LENGTH;
259483114Sscottl	}
259587183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
259683114Sscottl	return(error);
259770393Smsmith}
259882527Sscottl
259983114Sscottl/*
260082527Sscottl * Give the userland some information about the container.  The AAC arch
260182527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
260282527Sscottl * the containers to have b:t:l numbers.  Fake it.
260382527Sscottl */
260482527Sscottlstatic int
260582527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
260682527Sscottl{
260783114Sscottl	struct aac_query_disk query_disk;
260883114Sscottl	struct aac_container *co;
260983114Sscottl	struct aac_disk	*disk;
261083114Sscottl	int error, id;
261182527Sscottl
261283114Sscottl	debug_called(2);
261382527Sscottl
261483114Sscottl	disk = NULL;
261582527Sscottl
261683114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
261783114Sscottl		       sizeof(struct aac_query_disk));
261883114Sscottl	if (error)
261983114Sscottl		return (error);
262082527Sscottl
262183114Sscottl	id = query_disk.ContainerNumber;
262283114Sscottl	if (id == -1)
262383114Sscottl		return (EINVAL);
262482527Sscottl
262587310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
262683114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
262783114Sscottl		if (co->co_mntobj.ObjectId == id)
262883114Sscottl			break;
262983114Sscottl		}
263082527Sscottl
2631105528Sphk	if (co == NULL) {
263283114Sscottl			query_disk.Valid = 0;
263383114Sscottl			query_disk.Locked = 0;
263483114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
2635105528Sphk	} else {
2636105528Sphk		disk = device_get_softc(co->co_disk);
2637105528Sphk		query_disk.Valid = 1;
2638105528Sphk		query_disk.Locked =
2639105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
2640105528Sphk		query_disk.Deleted = 0;
2641105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
2642105528Sphk		query_disk.Target = disk->unit;
2643105528Sphk		query_disk.Lun = 0;
2644105528Sphk		query_disk.UnMapped = 0;
2645105528Sphk		bcopy(disk->ad_dev_t->si_name,
2646105528Sphk		      &query_disk.diskDeviceName[0], 10);
2647105528Sphk	}
264883114Sscottl	AAC_LOCK_RELEASE(&sc->aac_container_lock);
264982527Sscottl
265083114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
265183114Sscottl			sizeof(struct aac_query_disk));
265283114Sscottl
265383114Sscottl	return (error);
265482527Sscottl}
265582527Sscottl
265695536Sscottlstatic void
265795536Sscottlaac_get_bus_info(struct aac_softc *sc)
265895536Sscottl{
265995536Sscottl	struct aac_fib *fib;
266095536Sscottl	struct aac_ctcfg *c_cmd;
266195536Sscottl	struct aac_ctcfg_resp *c_resp;
266295536Sscottl	struct aac_vmioctl *vmi;
266395536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
266495536Sscottl	struct aac_getbusinf businfo;
266595536Sscottl	struct aac_cam_inf *caminf;
266695536Sscottl	device_t child;
266795536Sscottl	int i, found, error;
266895536Sscottl
266995536Sscottl	aac_alloc_sync_fib(sc, &fib, 0);
267095536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
267195966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
267295536Sscottl
267395536Sscottl	c_cmd->Command = VM_ContainerConfig;
267495536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
267595536Sscottl	c_cmd->param = 0;
267695536Sscottl
267795536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
267895536Sscottl	    sizeof(struct aac_ctcfg));
267995536Sscottl	if (error) {
268095536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
268195536Sscottl		    "VM_ContainerConfig command\n", error);
268295536Sscottl		aac_release_sync_fib(sc);
268395536Sscottl		return;
268495536Sscottl	}
268595536Sscottl
268695536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
268795536Sscottl	if (c_resp->Status != ST_OK) {
268895536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
268995536Sscottl		    c_resp->Status);
269095536Sscottl		aac_release_sync_fib(sc);
269195536Sscottl		return;
269295536Sscottl	}
269395536Sscottl
269495536Sscottl	sc->scsi_method_id = c_resp->param;
269595536Sscottl
269695536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
269795966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
269895966Sscottl
269995536Sscottl	vmi->Command = VM_Ioctl;
270095536Sscottl	vmi->ObjType = FT_DRIVE;
270195536Sscottl	vmi->MethId = sc->scsi_method_id;
270295536Sscottl	vmi->ObjId = 0;
270395536Sscottl	vmi->IoctlCmd = GetBusInfo;
270495536Sscottl
270595536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
270695536Sscottl	    sizeof(struct aac_vmioctl));
270795536Sscottl	if (error) {
270895536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
270995536Sscottl		    error);
271095536Sscottl		aac_release_sync_fib(sc);
271195536Sscottl		return;
271295536Sscottl	}
271395536Sscottl
271495536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
271595536Sscottl	if (vmi_resp->Status != ST_OK) {
271695536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
271795536Sscottl		    vmi_resp->Status);
271895536Sscottl		aac_release_sync_fib(sc);
271995536Sscottl		return;
272095536Sscottl	}
272195536Sscottl
272295536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
272395536Sscottl	aac_release_sync_fib(sc);
272495536Sscottl
272595536Sscottl	found = 0;
272695536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
272795536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
272895536Sscottl			continue;
272995536Sscottl
273095536Sscottl		MALLOC(caminf, struct aac_cam_inf *,
273195536Sscottl		    sizeof(struct aac_cam_inf), M_AACBUF, M_NOWAIT | M_ZERO);
273295536Sscottl		if (caminf == NULL)
273395536Sscottl			continue;
273495536Sscottl
273595536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
273695536Sscottl		if (child == NULL) {
273795536Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
273895536Sscottl			continue;
273995536Sscottl		}
274095536Sscottl
274195536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
274295536Sscottl		caminf->BusNumber = i;
274395536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
274495536Sscottl		caminf->aac_sc = sc;
274595536Sscottl
274695536Sscottl		device_set_ivars(child, caminf);
274795536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
274895536Sscottl
274995536Sscottl		found = 1;
275095536Sscottl	}
275195536Sscottl
275295536Sscottl	if (found)
275395536Sscottl		bus_generic_attach(sc->aac_dev);
275495536Sscottl
275595536Sscottl	return;
275695536Sscottl}
2757