aac.c revision 135289
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 135289 2004-09-16 02:37:40Z scottl $");
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
164133606Sscottl/* Rocket/MIPS interface */
165133606Sscottlstatic int	aac_rkt_get_fwstatus(struct aac_softc *sc);
166133606Sscottlstatic void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
167133606Sscottlstatic int	aac_rkt_get_istatus(struct aac_softc *sc);
168133606Sscottlstatic void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
169133606Sscottlstatic void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
170133606Sscottl				    u_int32_t arg0, u_int32_t arg1,
171133606Sscottl				    u_int32_t arg2, u_int32_t arg3);
172133606Sscottlstatic int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
173133606Sscottlstatic void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
174133606Sscottl
175133606Sscottlstruct aac_interface aac_rkt_interface = {
176133606Sscottl	aac_rkt_get_fwstatus,
177133606Sscottl	aac_rkt_qnotify,
178133606Sscottl	aac_rkt_get_istatus,
179133606Sscottl	aac_rkt_clear_istatus,
180133606Sscottl	aac_rkt_set_mailbox,
181133606Sscottl	aac_rkt_get_mailbox,
182133606Sscottl	aac_rkt_set_interrupts
183133606Sscottl};
184133606Sscottl
18565793Smsmith/* Debugging and Diagnostics */
18665793Smsmithstatic void	aac_describe_controller(struct aac_softc *sc);
18782567Sscottlstatic char	*aac_describe_code(struct aac_code_lookup *table,
18881082Sscottl				   u_int32_t code);
18965793Smsmith
19065793Smsmith/* Management Interface */
19165793Smsmithstatic d_open_t		aac_open;
19265793Smsmithstatic d_close_t	aac_close;
19365793Smsmithstatic d_ioctl_t	aac_ioctl;
19487183Sscottlstatic d_poll_t		aac_poll;
19581082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
19681082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
19783114Sscottl					   struct aac_fib *fib);
19881189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
19981189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
20081189Sscottlstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
20182527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
20265793Smsmith
20365793Smsmithstatic struct cdevsw aac_cdevsw = {
204126080Sphk	.d_version =	D_VERSION,
205126080Sphk	.d_flags =	D_NEEDGIANT,
206111815Sphk	.d_open =	aac_open,
207111815Sphk	.d_close =	aac_close,
208111815Sphk	.d_ioctl =	aac_ioctl,
209111815Sphk	.d_poll =	aac_poll,
210111815Sphk	.d_name =	"aac",
21165793Smsmith};
21265793Smsmith
21382527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
21482527Sscottl
21581154Sscottl/* sysctl node */
21681154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
21781154Sscottl
21883114Sscottl/*
21983114Sscottl * Device Interface
22083114Sscottl */
22165793Smsmith
22283114Sscottl/*
22365793Smsmith * Initialise the controller and softc
22465793Smsmith */
22565793Smsmithint
22665793Smsmithaac_attach(struct aac_softc *sc)
22765793Smsmith{
22883114Sscottl	int error, unit;
22965793Smsmith
23083114Sscottl	debug_called(1);
23165793Smsmith
23283114Sscottl	/*
23383114Sscottl	 * Initialise per-controller queues.
23483114Sscottl	 */
23583114Sscottl	aac_initq_free(sc);
23683114Sscottl	aac_initq_ready(sc);
23783114Sscottl	aac_initq_busy(sc);
23883114Sscottl	aac_initq_bio(sc);
23965793Smsmith
24083114Sscottl	/*
24183114Sscottl	 * Initialise command-completion task.
24283114Sscottl	 */
24383114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
24465793Smsmith
24583114Sscottl	/* disable interrupts before we enable anything */
24683114Sscottl	AAC_MASK_INTERRUPTS(sc);
24765793Smsmith
24883114Sscottl	/* mark controller as suspended until we get ourselves organised */
24983114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
25065793Smsmith
25183114Sscottl	/*
25290275Sscottl	 * Check that the firmware on the card is supported.
25390275Sscottl	 */
25490275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
25590275Sscottl		return(error);
25690275Sscottl
257117126Sscottl	/*
258117126Sscottl	 * Initialize locks
259117126Sscottl	 */
260133540Sscottl	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
261133540Sscottl	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
262133540Sscottl	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
263117126Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
26495350Sscottl
265121173Sscottl	/* Initialize the local AIF queue pointers */
266121173Sscottl	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
267117126Sscottl
26883114Sscottl	/*
26983114Sscottl	 * Initialise the adapter.
27083114Sscottl	 */
27183114Sscottl	if ((error = aac_init(sc)) != 0)
27283114Sscottl		return(error);
27365793Smsmith
27483114Sscottl	/*
27583114Sscottl	 * Print a little information about the controller.
27683114Sscottl	 */
27783114Sscottl	aac_describe_controller(sc);
27865793Smsmith
27983114Sscottl	/*
280111532Sscottl	 * Register to probe our containers later.
28187183Sscottl	 */
28283114Sscottl	sc->aac_ich.ich_func = aac_startup;
28383114Sscottl	sc->aac_ich.ich_arg = sc;
28483114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
28583114Sscottl		device_printf(sc->aac_dev,
28683114Sscottl			      "can't establish configuration hook\n");
28783114Sscottl		return(ENXIO);
28883114Sscottl	}
28965793Smsmith
29083114Sscottl	/*
29183114Sscottl	 * Make the control device.
29283114Sscottl	 */
29383114Sscottl	unit = device_get_unit(sc->aac_dev);
294108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
295108329Srwatson				 0640, "aac%d", unit);
29683114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
29783114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
29883114Sscottl	sc->aac_dev_t->si_drv1 = sc;
29965793Smsmith
30083114Sscottl	/* Create the AIF thread */
301110426Sscottl	if (kthread_create((void(*)(void *))aac_command_thread, sc,
302104354Sscottl			   &sc->aifthread, 0, 0, "aac%daif", unit))
30383114Sscottl		panic("Could not create AIF thread\n");
30482527Sscottl
30583114Sscottl	/* Register the shutdown method to only be called post-dump */
306110427Sscottl	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
307110427Sscottl	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
308110427Sscottl		device_printf(sc->aac_dev,
309110427Sscottl			      "shutdown event registration failed\n");
31082527Sscottl
31195536Sscottl	/* Register with CAM for the non-DASD devices */
312112679Sscottl	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
313110426Sscottl		TAILQ_INIT(&sc->aac_sim_tqh);
31495536Sscottl		aac_get_bus_info(sc);
315110426Sscottl	}
31695536Sscottl
31783114Sscottl	return(0);
31865793Smsmith}
31965793Smsmith
32083114Sscottl/*
32165793Smsmith * Probe for containers, create disks.
32265793Smsmith */
32365793Smsmithstatic void
32465793Smsmithaac_startup(void *arg)
32565793Smsmith{
32683114Sscottl	struct aac_softc *sc;
32795350Sscottl	struct aac_fib *fib;
32895350Sscottl	struct aac_mntinfo *mi;
32995350Sscottl	struct aac_mntinforesp *mir = NULL;
330115760Sscottl	int count = 0, i = 0;
33165793Smsmith
33283114Sscottl	debug_called(1);
33365793Smsmith
33483114Sscottl	sc = (struct aac_softc *)arg;
33565793Smsmith
33683114Sscottl	/* disconnect ourselves from the intrhook chain */
33783114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
33865793Smsmith
339130006Sscottl	aac_alloc_sync_fib(sc, &fib);
34095350Sscottl	mi = (struct aac_mntinfo *)&fib->data[0];
34195350Sscottl
34283114Sscottl	/* loop over possible containers */
34383114Sscottl	do {
34483114Sscottl		/* request information on this container */
34595966Sscottl		bzero(mi, sizeof(struct aac_mntinfo));
34695966Sscottl		mi->Command = VM_NameServe;
34795966Sscottl		mi->MntType = FT_FILESYS;
34895350Sscottl		mi->MntCount = i;
34995350Sscottl		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
35095350Sscottl				 sizeof(struct aac_mntinfo))) {
351115760Sscottl			printf("error probing container %d", i);
35283114Sscottl			continue;
35383114Sscottl		}
35465793Smsmith
35595350Sscottl		mir = (struct aac_mntinforesp *)&fib->data[0];
356115760Sscottl		/* XXX Need to check if count changed */
357115760Sscottl		count = mir->MntRespCount;
35895350Sscottl		aac_add_container(sc, mir, 0);
35983114Sscottl		i++;
360115760Sscottl	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
36165793Smsmith
36295350Sscottl	aac_release_sync_fib(sc);
36395350Sscottl
36483114Sscottl	/* poke the bus to actually attach the child devices */
36583114Sscottl	if (bus_generic_attach(sc->aac_dev))
36683114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
36765793Smsmith
36883114Sscottl	/* mark the controller up */
36983114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
37070393Smsmith
37183114Sscottl	/* enable interrupts now */
37283114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
37365793Smsmith}
37465793Smsmith
37583114Sscottl/*
37683114Sscottl * Create a device to respresent a new container
37783114Sscottl */
37883114Sscottlstatic void
37995350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
38083114Sscottl{
38183114Sscottl	struct aac_container *co;
38283114Sscottl	device_t child;
38383114Sscottl
38483114Sscottl	/*
38583114Sscottl	 * Check container volume type for validity.  Note that many of
38683114Sscottl	 * the possible types may never show up.
38783114Sscottl	 */
38883114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
389110428Sscottl		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
390110428Sscottl		       M_NOWAIT | M_ZERO);
39183114Sscottl		if (co == NULL)
39283114Sscottl			panic("Out of memory?!\n");
39383114Sscottl		debug(1, "id %x  name '%.16s'  size %u  type %d",
39483114Sscottl		      mir->MntTable[0].ObjectId,
39583114Sscottl		      mir->MntTable[0].FileSystemName,
39683114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
39783114Sscottl
39895536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
39983114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
40083114Sscottl		else
40183114Sscottl			device_set_ivars(child, co);
40283114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
40383114Sscottl				mir->MntTable[0].VolType));
40483114Sscottl		co->co_disk = child;
40583114Sscottl		co->co_found = f;
40683114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
40783114Sscottl		      sizeof(struct aac_mntobj));
408133540Sscottl		mtx_lock(&sc->aac_container_lock);
40983114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
410133540Sscottl		mtx_unlock(&sc->aac_container_lock);
41183114Sscottl	}
41283114Sscottl}
41383114Sscottl
41483114Sscottl/*
41565793Smsmith * Free all of the resources associated with (sc)
41665793Smsmith *
41765793Smsmith * Should not be called if the controller is active.
41865793Smsmith */
41965793Smsmithvoid
42065793Smsmithaac_free(struct aac_softc *sc)
42165793Smsmith{
422110604Sscottl
42383114Sscottl	debug_called(1);
42465793Smsmith
42583114Sscottl	/* remove the control device */
42683114Sscottl	if (sc->aac_dev_t != NULL)
42783114Sscottl		destroy_dev(sc->aac_dev_t);
42865793Smsmith
42983114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
430111141Sscottl	aac_free_commands(sc);
43183114Sscottl	if (sc->aac_fib_dmat)
43283114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
43365793Smsmith
434110604Sscottl	free(sc->aac_commands, M_AACBUF);
435110604Sscottl
43683114Sscottl	/* destroy the common area */
43783114Sscottl	if (sc->aac_common) {
43883114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
43983114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
44083114Sscottl				sc->aac_common_dmamap);
44183114Sscottl	}
44283114Sscottl	if (sc->aac_common_dmat)
44383114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
44465793Smsmith
44583114Sscottl	/* disconnect the interrupt handler */
44683114Sscottl	if (sc->aac_intr)
44783114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
44883114Sscottl	if (sc->aac_irq != NULL)
44983114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
45083114Sscottl				     sc->aac_irq);
45165793Smsmith
45283114Sscottl	/* destroy data-transfer DMA tag */
45383114Sscottl	if (sc->aac_buffer_dmat)
45483114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
45565793Smsmith
45683114Sscottl	/* destroy the parent DMA tag */
45783114Sscottl	if (sc->aac_parent_dmat)
45883114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
45965793Smsmith
46083114Sscottl	/* release the register window mapping */
46183114Sscottl	if (sc->aac_regs_resource != NULL)
46283114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
46383114Sscottl				     sc->aac_regs_rid, sc->aac_regs_resource);
46465793Smsmith}
46565793Smsmith
46683114Sscottl/*
46765793Smsmith * Disconnect from the controller completely, in preparation for unload.
46865793Smsmith */
46965793Smsmithint
47065793Smsmithaac_detach(device_t dev)
47165793Smsmith{
47283114Sscottl	struct aac_softc *sc;
473110426Sscottl	struct aac_container *co;
474110426Sscottl	struct aac_sim	*sim;
47583114Sscottl	int error;
47665793Smsmith
47783114Sscottl	debug_called(1);
47865793Smsmith
47983114Sscottl	sc = device_get_softc(dev);
48083114Sscottl
48183114Sscottl	if (sc->aac_state & AAC_STATE_OPEN)
482110426Sscottl		return(EBUSY);
48365793Smsmith
484110426Sscottl	/* Remove the child containers */
485110428Sscottl	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
486110426Sscottl		error = device_delete_child(dev, co->co_disk);
487110426Sscottl		if (error)
488110426Sscottl			return (error);
489111196Sscottl		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
490110428Sscottl		free(co, M_AACBUF);
491110426Sscottl	}
492110426Sscottl
493110426Sscottl	/* Remove the CAM SIMs */
494110428Sscottl	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
495110428Sscottl		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
496110426Sscottl		error = device_delete_child(dev, sim->sim_dev);
497110426Sscottl		if (error)
498110426Sscottl			return (error);
499110428Sscottl		free(sim, M_AACBUF);
500110426Sscottl	}
501110426Sscottl
50283114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
50383114Sscottl		sc->aifflags |= AAC_AIFFLAGS_EXIT;
50483114Sscottl		wakeup(sc->aifthread);
50583114Sscottl		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
50683114Sscottl	}
50782527Sscottl
50883114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
50983114Sscottl		panic("Cannot shutdown AIF thread\n");
51082527Sscottl
51183114Sscottl	if ((error = aac_shutdown(dev)))
51283114Sscottl		return(error);
51365793Smsmith
514110427Sscottl	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
515110427Sscottl
51683114Sscottl	aac_free(sc);
51765793Smsmith
518133542Sscottl	mtx_destroy(&sc->aac_aifq_lock);
519133542Sscottl	mtx_destroy(&sc->aac_io_lock);
520133542Sscottl	mtx_destroy(&sc->aac_container_lock);
521133542Sscottl
52283114Sscottl	return(0);
52365793Smsmith}
52465793Smsmith
52583114Sscottl/*
52665793Smsmith * Bring the controller down to a dormant state and detach all child devices.
52765793Smsmith *
52865793Smsmith * This function is called before detach or system shutdown.
52965793Smsmith *
53070393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
53165793Smsmith * allow shutdown if any device is open.
53265793Smsmith */
53365793Smsmithint
53465793Smsmithaac_shutdown(device_t dev)
53565793Smsmith{
53683114Sscottl	struct aac_softc *sc;
53795350Sscottl	struct aac_fib *fib;
53895350Sscottl	struct aac_close_command *cc;
53965793Smsmith
54083114Sscottl	debug_called(1);
54165793Smsmith
54283114Sscottl	sc = device_get_softc(dev);
54365793Smsmith
54483114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
54565793Smsmith
54683114Sscottl	/*
54783114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
54883114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
54983114Sscottl	 * We've been closed and all I/O completed already
55082527Sscottl	 */
55183114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
55283114Sscottl
553130006Sscottl	aac_alloc_sync_fib(sc, &fib);
55495350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
55595350Sscottl
55695966Sscottl	bzero(cc, sizeof(struct aac_close_command));
55795350Sscottl	cc->Command = VM_CloseAll;
55895350Sscottl	cc->ContainerId = 0xffffffff;
55995350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
56095350Sscottl	    sizeof(struct aac_close_command)))
56183114Sscottl		printf("FAILED.\n");
562110426Sscottl	else
563110426Sscottl		printf("done\n");
564110426Sscottl#if 0
56583114Sscottl	else {
56695350Sscottl		fib->data[0] = 0;
56783114Sscottl		/*
56883114Sscottl		 * XXX Issuing this command to the controller makes it shut down
56983114Sscottl		 * but also keeps it from coming back up without a reset of the
57083114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
57183114Sscottl		 * driver module with the intent to reload it later.
57283114Sscottl		 */
57395350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
57495350Sscottl		    fib, 1)) {
57583114Sscottl			printf("FAILED.\n");
57683114Sscottl		} else {
57783114Sscottl			printf("done.\n");
57883114Sscottl		}
57965793Smsmith	}
580110426Sscottl#endif
58165793Smsmith
58283114Sscottl	AAC_MASK_INTERRUPTS(sc);
583133539Sscottl	aac_release_sync_fib(sc);
58465793Smsmith
58583114Sscottl	return(0);
58665793Smsmith}
58765793Smsmith
58883114Sscottl/*
58965793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
59065793Smsmith */
59165793Smsmithint
59265793Smsmithaac_suspend(device_t dev)
59365793Smsmith{
59483114Sscottl	struct aac_softc *sc;
59565793Smsmith
59683114Sscottl	debug_called(1);
59765793Smsmith
59883114Sscottl	sc = device_get_softc(dev);
59983114Sscottl
60083114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
60183114Sscottl
60283114Sscottl	AAC_MASK_INTERRUPTS(sc);
60383114Sscottl	return(0);
60465793Smsmith}
60565793Smsmith
60683114Sscottl/*
60765793Smsmith * Bring the controller back to a state ready for operation.
60865793Smsmith */
60965793Smsmithint
61065793Smsmithaac_resume(device_t dev)
61165793Smsmith{
61283114Sscottl	struct aac_softc *sc;
61365793Smsmith
61483114Sscottl	debug_called(1);
61583114Sscottl
61683114Sscottl	sc = device_get_softc(dev);
61783114Sscottl
61883114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
61983114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
62083114Sscottl	return(0);
62165793Smsmith}
62265793Smsmith
62383114Sscottl/*
62465793Smsmith * Take an interrupt.
62565793Smsmith */
62665793Smsmithvoid
62765793Smsmithaac_intr(void *arg)
62865793Smsmith{
62983114Sscottl	struct aac_softc *sc;
63083114Sscottl	u_int16_t reason;
63165793Smsmith
63283114Sscottl	debug_called(2);
63365793Smsmith
63483114Sscottl	sc = (struct aac_softc *)arg;
63565793Smsmith
636109088Sscottl	/*
637125225Sscottl	 * Read the status register directly.  This is faster than taking the
638125225Sscottl	 * driver lock and reading the queues directly.  It also saves having
639125225Sscottl	 * to turn parts of the driver lock into a spin mutex, which would be
640125225Sscottl	 * ugly.
641109088Sscottl	 */
642125225Sscottl	reason = AAC_GET_ISTATUS(sc);
643109088Sscottl	AAC_CLEAR_ISTATUS(sc, reason);
64465793Smsmith
645125225Sscottl	/* handle completion processing */
646109088Sscottl	if (reason & AAC_DB_RESPONSE_READY)
647125225Sscottl		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
648109088Sscottl
649125225Sscottl	/* controller wants to talk to us */
650125225Sscottl	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
651125225Sscottl		/*
652125225Sscottl		 * XXX Make sure that we don't get fooled by strange messages
653125225Sscottl		 * that start with a NULL.
654125225Sscottl		 */
655125225Sscottl		if ((reason & AAC_DB_PRINTF) &&
656125225Sscottl		    (sc->aac_common->ac_printf[0] == 0))
657125225Sscottl			sc->aac_common->ac_printf[0] = 32;
65865793Smsmith
659125225Sscottl		/*
660125225Sscottl		 * This might miss doing the actual wakeup.  However, the
661125542Sscottl		 * msleep that this is waking up has a timeout, so it will
662125225Sscottl		 * wake up eventually.  AIFs and printfs are low enough
663125225Sscottl		 * priority that they can handle hanging out for a few seconds
664125225Sscottl		 * if needed.
665125225Sscottl		 */
666125225Sscottl		wakeup(sc->aifthread);
66783114Sscottl	}
668109088Sscottl}
66983114Sscottl
67083114Sscottl/*
67183114Sscottl * Command Processing
67283114Sscottl */
67365793Smsmith
67483114Sscottl/*
67565793Smsmith * Start as much queued I/O as possible on the controller
67665793Smsmith */
67795536Sscottlvoid
67865793Smsmithaac_startio(struct aac_softc *sc)
67965793Smsmith{
68083114Sscottl	struct aac_command *cm;
681129923Sscottl	int error;
68265793Smsmith
68383114Sscottl	debug_called(2);
68465793Smsmith
68583114Sscottl	for (;;) {
68683114Sscottl		/*
687129923Sscottl		 * This flag might be set if the card is out of resources.
688129923Sscottl		 * Checking it here prevents an infinite loop of deferrals.
689129923Sscottl		 */
690129923Sscottl		if (sc->flags & AAC_QUEUE_FRZN)
691129923Sscottl			break;
692129923Sscottl
693129923Sscottl		/*
69483114Sscottl		 * Try to get a command that's been put off for lack of
69583114Sscottl		 * resources
69683114Sscottl		 */
69783114Sscottl		cm = aac_dequeue_ready(sc);
69865793Smsmith
69983114Sscottl		/*
70083114Sscottl		 * Try to build a command off the bio queue (ignore error
70183114Sscottl		 * return)
70283114Sscottl		 */
70383114Sscottl		if (cm == NULL)
70483114Sscottl			aac_bio_command(sc, &cm);
70565793Smsmith
70683114Sscottl		/* nothing to do? */
70783114Sscottl		if (cm == NULL)
70883114Sscottl			break;
70965793Smsmith
710129923Sscottl		/* don't map more than once */
711129923Sscottl		if (cm->cm_flags & AAC_CMD_MAPPED)
712129923Sscottl			panic("aac: command %p already mapped", cm);
713129923Sscottl
714125559Sscottl		/*
715129923Sscottl		 * Set up the command to go to the controller.  If there are no
716129923Sscottl		 * data buffers associated with the command then it can bypass
717129923Sscottl		 * busdma.
718125559Sscottl		 */
719129923Sscottl		if (cm->cm_datalen != 0) {
720129923Sscottl			error = bus_dmamap_load(sc->aac_buffer_dmat,
721129923Sscottl						cm->cm_datamap, cm->cm_data,
722129923Sscottl						cm->cm_datalen,
723129923Sscottl						aac_map_command_sg, cm, 0);
724129923Sscottl			if (error == EINPROGRESS) {
725129923Sscottl				debug(1, "freezing queue\n");
726129923Sscottl				sc->flags |= AAC_QUEUE_FRZN;
727129923Sscottl				error = 0;
728129946Sscottl			} else if (error != 0)
729129923Sscottl				panic("aac_startio: unexpected error %d from "
730129923Sscottl				      "busdma\n", error);
731129923Sscottl		} else
732129923Sscottl			aac_map_command_sg(cm, NULL, 0, 0);
73365793Smsmith	}
73465793Smsmith}
73565793Smsmith
73683114Sscottl/*
73765793Smsmith * Handle notification of one or more FIBs coming from the controller.
73865793Smsmith */
73965793Smsmithstatic void
740110426Sscottlaac_command_thread(struct aac_softc *sc)
74165793Smsmith{
74283114Sscottl	struct aac_fib *fib;
74383114Sscottl	u_int32_t fib_size;
744125225Sscottl	int size, retval;
74565793Smsmith
74683114Sscottl	debug_called(2);
74765793Smsmith
748133540Sscottl	mtx_lock(&sc->aac_io_lock);
749125542Sscottl	sc->aifflags = AAC_AIFFLAGS_RUNNING;
75065793Smsmith
751125542Sscottl	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
75282527Sscottl
753125542Sscottl		retval = 0;
754125542Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
755125542Sscottl			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
756125542Sscottl					"aifthd", AAC_PERIODIC_INTERVAL * hz);
757125542Sscottl
758125225Sscottl		/*
759125225Sscottl		 * First see if any FIBs need to be allocated.  This needs
760125225Sscottl		 * to be called without the driver lock because contigmalloc
761125225Sscottl		 * will grab Giant, and would result in an LOR.
762125225Sscottl		 */
763125225Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
764133540Sscottl			mtx_unlock(&sc->aac_io_lock);
765125225Sscottl			aac_alloc_commands(sc);
766133540Sscottl			mtx_lock(&sc->aac_io_lock);
767125559Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
768125542Sscottl			aac_startio(sc);
769125225Sscottl		}
770125225Sscottl
771125225Sscottl		/*
772125225Sscottl		 * While we're here, check to see if any commands are stuck.
773125225Sscottl		 * This is pretty low-priority, so it's ok if it doesn't
774125225Sscottl		 * always fire.
775125225Sscottl		 */
776125225Sscottl		if (retval == EWOULDBLOCK)
777110426Sscottl			aac_timeout(sc);
778110426Sscottl
779110426Sscottl		/* Check the hardware printf message buffer */
780125225Sscottl		if (sc->aac_common->ac_printf[0] != 0)
781110426Sscottl			aac_print_printf(sc);
782110426Sscottl
783125225Sscottl		/* Also check to see if the adapter has a command for us. */
784125225Sscottl		while (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
785125225Sscottl				       &fib_size, &fib) == 0) {
78683114Sscottl
78783114Sscottl			AAC_PRINT_FIB(sc, fib);
78883114Sscottl
78983114Sscottl			switch (fib->Header.Command) {
79083114Sscottl			case AifRequest:
79183114Sscottl				aac_handle_aif(sc, fib);
79283114Sscottl				break;
79383114Sscottl			default:
79483114Sscottl				device_printf(sc->aac_dev, "unknown command "
79583114Sscottl					      "from controller\n");
79683114Sscottl				break;
79783114Sscottl			}
79882527Sscottl
79983114Sscottl			if ((fib->Header.XferState == 0) ||
80083114Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB))
80183114Sscottl				break;
80282527Sscottl
803110426Sscottl			/* Return the AIF to the controller. */
80483114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
80583114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
80683114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
80782527Sscottl
80883114Sscottl				/* XXX Compute the Size field? */
80983114Sscottl				size = fib->Header.Size;
81083114Sscottl				if (size > sizeof(struct aac_fib)) {
81195536Sscottl					size = sizeof(struct aac_fib);
81283114Sscottl					fib->Header.Size = size;
81383114Sscottl				}
81483114Sscottl				/*
81583114Sscottl				 * Since we did not generate this command, it
81683114Sscottl				 * cannot go through the normal
81783114Sscottl				 * enqueue->startio chain.
81883114Sscottl				 */
81983114Sscottl				aac_enqueue_response(sc,
82083114Sscottl						     AAC_ADAP_NORM_RESP_QUEUE,
82183114Sscottl						     fib);
82283114Sscottl			}
82382527Sscottl		}
82465793Smsmith	}
82583114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
826133540Sscottl	mtx_unlock(&sc->aac_io_lock);
82783114Sscottl	wakeup(sc->aac_dev);
82865793Smsmith
82983114Sscottl	kthread_exit(0);
83065793Smsmith}
83165793Smsmith
83283114Sscottl/*
833111143Sscottl * Process completed commands.
83465793Smsmith */
83565793Smsmithstatic void
836111143Sscottlaac_complete(void *context, int pending)
83765793Smsmith{
838111143Sscottl	struct aac_softc *sc;
83983114Sscottl	struct aac_command *cm;
84083114Sscottl	struct aac_fib *fib;
84183114Sscottl	u_int32_t fib_size;
84265793Smsmith
84383114Sscottl	debug_called(2);
84465793Smsmith
845111143Sscottl	sc = (struct aac_softc *)context;
846111143Sscottl
847133540Sscottl	mtx_lock(&sc->aac_io_lock);
848111532Sscottl
849111143Sscottl	/* pull completed commands off the queue */
85083114Sscottl	for (;;) {
85183114Sscottl		/* look for completed FIBs on our queue */
85283114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
85383114Sscottl				    &fib))
85483114Sscottl			break;	/* nothing to do */
855111143Sscottl
856125574Sscottl		/* get the command, unmap and hand off for processing */
857111152Sscottl		cm = sc->aac_commands + fib->Header.SenderData;
85883114Sscottl		if (cm == NULL) {
85983114Sscottl			AAC_PRINT_FIB(sc, fib);
860111143Sscottl			break;
86183114Sscottl		}
86265793Smsmith
863111143Sscottl		aac_remove_busy(cm);
864125574Sscottl		aac_unmap_command(cm);
86583114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
86683114Sscottl
86783114Sscottl		/* is there a completion handler? */
86883114Sscottl		if (cm->cm_complete != NULL) {
86983114Sscottl			cm->cm_complete(cm);
87083114Sscottl		} else {
87183114Sscottl			/* assume that someone is sleeping on this command */
87283114Sscottl			wakeup(cm);
87383114Sscottl		}
87465793Smsmith	}
87570393Smsmith
87683114Sscottl	/* see if we can start some more I/O */
877117363Sscottl	sc->flags &= ~AAC_QUEUE_FRZN;
87883114Sscottl	aac_startio(sc);
879111532Sscottl
880133540Sscottl	mtx_unlock(&sc->aac_io_lock);
88165793Smsmith}
88265793Smsmith
88383114Sscottl/*
88465793Smsmith * Handle a bio submitted from a disk device.
88565793Smsmith */
88665793Smsmithvoid
88765793Smsmithaac_submit_bio(struct bio *bp)
88865793Smsmith{
88983114Sscottl	struct aac_disk *ad;
89083114Sscottl	struct aac_softc *sc;
89165793Smsmith
89283114Sscottl	debug_called(2);
89365793Smsmith
894111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
89583114Sscottl	sc = ad->ad_controller;
89683114Sscottl
89783114Sscottl	/* queue the BIO and try to get some work done */
89883114Sscottl	aac_enqueue_bio(sc, bp);
89983114Sscottl	aac_startio(sc);
90065793Smsmith}
90165793Smsmith
90283114Sscottl/*
90365793Smsmith * Get a bio and build a command to go with it.
90465793Smsmith */
90565793Smsmithstatic int
90665793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
90765793Smsmith{
90883114Sscottl	struct aac_command *cm;
90983114Sscottl	struct aac_fib *fib;
91083114Sscottl	struct aac_disk *ad;
91183114Sscottl	struct bio *bp;
91265793Smsmith
91383114Sscottl	debug_called(2);
91465793Smsmith
91583114Sscottl	/* get the resources we will need */
91683114Sscottl	cm = NULL;
917125542Sscottl	bp = NULL;
918125542Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
919125542Sscottl		goto fail;
92083114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
92183114Sscottl		goto fail;
92265793Smsmith
92383114Sscottl	/* fill out the command */
92483114Sscottl	cm->cm_data = (void *)bp->bio_data;
92583114Sscottl	cm->cm_datalen = bp->bio_bcount;
92683114Sscottl	cm->cm_complete = aac_bio_complete;
92783114Sscottl	cm->cm_private = bp;
92883114Sscottl	cm->cm_timestamp = time_second;
92983114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
93065793Smsmith
93183114Sscottl	/* build the FIB */
93283114Sscottl	fib = cm->cm_fib;
933112856Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
93483114Sscottl	fib->Header.XferState =
935109088Sscottl		AAC_FIBSTATE_HOSTOWNED   |
936109088Sscottl		AAC_FIBSTATE_INITIALISED |
937109088Sscottl		AAC_FIBSTATE_EMPTY	 |
938109088Sscottl		AAC_FIBSTATE_FROMHOST	 |
939109088Sscottl		AAC_FIBSTATE_REXPECTED   |
940109088Sscottl		AAC_FIBSTATE_NORM	 |
941109088Sscottl		AAC_FIBSTATE_ASYNC	 |
942109088Sscottl		AAC_FIBSTATE_FAST_RESPONSE;
94365793Smsmith
94483114Sscottl	/* build the read/write request */
945111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
946112856Sscottl
947112856Sscottl	if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
948112856Sscottl		fib->Header.Command = ContainerCommand;
949112856Sscottl		if (bp->bio_cmd == BIO_READ) {
950112856Sscottl			struct aac_blockread *br;
951112856Sscottl			br = (struct aac_blockread *)&fib->data[0];
952112856Sscottl			br->Command = VM_CtBlockRead;
953112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
954112856Sscottl			br->BlockNumber = bp->bio_pblkno;
955112856Sscottl			br->ByteCount = bp->bio_bcount;
956112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread);
957112856Sscottl			cm->cm_sgtable = &br->SgMap;
958112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
959112856Sscottl		} else {
960112856Sscottl			struct aac_blockwrite *bw;
961112856Sscottl			bw = (struct aac_blockwrite *)&fib->data[0];
962112856Sscottl			bw->Command = VM_CtBlockWrite;
963112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
964112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
965112856Sscottl			bw->ByteCount = bp->bio_bcount;
966112856Sscottl			bw->Stable = CUNSTABLE;
967112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite);
968112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
969112856Sscottl			cm->cm_sgtable = &bw->SgMap;
970112856Sscottl		}
97183114Sscottl	} else {
972112856Sscottl		fib->Header.Command = ContainerCommand64;
973112856Sscottl		if (bp->bio_cmd == BIO_READ) {
974112856Sscottl			struct aac_blockread64 *br;
975112856Sscottl			br = (struct aac_blockread64 *)&fib->data[0];
976112856Sscottl			br->Command = VM_CtHostRead64;
977112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
978112856Sscottl			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
979112856Sscottl			br->BlockNumber = bp->bio_pblkno;
980112856Sscottl			br->Pad = 0;
981112856Sscottl			br->Flags = 0;
982112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread64);
983112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
984132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
985112856Sscottl		} else {
986112856Sscottl			struct aac_blockwrite64 *bw;
987112856Sscottl			bw = (struct aac_blockwrite64 *)&fib->data[0];
988112856Sscottl			bw->Command = VM_CtHostWrite64;
989112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
990112856Sscottl			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
991112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
992112856Sscottl			bw->Pad = 0;
993112856Sscottl			bw->Flags = 0;
994112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite64);
995112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
996132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
997112856Sscottl		}
99883114Sscottl	}
99965793Smsmith
100083114Sscottl	*cmp = cm;
100183114Sscottl	return(0);
100265793Smsmith
100365793Smsmithfail:
100483114Sscottl	if (bp != NULL)
100583114Sscottl		aac_enqueue_bio(sc, bp);
100683114Sscottl	if (cm != NULL)
100783114Sscottl		aac_release_command(cm);
100883114Sscottl	return(ENOMEM);
100965793Smsmith}
101065793Smsmith
101183114Sscottl/*
101265793Smsmith * Handle a bio-instigated command that has been completed.
101365793Smsmith */
101465793Smsmithstatic void
101565793Smsmithaac_bio_complete(struct aac_command *cm)
101665793Smsmith{
101783114Sscottl	struct aac_blockread_response *brr;
101883114Sscottl	struct aac_blockwrite_response *bwr;
101983114Sscottl	struct bio *bp;
102083114Sscottl	AAC_FSAStatus status;
102165793Smsmith
102283114Sscottl	/* fetch relevant status and then release the command */
102383114Sscottl	bp = (struct bio *)cm->cm_private;
1024111691Sscottl	if (bp->bio_cmd == BIO_READ) {
102583114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
102683114Sscottl		status = brr->Status;
102783114Sscottl	} else {
102883114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
102983114Sscottl		status = bwr->Status;
103083114Sscottl	}
103183114Sscottl	aac_release_command(cm);
103265793Smsmith
103383114Sscottl	/* fix up the bio based on status */
103483114Sscottl	if (status == ST_OK) {
103583114Sscottl		bp->bio_resid = 0;
103683114Sscottl	} else {
103783114Sscottl		bp->bio_error = EIO;
103883114Sscottl		bp->bio_flags |= BIO_ERROR;
103983114Sscottl		/* pass an error string out to the disk layer */
104083114Sscottl		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
104183114Sscottl						    status);
104283114Sscottl	}
104383114Sscottl	aac_biodone(bp);
104465793Smsmith}
104565793Smsmith
104683114Sscottl/*
104765793Smsmith * Submit a command to the controller, return when it completes.
104887183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
104987183Sscottl *     be stuck here forever.  At the same time, signals are not caught
1050128258Sscottl *     because there is a risk that a signal could wakeup the sleep before
1051128258Sscottl *     the card has a chance to complete the command.  Since there is no way
1052128258Sscottl *     to cancel a command that is in progress, we can't protect against the
1053128258Sscottl *     card completing a command late and spamming the command and data
1054128258Sscottl *     memory.  So, we are held hostage until the command completes.
105565793Smsmith */
105665793Smsmithstatic int
1057128258Sscottlaac_wait_command(struct aac_command *cm)
105865793Smsmith{
1059111532Sscottl	struct aac_softc *sc;
1060128258Sscottl	int error;
106165793Smsmith
106283114Sscottl	debug_called(2);
106365793Smsmith
1064111532Sscottl	sc = cm->cm_sc;
1065111532Sscottl
106683114Sscottl	/* Put the command on the ready queue and get things going */
106783114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
106883114Sscottl	aac_enqueue_ready(cm);
1069111532Sscottl	aac_startio(sc);
1070128258Sscottl	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
107183114Sscottl	return(error);
107265793Smsmith}
107365793Smsmith
107483114Sscottl/*
107583114Sscottl *Command Buffer Management
107683114Sscottl */
107765793Smsmith
107883114Sscottl/*
107965793Smsmith * Allocate a command.
108065793Smsmith */
108195536Sscottlint
108265793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
108365793Smsmith{
108483114Sscottl	struct aac_command *cm;
108565793Smsmith
108683114Sscottl	debug_called(3);
108765793Smsmith
1088110604Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL) {
1089112856Sscottl		if (sc->total_fibs < sc->aac_max_fibs) {
1090112856Sscottl			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1091112856Sscottl			wakeup(sc->aifthread);
1092112856Sscottl		}
1093111532Sscottl		return (EBUSY);
1094110604Sscottl	}
109565793Smsmith
109683114Sscottl	*cmp = cm;
109783114Sscottl	return(0);
109870393Smsmith}
109970393Smsmith
110083114Sscottl/*
110170393Smsmith * Release a command back to the freelist.
110270393Smsmith */
110395536Sscottlvoid
110470393Smsmithaac_release_command(struct aac_command *cm)
110570393Smsmith{
110683114Sscottl	debug_called(3);
110770393Smsmith
110883114Sscottl	/* (re)initialise the command/FIB */
110983114Sscottl	cm->cm_sgtable = NULL;
111083114Sscottl	cm->cm_flags = 0;
111183114Sscottl	cm->cm_complete = NULL;
111283114Sscottl	cm->cm_private = NULL;
111383114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
111483114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
111583114Sscottl	cm->cm_fib->Header.Flags = 0;
111683114Sscottl	cm->cm_fib->Header.SenderSize = sizeof(struct aac_fib);
111765793Smsmith
111883114Sscottl	/*
111983114Sscottl	 * These are duplicated in aac_start to cover the case where an
112083114Sscottl	 * intermediate stage may have destroyed them.  They're left
112183114Sscottl	 * initialised here for debugging purposes only.
112283114Sscottl	 */
1123109088Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1124109088Sscottl	cm->cm_fib->Header.SenderData = 0;
112565793Smsmith
112683114Sscottl	aac_enqueue_free(cm);
112765793Smsmith}
112865793Smsmith
112983114Sscottl/*
113070393Smsmith * Map helper for command/FIB allocation.
113165793Smsmith */
113265793Smsmithstatic void
113370393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
113465793Smsmith{
1135111141Sscottl	uint32_t	*fibphys;
113665793Smsmith
1137111141Sscottl	fibphys = (uint32_t *)arg;
113865793Smsmith
113983114Sscottl	debug_called(3);
114083114Sscottl
1141110604Sscottl	*fibphys = segs[0].ds_addr;
114265793Smsmith}
114365793Smsmith
114483114Sscottl/*
114570393Smsmith * Allocate and initialise commands/FIBs for this adapter.
114665793Smsmith */
114770393Smsmithstatic int
114870393Smsmithaac_alloc_commands(struct aac_softc *sc)
114965793Smsmith{
115083114Sscottl	struct aac_command *cm;
1151110604Sscottl	struct aac_fibmap *fm;
1152111141Sscottl	uint32_t fibphys;
1153110604Sscottl	int i, error;
115465793Smsmith
1155112679Sscottl	debug_called(2);
115665793Smsmith
1157112679Sscottl	if (sc->total_fibs + AAC_FIB_COUNT > sc->aac_max_fibs)
1158110604Sscottl		return (ENOMEM);
1159110604Sscottl
1160111141Sscottl	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1161112679Sscottl	if (fm == NULL)
1162112679Sscottl		return (ENOMEM);
1163110604Sscottl
116483114Sscottl	/* allocate the FIBs in DMAable memory and load them */
1165110604Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1166110604Sscottl			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1167110426Sscottl		device_printf(sc->aac_dev,
1168110426Sscottl			      "Not enough contiguous memory available.\n");
1169111141Sscottl		free(fm, M_AACBUF);
1170102602Sscottl		return (ENOMEM);
117183114Sscottl	}
1172109716Sscottl
1173117363Sscottl	/* Ignore errors since this doesn't bounce */
1174117363Sscottl	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1175117363Sscottl			      AAC_FIB_COUNT * sizeof(struct aac_fib),
1176117363Sscottl			      aac_map_command_helper, &fibphys, 0);
1177109716Sscottl
1178109716Sscottl	/* initialise constant fields in the command structure */
1179133540Sscottl	mtx_lock(&sc->aac_io_lock);
1180110604Sscottl	bzero(fm->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
118183114Sscottl	for (i = 0; i < AAC_FIB_COUNT; i++) {
1182111141Sscottl		cm = sc->aac_commands + sc->total_fibs;
1183110604Sscottl		fm->aac_commands = cm;
118483114Sscottl		cm->cm_sc = sc;
1185110604Sscottl		cm->cm_fib = fm->aac_fibs + i;
1186111141Sscottl		cm->cm_fibphys = fibphys + (i * sizeof(struct aac_fib));
1187111152Sscottl		cm->cm_index = sc->total_fibs;
118865793Smsmith
1189110604Sscottl		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1190110604Sscottl					       &cm->cm_datamap)) == 0)
119183114Sscottl			aac_release_command(cm);
1192111141Sscottl		else
1193111141Sscottl			break;
1194111141Sscottl		sc->total_fibs++;
119583114Sscottl	}
1196110604Sscottl
1197111141Sscottl	if (i > 0) {
1198111141Sscottl		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1199112679Sscottl		debug(1, "total_fibs= %d\n", sc->total_fibs);
1200133540Sscottl		mtx_unlock(&sc->aac_io_lock);
1201111141Sscottl		return (0);
1202111141Sscottl	}
1203110604Sscottl
1204133540Sscottl	mtx_unlock(&sc->aac_io_lock);
1205111141Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1206111141Sscottl	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1207111141Sscottl	free(fm, M_AACBUF);
1208111141Sscottl	return (ENOMEM);
120965793Smsmith}
121065793Smsmith
121183114Sscottl/*
121270393Smsmith * Free FIBs owned by this adapter.
121365793Smsmith */
121465793Smsmithstatic void
1215111141Sscottlaac_free_commands(struct aac_softc *sc)
121665793Smsmith{
1217111141Sscottl	struct aac_fibmap *fm;
1218110604Sscottl	struct aac_command *cm;
121983114Sscottl	int i;
122065793Smsmith
122183114Sscottl	debug_called(1);
122265793Smsmith
1223111141Sscottl	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1224111141Sscottl
1225111141Sscottl		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1226111141Sscottl		/*
1227111141Sscottl		 * We check against total_fibs to handle partially
1228111141Sscottl		 * allocated blocks.
1229111141Sscottl		 */
1230111141Sscottl		for (i = 0; i < AAC_FIB_COUNT && sc->total_fibs--; i++) {
1231111141Sscottl			cm = fm->aac_commands + i;
1232111141Sscottl			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1233111141Sscottl		}
1234111141Sscottl		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1235111141Sscottl		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1236111141Sscottl		free(fm, M_AACBUF);
1237110604Sscottl	}
123865793Smsmith}
123965793Smsmith
124083114Sscottl/*
124165793Smsmith * Command-mapping helper function - populate this command's s/g table.
124265793Smsmith */
124365793Smsmithstatic void
124465793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
124565793Smsmith{
1246117363Sscottl	struct aac_softc *sc;
124783114Sscottl	struct aac_command *cm;
124883114Sscottl	struct aac_fib *fib;
124983114Sscottl	int i;
125065793Smsmith
125183114Sscottl	debug_called(3);
125265793Smsmith
125383114Sscottl	cm = (struct aac_command *)arg;
1254117363Sscottl	sc = cm->cm_sc;
125583114Sscottl	fib = cm->cm_fib;
125665793Smsmith
125783114Sscottl	/* copy into the FIB */
1258112856Sscottl	if (cm->cm_sgtable != NULL) {
1259112856Sscottl		if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1260112856Sscottl			struct aac_sg_table *sg;
1261112856Sscottl			sg = cm->cm_sgtable;
1262112856Sscottl			sg->SgCount = nseg;
1263112856Sscottl			for (i = 0; i < nseg; i++) {
1264112856Sscottl				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1265112856Sscottl				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1266112856Sscottl			}
1267112856Sscottl			/* update the FIB size for the s/g count */
1268112856Sscottl			fib->Header.Size += nseg * sizeof(struct aac_sg_entry);
1269112856Sscottl		} else {
1270112856Sscottl			struct aac_sg_table64 *sg;
1271112856Sscottl			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1272112856Sscottl			sg->SgCount = nseg;
1273112856Sscottl			for (i = 0; i < nseg; i++) {
1274112856Sscottl				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1275112856Sscottl				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1276112856Sscottl			}
1277112856Sscottl			/* update the FIB size for the s/g count */
1278112856Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
127983114Sscottl		}
128065793Smsmith	}
128165793Smsmith
1282117363Sscottl	/* Fix up the address values in the FIB.  Use the command array index
1283117363Sscottl	 * instead of a pointer since these fields are only 32 bits.  Shift
1284117363Sscottl	 * the SenderFibAddress over to make room for the fast response bit.
1285117363Sscottl	 */
1286117363Sscottl	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 1);
1287117363Sscottl	cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
128865793Smsmith
1289117363Sscottl	/* save a pointer to the command for speedy reverse-lookup */
1290117363Sscottl	cm->cm_fib->Header.SenderData = cm->cm_index;
129165793Smsmith
1292117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAIN)
1293117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1294117363Sscottl				BUS_DMASYNC_PREREAD);
1295117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAOUT)
1296117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1297117363Sscottl				BUS_DMASYNC_PREWRITE);
1298117363Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
129965793Smsmith
1300129923Sscottl	/* Put the FIB on the outbound queue */
1301125559Sscottl	if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
1302125559Sscottl		aac_unmap_command(cm);
1303129923Sscottl		sc->flags |= AAC_QUEUE_FRZN;
1304117363Sscottl		aac_requeue_ready(cm);
1305125559Sscottl	}
130665793Smsmith
1307117363Sscottl	return;
130865793Smsmith}
130965793Smsmith
131083114Sscottl/*
131165793Smsmith * Unmap a command from controller-visible space.
131265793Smsmith */
131365793Smsmithstatic void
131465793Smsmithaac_unmap_command(struct aac_command *cm)
131565793Smsmith{
131683114Sscottl	struct aac_softc *sc;
131765793Smsmith
131883114Sscottl	debug_called(2);
131965793Smsmith
132083114Sscottl	sc = cm->cm_sc;
132165793Smsmith
132283114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
132383114Sscottl		return;
132465793Smsmith
132583114Sscottl	if (cm->cm_datalen != 0) {
132683114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
132783114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
132883114Sscottl					BUS_DMASYNC_POSTREAD);
132983114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
133083114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
133183114Sscottl					BUS_DMASYNC_POSTWRITE);
133283114Sscottl
133383114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
133483114Sscottl	}
133583114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
133665793Smsmith}
133765793Smsmith
133883114Sscottl/*
133983114Sscottl * Hardware Interface
134083114Sscottl */
134165793Smsmith
134283114Sscottl/*
134365793Smsmith * Initialise the adapter.
134465793Smsmith */
134565793Smsmithstatic void
134665793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
134765793Smsmith{
134883114Sscottl	struct aac_softc *sc;
134965793Smsmith
135083114Sscottl	debug_called(1);
135165793Smsmith
135283114Sscottl	sc = (struct aac_softc *)arg;
135383114Sscottl
135483114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
135565793Smsmith}
135665793Smsmith
135765793Smsmithstatic int
135890275Sscottlaac_check_firmware(struct aac_softc *sc)
135990275Sscottl{
1360112679Sscottl	u_int32_t major, minor, options;
136190275Sscottl
136290275Sscottl	debug_called(1);
136390275Sscottl
1364112679Sscottl	/*
1365112679Sscottl	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1366112679Sscottl	 * firmware version 1.x are not compatible with this driver.
1367112679Sscottl	 */
1368112679Sscottl	if (sc->flags & AAC_FLAGS_PERC2QC) {
136990275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
137090275Sscottl				     NULL)) {
137190275Sscottl			device_printf(sc->aac_dev,
137290275Sscottl				      "Error reading firmware version\n");
137390275Sscottl			return (EIO);
137490275Sscottl		}
137590275Sscottl
137690275Sscottl		/* These numbers are stored as ASCII! */
1377112679Sscottl		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1378112679Sscottl		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
137990275Sscottl		if (major == 1) {
138090275Sscottl			device_printf(sc->aac_dev,
138190275Sscottl			    "Firmware version %d.%d is not supported.\n",
138290275Sscottl			    major, minor);
138390275Sscottl			return (EINVAL);
138490275Sscottl		}
138590275Sscottl	}
138690275Sscottl
1387112679Sscottl	/*
1388112679Sscottl	 * Retrieve the capabilities/supported options word so we know what
1389112679Sscottl	 * work-arounds to enable.
1390112679Sscottl	 */
1391112679Sscottl	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1392112679Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1393112679Sscottl		return (EIO);
1394112679Sscottl	}
1395112679Sscottl	options = AAC_GET_MAILBOX(sc, 1);
1396112679Sscottl	sc->supported_options = options;
1397112679Sscottl
1398112679Sscottl	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1399112679Sscottl	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1400112679Sscottl		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1401112679Sscottl	if (options & AAC_SUPPORTED_NONDASD)
1402112679Sscottl		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1403117363Sscottl	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1404117363Sscottl	     && (sizeof(bus_addr_t) > 4)) {
1405112679Sscottl		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1406112679Sscottl		sc->flags |= AAC_FLAGS_SG_64BIT;
1407112679Sscottl	}
1408112679Sscottl
1409112679Sscottl	/* Check for broken hardware that does a lower number of commands */
1410112679Sscottl	if ((sc->flags & AAC_FLAGS_256FIBS) == 0)
1411112679Sscottl		sc->aac_max_fibs = AAC_MAX_FIBS;
1412112679Sscottl	else
1413112679Sscottl		sc->aac_max_fibs = 256;
1414112679Sscottl
141590275Sscottl	return (0);
141690275Sscottl}
141790275Sscottl
141890275Sscottlstatic int
141965793Smsmithaac_init(struct aac_softc *sc)
142065793Smsmith{
142183114Sscottl	struct aac_adapter_init	*ip;
142283114Sscottl	time_t then;
1423119146Sscottl	u_int32_t code, qoffset;
1424112679Sscottl	int error;
142565793Smsmith
142683114Sscottl	debug_called(1);
142765793Smsmith
142883114Sscottl	/*
142983114Sscottl	 * First wait for the adapter to come ready.
143083114Sscottl	 */
143183114Sscottl	then = time_second;
143283114Sscottl	do {
143383114Sscottl		code = AAC_GET_FWSTATUS(sc);
143483114Sscottl		if (code & AAC_SELF_TEST_FAILED) {
143583114Sscottl			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
143683114Sscottl			return(ENXIO);
143783114Sscottl		}
143883114Sscottl		if (code & AAC_KERNEL_PANIC) {
143983114Sscottl			device_printf(sc->aac_dev,
144083114Sscottl				      "FATAL: controller kernel panic\n");
144183114Sscottl			return(ENXIO);
144283114Sscottl		}
144383114Sscottl		if (time_second > (then + AAC_BOOT_TIMEOUT)) {
144483114Sscottl			device_printf(sc->aac_dev,
144583114Sscottl				      "FATAL: controller not coming ready, "
144683114Sscottl					   "status %x\n", code);
144783114Sscottl			return(ENXIO);
144883114Sscottl		}
144983114Sscottl	} while (!(code & AAC_UP_AND_RUNNING));
145083114Sscottl
1451112679Sscottl	error = ENOMEM;
145283114Sscottl	/*
1453112679Sscottl	 * Create DMA tag for mapping buffers into controller-addressable space.
1454112679Sscottl	 */
1455112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1456112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1457112679Sscottl			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1458112679Sscottl			       BUS_SPACE_MAXADDR :
1459112679Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1460112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1461112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1462112679Sscottl			       MAXBSIZE,		/* maxsize */
1463112679Sscottl			       AAC_MAXSGENTRIES,	/* nsegments */
1464112679Sscottl			       MAXBSIZE,		/* maxsegsize */
1465112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1466117126Sscottl			       busdma_lock_mutex,	/* lockfunc */
1467117126Sscottl			       &sc->aac_io_lock,	/* lockfuncarg */
1468112679Sscottl			       &sc->aac_buffer_dmat)) {
1469112679Sscottl		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1470112679Sscottl		goto out;
1471112679Sscottl	}
1472112679Sscottl
1473112679Sscottl	/*
1474112679Sscottl	 * Create DMA tag for mapping FIBs into controller-addressable space..
1475112679Sscottl	 */
1476112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1477112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1478112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1479112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1480112679Sscottl			       0x7fffffff,		/* lowaddr */
1481112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1482112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1483112679Sscottl			       AAC_FIB_COUNT *
1484112679Sscottl			       sizeof(struct aac_fib),  /* maxsize */
1485112679Sscottl			       1,			/* nsegments */
1486112679Sscottl			       AAC_FIB_COUNT *
1487112679Sscottl			       sizeof(struct aac_fib),	/* maxsegsize */
1488112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1489117126Sscottl			       NULL, NULL,		/* No locking needed */
1490112679Sscottl			       &sc->aac_fib_dmat)) {
1491112679Sscottl		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1492112679Sscottl		goto out;
1493112679Sscottl	}
1494112679Sscottl
1495112679Sscottl	/*
149683114Sscottl	 * Create DMA tag for the common structure and allocate it.
149783114Sscottl	 */
149883114Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
149995536Sscottl			       1, 0,			/* algnmnt, boundary */
1500112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1501112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1502112679Sscottl			       0x7fffffff,		/* lowaddr */
150383114Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
150483114Sscottl			       NULL, NULL, 		/* filter, filterarg */
1505110604Sscottl			       8192 + sizeof(struct aac_common), /* maxsize */
150683114Sscottl			       1,			/* nsegments */
150783114Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1508112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1509117126Sscottl			       NULL, NULL,		/* No locking needed */
151083114Sscottl			       &sc->aac_common_dmat)) {
151183114Sscottl		device_printf(sc->aac_dev,
151283114Sscottl			      "can't allocate common structure DMA tag\n");
1513112679Sscottl		goto out;
151465793Smsmith	}
151583114Sscottl	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
151683114Sscottl			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
151783114Sscottl		device_printf(sc->aac_dev, "can't allocate common structure\n");
1518112679Sscottl		goto out;
151965793Smsmith	}
1520110604Sscottl
1521110604Sscottl	/*
1522110604Sscottl	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1523110604Sscottl	 * below address 8192 in physical memory.
1524110604Sscottl	 * XXX If the padding is not needed, can it be put to use instead
1525110604Sscottl	 * of ignored?
1526110604Sscottl	 */
1527117363Sscottl	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1528110604Sscottl			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1529110604Sscottl			aac_common_map, sc, 0);
1530110604Sscottl
1531110604Sscottl	if (sc->aac_common_busaddr < 8192) {
1532132771Skan		sc->aac_common = (struct aac_common *)
1533132771Skan		    ((uint8_t *)sc->aac_common + 8192);
1534110604Sscottl		sc->aac_common_busaddr += 8192;
1535110604Sscottl	}
153683114Sscottl	bzero(sc->aac_common, sizeof(*sc->aac_common));
1537110604Sscottl
1538110604Sscottl	/* Allocate some FIBs and associated command structs */
1539110604Sscottl	TAILQ_INIT(&sc->aac_fibmap_tqh);
1540110604Sscottl	sc->aac_commands = malloc(AAC_MAX_FIBS * sizeof(struct aac_command),
1541111141Sscottl				  M_AACBUF, M_WAITOK|M_ZERO);
1542111141Sscottl	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1543110604Sscottl		if (aac_alloc_commands(sc) != 0)
1544110604Sscottl			break;
1545110604Sscottl	}
1546110604Sscottl	if (sc->total_fibs == 0)
1547112679Sscottl		goto out;
154883114Sscottl
154983114Sscottl	/*
155083114Sscottl	 * Fill in the init structure.  This tells the adapter about the
155183114Sscottl	 * physical location of various important shared data structures.
155283114Sscottl	 */
155383114Sscottl	ip = &sc->aac_common->ac_init;
155483114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1555109088Sscottl	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
155665793Smsmith
155783114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
155883114Sscottl					 offsetof(struct aac_common, ac_fibs);
1559114151Sscottl	ip->AdapterFibsVirtualAddress = 0;
156083114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
156183114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
156265793Smsmith
156383114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
156483114Sscottl				  offsetof(struct aac_common, ac_printf);
156583114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
156665793Smsmith
1567117361Sscottl	/*
1568117361Sscottl	 * The adapter assumes that pages are 4K in size, except on some
1569117361Sscottl 	 * broken firmware versions that do the page->byte conversion twice,
1570117361Sscottl	 * therefore 'assuming' that this value is in 16MB units (2^24).
1571117361Sscottl	 * Round up since the granularity is so high.
1572117361Sscottl	 */
1573109088Sscottl	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1574117361Sscottl	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1575117361Sscottl		ip->HostPhysMemPages =
1576117361Sscottl		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1577117362Sscottl	}
157883114Sscottl	ip->HostElapsedSeconds = time_second;	/* reset later if invalid */
157965793Smsmith
158083114Sscottl	/*
158183114Sscottl	 * Initialise FIB queues.  Note that it appears that the layout of the
158283114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
158383114Sscottl	 * adapter, which is only told about the base of the queue index fields.
158483114Sscottl	 *
158583114Sscottl	 * The initial values of the indices are assumed to inform the adapter
158683114Sscottl	 * of the sizes of the respective queues, and theoretically it could
158783114Sscottl	 * work out the entire layout of the queue structures from this.  We
158883114Sscottl	 * take the easy route and just lay this area out like everyone else
158983114Sscottl	 * does.
159083114Sscottl	 *
159183114Sscottl	 * The Linux driver uses a much more complex scheme whereby several
159283114Sscottl	 * header records are kept for each queue.  We use a couple of generic
159383114Sscottl	 * list manipulation functions which 'know' the size of each list by
159483114Sscottl	 * virtue of a table.
159583114Sscottl	 */
1596119146Sscottl	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
1597119625Sscottl	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
1598119625Sscottl	sc->aac_queues =
1599119625Sscottl	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1600119146Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
160165793Smsmith
160283114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
160381082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
160483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
160581082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
160683114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
160781082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
160883114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
160981082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
161083114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
161181082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
161283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
161381082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
161483114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
161581082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
161683114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
161781082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
161883114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
161981082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
162083114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
162181082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
162283114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
162381082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
162483114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
162581082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
162683114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
162781082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
162883114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
162981082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
163083114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
163181082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
163283114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
163381082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
163483114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
163581082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
163683114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
163781082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
163883114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
163981082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
164083114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
164181082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
164283114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
164381082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
164483114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
164581082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
164683114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
164781082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
164883114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
164981082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
165065793Smsmith
165183114Sscottl	/*
165283114Sscottl	 * Do controller-type-specific initialisation
165383114Sscottl	 */
165483114Sscottl	switch (sc->aac_hwif) {
165583114Sscottl	case AAC_HWIF_I960RX:
165683114Sscottl		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
165783114Sscottl		break;
1658133606Sscottl	case AAC_HWIF_RKT:
1659133606Sscottl		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
1660133606Sscottl		break;
1661133606Sscottl	default:
1662133606Sscottl		break;
166383114Sscottl	}
166465793Smsmith
166583114Sscottl	/*
166683114Sscottl	 * Give the init structure to the controller.
166783114Sscottl	 */
166883114Sscottl	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
166983114Sscottl			     sc->aac_common_busaddr +
167083114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
167183114Sscottl			     NULL)) {
167283114Sscottl		device_printf(sc->aac_dev,
167383114Sscottl			      "error establishing init structure\n");
1674112679Sscottl		error = EIO;
1675112679Sscottl		goto out;
167683114Sscottl	}
167765793Smsmith
1678112679Sscottl	error = 0;
1679112679Sscottlout:
1680112679Sscottl	return(error);
168165793Smsmith}
168265793Smsmith
168383114Sscottl/*
168465793Smsmith * Send a synchronous command to the controller and wait for a result.
168565793Smsmith */
168665793Smsmithstatic int
168765793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
168870393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
168970393Smsmith		 u_int32_t *sp)
169065793Smsmith{
169183114Sscottl	time_t then;
169283114Sscottl	u_int32_t status;
169365793Smsmith
169483114Sscottl	debug_called(3);
169565793Smsmith
169683114Sscottl	/* populate the mailbox */
169783114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
169865793Smsmith
169983114Sscottl	/* ensure the sync command doorbell flag is cleared */
170083114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
170165793Smsmith
170283114Sscottl	/* then set it to signal the adapter */
170383114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
170465793Smsmith
170583114Sscottl	/* spin waiting for the command to complete */
170683114Sscottl	then = time_second;
170783114Sscottl	do {
170883114Sscottl		if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) {
1709112679Sscottl			debug(1, "timed out");
171083114Sscottl			return(EIO);
171183114Sscottl		}
171283114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
171365793Smsmith
171483114Sscottl	/* clear the completion flag */
171583114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
171665793Smsmith
171783114Sscottl	/* get the command status */
1718112679Sscottl	status = AAC_GET_MAILBOX(sc, 0);
171983114Sscottl	if (sp != NULL)
172083114Sscottl		*sp = status;
172183114Sscottl	return(0);
172265793Smsmith}
172365793Smsmith
172495350Sscottlint
172565793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
172695350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
172765793Smsmith{
172883114Sscottl	debug_called(3);
172965793Smsmith
173083114Sscottl	if (datasize > AAC_FIB_DATASIZE)
173183114Sscottl		return(EINVAL);
173265793Smsmith
173383114Sscottl	/*
173483114Sscottl	 * Set up the sync FIB
173583114Sscottl	 */
173683114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
173783114Sscottl				AAC_FIBSTATE_INITIALISED |
173883114Sscottl				AAC_FIBSTATE_EMPTY;
173983114Sscottl	fib->Header.XferState |= xferstate;
174083114Sscottl	fib->Header.Command = command;
174183114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
174283114Sscottl	fib->Header.Size = sizeof(struct aac_fib) + datasize;
174383114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
1744119146Sscottl	fib->Header.SenderFibAddress = 0;	/* Not needed */
174583114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
174683114Sscottl					 offsetof(struct aac_common,
174783114Sscottl						  ac_sync_fib);
174865793Smsmith
174983114Sscottl	/*
175083114Sscottl	 * Give the FIB to the controller, wait for a response.
175183114Sscottl	 */
175283114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
175383114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
175483114Sscottl		debug(2, "IO error");
175583114Sscottl		return(EIO);
175683114Sscottl	}
175781151Sscottl
175895350Sscottl	return (0);
175965793Smsmith}
176065793Smsmith
176183114Sscottl/*
176265793Smsmith * Adapter-space FIB queue manipulation
176365793Smsmith *
176465793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
176565793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
176665793Smsmith */
176765793Smsmithstatic struct {
176883114Sscottl	int		size;
176983114Sscottl	int		notify;
177065793Smsmith} aac_qinfo[] = {
177183114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
177283114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
177383114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
177483114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
177583114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
177683114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
177783114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
177883114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
177965793Smsmith};
178065793Smsmith
178165793Smsmith/*
178281082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
178381082Sscottl * EBUSY if the queue is full.
178465793Smsmith *
178570393Smsmith * Note: it would be more efficient to defer notifying the controller in
178683114Sscottl *	 the case where we may be inserting several entries in rapid succession,
178783114Sscottl *	 but implementing this usefully may be difficult (it would involve a
178883114Sscottl *	 separate queue/notify interface).
178965793Smsmith */
179065793Smsmithstatic int
179181151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
179265793Smsmith{
179383114Sscottl	u_int32_t pi, ci;
1794111691Sscottl	int error;
179583114Sscottl	u_int32_t fib_size;
179683114Sscottl	u_int32_t fib_addr;
179765793Smsmith
179883114Sscottl	debug_called(3);
179982527Sscottl
180083114Sscottl	fib_size = cm->cm_fib->Header.Size;
180183114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
180281151Sscottl
180383114Sscottl	/* get the producer/consumer indices */
180483114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
180583114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
180665793Smsmith
180783114Sscottl	/* wrap the queue? */
180883114Sscottl	if (pi >= aac_qinfo[queue].size)
180983114Sscottl		pi = 0;
181065793Smsmith
181183114Sscottl	/* check for queue full */
181283114Sscottl	if ((pi + 1) == ci) {
181383114Sscottl		error = EBUSY;
181483114Sscottl		goto out;
181583114Sscottl	}
181665793Smsmith
1817129946Sscottl	/*
1818129946Sscottl	 * To avoid a race with its completion interrupt, place this command on
1819129946Sscottl	 * the busy queue prior to advertising it to the controller.
1820129946Sscottl	 */
1821129946Sscottl	aac_enqueue_busy(cm);
1822129946Sscottl
182383114Sscottl	/* populate queue entry */
182483114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
182583114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
182665793Smsmith
182783114Sscottl	/* update producer index */
182883114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
182965793Smsmith
183083114Sscottl	/* notify the adapter if we know how */
183183114Sscottl	if (aac_qinfo[queue].notify != 0)
183283114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
183365793Smsmith
183483114Sscottl	error = 0;
183565793Smsmith
183665793Smsmithout:
183783114Sscottl	return(error);
183865793Smsmith}
183965793Smsmith
184065793Smsmith/*
184182527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
184282527Sscottl * success or ENOENT if the queue is empty.
184365793Smsmith */
184465793Smsmithstatic int
184581082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
184681082Sscottl		struct aac_fib **fib_addr)
184765793Smsmith{
184883114Sscottl	u_int32_t pi, ci;
1849114151Sscottl	u_int32_t fib_index;
1850111691Sscottl	int error;
185183114Sscottl	int notify;
185265793Smsmith
185383114Sscottl	debug_called(3);
185465793Smsmith
185583114Sscottl	/* get the producer/consumer indices */
185683114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
185783114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
185865793Smsmith
185983114Sscottl	/* check for queue empty */
186083114Sscottl	if (ci == pi) {
186183114Sscottl		error = ENOENT;
186283114Sscottl		goto out;
186383114Sscottl	}
1864120129Sscottl
1865120129Sscottl	/* wrap the pi so the following test works */
1866120129Sscottl	if (pi >= aac_qinfo[queue].size)
1867120129Sscottl		pi = 0;
1868120129Sscottl
186983114Sscottl	notify = 0;
187083114Sscottl	if (ci == pi + 1)
187183114Sscottl		notify++;
187281151Sscottl
187383114Sscottl	/* wrap the queue? */
187483114Sscottl	if (ci >= aac_qinfo[queue].size)
187583114Sscottl		ci = 0;
187665793Smsmith
187783114Sscottl	/* fetch the entry */
187883114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
187965793Smsmith
1880114151Sscottl	switch (queue) {
1881114151Sscottl	case AAC_HOST_NORM_CMD_QUEUE:
1882114151Sscottl	case AAC_HOST_HIGH_CMD_QUEUE:
1883114151Sscottl		/*
1884114151Sscottl		 * The aq_fib_addr is only 32 bits wide so it can't be counted
1885114151Sscottl		 * on to hold an address.  For AIF's, the adapter assumes
1886114151Sscottl		 * that it's giving us an address into the array of AIF fibs.
1887114151Sscottl		 * Therefore, we have to convert it to an index.
1888114151Sscottl		 */
1889114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
1890114151Sscottl			sizeof(struct aac_fib);
1891114151Sscottl		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
1892114151Sscottl		break;
1893114151Sscottl
1894114151Sscottl	case AAC_HOST_NORM_RESP_QUEUE:
1895114151Sscottl	case AAC_HOST_HIGH_RESP_QUEUE:
1896114151Sscottl	{
1897114151Sscottl		struct aac_command *cm;
1898114151Sscottl
1899114151Sscottl		/*
1900114151Sscottl		 * As above, an index is used instead of an actual address.
1901114151Sscottl		 * Gotta shift the index to account for the fast response
1902114151Sscottl		 * bit.  No other correction is needed since this value was
1903114151Sscottl		 * originally provided by the driver via the SenderFibAddress
1904114151Sscottl		 * field.
1905114151Sscottl		 */
1906114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
1907114151Sscottl		cm = sc->aac_commands + (fib_index >> 1);
1908114151Sscottl		*fib_addr = cm->cm_fib;
1909114151Sscottl
1910114151Sscottl		/*
1911114151Sscottl		 * Is this a fast response? If it is, update the fib fields in
1912114151Sscottl		 * local memory since the whole fib isn't DMA'd back up.
1913114151Sscottl		 */
1914114151Sscottl		if (fib_index & 0x01) {
1915114151Sscottl			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
1916114151Sscottl			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
1917114151Sscottl		}
1918114151Sscottl		break;
1919109088Sscottl	}
1920114151Sscottl	default:
1921114151Sscottl		panic("Invalid queue in aac_dequeue_fib()");
1922114151Sscottl		break;
1923114151Sscottl	}
1924114151Sscottl
192583114Sscottl	/* update consumer index */
192683114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
192765793Smsmith
192883114Sscottl	/* if we have made the queue un-full, notify the adapter */
192983114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
193083114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
193183114Sscottl	error = 0;
193265793Smsmith
193365793Smsmithout:
193483114Sscottl	return(error);
193565793Smsmith}
193665793Smsmith
193783114Sscottl/*
193882527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
193982527Sscottl */
194082527Sscottlstatic int
194182527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
194282527Sscottl{
194383114Sscottl	u_int32_t pi, ci;
1944111691Sscottl	int error;
194583114Sscottl	u_int32_t fib_size;
194683114Sscottl	u_int32_t fib_addr;
194782527Sscottl
194883114Sscottl	debug_called(1);
194982527Sscottl
195083114Sscottl	/* Tell the adapter where the FIB is */
195183114Sscottl	fib_size = fib->Header.Size;
195283114Sscottl	fib_addr = fib->Header.SenderFibAddress;
195383114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
195482527Sscottl
195583114Sscottl	/* get the producer/consumer indices */
195683114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
195783114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
195882527Sscottl
195983114Sscottl	/* wrap the queue? */
196083114Sscottl	if (pi >= aac_qinfo[queue].size)
196183114Sscottl		pi = 0;
196282527Sscottl
196383114Sscottl	/* check for queue full */
196483114Sscottl	if ((pi + 1) == ci) {
196583114Sscottl		error = EBUSY;
196683114Sscottl		goto out;
196783114Sscottl	}
196882527Sscottl
196983114Sscottl	/* populate queue entry */
197083114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
197183114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
197282527Sscottl
197383114Sscottl	/* update producer index */
197483114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
197582527Sscottl
197683114Sscottl	/* notify the adapter if we know how */
197783114Sscottl	if (aac_qinfo[queue].notify != 0)
197883114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
197982527Sscottl
198083114Sscottl	error = 0;
198182527Sscottl
198282527Sscottlout:
198383114Sscottl	return(error);
198482527Sscottl}
198582527Sscottl
198683114Sscottl/*
198770393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
198870393Smsmith * and complain about them.
198970393Smsmith */
199070393Smsmithstatic void
199170393Smsmithaac_timeout(struct aac_softc *sc)
199270393Smsmith{
199383114Sscottl	struct aac_command *cm;
199483114Sscottl	time_t deadline;
1995135289Sscottl	int timedout, code;
199670393Smsmith
199783114Sscottl	/*
1998110426Sscottl	 * Traverse the busy command list, bitch about late commands once
199983114Sscottl	 * only.
200083114Sscottl	 */
2001135289Sscottl	timedout = 0;
200283114Sscottl	deadline = time_second - AAC_CMD_TIMEOUT;
200383114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
200483114Sscottl		if ((cm->cm_timestamp  < deadline)
200583114Sscottl			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
200683114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
200783114Sscottl			device_printf(sc->aac_dev,
200883114Sscottl				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
200983114Sscottl				      cm, (int)(time_second-cm->cm_timestamp));
201083114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
2011135289Sscottl			timedout++;
201283114Sscottl		}
201370393Smsmith	}
201470393Smsmith
2015135289Sscottl	if (timedout) {
2016135289Sscottl		code = AAC_GET_FWSTATUS(sc);
2017135289Sscottl		if (code != AAC_UP_AND_RUNNING) {
2018135289Sscottl			device_printf(sc->aac_dev, "WARNING! Controller is no "
2019135289Sscottl				      "longer running! code= 0x%x\n", code);
2020135289Sscottl		}
2021135289Sscottl	}
202283114Sscottl	return;
202370393Smsmith}
202470393Smsmith
202583114Sscottl/*
202683114Sscottl * Interface Function Vectors
202783114Sscottl */
202865793Smsmith
202983114Sscottl/*
203065793Smsmith * Read the current firmware status word.
203165793Smsmith */
203265793Smsmithstatic int
203365793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
203465793Smsmith{
203583114Sscottl	debug_called(3);
203665793Smsmith
203783114Sscottl	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
203865793Smsmith}
203965793Smsmith
204065793Smsmithstatic int
204165793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
204265793Smsmith{
204383114Sscottl	debug_called(3);
204465793Smsmith
204583114Sscottl	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
204665793Smsmith}
204765793Smsmith
204887183Sscottlstatic int
204987183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc)
205087183Sscottl{
205187183Sscottl	int val;
205287183Sscottl
205387183Sscottl	debug_called(3);
205487183Sscottl
205587183Sscottl	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
205687183Sscottl	return (val);
205787183Sscottl}
205887183Sscottl
2059133606Sscottlstatic int
2060133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc)
2061133606Sscottl{
2062133606Sscottl	debug_called(3);
2063133606Sscottl
2064133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
2065133606Sscottl}
2066133606Sscottl
206783114Sscottl/*
206865793Smsmith * Notify the controller of a change in a given queue
206965793Smsmith */
207065793Smsmith
207165793Smsmithstatic void
207265793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
207365793Smsmith{
207483114Sscottl	debug_called(3);
207565793Smsmith
207683114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
207765793Smsmith}
207865793Smsmith
207965793Smsmithstatic void
208065793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
208165793Smsmith{
208283114Sscottl	debug_called(3);
208365793Smsmith
208483114Sscottl	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
208565793Smsmith}
208665793Smsmith
208787183Sscottlstatic void
208887183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit)
208987183Sscottl{
209087183Sscottl	debug_called(3);
209187183Sscottl
209287183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
209387183Sscottl	AAC_FA_HACK(sc);
209487183Sscottl}
209587183Sscottl
2096133606Sscottlstatic void
2097133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit)
2098133606Sscottl{
2099133606Sscottl	debug_called(3);
2100133606Sscottl
2101133606Sscottl	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
2102133606Sscottl}
2103133606Sscottl
210483114Sscottl/*
210565793Smsmith * Get the interrupt reason bits
210665793Smsmith */
210765793Smsmithstatic int
210865793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
210965793Smsmith{
211083114Sscottl	debug_called(3);
211165793Smsmith
211283114Sscottl	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
211365793Smsmith}
211465793Smsmith
211565793Smsmithstatic int
211665793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
211765793Smsmith{
211883114Sscottl	debug_called(3);
211965793Smsmith
212083114Sscottl	return(AAC_GETREG4(sc, AAC_RX_ODBR));
212165793Smsmith}
212265793Smsmith
212387183Sscottlstatic int
212487183Sscottlaac_fa_get_istatus(struct aac_softc *sc)
212587183Sscottl{
212687183Sscottl	int val;
212787183Sscottl
212887183Sscottl	debug_called(3);
212987183Sscottl
213087183Sscottl	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
213187183Sscottl	return (val);
213287183Sscottl}
213387183Sscottl
2134133606Sscottlstatic int
2135133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc)
2136133606Sscottl{
2137133606Sscottl	debug_called(3);
2138133606Sscottl
2139133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
2140133606Sscottl}
2141133606Sscottl
214283114Sscottl/*
214365793Smsmith * Clear some interrupt reason bits
214465793Smsmith */
214565793Smsmithstatic void
214665793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
214765793Smsmith{
214883114Sscottl	debug_called(3);
214965793Smsmith
215083114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
215165793Smsmith}
215265793Smsmith
215365793Smsmithstatic void
215465793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
215565793Smsmith{
215683114Sscottl	debug_called(3);
215765793Smsmith
215883114Sscottl	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
215965793Smsmith}
216065793Smsmith
216187183Sscottlstatic void
216287183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask)
216387183Sscottl{
216487183Sscottl	debug_called(3);
216587183Sscottl
216687183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
216787183Sscottl	AAC_FA_HACK(sc);
216887183Sscottl}
216987183Sscottl
2170133606Sscottlstatic void
2171133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask)
2172133606Sscottl{
2173133606Sscottl	debug_called(3);
2174133606Sscottl
2175133606Sscottl	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
2176133606Sscottl}
2177133606Sscottl
217883114Sscottl/*
217965793Smsmith * Populate the mailbox and set the command word
218065793Smsmith */
218165793Smsmithstatic void
218265793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
218365793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
218465793Smsmith{
218583114Sscottl	debug_called(4);
218665793Smsmith
218783114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
218883114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
218983114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
219083114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
219183114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
219265793Smsmith}
219365793Smsmith
219465793Smsmithstatic void
219565793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
219665793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
219765793Smsmith{
219883114Sscottl	debug_called(4);
219965793Smsmith
220083114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
220183114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
220283114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
220383114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
220483114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
220565793Smsmith}
220665793Smsmith
220787183Sscottlstatic void
220887183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
220987183Sscottl		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
221087183Sscottl{
221187183Sscottl	debug_called(4);
221287183Sscottl
221387183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
221487183Sscottl	AAC_FA_HACK(sc);
221587183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
221687183Sscottl	AAC_FA_HACK(sc);
221787183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
221887183Sscottl	AAC_FA_HACK(sc);
221987183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
222087183Sscottl	AAC_FA_HACK(sc);
222187183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
222287183Sscottl	AAC_FA_HACK(sc);
222387183Sscottl}
222487183Sscottl
2225133606Sscottlstatic void
2226133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2227133606Sscottl		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2228133606Sscottl{
2229133606Sscottl	debug_called(4);
2230133606Sscottl
2231133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
2232133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2233133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2234133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2235133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
2236133606Sscottl}
2237133606Sscottl
223883114Sscottl/*
223965793Smsmith * Fetch the immediate command status word
224065793Smsmith */
224165793Smsmithstatic int
2242112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb)
224365793Smsmith{
224483114Sscottl	debug_called(4);
224565793Smsmith
2246112679Sscottl	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
224765793Smsmith}
224865793Smsmith
224965793Smsmithstatic int
2250112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb)
225165793Smsmith{
225283114Sscottl	debug_called(4);
225365793Smsmith
2254112679Sscottl	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
225565793Smsmith}
225665793Smsmith
225787183Sscottlstatic int
2258112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb)
225987183Sscottl{
226087183Sscottl	int val;
226187183Sscottl
226287183Sscottl	debug_called(4);
226387183Sscottl
2264112679Sscottl	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
226587183Sscottl	return (val);
226687183Sscottl}
226787183Sscottl
2268133606Sscottlstatic int
2269133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb)
2270133606Sscottl{
2271133606Sscottl	debug_called(4);
2272133606Sscottl
2273133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
2274133606Sscottl}
2275133606Sscottl
227683114Sscottl/*
227765793Smsmith * Set/clear interrupt masks
227865793Smsmith */
227965793Smsmithstatic void
228065793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
228165793Smsmith{
228283114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
228365793Smsmith
228483114Sscottl	if (enable) {
228583114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
228683114Sscottl	} else {
228783114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
228883114Sscottl	}
228965793Smsmith}
229065793Smsmith
229165793Smsmithstatic void
229265793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
229365793Smsmith{
229483114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
229565793Smsmith
229683114Sscottl	if (enable) {
229783114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
229883114Sscottl	} else {
229983114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
230083114Sscottl	}
230165793Smsmith}
230265793Smsmith
230387183Sscottlstatic void
230487183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable)
230587183Sscottl{
230687183Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
230787183Sscottl
230887183Sscottl	if (enable) {
230987183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
231087183Sscottl		AAC_FA_HACK(sc);
231187183Sscottl	} else {
231287183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
231387183Sscottl		AAC_FA_HACK(sc);
231487183Sscottl	}
231587183Sscottl}
231687183Sscottl
2317133606Sscottlstatic void
2318133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable)
2319133606Sscottl{
2320133606Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
2321133606Sscottl
2322133606Sscottl	if (enable) {
2323133606Sscottl		AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
2324133606Sscottl	} else {
2325133606Sscottl		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
2326133606Sscottl	}
2327133606Sscottl}
2328133606Sscottl
232983114Sscottl/*
233083114Sscottl * Debugging and Diagnostics
233183114Sscottl */
233265793Smsmith
233383114Sscottl/*
233465793Smsmith * Print some information about the controller.
233565793Smsmith */
233665793Smsmithstatic void
233765793Smsmithaac_describe_controller(struct aac_softc *sc)
233865793Smsmith{
233995350Sscottl	struct aac_fib *fib;
234083114Sscottl	struct aac_adapter_info	*info;
234165793Smsmith
234283114Sscottl	debug_called(2);
234365793Smsmith
2344130006Sscottl	aac_alloc_sync_fib(sc, &fib);
234595350Sscottl
234695350Sscottl	fib->data[0] = 0;
234795350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
234883114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
234995536Sscottl		aac_release_sync_fib(sc);
235083114Sscottl		return;
235183114Sscottl	}
235265793Smsmith
235383114Sscottl	/* save the kernel revision structure for later use */
2354135095Sscottl	info = (struct aac_adapter_info *)&fib->data[0];
235583114Sscottl	sc->aac_revision = info->KernelRevision;
235695536Sscottl
2357135095Sscottl	if (bootverbose) {
2358135095Sscottl		device_printf(sc->aac_dev, "%s %dMHz, %dMB cache memory, %s\n",
2359135095Sscottl		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2360135095Sscottl		    info->ClockSpeed, info->BufferMem / (1024 * 1024),
2361135095Sscottl		    aac_describe_code(aac_battery_platform,
2362135095Sscottl		    info->batteryPlatform));
2363112679Sscottl
2364135095Sscottl		device_printf(sc->aac_dev,
2365135095Sscottl		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2366135095Sscottl		    info->KernelRevision.external.comp.major,
2367135095Sscottl		    info->KernelRevision.external.comp.minor,
2368135095Sscottl		    info->KernelRevision.external.comp.dash,
2369135095Sscottl		    info->KernelRevision.buildNumber,
2370135095Sscottl		    (u_int32_t)(info->SerialNumber & 0xffffff));
2371135095Sscottl
2372112679Sscottl		device_printf(sc->aac_dev, "Supported Options=%b\n",
2373112679Sscottl			      sc->supported_options,
2374112679Sscottl			      "\20"
2375112679Sscottl			      "\1SNAPSHOT"
2376112679Sscottl			      "\2CLUSTERS"
2377112679Sscottl			      "\3WCACHE"
2378112679Sscottl			      "\4DATA64"
2379112679Sscottl			      "\5HOSTTIME"
2380112679Sscottl			      "\6RAID50"
2381112679Sscottl			      "\7WINDOW4GB"
2382112679Sscottl			      "\10SCSIUPGD"
2383112679Sscottl			      "\11SOFTERR"
2384112679Sscottl			      "\12NORECOND"
2385112679Sscottl			      "\13SGMAP64"
2386112679Sscottl			      "\14ALARM"
2387112679Sscottl			      "\15NONDASD");
2388112679Sscottl	}
2389135095Sscottl	aac_release_sync_fib(sc);
239065793Smsmith}
239165793Smsmith
239283114Sscottl/*
239365793Smsmith * Look up a text description of a numeric error code and return a pointer to
239465793Smsmith * same.
239565793Smsmith */
239665793Smsmithstatic char *
239765793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code)
239865793Smsmith{
239983114Sscottl	int i;
240065793Smsmith
240183114Sscottl	for (i = 0; table[i].string != NULL; i++)
240283114Sscottl		if (table[i].code == code)
240383114Sscottl			return(table[i].string);
240483114Sscottl	return(table[i + 1].string);
240565793Smsmith}
240665793Smsmith
240783114Sscottl/*
240883114Sscottl * Management Interface
240983114Sscottl */
241065793Smsmith
241165793Smsmithstatic int
2412130585Sphkaac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
241365793Smsmith{
241483114Sscottl	struct aac_softc *sc;
241565793Smsmith
241683114Sscottl	debug_called(2);
241765793Smsmith
241883114Sscottl	sc = dev->si_drv1;
241965793Smsmith
242083114Sscottl	/* Check to make sure the device isn't already open */
242183114Sscottl	if (sc->aac_state & AAC_STATE_OPEN) {
242283114Sscottl		return EBUSY;
242383114Sscottl	}
242483114Sscottl	sc->aac_state |= AAC_STATE_OPEN;
242583114Sscottl
242683114Sscottl	return 0;
242765793Smsmith}
242865793Smsmith
242965793Smsmithstatic int
2430130585Sphkaac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
243165793Smsmith{
243283114Sscottl	struct aac_softc *sc;
243365793Smsmith
243483114Sscottl	debug_called(2);
243565793Smsmith
243683114Sscottl	sc = dev->si_drv1;
243765793Smsmith
243883114Sscottl	/* Mark this unit as no longer open  */
243983114Sscottl	sc->aac_state &= ~AAC_STATE_OPEN;
244083114Sscottl
244183114Sscottl	return 0;
244265793Smsmith}
244365793Smsmith
244465793Smsmithstatic int
2445130585Sphkaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
244665793Smsmith{
244783114Sscottl	union aac_statrequest *as;
244883114Sscottl	struct aac_softc *sc;
244983114Sscottl	int error = 0;
2450119146Sscottl	uint32_t cookie;
245165793Smsmith
245283114Sscottl	debug_called(2);
245365793Smsmith
245483114Sscottl	as = (union aac_statrequest *)arg;
245583114Sscottl	sc = dev->si_drv1;
245683114Sscottl
245783114Sscottl	switch (cmd) {
245883114Sscottl	case AACIO_STATS:
245983114Sscottl		switch (as->as_item) {
246083114Sscottl		case AACQ_FREE:
246183114Sscottl		case AACQ_BIO:
246283114Sscottl		case AACQ_READY:
246383114Sscottl		case AACQ_BUSY:
246483114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
246583114Sscottl			      sizeof(struct aac_qstat));
246683114Sscottl			break;
246783114Sscottl		default:
246883114Sscottl			error = ENOENT;
246983114Sscottl			break;
247083114Sscottl		}
247183114Sscottl	break;
247283114Sscottl
247383114Sscottl	case FSACTL_SENDFIB:
247483114Sscottl		arg = *(caddr_t*)arg;
247583114Sscottl	case FSACTL_LNX_SENDFIB:
247683114Sscottl		debug(1, "FSACTL_SENDFIB");
247783114Sscottl		error = aac_ioctl_sendfib(sc, arg);
247883114Sscottl		break;
247983114Sscottl	case FSACTL_AIF_THREAD:
248083114Sscottl	case FSACTL_LNX_AIF_THREAD:
248183114Sscottl		debug(1, "FSACTL_AIF_THREAD");
248283114Sscottl		error = EINVAL;
248383114Sscottl		break;
248483114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
248583114Sscottl		arg = *(caddr_t*)arg;
248687183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
248783114Sscottl		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
248883114Sscottl		/*
248983114Sscottl		 * Pass the caller out an AdapterFibContext.
249083114Sscottl		 *
249183114Sscottl		 * Note that because we only support one opener, we
249283114Sscottl		 * basically ignore this.  Set the caller's context to a magic
249383114Sscottl		 * number just in case.
249483114Sscottl		 *
249583114Sscottl		 * The Linux code hands the driver a pointer into kernel space,
249683114Sscottl		 * and then trusts it when the caller hands it back.  Aiee!
249783114Sscottl		 * Here, we give it the proc pointer of the per-adapter aif
249883114Sscottl		 * thread. It's only used as a sanity check in other calls.
249983114Sscottl		 */
2500119146Sscottl		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2501119146Sscottl		error = copyout(&cookie, arg, sizeof(cookie));
250283114Sscottl		break;
250383114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
250483114Sscottl		arg = *(caddr_t*)arg;
250583114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
250683114Sscottl		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
250783114Sscottl		error = aac_getnext_aif(sc, arg);
250883114Sscottl		break;
250983114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
251083114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
251183114Sscottl		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
251283114Sscottl		/* don't do anything here */
251383114Sscottl		break;
251483114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
251583114Sscottl		arg = *(caddr_t*)arg;
251683114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
251783114Sscottl		debug(1, "FSACTL_MINIPORT_REV_CHECK");
251883114Sscottl		error = aac_rev_check(sc, arg);
251983114Sscottl		break;
252083114Sscottl	case FSACTL_QUERY_DISK:
252183114Sscottl		arg = *(caddr_t*)arg;
252283114Sscottl	case FSACTL_LNX_QUERY_DISK:
252383114Sscottl		debug(1, "FSACTL_QUERY_DISK");
252483114Sscottl		error = aac_query_disk(sc, arg);
252583114Sscottl			break;
252683114Sscottl	case FSACTL_DELETE_DISK:
252783114Sscottl	case FSACTL_LNX_DELETE_DISK:
252883114Sscottl		/*
252983114Sscottl		 * We don't trust the underland to tell us when to delete a
253083114Sscottl		 * container, rather we rely on an AIF coming from the
253183114Sscottl		 * controller
253283114Sscottl		 */
253383114Sscottl		error = 0;
253483114Sscottl		break;
253570393Smsmith	default:
253687183Sscottl		debug(1, "unsupported cmd 0x%lx\n", cmd);
253783114Sscottl		error = EINVAL;
253883114Sscottl		break;
253970393Smsmith	}
254083114Sscottl	return(error);
254165793Smsmith}
254265793Smsmith
254387183Sscottlstatic int
2544130585Sphkaac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
254587183Sscottl{
254687183Sscottl	struct aac_softc *sc;
254787183Sscottl	int revents;
254887183Sscottl
254987183Sscottl	sc = dev->si_drv1;
255087183Sscottl	revents = 0;
255187183Sscottl
2552133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
255387183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
255487183Sscottl		if (sc->aac_aifq_tail != sc->aac_aifq_head)
255587183Sscottl			revents |= poll_events & (POLLIN | POLLRDNORM);
255687183Sscottl	}
2557133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
255887183Sscottl
255987183Sscottl	if (revents == 0) {
256087183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
256187183Sscottl			selrecord(td, &sc->rcv_select);
256287183Sscottl	}
256387183Sscottl
256487183Sscottl	return (revents);
256587183Sscottl}
256687183Sscottl
256783114Sscottl/*
256865793Smsmith * Send a FIB supplied from userspace
256965793Smsmith */
257065793Smsmithstatic int
257165793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
257265793Smsmith{
257383114Sscottl	struct aac_command *cm;
257483114Sscottl	int size, error;
257565793Smsmith
257683114Sscottl	debug_called(2);
257765793Smsmith
257883114Sscottl	cm = NULL;
257965793Smsmith
258083114Sscottl	/*
258183114Sscottl	 * Get a command
258283114Sscottl	 */
2583133540Sscottl	mtx_lock(&sc->aac_io_lock);
258483114Sscottl	if (aac_alloc_command(sc, &cm)) {
258583114Sscottl		error = EBUSY;
258683114Sscottl		goto out;
258783114Sscottl	}
258865793Smsmith
258983114Sscottl	/*
259083114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
259183114Sscottl	 */
259283114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
259383114Sscottl			    sizeof(struct aac_fib_header))) != 0)
259483114Sscottl		goto out;
259583114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
259683114Sscottl	if (size > sizeof(struct aac_fib)) {
2597119146Sscottl		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
259883114Sscottl			      size, sizeof(struct aac_fib));
259983114Sscottl		size = sizeof(struct aac_fib);
260083114Sscottl	}
260183114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
260283114Sscottl		goto out;
260383114Sscottl	cm->cm_fib->Header.Size = size;
260483114Sscottl	cm->cm_timestamp = time_second;
260565793Smsmith
260683114Sscottl	/*
260783114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
260883114Sscottl	 */
2609128258Sscottl	if ((error = aac_wait_command(cm)) != 0) {
2610110426Sscottl		device_printf(sc->aac_dev,
2611110426Sscottl			      "aac_wait_command return %d\n", error);
261283114Sscottl		goto out;
261387183Sscottl	}
261465793Smsmith
261583114Sscottl	/*
261683114Sscottl	 * Copy the FIB and data back out to the caller.
261783114Sscottl	 */
261883114Sscottl	size = cm->cm_fib->Header.Size;
261983114Sscottl	if (size > sizeof(struct aac_fib)) {
2620119146Sscottl		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
262183114Sscottl			      size, sizeof(struct aac_fib));
262283114Sscottl		size = sizeof(struct aac_fib);
262383114Sscottl	}
262483114Sscottl	error = copyout(cm->cm_fib, ufib, size);
262565793Smsmith
262665793Smsmithout:
262783114Sscottl	if (cm != NULL) {
262883114Sscottl		aac_release_command(cm);
262983114Sscottl	}
2630111532Sscottl
2631133540Sscottl	mtx_unlock(&sc->aac_io_lock);
263283114Sscottl	return(error);
263365793Smsmith}
263465793Smsmith
263583114Sscottl/*
263665793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
263782527Sscottl * If the queue fills up, then drop the older entries.
263865793Smsmith */
263965793Smsmithstatic void
264082527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
264165793Smsmith{
264283114Sscottl	struct aac_aif_command *aif;
264383114Sscottl	struct aac_container *co, *co_next;
264495350Sscottl	struct aac_mntinfo *mi;
264595350Sscottl	struct aac_mntinforesp *mir = NULL;
264683114Sscottl	u_int16_t rsize;
264787183Sscottl	int next, found;
2648115760Sscottl	int count = 0, added = 0, i = 0;
264965793Smsmith
265083114Sscottl	debug_called(2);
265165793Smsmith
265283114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
265383114Sscottl	aac_print_aif(sc, aif);
265482527Sscottl
265583114Sscottl	/* Is it an event that we should care about? */
265683114Sscottl	switch (aif->command) {
265783114Sscottl	case AifCmdEventNotify:
265883114Sscottl		switch (aif->data.EN.type) {
265983114Sscottl		case AifEnAddContainer:
266083114Sscottl		case AifEnDeleteContainer:
266183114Sscottl			/*
266283114Sscottl			 * A container was added or deleted, but the message
266383114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
266483114Sscottl			 * containers and sort things out.
266583114Sscottl			 */
2666130006Sscottl			aac_alloc_sync_fib(sc, &fib);
266795350Sscottl			mi = (struct aac_mntinfo *)&fib->data[0];
266883114Sscottl			do {
266983114Sscottl				/*
267083114Sscottl				 * Ask the controller for its containers one at
267183114Sscottl				 * a time.
267283114Sscottl				 * XXX What if the controller's list changes
267383114Sscottl				 * midway through this enumaration?
267483114Sscottl				 * XXX This should be done async.
267583114Sscottl				 */
267695966Sscottl				bzero(mi, sizeof(struct aac_mntinfo));
267795966Sscottl				mi->Command = VM_NameServe;
267895966Sscottl				mi->MntType = FT_FILESYS;
267995350Sscottl				mi->MntCount = i;
268083114Sscottl				rsize = sizeof(mir);
268195350Sscottl				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
268295350Sscottl						 sizeof(struct aac_mntinfo))) {
2683115760Sscottl					printf("Error probing container %d\n",
268483114Sscottl					      i);
268583114Sscottl					continue;
268683114Sscottl				}
268795350Sscottl				mir = (struct aac_mntinforesp *)&fib->data[0];
2688115760Sscottl				/* XXX Need to check if count changed */
2689115760Sscottl				count = mir->MntRespCount;
269083114Sscottl				/*
269183114Sscottl				 * Check the container against our list.
269283114Sscottl				 * co->co_found was already set to 0 in a
269383114Sscottl				 * previous run.
269483114Sscottl				 */
269595350Sscottl				if ((mir->Status == ST_OK) &&
269695350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
269783114Sscottl					found = 0;
269883114Sscottl					TAILQ_FOREACH(co,
269983114Sscottl						      &sc->aac_container_tqh,
270083114Sscottl						      co_link) {
270183114Sscottl						if (co->co_mntobj.ObjectId ==
270295350Sscottl						    mir->MntTable[0].ObjectId) {
270383114Sscottl							co->co_found = 1;
270483114Sscottl							found = 1;
270583114Sscottl							break;
270683114Sscottl						}
270783114Sscottl					}
270883114Sscottl					/*
270983114Sscottl					 * If the container matched, continue
271083114Sscottl					 * in the list.
271183114Sscottl					 */
271283114Sscottl					if (found) {
271383114Sscottl						i++;
271483114Sscottl						continue;
271583114Sscottl					}
271683114Sscottl
271783114Sscottl					/*
271883114Sscottl					 * This is a new container.  Do all the
2719110426Sscottl					 * appropriate things to set it up.
2720110426Sscottl					 */
272195350Sscottl					aac_add_container(sc, mir, 1);
272283114Sscottl					added = 1;
272383114Sscottl				}
272483114Sscottl				i++;
2725115760Sscottl			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
272695350Sscottl			aac_release_sync_fib(sc);
272783114Sscottl
272883114Sscottl			/*
272983114Sscottl			 * Go through our list of containers and see which ones
273083114Sscottl			 * were not marked 'found'.  Since the controller didn't
273183114Sscottl			 * list them they must have been deleted.  Do the
273283114Sscottl			 * appropriate steps to destroy the device.  Also reset
273383114Sscottl			 * the co->co_found field.
273483114Sscottl			 */
273583114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
273683114Sscottl			while (co != NULL) {
273783114Sscottl				if (co->co_found == 0) {
273883114Sscottl					device_delete_child(sc->aac_dev,
273983114Sscottl							    co->co_disk);
274083114Sscottl					co_next = TAILQ_NEXT(co, co_link);
2741133540Sscottl					mtx_lock(&sc->aac_container_lock);
274283114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
274383114Sscottl						     co_link);
2744133540Sscottl					mtx_unlock(&sc->aac_container_lock);
2745133541Sscottl					free(co, M_AACBUF);
274683114Sscottl					co = co_next;
274783114Sscottl				} else {
274883114Sscottl					co->co_found = 0;
274983114Sscottl					co = TAILQ_NEXT(co, co_link);
275083114Sscottl				}
275182527Sscottl			}
275282527Sscottl
275383114Sscottl			/* Attach the newly created containers */
275483114Sscottl			if (added)
275583114Sscottl				bus_generic_attach(sc->aac_dev);
275683114Sscottl
2757105528Sphk			break;
275882527Sscottl
275983114Sscottl		default:
276083114Sscottl			break;
276182527Sscottl		}
276282527Sscottl
276382527Sscottl	default:
276483114Sscottl		break;
276582527Sscottl	}
276682527Sscottl
276783114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
2768133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
276983114Sscottl	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
277083114Sscottl	if (next != sc->aac_aifq_tail) {
277183114Sscottl		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
277287183Sscottl		sc->aac_aifq_head = next;
277387183Sscottl
277487183Sscottl		/* On the off chance that someone is sleeping for an aif... */
277587183Sscottl		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
277687183Sscottl			wakeup(sc->aac_aifq);
277787183Sscottl		/* Wakeup any poll()ers */
2778122352Stanimura		selwakeuppri(&sc->rcv_select, PRIBIO);
277983114Sscottl	}
2780133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
278182527Sscottl
278283114Sscottl	return;
278365793Smsmith}
278465793Smsmith
278583114Sscottl/*
278670393Smsmith * Return the Revision of the driver to userspace and check to see if the
278782527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
278882527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
278982527Sscottl * returning what the card reported.
279065793Smsmith */
279165793Smsmithstatic int
279281189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
279365793Smsmith{
279483114Sscottl	struct aac_rev_check rev_check;
279583114Sscottl	struct aac_rev_check_resp rev_check_resp;
279683114Sscottl	int error = 0;
279765793Smsmith
279883114Sscottl	debug_called(2);
279965793Smsmith
280083114Sscottl	/*
280183114Sscottl	 * Copyin the revision struct from userspace
280283114Sscottl	 */
280383114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
280481082Sscottl			sizeof(struct aac_rev_check))) != 0) {
280583114Sscottl		return error;
280683114Sscottl	}
280765793Smsmith
280883114Sscottl	debug(2, "Userland revision= %d\n",
280983114Sscottl	      rev_check.callingRevision.buildNumber);
281065793Smsmith
281183114Sscottl	/*
281283114Sscottl	 * Doctor up the response struct.
281383114Sscottl	 */
281483114Sscottl	rev_check_resp.possiblyCompatible = 1;
281583114Sscottl	rev_check_resp.adapterSWRevision.external.ul =
281683114Sscottl	    sc->aac_revision.external.ul;
281783114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
281883114Sscottl	    sc->aac_revision.buildNumber;
281965793Smsmith
282083114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
282183114Sscottl			sizeof(struct aac_rev_check_resp)));
282265793Smsmith}
282365793Smsmith
282483114Sscottl/*
282565793Smsmith * Pass the caller the next AIF in their queue
282665793Smsmith */
282765793Smsmithstatic int
282881189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
282965793Smsmith{
283083114Sscottl	struct get_adapter_fib_ioctl agf;
2831111691Sscottl	int error;
283265793Smsmith
283383114Sscottl	debug_called(2);
283465793Smsmith
283583114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
283665793Smsmith
283783114Sscottl		/*
283883114Sscottl		 * Check the magic number that we gave the caller.
283983114Sscottl		 */
2840119146Sscottl		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
284183114Sscottl			error = EFAULT;
284283114Sscottl		} else {
284381189Sscottl			error = aac_return_aif(sc, agf.AifFib);
284483114Sscottl			if ((error == EAGAIN) && (agf.Wait)) {
284583114Sscottl				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
284683114Sscottl				while (error == EAGAIN) {
284783114Sscottl					error = tsleep(sc->aac_aifq, PRIBIO |
284883114Sscottl						       PCATCH, "aacaif", 0);
284983114Sscottl					if (error == 0)
285083114Sscottl						error = aac_return_aif(sc,
285183114Sscottl						    agf.AifFib);
285283114Sscottl				}
285383114Sscottl				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
285483114Sscottl			}
285565793Smsmith		}
285665793Smsmith	}
285783114Sscottl	return(error);
285865793Smsmith}
285965793Smsmith
286083114Sscottl/*
286170393Smsmith * Hand the next AIF off the top of the queue out to userspace.
286270393Smsmith */
286370393Smsmithstatic int
286481189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr)
286570393Smsmith{
2866121173Sscottl	int next, error;
286770393Smsmith
286883114Sscottl	debug_called(2);
286970393Smsmith
2870133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
287183114Sscottl	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
2872133540Sscottl		mtx_unlock(&sc->aac_aifq_lock);
2873121173Sscottl		return (EAGAIN);
287483114Sscottl	}
2875121173Sscottl
2876121173Sscottl	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
2877121173Sscottl	error = copyout(&sc->aac_aifq[next], uptr,
2878121173Sscottl			sizeof(struct aac_aif_command));
2879121173Sscottl	if (error)
2880121173Sscottl		device_printf(sc->aac_dev,
2881121173Sscottl		    "aac_return_aif: copyout returned %d\n", error);
2882121173Sscottl	else
2883121173Sscottl		sc->aac_aifq_tail = next;
2884121173Sscottl
2885133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
288683114Sscottl	return(error);
288770393Smsmith}
288882527Sscottl
288983114Sscottl/*
289082527Sscottl * Give the userland some information about the container.  The AAC arch
289182527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
289282527Sscottl * the containers to have b:t:l numbers.  Fake it.
289382527Sscottl */
289482527Sscottlstatic int
289582527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
289682527Sscottl{
289783114Sscottl	struct aac_query_disk query_disk;
289883114Sscottl	struct aac_container *co;
289983114Sscottl	struct aac_disk	*disk;
290083114Sscottl	int error, id;
290182527Sscottl
290283114Sscottl	debug_called(2);
290382527Sscottl
290483114Sscottl	disk = NULL;
290582527Sscottl
290683114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
290783114Sscottl		       sizeof(struct aac_query_disk));
290883114Sscottl	if (error)
290983114Sscottl		return (error);
291082527Sscottl
291183114Sscottl	id = query_disk.ContainerNumber;
291283114Sscottl	if (id == -1)
291383114Sscottl		return (EINVAL);
291482527Sscottl
2915133540Sscottl	mtx_lock(&sc->aac_container_lock);
291683114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
291783114Sscottl		if (co->co_mntobj.ObjectId == id)
291883114Sscottl			break;
291983114Sscottl		}
292082527Sscottl
2921105528Sphk	if (co == NULL) {
292283114Sscottl			query_disk.Valid = 0;
292383114Sscottl			query_disk.Locked = 0;
292483114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
2925105528Sphk	} else {
2926105528Sphk		disk = device_get_softc(co->co_disk);
2927105528Sphk		query_disk.Valid = 1;
2928105528Sphk		query_disk.Locked =
2929105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
2930105528Sphk		query_disk.Deleted = 0;
2931105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
2932105528Sphk		query_disk.Target = disk->unit;
2933105528Sphk		query_disk.Lun = 0;
2934105528Sphk		query_disk.UnMapped = 0;
2935111525Sscottl		sprintf(&query_disk.diskDeviceName[0], "%s%d",
2936125975Sphk		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
2937105528Sphk	}
2938133540Sscottl	mtx_unlock(&sc->aac_container_lock);
293982527Sscottl
294083114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
294183114Sscottl			sizeof(struct aac_query_disk));
294283114Sscottl
294383114Sscottl	return (error);
294482527Sscottl}
294582527Sscottl
294695536Sscottlstatic void
294795536Sscottlaac_get_bus_info(struct aac_softc *sc)
294895536Sscottl{
294995536Sscottl	struct aac_fib *fib;
295095536Sscottl	struct aac_ctcfg *c_cmd;
295195536Sscottl	struct aac_ctcfg_resp *c_resp;
295295536Sscottl	struct aac_vmioctl *vmi;
295395536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
295495536Sscottl	struct aac_getbusinf businfo;
2955110426Sscottl	struct aac_sim *caminf;
295695536Sscottl	device_t child;
295795536Sscottl	int i, found, error;
295895536Sscottl
2959130006Sscottl	aac_alloc_sync_fib(sc, &fib);
296095536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
296195966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
296295536Sscottl
296395536Sscottl	c_cmd->Command = VM_ContainerConfig;
296495536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
296595536Sscottl	c_cmd->param = 0;
296695536Sscottl
296795536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
296895536Sscottl	    sizeof(struct aac_ctcfg));
296995536Sscottl	if (error) {
297095536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
297195536Sscottl		    "VM_ContainerConfig command\n", error);
297295536Sscottl		aac_release_sync_fib(sc);
297395536Sscottl		return;
297495536Sscottl	}
297595536Sscottl
297695536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
297795536Sscottl	if (c_resp->Status != ST_OK) {
297895536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
297995536Sscottl		    c_resp->Status);
298095536Sscottl		aac_release_sync_fib(sc);
298195536Sscottl		return;
298295536Sscottl	}
298395536Sscottl
298495536Sscottl	sc->scsi_method_id = c_resp->param;
298595536Sscottl
298695536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
298795966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
298895966Sscottl
298995536Sscottl	vmi->Command = VM_Ioctl;
299095536Sscottl	vmi->ObjType = FT_DRIVE;
299195536Sscottl	vmi->MethId = sc->scsi_method_id;
299295536Sscottl	vmi->ObjId = 0;
299395536Sscottl	vmi->IoctlCmd = GetBusInfo;
299495536Sscottl
299595536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
299695536Sscottl	    sizeof(struct aac_vmioctl));
299795536Sscottl	if (error) {
299895536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
299995536Sscottl		    error);
300095536Sscottl		aac_release_sync_fib(sc);
300195536Sscottl		return;
300295536Sscottl	}
300395536Sscottl
300495536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
300595536Sscottl	if (vmi_resp->Status != ST_OK) {
300695536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
300795536Sscottl		    vmi_resp->Status);
300895536Sscottl		aac_release_sync_fib(sc);
300995536Sscottl		return;
301095536Sscottl	}
301195536Sscottl
301295536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
301395536Sscottl	aac_release_sync_fib(sc);
301495536Sscottl
301595536Sscottl	found = 0;
301695536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
301795536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
301895536Sscottl			continue;
301995536Sscottl
3020110428Sscottl		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3021110428Sscottl		    M_AACBUF, M_NOWAIT | M_ZERO);
302295536Sscottl		if (caminf == NULL)
302395536Sscottl			continue;
302495536Sscottl
302595536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
302695536Sscottl		if (child == NULL) {
302795536Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
302895536Sscottl			continue;
302995536Sscottl		}
303095536Sscottl
303195536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
303295536Sscottl		caminf->BusNumber = i;
303395536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
303495536Sscottl		caminf->aac_sc = sc;
3035110432Sscottl		caminf->sim_dev = child;
303695536Sscottl
303795536Sscottl		device_set_ivars(child, caminf);
303895536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
3039110426Sscottl		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
304095536Sscottl
304195536Sscottl		found = 1;
304295536Sscottl	}
304395536Sscottl
304495536Sscottl	if (found)
304595536Sscottl		bus_generic_attach(sc->aac_dev);
304695536Sscottl
304795536Sscottl	return;
304895536Sscottl}
3049