aac.c revision 132771
165793Smsmith/*-
265793Smsmith * Copyright (c) 2000 Michael Smith
381082Sscottl * Copyright (c) 2001 Scott Long
465793Smsmith * Copyright (c) 2000 BSDi
581082Sscottl * Copyright (c) 2001 Adaptec, Inc.
665793Smsmith * All rights reserved.
765793Smsmith *
865793Smsmith * Redistribution and use in source and binary forms, with or without
965793Smsmith * modification, are permitted provided that the following conditions
1065793Smsmith * are met:
1165793Smsmith * 1. Redistributions of source code must retain the above copyright
1265793Smsmith *    notice, this list of conditions and the following disclaimer.
1365793Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1465793Smsmith *    notice, this list of conditions and the following disclaimer in the
1565793Smsmith *    documentation and/or other materials provided with the distribution.
1665793Smsmith *
1765793Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1865793Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1965793Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2065793Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2165793Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2265793Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2365793Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2465793Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2565793Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2665793Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2765793Smsmith * SUCH DAMAGE.
2865793Smsmith */
2965793Smsmith
30119418Sobrien#include <sys/cdefs.h>
31119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aac/aac.c 132771 2004-07-28 06:21:53Z kan $");
32119418Sobrien
3365793Smsmith/*
3465793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3565793Smsmith */
3665793Smsmith
3781151Sscottl#include "opt_aac.h"
3881151Sscottl
3982527Sscottl/* #include <stddef.h> */
4065793Smsmith#include <sys/param.h>
4165793Smsmith#include <sys/systm.h>
4265793Smsmith#include <sys/malloc.h>
4365793Smsmith#include <sys/kernel.h>
4482527Sscottl#include <sys/kthread.h>
4581154Sscottl#include <sys/sysctl.h>
4687183Sscottl#include <sys/poll.h>
47112946Sphk#include <sys/ioccom.h>
4865793Smsmith
4965793Smsmith#include <sys/bus.h>
5065793Smsmith#include <sys/conf.h>
5165793Smsmith#include <sys/signalvar.h>
5270393Smsmith#include <sys/time.h>
5382527Sscottl#include <sys/eventhandler.h>
5465793Smsmith
5565793Smsmith#include <machine/bus_memio.h>
5665793Smsmith#include <machine/bus.h>
5765793Smsmith#include <machine/resource.h>
5865793Smsmith
5965793Smsmith#include <dev/aac/aacreg.h>
6070393Smsmith#include <dev/aac/aac_ioctl.h>
6165793Smsmith#include <dev/aac/aacvar.h>
6265793Smsmith#include <dev/aac/aac_tables.h>
6365793Smsmith
6465793Smsmithstatic void	aac_startup(void *arg);
6583114Sscottlstatic void	aac_add_container(struct aac_softc *sc,
6695350Sscottl				  struct aac_mntinforesp *mir, int f);
6795536Sscottlstatic void	aac_get_bus_info(struct aac_softc *sc);
6865793Smsmith
6965793Smsmith/* Command Processing */
7070393Smsmithstatic void	aac_timeout(struct aac_softc *sc);
7165793Smsmithstatic void	aac_complete(void *context, int pending);
7265793Smsmithstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7365793Smsmithstatic void	aac_bio_complete(struct aac_command *cm);
74128258Sscottlstatic int	aac_wait_command(struct aac_command *cm);
75110426Sscottlstatic void	aac_command_thread(struct aac_softc *sc);
7665793Smsmith
7765793Smsmith/* Command Buffer Management */
78117363Sscottlstatic void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
79117363Sscottl				   int nseg, int error);
8081082Sscottlstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
8181082Sscottl				       int nseg, int error);
8270393Smsmithstatic int	aac_alloc_commands(struct aac_softc *sc);
83111141Sscottlstatic void	aac_free_commands(struct aac_softc *sc);
8465793Smsmithstatic void	aac_unmap_command(struct aac_command *cm);
8565793Smsmith
8665793Smsmith/* Hardware Interface */
8781082Sscottlstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
8881082Sscottl			       int error);
8990275Sscottlstatic int	aac_check_firmware(struct aac_softc *sc);
9065793Smsmithstatic int	aac_init(struct aac_softc *sc);
9165793Smsmithstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
9281082Sscottl				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
9381082Sscottl				 u_int32_t arg3, u_int32_t *sp);
9481082Sscottlstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
9581151Sscottl				struct aac_command *cm);
9681082Sscottlstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
9783114Sscottl				u_int32_t *fib_size, struct aac_fib **fib_addr);
9882527Sscottlstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
9982527Sscottl				     struct aac_fib *fib);
10065793Smsmith
10187183Sscottl/* Falcon/PPC interface */
10287183Sscottlstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
10387183Sscottlstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
10487183Sscottlstatic int	aac_fa_get_istatus(struct aac_softc *sc);
10587183Sscottlstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
10687183Sscottlstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
10787183Sscottl				   u_int32_t arg0, u_int32_t arg1,
10887183Sscottl				   u_int32_t arg2, u_int32_t arg3);
109112679Sscottlstatic int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
11087183Sscottlstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
11187183Sscottl
11287183Sscottlstruct aac_interface aac_fa_interface = {
11387183Sscottl	aac_fa_get_fwstatus,
11487183Sscottl	aac_fa_qnotify,
11587183Sscottl	aac_fa_get_istatus,
11687183Sscottl	aac_fa_clear_istatus,
11787183Sscottl	aac_fa_set_mailbox,
118112679Sscottl	aac_fa_get_mailbox,
11987183Sscottl	aac_fa_set_interrupts
12087183Sscottl};
12187183Sscottl
12265793Smsmith/* StrongARM interface */
12365793Smsmithstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
12465793Smsmithstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
12565793Smsmithstatic int	aac_sa_get_istatus(struct aac_softc *sc);
12665793Smsmithstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
12765793Smsmithstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
12881082Sscottl				   u_int32_t arg0, u_int32_t arg1,
12981082Sscottl				   u_int32_t arg2, u_int32_t arg3);
130112679Sscottlstatic int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13165793Smsmithstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
13265793Smsmith
13365793Smsmithstruct aac_interface aac_sa_interface = {
13483114Sscottl	aac_sa_get_fwstatus,
13583114Sscottl	aac_sa_qnotify,
13683114Sscottl	aac_sa_get_istatus,
13783114Sscottl	aac_sa_clear_istatus,
13883114Sscottl	aac_sa_set_mailbox,
139112679Sscottl	aac_sa_get_mailbox,
14083114Sscottl	aac_sa_set_interrupts
14165793Smsmith};
14265793Smsmith
14383114Sscottl/* i960Rx interface */
14465793Smsmithstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
14565793Smsmithstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
14665793Smsmithstatic int	aac_rx_get_istatus(struct aac_softc *sc);
14765793Smsmithstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
14865793Smsmithstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
14981082Sscottl				   u_int32_t arg0, u_int32_t arg1,
15081082Sscottl				   u_int32_t arg2, u_int32_t arg3);
151112679Sscottlstatic int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
15265793Smsmithstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
15365793Smsmith
15465793Smsmithstruct aac_interface aac_rx_interface = {
15583114Sscottl	aac_rx_get_fwstatus,
15683114Sscottl	aac_rx_qnotify,
15783114Sscottl	aac_rx_get_istatus,
15883114Sscottl	aac_rx_clear_istatus,
15983114Sscottl	aac_rx_set_mailbox,
160112679Sscottl	aac_rx_get_mailbox,
16183114Sscottl	aac_rx_set_interrupts
16265793Smsmith};
16365793Smsmith
16465793Smsmith/* Debugging and Diagnostics */
16565793Smsmithstatic void	aac_describe_controller(struct aac_softc *sc);
16682567Sscottlstatic char	*aac_describe_code(struct aac_code_lookup *table,
16781082Sscottl				   u_int32_t code);
16865793Smsmith
16965793Smsmith/* Management Interface */
17065793Smsmithstatic d_open_t		aac_open;
17165793Smsmithstatic d_close_t	aac_close;
17265793Smsmithstatic d_ioctl_t	aac_ioctl;
17387183Sscottlstatic d_poll_t		aac_poll;
17481082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
17581082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
17683114Sscottl					   struct aac_fib *fib);
17781189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
17881189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
17981189Sscottlstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
18082527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
18165793Smsmith
18265793Smsmithstatic struct cdevsw aac_cdevsw = {
183126080Sphk	.d_version =	D_VERSION,
184126080Sphk	.d_flags =	D_NEEDGIANT,
185111815Sphk	.d_open =	aac_open,
186111815Sphk	.d_close =	aac_close,
187111815Sphk	.d_ioctl =	aac_ioctl,
188111815Sphk	.d_poll =	aac_poll,
189111815Sphk	.d_name =	"aac",
19065793Smsmith};
19165793Smsmith
19282527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
19382527Sscottl
19481154Sscottl/* sysctl node */
19581154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
19681154Sscottl
19783114Sscottl/*
19883114Sscottl * Device Interface
19983114Sscottl */
20065793Smsmith
20183114Sscottl/*
20265793Smsmith * Initialise the controller and softc
20365793Smsmith */
20465793Smsmithint
20565793Smsmithaac_attach(struct aac_softc *sc)
20665793Smsmith{
20783114Sscottl	int error, unit;
20865793Smsmith
20983114Sscottl	debug_called(1);
21065793Smsmith
21183114Sscottl	/*
21283114Sscottl	 * Initialise per-controller queues.
21383114Sscottl	 */
21483114Sscottl	aac_initq_free(sc);
21583114Sscottl	aac_initq_ready(sc);
21683114Sscottl	aac_initq_busy(sc);
21783114Sscottl	aac_initq_bio(sc);
21865793Smsmith
21983114Sscottl	/*
22083114Sscottl	 * Initialise command-completion task.
22183114Sscottl	 */
22283114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
22365793Smsmith
22483114Sscottl	/* disable interrupts before we enable anything */
22583114Sscottl	AAC_MASK_INTERRUPTS(sc);
22665793Smsmith
22783114Sscottl	/* mark controller as suspended until we get ourselves organised */
22883114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
22965793Smsmith
23083114Sscottl	/*
23190275Sscottl	 * Check that the firmware on the card is supported.
23290275Sscottl	 */
23390275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
23490275Sscottl		return(error);
23590275Sscottl
236117126Sscottl	/*
237117126Sscottl	 * Initialize locks
238117126Sscottl	 */
239117126Sscottl	AAC_LOCK_INIT(&sc->aac_aifq_lock, "AAC AIF lock");
240117126Sscottl	AAC_LOCK_INIT(&sc->aac_io_lock, "AAC I/O lock");
241117126Sscottl	AAC_LOCK_INIT(&sc->aac_container_lock, "AAC container lock");
242117126Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
24395350Sscottl
244121173Sscottl	/* Initialize the local AIF queue pointers */
245121173Sscottl	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
246117126Sscottl
24783114Sscottl	/*
24883114Sscottl	 * Initialise the adapter.
24983114Sscottl	 */
25083114Sscottl	if ((error = aac_init(sc)) != 0)
25183114Sscottl		return(error);
25265793Smsmith
25383114Sscottl	/*
25483114Sscottl	 * Print a little information about the controller.
25583114Sscottl	 */
25683114Sscottl	aac_describe_controller(sc);
25765793Smsmith
25883114Sscottl	/*
259111532Sscottl	 * Register to probe our containers later.
26087183Sscottl	 */
26183114Sscottl	sc->aac_ich.ich_func = aac_startup;
26283114Sscottl	sc->aac_ich.ich_arg = sc;
26383114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
26483114Sscottl		device_printf(sc->aac_dev,
26583114Sscottl			      "can't establish configuration hook\n");
26683114Sscottl		return(ENXIO);
26783114Sscottl	}
26865793Smsmith
26983114Sscottl	/*
27083114Sscottl	 * Make the control device.
27183114Sscottl	 */
27283114Sscottl	unit = device_get_unit(sc->aac_dev);
273108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
274108329Srwatson				 0640, "aac%d", unit);
27583114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
27683114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
27783114Sscottl	sc->aac_dev_t->si_drv1 = sc;
27865793Smsmith
27983114Sscottl	/* Create the AIF thread */
280110426Sscottl	if (kthread_create((void(*)(void *))aac_command_thread, sc,
281104354Sscottl			   &sc->aifthread, 0, 0, "aac%daif", unit))
28283114Sscottl		panic("Could not create AIF thread\n");
28382527Sscottl
28483114Sscottl	/* Register the shutdown method to only be called post-dump */
285110427Sscottl	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
286110427Sscottl	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
287110427Sscottl		device_printf(sc->aac_dev,
288110427Sscottl			      "shutdown event registration failed\n");
28982527Sscottl
29095536Sscottl	/* Register with CAM for the non-DASD devices */
291112679Sscottl	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
292110426Sscottl		TAILQ_INIT(&sc->aac_sim_tqh);
29395536Sscottl		aac_get_bus_info(sc);
294110426Sscottl	}
29595536Sscottl
29683114Sscottl	return(0);
29765793Smsmith}
29865793Smsmith
29983114Sscottl/*
30065793Smsmith * Probe for containers, create disks.
30165793Smsmith */
30265793Smsmithstatic void
30365793Smsmithaac_startup(void *arg)
30465793Smsmith{
30583114Sscottl	struct aac_softc *sc;
30695350Sscottl	struct aac_fib *fib;
30795350Sscottl	struct aac_mntinfo *mi;
30895350Sscottl	struct aac_mntinforesp *mir = NULL;
309115760Sscottl	int count = 0, i = 0;
31065793Smsmith
31183114Sscottl	debug_called(1);
31265793Smsmith
31383114Sscottl	sc = (struct aac_softc *)arg;
31465793Smsmith
31583114Sscottl	/* disconnect ourselves from the intrhook chain */
31683114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
31765793Smsmith
318130006Sscottl	aac_alloc_sync_fib(sc, &fib);
31995350Sscottl	mi = (struct aac_mntinfo *)&fib->data[0];
32095350Sscottl
32183114Sscottl	/* loop over possible containers */
32283114Sscottl	do {
32383114Sscottl		/* request information on this container */
32495966Sscottl		bzero(mi, sizeof(struct aac_mntinfo));
32595966Sscottl		mi->Command = VM_NameServe;
32695966Sscottl		mi->MntType = FT_FILESYS;
32795350Sscottl		mi->MntCount = i;
32895350Sscottl		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
32995350Sscottl				 sizeof(struct aac_mntinfo))) {
330115760Sscottl			printf("error probing container %d", i);
33183114Sscottl			continue;
33283114Sscottl		}
33365793Smsmith
33495350Sscottl		mir = (struct aac_mntinforesp *)&fib->data[0];
335115760Sscottl		/* XXX Need to check if count changed */
336115760Sscottl		count = mir->MntRespCount;
33795350Sscottl		aac_add_container(sc, mir, 0);
33883114Sscottl		i++;
339115760Sscottl	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
34065793Smsmith
34195350Sscottl	aac_release_sync_fib(sc);
34295350Sscottl
34383114Sscottl	/* poke the bus to actually attach the child devices */
34483114Sscottl	if (bus_generic_attach(sc->aac_dev))
34583114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
34665793Smsmith
34783114Sscottl	/* mark the controller up */
34883114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
34970393Smsmith
35083114Sscottl	/* enable interrupts now */
35183114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
35265793Smsmith}
35365793Smsmith
35483114Sscottl/*
35583114Sscottl * Create a device to respresent a new container
35683114Sscottl */
35783114Sscottlstatic void
35895350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
35983114Sscottl{
36083114Sscottl	struct aac_container *co;
36183114Sscottl	device_t child;
36283114Sscottl
36383114Sscottl	/*
36483114Sscottl	 * Check container volume type for validity.  Note that many of
36583114Sscottl	 * the possible types may never show up.
36683114Sscottl	 */
36783114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
368110428Sscottl		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
369110428Sscottl		       M_NOWAIT | M_ZERO);
37083114Sscottl		if (co == NULL)
37183114Sscottl			panic("Out of memory?!\n");
37283114Sscottl		debug(1, "id %x  name '%.16s'  size %u  type %d",
37383114Sscottl		      mir->MntTable[0].ObjectId,
37483114Sscottl		      mir->MntTable[0].FileSystemName,
37583114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
37683114Sscottl
37795536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
37883114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
37983114Sscottl		else
38083114Sscottl			device_set_ivars(child, co);
38183114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
38283114Sscottl				mir->MntTable[0].VolType));
38383114Sscottl		co->co_disk = child;
38483114Sscottl		co->co_found = f;
38583114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
38683114Sscottl		      sizeof(struct aac_mntobj));
38787310Sscottl		AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
38883114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
38983114Sscottl		AAC_LOCK_RELEASE(&sc->aac_container_lock);
39083114Sscottl	}
39183114Sscottl}
39283114Sscottl
39383114Sscottl/*
39465793Smsmith * Free all of the resources associated with (sc)
39565793Smsmith *
39665793Smsmith * Should not be called if the controller is active.
39765793Smsmith */
39865793Smsmithvoid
39965793Smsmithaac_free(struct aac_softc *sc)
40065793Smsmith{
401110604Sscottl
40283114Sscottl	debug_called(1);
40365793Smsmith
40483114Sscottl	/* remove the control device */
40583114Sscottl	if (sc->aac_dev_t != NULL)
40683114Sscottl		destroy_dev(sc->aac_dev_t);
40765793Smsmith
40883114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
409111141Sscottl	aac_free_commands(sc);
41083114Sscottl	if (sc->aac_fib_dmat)
41183114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
41265793Smsmith
413110604Sscottl	free(sc->aac_commands, M_AACBUF);
414110604Sscottl
41583114Sscottl	/* destroy the common area */
41683114Sscottl	if (sc->aac_common) {
41783114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
41883114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
41983114Sscottl				sc->aac_common_dmamap);
42083114Sscottl	}
42183114Sscottl	if (sc->aac_common_dmat)
42283114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
42365793Smsmith
42483114Sscottl	/* disconnect the interrupt handler */
42583114Sscottl	if (sc->aac_intr)
42683114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
42783114Sscottl	if (sc->aac_irq != NULL)
42883114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
42983114Sscottl				     sc->aac_irq);
43065793Smsmith
43183114Sscottl	/* destroy data-transfer DMA tag */
43283114Sscottl	if (sc->aac_buffer_dmat)
43383114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
43465793Smsmith
43583114Sscottl	/* destroy the parent DMA tag */
43683114Sscottl	if (sc->aac_parent_dmat)
43783114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
43865793Smsmith
43983114Sscottl	/* release the register window mapping */
44083114Sscottl	if (sc->aac_regs_resource != NULL)
44183114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
44283114Sscottl				     sc->aac_regs_rid, sc->aac_regs_resource);
44365793Smsmith}
44465793Smsmith
44583114Sscottl/*
44665793Smsmith * Disconnect from the controller completely, in preparation for unload.
44765793Smsmith */
44865793Smsmithint
44965793Smsmithaac_detach(device_t dev)
45065793Smsmith{
45183114Sscottl	struct aac_softc *sc;
452110426Sscottl	struct aac_container *co;
453110426Sscottl	struct aac_sim	*sim;
45483114Sscottl	int error;
45565793Smsmith
45683114Sscottl	debug_called(1);
45765793Smsmith
45883114Sscottl	sc = device_get_softc(dev);
45983114Sscottl
46083114Sscottl	if (sc->aac_state & AAC_STATE_OPEN)
461110426Sscottl		return(EBUSY);
46265793Smsmith
463110426Sscottl	/* Remove the child containers */
464110428Sscottl	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
465110426Sscottl		error = device_delete_child(dev, co->co_disk);
466110426Sscottl		if (error)
467110426Sscottl			return (error);
468111196Sscottl		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
469110428Sscottl		free(co, M_AACBUF);
470110426Sscottl	}
471110426Sscottl
472110426Sscottl	/* Remove the CAM SIMs */
473110428Sscottl	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
474110428Sscottl		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
475110426Sscottl		error = device_delete_child(dev, sim->sim_dev);
476110426Sscottl		if (error)
477110426Sscottl			return (error);
478110428Sscottl		free(sim, M_AACBUF);
479110426Sscottl	}
480110426Sscottl
48183114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
48283114Sscottl		sc->aifflags |= AAC_AIFFLAGS_EXIT;
48383114Sscottl		wakeup(sc->aifthread);
48483114Sscottl		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
48583114Sscottl	}
48682527Sscottl
48783114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
48883114Sscottl		panic("Cannot shutdown AIF thread\n");
48982527Sscottl
49083114Sscottl	if ((error = aac_shutdown(dev)))
49183114Sscottl		return(error);
49265793Smsmith
493110427Sscottl	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
494110427Sscottl
49583114Sscottl	aac_free(sc);
49665793Smsmith
49783114Sscottl	return(0);
49865793Smsmith}
49965793Smsmith
50083114Sscottl/*
50165793Smsmith * Bring the controller down to a dormant state and detach all child devices.
50265793Smsmith *
50365793Smsmith * This function is called before detach or system shutdown.
50465793Smsmith *
50570393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
50665793Smsmith * allow shutdown if any device is open.
50765793Smsmith */
50865793Smsmithint
50965793Smsmithaac_shutdown(device_t dev)
51065793Smsmith{
51183114Sscottl	struct aac_softc *sc;
51295350Sscottl	struct aac_fib *fib;
51395350Sscottl	struct aac_close_command *cc;
51465793Smsmith
51583114Sscottl	debug_called(1);
51665793Smsmith
51783114Sscottl	sc = device_get_softc(dev);
51865793Smsmith
51983114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
52065793Smsmith
52183114Sscottl	/*
52283114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
52383114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
52483114Sscottl	 * We've been closed and all I/O completed already
52582527Sscottl	 */
52683114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
52783114Sscottl
528130006Sscottl	aac_alloc_sync_fib(sc, &fib);
52995350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
53095350Sscottl
53195966Sscottl	bzero(cc, sizeof(struct aac_close_command));
53295350Sscottl	cc->Command = VM_CloseAll;
53395350Sscottl	cc->ContainerId = 0xffffffff;
53495350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
53595350Sscottl	    sizeof(struct aac_close_command)))
53683114Sscottl		printf("FAILED.\n");
537110426Sscottl	else
538110426Sscottl		printf("done\n");
539110426Sscottl#if 0
54083114Sscottl	else {
54195350Sscottl		fib->data[0] = 0;
54283114Sscottl		/*
54383114Sscottl		 * XXX Issuing this command to the controller makes it shut down
54483114Sscottl		 * but also keeps it from coming back up without a reset of the
54583114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
54683114Sscottl		 * driver module with the intent to reload it later.
54783114Sscottl		 */
54895350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
54995350Sscottl		    fib, 1)) {
55083114Sscottl			printf("FAILED.\n");
55183114Sscottl		} else {
55283114Sscottl			printf("done.\n");
55383114Sscottl		}
55465793Smsmith	}
555110426Sscottl#endif
55665793Smsmith
55783114Sscottl	AAC_MASK_INTERRUPTS(sc);
55865793Smsmith
55983114Sscottl	return(0);
56065793Smsmith}
56165793Smsmith
56283114Sscottl/*
56365793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
56465793Smsmith */
56565793Smsmithint
56665793Smsmithaac_suspend(device_t dev)
56765793Smsmith{
56883114Sscottl	struct aac_softc *sc;
56965793Smsmith
57083114Sscottl	debug_called(1);
57165793Smsmith
57283114Sscottl	sc = device_get_softc(dev);
57383114Sscottl
57483114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
57583114Sscottl
57683114Sscottl	AAC_MASK_INTERRUPTS(sc);
57783114Sscottl	return(0);
57865793Smsmith}
57965793Smsmith
58083114Sscottl/*
58165793Smsmith * Bring the controller back to a state ready for operation.
58265793Smsmith */
58365793Smsmithint
58465793Smsmithaac_resume(device_t dev)
58565793Smsmith{
58683114Sscottl	struct aac_softc *sc;
58765793Smsmith
58883114Sscottl	debug_called(1);
58983114Sscottl
59083114Sscottl	sc = device_get_softc(dev);
59183114Sscottl
59283114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
59383114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
59483114Sscottl	return(0);
59565793Smsmith}
59665793Smsmith
59783114Sscottl/*
59865793Smsmith * Take an interrupt.
59965793Smsmith */
60065793Smsmithvoid
60165793Smsmithaac_intr(void *arg)
60265793Smsmith{
60383114Sscottl	struct aac_softc *sc;
60483114Sscottl	u_int16_t reason;
60565793Smsmith
60683114Sscottl	debug_called(2);
60765793Smsmith
60883114Sscottl	sc = (struct aac_softc *)arg;
60965793Smsmith
610109088Sscottl	/*
611125225Sscottl	 * Read the status register directly.  This is faster than taking the
612125225Sscottl	 * driver lock and reading the queues directly.  It also saves having
613125225Sscottl	 * to turn parts of the driver lock into a spin mutex, which would be
614125225Sscottl	 * ugly.
615109088Sscottl	 */
616125225Sscottl	reason = AAC_GET_ISTATUS(sc);
617109088Sscottl	AAC_CLEAR_ISTATUS(sc, reason);
61865793Smsmith
619125225Sscottl	/* handle completion processing */
620109088Sscottl	if (reason & AAC_DB_RESPONSE_READY)
621125225Sscottl		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
622109088Sscottl
623125225Sscottl	/* controller wants to talk to us */
624125225Sscottl	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
625125225Sscottl		/*
626125225Sscottl		 * XXX Make sure that we don't get fooled by strange messages
627125225Sscottl		 * that start with a NULL.
628125225Sscottl		 */
629125225Sscottl		if ((reason & AAC_DB_PRINTF) &&
630125225Sscottl		    (sc->aac_common->ac_printf[0] == 0))
631125225Sscottl			sc->aac_common->ac_printf[0] = 32;
63265793Smsmith
633125225Sscottl		/*
634125225Sscottl		 * This might miss doing the actual wakeup.  However, the
635125542Sscottl		 * msleep that this is waking up has a timeout, so it will
636125225Sscottl		 * wake up eventually.  AIFs and printfs are low enough
637125225Sscottl		 * priority that they can handle hanging out for a few seconds
638125225Sscottl		 * if needed.
639125225Sscottl		 */
640125225Sscottl		wakeup(sc->aifthread);
64183114Sscottl	}
642109088Sscottl}
64383114Sscottl
64483114Sscottl/*
64583114Sscottl * Command Processing
64683114Sscottl */
64765793Smsmith
64883114Sscottl/*
64965793Smsmith * Start as much queued I/O as possible on the controller
65065793Smsmith */
65195536Sscottlvoid
65265793Smsmithaac_startio(struct aac_softc *sc)
65365793Smsmith{
65483114Sscottl	struct aac_command *cm;
655129923Sscottl	int error;
65665793Smsmith
65783114Sscottl	debug_called(2);
65865793Smsmith
65983114Sscottl	for (;;) {
66083114Sscottl		/*
661129923Sscottl		 * This flag might be set if the card is out of resources.
662129923Sscottl		 * Checking it here prevents an infinite loop of deferrals.
663129923Sscottl		 */
664129923Sscottl		if (sc->flags & AAC_QUEUE_FRZN)
665129923Sscottl			break;
666129923Sscottl
667129923Sscottl		/*
66883114Sscottl		 * Try to get a command that's been put off for lack of
66983114Sscottl		 * resources
67083114Sscottl		 */
67183114Sscottl		cm = aac_dequeue_ready(sc);
67265793Smsmith
67383114Sscottl		/*
67483114Sscottl		 * Try to build a command off the bio queue (ignore error
67583114Sscottl		 * return)
67683114Sscottl		 */
67783114Sscottl		if (cm == NULL)
67883114Sscottl			aac_bio_command(sc, &cm);
67965793Smsmith
68083114Sscottl		/* nothing to do? */
68183114Sscottl		if (cm == NULL)
68283114Sscottl			break;
68365793Smsmith
684129923Sscottl		/* don't map more than once */
685129923Sscottl		if (cm->cm_flags & AAC_CMD_MAPPED)
686129923Sscottl			panic("aac: command %p already mapped", cm);
687129923Sscottl
688125559Sscottl		/*
689129923Sscottl		 * Set up the command to go to the controller.  If there are no
690129923Sscottl		 * data buffers associated with the command then it can bypass
691129923Sscottl		 * busdma.
692125559Sscottl		 */
693129923Sscottl		if (cm->cm_datalen != 0) {
694129923Sscottl			error = bus_dmamap_load(sc->aac_buffer_dmat,
695129923Sscottl						cm->cm_datamap, cm->cm_data,
696129923Sscottl						cm->cm_datalen,
697129923Sscottl						aac_map_command_sg, cm, 0);
698129923Sscottl			if (error == EINPROGRESS) {
699129923Sscottl				debug(1, "freezing queue\n");
700129923Sscottl				sc->flags |= AAC_QUEUE_FRZN;
701129923Sscottl				error = 0;
702129946Sscottl			} else if (error != 0)
703129923Sscottl				panic("aac_startio: unexpected error %d from "
704129923Sscottl				      "busdma\n", error);
705129923Sscottl		} else
706129923Sscottl			aac_map_command_sg(cm, NULL, 0, 0);
70765793Smsmith	}
70865793Smsmith}
70965793Smsmith
71083114Sscottl/*
71165793Smsmith * Handle notification of one or more FIBs coming from the controller.
71265793Smsmith */
71365793Smsmithstatic void
714110426Sscottlaac_command_thread(struct aac_softc *sc)
71565793Smsmith{
71683114Sscottl	struct aac_fib *fib;
71783114Sscottl	u_int32_t fib_size;
718125225Sscottl	int size, retval;
71965793Smsmith
72083114Sscottl	debug_called(2);
72165793Smsmith
722125542Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
723125542Sscottl	sc->aifflags = AAC_AIFFLAGS_RUNNING;
72465793Smsmith
725125542Sscottl	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
72682527Sscottl
727125542Sscottl		retval = 0;
728125542Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
729125542Sscottl			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
730125542Sscottl					"aifthd", AAC_PERIODIC_INTERVAL * hz);
731125542Sscottl
732125225Sscottl		/*
733125225Sscottl		 * First see if any FIBs need to be allocated.  This needs
734125225Sscottl		 * to be called without the driver lock because contigmalloc
735125225Sscottl		 * will grab Giant, and would result in an LOR.
736125225Sscottl		 */
737125225Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
738125542Sscottl			AAC_LOCK_RELEASE(&sc->aac_io_lock);
739125225Sscottl			aac_alloc_commands(sc);
740125542Sscottl			AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
741125559Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
742125542Sscottl			aac_startio(sc);
743125225Sscottl		}
744125225Sscottl
745125225Sscottl		/*
746125225Sscottl		 * While we're here, check to see if any commands are stuck.
747125225Sscottl		 * This is pretty low-priority, so it's ok if it doesn't
748125225Sscottl		 * always fire.
749125225Sscottl		 */
750125225Sscottl		if (retval == EWOULDBLOCK)
751110426Sscottl			aac_timeout(sc);
752110426Sscottl
753110426Sscottl		/* Check the hardware printf message buffer */
754125225Sscottl		if (sc->aac_common->ac_printf[0] != 0)
755110426Sscottl			aac_print_printf(sc);
756110426Sscottl
757125225Sscottl		/* Also check to see if the adapter has a command for us. */
758125225Sscottl		while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
759125225Sscottl				       &fib_size, &fib) == 0) {
76083114Sscottl
76183114Sscottl			AAC_PRINT_FIB(sc, fib);
76283114Sscottl
76383114Sscottl			switch (fib->Header.Command) {
76483114Sscottl			case AifRequest:
76583114Sscottl				aac_handle_aif(sc, fib);
76683114Sscottl				break;
76783114Sscottl			default:
76883114Sscottl				device_printf(sc->aac_dev, "unknown command "
76983114Sscottl					      "from controller\n");
77083114Sscottl				break;
77183114Sscottl			}
77282527Sscottl
77383114Sscottl			if ((fib->Header.XferState == 0) ||
77483114Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
77583114Sscottl				break;
77682527Sscottl
777110426Sscottl			/* Return the AIF to the controller. */
77883114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
77983114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
78083114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
78182527Sscottl
78283114Sscottl				/* XXX Compute the Size field? */
78383114Sscottl				size = fib->Header.Size;
78483114Sscottl				if (size > sizeof(struct aac_fib)) {
78595536Sscottl					size = sizeof(struct aac_fib);
78683114Sscottl					fib->Header.Size = size;
78783114Sscottl				}
78883114Sscottl				/*
78983114Sscottl				 * Since we did not generate this command, it
79083114Sscottl				 * cannot go through the normal
79183114Sscottl				 * enqueue->startio chain.
79283114Sscottl				 */
79383114Sscottl				aac_enqueue_response(sc,
79483114Sscottl						     AAC_ADAP_NORM_RESP_QUEUE,
79583114Sscottl						     fib);
79683114Sscottl			}
79782527Sscottl		}
79865793Smsmith	}
79983114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
800125542Sscottl	AAC_LOCK_RELEASE(&sc->aac_io_lock);
80183114Sscottl	wakeup(sc->aac_dev);
80265793Smsmith
80383114Sscottl	kthread_exit(0);
80465793Smsmith}
80565793Smsmith
80683114Sscottl/*
807111143Sscottl * Process completed commands.
80865793Smsmith */
80965793Smsmithstatic void
810111143Sscottlaac_complete(void *context, int pending)
81165793Smsmith{
812111143Sscottl	struct aac_softc *sc;
81383114Sscottl	struct aac_command *cm;
81483114Sscottl	struct aac_fib *fib;
81583114Sscottl	u_int32_t fib_size;
81665793Smsmith
81783114Sscottl	debug_called(2);
81865793Smsmith
819111143Sscottl	sc = (struct aac_softc *)context;
820111143Sscottl
821111532Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
822111532Sscottl
823111143Sscottl	/* pull completed commands off the queue */
82483114Sscottl	for (;;) {
82583114Sscottl		/* look for completed FIBs on our queue */
82683114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
82783114Sscottl				    &fib))
82883114Sscottl			break;	/* nothing to do */
829111143Sscottl
830125574Sscottl		/* get the command, unmap and hand off for processing */
831111152Sscottl		cm = sc->aac_commands + fib->Header.SenderData;
83283114Sscottl		if (cm == NULL) {
83383114Sscottl			AAC_PRINT_FIB(sc, fib);
834111143Sscottl			break;
83583114Sscottl		}
83665793Smsmith
837111143Sscottl		aac_remove_busy(cm);
838125574Sscottl		aac_unmap_command(cm);
83983114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
84083114Sscottl
84183114Sscottl		/* is there a completion handler? */
84283114Sscottl		if (cm->cm_complete != NULL) {
84383114Sscottl			cm->cm_complete(cm);
84483114Sscottl		} else {
84583114Sscottl			/* assume that someone is sleeping on this command */
84683114Sscottl			wakeup(cm);
84783114Sscottl		}
84865793Smsmith	}
84970393Smsmith
85083114Sscottl	/* see if we can start some more I/O */
851117363Sscottl	sc->flags &= ~AAC_QUEUE_FRZN;
85283114Sscottl	aac_startio(sc);
853111532Sscottl
854111532Sscottl	AAC_LOCK_RELEASE(&sc->aac_io_lock);
85565793Smsmith}
85665793Smsmith
85783114Sscottl/*
85865793Smsmith * Handle a bio submitted from a disk device.
85965793Smsmith */
86065793Smsmithvoid
86165793Smsmithaac_submit_bio(struct bio *bp)
86265793Smsmith{
86383114Sscottl	struct aac_disk *ad;
86483114Sscottl	struct aac_softc *sc;
86565793Smsmith
86683114Sscottl	debug_called(2);
86765793Smsmith
868111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
86983114Sscottl	sc = ad->ad_controller;
87083114Sscottl
87183114Sscottl	/* queue the BIO and try to get some work done */
87283114Sscottl	aac_enqueue_bio(sc, bp);
87383114Sscottl	aac_startio(sc);
87465793Smsmith}
87565793Smsmith
87683114Sscottl/*
87765793Smsmith * Get a bio and build a command to go with it.
87865793Smsmith */
87965793Smsmithstatic int
88065793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
88165793Smsmith{
88283114Sscottl	struct aac_command *cm;
88383114Sscottl	struct aac_fib *fib;
88483114Sscottl	struct aac_disk *ad;
88583114Sscottl	struct bio *bp;
88665793Smsmith
88783114Sscottl	debug_called(2);
88865793Smsmith
88983114Sscottl	/* get the resources we will need */
89083114Sscottl	cm = NULL;
891125542Sscottl	bp = NULL;
892125542Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
893125542Sscottl		goto fail;
89483114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
89583114Sscottl		goto fail;
89665793Smsmith
89783114Sscottl	/* fill out the command */
89883114Sscottl	cm->cm_data = (void *)bp->bio_data;
89983114Sscottl	cm->cm_datalen = bp->bio_bcount;
90083114Sscottl	cm->cm_complete = aac_bio_complete;
90183114Sscottl	cm->cm_private = bp;
90283114Sscottl	cm->cm_timestamp = time_second;
90383114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
90465793Smsmith
90583114Sscottl	/* build the FIB */
90683114Sscottl	fib = cm->cm_fib;
907112856Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
90883114Sscottl	fib->Header.XferState =
909109088Sscottl		AAC_FIBSTATE_HOSTOWNED   |
910109088Sscottl		AAC_FIBSTATE_INITIALISED |
911109088Sscottl		AAC_FIBSTATE_EMPTY	 |
912109088Sscottl		AAC_FIBSTATE_FROMHOST	 |
913109088Sscottl		AAC_FIBSTATE_REXPECTED   |
914109088Sscottl		AAC_FIBSTATE_NORM	 |
915109088Sscottl		AAC_FIBSTATE_ASYNC	 |
916109088Sscottl		AAC_FIBSTATE_FAST_RESPONSE;
91765793Smsmith
91883114Sscottl	/* build the read/write request */
919111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
920112856Sscottl
921112856Sscottl	if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
922112856Sscottl		fib->Header.Command = ContainerCommand;
923112856Sscottl		if (bp->bio_cmd == BIO_READ) {
924112856Sscottl			struct aac_blockread *br;
925112856Sscottl			br = (struct aac_blockread *)&fib->data[0];
926112856Sscottl			br->Command = VM_CtBlockRead;
927112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
928112856Sscottl			br->BlockNumber = bp->bio_pblkno;
929112856Sscottl			br->ByteCount = bp->bio_bcount;
930112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread);
931112856Sscottl			cm->cm_sgtable = &br->SgMap;
932112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
933112856Sscottl		} else {
934112856Sscottl			struct aac_blockwrite *bw;
935112856Sscottl			bw = (struct aac_blockwrite *)&fib->data[0];
936112856Sscottl			bw->Command = VM_CtBlockWrite;
937112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
938112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
939112856Sscottl			bw->ByteCount = bp->bio_bcount;
940112856Sscottl			bw->Stable = CUNSTABLE;
941112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite);
942112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
943112856Sscottl			cm->cm_sgtable = &bw->SgMap;
944112856Sscottl		}
94583114Sscottl	} else {
946112856Sscottl		fib->Header.Command = ContainerCommand64;
947112856Sscottl		if (bp->bio_cmd == BIO_READ) {
948112856Sscottl			struct aac_blockread64 *br;
949112856Sscottl			br = (struct aac_blockread64 *)&fib->data[0];
950112856Sscottl			br->Command = VM_CtHostRead64;
951112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
952112856Sscottl			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
953112856Sscottl			br->BlockNumber = bp->bio_pblkno;
954112856Sscottl			br->Pad = 0;
955112856Sscottl			br->Flags = 0;
956112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread64);
957112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
958132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
959112856Sscottl		} else {
960112856Sscottl			struct aac_blockwrite64 *bw;
961112856Sscottl			bw = (struct aac_blockwrite64 *)&fib->data[0];
962112856Sscottl			bw->Command = VM_CtHostWrite64;
963112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
964112856Sscottl			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
965112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
966112856Sscottl			bw->Pad = 0;
967112856Sscottl			bw->Flags = 0;
968112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite64);
969112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
970132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
971112856Sscottl		}
97283114Sscottl	}
97365793Smsmith
97483114Sscottl	*cmp = cm;
97583114Sscottl	return(0);
97665793Smsmith
97765793Smsmithfail:
97883114Sscottl	if (bp != NULL)
97983114Sscottl		aac_enqueue_bio(sc, bp);
98083114Sscottl	if (cm != NULL)
98183114Sscottl		aac_release_command(cm);
98283114Sscottl	return(ENOMEM);
98365793Smsmith}
98465793Smsmith
98583114Sscottl/*
98665793Smsmith * Handle a bio-instigated command that has been completed.
98765793Smsmith */
98865793Smsmithstatic void
98965793Smsmithaac_bio_complete(struct aac_command *cm)
99065793Smsmith{
99183114Sscottl	struct aac_blockread_response *brr;
99283114Sscottl	struct aac_blockwrite_response *bwr;
99383114Sscottl	struct bio *bp;
99483114Sscottl	AAC_FSAStatus status;
99565793Smsmith
99683114Sscottl	/* fetch relevant status and then release the command */
99783114Sscottl	bp = (struct bio *)cm->cm_private;
998111691Sscottl	if (bp->bio_cmd == BIO_READ) {
99983114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
100083114Sscottl		status = brr->Status;
100183114Sscottl	} else {
100283114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
100383114Sscottl		status = bwr->Status;
100483114Sscottl	}
100583114Sscottl	aac_release_command(cm);
100665793Smsmith
100783114Sscottl	/* fix up the bio based on status */
100883114Sscottl	if (status == ST_OK) {
100983114Sscottl		bp->bio_resid = 0;
101083114Sscottl	} else {
101183114Sscottl		bp->bio_error = EIO;
101283114Sscottl		bp->bio_flags |= BIO_ERROR;
101383114Sscottl		/* pass an error string out to the disk layer */
101483114Sscottl		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
101583114Sscottl						    status);
101683114Sscottl	}
101783114Sscottl	aac_biodone(bp);
101865793Smsmith}
101965793Smsmith
102083114Sscottl/*
102165793Smsmith * Submit a command to the controller, return when it completes.
102287183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
102387183Sscottl *     be stuck here forever.  At the same time, signals are not caught
1024128258Sscottl *     because there is a risk that a signal could wakeup the sleep before
1025128258Sscottl *     the card has a chance to complete the command.  Since there is no way
1026128258Sscottl *     to cancel a command that is in progress, we can't protect against the
1027128258Sscottl *     card completing a command late and spamming the command and data
1028128258Sscottl *     memory.  So, we are held hostage until the command completes.
102965793Smsmith */
103065793Smsmithstatic int
1031128258Sscottlaac_wait_command(struct aac_command *cm)
103265793Smsmith{
1033111532Sscottl	struct aac_softc *sc;
1034128258Sscottl	int error;
103565793Smsmith
103683114Sscottl	debug_called(2);
103765793Smsmith
1038111532Sscottl	sc = cm->cm_sc;
1039111532Sscottl
104083114Sscottl	/* Put the command on the ready queue and get things going */
104183114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
104283114Sscottl	aac_enqueue_ready(cm);
1043111532Sscottl	aac_startio(sc);
1044128258Sscottl	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
104583114Sscottl	return(error);
104665793Smsmith}
104765793Smsmith
104883114Sscottl/*
104983114Sscottl *Command Buffer Management
105083114Sscottl */
105165793Smsmith
105283114Sscottl/*
105365793Smsmith * Allocate a command.
105465793Smsmith */
105595536Sscottlint
105665793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
105765793Smsmith{
105883114Sscottl	struct aac_command *cm;
105965793Smsmith
106083114Sscottl	debug_called(3);
106165793Smsmith
1062110604Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL) {
1063112856Sscottl		if (sc->total_fibs < sc->aac_max_fibs) {
1064112856Sscottl			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1065112856Sscottl			wakeup(sc->aifthread);
1066112856Sscottl		}
1067111532Sscottl		return (EBUSY);
1068110604Sscottl	}
106965793Smsmith
107083114Sscottl	*cmp = cm;
107183114Sscottl	return(0);
107270393Smsmith}
107370393Smsmith
107483114Sscottl/*
107570393Smsmith * Release a command back to the freelist.
107670393Smsmith */
107795536Sscottlvoid
107870393Smsmithaac_release_command(struct aac_command *cm)
107970393Smsmith{
108083114Sscottl	debug_called(3);
108170393Smsmith
108283114Sscottl	/* (re)initialise the command/FIB */
108383114Sscottl	cm->cm_sgtable = NULL;
108483114Sscottl	cm->cm_flags = 0;
108583114Sscottl	cm->cm_complete = NULL;
108683114Sscottl	cm->cm_private = NULL;
108783114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
108883114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
108983114Sscottl	cm->cm_fib->Header.Flags = 0;
109083114Sscottl	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
109165793Smsmith
109283114Sscottl	/*
109383114Sscottl	 * These are duplicated in aac_start to cover the case where an
109483114Sscottl	 * intermediate stage may have destroyed them.  They're left
109583114Sscottl	 * initialised here for debugging purposes only.
109683114Sscottl	 */
1097109088Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1098109088Sscottl	cm->cm_fib->Header.SenderData = 0;
109965793Smsmith
110083114Sscottl	aac_enqueue_free(cm);
110165793Smsmith}
110265793Smsmith
110383114Sscottl/*
110470393Smsmith * Map helper for command/FIB allocation.
110565793Smsmith */
110665793Smsmithstatic void
110770393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
110865793Smsmith{
1109111141Sscottl	uint32_t	*fibphys;
111065793Smsmith
1111111141Sscottl	fibphys = (uint32_t *)arg;
111265793Smsmith
111383114Sscottl	debug_called(3);
111483114Sscottl
1115110604Sscottl	*fibphys = segs[0].ds_addr;
111665793Smsmith}
111765793Smsmith
111883114Sscottl/*
111970393Smsmith * Allocate and initialise commands/FIBs for this adapter.
112065793Smsmith */
112170393Smsmithstatic int
112270393Smsmithaac_alloc_commands(struct aac_softc *sc)
112365793Smsmith{
112483114Sscottl	struct aac_command *cm;
1125110604Sscottl	struct aac_fibmap *fm;
1126111141Sscottl	uint32_t fibphys;
1127110604Sscottl	int i, error;
112865793Smsmith
1129112679Sscottl	debug_called(2);
113065793Smsmith
1131112679Sscottl	if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
1132110604Sscottl		return (ENOMEM);
1133110604Sscottl
1134111141Sscottl	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1135112679Sscottl	if (fm == NULL)
1136112679Sscottl		return (ENOMEM);
1137110604Sscottl
113883114Sscottl	/* allocate the FIBs in DMAable memory and load them */
1139110604Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1140110604Sscottl			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1141110426Sscottl		device_printf(sc->aac_dev,
1142110426Sscottl			      "Not enough contiguous memory available.\n");
1143111141Sscottl		free(fm, M_AACBUF);
1144102602Sscottl		return (ENOMEM);
114583114Sscottl	}
1146109716Sscottl
1147117363Sscottl	/* Ignore errors since this doesn't bounce */
1148117363Sscottl	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1149117363Sscottl			      AAC_FIB_COUNT * sizeof(struct aac_fib),
1150117363Sscottl			      aac_map_command_helper, &fibphys, 0);
1151109716Sscottl
1152109716Sscottl	/* initialise constant fields in the command structure */
1153125225Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
1154110604Sscottl	bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
115583114Sscottl	for (i = 0; i < AAC_FIB_COUNT; i++) {
1156111141Sscottl		cm = sc->aac_commands + sc->total_fibs;
1157110604Sscottl		fm->aac_commands = cm;
115883114Sscottl		cm->cm_sc = sc;
1159110604Sscottl		cm->cm_fib = fm->aac_fibs + i;
1160111141Sscottl		cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib));
1161111152Sscottl		cm->cm_index = sc->total_fibs;
116265793Smsmith
1163110604Sscottl		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1164110604Sscottl					       &cm->cm_datamap)) == 0)
116583114Sscottl			aac_release_command(cm);
1166111141Sscottl		else
1167111141Sscottl			break;
1168111141Sscottl		sc->total_fibs++;
116983114Sscottl	}
1170110604Sscottl
1171111141Sscottl	if (i > 0) {
1172111141Sscottl		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1173112679Sscottl		debug(1, "total_fibs= %d\n", sc->total_fibs);
1174125225Sscottl		AAC_LOCK_RELEASE(&sc->aac_io_lock);
1175111141Sscottl		return (0);
1176111141Sscottl	}
1177110604Sscottl
1178125225Sscottl	AAC_LOCK_RELEASE(&sc->aac_io_lock);
1179111141Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1180111141Sscottl	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1181111141Sscottl	free(fm, M_AACBUF);
1182111141Sscottl	return (ENOMEM);
118365793Smsmith}
118465793Smsmith
118583114Sscottl/*
118670393Smsmith * Free FIBs owned by this adapter.
118765793Smsmith */
118865793Smsmithstatic void
1189111141Sscottlaac_free_commands(struct aac_softc *sc)
119065793Smsmith{
1191111141Sscottl	struct aac_fibmap *fm;
1192110604Sscottl	struct aac_command *cm;
119383114Sscottl	int i;
119465793Smsmith
119583114Sscottl	debug_called(1);
119665793Smsmith
1197111141Sscottl	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1198111141Sscottl
1199111141Sscottl		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1200111141Sscottl		/*
1201111141Sscottl		 * We check against total_fibs to handle partially
1202111141Sscottl		 * allocated blocks.
1203111141Sscottl		 */
1204111141Sscottl		for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
1205111141Sscottl			cm = fm->aac_commands + i;
1206111141Sscottl			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1207111141Sscottl		}
1208111141Sscottl		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1209111141Sscottl		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1210111141Sscottl		free(fm, M_AACBUF);
1211110604Sscottl	}
121265793Smsmith}
121365793Smsmith
121483114Sscottl/*
121565793Smsmith * Command-mapping helper function - populate this command's s/g table.
121665793Smsmith */
121765793Smsmithstatic void
121865793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
121965793Smsmith{
1220117363Sscottl	struct aac_softc *sc;
122183114Sscottl	struct aac_command *cm;
122283114Sscottl	struct aac_fib *fib;
122383114Sscottl	int i;
122465793Smsmith
122583114Sscottl	debug_called(3);
122665793Smsmith
122783114Sscottl	cm = (struct aac_command *)arg;
1228117363Sscottl	sc = cm->cm_sc;
122983114Sscottl	fib = cm->cm_fib;
123065793Smsmith
123183114Sscottl	/* copy into the FIB */
1232112856Sscottl	if (cm->cm_sgtable != NULL) {
1233112856Sscottl		if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1234112856Sscottl			struct aac_sg_table *sg;
1235112856Sscottl			sg = cm->cm_sgtable;
1236112856Sscottl			sg->SgCount = nseg;
1237112856Sscottl			for (i = 0; i < nseg; i++) {
1238112856Sscottl				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1239112856Sscottl				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1240112856Sscottl			}
1241112856Sscottl			/* update the FIB size for the s/g count */
1242112856Sscottl			fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
1243112856Sscottl		} else {
1244112856Sscottl			struct aac_sg_table64 *sg;
1245112856Sscottl			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1246112856Sscottl			sg->SgCount = nseg;
1247112856Sscottl			for (i = 0; i < nseg; i++) {
1248112856Sscottl				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1249112856Sscottl				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1250112856Sscottl			}
1251112856Sscottl			/* update the FIB size for the s/g count */
1252112856Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
125383114Sscottl		}
125465793Smsmith	}
125565793Smsmith
1256117363Sscottl	/* Fix up the address values in the FIB.  Use the command array index
1257117363Sscottl	 * instead of a pointer since these fields are only 32 bits.  Shift
1258117363Sscottl	 * the SenderFibAddress over to make room for the fast response bit.
1259117363Sscottl	 */
1260117363Sscottl	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
1261117363Sscottl	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
126265793Smsmith
1263117363Sscottl	/* save a pointer to the command for speedy reverse-lookup */
1264117363Sscottl	cm->cm_fib->Header.SenderData = cm->cm_index;
126565793Smsmith
1266117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAIN)
1267117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1268117363Sscottl				BUS_DMASYNC_PREREAD);
1269117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAOUT)
1270117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1271117363Sscottl				BUS_DMASYNC_PREWRITE);
1272117363Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
127365793Smsmith
1274129923Sscottl	/* Put the FIB on the outbound queue */
1275125559Sscottl	if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
1276125559Sscottl		aac_unmap_command(cm);
1277129923Sscottl		sc->flags |= AAC_QUEUE_FRZN;
1278117363Sscottl		aac_requeue_ready(cm);
1279125559Sscottl	}
128065793Smsmith
1281117363Sscottl	return;
128265793Smsmith}
128365793Smsmith
128483114Sscottl/*
128565793Smsmith * Unmap a command from controller-visible space.
128665793Smsmith */
128765793Smsmithstatic void
128865793Smsmithaac_unmap_command(struct aac_command *cm)
128965793Smsmith{
129083114Sscottl	struct aac_softc *sc;
129165793Smsmith
129283114Sscottl	debug_called(2);
129365793Smsmith
129483114Sscottl	sc = cm->cm_sc;
129565793Smsmith
129683114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
129783114Sscottl		return;
129865793Smsmith
129983114Sscottl	if (cm->cm_datalen != 0) {
130083114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
130183114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
130283114Sscottl					BUS_DMASYNC_POSTREAD);
130383114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
130483114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
130583114Sscottl					BUS_DMASYNC_POSTWRITE);
130683114Sscottl
130783114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
130883114Sscottl	}
130983114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
131065793Smsmith}
131165793Smsmith
131283114Sscottl/*
131383114Sscottl * Hardware Interface
131483114Sscottl */
131565793Smsmith
131683114Sscottl/*
131765793Smsmith * Initialise the adapter.
131865793Smsmith */
131965793Smsmithstatic void
132065793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
132165793Smsmith{
132283114Sscottl	struct aac_softc *sc;
132365793Smsmith
132483114Sscottl	debug_called(1);
132565793Smsmith
132683114Sscottl	sc = (struct aac_softc *)arg;
132783114Sscottl
132883114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
132965793Smsmith}
133065793Smsmith
133165793Smsmithstatic int
133290275Sscottlaac_check_firmware(struct aac_softc *sc)
133390275Sscottl{
1334112679Sscottl	u_int32_t major, minor, options;
133590275Sscottl
133690275Sscottl	debug_called(1);
133790275Sscottl
1338112679Sscottl	/*
1339112679Sscottl	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1340112679Sscottl	 * firmware version 1.x are not compatible with this driver.
1341112679Sscottl	 */
1342112679Sscottl	if (sc->flags & AAC_FLAGS_PERC2QC) {
134390275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
134490275Sscottl				     NULL)) {
134590275Sscottl			device_printf(sc->aac_dev,
134690275Sscottl				      "Error reading firmware version\n");
134790275Sscottl			return (EIO);
134890275Sscottl		}
134990275Sscottl
135090275Sscottl		/* These numbers are stored as ASCII! */
1351112679Sscottl		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1352112679Sscottl		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
135390275Sscottl		if (major == 1) {
135490275Sscottl			device_printf(sc->aac_dev,
135590275Sscottl			    "Firmware version %d.%d is not supported.\n",
135690275Sscottl			    major, minor);
135790275Sscottl			return (EINVAL);
135890275Sscottl		}
135990275Sscottl	}
136090275Sscottl
1361112679Sscottl	/*
1362112679Sscottl	 * Retrieve the capabilities/supported options word so we know what
1363112679Sscottl	 * work-arounds to enable.
1364112679Sscottl	 */
1365112679Sscottl	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1366112679Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1367112679Sscottl		return (EIO);
1368112679Sscottl	}
1369112679Sscottl	options = AAC_GET_MAILBOX(sc, 1);
1370112679Sscottl	sc->supported_options = options;
1371112679Sscottl
1372112679Sscottl	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1373112679Sscottl	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1374112679Sscottl		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1375112679Sscottl	if (options & AAC_SUPPORTED_NONDASD)
1376112679Sscottl		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1377117363Sscottl	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1378117363Sscottl	     && (sizeof(bus_addr_t) > 4)) {
1379112679Sscottl		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1380112679Sscottl		sc->flags |= AAC_FLAGS_SG_64BIT;
1381112679Sscottl	}
1382112679Sscottl
1383112679Sscottl	/* Check for broken hardware that does a lower number of commands */
1384112679Sscottl	if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
1385112679Sscottl		sc->aac_max_fibs = AAC_MAX_FIBS;
1386112679Sscottl	else
1387112679Sscottl		sc->aac_max_fibs = 256;
1388112679Sscottl
138990275Sscottl	return (0);
139090275Sscottl}
139190275Sscottl
139290275Sscottlstatic int
139365793Smsmithaac_init(struct aac_softc *sc)
139465793Smsmith{
139583114Sscottl	struct aac_adapter_init	*ip;
139683114Sscottl	time_t then;
1397119146Sscottl	u_int32_t code, qoffset;
1398112679Sscottl	int error;
139965793Smsmith
140083114Sscottl	debug_called(1);
140165793Smsmith
140283114Sscottl	/*
140383114Sscottl	 * First wait for the adapter to come ready.
140483114Sscottl	 */
140583114Sscottl	then = time_second;
140683114Sscottl	do {
140783114Sscottl		code = AAC_GET_FWSTATUS(sc);
140883114Sscottl		if (code & AAC_SELF_TEST_FAILED) {
140983114Sscottl			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
141083114Sscottl			return(ENXIO);
141183114Sscottl		}
141283114Sscottl		if (code & AAC_KERNEL_PANIC) {
141383114Sscottl			device_printf(sc->aac_dev,
141483114Sscottl				      "FATAL: controller kernel panic\n");
141583114Sscottl			return(ENXIO);
141683114Sscottl		}
141783114Sscottl		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
141883114Sscottl			device_printf(sc->aac_dev,
141983114Sscottl				      "FATAL: controller not coming ready, "
142083114Sscottl					   "status %x\n", code);
142183114Sscottl			return(ENXIO);
142283114Sscottl		}
142383114Sscottl	} while (!(code & AAC_UP_AND_RUNNING));
142483114Sscottl
1425112679Sscottl	error = ENOMEM;
142683114Sscottl	/*
1427112679Sscottl	 * Create DMA tag for mapping buffers into controller-addressable space.
1428112679Sscottl	 */
1429112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1430112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1431112679Sscottl			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1432112679Sscottl			       BUS_SPACE_MAXADDR :
1433112679Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1434112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1435112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1436112679Sscottl			       MAXBSIZE,		/* maxsize */
1437112679Sscottl			       AAC_MAXSGENTRIES,	/* nsegments */
1438112679Sscottl			       MAXBSIZE,		/* maxsegsize */
1439112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1440117126Sscottl			       busdma_lock_mutex,	/* lockfunc */
1441117126Sscottl			       &sc->aac_io_lock,	/* lockfuncarg */
1442112679Sscottl			       &sc->aac_buffer_dmat)) {
1443112679Sscottl		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1444112679Sscottl		goto out;
1445112679Sscottl	}
1446112679Sscottl
1447112679Sscottl	/*
1448112679Sscottl	 * Create DMA tag for mapping FIBs into controller-addressable space..
1449112679Sscottl	 */
1450112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1451112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1452112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1453112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1454112679Sscottl			       0x7fffffff,		/* lowaddr */
1455112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1456112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1457112679Sscottl			       AAC_FIB_COUNT *
1458112679Sscottl			       sizeof(struct aac_fib),  /* maxsize */
1459112679Sscottl			       1,			/* nsegments */
1460112679Sscottl			       AAC_FIB_COUNT *
1461112679Sscottl			       sizeof(struct aac_fib),	/* maxsegsize */
1462112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1463117126Sscottl			       NULL, NULL,		/* No locking needed */
1464112679Sscottl			       &sc->aac_fib_dmat)) {
1465112679Sscottl		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1466112679Sscottl		goto out;
1467112679Sscottl	}
1468112679Sscottl
1469112679Sscottl	/*
147083114Sscottl	 * Create DMA tag for the common structure and allocate it.
147183114Sscottl	 */
147283114Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
147395536Sscottl			       1, 0,			/* algnmnt, boundary */
1474112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1475112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1476112679Sscottl			       0x7fffffff,		/* lowaddr */
147783114Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
147883114Sscottl			       NULL, NULL, 		/* filter, filterarg */
1479110604Sscottl			       8192 + sizeof(struct aac_common), /* maxsize */
148083114Sscottl			       1,			/* nsegments */
148183114Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1482112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1483117126Sscottl			       NULL, NULL,		/* No locking needed */
148483114Sscottl			       &sc->aac_common_dmat)) {
148583114Sscottl		device_printf(sc->aac_dev,
148683114Sscottl			      "can't allocate common structure DMA tag\n");
1487112679Sscottl		goto out;
148865793Smsmith	}
148983114Sscottl	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
149083114Sscottl			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
149183114Sscottl		device_printf(sc->aac_dev, "can't allocate common structure\n");
1492112679Sscottl		goto out;
149365793Smsmith	}
1494110604Sscottl
1495110604Sscottl	/*
1496110604Sscottl	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1497110604Sscottl	 * below address 8192 in physical memory.
1498110604Sscottl	 * XXX If the padding is not needed, can it be put to use instead
1499110604Sscottl	 * of ignored?
1500110604Sscottl	 */
1501117363Sscottl	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1502110604Sscottl			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1503110604Sscottl			aac_common_map, sc, 0);
1504110604Sscottl
1505110604Sscottl	if (sc->aac_common_busaddr < 8192) {
1506132771Skan		sc->aac_common = (struct aac_common *)
1507132771Skan		    ((uint8_t *)sc->aac_common + 8192);
1508110604Sscottl		sc->aac_common_busaddr += 8192;
1509110604Sscottl	}
151083114Sscottl	bzero(sc->aac_common, sizeof(*sc->aac_common));
1511110604Sscottl
1512110604Sscottl	/* Allocate some FIBs and associated command structs */
1513110604Sscottl	TAILQ_INIT(&sc->aac_fibmap_tqh);
1514110604Sscottl	sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
1515111141Sscottl				  M_AACBUF, M_WAITOK|M_ZERO);
1516111141Sscottl	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1517110604Sscottl		if (aac_alloc_commands(sc) != 0)
1518110604Sscottl			break;
1519110604Sscottl	}
1520110604Sscottl	if (sc->total_fibs == 0)
1521112679Sscottl		goto out;
152283114Sscottl
152383114Sscottl	/*
152483114Sscottl	 * Fill in the init structure.  This tells the adapter about the
152583114Sscottl	 * physical location of various important shared data structures.
152683114Sscottl	 */
152783114Sscottl	ip = &sc->aac_common->ac_init;
152883114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1529109088Sscottl	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
153065793Smsmith
153183114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
153283114Sscottl					 offsetof(struct aac_common, ac_fibs);
1533114151Sscottl	ip->AdapterFibsVirtualAddress = 0;
153483114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
153583114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
153665793Smsmith
153783114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
153883114Sscottl				  offsetof(struct aac_common, ac_printf);
153983114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
154065793Smsmith
1541117361Sscottl	/*
1542117361Sscottl	 * The adapter assumes that pages are 4K in size, except on some
1543117361Sscottl 	 * broken firmware versions that do the page->byte conversion twice,
1544117361Sscottl	 * therefore 'assuming' that this value is in 16MB units (2^24).
1545117361Sscottl	 * Round up since the granularity is so high.
1546117361Sscottl	 */
1547109088Sscottl	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1548117361Sscottl	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1549117361Sscottl		ip->HostPhysMemPages =
1550117361Sscottl		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1551117362Sscottl	}
155283114Sscottl	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
155365793Smsmith
155483114Sscottl	/*
155583114Sscottl	 * Initialise FIB queues.  Note that it appears that the layout of the
155683114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
155783114Sscottl	 * adapter, which is only told about the base of the queue index fields.
155883114Sscottl	 *
155983114Sscottl	 * The initial values of the indices are assumed to inform the adapter
156083114Sscottl	 * of the sizes of the respective queues, and theoretically it could
156183114Sscottl	 * work out the entire layout of the queue structures from this.  We
156283114Sscottl	 * take the easy route and just lay this area out like everyone else
156383114Sscottl	 * does.
156483114Sscottl	 *
156583114Sscottl	 * The Linux driver uses a much more complex scheme whereby several
156683114Sscottl	 * header records are kept for each queue.  We use a couple of generic
156783114Sscottl	 * list manipulation functions which 'know' the size of each list by
156883114Sscottl	 * virtue of a table.
156983114Sscottl	 */
1570119146Sscottl	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
1571119625Sscottl	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
1572119625Sscottl	sc->aac_queues =
1573119625Sscottl	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1574119146Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
157565793Smsmith
157683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
157781082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
157883114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
157981082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
158083114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
158181082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
158283114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
158381082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
158483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
158581082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
158683114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
158781082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
158883114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
158981082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
159083114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
159181082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
159283114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
159381082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
159483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
159581082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
159683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
159781082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
159883114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
159981082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
160083114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
160181082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
160283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
160381082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
160483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
160581082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
160683114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
160781082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
160883114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
160981082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
161083114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
161181082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
161283114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
161381082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
161483114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
161581082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
161683114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
161781082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
161883114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
161981082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
162083114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
162181082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
162283114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
162381082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
162465793Smsmith
162583114Sscottl	/*
162683114Sscottl	 * Do controller-type-specific initialisation
162783114Sscottl	 */
162883114Sscottl	switch (sc->aac_hwif) {
162983114Sscottl	case AAC_HWIF_I960RX:
163083114Sscottl		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
163183114Sscottl		break;
163283114Sscottl	}
163365793Smsmith
163483114Sscottl	/*
163583114Sscottl	 * Give the init structure to the controller.
163683114Sscottl	 */
163783114Sscottl	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
163883114Sscottl			     sc->aac_common_busaddr +
163983114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
164083114Sscottl			     NULL)) {
164183114Sscottl		device_printf(sc->aac_dev,
164283114Sscottl			      "error establishing init structure\n");
1643112679Sscottl		error = EIO;
1644112679Sscottl		goto out;
164583114Sscottl	}
164665793Smsmith
1647112679Sscottl	error = 0;
1648112679Sscottlout:
1649112679Sscottl	return(error);
165065793Smsmith}
165165793Smsmith
165283114Sscottl/*
165365793Smsmith * Send a synchronous command to the controller and wait for a result.
165465793Smsmith */
165565793Smsmithstatic int
165665793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
165770393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
165870393Smsmith		 u_int32_t *sp)
165965793Smsmith{
166083114Sscottl	time_t then;
166183114Sscottl	u_int32_t status;
166265793Smsmith
166383114Sscottl	debug_called(3);
166465793Smsmith
166583114Sscottl	/* populate the mailbox */
166683114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
166765793Smsmith
166883114Sscottl	/* ensure the sync command doorbell flag is cleared */
166983114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
167065793Smsmith
167183114Sscottl	/* then set it to signal the adapter */
167283114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
167365793Smsmith
167483114Sscottl	/* spin waiting for the command to complete */
167583114Sscottl	then = time_second;
167683114Sscottl	do {
167783114Sscottl		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1678112679Sscottl			debug(1, "timed out");
167983114Sscottl			return(EIO);
168083114Sscottl		}
168183114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
168265793Smsmith
168383114Sscottl	/* clear the completion flag */
168483114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
168565793Smsmith
168683114Sscottl	/* get the command status */
1687112679Sscottl	status = AAC_GET_MAILBOX(sc, 0);
168883114Sscottl	if (sp != NULL)
168983114Sscottl		*sp = status;
169083114Sscottl	return(0);
169165793Smsmith}
169265793Smsmith
169395350Sscottlint
169465793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
169595350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
169665793Smsmith{
169783114Sscottl	debug_called(3);
169865793Smsmith
169983114Sscottl	if (datasize > AAC_FIB_DATASIZE)
170083114Sscottl		return(EINVAL);
170165793Smsmith
170283114Sscottl	/*
170383114Sscottl	 * Set up the sync FIB
170483114Sscottl	 */
170583114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
170683114Sscottl				AAC_FIBSTATE_INITIALISED |
170783114Sscottl				AAC_FIBSTATE_EMPTY;
170883114Sscottl	fib->Header.XferState |= xferstate;
170983114Sscottl	fib->Header.Command = command;
171083114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
171183114Sscottl	fib->Header.Size = sizeof(struct aac_fib) + datasize;
171283114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
1713119146Sscottl	fib->Header.SenderFibAddress = 0;	/* Not needed */
171483114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
171583114Sscottl					 offsetof(struct aac_common,
171683114Sscottl						  ac_sync_fib);
171765793Smsmith
171883114Sscottl	/*
171983114Sscottl	 * Give the FIB to the controller, wait for a response.
172083114Sscottl	 */
172183114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
172283114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
172383114Sscottl		debug(2, "IO error");
172483114Sscottl		return(EIO);
172583114Sscottl	}
172681151Sscottl
172795350Sscottl	return (0);
172865793Smsmith}
172965793Smsmith
173083114Sscottl/*
173165793Smsmith * Adapter-space FIB queue manipulation
173265793Smsmith *
173365793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
173465793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
173565793Smsmith */
173665793Smsmithstatic struct {
173783114Sscottl	int		size;
173883114Sscottl	int		notify;
173965793Smsmith} aac_qinfo[] = {
174083114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
174183114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
174283114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
174383114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
174483114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
174583114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
174683114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
174783114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
174865793Smsmith};
174965793Smsmith
175065793Smsmith/*
175181082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
175281082Sscottl * EBUSY if the queue is full.
175365793Smsmith *
175470393Smsmith * Note: it would be more efficient to defer notifying the controller in
175583114Sscottl *	 the case where we may be inserting several entries in rapid succession,
175683114Sscottl *	 but implementing this usefully may be difficult (it would involve a
175783114Sscottl *	 separate queue/notify interface).
175865793Smsmith */
175965793Smsmithstatic int
176081151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
176165793Smsmith{
176283114Sscottl	u_int32_t pi, ci;
1763111691Sscottl	int error;
176483114Sscottl	u_int32_t fib_size;
176583114Sscottl	u_int32_t fib_addr;
176665793Smsmith
176783114Sscottl	debug_called(3);
176882527Sscottl
176983114Sscottl	fib_size = cm->cm_fib->Header.Size;
177083114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
177181151Sscottl
177283114Sscottl	/* get the producer/consumer indices */
177383114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
177483114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
177565793Smsmith
177683114Sscottl	/* wrap the queue? */
177783114Sscottl	if (pi >= aac_qinfo[queue].size)
177883114Sscottl		pi = 0;
177965793Smsmith
178083114Sscottl	/* check for queue full */
178183114Sscottl	if ((pi + 1) == ci) {
178283114Sscottl		error = EBUSY;
178383114Sscottl		goto out;
178483114Sscottl	}
178565793Smsmith
1786129946Sscottl	/*
1787129946Sscottl	 * To avoid a race with its completion interrupt, place this command on
1788129946Sscottl	 * the busy queue prior to advertising it to the controller.
1789129946Sscottl	 */
1790129946Sscottl	aac_enqueue_busy(cm);
1791129946Sscottl
179283114Sscottl	/* populate queue entry */
179383114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
179483114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
179565793Smsmith
179683114Sscottl	/* update producer index */
179783114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
179865793Smsmith
179983114Sscottl	/* notify the adapter if we know how */
180083114Sscottl	if (aac_qinfo[queue].notify != 0)
180183114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
180265793Smsmith
180383114Sscottl	error = 0;
180465793Smsmith
180565793Smsmithout:
180683114Sscottl	return(error);
180765793Smsmith}
180865793Smsmith
180965793Smsmith/*
181082527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
181182527Sscottl * success or ENOENT if the queue is empty.
181265793Smsmith */
181365793Smsmithstatic int
181481082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
181581082Sscottl		struct aac_fib **fib_addr)
181665793Smsmith{
181783114Sscottl	u_int32_t pi, ci;
1818114151Sscottl	u_int32_t fib_index;
1819111691Sscottl	int error;
182083114Sscottl	int notify;
182165793Smsmith
182283114Sscottl	debug_called(3);
182365793Smsmith
182483114Sscottl	/* get the producer/consumer indices */
182583114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
182683114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
182765793Smsmith
182883114Sscottl	/* check for queue empty */
182983114Sscottl	if (ci == pi) {
183083114Sscottl		error = ENOENT;
183183114Sscottl		goto out;
183283114Sscottl	}
1833120129Sscottl
1834120129Sscottl	/* wrap the pi so the following test works */
1835120129Sscottl	if (pi >= aac_qinfo[queue].size)
1836120129Sscottl		pi = 0;
1837120129Sscottl
183883114Sscottl	notify = 0;
183983114Sscottl	if (ci == pi + 1)
184083114Sscottl		notify++;
184181151Sscottl
184283114Sscottl	/* wrap the queue? */
184383114Sscottl	if (ci >= aac_qinfo[queue].size)
184483114Sscottl		ci = 0;
184565793Smsmith
184683114Sscottl	/* fetch the entry */
184783114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
184865793Smsmith
1849114151Sscottl	switch (queue) {
1850114151Sscottl	case AAC_HOST_NORM_CMD_QUEUE:
1851114151Sscottl	case AAC_HOST_HIGH_CMD_QUEUE:
1852114151Sscottl		/*
1853114151Sscottl		 * The aq_fib_addr is only 32 bits wide so it can't be counted
1854114151Sscottl		 * on to hold an address.  For AIF's, the adapter assumes
1855114151Sscottl		 * that it's giving us an address into the array of AIF fibs.
1856114151Sscottl		 * Therefore, we have to convert it to an index.
1857114151Sscottl		 */
1858114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
1859114151Sscottl			sizeof(struct aac_fib);
1860114151Sscottl		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
1861114151Sscottl		break;
1862114151Sscottl
1863114151Sscottl	case AAC_HOST_NORM_RESP_QUEUE:
1864114151Sscottl	case AAC_HOST_HIGH_RESP_QUEUE:
1865114151Sscottl	{
1866114151Sscottl		struct aac_command *cm;
1867114151Sscottl
1868114151Sscottl		/*
1869114151Sscottl		 * As above, an index is used instead of an actual address.
1870114151Sscottl		 * Gotta shift the index to account for the fast response
1871114151Sscottl		 * bit.  No other correction is needed since this value was
1872114151Sscottl		 * originally provided by the driver via the SenderFibAddress
1873114151Sscottl		 * field.
1874114151Sscottl		 */
1875114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
1876114151Sscottl		cm = sc->aac_commands + (fib_index >> 1);
1877114151Sscottl		*fib_addr = cm->cm_fib;
1878114151Sscottl
1879114151Sscottl		/*
1880114151Sscottl		 * Is this a fast response? If it is, update the fib fields in
1881114151Sscottl		 * local memory since the whole fib isn't DMA'd back up.
1882114151Sscottl		 */
1883114151Sscottl		if (fib_index & 0x01) {
1884114151Sscottl			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
1885114151Sscottl			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
1886114151Sscottl		}
1887114151Sscottl		break;
1888109088Sscottl	}
1889114151Sscottl	default:
1890114151Sscottl		panic("Invalid queue in aac_dequeue_fib()");
1891114151Sscottl		break;
1892114151Sscottl	}
1893114151Sscottl
189483114Sscottl	/* update consumer index */
189583114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
189665793Smsmith
189783114Sscottl	/* if we have made the queue un-full, notify the adapter */
189883114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
189983114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
190083114Sscottl	error = 0;
190165793Smsmith
190265793Smsmithout:
190383114Sscottl	return(error);
190465793Smsmith}
190565793Smsmith
190683114Sscottl/*
190782527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
190882527Sscottl */
190982527Sscottlstatic int
191082527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
191182527Sscottl{
191283114Sscottl	u_int32_t pi, ci;
1913111691Sscottl	int error;
191483114Sscottl	u_int32_t fib_size;
191583114Sscottl	u_int32_t fib_addr;
191682527Sscottl
191783114Sscottl	debug_called(1);
191882527Sscottl
191983114Sscottl	/* Tell the adapter where the FIB is */
192083114Sscottl	fib_size = fib->Header.Size;
192183114Sscottl	fib_addr = fib->Header.SenderFibAddress;
192283114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
192382527Sscottl
192483114Sscottl	/* get the producer/consumer indices */
192583114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
192683114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
192782527Sscottl
192883114Sscottl	/* wrap the queue? */
192983114Sscottl	if (pi >= aac_qinfo[queue].size)
193083114Sscottl		pi = 0;
193182527Sscottl
193283114Sscottl	/* check for queue full */
193383114Sscottl	if ((pi + 1) == ci) {
193483114Sscottl		error = EBUSY;
193583114Sscottl		goto out;
193683114Sscottl	}
193782527Sscottl
193883114Sscottl	/* populate queue entry */
193983114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
194083114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
194182527Sscottl
194283114Sscottl	/* update producer index */
194383114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
194482527Sscottl
194583114Sscottl	/* notify the adapter if we know how */
194683114Sscottl	if (aac_qinfo[queue].notify != 0)
194783114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
194882527Sscottl
194983114Sscottl	error = 0;
195082527Sscottl
195182527Sscottlout:
195283114Sscottl	return(error);
195382527Sscottl}
195482527Sscottl
195583114Sscottl/*
195670393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
195770393Smsmith * and complain about them.
195870393Smsmith */
195970393Smsmithstatic void
196070393Smsmithaac_timeout(struct aac_softc *sc)
196170393Smsmith{
196283114Sscottl	struct aac_command *cm;
196383114Sscottl	time_t deadline;
196470393Smsmith
196583114Sscottl	/*
1966110426Sscottl	 * Traverse the busy command list, bitch about late commands once
196783114Sscottl	 * only.
196883114Sscottl	 */
196983114Sscottl	deadline = time_second - AAC_CMD_TIMEOUT;
197083114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
197183114Sscottl		if ((cm->cm_timestamp  < deadline)
197283114Sscottl			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
197383114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
197483114Sscottl			device_printf(sc->aac_dev,
197583114Sscottl				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
197683114Sscottl				      cm, (int)(time_second-cm->cm_timestamp));
197783114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
197883114Sscottl		}
197970393Smsmith	}
198070393Smsmith
198183114Sscottl	return;
198270393Smsmith}
198370393Smsmith
198483114Sscottl/*
198583114Sscottl * Interface Function Vectors
198683114Sscottl */
198765793Smsmith
198883114Sscottl/*
198965793Smsmith * Read the current firmware status word.
199065793Smsmith */
199165793Smsmithstatic int
199265793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
199365793Smsmith{
199483114Sscottl	debug_called(3);
199565793Smsmith
199683114Sscottl	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
199765793Smsmith}
199865793Smsmith
199965793Smsmithstatic int
200065793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
200165793Smsmith{
200283114Sscottl	debug_called(3);
200365793Smsmith
200483114Sscottl	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
200565793Smsmith}
200665793Smsmith
200787183Sscottlstatic int
200887183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc)
200987183Sscottl{
201087183Sscottl	int val;
201187183Sscottl
201287183Sscottl	debug_called(3);
201387183Sscottl
201487183Sscottl	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
201587183Sscottl	return (val);
201687183Sscottl}
201787183Sscottl
201883114Sscottl/*
201965793Smsmith * Notify the controller of a change in a given queue
202065793Smsmith */
202165793Smsmith
202265793Smsmithstatic void
202365793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
202465793Smsmith{
202583114Sscottl	debug_called(3);
202665793Smsmith
202783114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
202865793Smsmith}
202965793Smsmith
203065793Smsmithstatic void
203165793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
203265793Smsmith{
203383114Sscottl	debug_called(3);
203465793Smsmith
203583114Sscottl	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
203665793Smsmith}
203765793Smsmith
203887183Sscottlstatic void
203987183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit)
204087183Sscottl{
204187183Sscottl	debug_called(3);
204287183Sscottl
204387183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
204487183Sscottl	AAC_FA_HACK(sc);
204587183Sscottl}
204687183Sscottl
204783114Sscottl/*
204865793Smsmith * Get the interrupt reason bits
204965793Smsmith */
205065793Smsmithstatic int
205165793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
205265793Smsmith{
205383114Sscottl	debug_called(3);
205465793Smsmith
205583114Sscottl	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
205665793Smsmith}
205765793Smsmith
205865793Smsmithstatic int
205965793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
206065793Smsmith{
206183114Sscottl	debug_called(3);
206265793Smsmith
206383114Sscottl	return(AAC_GETREG4(sc, AAC_RX_ODBR));
206465793Smsmith}
206565793Smsmith
206687183Sscottlstatic int
206787183Sscottlaac_fa_get_istatus(struct aac_softc *sc)
206887183Sscottl{
206987183Sscottl	int val;
207087183Sscottl
207187183Sscottl	debug_called(3);
207287183Sscottl
207387183Sscottl	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
207487183Sscottl	return (val);
207587183Sscottl}
207687183Sscottl
207783114Sscottl/*
207865793Smsmith * Clear some interrupt reason bits
207965793Smsmith */
208065793Smsmithstatic void
208165793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
208265793Smsmith{
208383114Sscottl	debug_called(3);
208465793Smsmith
208583114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
208665793Smsmith}
208765793Smsmith
208865793Smsmithstatic void
208965793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
209065793Smsmith{
209183114Sscottl	debug_called(3);
209265793Smsmith
209383114Sscottl	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
209465793Smsmith}
209565793Smsmith
209687183Sscottlstatic void
209787183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask)
209887183Sscottl{
209987183Sscottl	debug_called(3);
210087183Sscottl
210187183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
210287183Sscottl	AAC_FA_HACK(sc);
210387183Sscottl}
210487183Sscottl
210583114Sscottl/*
210665793Smsmith * Populate the mailbox and set the command word
210765793Smsmith */
210865793Smsmithstatic void
210965793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
211065793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
211165793Smsmith{
211283114Sscottl	debug_called(4);
211365793Smsmith
211483114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
211583114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
211683114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
211783114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
211883114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
211965793Smsmith}
212065793Smsmith
212165793Smsmithstatic void
212265793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
212365793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
212465793Smsmith{
212583114Sscottl	debug_called(4);
212665793Smsmith
212783114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
212883114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
212983114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
213083114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
213183114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
213265793Smsmith}
213365793Smsmith
213487183Sscottlstatic void
213587183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
213687183Sscottl		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
213787183Sscottl{
213887183Sscottl	debug_called(4);
213987183Sscottl
214087183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
214187183Sscottl	AAC_FA_HACK(sc);
214287183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
214387183Sscottl	AAC_FA_HACK(sc);
214487183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
214587183Sscottl	AAC_FA_HACK(sc);
214687183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
214787183Sscottl	AAC_FA_HACK(sc);
214887183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
214987183Sscottl	AAC_FA_HACK(sc);
215087183Sscottl}
215187183Sscottl
215283114Sscottl/*
215365793Smsmith * Fetch the immediate command status word
215465793Smsmith */
215565793Smsmithstatic int
2156112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb)
215765793Smsmith{
215883114Sscottl	debug_called(4);
215965793Smsmith
2160112679Sscottl	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
216165793Smsmith}
216265793Smsmith
216365793Smsmithstatic int
2164112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb)
216565793Smsmith{
216683114Sscottl	debug_called(4);
216765793Smsmith
2168112679Sscottl	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
216965793Smsmith}
217065793Smsmith
217187183Sscottlstatic int
2172112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb)
217387183Sscottl{
217487183Sscottl	int val;
217587183Sscottl
217687183Sscottl	debug_called(4);
217787183Sscottl
2178112679Sscottl	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
217987183Sscottl	return (val);
218087183Sscottl}
218187183Sscottl
218283114Sscottl/*
218365793Smsmith * Set/clear interrupt masks
218465793Smsmith */
218565793Smsmithstatic void
218665793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
218765793Smsmith{
218883114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
218965793Smsmith
219083114Sscottl	if (enable) {
219183114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
219283114Sscottl	} else {
219383114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
219483114Sscottl	}
219565793Smsmith}
219665793Smsmith
219765793Smsmithstatic void
219865793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
219965793Smsmith{
220083114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
220165793Smsmith
220283114Sscottl	if (enable) {
220383114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
220483114Sscottl	} else {
220583114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
220683114Sscottl	}
220765793Smsmith}
220865793Smsmith
220987183Sscottlstatic void
221087183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable)
221187183Sscottl{
221287183Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
221387183Sscottl
221487183Sscottl	if (enable) {
221587183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
221687183Sscottl		AAC_FA_HACK(sc);
221787183Sscottl	} else {
221887183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
221987183Sscottl		AAC_FA_HACK(sc);
222087183Sscottl	}
222187183Sscottl}
222287183Sscottl
222383114Sscottl/*
222483114Sscottl * Debugging and Diagnostics
222583114Sscottl */
222665793Smsmith
222783114Sscottl/*
222865793Smsmith * Print some information about the controller.
222965793Smsmith */
223065793Smsmithstatic void
223165793Smsmithaac_describe_controller(struct aac_softc *sc)
223265793Smsmith{
223395350Sscottl	struct aac_fib *fib;
223483114Sscottl	struct aac_adapter_info	*info;
223565793Smsmith
223683114Sscottl	debug_called(2);
223765793Smsmith
2238130006Sscottl	aac_alloc_sync_fib(sc, &fib);
223995350Sscottl
224095350Sscottl	fib->data[0] = 0;
224195350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
224283114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
224395536Sscottl		aac_release_sync_fib(sc);
224483114Sscottl		return;
224583114Sscottl	}
2246112679Sscottl	info = (struct aac_adapter_info *)&fib->data[0];
224765793Smsmith
224883114Sscottl	device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
224983114Sscottl		      aac_describe_code(aac_cpu_variant, info->CpuVariant),
225083114Sscottl		      info->ClockSpeed, info->BufferMem / (1024 * 1024),
225183114Sscottl		      aac_describe_code(aac_battery_platform,
225283114Sscottl					info->batteryPlatform));
225365793Smsmith
225483114Sscottl	/* save the kernel revision structure for later use */
225583114Sscottl	sc->aac_revision = info->KernelRevision;
225683114Sscottl	device_printf(sc->aac_dev, "Kernel %d.%d-%d, Build %d, S/N %6X\n",
225783114Sscottl		      info->KernelRevision.external.comp.major,
225883114Sscottl		      info->KernelRevision.external.comp.minor,
225983114Sscottl		      info->KernelRevision.external.comp.dash,
226083114Sscottl		      info->KernelRevision.buildNumber,
226183114Sscottl		      (u_int32_t)(info->SerialNumber & 0xffffff));
226295536Sscottl
226395536Sscottl	aac_release_sync_fib(sc);
2264112679Sscottl
2265112679Sscottl	if (1 || bootverbose) {
2266112679Sscottl		device_printf(sc->aac_dev, "Supported Options=%b\n",
2267112679Sscottl			      sc->supported_options,
2268112679Sscottl			      "\20"
2269112679Sscottl			      "\1SNAPSHOT"
2270112679Sscottl			      "\2CLUSTERS"
2271112679Sscottl			      "\3WCACHE"
2272112679Sscottl			      "\4DATA64"
2273112679Sscottl			      "\5HOSTTIME"
2274112679Sscottl			      "\6RAID50"
2275112679Sscottl			      "\7WINDOW4GB"
2276112679Sscottl			      "\10SCSIUPGD"
2277112679Sscottl			      "\11SOFTERR"
2278112679Sscottl			      "\12NORECOND"
2279112679Sscottl			      "\13SGMAP64"
2280112679Sscottl			      "\14ALARM"
2281112679Sscottl			      "\15NONDASD");
2282112679Sscottl	}
228365793Smsmith}
228465793Smsmith
228583114Sscottl/*
228665793Smsmith * Look up a text description of a numeric error code and return a pointer to
228765793Smsmith * same.
228865793Smsmith */
228965793Smsmithstatic char *
229065793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code)
229165793Smsmith{
229283114Sscottl	int i;
229365793Smsmith
229483114Sscottl	for (i = 0; table[i].string != NULL; i++)
229583114Sscottl		if (table[i].code == code)
229683114Sscottl			return(table[i].string);
229783114Sscottl	return(table[i + 1].string);
229865793Smsmith}
229965793Smsmith
230083114Sscottl/*
230183114Sscottl * Management Interface
230283114Sscottl */
230365793Smsmith
230465793Smsmithstatic int
2305130585Sphkaac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
230665793Smsmith{
230783114Sscottl	struct aac_softc *sc;
230865793Smsmith
230983114Sscottl	debug_called(2);
231065793Smsmith
231183114Sscottl	sc = dev->si_drv1;
231265793Smsmith
231383114Sscottl	/* Check to make sure the device isn't already open */
231483114Sscottl	if (sc->aac_state & AAC_STATE_OPEN) {
231583114Sscottl		return EBUSY;
231683114Sscottl	}
231783114Sscottl	sc->aac_state |= AAC_STATE_OPEN;
231883114Sscottl
231983114Sscottl	return 0;
232065793Smsmith}
232165793Smsmith
232265793Smsmithstatic int
2323130585Sphkaac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
232465793Smsmith{
232583114Sscottl	struct aac_softc *sc;
232665793Smsmith
232783114Sscottl	debug_called(2);
232865793Smsmith
232983114Sscottl	sc = dev->si_drv1;
233065793Smsmith
233183114Sscottl	/* Mark this unit as no longer open  */
233283114Sscottl	sc->aac_state &= ~AAC_STATE_OPEN;
233383114Sscottl
233483114Sscottl	return 0;
233565793Smsmith}
233665793Smsmith
233765793Smsmithstatic int
2338130585Sphkaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
233965793Smsmith{
234083114Sscottl	union aac_statrequest *as;
234183114Sscottl	struct aac_softc *sc;
234283114Sscottl	int error = 0;
2343119146Sscottl	uint32_t cookie;
234465793Smsmith
234583114Sscottl	debug_called(2);
234665793Smsmith
234783114Sscottl	as = (union aac_statrequest *)arg;
234883114Sscottl	sc = dev->si_drv1;
234983114Sscottl
235083114Sscottl	switch (cmd) {
235183114Sscottl	case AACIO_STATS:
235283114Sscottl		switch (as->as_item) {
235383114Sscottl		case AACQ_FREE:
235483114Sscottl		case AACQ_BIO:
235583114Sscottl		case AACQ_READY:
235683114Sscottl		case AACQ_BUSY:
235783114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
235883114Sscottl			      sizeof(struct aac_qstat));
235983114Sscottl			break;
236083114Sscottl		default:
236183114Sscottl			error = ENOENT;
236283114Sscottl			break;
236383114Sscottl		}
236483114Sscottl	break;
236583114Sscottl
236683114Sscottl	case FSACTL_SENDFIB:
236783114Sscottl		arg = *(caddr_t*)arg;
236883114Sscottl	case FSACTL_LNX_SENDFIB:
236983114Sscottl		debug(1, "FSACTL_SENDFIB");
237083114Sscottl		error = aac_ioctl_sendfib(sc, arg);
237183114Sscottl		break;
237283114Sscottl	case FSACTL_AIF_THREAD:
237383114Sscottl	case FSACTL_LNX_AIF_THREAD:
237483114Sscottl		debug(1, "FSACTL_AIF_THREAD");
237583114Sscottl		error = EINVAL;
237683114Sscottl		break;
237783114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
237883114Sscottl		arg = *(caddr_t*)arg;
237987183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
238083114Sscottl		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
238183114Sscottl		/*
238283114Sscottl		 * Pass the caller out an AdapterFibContext.
238383114Sscottl		 *
238483114Sscottl		 * Note that because we only support one opener, we
238583114Sscottl		 * basically ignore this.  Set the caller's context to a magic
238683114Sscottl		 * number just in case.
238783114Sscottl		 *
238883114Sscottl		 * The Linux code hands the driver a pointer into kernel space,
238983114Sscottl		 * and then trusts it when the caller hands it back.  Aiee!
239083114Sscottl		 * Here, we give it the proc pointer of the per-adapter aif
239183114Sscottl		 * thread. It's only used as a sanity check in other calls.
239283114Sscottl		 */
2393119146Sscottl		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2394119146Sscottl		error = copyout(&cookie, arg, sizeof(cookie));
239583114Sscottl		break;
239683114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
239783114Sscottl		arg = *(caddr_t*)arg;
239883114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
239983114Sscottl		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
240083114Sscottl		error = aac_getnext_aif(sc, arg);
240183114Sscottl		break;
240283114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
240383114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
240483114Sscottl		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
240583114Sscottl		/* don't do anything here */
240683114Sscottl		break;
240783114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
240883114Sscottl		arg = *(caddr_t*)arg;
240983114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
241083114Sscottl		debug(1, "FSACTL_MINIPORT_REV_CHECK");
241183114Sscottl		error = aac_rev_check(sc, arg);
241283114Sscottl		break;
241383114Sscottl	case FSACTL_QUERY_DISK:
241483114Sscottl		arg = *(caddr_t*)arg;
241583114Sscottl	case FSACTL_LNX_QUERY_DISK:
241683114Sscottl		debug(1, "FSACTL_QUERY_DISK");
241783114Sscottl		error = aac_query_disk(sc, arg);
241883114Sscottl			break;
241983114Sscottl	case FSACTL_DELETE_DISK:
242083114Sscottl	case FSACTL_LNX_DELETE_DISK:
242183114Sscottl		/*
242283114Sscottl		 * We don't trust the underland to tell us when to delete a
242383114Sscottl		 * container, rather we rely on an AIF coming from the
242483114Sscottl		 * controller
242583114Sscottl		 */
242683114Sscottl		error = 0;
242783114Sscottl		break;
242870393Smsmith	default:
242987183Sscottl		debug(1, "unsupported cmd 0x%lx\n", cmd);
243083114Sscottl		error = EINVAL;
243183114Sscottl		break;
243270393Smsmith	}
243383114Sscottl	return(error);
243465793Smsmith}
243565793Smsmith
243687183Sscottlstatic int
2437130585Sphkaac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
243887183Sscottl{
243987183Sscottl	struct aac_softc *sc;
244087183Sscottl	int revents;
244187183Sscottl
244287183Sscottl	sc = dev->si_drv1;
244387183Sscottl	revents = 0;
244487183Sscottl
244587310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
244687183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
244787183Sscottl		if (sc->aac_aifq_tail != sc->aac_aifq_head)
244887183Sscottl			revents |= poll_events & (POLLIN | POLLRDNORM);
244987183Sscottl	}
245087183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
245187183Sscottl
245287183Sscottl	if (revents == 0) {
245387183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
245487183Sscottl			selrecord(td, &sc->rcv_select);
245587183Sscottl	}
245687183Sscottl
245787183Sscottl	return (revents);
245887183Sscottl}
245987183Sscottl
246083114Sscottl/*
246165793Smsmith * Send a FIB supplied from userspace
246265793Smsmith */
246365793Smsmithstatic int
246465793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
246565793Smsmith{
246683114Sscottl	struct aac_command *cm;
246783114Sscottl	int size, error;
246865793Smsmith
246983114Sscottl	debug_called(2);
247065793Smsmith
247183114Sscottl	cm = NULL;
247265793Smsmith
247383114Sscottl	/*
247483114Sscottl	 * Get a command
247583114Sscottl	 */
2476111532Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_io_lock);
247783114Sscottl	if (aac_alloc_command(sc, &cm)) {
247883114Sscottl		error = EBUSY;
247983114Sscottl		goto out;
248083114Sscottl	}
248165793Smsmith
248283114Sscottl	/*
248383114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
248483114Sscottl	 */
248583114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
248683114Sscottl			    sizeof(struct aac_fib_header))) != 0)
248783114Sscottl		goto out;
248883114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
248983114Sscottl	if (size > sizeof(struct aac_fib)) {
2490119146Sscottl		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
249183114Sscottl			      size, sizeof(struct aac_fib));
249283114Sscottl		size = sizeof(struct aac_fib);
249383114Sscottl	}
249483114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
249583114Sscottl		goto out;
249683114Sscottl	cm->cm_fib->Header.Size = size;
249783114Sscottl	cm->cm_timestamp = time_second;
249865793Smsmith
249983114Sscottl	/*
250083114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
250183114Sscottl	 */
2502128258Sscottl	if ((error = aac_wait_command(cm)) != 0) {
2503110426Sscottl		device_printf(sc->aac_dev,
2504110426Sscottl			      "aac_wait_command return %d\n", error);
250583114Sscottl		goto out;
250687183Sscottl	}
250765793Smsmith
250883114Sscottl	/*
250983114Sscottl	 * Copy the FIB and data back out to the caller.
251083114Sscottl	 */
251183114Sscottl	size = cm->cm_fib->Header.Size;
251283114Sscottl	if (size > sizeof(struct aac_fib)) {
2513119146Sscottl		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
251483114Sscottl			      size, sizeof(struct aac_fib));
251583114Sscottl		size = sizeof(struct aac_fib);
251683114Sscottl	}
251783114Sscottl	error = copyout(cm->cm_fib, ufib, size);
251865793Smsmith
251965793Smsmithout:
252083114Sscottl	if (cm != NULL) {
252183114Sscottl		aac_release_command(cm);
252283114Sscottl	}
2523111532Sscottl
2524111532Sscottl	AAC_LOCK_RELEASE(&sc->aac_io_lock);
252583114Sscottl	return(error);
252665793Smsmith}
252765793Smsmith
252883114Sscottl/*
252965793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
253082527Sscottl * If the queue fills up, then drop the older entries.
253165793Smsmith */
253265793Smsmithstatic void
253382527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
253465793Smsmith{
253583114Sscottl	struct aac_aif_command *aif;
253683114Sscottl	struct aac_container *co, *co_next;
253795350Sscottl	struct aac_mntinfo *mi;
253895350Sscottl	struct aac_mntinforesp *mir = NULL;
253983114Sscottl	u_int16_t rsize;
254087183Sscottl	int next, found;
2541115760Sscottl	int count = 0, added = 0, i = 0;
254265793Smsmith
254383114Sscottl	debug_called(2);
254465793Smsmith
254583114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
254683114Sscottl	aac_print_aif(sc, aif);
254782527Sscottl
254883114Sscottl	/* Is it an event that we should care about? */
254983114Sscottl	switch (aif->command) {
255083114Sscottl	case AifCmdEventNotify:
255183114Sscottl		switch (aif->data.EN.type) {
255283114Sscottl		case AifEnAddContainer:
255383114Sscottl		case AifEnDeleteContainer:
255483114Sscottl			/*
255583114Sscottl			 * A container was added or deleted, but the message
255683114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
255783114Sscottl			 * containers and sort things out.
255883114Sscottl			 */
2559130006Sscottl			aac_alloc_sync_fib(sc, &fib);
256095350Sscottl			mi = (struct aac_mntinfo *)&fib->data[0];
256183114Sscottl			do {
256283114Sscottl				/*
256383114Sscottl				 * Ask the controller for its containers one at
256483114Sscottl				 * a time.
256583114Sscottl				 * XXX What if the controller's list changes
256683114Sscottl				 * midway through this enumaration?
256783114Sscottl				 * XXX This should be done async.
256883114Sscottl				 */
256995966Sscottl				bzero(mi, sizeof(struct aac_mntinfo));
257095966Sscottl				mi->Command = VM_NameServe;
257195966Sscottl				mi->MntType = FT_FILESYS;
257295350Sscottl				mi->MntCount = i;
257383114Sscottl				rsize = sizeof(mir);
257495350Sscottl				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
257595350Sscottl						 sizeof(struct aac_mntinfo))) {
2576115760Sscottl					printf("Error probing container %d\n",
257783114Sscottl					      i);
257883114Sscottl					continue;
257983114Sscottl				}
258095350Sscottl				mir = (struct aac_mntinforesp *)&fib->data[0];
2581115760Sscottl				/* XXX Need to check if count changed */
2582115760Sscottl				count = mir->MntRespCount;
258383114Sscottl				/*
258483114Sscottl				 * Check the container against our list.
258583114Sscottl				 * co->co_found was already set to 0 in a
258683114Sscottl				 * previous run.
258783114Sscottl				 */
258895350Sscottl				if ((mir->Status == ST_OK) &&
258995350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
259083114Sscottl					found = 0;
259183114Sscottl					TAILQ_FOREACH(co,
259283114Sscottl						      &sc->aac_container_tqh,
259383114Sscottl						      co_link) {
259483114Sscottl						if (co->co_mntobj.ObjectId ==
259595350Sscottl						    mir->MntTable[0].ObjectId) {
259683114Sscottl							co->co_found = 1;
259783114Sscottl							found = 1;
259883114Sscottl							break;
259983114Sscottl						}
260083114Sscottl					}
260183114Sscottl					/*
260283114Sscottl					 * If the container matched, continue
260383114Sscottl					 * in the list.
260483114Sscottl					 */
260583114Sscottl					if (found) {
260683114Sscottl						i++;
260783114Sscottl						continue;
260883114Sscottl					}
260983114Sscottl
261083114Sscottl					/*
261183114Sscottl					 * This is a new container.  Do all the
2612110426Sscottl					 * appropriate things to set it up.
2613110426Sscottl					 */
261495350Sscottl					aac_add_container(sc, mir, 1);
261583114Sscottl					added = 1;
261683114Sscottl				}
261783114Sscottl				i++;
2618115760Sscottl			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
261995350Sscottl			aac_release_sync_fib(sc);
262083114Sscottl
262183114Sscottl			/*
262283114Sscottl			 * Go through our list of containers and see which ones
262383114Sscottl			 * were not marked 'found'.  Since the controller didn't
262483114Sscottl			 * list them they must have been deleted.  Do the
262583114Sscottl			 * appropriate steps to destroy the device.  Also reset
262683114Sscottl			 * the co->co_found field.
262783114Sscottl			 */
262883114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
262983114Sscottl			while (co != NULL) {
263083114Sscottl				if (co->co_found == 0) {
263183114Sscottl					device_delete_child(sc->aac_dev,
263283114Sscottl							    co->co_disk);
263383114Sscottl					co_next = TAILQ_NEXT(co, co_link);
263487310Sscottl					AAC_LOCK_ACQUIRE(&sc->
263583114Sscottl							aac_container_lock);
263683114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
263783114Sscottl						     co_link);
263883114Sscottl					AAC_LOCK_RELEASE(&sc->
263983114Sscottl							 aac_container_lock);
264083114Sscottl					FREE(co, M_AACBUF);
264183114Sscottl					co = co_next;
264283114Sscottl				} else {
264383114Sscottl					co->co_found = 0;
264483114Sscottl					co = TAILQ_NEXT(co, co_link);
264583114Sscottl				}
264682527Sscottl			}
264782527Sscottl
264883114Sscottl			/* Attach the newly created containers */
264983114Sscottl			if (added)
265083114Sscottl				bus_generic_attach(sc->aac_dev);
265183114Sscottl
2652105528Sphk			break;
265382527Sscottl
265483114Sscottl		default:
265583114Sscottl			break;
265682527Sscottl		}
265782527Sscottl
265882527Sscottl	default:
265983114Sscottl		break;
266082527Sscottl	}
266182527Sscottl
266283114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
266387310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
266483114Sscottl	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
266583114Sscottl	if (next != sc->aac_aifq_tail) {
266683114Sscottl		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
266787183Sscottl		sc->aac_aifq_head = next;
266887183Sscottl
266987183Sscottl		/* On the off chance that someone is sleeping for an aif... */
267087183Sscottl		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
267187183Sscottl			wakeup(sc->aac_aifq);
267287183Sscottl		/* Wakeup any poll()ers */
2673122352Stanimura		selwakeuppri(&sc->rcv_select, PRIBIO);
267483114Sscottl	}
267587183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
267682527Sscottl
267783114Sscottl	return;
267865793Smsmith}
267965793Smsmith
268083114Sscottl/*
268170393Smsmith * Return the Revision of the driver to userspace and check to see if the
268282527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
268382527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
268482527Sscottl * returning what the card reported.
268565793Smsmith */
268665793Smsmithstatic int
268781189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
268865793Smsmith{
268983114Sscottl	struct aac_rev_check rev_check;
269083114Sscottl	struct aac_rev_check_resp rev_check_resp;
269183114Sscottl	int error = 0;
269265793Smsmith
269383114Sscottl	debug_called(2);
269465793Smsmith
269583114Sscottl	/*
269683114Sscottl	 * Copyin the revision struct from userspace
269783114Sscottl	 */
269883114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
269981082Sscottl			sizeof(struct aac_rev_check))) != 0) {
270083114Sscottl		return error;
270183114Sscottl	}
270265793Smsmith
270383114Sscottl	debug(2, "Userland revision= %d\n",
270483114Sscottl	      rev_check.callingRevision.buildNumber);
270565793Smsmith
270683114Sscottl	/*
270783114Sscottl	 * Doctor up the response struct.
270883114Sscottl	 */
270983114Sscottl	rev_check_resp.possiblyCompatible = 1;
271083114Sscottl	rev_check_resp.adapterSWRevision.external.ul =
271183114Sscottl	    sc->aac_revision.external.ul;
271283114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
271383114Sscottl	    sc->aac_revision.buildNumber;
271465793Smsmith
271583114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
271683114Sscottl			sizeof(struct aac_rev_check_resp)));
271765793Smsmith}
271865793Smsmith
271983114Sscottl/*
272065793Smsmith * Pass the caller the next AIF in their queue
272165793Smsmith */
272265793Smsmithstatic int
272381189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
272465793Smsmith{
272583114Sscottl	struct get_adapter_fib_ioctl agf;
2726111691Sscottl	int error;
272765793Smsmith
272883114Sscottl	debug_called(2);
272965793Smsmith
273083114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
273165793Smsmith
273283114Sscottl		/*
273383114Sscottl		 * Check the magic number that we gave the caller.
273483114Sscottl		 */
2735119146Sscottl		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
273683114Sscottl			error = EFAULT;
273783114Sscottl		} else {
273881189Sscottl			error = aac_return_aif(sc, agf.AifFib);
273983114Sscottl			if ((error == EAGAIN) && (agf.Wait)) {
274083114Sscottl				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
274183114Sscottl				while (error == EAGAIN) {
274283114Sscottl					error = tsleep(sc->aac_aifq, PRIBIO |
274383114Sscottl						       PCATCH, "aacaif", 0);
274483114Sscottl					if (error == 0)
274583114Sscottl						error = aac_return_aif(sc,
274683114Sscottl						    agf.AifFib);
274783114Sscottl				}
274883114Sscottl				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
274983114Sscottl			}
275065793Smsmith		}
275165793Smsmith	}
275283114Sscottl	return(error);
275365793Smsmith}
275465793Smsmith
275583114Sscottl/*
275670393Smsmith * Hand the next AIF off the top of the queue out to userspace.
275770393Smsmith */
275870393Smsmithstatic int
275981189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr)
276070393Smsmith{
2761121173Sscottl	int next, error;
276270393Smsmith
276383114Sscottl	debug_called(2);
276470393Smsmith
276587310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_aifq_lock);
276683114Sscottl	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
2767121173Sscottl		AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
2768121173Sscottl		return (EAGAIN);
276983114Sscottl	}
2770121173Sscottl
2771121173Sscottl	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
2772121173Sscottl	error = copyout(&sc->aac_aifq[next], uptr,
2773121173Sscottl			sizeof(struct aac_aif_command));
2774121173Sscottl	if (error)
2775121173Sscottl		device_printf(sc->aac_dev,
2776121173Sscottl		    "aac_return_aif: copyout returned %d\n", error);
2777121173Sscottl	else
2778121173Sscottl		sc->aac_aifq_tail = next;
2779121173Sscottl
278087183Sscottl	AAC_LOCK_RELEASE(&sc->aac_aifq_lock);
278183114Sscottl	return(error);
278270393Smsmith}
278382527Sscottl
278483114Sscottl/*
278582527Sscottl * Give the userland some information about the container.  The AAC arch
278682527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
278782527Sscottl * the containers to have b:t:l numbers.  Fake it.
278882527Sscottl */
278982527Sscottlstatic int
279082527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
279182527Sscottl{
279283114Sscottl	struct aac_query_disk query_disk;
279383114Sscottl	struct aac_container *co;
279483114Sscottl	struct aac_disk	*disk;
279583114Sscottl	int error, id;
279682527Sscottl
279783114Sscottl	debug_called(2);
279882527Sscottl
279983114Sscottl	disk = NULL;
280082527Sscottl
280183114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
280283114Sscottl		       sizeof(struct aac_query_disk));
280383114Sscottl	if (error)
280483114Sscottl		return (error);
280582527Sscottl
280683114Sscottl	id = query_disk.ContainerNumber;
280783114Sscottl	if (id == -1)
280883114Sscottl		return (EINVAL);
280982527Sscottl
281087310Sscottl	AAC_LOCK_ACQUIRE(&sc->aac_container_lock);
281183114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
281283114Sscottl		if (co->co_mntobj.ObjectId == id)
281383114Sscottl			break;
281483114Sscottl		}
281582527Sscottl
2816105528Sphk	if (co == NULL) {
281783114Sscottl			query_disk.Valid = 0;
281883114Sscottl			query_disk.Locked = 0;
281983114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
2820105528Sphk	} else {
2821105528Sphk		disk = device_get_softc(co->co_disk);
2822105528Sphk		query_disk.Valid = 1;
2823105528Sphk		query_disk.Locked =
2824105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
2825105528Sphk		query_disk.Deleted = 0;
2826105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
2827105528Sphk		query_disk.Target = disk->unit;
2828105528Sphk		query_disk.Lun = 0;
2829105528Sphk		query_disk.UnMapped = 0;
2830111525Sscottl		sprintf(&query_disk.diskDeviceName[0], "%s%d",
2831125975Sphk		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
2832105528Sphk	}
283383114Sscottl	AAC_LOCK_RELEASE(&sc->aac_container_lock);
283482527Sscottl
283583114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
283683114Sscottl			sizeof(struct aac_query_disk));
283783114Sscottl
283883114Sscottl	return (error);
283982527Sscottl}
284082527Sscottl
284195536Sscottlstatic void
284295536Sscottlaac_get_bus_info(struct aac_softc *sc)
284395536Sscottl{
284495536Sscottl	struct aac_fib *fib;
284595536Sscottl	struct aac_ctcfg *c_cmd;
284695536Sscottl	struct aac_ctcfg_resp *c_resp;
284795536Sscottl	struct aac_vmioctl *vmi;
284895536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
284995536Sscottl	struct aac_getbusinf businfo;
2850110426Sscottl	struct aac_sim *caminf;
285195536Sscottl	device_t child;
285295536Sscottl	int i, found, error;
285395536Sscottl
2854130006Sscottl	aac_alloc_sync_fib(sc, &fib);
285595536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
285695966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
285795536Sscottl
285895536Sscottl	c_cmd->Command = VM_ContainerConfig;
285995536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
286095536Sscottl	c_cmd->param = 0;
286195536Sscottl
286295536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
286395536Sscottl	    sizeof(struct aac_ctcfg));
286495536Sscottl	if (error) {
286595536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
286695536Sscottl		    "VM_ContainerConfig command\n", error);
286795536Sscottl		aac_release_sync_fib(sc);
286895536Sscottl		return;
286995536Sscottl	}
287095536Sscottl
287195536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
287295536Sscottl	if (c_resp->Status != ST_OK) {
287395536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
287495536Sscottl		    c_resp->Status);
287595536Sscottl		aac_release_sync_fib(sc);
287695536Sscottl		return;
287795536Sscottl	}
287895536Sscottl
287995536Sscottl	sc->scsi_method_id = c_resp->param;
288095536Sscottl
288195536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
288295966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
288395966Sscottl
288495536Sscottl	vmi->Command = VM_Ioctl;
288595536Sscottl	vmi->ObjType = FT_DRIVE;
288695536Sscottl	vmi->MethId = sc->scsi_method_id;
288795536Sscottl	vmi->ObjId = 0;
288895536Sscottl	vmi->IoctlCmd = GetBusInfo;
288995536Sscottl
289095536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
289195536Sscottl	    sizeof(struct aac_vmioctl));
289295536Sscottl	if (error) {
289395536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
289495536Sscottl		    error);
289595536Sscottl		aac_release_sync_fib(sc);
289695536Sscottl		return;
289795536Sscottl	}
289895536Sscottl
289995536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
290095536Sscottl	if (vmi_resp->Status != ST_OK) {
290195536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
290295536Sscottl		    vmi_resp->Status);
290395536Sscottl		aac_release_sync_fib(sc);
290495536Sscottl		return;
290595536Sscottl	}
290695536Sscottl
290795536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
290895536Sscottl	aac_release_sync_fib(sc);
290995536Sscottl
291095536Sscottl	found = 0;
291195536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
291295536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
291395536Sscottl			continue;
291495536Sscottl
2915110428Sscottl		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
2916110428Sscottl		    M_AACBUF, M_NOWAIT | M_ZERO);
291795536Sscottl		if (caminf == NULL)
291895536Sscottl			continue;
291995536Sscottl
292095536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
292195536Sscottl		if (child == NULL) {
292295536Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
292395536Sscottl			continue;
292495536Sscottl		}
292595536Sscottl
292695536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
292795536Sscottl		caminf->BusNumber = i;
292895536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
292995536Sscottl		caminf->aac_sc = sc;
2930110432Sscottl		caminf->sim_dev = child;
293195536Sscottl
293295536Sscottl		device_set_ivars(child, caminf);
293395536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
2934110426Sscottl		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
293595536Sscottl
293695536Sscottl		found = 1;
293795536Sscottl	}
293895536Sscottl
293995536Sscottl	if (found)
294095536Sscottl		bus_generic_attach(sc->aac_dev);
294195536Sscottl
294295536Sscottl	return;
294395536Sscottl}
2944