aac.c revision 90275
190075Sobrien/*-
290075Sobrien * Copyright (c) 2000 Michael Smith
390075Sobrien * Copyright (c) 2001 Scott Long
490075Sobrien * Copyright (c) 2000 BSDi
590075Sobrien * Copyright (c) 2001 Adaptec, Inc.
690075Sobrien * All rights reserved.
790075Sobrien *
890075Sobrien * Redistribution and use in source and binary forms, with or without
990075Sobrien * modification, are permitted provided that the following conditions
1090075Sobrien * are met:
1190075Sobrien * 1. Redistributions of source code must retain the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer.
1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1452284Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1652284Sobrien *
1752284Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1852284Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1952284Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2052284Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2190075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2252284Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2352284Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2452284Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2550397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2690075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2790075Sobrien * SUCH DAMAGE.
2890075Sobrien *
2990075Sobrien *	$FreeBSD: head/sys/dev/aac/aac.c 90275 2002-02-06 01:34:09Z scottl $
3090075Sobrien */
3190075Sobrien
3290075Sobrien/*
3390075Sobrien * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3490075Sobrien */
3590075Sobrien
3690075Sobrien#include "opt_aac.h"
3790075Sobrien
3890075Sobrien/* #include <stddef.h> */
3990075Sobrien#include <sys/param.h>
4050397Sobrien#include <sys/systm.h>
4190075Sobrien#include <sys/malloc.h>
4250397Sobrien#include <sys/kernel.h>
4350397Sobrien#include <sys/kthread.h>
4450397Sobrien#include <sys/lock.h>
4550397Sobrien#include <sys/mutex.h>
4690075Sobrien#include <sys/sysctl.h>
4790075Sobrien#include <sys/poll.h>
4890075Sobrien#if __FreeBSD_version >= 500005
4990075Sobrien#include <sys/selinfo.h>
5050397Sobrien#else
5150397Sobrien#include <sys/select.h>
5290075Sobrien#endif
5390075Sobrien
5490075Sobrien#include <dev/aac/aac_compat.h>
5590075Sobrien
5690075Sobrien#include <sys/bus.h>
5790075Sobrien#include <sys/conf.h>
5890075Sobrien#include <sys/devicestat.h>
5990075Sobrien#include <sys/disk.h>
6090075Sobrien#include <sys/file.h>
6190075Sobrien#include <sys/signalvar.h>
6290075Sobrien#include <sys/time.h>
6390075Sobrien#include <sys/eventhandler.h>
6490075Sobrien
6590075Sobrien#include <machine/bus_memio.h>
6690075Sobrien#include <machine/bus.h>
6790075Sobrien#include <machine/resource.h>
6890075Sobrien
6950397Sobrien#include <dev/aac/aacreg.h>
7090075Sobrien#include <dev/aac/aac_ioctl.h>
7190075Sobrien#include <dev/aac/aacvar.h>
7290075Sobrien#include <dev/aac/aac_tables.h>
7390075Sobrien
7490075Sobrienstatic void	aac_startup(void *arg);
7590075Sobrienstatic void	aac_add_container(struct aac_softc *sc,
7650397Sobrien				  struct aac_mntinforesponse *mir, int f);
7750397Sobrien
7850397Sobrien/* Command Processing */
7990075Sobrienstatic void	aac_startio(struct aac_softc *sc);
8050397Sobrienstatic void	aac_timeout(struct aac_softc *sc);
8150397Sobrienstatic int	aac_start(struct aac_command *cm);
8250397Sobrienstatic void	aac_complete(void *context, int pending);
8350397Sobrienstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
8490075Sobrienstatic void	aac_bio_complete(struct aac_command *cm);
8550397Sobrienstatic int	aac_wait_command(struct aac_command *cm, int timeout);
8650397Sobrienstatic void	aac_host_command(struct aac_softc *sc);
8750397Sobrienstatic void	aac_host_response(struct aac_softc *sc);
8850397Sobrien
8950397Sobrien/* Command Buffer Management */
9090075Sobrienstatic int	aac_alloc_command(struct aac_softc *sc,
9150397Sobrien				  struct aac_command **cmp);
9250397Sobrienstatic void	aac_release_command(struct aac_command *cm);
9350397Sobrienstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
9450397Sobrien				       int nseg, int error);
9590075Sobrienstatic int	aac_alloc_commands(struct aac_softc *sc);
9650397Sobrienstatic void	aac_free_commands(struct aac_softc *sc);
9750397Sobrienstatic void	aac_map_command(struct aac_command *cm);
9850397Sobrienstatic void	aac_unmap_command(struct aac_command *cm);
9950397Sobrien
10090075Sobrien/* Hardware Interface */
10150397Sobrienstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
10250397Sobrien			       int error);
10350397Sobrienstatic int	aac_check_firmware(struct aac_softc *sc);
10450397Sobrienstatic int	aac_init(struct aac_softc *sc);
10550397Sobrienstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
10650397Sobrien				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
10750397Sobrien				 u_int32_t arg3, u_int32_t *sp);
10850397Sobrienstatic int	aac_sync_fib(struct aac_softc *sc, u_int32_t command,
10950397Sobrien			     u_int32_t xferstate, void *data,
11050397Sobrien			     u_int16_t datasize, void *result,
11150397Sobrien			     u_int16_t *resultsize);
11250397Sobrienstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
11350397Sobrien				struct aac_command *cm);
11450397Sobrienstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
11550397Sobrien				u_int32_t *fib_size, struct aac_fib **fib_addr);
11650397Sobrienstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
11750397Sobrien				     struct aac_fib *fib);
11850397Sobrien
11950397Sobrien/* Falcon/PPC interface */
12050397Sobrienstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
12150397Sobrienstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
12250397Sobrienstatic int	aac_fa_get_istatus(struct aac_softc *sc);
12350397Sobrienstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
12450397Sobrienstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
12550397Sobrien				   u_int32_t arg0, u_int32_t arg1,
12650397Sobrien				   u_int32_t arg2, u_int32_t arg3);
12750397Sobrienstatic int	aac_fa_get_mailboxstatus(struct aac_softc *sc);
12850397Sobrienstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
12950397Sobrien
13050397Sobrienstruct aac_interface aac_fa_interface = {
13150397Sobrien	aac_fa_get_fwstatus,
13290075Sobrien	aac_fa_qnotify,
13350397Sobrien	aac_fa_get_istatus,
13450397Sobrien	aac_fa_clear_istatus,
13550397Sobrien	aac_fa_set_mailbox,
13650397Sobrien	aac_fa_get_mailboxstatus,
13750397Sobrien	aac_fa_set_interrupts
13850397Sobrien};
13950397Sobrien
14050397Sobrien/* StrongARM interface */
14150397Sobrienstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
14250397Sobrienstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
14350397Sobrienstatic int	aac_sa_get_istatus(struct aac_softc *sc);
14450397Sobrienstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
14550397Sobrienstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
14650397Sobrien				   u_int32_t arg0, u_int32_t arg1,
14750397Sobrien				   u_int32_t arg2, u_int32_t arg3);
14850397Sobrienstatic int	aac_sa_get_mailboxstatus(struct aac_softc *sc);
14950397Sobrienstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
15050397Sobrien
15150397Sobrienstruct aac_interface aac_sa_interface = {
15250397Sobrien	aac_sa_get_fwstatus,
15350397Sobrien	aac_sa_qnotify,
15450397Sobrien	aac_sa_get_istatus,
15550397Sobrien	aac_sa_clear_istatus,
15650397Sobrien	aac_sa_set_mailbox,
15750397Sobrien	aac_sa_get_mailboxstatus,
15850397Sobrien	aac_sa_set_interrupts
15950397Sobrien};
16050397Sobrien
16150397Sobrien/* i960Rx interface */
16250397Sobrienstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
16350397Sobrienstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
16490075Sobrienstatic int	aac_rx_get_istatus(struct aac_softc *sc);
16550397Sobrienstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
16650397Sobrienstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
16750397Sobrien				   u_int32_t arg0, u_int32_t arg1,
16850397Sobrien				   u_int32_t arg2, u_int32_t arg3);
16990075Sobrienstatic int	aac_rx_get_mailboxstatus(struct aac_softc *sc);
17050397Sobrienstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
17150397Sobrien
17250397Sobrienstruct aac_interface aac_rx_interface = {
17390075Sobrien	aac_rx_get_fwstatus,
17490075Sobrien	aac_rx_qnotify,
17590075Sobrien	aac_rx_get_istatus,
17690075Sobrien	aac_rx_clear_istatus,
17790075Sobrien	aac_rx_set_mailbox,
17890075Sobrien	aac_rx_get_mailboxstatus,
17990075Sobrien	aac_rx_set_interrupts
18090075Sobrien};
18190075Sobrien
18290075Sobrien/* Debugging and Diagnostics */
18390075Sobrienstatic void	aac_describe_controller(struct aac_softc *sc);
18490075Sobrienstatic char	*aac_describe_code(struct aac_code_lookup *table,
18590075Sobrien				   u_int32_t code);
18690075Sobrien
18790075Sobrien/* Management Interface */
18890075Sobrienstatic d_open_t		aac_open;
18990075Sobrienstatic d_close_t	aac_close;
19090075Sobrienstatic d_ioctl_t	aac_ioctl;
19190075Sobrienstatic d_poll_t		aac_poll;
19290075Sobrienstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
19390075Sobrienstatic void		aac_handle_aif(struct aac_softc *sc,
19490075Sobrien					   struct aac_fib *fib);
19590075Sobrienstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
19690075Sobrienstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
19790075Sobrienstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
19890075Sobrienstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
19990075Sobrien
20090075Sobrien#define AAC_CDEV_MAJOR	150
20190075Sobrien
20290075Sobrienstatic struct cdevsw aac_cdevsw = {
20390075Sobrien	aac_open,		/* open */
20490075Sobrien	aac_close,		/* close */
20552284Sobrien	noread,			/* read */
20652284Sobrien	nowrite,		/* write */
20790075Sobrien	aac_ioctl,		/* ioctl */
20852284Sobrien	aac_poll,		/* poll */
20952284Sobrien	nommap,			/* mmap */
21052284Sobrien	nostrategy,		/* strategy */
21152284Sobrien	"aac",			/* name */
21252284Sobrien	AAC_CDEV_MAJOR,		/* major */
21352284Sobrien	nodump,			/* dump */
21452284Sobrien	nopsize,		/* psize */
21552284Sobrien	0,			/* flags */
21652284Sobrien#if __FreeBSD_version < 500005
21752284Sobrien	-1,			/* bmaj */
21852284Sobrien#endif
21952284Sobrien};
22052284Sobrien
22152284SobrienMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
22290075Sobrien
22352284Sobrien/* sysctl node */
22452284SobrienSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
22552284Sobrien
22690075Sobrien/*
22750397Sobrien * Device Interface
22850397Sobrien */
22950397Sobrien
23050397Sobrien/*
23150397Sobrien * Initialise the controller and softc
23250397Sobrien */
23350397Sobrienint
23450397Sobrienaac_attach(struct aac_softc *sc)
23550397Sobrien{
23650397Sobrien	int error, unit;
23750397Sobrien
23850397Sobrien	debug_called(1);
23950397Sobrien
24050397Sobrien	/*
24150397Sobrien	 * Initialise per-controller queues.
24250397Sobrien	 */
24350397Sobrien	aac_initq_free(sc);
24450397Sobrien	aac_initq_ready(sc);
24550397Sobrien	aac_initq_busy(sc);
24650397Sobrien	aac_initq_complete(sc);
24750397Sobrien	aac_initq_bio(sc);
24850397Sobrien
24950397Sobrien#if __FreeBSD_version >= 500005
25050397Sobrien	/*
25150397Sobrien	 * Initialise command-completion task.
25250397Sobrien	 */
25350397Sobrien	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
25450397Sobrien#endif
25550397Sobrien
25650397Sobrien	/* disable interrupts before we enable anything */
25750397Sobrien	AAC_MASK_INTERRUPTS(sc);
25850397Sobrien
25950397Sobrien	/* mark controller as suspended until we get ourselves organised */
26050397Sobrien	sc->aac_state |= AAC_STATE_SUSPEND;
26150397Sobrien
26250397Sobrien	/*
26350397Sobrien	 * Check that the firmware on the card is supported.
26450397Sobrien	 */
26550397Sobrien	if ((error = aac_check_firmware(sc)) != 0)
26650397Sobrien		return(error);
26750397Sobrien
26850397Sobrien	/*
26950397Sobrien	 * Allocate command structures.
27050397Sobrien	 */
27150397Sobrien	if ((error = aac_alloc_commands(sc)) != 0)
27250397Sobrien		return(error);
27350397Sobrien
27450397Sobrien	/*
27550397Sobrien	 * Initialise the adapter.
27650397Sobrien	 */
27750397Sobrien	if ((error = aac_init(sc)) != 0)
27850397Sobrien		return(error);
27950397Sobrien
28050397Sobrien	/*
28150397Sobrien	 * Print a little information about the controller.
28250397Sobrien	 */
28350397Sobrien	aac_describe_controller(sc);
28450397Sobrien
28550397Sobrien	/*
28650397Sobrien	 * Register to probe our containers later.
28750397Sobrien	 */
28850397Sobrien	TAILQ_INIT(&sc->aac_container_tqh);
28952284Sobrien	AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
29090075Sobrien
29190075Sobrien	/*
29290075Sobrien	 * Lock for the AIF queue
29390075Sobrien	 */
29490075Sobrien	AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
29590075Sobrien
29690075Sobrien	sc->aac_ich.ich_func = aac_startup;
29790075Sobrien	sc->aac_ich.ich_arg = sc;
29890075Sobrien	if (config_intrhook_establish(&sc->aac_ich) != 0) {
29990075Sobrien		device_printf(sc->aac_dev,
30090075Sobrien			      "can't establish configuration hook\n");
30190075Sobrien		return(ENXIO);
30290075Sobrien	}
30390075Sobrien
30490075Sobrien	/*
30590075Sobrien	 * Make the control device.
30690075Sobrien	 */
30790075Sobrien	unit = device_get_unit(sc->aac_dev);
30890075Sobrien	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644,
30990075Sobrien				 "aac%d", unit);
31090075Sobrien#if __FreeBSD_version > 500005
31190075Sobrien	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
31290075Sobrien	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
31390075Sobrien#endif
31490075Sobrien	sc->aac_dev_t->si_drv1 = sc;
31590075Sobrien
31690075Sobrien	/* Create the AIF thread */
31790075Sobrien#if __FreeBSD_version > 500005
31890075Sobrien	if (kthread_create((void(*)(void *))aac_host_command, sc,
31990075Sobrien			   &sc->aifthread, 0, "aac%daif", unit))
32090075Sobrien#else
32190075Sobrien	if (kthread_create((void(*)(void *))aac_host_command, sc,
32290075Sobrien			   &sc->aifthread, "aac%daif", unit))
32390075Sobrien#endif
32490075Sobrien		panic("Could not create AIF thread\n");
32590075Sobrien
32690075Sobrien	/* Register the shutdown method to only be called post-dump */
32790075Sobrien	if ((EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, sc->aac_dev,
32890075Sobrien				   SHUTDOWN_PRI_DEFAULT)) == NULL)
32990075Sobrien	device_printf(sc->aac_dev, "shutdown event registration failed\n");
33090075Sobrien
33190075Sobrien	return(0);
33290075Sobrien}
33390075Sobrien
33490075Sobrien/*
33590075Sobrien * Probe for containers, create disks.
33690075Sobrien */
33790075Sobrienstatic void
33890075Sobrienaac_startup(void *arg)
33990075Sobrien{
34090075Sobrien	struct aac_softc *sc;
34152284Sobrien	struct aac_mntinfo mi;
34252284Sobrien	struct aac_mntinforesponse mir;
34352284Sobrien	u_int16_t rsize;
34452284Sobrien	int i = 0;
34552284Sobrien
34652284Sobrien	debug_called(1);
34752284Sobrien
34852284Sobrien	sc = (struct aac_softc *)arg;
34952284Sobrien
35052284Sobrien	/* disconnect ourselves from the intrhook chain */
35152284Sobrien	config_intrhook_disestablish(&sc->aac_ich);
35252284Sobrien
35352284Sobrien	/* loop over possible containers */
35452284Sobrien	mi.Command = VM_NameServe;
35552284Sobrien	mi.MntType = FT_FILESYS;
35652284Sobrien	do {
35752284Sobrien		/* request information on this container */
35890075Sobrien		mi.MntCount = i;
35990075Sobrien		rsize = sizeof(mir);
36090075Sobrien		if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
36190075Sobrien				 sizeof(struct aac_mntinfo), &mir, &rsize)) {
36290075Sobrien			debug(2, "error probing container %d", i);
36390075Sobrien			continue;
36490075Sobrien		}
36590075Sobrien		/* check response size */
36690075Sobrien		if (rsize != sizeof(mir)) {
36790075Sobrien			debug(2, "container info response wrong size "
36890075Sobrien			      "(%d should be %d)", rsize, sizeof(mir));
36990075Sobrien			continue;
37090075Sobrien		}
37190075Sobrien
37290075Sobrien		aac_add_container(sc, &mir, 0);
37390075Sobrien		i++;
37490075Sobrien	} while ((i < mir.MntRespCount) && (i < AAC_MAX_CONTAINERS));
37590075Sobrien
37690075Sobrien	/* poke the bus to actually attach the child devices */
37790075Sobrien	if (bus_generic_attach(sc->aac_dev))
37890075Sobrien		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
37990075Sobrien
38090075Sobrien	/* mark the controller up */
38190075Sobrien	sc->aac_state &= ~AAC_STATE_SUSPEND;
38290075Sobrien
38390075Sobrien	/* enable interrupts now */
38490075Sobrien	AAC_UNMASK_INTERRUPTS(sc);
38590075Sobrien
38690075Sobrien	/* enable the timeout watchdog */
38790075Sobrien	timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
38890075Sobrien}
38990075Sobrien
39090075Sobrien/*
39190075Sobrien * Create a device to respresent a new container
39290075Sobrien */
39390075Sobrienstatic void
39490075Sobrienaac_add_container(struct aac_softc *sc, struct aac_mntinforesponse *mir, int f)
39590075Sobrien{
39690075Sobrien	struct aac_container *co;
39790075Sobrien	device_t child;
39890075Sobrien
39990075Sobrien	/*
40090075Sobrien	 * Check container volume type for validity.  Note that many of
40190075Sobrien	 * the possible types may never show up.
40290075Sobrien	 */
40390075Sobrien	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
40490075Sobrien		MALLOC(co, struct aac_container *, sizeof *co, M_AACBUF,
40590075Sobrien		       M_NOWAIT);
40690075Sobrien		if (co == NULL)
40790075Sobrien			panic("Out of memory?!\n");
40890075Sobrien		debug(1, "id %x  name '%.16s'  size %u  type %d",
40990075Sobrien		      mir->MntTable[0].ObjectId,
41090075Sobrien		      mir->MntTable[0].FileSystemName,
41190075Sobrien		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
41290075Sobrien
41390075Sobrien		if ((child = device_add_child(sc->aac_dev, NULL, -1)) == NULL)
41490075Sobrien			device_printf(sc->aac_dev, "device_add_child failed\n");
41590075Sobrien		else
41690075Sobrien			device_set_ivars(child, co);
41790075Sobrien		device_set_desc(child, aac_describe_code(aac_container_types,
41890075Sobrien				mir->MntTable[0].VolType));
41990075Sobrien		co->co_disk = child;
42090075Sobrien		co->co_found = f;
42190075Sobrien		bcopy(&mir->MntTable[0], &co->co_mntobj,
42290075Sobrien		      sizeof(struct aac_mntobj));
42390075Sobrien		AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
42490075Sobrien		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
42590075Sobrien		AAC_LOCK_RELEASE(&sc->aac_container_lock);
42690075Sobrien	}
42790075Sobrien}
42890075Sobrien
42990075Sobrien/*
43090075Sobrien * Free all of the resources associated with (sc)
43190075Sobrien *
43290075Sobrien * Should not be called if the controller is active.
43390075Sobrien */
43490075Sobrienvoid
43590075Sobrienaac_free(struct aac_softc *sc)
43690075Sobrien{
43790075Sobrien	debug_called(1);
43890075Sobrien
43990075Sobrien	/* remove the control device */
44090075Sobrien	if (sc->aac_dev_t != NULL)
44190075Sobrien		destroy_dev(sc->aac_dev_t);
44290075Sobrien
44390075Sobrien	/* throw away any FIB buffers, discard the FIB DMA tag */
44490075Sobrien	if (sc->aac_fibs != NULL)
44590075Sobrien		aac_free_commands(sc);
44690075Sobrien	if (sc->aac_fib_dmat)
44790075Sobrien		bus_dma_tag_destroy(sc->aac_fib_dmat);
44890075Sobrien
44990075Sobrien	/* destroy the common area */
45090075Sobrien	if (sc->aac_common) {
45190075Sobrien		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
45290075Sobrien		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
45390075Sobrien				sc->aac_common_dmamap);
45490075Sobrien	}
45590075Sobrien	if (sc->aac_common_dmat)
45690075Sobrien		bus_dma_tag_destroy(sc->aac_common_dmat);
45790075Sobrien
45890075Sobrien	/* disconnect the interrupt handler */
45990075Sobrien	if (sc->aac_intr)
46090075Sobrien		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
46190075Sobrien	if (sc->aac_irq != NULL)
46290075Sobrien		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
46390075Sobrien				     sc->aac_irq);
46490075Sobrien
46590075Sobrien	/* destroy data-transfer DMA tag */
46690075Sobrien	if (sc->aac_buffer_dmat)
46790075Sobrien		bus_dma_tag_destroy(sc->aac_buffer_dmat);
46890075Sobrien
46990075Sobrien	/* destroy the parent DMA tag */
47090075Sobrien	if (sc->aac_parent_dmat)
47190075Sobrien		bus_dma_tag_destroy(sc->aac_parent_dmat);
47290075Sobrien
47390075Sobrien	/* release the register window mapping */
47490075Sobrien	if (sc->aac_regs_resource != NULL)
47590075Sobrien		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
47690075Sobrien				     sc->aac_regs_rid, sc->aac_regs_resource);
47790075Sobrien}
47890075Sobrien
47990075Sobrien/*
48090075Sobrien * Disconnect from the controller completely, in preparation for unload.
48190075Sobrien */
48290075Sobrienint
48390075Sobrienaac_detach(device_t dev)
48490075Sobrien{
48590075Sobrien	struct aac_softc *sc;
48690075Sobrien#if AAC_BROKEN
48790075Sobrien	int error;
48890075Sobrien#endif
48990075Sobrien
49090075Sobrien	debug_called(1);
49190075Sobrien
49290075Sobrien	sc = device_get_softc(dev);
49390075Sobrien
49490075Sobrien	if (sc->aac_state & AAC_STATE_OPEN)
49590075Sobrien	return(EBUSY);
49690075Sobrien
49790075Sobrien#if AAC_BROKEN
49890075Sobrien	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
49990075Sobrien		sc->aifflags |= AAC_AIFFLAGS_EXIT;
50090075Sobrien		wakeup(sc->aifthread);
50190075Sobrien		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
50290075Sobrien	}
50390075Sobrien
50490075Sobrien	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
50590075Sobrien		panic("Cannot shutdown AIF thread\n");
50690075Sobrien
50790075Sobrien	if ((error = aac_shutdown(dev)))
50890075Sobrien		return(error);
50990075Sobrien
51090075Sobrien	aac_free(sc);
51190075Sobrien
51290075Sobrien	return(0);
51390075Sobrien#else
51490075Sobrien	return (EBUSY);
51590075Sobrien#endif
51690075Sobrien}
51790075Sobrien
51890075Sobrien/*
51990075Sobrien * Bring the controller down to a dormant state and detach all child devices.
52090075Sobrien *
52190075Sobrien * This function is called before detach or system shutdown.
52290075Sobrien *
52390075Sobrien * Note that we can assume that the bioq on the controller is empty, as we won't
52490075Sobrien * allow shutdown if any device is open.
52590075Sobrien */
52690075Sobrienint
52790075Sobrienaac_shutdown(device_t dev)
52890075Sobrien{
52990075Sobrien	struct aac_softc *sc;
53090075Sobrien	struct aac_close_command cc;
53190075Sobrien	int s, i;
53290075Sobrien
53390075Sobrien	debug_called(1);
53490075Sobrien
53590075Sobrien	sc = device_get_softc(dev);
53690075Sobrien
53790075Sobrien	s = splbio();
53890075Sobrien
53990075Sobrien	sc->aac_state |= AAC_STATE_SUSPEND;
54090075Sobrien
54190075Sobrien	/*
54290075Sobrien	 * Send a Container shutdown followed by a HostShutdown FIB to the
54390075Sobrien	 * controller to convince it that we don't want to talk to it anymore.
54490075Sobrien	 * We've been closed and all I/O completed already
54590075Sobrien	 */
54690075Sobrien	device_printf(sc->aac_dev, "shutting down controller...");
54790075Sobrien
54890075Sobrien	cc.Command = VM_CloseAll;
54990075Sobrien	cc.ContainerId = 0xffffffff;
55090075Sobrien	if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc), NULL, NULL))
55190075Sobrien		printf("FAILED.\n");
55290075Sobrien	else {
55390075Sobrien		i = 0;
55490075Sobrien		/*
55590075Sobrien		 * XXX Issuing this command to the controller makes it shut down
55690075Sobrien		 * but also keeps it from coming back up without a reset of the
55790075Sobrien		 * PCI bus.  This is not desirable if you are just unloading the
55890075Sobrien		 * driver module with the intent to reload it later.
55990075Sobrien		 */
56090075Sobrien		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, &i,
56190075Sobrien				 sizeof(i), NULL, NULL)) {
56290075Sobrien			printf("FAILED.\n");
56390075Sobrien		} else {
56490075Sobrien			printf("done.\n");
56590075Sobrien		}
56690075Sobrien	}
56790075Sobrien
56890075Sobrien	AAC_MASK_INTERRUPTS(sc);
56990075Sobrien
57090075Sobrien	splx(s);
57190075Sobrien	return(0);
57290075Sobrien}
57390075Sobrien
57490075Sobrien/*
57590075Sobrien * Bring the controller to a quiescent state, ready for system suspend.
57690075Sobrien */
57790075Sobrienint
57890075Sobrienaac_suspend(device_t dev)
57990075Sobrien{
58090075Sobrien	struct aac_softc *sc;
58190075Sobrien	int s;
58290075Sobrien
58390075Sobrien	debug_called(1);
58490075Sobrien
58590075Sobrien	sc = device_get_softc(dev);
58690075Sobrien
58790075Sobrien	s = splbio();
58890075Sobrien
58990075Sobrien	sc->aac_state |= AAC_STATE_SUSPEND;
59090075Sobrien
59190075Sobrien	AAC_MASK_INTERRUPTS(sc);
59290075Sobrien	splx(s);
59390075Sobrien	return(0);
59490075Sobrien}
59590075Sobrien
59690075Sobrien/*
59790075Sobrien * Bring the controller back to a state ready for operation.
59890075Sobrien */
59990075Sobrienint
60090075Sobrienaac_resume(device_t dev)
60190075Sobrien{
60290075Sobrien	struct aac_softc *sc;
60390075Sobrien
60490075Sobrien	debug_called(1);
60590075Sobrien
60690075Sobrien	sc = device_get_softc(dev);
60790075Sobrien
60890075Sobrien	sc->aac_state &= ~AAC_STATE_SUSPEND;
60990075Sobrien	AAC_UNMASK_INTERRUPTS(sc);
61090075Sobrien	return(0);
61190075Sobrien}
61290075Sobrien
61390075Sobrien/*
61490075Sobrien * Take an interrupt.
61590075Sobrien */
61690075Sobrienvoid
61790075Sobrienaac_intr(void *arg)
61890075Sobrien{
61990075Sobrien	struct aac_softc *sc;
62090075Sobrien	u_int16_t reason;
62190075Sobrien
62290075Sobrien	debug_called(2);
62390075Sobrien
62490075Sobrien	sc = (struct aac_softc *)arg;
62590075Sobrien
62690075Sobrien	reason = AAC_GET_ISTATUS(sc);
62790075Sobrien
62890075Sobrien	/* controller wants to talk to the log */
62990075Sobrien	if (reason & AAC_DB_PRINTF) {
63090075Sobrien		AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
63190075Sobrien		aac_print_printf(sc);
63290075Sobrien	}
63390075Sobrien
63490075Sobrien	/* controller has a message for us? */
63590075Sobrien	if (reason & AAC_DB_COMMAND_READY) {
63690075Sobrien		AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
63790075Sobrien		/* XXX What happens if the thread is already awake? */
63890075Sobrien		if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
63990075Sobrien			sc->aifflags |= AAC_AIFFLAGS_PENDING;
64090075Sobrien			wakeup(sc->aifthread);
64190075Sobrien		}
64290075Sobrien	}
64390075Sobrien
64490075Sobrien	/* controller has a response for us? */
64590075Sobrien	if (reason & AAC_DB_RESPONSE_READY) {
64690075Sobrien		AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
64790075Sobrien		aac_host_response(sc);
64890075Sobrien	}
64990075Sobrien
65090075Sobrien	/*
65190075Sobrien	 * spurious interrupts that we don't use - reset the mask and clear the
65290075Sobrien	 * interrupts
65390075Sobrien	 */
65490075Sobrien	if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
65590075Sobrien		AAC_UNMASK_INTERRUPTS(sc);
65690075Sobrien		AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL |
65790075Sobrien				  AAC_DB_RESPONSE_NOT_FULL);
65890075Sobrien	}
65990075Sobrien};
66090075Sobrien
66190075Sobrien/*
66290075Sobrien * Command Processing
66390075Sobrien */
66490075Sobrien
66590075Sobrien/*
66690075Sobrien * Start as much queued I/O as possible on the controller
66790075Sobrien */
66890075Sobrienstatic void
66990075Sobrienaac_startio(struct aac_softc *sc)
67090075Sobrien{
67190075Sobrien	struct aac_command *cm;
67290075Sobrien
67390075Sobrien	debug_called(2);
67490075Sobrien
67590075Sobrien	for (;;) {
67690075Sobrien		/*
67790075Sobrien		 * Try to get a command that's been put off for lack of
67890075Sobrien		 * resources
67990075Sobrien		 */
68090075Sobrien		cm = aac_dequeue_ready(sc);
68190075Sobrien
68290075Sobrien		/*
68390075Sobrien		 * Try to build a command off the bio queue (ignore error
68490075Sobrien		 * return)
68590075Sobrien		 */
68690075Sobrien		if (cm == NULL)
68790075Sobrien			aac_bio_command(sc, &cm);
68890075Sobrien
68990075Sobrien		/* nothing to do? */
69090075Sobrien		if (cm == NULL)
69190075Sobrien			break;
69290075Sobrien
69390075Sobrien		/* try to give the command to the controller */
69490075Sobrien		if (aac_start(cm) == EBUSY) {
69590075Sobrien			/* put it on the ready queue for later */
69690075Sobrien			aac_requeue_ready(cm);
69790075Sobrien			break;
69890075Sobrien		}
69990075Sobrien	}
70090075Sobrien}
70190075Sobrien
70290075Sobrien/*
70390075Sobrien * Deliver a command to the controller; allocate controller resources at the
70490075Sobrien * last moment when possible.
70590075Sobrien */
70690075Sobrienstatic int
70790075Sobrienaac_start(struct aac_command *cm)
70890075Sobrien{
70990075Sobrien	struct aac_softc *sc;
71090075Sobrien	int error;
71190075Sobrien
71290075Sobrien	debug_called(2);
71390075Sobrien
71490075Sobrien	sc = cm->cm_sc;
71590075Sobrien
71690075Sobrien	/* get the command mapped */
71790075Sobrien	aac_map_command(cm);
71890075Sobrien
71990075Sobrien	/* fix up the address values in the FIB */
72090075Sobrien	cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
72190075Sobrien	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
72290075Sobrien
72390075Sobrien	/* save a pointer to the command for speedy reverse-lookup */
72490075Sobrien	cm->cm_fib->Header.SenderData = (u_int32_t)cm;	/* XXX 64-bit physical
72590075Sobrien							 * address issue */
72690075Sobrien
72790075Sobrien	/* put the FIB on the outbound queue */
72890075Sobrien	error = aac_enqueue_fib(sc, cm->cm_queue, cm);
72990075Sobrien	return(error);
73090075Sobrien}
73190075Sobrien
73290075Sobrien/*
73390075Sobrien * Handle notification of one or more FIBs coming from the controller.
73490075Sobrien */
73590075Sobrienstatic void
73690075Sobrienaac_host_command(struct aac_softc *sc)
73790075Sobrien{
73890075Sobrien	struct aac_fib *fib;
73990075Sobrien	u_int32_t fib_size;
74090075Sobrien	int size;
74190075Sobrien
74290075Sobrien	debug_called(2);
74390075Sobrien
74490075Sobrien	sc->aifflags |= AAC_AIFFLAGS_RUNNING;
74590075Sobrien
74690075Sobrien	while (!(sc->aifflags & AAC_AIFFLAGS_EXIT)) {
74790075Sobrien		if (!(sc->aifflags & AAC_AIFFLAGS_PENDING))
74890075Sobrien			tsleep(sc->aifthread, PRIBIO, "aifthd", 15 * hz);
74990075Sobrien
75090075Sobrien		sc->aifflags &= ~AAC_AIFFLAGS_PENDING;
75190075Sobrien		for (;;) {
75290075Sobrien			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
75390075Sobrien					    &fib_size, &fib))
75490075Sobrien				break;	/* nothing to do */
75590075Sobrien
75690075Sobrien			AAC_PRINT_FIB(sc, fib);
75790075Sobrien
75890075Sobrien			switch (fib->Header.Command) {
75990075Sobrien			case AifRequest:
76090075Sobrien				aac_handle_aif(sc, fib);
76190075Sobrien				break;
76290075Sobrien			default:
76390075Sobrien				device_printf(sc->aac_dev, "unknown command "
76490075Sobrien					      "from controller\n");
76590075Sobrien				break;
76690075Sobrien			}
76790075Sobrien
76890075Sobrien			/* Return the AIF to the controller. */
76990075Sobrien			if ((fib->Header.XferState == 0) ||
77090075Sobrien			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
77190075Sobrien				break;
77290075Sobrien
77390075Sobrien			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
77490075Sobrien				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
77590075Sobrien				*(AAC_FSAStatus*)fib->data = ST_OK;
77690075Sobrien
77790075Sobrien				/* XXX Compute the Size field? */
77890075Sobrien				size = fib->Header.Size;
77990075Sobrien				if (size > sizeof(struct aac_fib)) {
78090075Sobrien	 				size = sizeof(struct aac_fib);
78190075Sobrien					fib->Header.Size = size;
78290075Sobrien				}
78390075Sobrien				/*
78490075Sobrien				 * Since we did not generate this command, it
78590075Sobrien				 * cannot go through the normal
78690075Sobrien				 * enqueue->startio chain.
78790075Sobrien				 */
78890075Sobrien				aac_enqueue_response(sc,
78990075Sobrien						     AAC_ADAP_NORM_RESP_QUEUE,
79090075Sobrien						     fib);
79190075Sobrien			}
79290075Sobrien		}
79390075Sobrien	}
79490075Sobrien	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
79590075Sobrien	wakeup(sc->aac_dev);
79690075Sobrien
79790075Sobrien#if __FreeBSD_version > 500005
79890075Sobrien	mtx_lock(&Giant);
79990075Sobrien#endif
80090075Sobrien	kthread_exit(0);
80190075Sobrien}
80290075Sobrien
80390075Sobrien/*
80490075Sobrien * Handle notification of one or more FIBs completed by the controller
80590075Sobrien */
80690075Sobrienstatic void
80790075Sobrienaac_host_response(struct aac_softc *sc)
80890075Sobrien{
80990075Sobrien	struct aac_command *cm;
81090075Sobrien	struct aac_fib *fib;
81190075Sobrien	u_int32_t fib_size;
81290075Sobrien
81390075Sobrien	debug_called(2);
81490075Sobrien
81590075Sobrien	for (;;) {
81690075Sobrien		/* look for completed FIBs on our queue */
81790075Sobrien		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
81890075Sobrien				    &fib))
81990075Sobrien			break;	/* nothing to do */
82090075Sobrien
82190075Sobrien		/* get the command, unmap and queue for later processing */
82290075Sobrien		cm = (struct aac_command *)fib->Header.SenderData;
82390075Sobrien		if (cm == NULL) {
82490075Sobrien			AAC_PRINT_FIB(sc, fib);
82590075Sobrien		} else {
82690075Sobrien			aac_remove_busy(cm);
82790075Sobrien			aac_unmap_command(cm);		/* XXX defer? */
82890075Sobrien			aac_enqueue_complete(cm);
82990075Sobrien		}
83090075Sobrien	}
83190075Sobrien
83290075Sobrien	/* handle completion processing */
83390075Sobrien#if __FreeBSD_version >= 500005
83490075Sobrien	taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete);
83590075Sobrien#else
83690075Sobrien	aac_complete(sc, 0);
83790075Sobrien#endif
83890075Sobrien}
83990075Sobrien
84090075Sobrien/*
84190075Sobrien * Process completed commands.
84290075Sobrien */
84390075Sobrienstatic void
84490075Sobrienaac_complete(void *context, int pending)
84590075Sobrien{
84690075Sobrien	struct aac_softc *sc;
84790075Sobrien	struct aac_command *cm;
84890075Sobrien
84990075Sobrien	debug_called(2);
85090075Sobrien
85190075Sobrien	sc = (struct aac_softc *)context;
85290075Sobrien
85390075Sobrien	/* pull completed commands off the queue */
85490075Sobrien	for (;;) {
85590075Sobrien		cm = aac_dequeue_complete(sc);
85690075Sobrien		if (cm == NULL)
85790075Sobrien			break;
85890075Sobrien		cm->cm_flags |= AAC_CMD_COMPLETED;
85990075Sobrien
86090075Sobrien		/* is there a completion handler? */
86190075Sobrien		if (cm->cm_complete != NULL) {
86290075Sobrien			cm->cm_complete(cm);
86390075Sobrien		} else {
86490075Sobrien			/* assume that someone is sleeping on this command */
86590075Sobrien			wakeup(cm);
86690075Sobrien		}
86790075Sobrien	}
86890075Sobrien
86990075Sobrien	/* see if we can start some more I/O */
87090075Sobrien	aac_startio(sc);
87190075Sobrien}
87290075Sobrien
87390075Sobrien/*
87490075Sobrien * Handle a bio submitted from a disk device.
87590075Sobrien */
87690075Sobrienvoid
87790075Sobrienaac_submit_bio(struct bio *bp)
87890075Sobrien{
87990075Sobrien	struct aac_disk *ad;
88090075Sobrien	struct aac_softc *sc;
88190075Sobrien
88290075Sobrien	debug_called(2);
88390075Sobrien
88490075Sobrien	ad = (struct aac_disk *)bp->bio_dev->si_drv1;
88590075Sobrien	sc = ad->ad_controller;
88690075Sobrien
88790075Sobrien	/* queue the BIO and try to get some work done */
88890075Sobrien	aac_enqueue_bio(sc, bp);
88990075Sobrien	aac_startio(sc);
89090075Sobrien}
89190075Sobrien
89290075Sobrien/*
89390075Sobrien * Get a bio and build a command to go with it.
89490075Sobrien */
89590075Sobrienstatic int
89690075Sobrienaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
89790075Sobrien{
89890075Sobrien	struct aac_command *cm;
89990075Sobrien	struct aac_fib *fib;
90090075Sobrien	struct aac_blockread *br;
90190075Sobrien	struct aac_blockwrite *bw;
90290075Sobrien	struct aac_disk *ad;
90390075Sobrien	struct bio *bp;
90490075Sobrien
90590075Sobrien	debug_called(2);
90690075Sobrien
90790075Sobrien	/* get the resources we will need */
90890075Sobrien	cm = NULL;
90990075Sobrien	if ((bp = aac_dequeue_bio(sc)) == NULL)
91090075Sobrien		goto fail;
91190075Sobrien	if (aac_alloc_command(sc, &cm))	/* get a command */
91290075Sobrien		goto fail;
91390075Sobrien
91490075Sobrien	/* fill out the command */
91590075Sobrien	cm->cm_data = (void *)bp->bio_data;
91690075Sobrien	cm->cm_datalen = bp->bio_bcount;
91790075Sobrien	cm->cm_complete = aac_bio_complete;
91890075Sobrien	cm->cm_private = bp;
91990075Sobrien	cm->cm_timestamp = time_second;
92090075Sobrien	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
92190075Sobrien
92290075Sobrien	/* build the FIB */
92390075Sobrien	fib = cm->cm_fib;
92490075Sobrien	fib->Header.XferState =
92590075Sobrien	AAC_FIBSTATE_HOSTOWNED   |
92690075Sobrien	AAC_FIBSTATE_INITIALISED |
92790075Sobrien	AAC_FIBSTATE_FROMHOST	 |
92890075Sobrien	AAC_FIBSTATE_REXPECTED   |
92990075Sobrien	AAC_FIBSTATE_NORM;
93090075Sobrien	fib->Header.Command = ContainerCommand;
93190075Sobrien	fib->Header.Size = sizeof(struct aac_fib_header);
93290075Sobrien
93390075Sobrien	/* build the read/write request */
93490075Sobrien	ad = (struct aac_disk *)bp->bio_dev->si_drv1;
93590075Sobrien	if (BIO_IS_READ(bp)) {
93690075Sobrien		br = (struct aac_blockread *)&fib->data[0];
93790075Sobrien		br->Command = VM_CtBlockRead;
93890075Sobrien		br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
93990075Sobrien		br->BlockNumber = bp->bio_pblkno;
94090075Sobrien		br->ByteCount = bp->bio_bcount;
94190075Sobrien		fib->Header.Size += sizeof(struct aac_blockread);
94290075Sobrien		cm->cm_sgtable = &br->SgMap;
94390075Sobrien		cm->cm_flags |= AAC_CMD_DATAIN;
94490075Sobrien	} else {
94590075Sobrien		bw = (struct aac_blockwrite *)&fib->data[0];
94690075Sobrien		bw->Command = VM_CtBlockWrite;
94790075Sobrien		bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
94890075Sobrien		bw->BlockNumber = bp->bio_pblkno;
94990075Sobrien		bw->ByteCount = bp->bio_bcount;
95090075Sobrien		bw->Stable = CUNSTABLE;	/* XXX what's appropriate here? */
95190075Sobrien		fib->Header.Size += sizeof(struct aac_blockwrite);
95290075Sobrien		cm->cm_flags |= AAC_CMD_DATAOUT;
95390075Sobrien		cm->cm_sgtable = &bw->SgMap;
95490075Sobrien	}
95590075Sobrien
95690075Sobrien	*cmp = cm;
95790075Sobrien	return(0);
95890075Sobrien
95990075Sobrienfail:
96090075Sobrien	if (bp != NULL)
96190075Sobrien		aac_enqueue_bio(sc, bp);
96290075Sobrien	if (cm != NULL)
96390075Sobrien		aac_release_command(cm);
96490075Sobrien	return(ENOMEM);
96590075Sobrien}
96690075Sobrien
96790075Sobrien/*
96890075Sobrien * Handle a bio-instigated command that has been completed.
96990075Sobrien */
97090075Sobrienstatic void
97190075Sobrienaac_bio_complete(struct aac_command *cm)
97290075Sobrien{
97390075Sobrien	struct aac_blockread_response *brr;
97490075Sobrien	struct aac_blockwrite_response *bwr;
97590075Sobrien	struct bio *bp;
97690075Sobrien	AAC_FSAStatus status;
97790075Sobrien
97890075Sobrien	/* fetch relevant status and then release the command */
97990075Sobrien	bp = (struct bio *)cm->cm_private;
98090075Sobrien	if (BIO_IS_READ(bp)) {
98190075Sobrien		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
98290075Sobrien		status = brr->Status;
98390075Sobrien	} else {
98490075Sobrien		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
98590075Sobrien		status = bwr->Status;
98690075Sobrien	}
98790075Sobrien	aac_release_command(cm);
98890075Sobrien
98990075Sobrien	/* fix up the bio based on status */
99090075Sobrien	if (status == ST_OK) {
99190075Sobrien		bp->bio_resid = 0;
99290075Sobrien	} else {
99390075Sobrien		bp->bio_error = EIO;
99490075Sobrien		bp->bio_flags |= BIO_ERROR;
99590075Sobrien		/* pass an error string out to the disk layer */
99690075Sobrien		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
99790075Sobrien						    status);
99890075Sobrien	}
99990075Sobrien	aac_biodone(bp);
100090075Sobrien}
100190075Sobrien
100290075Sobrien/*
100390075Sobrien * Dump a block of data to the controller.  If the queue is full, tell the
100490075Sobrien * caller to hold off and wait for the queue to drain.
100590075Sobrien */
100690075Sobrienint
100790075Sobrienaac_dump_enqueue(struct aac_disk *ad, u_int32_t lba, void *data, int dumppages)
100890075Sobrien{
100990075Sobrien	struct aac_softc *sc;
101090075Sobrien	struct aac_command *cm;
101190075Sobrien	struct aac_fib *fib;
101290075Sobrien	struct aac_blockwrite *bw;
101390075Sobrien
101490075Sobrien	sc = ad->ad_controller;
101590075Sobrien	cm = NULL;
101690075Sobrien
101790075Sobrien	if (aac_alloc_command(sc, &cm))
101890075Sobrien		return (EBUSY);
101990075Sobrien
102090075Sobrien	/* fill out the command */
102190075Sobrien	cm->cm_data = data;
102290075Sobrien	cm->cm_datalen = dumppages * PAGE_SIZE;
102390075Sobrien	cm->cm_complete = NULL;
102490075Sobrien	cm->cm_private = NULL;
102590075Sobrien	cm->cm_timestamp = time_second;
102690075Sobrien	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
102790075Sobrien
102890075Sobrien	/* build the FIB */
102990075Sobrien	fib = cm->cm_fib;
103090075Sobrien	fib->Header.XferState =
103190075Sobrien	AAC_FIBSTATE_HOSTOWNED   |
103290075Sobrien	AAC_FIBSTATE_INITIALISED |
103390075Sobrien	AAC_FIBSTATE_FROMHOST	 |
103490075Sobrien	AAC_FIBSTATE_REXPECTED   |
103590075Sobrien	AAC_FIBSTATE_NORM;
103690075Sobrien	fib->Header.Command = ContainerCommand;
103790075Sobrien	fib->Header.Size = sizeof(struct aac_fib_header);
103890075Sobrien
103990075Sobrien	bw = (struct aac_blockwrite *)&fib->data[0];
104090075Sobrien	bw->Command = VM_CtBlockWrite;
104190075Sobrien	bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
104290075Sobrien	bw->BlockNumber = lba;
104390075Sobrien	bw->ByteCount = dumppages * PAGE_SIZE;
104490075Sobrien	bw->Stable = CUNSTABLE;		/* XXX what's appropriate here? */
104590075Sobrien	fib->Header.Size += sizeof(struct aac_blockwrite);
104690075Sobrien	cm->cm_flags |= AAC_CMD_DATAOUT;
104790075Sobrien	cm->cm_sgtable = &bw->SgMap;
104890075Sobrien
104990075Sobrien	return (aac_start(cm));
105090075Sobrien}
105190075Sobrien
105290075Sobrien/*
105390075Sobrien * Wait for the card's queue to drain when dumping.  Also check for monitor
105490075Sobrien * printf's
105590075Sobrien */
105690075Sobrienvoid
105790075Sobrienaac_dump_complete(struct aac_softc *sc)
105890075Sobrien{
105990075Sobrien	struct aac_fib *fib;
106090075Sobrien	struct aac_command *cm;
106190075Sobrien	u_int16_t reason;
106290075Sobrien	u_int32_t pi, ci, fib_size;
106390075Sobrien
106490075Sobrien	do {
106590075Sobrien		reason = AAC_GET_ISTATUS(sc);
106690075Sobrien		if (reason & AAC_DB_RESPONSE_READY) {
106790075Sobrien			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
106890075Sobrien			for (;;) {
106990075Sobrien				if (aac_dequeue_fib(sc,
107090075Sobrien						    AAC_HOST_NORM_RESP_QUEUE,
107190075Sobrien						    &fib_size, &fib))
107290075Sobrien					break;
107390075Sobrien				cm = (struct aac_command *)
107490075Sobrien					fib->Header.SenderData;
107590075Sobrien				if (cm == NULL)
107690075Sobrien					AAC_PRINT_FIB(sc, fib);
107790075Sobrien				else {
107890075Sobrien					aac_remove_busy(cm);
107990075Sobrien					aac_unmap_command(cm);
108090075Sobrien					aac_enqueue_complete(cm);
108190075Sobrien					aac_release_command(cm);
108290075Sobrien				}
108390075Sobrien			}
108490075Sobrien		}
108590075Sobrien		if (reason & AAC_DB_PRINTF) {
108690075Sobrien			AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
108790075Sobrien			aac_print_printf(sc);
108890075Sobrien		}
108990075Sobrien		pi = sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][
109090075Sobrien			AAC_PRODUCER_INDEX];
109190075Sobrien		ci = sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][
109290075Sobrien			AAC_CONSUMER_INDEX];
109390075Sobrien	} while (ci != pi);
109490075Sobrien
109590075Sobrien	return;
109690075Sobrien}
109790075Sobrien
109890075Sobrien/*
109990075Sobrien * Submit a command to the controller, return when it completes.
110090075Sobrien * XXX This is very dangerous!  If the card has gone out to lunch, we could
110190075Sobrien *     be stuck here forever.  At the same time, signals are not caught
110290075Sobrien *     because there is a risk that a signal could wakeup the tsleep before
110390075Sobrien *     the card has a chance to complete the command.  The passed in timeout
110490075Sobrien *     is ignored for the same reason.  Since there is no way to cancel a
110590075Sobrien *     command in progress, we should probably create a 'dead' queue where
110690075Sobrien *     commands go that have been interrupted/timed-out/etc, that keeps them
110790075Sobrien *     out of the free pool.  That way, if the card is just slow, it won't
110890075Sobrien *     spam the memory of a command that has been recycled.
110990075Sobrien */
111090075Sobrienstatic int
111190075Sobrienaac_wait_command(struct aac_command *cm, int timeout)
111290075Sobrien{
111390075Sobrien	int s, error = 0;
111490075Sobrien
111590075Sobrien	debug_called(2);
111690075Sobrien
111790075Sobrien	/* Put the command on the ready queue and get things going */
111890075Sobrien	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
111990075Sobrien	aac_enqueue_ready(cm);
112090075Sobrien	aac_startio(cm->cm_sc);
112190075Sobrien	s = splbio();
112290075Sobrien	while (!(cm->cm_flags & AAC_CMD_COMPLETED) && (error != EWOULDBLOCK)) {
112390075Sobrien		error = tsleep(cm, PRIBIO, "aacwait", 0);
112490075Sobrien	}
112590075Sobrien	splx(s);
112690075Sobrien	return(error);
112790075Sobrien}
112890075Sobrien
112990075Sobrien/*
113090075Sobrien *Command Buffer Management
113190075Sobrien */
113290075Sobrien
113390075Sobrien/*
113490075Sobrien * Allocate a command.
113590075Sobrien */
113690075Sobrienstatic int
113790075Sobrienaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
113890075Sobrien{
113990075Sobrien	struct aac_command *cm;
114090075Sobrien
114190075Sobrien	debug_called(3);
114290075Sobrien
114390075Sobrien	if ((cm = aac_dequeue_free(sc)) == NULL)
114490075Sobrien		return(ENOMEM);
114590075Sobrien
114690075Sobrien	*cmp = cm;
114790075Sobrien	return(0);
114890075Sobrien}
114990075Sobrien
115090075Sobrien/*
115190075Sobrien * Release a command back to the freelist.
115290075Sobrien */
115390075Sobrienstatic void
115490075Sobrienaac_release_command(struct aac_command *cm)
115590075Sobrien{
115690075Sobrien	debug_called(3);
115790075Sobrien
115890075Sobrien	/* (re)initialise the command/FIB */
115990075Sobrien	cm->cm_sgtable = NULL;
116090075Sobrien	cm->cm_flags = 0;
116190075Sobrien	cm->cm_complete = NULL;
116290075Sobrien	cm->cm_private = NULL;
116390075Sobrien	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
116490075Sobrien	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
116590075Sobrien	cm->cm_fib->Header.Flags = 0;
116690075Sobrien	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
116790075Sobrien
116890075Sobrien	/*
116990075Sobrien	 * These are duplicated in aac_start to cover the case where an
117090075Sobrien	 * intermediate stage may have destroyed them.  They're left
117190075Sobrien	 * initialised here for debugging purposes only.
117290075Sobrien	 */
117390075Sobrien	cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
117490075Sobrien	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
117590075Sobrien
117690075Sobrien	aac_enqueue_free(cm);
117790075Sobrien}
117890075Sobrien
117990075Sobrien/*
118090075Sobrien * Map helper for command/FIB allocation.
118190075Sobrien */
118290075Sobrienstatic void
118390075Sobrienaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
118490075Sobrien{
118590075Sobrien	struct aac_softc *sc;
118690075Sobrien
118790075Sobrien	sc = (struct aac_softc *)arg;
118890075Sobrien
118990075Sobrien	debug_called(3);
119090075Sobrien
119190075Sobrien	sc->aac_fibphys = segs[0].ds_addr;
119290075Sobrien}
119390075Sobrien
119490075Sobrien/*
119590075Sobrien * Allocate and initialise commands/FIBs for this adapter.
119690075Sobrien */
119790075Sobrienstatic int
119890075Sobrienaac_alloc_commands(struct aac_softc *sc)
119990075Sobrien{
120090075Sobrien	struct aac_command *cm;
120190075Sobrien	int i;
120290075Sobrien
120390075Sobrien	debug_called(1);
120490075Sobrien
120590075Sobrien	/* allocate the FIBs in DMAable memory and load them */
120690075Sobrien	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&sc->aac_fibs,
120790075Sobrien			 BUS_DMA_NOWAIT, &sc->aac_fibmap)) {
120890075Sobrien		return(ENOMEM);
120990075Sobrien	}
121090075Sobrien	bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
121190075Sobrien			AAC_FIB_COUNT * sizeof(struct aac_fib),
121290075Sobrien			aac_map_command_helper, sc, 0);
121390075Sobrien
121490075Sobrien	/* initialise constant fields in the command structure */
121590075Sobrien	for (i = 0; i < AAC_FIB_COUNT; i++) {
121690075Sobrien		cm = &sc->aac_command[i];
121790075Sobrien		cm->cm_sc = sc;
121890075Sobrien		cm->cm_fib = sc->aac_fibs + i;
121990075Sobrien		cm->cm_fibphys = sc->aac_fibphys + (i * sizeof(struct aac_fib));
122090075Sobrien
122190075Sobrien		if (!bus_dmamap_create(sc->aac_buffer_dmat, 0, &cm->cm_datamap))
122290075Sobrien			aac_release_command(cm);
122390075Sobrien	}
122490075Sobrien	return(0);
122590075Sobrien}
122690075Sobrien
122790075Sobrien/*
122890075Sobrien * Free FIBs owned by this adapter.
122990075Sobrien */
123090075Sobrienstatic void
123190075Sobrienaac_free_commands(struct aac_softc *sc)
123290075Sobrien{
123390075Sobrien	int i;
123490075Sobrien
123590075Sobrien	debug_called(1);
123690075Sobrien
123790075Sobrien	for (i = 0; i < AAC_FIB_COUNT; i++)
123890075Sobrien		bus_dmamap_destroy(sc->aac_buffer_dmat,
123990075Sobrien				   sc->aac_command[i].cm_datamap);
124090075Sobrien
124190075Sobrien	bus_dmamap_unload(sc->aac_fib_dmat, sc->aac_fibmap);
124290075Sobrien	bus_dmamem_free(sc->aac_fib_dmat, sc->aac_fibs, sc->aac_fibmap);
124390075Sobrien}
124490075Sobrien
124590075Sobrien/*
124690075Sobrien * Command-mapping helper function - populate this command's s/g table.
124790075Sobrien */
124890075Sobrienstatic void
124990075Sobrienaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
125090075Sobrien{
125190075Sobrien	struct aac_command *cm;
125290075Sobrien	struct aac_fib *fib;
125390075Sobrien	struct aac_sg_table *sg;
125490075Sobrien	int i;
125590075Sobrien
125690075Sobrien	debug_called(3);
125790075Sobrien
125890075Sobrien	cm = (struct aac_command *)arg;
125990075Sobrien	fib = cm->cm_fib;
126090075Sobrien
126190075Sobrien	/* find the s/g table */
126290075Sobrien	sg = cm->cm_sgtable;
126390075Sobrien
126490075Sobrien	/* copy into the FIB */
126590075Sobrien	if (sg != NULL) {
126690075Sobrien		sg->SgCount = nseg;
126790075Sobrien		for (i = 0; i < nseg; i++) {
126890075Sobrien			sg->SgEntry[i].SgAddress = segs[i].ds_addr;
126990075Sobrien			sg->SgEntry[i].SgByteCount = segs[i].ds_len;
127090075Sobrien		}
127190075Sobrien		/* update the FIB size for the s/g count */
127290075Sobrien		fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
127390075Sobrien	}
127490075Sobrien
127590075Sobrien}
127690075Sobrien
127790075Sobrien/*
127890075Sobrien * Map a command into controller-visible space.
127990075Sobrien */
128090075Sobrienstatic void
128190075Sobrienaac_map_command(struct aac_command *cm)
128290075Sobrien{
128390075Sobrien	struct aac_softc *sc;
128490075Sobrien
128590075Sobrien	debug_called(2);
128690075Sobrien
128790075Sobrien	sc = cm->cm_sc;
128890075Sobrien
128990075Sobrien	/* don't map more than once */
129090075Sobrien	if (cm->cm_flags & AAC_CMD_MAPPED)
129190075Sobrien		return;
129290075Sobrien
129390075Sobrien	if (cm->cm_datalen != 0) {
129490075Sobrien		bus_dmamap_load(sc->aac_buffer_dmat, cm->cm_datamap,
129590075Sobrien				cm->cm_data, cm->cm_datalen,
129690075Sobrien				aac_map_command_sg, cm, 0);
129790075Sobrien
129890075Sobrien	if (cm->cm_flags & AAC_CMD_DATAIN)
129990075Sobrien		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
130090075Sobrien				BUS_DMASYNC_PREREAD);
130190075Sobrien	if (cm->cm_flags & AAC_CMD_DATAOUT)
130290075Sobrien		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
130390075Sobrien				BUS_DMASYNC_PREWRITE);
130490075Sobrien	}
130590075Sobrien	cm->cm_flags |= AAC_CMD_MAPPED;
130690075Sobrien}
130790075Sobrien
130890075Sobrien/*
130990075Sobrien * Unmap a command from controller-visible space.
131090075Sobrien */
131152284Sobrienstatic void
131252284Sobrienaac_unmap_command(struct aac_command *cm)
131352284Sobrien{
131452284Sobrien	struct aac_softc *sc;
131590075Sobrien
131690075Sobrien	debug_called(2);
131790075Sobrien
131890075Sobrien	sc = cm->cm_sc;
131990075Sobrien
132090075Sobrien	if (!(cm->cm_flags & AAC_CMD_MAPPED))
132190075Sobrien		return;
132252284Sobrien
132390075Sobrien	if (cm->cm_datalen != 0) {
132452284Sobrien		if (cm->cm_flags & AAC_CMD_DATAIN)
132590075Sobrien			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
132690075Sobrien					BUS_DMASYNC_POSTREAD);
132790075Sobrien		if (cm->cm_flags & AAC_CMD_DATAOUT)
132890075Sobrien			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
132990075Sobrien					BUS_DMASYNC_POSTWRITE);
133090075Sobrien
133190075Sobrien		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
133290075Sobrien	}
133390075Sobrien	cm->cm_flags &= ~AAC_CMD_MAPPED;
133490075Sobrien}
133590075Sobrien
133690075Sobrien/*
133790075Sobrien * Hardware Interface
133890075Sobrien */
133990075Sobrien
134090075Sobrien/*
134190075Sobrien * Initialise the adapter.
134290075Sobrien */
134390075Sobrienstatic void
134490075Sobrienaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
134590075Sobrien{
134690075Sobrien	struct aac_softc *sc;
134790075Sobrien
134890075Sobrien	debug_called(1);
134990075Sobrien
135090075Sobrien	sc = (struct aac_softc *)arg;
135190075Sobrien
135290075Sobrien	sc->aac_common_busaddr = segs[0].ds_addr;
135390075Sobrien}
135452284Sobrien
135552284Sobrien/*
135652284Sobrien * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
135752284Sobrien * firmware version 1.x are not compatible with this driver.
135852284Sobrien */
135952284Sobrienstatic int
136052284Sobrienaac_check_firmware(struct aac_softc *sc)
136152284Sobrien{
136290075Sobrien	u_int32_t major, minor;
136352284Sobrien
136490075Sobrien	debug_called(1);
136590075Sobrien
136690075Sobrien	if (sc->quirks & AAC_QUIRK_PERC2QC) {
136752284Sobrien		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
136852284Sobrien				     NULL)) {
136952284Sobrien			device_printf(sc->aac_dev,
137090075Sobrien				      "Error reading firmware version\n");
137190075Sobrien			return (EIO);
137290075Sobrien		}
137352284Sobrien
137452284Sobrien		/* These numbers are stored as ASCII! */
137552284Sobrien		major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30;
137652284Sobrien		minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30;
137752284Sobrien		if (major == 1) {
137852284Sobrien			device_printf(sc->aac_dev,
137952284Sobrien			    "Firmware version %d.%d is not supported.\n",
138052284Sobrien			    major, minor);
138152284Sobrien			return (EINVAL);
138252284Sobrien		}
138390075Sobrien	}
138490075Sobrien
138552284Sobrien	return (0);
138652284Sobrien}
138790075Sobrien
138890075Sobrienstatic int
138990075Sobrienaac_init(struct aac_softc *sc)
139090075Sobrien{
139190075Sobrien	struct aac_adapter_init	*ip;
139252284Sobrien	time_t then;
139390075Sobrien	u_int32_t code;
139490075Sobrien	u_int8_t *qaddr;
139590075Sobrien
139690075Sobrien	debug_called(1);
139790075Sobrien
139890075Sobrien	/*
139990075Sobrien	 * First wait for the adapter to come ready.
140090075Sobrien	 */
140190075Sobrien	then = time_second;
140252284Sobrien	do {
140390075Sobrien		code = AAC_GET_FWSTATUS(sc);
140490075Sobrien		if (code & AAC_SELF_TEST_FAILED) {
140590075Sobrien			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
140690075Sobrien			return(ENXIO);
140790075Sobrien		}
140890075Sobrien		if (code & AAC_KERNEL_PANIC) {
140990075Sobrien			device_printf(sc->aac_dev,
141090075Sobrien				      "FATAL: controller kernel panic\n");
141190075Sobrien			return(ENXIO);
141290075Sobrien		}
141390075Sobrien		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
141490075Sobrien			device_printf(sc->aac_dev,
141552284Sobrien				      "FATAL: controller not coming ready, "
141652284Sobrien					   "status %x\n", code);
141790075Sobrien			return(ENXIO);
141890075Sobrien		}
141990075Sobrien	} while (!(code & AAC_UP_AND_RUNNING));
142090075Sobrien
142190075Sobrien	/*
142290075Sobrien	 * Create DMA tag for the common structure and allocate it.
142390075Sobrien	 */
142490075Sobrien	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
142590075Sobrien			       1, 0, 			/* algnmnt, boundary */
142652284Sobrien			       BUS_SPACE_MAXADDR,	/* lowaddr */
142790075Sobrien			       BUS_SPACE_MAXADDR, 	/* highaddr */
142890075Sobrien			       NULL, NULL, 		/* filter, filterarg */
142990075Sobrien			       sizeof(struct aac_common), /* maxsize */
143090075Sobrien			       1,			/* nsegments */
143190075Sobrien			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
143290075Sobrien			       0,			/* flags */
143352284Sobrien			       &sc->aac_common_dmat)) {
143490075Sobrien		device_printf(sc->aac_dev,
143590075Sobrien			      "can't allocate common structure DMA tag\n");
143690075Sobrien		return(ENOMEM);
143790075Sobrien	}
143852284Sobrien	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
143990075Sobrien			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
144090075Sobrien		device_printf(sc->aac_dev, "can't allocate common structure\n");
144190075Sobrien		return(ENOMEM);
144290075Sobrien	}
144390075Sobrien	bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
144490075Sobrien			sc->aac_common, sizeof(*sc->aac_common), aac_common_map,
144590075Sobrien		        sc, 0);
144690075Sobrien	bzero(sc->aac_common, sizeof(*sc->aac_common));
144790075Sobrien
144890075Sobrien	/*
144990075Sobrien	 * Fill in the init structure.  This tells the adapter about the
145090075Sobrien	 * physical location of various important shared data structures.
145190075Sobrien	 */
145252284Sobrien	ip = &sc->aac_common->ac_init;
145390075Sobrien	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
145452284Sobrien
145552284Sobrien	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
145652284Sobrien					 offsetof(struct aac_common, ac_fibs);
145752284Sobrien	ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
145852284Sobrien	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
145952284Sobrien	ip->AdapterFibAlign = sizeof(struct aac_fib);
146052284Sobrien
146152284Sobrien	ip->PrintfBufferAddress = sc->aac_common_busaddr +
146252284Sobrien				  offsetof(struct aac_common, ac_printf);
146390075Sobrien	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
146452284Sobrien
146552284Sobrien	ip->HostPhysMemPages = 0;		/* not used? */
146690075Sobrien	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
146752284Sobrien
146890075Sobrien	/*
146952284Sobrien	 * Initialise FIB queues.  Note that it appears that the layout of the
147052284Sobrien	 * indexes and the segmentation of the entries may be mandated by the
147190075Sobrien	 * adapter, which is only told about the base of the queue index fields.
147290075Sobrien	 *
147390075Sobrien	 * The initial values of the indices are assumed to inform the adapter
147452284Sobrien	 * of the sizes of the respective queues, and theoretically it could
147552284Sobrien	 * work out the entire layout of the queue structures from this.  We
147690075Sobrien	 * take the easy route and just lay this area out like everyone else
147790075Sobrien	 * does.
147890075Sobrien	 *
147990075Sobrien	 * The Linux driver uses a much more complex scheme whereby several
148090075Sobrien	 * header records are kept for each queue.  We use a couple of generic
148190075Sobrien	 * list manipulation functions which 'know' the size of each list by
148290075Sobrien	 * virtue of a table.
148390075Sobrien	 */
148490075Sobrien	qaddr = &sc->aac_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
148590075Sobrien	qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN;
148690075Sobrien	sc->aac_queues = (struct aac_queue_table *)qaddr;
148790075Sobrien	ip->CommHeaderAddress = sc->aac_common_busaddr +
148890075Sobrien				((u_int32_t)sc->aac_queues -
148990075Sobrien				(u_int32_t)sc->aac_common);
149090075Sobrien	bzero(sc->aac_queues, sizeof(struct aac_queue_table));
149152284Sobrien
149252284Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
149352284Sobrien		AAC_HOST_NORM_CMD_ENTRIES;
149452284Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
149590075Sobrien		AAC_HOST_NORM_CMD_ENTRIES;
149652284Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
149752284Sobrien		AAC_HOST_HIGH_CMD_ENTRIES;
149852284Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
149952284Sobrien		AAC_HOST_HIGH_CMD_ENTRIES;
150052284Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
150152284Sobrien		AAC_ADAP_NORM_CMD_ENTRIES;
150252284Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
150352284Sobrien		AAC_ADAP_NORM_CMD_ENTRIES;
150490075Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
150552284Sobrien		AAC_ADAP_HIGH_CMD_ENTRIES;
150652284Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
150752284Sobrien		AAC_ADAP_HIGH_CMD_ENTRIES;
150890075Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
150990075Sobrien		AAC_HOST_NORM_RESP_ENTRIES;
151090075Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
151190075Sobrien		AAC_HOST_NORM_RESP_ENTRIES;
151290075Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
151390075Sobrien		AAC_HOST_HIGH_RESP_ENTRIES;
151490075Sobrien	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
151590075Sobrien		AAC_HOST_HIGH_RESP_ENTRIES;
151690075Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
151790075Sobrien		AAC_ADAP_NORM_RESP_ENTRIES;
151890075Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
151990075Sobrien		AAC_ADAP_NORM_RESP_ENTRIES;
152090075Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
152190075Sobrien		AAC_ADAP_HIGH_RESP_ENTRIES;
152290075Sobrien	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
152390075Sobrien		AAC_ADAP_HIGH_RESP_ENTRIES;
152490075Sobrien	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
152590075Sobrien		&sc->aac_queues->qt_HostNormCmdQueue[0];
152690075Sobrien	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
152790075Sobrien		&sc->aac_queues->qt_HostHighCmdQueue[0];
152890075Sobrien	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
152990075Sobrien		&sc->aac_queues->qt_AdapNormCmdQueue[0];
153090075Sobrien	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
153190075Sobrien		&sc->aac_queues->qt_AdapHighCmdQueue[0];
153290075Sobrien	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
153390075Sobrien		&sc->aac_queues->qt_HostNormRespQueue[0];
153490075Sobrien	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
153590075Sobrien		&sc->aac_queues->qt_HostHighRespQueue[0];
153690075Sobrien	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
153752284Sobrien		&sc->aac_queues->qt_AdapNormRespQueue[0];
153852284Sobrien	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
153990075Sobrien		&sc->aac_queues->qt_AdapHighRespQueue[0];
154090075Sobrien
154152284Sobrien	/*
154290075Sobrien	 * Do controller-type-specific initialisation
154352284Sobrien	 */
154452284Sobrien	switch (sc->aac_hwif) {
154590075Sobrien	case AAC_HWIF_I960RX:
154690075Sobrien		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
154790075Sobrien		break;
154890075Sobrien	}
154990075Sobrien
155090075Sobrien	/*
155190075Sobrien	 * Give the init structure to the controller.
155290075Sobrien	 */
155390075Sobrien	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
155490075Sobrien			     sc->aac_common_busaddr +
155590075Sobrien			     offsetof(struct aac_common, ac_init), 0, 0, 0,
155690075Sobrien			     NULL)) {
155790075Sobrien		device_printf(sc->aac_dev,
155890075Sobrien			      "error establishing init structure\n");
155990075Sobrien		return(EIO);
156090075Sobrien	}
156190075Sobrien
156290075Sobrien	return(0);
156390075Sobrien}
156490075Sobrien
156590075Sobrien/*
156690075Sobrien * Send a synchronous command to the controller and wait for a result.
156790075Sobrien */
156890075Sobrienstatic int
156990075Sobrienaac_sync_command(struct aac_softc *sc, u_int32_t command,
157090075Sobrien		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
157190075Sobrien		 u_int32_t *sp)
157290075Sobrien{
157390075Sobrien	time_t then;
157490075Sobrien	u_int32_t status;
157552284Sobrien
157690075Sobrien	debug_called(3);
157790075Sobrien
157852284Sobrien	/* populate the mailbox */
157990075Sobrien	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
158052284Sobrien
158152284Sobrien	/* ensure the sync command doorbell flag is cleared */
158252284Sobrien	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
158390075Sobrien
158452284Sobrien	/* then set it to signal the adapter */
158552284Sobrien	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
158652284Sobrien
158790075Sobrien	/* spin waiting for the command to complete */
158890075Sobrien	then = time_second;
158990075Sobrien	do {
159090075Sobrien		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
159190075Sobrien			debug(2, "timed out");
159290075Sobrien			return(EIO);
159390075Sobrien		}
159490075Sobrien	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
159590075Sobrien
159690075Sobrien	/* clear the completion flag */
159790075Sobrien	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
159890075Sobrien
159990075Sobrien	/* get the command status */
160090075Sobrien	status = AAC_GET_MAILBOXSTATUS(sc);
160190075Sobrien	if (sp != NULL)
160290075Sobrien		*sp = status;
160390075Sobrien	return(0);
160490075Sobrien}
160590075Sobrien
160690075Sobrien/*
160790075Sobrien * Send a synchronous FIB to the controller and wait for a result.
160890075Sobrien */
160952284Sobrienstatic int
161052284Sobrienaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
161190075Sobrien		 void *data, u_int16_t datasize,
161290075Sobrien		 void *result, u_int16_t *resultsize)
161352284Sobrien{
161452284Sobrien	struct aac_fib *fib;
161590075Sobrien
161652284Sobrien	debug_called(3);
161752284Sobrien
161852284Sobrien	fib = &sc->aac_common->ac_sync_fib;
161952284Sobrien
162052284Sobrien	if (datasize > AAC_FIB_DATASIZE)
162152284Sobrien		return(EINVAL);
162252284Sobrien
162352284Sobrien	/*
162490075Sobrien	 * Set up the sync FIB
162590075Sobrien	 */
162690075Sobrien	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
162752284Sobrien				AAC_FIBSTATE_INITIALISED |
162890075Sobrien				AAC_FIBSTATE_EMPTY;
162990075Sobrien	fib->Header.XferState |= xferstate;
163090075Sobrien	fib->Header.Command = command;
163190075Sobrien	fib->Header.StructType = AAC_FIBTYPE_TFIB;
163290075Sobrien	fib->Header.Size = sizeof(struct aac_fib) + datasize;
163352284Sobrien	fib->Header.SenderSize = sizeof(struct aac_fib);
163490075Sobrien	fib->Header.SenderFibAddress = (u_int32_t)fib;
163590075Sobrien	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
163652284Sobrien					 offsetof(struct aac_common,
163790075Sobrien						  ac_sync_fib);
163852284Sobrien
163990075Sobrien	/*
164090075Sobrien	 * Copy in data.
164190075Sobrien	 */
164290075Sobrien	if (data != NULL) {
164390075Sobrien		KASSERT(datasize <= sizeof(fib->data),
164490075Sobrien			("aac_sync_fib: datasize to large"));
164590075Sobrien		bcopy(data, fib->data, datasize);
164690075Sobrien		fib->Header.XferState |= AAC_FIBSTATE_FROMHOST |
164790075Sobrien					 AAC_FIBSTATE_NORM;
164890075Sobrien	}
164990075Sobrien
165090075Sobrien	/*
165190075Sobrien	 * Give the FIB to the controller, wait for a response.
165290075Sobrien	 */
165390075Sobrien	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
165490075Sobrien			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
165590075Sobrien		debug(2, "IO error");
165690075Sobrien		return(EIO);
165790075Sobrien	}
165890075Sobrien
165990075Sobrien	/*
166090075Sobrien	 * Copy out the result
166190075Sobrien	 */
166290075Sobrien	if (result != NULL) {
166390075Sobrien		u_int copysize;
166490075Sobrien
166590075Sobrien		copysize = fib->Header.Size - sizeof(struct aac_fib_header);
166690075Sobrien		if (copysize > *resultsize)
166790075Sobrien			copysize = *resultsize;
166890075Sobrien		*resultsize = fib->Header.Size - sizeof(struct aac_fib_header);
166990075Sobrien		bcopy(fib->data, result, copysize);
167090075Sobrien	}
167190075Sobrien	return(0);
167290075Sobrien}
167390075Sobrien
167490075Sobrien/*
167552284Sobrien * Adapter-space FIB queue manipulation
167652284Sobrien *
167752284Sobrien * Note that the queue implementation here is a little funky; neither the PI or
167890075Sobrien * CI will ever be zero.  This behaviour is a controller feature.
167952284Sobrien */
168052284Sobrienstatic struct {
168152284Sobrien	int		size;
168252284Sobrien	int		notify;
168352284Sobrien} aac_qinfo[] = {
168452284Sobrien	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
168552284Sobrien	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
168652284Sobrien	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
168752284Sobrien	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
168852284Sobrien	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
168990075Sobrien	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
169090075Sobrien	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
169190075Sobrien	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
169252284Sobrien};
1693
1694/*
1695 * Atomically insert an entry into the nominated queue, returns 0 on success or
1696 * EBUSY if the queue is full.
1697 *
1698 * Note: it would be more efficient to defer notifying the controller in
1699 *	 the case where we may be inserting several entries in rapid succession,
1700 *	 but implementing this usefully may be difficult (it would involve a
1701 *	 separate queue/notify interface).
1702 */
1703static int
1704aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
1705{
1706	u_int32_t pi, ci;
1707	int s, error;
1708	u_int32_t fib_size;
1709	u_int32_t fib_addr;
1710
1711	debug_called(3);
1712
1713	fib_size = cm->cm_fib->Header.Size;
1714	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
1715
1716	s = splbio();
1717
1718	/* get the producer/consumer indices */
1719	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
1720	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
1721
1722	/* wrap the queue? */
1723	if (pi >= aac_qinfo[queue].size)
1724		pi = 0;
1725
1726	/* check for queue full */
1727	if ((pi + 1) == ci) {
1728		error = EBUSY;
1729		goto out;
1730	}
1731
1732	/* populate queue entry */
1733	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
1734	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
1735
1736	/* update producer index */
1737	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
1738
1739	/*
1740	 * To avoid a race with its completion interrupt, place this command on
1741	 * the busy queue prior to advertising it to the controller.
1742	 */
1743	aac_enqueue_busy(cm);
1744
1745	/* notify the adapter if we know how */
1746	if (aac_qinfo[queue].notify != 0)
1747		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1748
1749	error = 0;
1750
1751out:
1752	splx(s);
1753	return(error);
1754}
1755
1756/*
1757 * Atomically remove one entry from the nominated queue, returns 0 on
1758 * success or ENOENT if the queue is empty.
1759 */
1760static int
1761aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1762		struct aac_fib **fib_addr)
1763{
1764	u_int32_t pi, ci;
1765	int s, error;
1766	int notify;
1767
1768	debug_called(3);
1769
1770	s = splbio();
1771
1772	/* get the producer/consumer indices */
1773	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
1774	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
1775
1776	/* check for queue empty */
1777	if (ci == pi) {
1778		error = ENOENT;
1779		goto out;
1780	}
1781
1782	notify = 0;
1783	if (ci == pi + 1)
1784		notify++;
1785
1786	/* wrap the queue? */
1787	if (ci >= aac_qinfo[queue].size)
1788		ci = 0;
1789
1790	/* fetch the entry */
1791	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
1792	*fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] +
1793				       ci)->aq_fib_addr;
1794
1795	/* update consumer index */
1796	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
1797
1798	/* if we have made the queue un-full, notify the adapter */
1799	if (notify && (aac_qinfo[queue].notify != 0))
1800		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1801	error = 0;
1802
1803out:
1804	splx(s);
1805	return(error);
1806}
1807
1808/*
1809 * Put our response to an Adapter Initialed Fib on the response queue
1810 */
1811static int
1812aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
1813{
1814	u_int32_t pi, ci;
1815	int s, error;
1816	u_int32_t fib_size;
1817	u_int32_t fib_addr;
1818
1819	debug_called(1);
1820
1821	/* Tell the adapter where the FIB is */
1822	fib_size = fib->Header.Size;
1823	fib_addr = fib->Header.SenderFibAddress;
1824	fib->Header.ReceiverFibAddress = fib_addr;
1825
1826	s = splbio();
1827
1828	/* get the producer/consumer indices */
1829	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
1830	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
1831
1832	/* wrap the queue? */
1833	if (pi >= aac_qinfo[queue].size)
1834		pi = 0;
1835
1836	/* check for queue full */
1837	if ((pi + 1) == ci) {
1838		error = EBUSY;
1839		goto out;
1840	}
1841
1842	/* populate queue entry */
1843	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
1844	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
1845
1846	/* update producer index */
1847	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
1848
1849	/* notify the adapter if we know how */
1850	if (aac_qinfo[queue].notify != 0)
1851		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1852
1853	error = 0;
1854
1855out:
1856	splx(s);
1857	return(error);
1858}
1859
1860/*
1861 * Check for commands that have been outstanding for a suspiciously long time,
1862 * and complain about them.
1863 */
1864static void
1865aac_timeout(struct aac_softc *sc)
1866{
1867	int s;
1868	struct aac_command *cm;
1869	time_t deadline;
1870
1871#if 0
1872	/* simulate an interrupt to handle possibly-missed interrupts */
1873	/*
1874	 * XXX This was done to work around another bug which has since been
1875	 * fixed.  It is dangerous anyways because you don't want multiple
1876	 * threads in the interrupt handler at the same time!  If calling
1877	 * is deamed neccesary in the future, proper mutexes must be used.
1878	 */
1879	s = splbio();
1880	aac_intr(sc);
1881	splx(s);
1882
1883	/* kick the I/O queue to restart it in the case of deadlock */
1884	aac_startio(sc);
1885#endif
1886
1887	/*
1888	 * traverse the busy command list, bitch about late commands once
1889	 * only.
1890	 */
1891	deadline = time_second - AAC_CMD_TIMEOUT;
1892	s = splbio();
1893	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
1894		if ((cm->cm_timestamp  < deadline)
1895			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
1896			cm->cm_flags |= AAC_CMD_TIMEDOUT;
1897			device_printf(sc->aac_dev,
1898				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
1899				      cm, (int)(time_second-cm->cm_timestamp));
1900			AAC_PRINT_FIB(sc, cm->cm_fib);
1901		}
1902	}
1903	splx(s);
1904
1905	/* reset the timer for next time */
1906	timeout((timeout_t*)aac_timeout, sc, AAC_PERIODIC_INTERVAL * hz);
1907	return;
1908}
1909
1910/*
1911 * Interface Function Vectors
1912 */
1913
1914/*
1915 * Read the current firmware status word.
1916 */
1917static int
1918aac_sa_get_fwstatus(struct aac_softc *sc)
1919{
1920	debug_called(3);
1921
1922	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
1923}
1924
1925static int
1926aac_rx_get_fwstatus(struct aac_softc *sc)
1927{
1928	debug_called(3);
1929
1930	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
1931}
1932
1933static int
1934aac_fa_get_fwstatus(struct aac_softc *sc)
1935{
1936	int val;
1937
1938	debug_called(3);
1939
1940	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
1941	return (val);
1942}
1943
1944/*
1945 * Notify the controller of a change in a given queue
1946 */
1947
1948static void
1949aac_sa_qnotify(struct aac_softc *sc, int qbit)
1950{
1951	debug_called(3);
1952
1953	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
1954}
1955
1956static void
1957aac_rx_qnotify(struct aac_softc *sc, int qbit)
1958{
1959	debug_called(3);
1960
1961	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
1962}
1963
1964static void
1965aac_fa_qnotify(struct aac_softc *sc, int qbit)
1966{
1967	debug_called(3);
1968
1969	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
1970	AAC_FA_HACK(sc);
1971}
1972
1973/*
1974 * Get the interrupt reason bits
1975 */
1976static int
1977aac_sa_get_istatus(struct aac_softc *sc)
1978{
1979	debug_called(3);
1980
1981	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
1982}
1983
1984static int
1985aac_rx_get_istatus(struct aac_softc *sc)
1986{
1987	debug_called(3);
1988
1989	return(AAC_GETREG4(sc, AAC_RX_ODBR));
1990}
1991
1992static int
1993aac_fa_get_istatus(struct aac_softc *sc)
1994{
1995	int val;
1996
1997	debug_called(3);
1998
1999	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
2000	return (val);
2001}
2002
2003/*
2004 * Clear some interrupt reason bits
2005 */
2006static void
2007aac_sa_clear_istatus(struct aac_softc *sc, int mask)
2008{
2009	debug_called(3);
2010
2011	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
2012}
2013
2014static void
2015aac_rx_clear_istatus(struct aac_softc *sc, int mask)
2016{
2017	debug_called(3);
2018
2019	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
2020}
2021
2022static void
2023aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2024{
2025	debug_called(3);
2026
2027	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2028	AAC_FA_HACK(sc);
2029}
2030
2031/*
2032 * Populate the mailbox and set the command word
2033 */
2034static void
2035aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2036		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2037{
2038	debug_called(4);
2039
2040	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
2041	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2042	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2043	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2044	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
2045}
2046
2047static void
2048aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
2049		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2050{
2051	debug_called(4);
2052
2053	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
2054	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2055	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2056	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2057	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
2058}
2059
2060static void
2061aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2062		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2063{
2064	debug_called(4);
2065
2066	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
2067	AAC_FA_HACK(sc);
2068	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2069	AAC_FA_HACK(sc);
2070	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2071	AAC_FA_HACK(sc);
2072	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2073	AAC_FA_HACK(sc);
2074	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2075	AAC_FA_HACK(sc);
2076}
2077
2078/*
2079 * Fetch the immediate command status word
2080 */
2081static int
2082aac_sa_get_mailboxstatus(struct aac_softc *sc)
2083{
2084	debug_called(4);
2085
2086	return(AAC_GETREG4(sc, AAC_SA_MAILBOX));
2087}
2088
2089static int
2090aac_rx_get_mailboxstatus(struct aac_softc *sc)
2091{
2092	debug_called(4);
2093
2094	return(AAC_GETREG4(sc, AAC_RX_MAILBOX));
2095}
2096
2097static int
2098aac_fa_get_mailboxstatus(struct aac_softc *sc)
2099{
2100	int val;
2101
2102	debug_called(4);
2103
2104	val = AAC_GETREG4(sc, AAC_FA_MAILBOX);
2105	return (val);
2106}
2107
2108/*
2109 * Set/clear interrupt masks
2110 */
2111static void
2112aac_sa_set_interrupts(struct aac_softc *sc, int enable)
2113{
2114	debug(2, "%sable interrupts", enable ? "en" : "dis");
2115
2116	if (enable) {
2117		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2118	} else {
2119		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
2120	}
2121}
2122
2123static void
2124aac_rx_set_interrupts(struct aac_softc *sc, int enable)
2125{
2126	debug(2, "%sable interrupts", enable ? "en" : "dis");
2127
2128	if (enable) {
2129		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
2130	} else {
2131		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
2132	}
2133}
2134
2135static void
2136aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2137{
2138	debug(2, "%sable interrupts", enable ? "en" : "dis");
2139
2140	if (enable) {
2141		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2142		AAC_FA_HACK(sc);
2143	} else {
2144		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
2145		AAC_FA_HACK(sc);
2146	}
2147}
2148
2149/*
2150 * Debugging and Diagnostics
2151 */
2152
2153/*
2154 * Print some information about the controller.
2155 */
2156static void
2157aac_describe_controller(struct aac_softc *sc)
2158{
2159	u_int8_t buf[AAC_FIB_DATASIZE];	/* XXX really a bit big
2160					 * for the stack */
2161	u_int16_t bufsize;
2162	struct aac_adapter_info	*info;
2163	u_int8_t arg;
2164
2165	debug_called(2);
2166
2167	arg = 0;
2168	bufsize = sizeof(buf);
2169	if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf,
2170			 &bufsize)) {
2171		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2172		return;
2173	}
2174	if (bufsize != sizeof(*info)) {
2175		device_printf(sc->aac_dev,
2176			      "RequestAdapterInfo returned wrong data size "
2177			      "(%d != %d)\n", bufsize, sizeof(*info));
2178		/*return;*/
2179	}
2180	info = (struct aac_adapter_info *)&buf[0];
2181
2182	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
2183		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
2184		      info->ClockSpeed, info->BufferMem / (1024 * 1024),
2185		      aac_describe_code(aac_battery_platform,
2186					info->batteryPlatform));
2187
2188	/* save the kernel revision structure for later use */
2189	sc->aac_revision = info->KernelRevision;
2190	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2191		      info->KernelRevision.external.comp.major,
2192		      info->KernelRevision.external.comp.minor,
2193		      info->KernelRevision.external.comp.dash,
2194		      info->KernelRevision.buildNumber,
2195		      (u_int32_t)(info->SerialNumber & 0xffffff));
2196}
2197
2198/*
2199 * Look up a text description of a numeric error code and return a pointer to
2200 * same.
2201 */
2202static char *
2203aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
2204{
2205	int i;
2206
2207	for (i = 0; table[i].string != NULL; i++)
2208		if (table[i].code == code)
2209			return(table[i].string);
2210	return(table[i + 1].string);
2211}
2212
2213/*
2214 * Management Interface
2215 */
2216
2217static int
2218aac_open(dev_t dev, int flags, int fmt, d_thread_t *td)
2219{
2220	struct aac_softc *sc;
2221
2222	debug_called(2);
2223
2224	sc = dev->si_drv1;
2225
2226	/* Check to make sure the device isn't already open */
2227	if (sc->aac_state & AAC_STATE_OPEN) {
2228		return EBUSY;
2229	}
2230	sc->aac_state |= AAC_STATE_OPEN;
2231
2232	return 0;
2233}
2234
2235static int
2236aac_close(dev_t dev, int flags, int fmt, d_thread_t *td)
2237{
2238	struct aac_softc *sc;
2239
2240	debug_called(2);
2241
2242	sc = dev->si_drv1;
2243
2244	/* Mark this unit as no longer open  */
2245	sc->aac_state &= ~AAC_STATE_OPEN;
2246
2247	return 0;
2248}
2249
2250static int
2251aac_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
2252{
2253	union aac_statrequest *as;
2254	struct aac_softc *sc;
2255	int error = 0;
2256	int i;
2257
2258	debug_called(2);
2259
2260	as = (union aac_statrequest *)arg;
2261	sc = dev->si_drv1;
2262
2263	switch (cmd) {
2264	case AACIO_STATS:
2265		switch (as->as_item) {
2266		case AACQ_FREE:
2267		case AACQ_BIO:
2268		case AACQ_READY:
2269		case AACQ_BUSY:
2270		case AACQ_COMPLETE:
2271			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2272			      sizeof(struct aac_qstat));
2273			break;
2274		default:
2275			error = ENOENT;
2276			break;
2277		}
2278	break;
2279
2280	case FSACTL_SENDFIB:
2281		arg = *(caddr_t*)arg;
2282	case FSACTL_LNX_SENDFIB:
2283		debug(1, "FSACTL_SENDFIB");
2284		error = aac_ioctl_sendfib(sc, arg);
2285		break;
2286	case FSACTL_AIF_THREAD:
2287	case FSACTL_LNX_AIF_THREAD:
2288		debug(1, "FSACTL_AIF_THREAD");
2289		error = EINVAL;
2290		break;
2291	case FSACTL_OPEN_GET_ADAPTER_FIB:
2292		arg = *(caddr_t*)arg;
2293	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
2294		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
2295		/*
2296		 * Pass the caller out an AdapterFibContext.
2297		 *
2298		 * Note that because we only support one opener, we
2299		 * basically ignore this.  Set the caller's context to a magic
2300		 * number just in case.
2301		 *
2302		 * The Linux code hands the driver a pointer into kernel space,
2303		 * and then trusts it when the caller hands it back.  Aiee!
2304		 * Here, we give it the proc pointer of the per-adapter aif
2305		 * thread. It's only used as a sanity check in other calls.
2306		 */
2307		i = (int)sc->aifthread;
2308		error = copyout(&i, arg, sizeof(i));
2309		break;
2310	case FSACTL_GET_NEXT_ADAPTER_FIB:
2311		arg = *(caddr_t*)arg;
2312	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
2313		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
2314		error = aac_getnext_aif(sc, arg);
2315		break;
2316	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2317	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
2318		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2319		/* don't do anything here */
2320		break;
2321	case FSACTL_MINIPORT_REV_CHECK:
2322		arg = *(caddr_t*)arg;
2323	case FSACTL_LNX_MINIPORT_REV_CHECK:
2324		debug(1, "FSACTL_MINIPORT_REV_CHECK");
2325		error = aac_rev_check(sc, arg);
2326		break;
2327	case FSACTL_QUERY_DISK:
2328		arg = *(caddr_t*)arg;
2329	case FSACTL_LNX_QUERY_DISK:
2330		debug(1, "FSACTL_QUERY_DISK");
2331		error = aac_query_disk(sc, arg);
2332			break;
2333	case FSACTL_DELETE_DISK:
2334	case FSACTL_LNX_DELETE_DISK:
2335		/*
2336		 * We don't trust the underland to tell us when to delete a
2337		 * container, rather we rely on an AIF coming from the
2338		 * controller
2339		 */
2340		error = 0;
2341		break;
2342	default:
2343		debug(1, "unsupported cmd 0x%lx\n", cmd);
2344		error = EINVAL;
2345		break;
2346	}
2347	return(error);
2348}
2349
2350static int
2351aac_poll(dev_t dev, int poll_events, d_thread_t *td)
2352{
2353	struct aac_softc *sc;
2354	int revents;
2355
2356	sc = dev->si_drv1;
2357	revents = 0;
2358
2359	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
2360	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2361		if (sc->aac_aifq_tail != sc->aac_aifq_head)
2362			revents |= poll_events & (POLLIN | POLLRDNORM);
2363	}
2364	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
2365
2366	if (revents == 0) {
2367		if (poll_events & (POLLIN | POLLRDNORM))
2368			selrecord(td, &sc->rcv_select);
2369	}
2370
2371	return (revents);
2372}
2373
2374/*
2375 * Send a FIB supplied from userspace
2376 */
2377static int
2378aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
2379{
2380	struct aac_command *cm;
2381	int size, error;
2382
2383	debug_called(2);
2384
2385	cm = NULL;
2386
2387	/*
2388	 * Get a command
2389	 */
2390	if (aac_alloc_command(sc, &cm)) {
2391		error = EBUSY;
2392		goto out;
2393	}
2394
2395	/*
2396	 * Fetch the FIB header, then re-copy to get data as well.
2397	 */
2398	if ((error = copyin(ufib, cm->cm_fib,
2399			    sizeof(struct aac_fib_header))) != 0)
2400		goto out;
2401	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
2402	if (size > sizeof(struct aac_fib)) {
2403		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
2404			      size, sizeof(struct aac_fib));
2405		size = sizeof(struct aac_fib);
2406	}
2407	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
2408		goto out;
2409	cm->cm_fib->Header.Size = size;
2410	cm->cm_timestamp = time_second;
2411
2412	/*
2413	 * Pass the FIB to the controller, wait for it to complete.
2414	 */
2415	if ((error = aac_wait_command(cm, 30)) != 0) {	/* XXX user timeout? */
2416		printf("aac_wait_command return %d\n", error);
2417		goto out;
2418	}
2419
2420	/*
2421	 * Copy the FIB and data back out to the caller.
2422	 */
2423	size = cm->cm_fib->Header.Size;
2424	if (size > sizeof(struct aac_fib)) {
2425		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
2426			      size, sizeof(struct aac_fib));
2427		size = sizeof(struct aac_fib);
2428	}
2429	error = copyout(cm->cm_fib, ufib, size);
2430
2431out:
2432	if (cm != NULL) {
2433		aac_release_command(cm);
2434	}
2435	return(error);
2436}
2437
2438/*
2439 * Handle an AIF sent to us by the controller; queue it for later reference.
2440 * If the queue fills up, then drop the older entries.
2441 */
2442static void
2443aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
2444{
2445	struct aac_aif_command *aif;
2446	struct aac_container *co, *co_next;
2447	struct aac_mntinfo mi;
2448	struct aac_mntinforesponse mir;
2449	u_int16_t rsize;
2450	int next, found;
2451	int added = 0, i = 0;
2452
2453	debug_called(2);
2454
2455	aif = (struct aac_aif_command*)&fib->data[0];
2456	aac_print_aif(sc, aif);
2457
2458	/* Is it an event that we should care about? */
2459	switch (aif->command) {
2460	case AifCmdEventNotify:
2461		switch (aif->data.EN.type) {
2462		case AifEnAddContainer:
2463		case AifEnDeleteContainer:
2464			/*
2465			 * A container was added or deleted, but the message
2466			 * doesn't tell us anything else!  Re-enumerate the
2467			 * containers and sort things out.
2468			 */
2469			mi.Command = VM_NameServe;
2470			mi.MntType = FT_FILESYS;
2471			do {
2472				/*
2473				 * Ask the controller for its containers one at
2474				 * a time.
2475				 * XXX What if the controller's list changes
2476				 * midway through this enumaration?
2477				 * XXX This should be done async.
2478				 */
2479				mi.MntCount = i;
2480				rsize = sizeof(mir);
2481				if (aac_sync_fib(sc, ContainerCommand, 0, &mi,
2482						 sizeof(mi), &mir, &rsize)) {
2483					debug(2, "Error probing container %d\n",
2484					      i);
2485					continue;
2486				}
2487				if (rsize != sizeof(mir)) {
2488					debug(2, "Container response size too "
2489						 "large\n");
2490					continue;
2491				}
2492				/*
2493				 * Check the container against our list.
2494				 * co->co_found was already set to 0 in a
2495				 * previous run.
2496				 */
2497				if ((mir.Status == ST_OK) &&
2498				    (mir.MntTable[0].VolType != CT_NONE)) {
2499					found = 0;
2500					TAILQ_FOREACH(co,
2501						      &sc->aac_container_tqh,
2502						      co_link) {
2503						if (co->co_mntobj.ObjectId ==
2504						    mir.MntTable[0].ObjectId) {
2505							co->co_found = 1;
2506							found = 1;
2507							break;
2508						}
2509					}
2510					/*
2511					 * If the container matched, continue
2512					 * in the list.
2513					 */
2514					if (found) {
2515						i++;
2516						continue;
2517					}
2518
2519					/*
2520					 * This is a new container.  Do all the
2521					 * appropriate things to set it up.						 */
2522					aac_add_container(sc, &mir, 1);
2523					added = 1;
2524				}
2525				i++;
2526			} while ((i < mir.MntRespCount) &&
2527				 (i < AAC_MAX_CONTAINERS));
2528
2529			/*
2530			 * Go through our list of containers and see which ones
2531			 * were not marked 'found'.  Since the controller didn't
2532			 * list them they must have been deleted.  Do the
2533			 * appropriate steps to destroy the device.  Also reset
2534			 * the co->co_found field.
2535			 */
2536			co = TAILQ_FIRST(&sc->aac_container_tqh);
2537			while (co != NULL) {
2538				if (co->co_found == 0) {
2539					device_delete_child(sc->aac_dev,
2540							    co->co_disk);
2541					co_next = TAILQ_NEXT(co, co_link);
2542					AAC_LOCK_ACQUIRE(&sc->
2543							aac_container_lock);
2544					TAILQ_REMOVE(&sc->aac_container_tqh, co,
2545						     co_link);
2546					AAC_LOCK_RELEASE(&sc->
2547							 aac_container_lock);
2548					FREE(co, M_AACBUF);
2549					co = co_next;
2550				} else {
2551					co->co_found = 0;
2552					co = TAILQ_NEXT(co, co_link);
2553				}
2554			}
2555
2556			/* Attach the newly created containers */
2557			if (added)
2558				bus_generic_attach(sc->aac_dev);
2559
2560				break;
2561
2562		default:
2563			break;
2564		}
2565
2566	default:
2567		break;
2568	}
2569
2570	/* Copy the AIF data to the AIF queue for ioctl retrieval */
2571	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
2572	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
2573	if (next != sc->aac_aifq_tail) {
2574		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
2575		sc->aac_aifq_head = next;
2576
2577		/* On the off chance that someone is sleeping for an aif... */
2578		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
2579			wakeup(sc->aac_aifq);
2580		/* Wakeup any poll()ers */
2581		selwakeup(&sc->rcv_select);
2582	}
2583	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
2584
2585	return;
2586}
2587
2588/*
2589 * Linux Management Interface
2590 * This is soon to be removed!
2591 */
2592
2593#ifdef AAC_COMPAT_LINUX
2594
2595#include <sys/proc.h>
2596#include <machine/../linux/linux.h>
2597#include <machine/../linux/linux_proto.h>
2598#include <compat/linux/linux_ioctl.h>
2599
2600/* There are multiple ioctl number ranges that need to be handled */
2601#define AAC_LINUX_IOCTL_MIN  0x0000
2602#define AAC_LINUX_IOCTL_MAX  0x21ff
2603
2604static linux_ioctl_function_t aac_linux_ioctl;
2605static struct linux_ioctl_handler aac_handler = {aac_linux_ioctl,
2606						 AAC_LINUX_IOCTL_MIN,
2607						 AAC_LINUX_IOCTL_MAX};
2608
2609SYSINIT  (aac_register,   SI_SUB_KLD, SI_ORDER_MIDDLE,
2610	  linux_ioctl_register_handler, &aac_handler);
2611SYSUNINIT(aac_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
2612	  linux_ioctl_unregister_handler, &aac_handler);
2613
2614MODULE_DEPEND(aac, linux, 1, 1, 1);
2615
2616static int
2617aac_linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
2618{
2619	struct file *fp;
2620	u_long cmd;
2621	int error;
2622
2623	debug_called(2);
2624
2625	if ((error = fget(td, args->fd, &fp)) != 0)
2626		return (error);
2627	cmd = args->cmd;
2628
2629	/*
2630	 * Pass the ioctl off to our standard handler.
2631	 */
2632	error = (fo_ioctl(fp, cmd, (caddr_t)args->arg, td));
2633	fdrop(fp, td);
2634	return (error);
2635}
2636
2637#endif
2638
2639/*
2640 * Return the Revision of the driver to userspace and check to see if the
2641 * userspace app is possibly compatible.  This is extremely bogus since
2642 * our driver doesn't follow Adaptec's versioning system.  Cheat by just
2643 * returning what the card reported.
2644 */
2645static int
2646aac_rev_check(struct aac_softc *sc, caddr_t udata)
2647{
2648	struct aac_rev_check rev_check;
2649	struct aac_rev_check_resp rev_check_resp;
2650	int error = 0;
2651
2652	debug_called(2);
2653
2654	/*
2655	 * Copyin the revision struct from userspace
2656	 */
2657	if ((error = copyin(udata, (caddr_t)&rev_check,
2658			sizeof(struct aac_rev_check))) != 0) {
2659		return error;
2660	}
2661
2662	debug(2, "Userland revision= %d\n",
2663	      rev_check.callingRevision.buildNumber);
2664
2665	/*
2666	 * Doctor up the response struct.
2667	 */
2668	rev_check_resp.possiblyCompatible = 1;
2669	rev_check_resp.adapterSWRevision.external.ul =
2670	    sc->aac_revision.external.ul;
2671	rev_check_resp.adapterSWRevision.buildNumber =
2672	    sc->aac_revision.buildNumber;
2673
2674	return(copyout((caddr_t)&rev_check_resp, udata,
2675			sizeof(struct aac_rev_check_resp)));
2676}
2677
2678/*
2679 * Pass the caller the next AIF in their queue
2680 */
2681static int
2682aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
2683{
2684	struct get_adapter_fib_ioctl agf;
2685	int error, s;
2686
2687	debug_called(2);
2688
2689	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
2690
2691		/*
2692		 * Check the magic number that we gave the caller.
2693		 */
2694		if (agf.AdapterFibContext != (int)sc->aifthread) {
2695			error = EFAULT;
2696		} else {
2697
2698			s = splbio();
2699			error = aac_return_aif(sc, agf.AifFib);
2700
2701			if ((error == EAGAIN) && (agf.Wait)) {
2702				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
2703				while (error == EAGAIN) {
2704					error = tsleep(sc->aac_aifq, PRIBIO |
2705						       PCATCH, "aacaif", 0);
2706					if (error == 0)
2707						error = aac_return_aif(sc,
2708						    agf.AifFib);
2709				}
2710				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
2711			}
2712		splx(s);
2713		}
2714	}
2715	return(error);
2716}
2717
2718/*
2719 * Hand the next AIF off the top of the queue out to userspace.
2720 */
2721static int
2722aac_return_aif(struct aac_softc *sc, caddr_t uptr)
2723{
2724	int error;
2725
2726	debug_called(2);
2727
2728	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
2729	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
2730		error = EAGAIN;
2731	} else {
2732		error = copyout(&sc->aac_aifq[sc->aac_aifq_tail], uptr,
2733				sizeof(struct aac_aif_command));
2734		if (error)
2735			printf("aac_return_aif: copyout returned %d\n", error);
2736		if (!error)
2737			sc->aac_aifq_tail = (sc->aac_aifq_tail + 1) %
2738					    AAC_AIFQ_LENGTH;
2739	}
2740	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
2741	return(error);
2742}
2743
2744/*
2745 * Give the userland some information about the container.  The AAC arch
2746 * expects the driver to be a SCSI passthrough type driver, so it expects
2747 * the containers to have b:t:l numbers.  Fake it.
2748 */
2749static int
2750aac_query_disk(struct aac_softc *sc, caddr_t uptr)
2751{
2752	struct aac_query_disk query_disk;
2753	struct aac_container *co;
2754	struct aac_disk	*disk;
2755	int error, id;
2756
2757	debug_called(2);
2758
2759	disk = NULL;
2760
2761	error = copyin(uptr, (caddr_t)&query_disk,
2762		       sizeof(struct aac_query_disk));
2763	if (error)
2764		return (error);
2765
2766	id = query_disk.ContainerNumber;
2767	if (id == -1)
2768		return (EINVAL);
2769
2770	AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
2771	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
2772		if (co->co_mntobj.ObjectId == id)
2773			break;
2774		}
2775
2776		if (co == NULL) {
2777			query_disk.Valid = 0;
2778			query_disk.Locked = 0;
2779			query_disk.Deleted = 1;		/* XXX is this right? */
2780		} else {
2781			disk = device_get_softc(co->co_disk);
2782			query_disk.Valid = 1;
2783			query_disk.Locked =
2784			    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
2785			query_disk.Deleted = 0;
2786			query_disk.Bus = device_get_unit(sc->aac_dev);
2787			query_disk.Target = disk->unit;
2788			query_disk.Lun = 0;
2789			query_disk.UnMapped = 0;
2790			bcopy(disk->ad_dev_t->si_name,
2791			      &query_disk.diskDeviceName[0], 10);
2792		}
2793	AAC_LOCK_RELEASE(&sc->aac_container_lock);
2794
2795	error = copyout((caddr_t)&query_disk, uptr,
2796			sizeof(struct aac_query_disk));
2797
2798	return (error);
2799}
2800
2801