aac.c revision 151086
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 151086 2005-10-08 15:55:09Z scottl $");
32119418Sobrien
3365793Smsmith/*
3465793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3565793Smsmith */
36151086Sscottl#define AAC_DRIVER_VERSION		0x02000000
37151086Sscottl#define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
38151086Sscottl#define AAC_DRIVERNAME			"aac"
3965793Smsmith
4081151Sscottl#include "opt_aac.h"
4181151Sscottl
4282527Sscottl/* #include <stddef.h> */
4365793Smsmith#include <sys/param.h>
4465793Smsmith#include <sys/systm.h>
4565793Smsmith#include <sys/malloc.h>
4665793Smsmith#include <sys/kernel.h>
4782527Sscottl#include <sys/kthread.h>
4881154Sscottl#include <sys/sysctl.h>
4987183Sscottl#include <sys/poll.h>
50112946Sphk#include <sys/ioccom.h>
5165793Smsmith
5265793Smsmith#include <sys/bus.h>
5365793Smsmith#include <sys/conf.h>
5465793Smsmith#include <sys/signalvar.h>
5570393Smsmith#include <sys/time.h>
5682527Sscottl#include <sys/eventhandler.h>
57151086Sscottl#include <sys/rman.h>
5865793Smsmith
5965793Smsmith#include <machine/bus.h>
60143838Sscottl#include <sys/bus_dma.h>
6165793Smsmith#include <machine/resource.h>
6265793Smsmith
63151086Sscottl#include <dev/pci/pcireg.h>
64151086Sscottl#include <dev/pci/pcivar.h>
65151086Sscottl
6665793Smsmith#include <dev/aac/aacreg.h>
67138635Sscottl#include <sys/aac_ioctl.h>
6865793Smsmith#include <dev/aac/aacvar.h>
6965793Smsmith#include <dev/aac/aac_tables.h>
7065793Smsmith
7165793Smsmithstatic void	aac_startup(void *arg);
7283114Sscottlstatic void	aac_add_container(struct aac_softc *sc,
7395350Sscottl				  struct aac_mntinforesp *mir, int f);
7495536Sscottlstatic void	aac_get_bus_info(struct aac_softc *sc);
7565793Smsmith
7665793Smsmith/* Command Processing */
7770393Smsmithstatic void	aac_timeout(struct aac_softc *sc);
7865793Smsmithstatic void	aac_complete(void *context, int pending);
7965793Smsmithstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
8065793Smsmithstatic void	aac_bio_complete(struct aac_command *cm);
81128258Sscottlstatic int	aac_wait_command(struct aac_command *cm);
82110426Sscottlstatic void	aac_command_thread(struct aac_softc *sc);
8365793Smsmith
8465793Smsmith/* Command Buffer Management */
85117363Sscottlstatic void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
86117363Sscottl				   int nseg, int error);
8781082Sscottlstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
8881082Sscottl				       int nseg, int error);
8970393Smsmithstatic int	aac_alloc_commands(struct aac_softc *sc);
90111141Sscottlstatic void	aac_free_commands(struct aac_softc *sc);
9165793Smsmithstatic void	aac_unmap_command(struct aac_command *cm);
9265793Smsmith
9365793Smsmith/* Hardware Interface */
9481082Sscottlstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
9581082Sscottl			       int error);
9690275Sscottlstatic int	aac_check_firmware(struct aac_softc *sc);
9765793Smsmithstatic int	aac_init(struct aac_softc *sc);
9865793Smsmithstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
9981082Sscottl				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
10081082Sscottl				 u_int32_t arg3, u_int32_t *sp);
10181082Sscottlstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
10281151Sscottl				struct aac_command *cm);
10381082Sscottlstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
10483114Sscottl				u_int32_t *fib_size, struct aac_fib **fib_addr);
10582527Sscottlstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
10682527Sscottl				     struct aac_fib *fib);
10765793Smsmith
10887183Sscottl/* Falcon/PPC interface */
10987183Sscottlstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
11087183Sscottlstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
11187183Sscottlstatic int	aac_fa_get_istatus(struct aac_softc *sc);
11287183Sscottlstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
11387183Sscottlstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
11487183Sscottl				   u_int32_t arg0, u_int32_t arg1,
11587183Sscottl				   u_int32_t arg2, u_int32_t arg3);
116112679Sscottlstatic int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
11787183Sscottlstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
11887183Sscottl
11987183Sscottlstruct aac_interface aac_fa_interface = {
12087183Sscottl	aac_fa_get_fwstatus,
12187183Sscottl	aac_fa_qnotify,
12287183Sscottl	aac_fa_get_istatus,
12387183Sscottl	aac_fa_clear_istatus,
12487183Sscottl	aac_fa_set_mailbox,
125112679Sscottl	aac_fa_get_mailbox,
126151086Sscottl	aac_fa_set_interrupts,
127151086Sscottl	NULL, NULL, NULL
12887183Sscottl};
12987183Sscottl
13065793Smsmith/* StrongARM interface */
13165793Smsmithstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
13265793Smsmithstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
13365793Smsmithstatic int	aac_sa_get_istatus(struct aac_softc *sc);
13465793Smsmithstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
13565793Smsmithstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
13681082Sscottl				   u_int32_t arg0, u_int32_t arg1,
13781082Sscottl				   u_int32_t arg2, u_int32_t arg3);
138112679Sscottlstatic int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
13965793Smsmithstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
14065793Smsmith
14165793Smsmithstruct aac_interface aac_sa_interface = {
14283114Sscottl	aac_sa_get_fwstatus,
14383114Sscottl	aac_sa_qnotify,
14483114Sscottl	aac_sa_get_istatus,
14583114Sscottl	aac_sa_clear_istatus,
14683114Sscottl	aac_sa_set_mailbox,
147112679Sscottl	aac_sa_get_mailbox,
148151086Sscottl	aac_sa_set_interrupts,
149151086Sscottl	NULL, NULL, NULL
15065793Smsmith};
15165793Smsmith
15283114Sscottl/* i960Rx interface */
15365793Smsmithstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
15465793Smsmithstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
15565793Smsmithstatic int	aac_rx_get_istatus(struct aac_softc *sc);
15665793Smsmithstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
15765793Smsmithstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
15881082Sscottl				   u_int32_t arg0, u_int32_t arg1,
15981082Sscottl				   u_int32_t arg2, u_int32_t arg3);
160112679Sscottlstatic int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
16165793Smsmithstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
162151086Sscottlstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
163151086Sscottlstatic int aac_rx_get_outb_queue(struct aac_softc *sc);
164151086Sscottlstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
16565793Smsmith
16665793Smsmithstruct aac_interface aac_rx_interface = {
16783114Sscottl	aac_rx_get_fwstatus,
16883114Sscottl	aac_rx_qnotify,
16983114Sscottl	aac_rx_get_istatus,
17083114Sscottl	aac_rx_clear_istatus,
17183114Sscottl	aac_rx_set_mailbox,
172112679Sscottl	aac_rx_get_mailbox,
173151086Sscottl	aac_rx_set_interrupts,
174151086Sscottl	aac_rx_send_command,
175151086Sscottl	aac_rx_get_outb_queue,
176151086Sscottl	aac_rx_set_outb_queue
17765793Smsmith};
17865793Smsmith
179133606Sscottl/* Rocket/MIPS interface */
180133606Sscottlstatic int	aac_rkt_get_fwstatus(struct aac_softc *sc);
181133606Sscottlstatic void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
182133606Sscottlstatic int	aac_rkt_get_istatus(struct aac_softc *sc);
183133606Sscottlstatic void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
184133606Sscottlstatic void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
185133606Sscottl				    u_int32_t arg0, u_int32_t arg1,
186133606Sscottl				    u_int32_t arg2, u_int32_t arg3);
187133606Sscottlstatic int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
188133606Sscottlstatic void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
189151086Sscottlstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
190151086Sscottlstatic int aac_rkt_get_outb_queue(struct aac_softc *sc);
191151086Sscottlstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
192133606Sscottl
193133606Sscottlstruct aac_interface aac_rkt_interface = {
194133606Sscottl	aac_rkt_get_fwstatus,
195133606Sscottl	aac_rkt_qnotify,
196133606Sscottl	aac_rkt_get_istatus,
197133606Sscottl	aac_rkt_clear_istatus,
198133606Sscottl	aac_rkt_set_mailbox,
199133606Sscottl	aac_rkt_get_mailbox,
200151086Sscottl	aac_rkt_set_interrupts,
201151086Sscottl	aac_rkt_send_command,
202151086Sscottl	aac_rkt_get_outb_queue,
203151086Sscottl	aac_rkt_set_outb_queue
204133606Sscottl};
205133606Sscottl
20665793Smsmith/* Debugging and Diagnostics */
20765793Smsmithstatic void	aac_describe_controller(struct aac_softc *sc);
20882567Sscottlstatic char	*aac_describe_code(struct aac_code_lookup *table,
20981082Sscottl				   u_int32_t code);
21065793Smsmith
21165793Smsmith/* Management Interface */
21265793Smsmithstatic d_open_t		aac_open;
21365793Smsmithstatic d_close_t	aac_close;
21465793Smsmithstatic d_ioctl_t	aac_ioctl;
21587183Sscottlstatic d_poll_t		aac_poll;
21681082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
21781082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
21883114Sscottl					   struct aac_fib *fib);
21981189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
22081189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
22181189Sscottlstatic int		aac_return_aif(struct aac_softc *sc, caddr_t uptr);
22282527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
223151086Sscottlstatic int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
224151086Sscottlstatic void		aac_ioctl_event(struct aac_softc *sc,
225151086Sscottl				        struct aac_event *event, void *arg);
22665793Smsmith
22765793Smsmithstatic struct cdevsw aac_cdevsw = {
228126080Sphk	.d_version =	D_VERSION,
229126080Sphk	.d_flags =	D_NEEDGIANT,
230111815Sphk	.d_open =	aac_open,
231111815Sphk	.d_close =	aac_close,
232111815Sphk	.d_ioctl =	aac_ioctl,
233111815Sphk	.d_poll =	aac_poll,
234111815Sphk	.d_name =	"aac",
23565793Smsmith};
23665793Smsmith
23782527SscottlMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
23882527Sscottl
23981154Sscottl/* sysctl node */
24081154SscottlSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
24181154Sscottl
24283114Sscottl/*
24383114Sscottl * Device Interface
24483114Sscottl */
24565793Smsmith
24683114Sscottl/*
24765793Smsmith * Initialise the controller and softc
24865793Smsmith */
24965793Smsmithint
25065793Smsmithaac_attach(struct aac_softc *sc)
25165793Smsmith{
25283114Sscottl	int error, unit;
25365793Smsmith
25483114Sscottl	debug_called(1);
25565793Smsmith
25683114Sscottl	/*
25783114Sscottl	 * Initialise per-controller queues.
25883114Sscottl	 */
25983114Sscottl	aac_initq_free(sc);
26083114Sscottl	aac_initq_ready(sc);
26183114Sscottl	aac_initq_busy(sc);
26283114Sscottl	aac_initq_bio(sc);
26365793Smsmith
26483114Sscottl	/*
26583114Sscottl	 * Initialise command-completion task.
26683114Sscottl	 */
26783114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
26865793Smsmith
26983114Sscottl	/* mark controller as suspended until we get ourselves organised */
27083114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
27165793Smsmith
27283114Sscottl	/*
27390275Sscottl	 * Check that the firmware on the card is supported.
27490275Sscottl	 */
27590275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
27690275Sscottl		return(error);
27790275Sscottl
278117126Sscottl	/*
279117126Sscottl	 * Initialize locks
280117126Sscottl	 */
281133540Sscottl	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
282133540Sscottl	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
283133540Sscottl	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
284117126Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
28595350Sscottl
286121173Sscottl	/* Initialize the local AIF queue pointers */
287121173Sscottl	sc->aac_aifq_head = sc->aac_aifq_tail = AAC_AIFQ_LENGTH;
288117126Sscottl
28983114Sscottl	/*
29083114Sscottl	 * Initialise the adapter.
29183114Sscottl	 */
29283114Sscottl	if ((error = aac_init(sc)) != 0)
29383114Sscottl		return(error);
29465793Smsmith
29583114Sscottl	/*
296151086Sscottl	 * Allocate and connect our interrupt.
297151086Sscottl	 */
298151086Sscottl	sc->aac_irq_rid = 0;
299151086Sscottl	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
300151086Sscottl			   			  &sc->aac_irq_rid,
301151086Sscottl			   			  RF_SHAREABLE |
302151086Sscottl						  RF_ACTIVE)) == NULL) {
303151086Sscottl		device_printf(sc->aac_dev, "can't allocate interrupt\n");
304151086Sscottl		return (EINVAL);
305151086Sscottl	}
306151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
307151086Sscottl		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
308151086Sscottl				   INTR_MPSAFE|INTR_TYPE_BIO, aac_new_intr,
309151086Sscottl				   sc, &sc->aac_intr)) {
310151086Sscottl			device_printf(sc->aac_dev, "can't set up interrupt\n");
311151086Sscottl			return (EINVAL);
312151086Sscottl		}
313151086Sscottl	} else {
314151086Sscottl		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
315151086Sscottl				   INTR_FAST|INTR_TYPE_BIO, aac_fast_intr,
316151086Sscottl				   sc, &sc->aac_intr)) {
317151086Sscottl			device_printf(sc->aac_dev,
318151086Sscottl				      "can't set up FAST interrupt\n");
319151086Sscottl			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
320151086Sscottl					   INTR_MPSAFE|INTR_TYPE_BIO,
321151086Sscottl					   aac_fast_intr, sc, &sc->aac_intr)) {
322151086Sscottl				device_printf(sc->aac_dev,
323151086Sscottl					     "can't set up MPSAFE interrupt\n");
324151086Sscottl				return (EINVAL);
325151086Sscottl			}
326151086Sscottl		}
327151086Sscottl	}
328151086Sscottl
329151086Sscottl	/*
33083114Sscottl	 * Print a little information about the controller.
33183114Sscottl	 */
33283114Sscottl	aac_describe_controller(sc);
33365793Smsmith
33483114Sscottl	/*
335111532Sscottl	 * Register to probe our containers later.
33687183Sscottl	 */
33783114Sscottl	sc->aac_ich.ich_func = aac_startup;
33883114Sscottl	sc->aac_ich.ich_arg = sc;
33983114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
34083114Sscottl		device_printf(sc->aac_dev,
34183114Sscottl			      "can't establish configuration hook\n");
34283114Sscottl		return(ENXIO);
34383114Sscottl	}
34465793Smsmith
34583114Sscottl	/*
34683114Sscottl	 * Make the control device.
34783114Sscottl	 */
34883114Sscottl	unit = device_get_unit(sc->aac_dev);
349108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
350108329Srwatson				 0640, "aac%d", unit);
35183114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
35283114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
35383114Sscottl	sc->aac_dev_t->si_drv1 = sc;
35465793Smsmith
35583114Sscottl	/* Create the AIF thread */
356110426Sscottl	if (kthread_create((void(*)(void *))aac_command_thread, sc,
357151086Sscottl		   &sc->aifthread, 0, 0, "aac%daif", unit))
35883114Sscottl		panic("Could not create AIF thread\n");
35982527Sscottl
36083114Sscottl	/* Register the shutdown method to only be called post-dump */
361110427Sscottl	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
362110427Sscottl	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
363110427Sscottl		device_printf(sc->aac_dev,
364110427Sscottl			      "shutdown event registration failed\n");
36582527Sscottl
36695536Sscottl	/* Register with CAM for the non-DASD devices */
367112679Sscottl	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
368110426Sscottl		TAILQ_INIT(&sc->aac_sim_tqh);
36995536Sscottl		aac_get_bus_info(sc);
370110426Sscottl	}
37195536Sscottl
37283114Sscottl	return(0);
37365793Smsmith}
37465793Smsmith
375151086Sscottlvoid
376151086Sscottlaac_add_event(struct aac_softc *sc, struct aac_event *event)
377151086Sscottl{
378151086Sscottl
379151086Sscottl	switch (event->ev_type & AAC_EVENT_MASK) {
380151086Sscottl	case AAC_EVENT_CMFREE:
381151086Sscottl		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
382151086Sscottl		break;
383151086Sscottl	default:
384151086Sscottl		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
385151086Sscottl		    event->ev_type);
386151086Sscottl		break;
387151086Sscottl	}
388151086Sscottl
389151086Sscottl	return;
390151086Sscottl}
391151086Sscottl
39283114Sscottl/*
39365793Smsmith * Probe for containers, create disks.
39465793Smsmith */
39565793Smsmithstatic void
39665793Smsmithaac_startup(void *arg)
39765793Smsmith{
39883114Sscottl	struct aac_softc *sc;
39995350Sscottl	struct aac_fib *fib;
40095350Sscottl	struct aac_mntinfo *mi;
40195350Sscottl	struct aac_mntinforesp *mir = NULL;
402115760Sscottl	int count = 0, i = 0;
40365793Smsmith
40483114Sscottl	debug_called(1);
40565793Smsmith
40683114Sscottl	sc = (struct aac_softc *)arg;
40765793Smsmith
40883114Sscottl	/* disconnect ourselves from the intrhook chain */
40983114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
41065793Smsmith
411151086Sscottl	mtx_lock(&sc->aac_io_lock);
412130006Sscottl	aac_alloc_sync_fib(sc, &fib);
41395350Sscottl	mi = (struct aac_mntinfo *)&fib->data[0];
41495350Sscottl
41583114Sscottl	/* loop over possible containers */
41683114Sscottl	do {
41783114Sscottl		/* request information on this container */
41895966Sscottl		bzero(mi, sizeof(struct aac_mntinfo));
41995966Sscottl		mi->Command = VM_NameServe;
42095966Sscottl		mi->MntType = FT_FILESYS;
42195350Sscottl		mi->MntCount = i;
42295350Sscottl		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
42395350Sscottl				 sizeof(struct aac_mntinfo))) {
424115760Sscottl			printf("error probing container %d", i);
42583114Sscottl			continue;
42683114Sscottl		}
42765793Smsmith
42895350Sscottl		mir = (struct aac_mntinforesp *)&fib->data[0];
429115760Sscottl		/* XXX Need to check if count changed */
430115760Sscottl		count = mir->MntRespCount;
43195350Sscottl		aac_add_container(sc, mir, 0);
43283114Sscottl		i++;
433115760Sscottl	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
43465793Smsmith
43595350Sscottl	aac_release_sync_fib(sc);
436151086Sscottl	mtx_unlock(&sc->aac_io_lock);
43795350Sscottl
43883114Sscottl	/* poke the bus to actually attach the child devices */
43983114Sscottl	if (bus_generic_attach(sc->aac_dev))
44083114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
44165793Smsmith
44283114Sscottl	/* mark the controller up */
44383114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
44470393Smsmith
44583114Sscottl	/* enable interrupts now */
44683114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
44765793Smsmith}
44865793Smsmith
44983114Sscottl/*
45083114Sscottl * Create a device to respresent a new container
45183114Sscottl */
45283114Sscottlstatic void
45395350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
45483114Sscottl{
45583114Sscottl	struct aac_container *co;
45683114Sscottl	device_t child;
45783114Sscottl
45883114Sscottl	/*
45983114Sscottl	 * Check container volume type for validity.  Note that many of
46083114Sscottl	 * the possible types may never show up.
46183114Sscottl	 */
46283114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
463110428Sscottl		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
464110428Sscottl		       M_NOWAIT | M_ZERO);
46583114Sscottl		if (co == NULL)
46683114Sscottl			panic("Out of memory?!\n");
46783114Sscottl		debug(1, "id %x  name '%.16s'  size %u  type %d",
46883114Sscottl		      mir->MntTable[0].ObjectId,
46983114Sscottl		      mir->MntTable[0].FileSystemName,
47083114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
47183114Sscottl
47295536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
47383114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
47483114Sscottl		else
47583114Sscottl			device_set_ivars(child, co);
47683114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
47783114Sscottl				mir->MntTable[0].VolType));
47883114Sscottl		co->co_disk = child;
47983114Sscottl		co->co_found = f;
48083114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
48183114Sscottl		      sizeof(struct aac_mntobj));
482133540Sscottl		mtx_lock(&sc->aac_container_lock);
48383114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
484133540Sscottl		mtx_unlock(&sc->aac_container_lock);
48583114Sscottl	}
48683114Sscottl}
48783114Sscottl
48883114Sscottl/*
48965793Smsmith * Free all of the resources associated with (sc)
49065793Smsmith *
49165793Smsmith * Should not be called if the controller is active.
49265793Smsmith */
49365793Smsmithvoid
49465793Smsmithaac_free(struct aac_softc *sc)
49565793Smsmith{
496110604Sscottl
49783114Sscottl	debug_called(1);
49865793Smsmith
49983114Sscottl	/* remove the control device */
50083114Sscottl	if (sc->aac_dev_t != NULL)
50183114Sscottl		destroy_dev(sc->aac_dev_t);
50265793Smsmith
50383114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
504111141Sscottl	aac_free_commands(sc);
50583114Sscottl	if (sc->aac_fib_dmat)
50683114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
50765793Smsmith
508110604Sscottl	free(sc->aac_commands, M_AACBUF);
509110604Sscottl
51083114Sscottl	/* destroy the common area */
51183114Sscottl	if (sc->aac_common) {
51283114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
51383114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
51483114Sscottl				sc->aac_common_dmamap);
51583114Sscottl	}
51683114Sscottl	if (sc->aac_common_dmat)
51783114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
51865793Smsmith
51983114Sscottl	/* disconnect the interrupt handler */
52083114Sscottl	if (sc->aac_intr)
52183114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
52283114Sscottl	if (sc->aac_irq != NULL)
52383114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
52483114Sscottl				     sc->aac_irq);
52565793Smsmith
52683114Sscottl	/* destroy data-transfer DMA tag */
52783114Sscottl	if (sc->aac_buffer_dmat)
52883114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
52965793Smsmith
53083114Sscottl	/* destroy the parent DMA tag */
53183114Sscottl	if (sc->aac_parent_dmat)
53283114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
53365793Smsmith
53483114Sscottl	/* release the register window mapping */
53583114Sscottl	if (sc->aac_regs_resource != NULL)
53683114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
53783114Sscottl				     sc->aac_regs_rid, sc->aac_regs_resource);
53865793Smsmith}
53965793Smsmith
54083114Sscottl/*
54165793Smsmith * Disconnect from the controller completely, in preparation for unload.
54265793Smsmith */
54365793Smsmithint
54465793Smsmithaac_detach(device_t dev)
54565793Smsmith{
54683114Sscottl	struct aac_softc *sc;
547110426Sscottl	struct aac_container *co;
548110426Sscottl	struct aac_sim	*sim;
54983114Sscottl	int error;
55065793Smsmith
55183114Sscottl	debug_called(1);
55265793Smsmith
55383114Sscottl	sc = device_get_softc(dev);
55483114Sscottl
55583114Sscottl	if (sc->aac_state & AAC_STATE_OPEN)
556110426Sscottl		return(EBUSY);
55765793Smsmith
558110426Sscottl	/* Remove the child containers */
559110428Sscottl	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
560110426Sscottl		error = device_delete_child(dev, co->co_disk);
561110426Sscottl		if (error)
562110426Sscottl			return (error);
563111196Sscottl		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
564110428Sscottl		free(co, M_AACBUF);
565110426Sscottl	}
566110426Sscottl
567110426Sscottl	/* Remove the CAM SIMs */
568110428Sscottl	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
569110428Sscottl		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
570110426Sscottl		error = device_delete_child(dev, sim->sim_dev);
571110426Sscottl		if (error)
572110426Sscottl			return (error);
573110428Sscottl		free(sim, M_AACBUF);
574110426Sscottl	}
575110426Sscottl
57683114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
57783114Sscottl		sc->aifflags |= AAC_AIFFLAGS_EXIT;
57883114Sscottl		wakeup(sc->aifthread);
57983114Sscottl		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
58083114Sscottl	}
58182527Sscottl
58283114Sscottl	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
58383114Sscottl		panic("Cannot shutdown AIF thread\n");
58482527Sscottl
58583114Sscottl	if ((error = aac_shutdown(dev)))
58683114Sscottl		return(error);
58765793Smsmith
588110427Sscottl	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
589110427Sscottl
59083114Sscottl	aac_free(sc);
59165793Smsmith
592133542Sscottl	mtx_destroy(&sc->aac_aifq_lock);
593133542Sscottl	mtx_destroy(&sc->aac_io_lock);
594133542Sscottl	mtx_destroy(&sc->aac_container_lock);
595133542Sscottl
59683114Sscottl	return(0);
59765793Smsmith}
59865793Smsmith
59983114Sscottl/*
60065793Smsmith * Bring the controller down to a dormant state and detach all child devices.
60165793Smsmith *
60265793Smsmith * This function is called before detach or system shutdown.
60365793Smsmith *
60470393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
60565793Smsmith * allow shutdown if any device is open.
60665793Smsmith */
60765793Smsmithint
60865793Smsmithaac_shutdown(device_t dev)
60965793Smsmith{
61083114Sscottl	struct aac_softc *sc;
61195350Sscottl	struct aac_fib *fib;
61295350Sscottl	struct aac_close_command *cc;
61365793Smsmith
61483114Sscottl	debug_called(1);
61565793Smsmith
61683114Sscottl	sc = device_get_softc(dev);
61765793Smsmith
61883114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
61965793Smsmith
62083114Sscottl	/*
62183114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
62283114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
62383114Sscottl	 * We've been closed and all I/O completed already
62482527Sscottl	 */
62583114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
62683114Sscottl
627151086Sscottl	mtx_lock(&sc->aac_io_lock);
628130006Sscottl	aac_alloc_sync_fib(sc, &fib);
62995350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
63095350Sscottl
63195966Sscottl	bzero(cc, sizeof(struct aac_close_command));
63295350Sscottl	cc->Command = VM_CloseAll;
63395350Sscottl	cc->ContainerId = 0xffffffff;
63495350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
63595350Sscottl	    sizeof(struct aac_close_command)))
63683114Sscottl		printf("FAILED.\n");
637110426Sscottl	else
638110426Sscottl		printf("done\n");
639110426Sscottl#if 0
64083114Sscottl	else {
64195350Sscottl		fib->data[0] = 0;
64283114Sscottl		/*
64383114Sscottl		 * XXX Issuing this command to the controller makes it shut down
64483114Sscottl		 * but also keeps it from coming back up without a reset of the
64583114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
64683114Sscottl		 * driver module with the intent to reload it later.
64783114Sscottl		 */
64895350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
64995350Sscottl		    fib, 1)) {
65083114Sscottl			printf("FAILED.\n");
65183114Sscottl		} else {
65283114Sscottl			printf("done.\n");
65383114Sscottl		}
65465793Smsmith	}
655110426Sscottl#endif
65665793Smsmith
65783114Sscottl	AAC_MASK_INTERRUPTS(sc);
658133539Sscottl	aac_release_sync_fib(sc);
659151086Sscottl	mtx_unlock(&sc->aac_io_lock);
66065793Smsmith
66183114Sscottl	return(0);
66265793Smsmith}
66365793Smsmith
66483114Sscottl/*
66565793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
66665793Smsmith */
66765793Smsmithint
66865793Smsmithaac_suspend(device_t dev)
66965793Smsmith{
67083114Sscottl	struct aac_softc *sc;
67165793Smsmith
67283114Sscottl	debug_called(1);
67365793Smsmith
67483114Sscottl	sc = device_get_softc(dev);
67583114Sscottl
67683114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
67783114Sscottl
67883114Sscottl	AAC_MASK_INTERRUPTS(sc);
67983114Sscottl	return(0);
68065793Smsmith}
68165793Smsmith
68283114Sscottl/*
68365793Smsmith * Bring the controller back to a state ready for operation.
68465793Smsmith */
68565793Smsmithint
68665793Smsmithaac_resume(device_t dev)
68765793Smsmith{
68883114Sscottl	struct aac_softc *sc;
68965793Smsmith
69083114Sscottl	debug_called(1);
69183114Sscottl
69283114Sscottl	sc = device_get_softc(dev);
69383114Sscottl
69483114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
69583114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
69683114Sscottl	return(0);
69765793Smsmith}
69865793Smsmith
69983114Sscottl/*
700151086Sscottl * Interrupt handler for NEW_COMM interface.
70165793Smsmith */
70265793Smsmithvoid
703151086Sscottlaac_new_intr(void *arg)
70465793Smsmith{
70583114Sscottl	struct aac_softc *sc;
706151086Sscottl	u_int32_t index, fast;
707151086Sscottl	struct aac_command *cm;
708151086Sscottl	struct aac_fib *fib;
709151086Sscottl	int i;
710151086Sscottl
711151086Sscottl	debug_called(2);
712151086Sscottl
713151086Sscottl	sc = (struct aac_softc *)arg;
714151086Sscottl
715151086Sscottl	mtx_lock(&sc->aac_io_lock);
716151086Sscottl	while (1) {
717151086Sscottl		index = AAC_GET_OUTB_QUEUE(sc);
718151086Sscottl		if (index == 0xffffffff)
719151086Sscottl			index = AAC_GET_OUTB_QUEUE(sc);
720151086Sscottl		if (index == 0xffffffff)
721151086Sscottl			break;
722151086Sscottl		if (index & 2) {
723151086Sscottl			if (index == 0xfffffffe) {
724151086Sscottl				/* XXX This means that the controller wants
725151086Sscottl				 * more work.  Ignore it for now.
726151086Sscottl				 */
727151086Sscottl				continue;
728151086Sscottl			}
729151086Sscottl			/* AIF */
730151086Sscottl			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
731151086Sscottl				   M_NOWAIT | M_ZERO);
732151086Sscottl			if (fib == NULL) {
733151086Sscottl				/* If we're really this short on memory,
734151086Sscottl				 * hopefully breaking out of the handler will
735151086Sscottl				 * allow something to get freed.  This
736151086Sscottl				 * actually sucks a whole lot.
737151086Sscottl				 */
738151086Sscottl				break;
739151086Sscottl			}
740151086Sscottl			index &= ~2;
741151086Sscottl			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
742151086Sscottl				((u_int32_t *)fib)[i] = AAC_GETREG4(sc, index + i*4);
743151086Sscottl			aac_handle_aif(sc, fib);
744151086Sscottl			free(fib, M_AACBUF);
745151086Sscottl
746151086Sscottl			/*
747151086Sscottl			 * AIF memory is owned by the adapter, so let it
748151086Sscottl			 * know that we are done with it.
749151086Sscottl			 */
750151086Sscottl			AAC_SET_OUTB_QUEUE(sc, index);
751151086Sscottl			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
752151086Sscottl		} else {
753151086Sscottl			fast = index & 1;
754151086Sscottl			cm = sc->aac_commands + (index >> 2);
755151086Sscottl			fib = cm->cm_fib;
756151086Sscottl			if (fast) {
757151086Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
758151086Sscottl				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
759151086Sscottl			}
760151086Sscottl			aac_remove_busy(cm);
761151086Sscottl 			aac_unmap_command(cm);
762151086Sscottl			cm->cm_flags |= AAC_CMD_COMPLETED;
763151086Sscottl
764151086Sscottl			/* is there a completion handler? */
765151086Sscottl			if (cm->cm_complete != NULL) {
766151086Sscottl				cm->cm_complete(cm);
767151086Sscottl			} else {
768151086Sscottl				/* assume that someone is sleeping on this
769151086Sscottl				 * command
770151086Sscottl				 */
771151086Sscottl				wakeup(cm);
772151086Sscottl			}
773151086Sscottl			sc->flags &= ~AAC_QUEUE_FRZN;
774151086Sscottl		}
775151086Sscottl	}
776151086Sscottl	/* see if we can start some more I/O */
777151086Sscottl	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
778151086Sscottl		aac_startio(sc);
779151086Sscottl
780151086Sscottl	mtx_unlock(&sc->aac_io_lock);
781151086Sscottl}
782151086Sscottl
783151086Sscottlvoid
784151086Sscottlaac_fast_intr(void *arg)
785151086Sscottl{
786151086Sscottl	struct aac_softc *sc;
78783114Sscottl	u_int16_t reason;
78865793Smsmith
78983114Sscottl	debug_called(2);
79065793Smsmith
79183114Sscottl	sc = (struct aac_softc *)arg;
79265793Smsmith
793109088Sscottl	/*
794125225Sscottl	 * Read the status register directly.  This is faster than taking the
795125225Sscottl	 * driver lock and reading the queues directly.  It also saves having
796125225Sscottl	 * to turn parts of the driver lock into a spin mutex, which would be
797125225Sscottl	 * ugly.
798109088Sscottl	 */
799125225Sscottl	reason = AAC_GET_ISTATUS(sc);
800109088Sscottl	AAC_CLEAR_ISTATUS(sc, reason);
80165793Smsmith
802125225Sscottl	/* handle completion processing */
803109088Sscottl	if (reason & AAC_DB_RESPONSE_READY)
804125225Sscottl		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
805109088Sscottl
806125225Sscottl	/* controller wants to talk to us */
807125225Sscottl	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
808125225Sscottl		/*
809125225Sscottl		 * XXX Make sure that we don't get fooled by strange messages
810125225Sscottl		 * that start with a NULL.
811125225Sscottl		 */
812125225Sscottl		if ((reason & AAC_DB_PRINTF) &&
813151086Sscottl			(sc->aac_common->ac_printf[0] == 0))
814125225Sscottl			sc->aac_common->ac_printf[0] = 32;
81565793Smsmith
816125225Sscottl		/*
817125225Sscottl		 * This might miss doing the actual wakeup.  However, the
818125542Sscottl		 * msleep that this is waking up has a timeout, so it will
819125225Sscottl		 * wake up eventually.  AIFs and printfs are low enough
820125225Sscottl		 * priority that they can handle hanging out for a few seconds
821125225Sscottl		 * if needed.
822125225Sscottl		 */
823125225Sscottl		wakeup(sc->aifthread);
82483114Sscottl	}
825109088Sscottl}
82683114Sscottl
82783114Sscottl/*
82883114Sscottl * Command Processing
82983114Sscottl */
83065793Smsmith
83183114Sscottl/*
83265793Smsmith * Start as much queued I/O as possible on the controller
83365793Smsmith */
83495536Sscottlvoid
83565793Smsmithaac_startio(struct aac_softc *sc)
83665793Smsmith{
83783114Sscottl	struct aac_command *cm;
838129923Sscottl	int error;
83965793Smsmith
84083114Sscottl	debug_called(2);
84165793Smsmith
84283114Sscottl	for (;;) {
84383114Sscottl		/*
844129923Sscottl		 * This flag might be set if the card is out of resources.
845129923Sscottl		 * Checking it here prevents an infinite loop of deferrals.
846129923Sscottl		 */
847129923Sscottl		if (sc->flags & AAC_QUEUE_FRZN)
848129923Sscottl			break;
849129923Sscottl
850129923Sscottl		/*
85183114Sscottl		 * Try to get a command that's been put off for lack of
85283114Sscottl		 * resources
85383114Sscottl		 */
85483114Sscottl		cm = aac_dequeue_ready(sc);
85565793Smsmith
85683114Sscottl		/*
85783114Sscottl		 * Try to build a command off the bio queue (ignore error
85883114Sscottl		 * return)
85983114Sscottl		 */
86083114Sscottl		if (cm == NULL)
86183114Sscottl			aac_bio_command(sc, &cm);
86265793Smsmith
86383114Sscottl		/* nothing to do? */
86483114Sscottl		if (cm == NULL)
86583114Sscottl			break;
86665793Smsmith
867129923Sscottl		/* don't map more than once */
868129923Sscottl		if (cm->cm_flags & AAC_CMD_MAPPED)
869129923Sscottl			panic("aac: command %p already mapped", cm);
870129923Sscottl
871125559Sscottl		/*
872129923Sscottl		 * Set up the command to go to the controller.  If there are no
873129923Sscottl		 * data buffers associated with the command then it can bypass
874129923Sscottl		 * busdma.
875125559Sscottl		 */
876129923Sscottl		if (cm->cm_datalen != 0) {
877129923Sscottl			error = bus_dmamap_load(sc->aac_buffer_dmat,
878129923Sscottl						cm->cm_datamap, cm->cm_data,
879129923Sscottl						cm->cm_datalen,
880129923Sscottl						aac_map_command_sg, cm, 0);
881129923Sscottl			if (error == EINPROGRESS) {
882129923Sscottl				debug(1, "freezing queue\n");
883129923Sscottl				sc->flags |= AAC_QUEUE_FRZN;
884129923Sscottl				error = 0;
885129946Sscottl			} else if (error != 0)
886129923Sscottl				panic("aac_startio: unexpected error %d from "
887129923Sscottl				      "busdma\n", error);
888129923Sscottl		} else
889129923Sscottl			aac_map_command_sg(cm, NULL, 0, 0);
89065793Smsmith	}
89165793Smsmith}
89265793Smsmith
89383114Sscottl/*
89465793Smsmith * Handle notification of one or more FIBs coming from the controller.
89565793Smsmith */
89665793Smsmithstatic void
897110426Sscottlaac_command_thread(struct aac_softc *sc)
89865793Smsmith{
89983114Sscottl	struct aac_fib *fib;
90083114Sscottl	u_int32_t fib_size;
901125225Sscottl	int size, retval;
90265793Smsmith
90383114Sscottl	debug_called(2);
90465793Smsmith
905133540Sscottl	mtx_lock(&sc->aac_io_lock);
906125542Sscottl	sc->aifflags = AAC_AIFFLAGS_RUNNING;
90765793Smsmith
908125542Sscottl	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
90982527Sscottl
910125542Sscottl		retval = 0;
911125542Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
912125542Sscottl			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
913125542Sscottl					"aifthd", AAC_PERIODIC_INTERVAL * hz);
914125542Sscottl
915125225Sscottl		/*
916125225Sscottl		 * First see if any FIBs need to be allocated.  This needs
917125225Sscottl		 * to be called without the driver lock because contigmalloc
918125225Sscottl		 * will grab Giant, and would result in an LOR.
919125225Sscottl		 */
920125225Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
921133540Sscottl			mtx_unlock(&sc->aac_io_lock);
922125225Sscottl			aac_alloc_commands(sc);
923133540Sscottl			mtx_lock(&sc->aac_io_lock);
924125559Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
925125542Sscottl			aac_startio(sc);
926125225Sscottl		}
927125225Sscottl
928125225Sscottl		/*
929125225Sscottl		 * While we're here, check to see if any commands are stuck.
930125225Sscottl		 * This is pretty low-priority, so it's ok if it doesn't
931125225Sscottl		 * always fire.
932125225Sscottl		 */
933125225Sscottl		if (retval == EWOULDBLOCK)
934110426Sscottl			aac_timeout(sc);
935110426Sscottl
936110426Sscottl		/* Check the hardware printf message buffer */
937125225Sscottl		if (sc->aac_common->ac_printf[0] != 0)
938110426Sscottl			aac_print_printf(sc);
939110426Sscottl
940125225Sscottl		/* Also check to see if the adapter has a command for us. */
941151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
942151086Sscottl			continue;
943151086Sscottl		for (;;) {
944151086Sscottl			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
945151086Sscottl					   &fib_size, &fib))
946151086Sscottl				break;
94783114Sscottl
94883114Sscottl			AAC_PRINT_FIB(sc, fib);
94983114Sscottl
95083114Sscottl			switch (fib->Header.Command) {
95183114Sscottl			case AifRequest:
95283114Sscottl				aac_handle_aif(sc, fib);
95383114Sscottl				break;
95483114Sscottl			default:
95583114Sscottl				device_printf(sc->aac_dev, "unknown command "
95683114Sscottl					      "from controller\n");
95783114Sscottl				break;
95883114Sscottl			}
95982527Sscottl
96083114Sscottl			if ((fib->Header.XferState == 0) ||
961151086Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
96283114Sscottl				break;
963151086Sscottl			}
96482527Sscottl
965110426Sscottl			/* Return the AIF to the controller. */
96683114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
96783114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
96883114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
96982527Sscottl
97083114Sscottl				/* XXX Compute the Size field? */
97183114Sscottl				size = fib->Header.Size;
97283114Sscottl				if (size > sizeof(struct aac_fib)) {
97395536Sscottl					size = sizeof(struct aac_fib);
97483114Sscottl					fib->Header.Size = size;
97583114Sscottl				}
97683114Sscottl				/*
97783114Sscottl				 * Since we did not generate this command, it
97883114Sscottl				 * cannot go through the normal
97983114Sscottl				 * enqueue->startio chain.
98083114Sscottl				 */
98183114Sscottl				aac_enqueue_response(sc,
982151086Sscottl						 AAC_ADAP_NORM_RESP_QUEUE,
983151086Sscottl						 fib);
98483114Sscottl			}
98582527Sscottl		}
98665793Smsmith	}
98783114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
988133540Sscottl	mtx_unlock(&sc->aac_io_lock);
98983114Sscottl	wakeup(sc->aac_dev);
99065793Smsmith
99183114Sscottl	kthread_exit(0);
99265793Smsmith}
99365793Smsmith
99483114Sscottl/*
995111143Sscottl * Process completed commands.
99665793Smsmith */
99765793Smsmithstatic void
998111143Sscottlaac_complete(void *context, int pending)
99965793Smsmith{
1000111143Sscottl	struct aac_softc *sc;
100183114Sscottl	struct aac_command *cm;
100283114Sscottl	struct aac_fib *fib;
100383114Sscottl	u_int32_t fib_size;
100465793Smsmith
100583114Sscottl	debug_called(2);
100665793Smsmith
1007111143Sscottl	sc = (struct aac_softc *)context;
1008111143Sscottl
1009133540Sscottl	mtx_lock(&sc->aac_io_lock);
1010111532Sscottl
1011111143Sscottl	/* pull completed commands off the queue */
101283114Sscottl	for (;;) {
101383114Sscottl		/* look for completed FIBs on our queue */
101483114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1015151086Sscottl							&fib))
101683114Sscottl			break;	/* nothing to do */
1017111143Sscottl
1018125574Sscottl		/* get the command, unmap and hand off for processing */
1019111152Sscottl		cm = sc->aac_commands + fib->Header.SenderData;
102083114Sscottl		if (cm == NULL) {
102183114Sscottl			AAC_PRINT_FIB(sc, fib);
1022111143Sscottl			break;
102383114Sscottl		}
1024151086Sscottl		aac_remove_busy(cm);
102565793Smsmith
1026151086Sscottl 		aac_unmap_command(cm);
102783114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
102883114Sscottl
102983114Sscottl		/* is there a completion handler? */
103083114Sscottl		if (cm->cm_complete != NULL) {
103183114Sscottl			cm->cm_complete(cm);
103283114Sscottl		} else {
103383114Sscottl			/* assume that someone is sleeping on this command */
103483114Sscottl			wakeup(cm);
103583114Sscottl		}
103665793Smsmith	}
103770393Smsmith
103883114Sscottl	/* see if we can start some more I/O */
1039117363Sscottl	sc->flags &= ~AAC_QUEUE_FRZN;
104083114Sscottl	aac_startio(sc);
1041111532Sscottl
1042133540Sscottl	mtx_unlock(&sc->aac_io_lock);
104365793Smsmith}
104465793Smsmith
104583114Sscottl/*
104665793Smsmith * Handle a bio submitted from a disk device.
104765793Smsmith */
104865793Smsmithvoid
104965793Smsmithaac_submit_bio(struct bio *bp)
105065793Smsmith{
105183114Sscottl	struct aac_disk *ad;
105283114Sscottl	struct aac_softc *sc;
105365793Smsmith
105483114Sscottl	debug_called(2);
105565793Smsmith
1056111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
105783114Sscottl	sc = ad->ad_controller;
105883114Sscottl
105983114Sscottl	/* queue the BIO and try to get some work done */
106083114Sscottl	aac_enqueue_bio(sc, bp);
106183114Sscottl	aac_startio(sc);
106265793Smsmith}
106365793Smsmith
106483114Sscottl/*
106565793Smsmith * Get a bio and build a command to go with it.
106665793Smsmith */
106765793Smsmithstatic int
106865793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
106965793Smsmith{
107083114Sscottl	struct aac_command *cm;
107183114Sscottl	struct aac_fib *fib;
107283114Sscottl	struct aac_disk *ad;
107383114Sscottl	struct bio *bp;
107465793Smsmith
107583114Sscottl	debug_called(2);
107665793Smsmith
107783114Sscottl	/* get the resources we will need */
107883114Sscottl	cm = NULL;
1079125542Sscottl	bp = NULL;
1080125542Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
1081125542Sscottl		goto fail;
108283114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
108383114Sscottl		goto fail;
108465793Smsmith
108583114Sscottl	/* fill out the command */
108683114Sscottl	cm->cm_data = (void *)bp->bio_data;
108783114Sscottl	cm->cm_datalen = bp->bio_bcount;
108883114Sscottl	cm->cm_complete = aac_bio_complete;
108983114Sscottl	cm->cm_private = bp;
1090150119Sscottl	cm->cm_timestamp = time_uptime;
109183114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
109265793Smsmith
109383114Sscottl	/* build the FIB */
109483114Sscottl	fib = cm->cm_fib;
1095112856Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
109683114Sscottl	fib->Header.XferState =
1097109088Sscottl		AAC_FIBSTATE_HOSTOWNED   |
1098109088Sscottl		AAC_FIBSTATE_INITIALISED |
1099109088Sscottl		AAC_FIBSTATE_EMPTY	 |
1100109088Sscottl		AAC_FIBSTATE_FROMHOST	 |
1101109088Sscottl		AAC_FIBSTATE_REXPECTED   |
1102109088Sscottl		AAC_FIBSTATE_NORM	 |
1103109088Sscottl		AAC_FIBSTATE_ASYNC	 |
1104109088Sscottl		AAC_FIBSTATE_FAST_RESPONSE;
110565793Smsmith
110683114Sscottl	/* build the read/write request */
1107111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1108112856Sscottl
1109151086Sscottl	if (sc->flags & AAC_FLAGS_RAW_IO) {
1110151086Sscottl		struct aac_raw_io *raw;
1111151086Sscottl		raw = (struct aac_raw_io *)&fib->data[0];
1112151086Sscottl		fib->Header.Command = RawIo;
1113151086Sscottl		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
1114151086Sscottl		raw->ByteCount = bp->bio_bcount;
1115151086Sscottl		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1116151086Sscottl		raw->BpTotal = 0;
1117151086Sscottl		raw->BpComplete = 0;
1118151086Sscottl		fib->Header.Size += sizeof(struct aac_raw_io);
1119151086Sscottl		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
1120151086Sscottl		if (bp->bio_cmd == BIO_READ) {
1121151086Sscottl			raw->Flags = 1;
1122151086Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1123151086Sscottl		} else {
1124151086Sscottl			raw->Flags = 0;
1125151086Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1126151086Sscottl		}
1127151086Sscottl	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1128112856Sscottl		fib->Header.Command = ContainerCommand;
1129112856Sscottl		if (bp->bio_cmd == BIO_READ) {
1130112856Sscottl			struct aac_blockread *br;
1131112856Sscottl			br = (struct aac_blockread *)&fib->data[0];
1132112856Sscottl			br->Command = VM_CtBlockRead;
1133112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1134112856Sscottl			br->BlockNumber = bp->bio_pblkno;
1135112856Sscottl			br->ByteCount = bp->bio_bcount;
1136112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread);
1137112856Sscottl			cm->cm_sgtable = &br->SgMap;
1138112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1139112856Sscottl		} else {
1140112856Sscottl			struct aac_blockwrite *bw;
1141112856Sscottl			bw = (struct aac_blockwrite *)&fib->data[0];
1142112856Sscottl			bw->Command = VM_CtBlockWrite;
1143112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1144112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
1145112856Sscottl			bw->ByteCount = bp->bio_bcount;
1146112856Sscottl			bw->Stable = CUNSTABLE;
1147112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite);
1148112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1149112856Sscottl			cm->cm_sgtable = &bw->SgMap;
1150112856Sscottl		}
115183114Sscottl	} else {
1152112856Sscottl		fib->Header.Command = ContainerCommand64;
1153112856Sscottl		if (bp->bio_cmd == BIO_READ) {
1154112856Sscottl			struct aac_blockread64 *br;
1155112856Sscottl			br = (struct aac_blockread64 *)&fib->data[0];
1156112856Sscottl			br->Command = VM_CtHostRead64;
1157112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1158112856Sscottl			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1159112856Sscottl			br->BlockNumber = bp->bio_pblkno;
1160112856Sscottl			br->Pad = 0;
1161112856Sscottl			br->Flags = 0;
1162112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread64);
1163112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1164132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1165112856Sscottl		} else {
1166112856Sscottl			struct aac_blockwrite64 *bw;
1167112856Sscottl			bw = (struct aac_blockwrite64 *)&fib->data[0];
1168112856Sscottl			bw->Command = VM_CtHostWrite64;
1169112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1170112856Sscottl			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1171112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
1172112856Sscottl			bw->Pad = 0;
1173112856Sscottl			bw->Flags = 0;
1174112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite64);
1175112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1176132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1177112856Sscottl		}
117883114Sscottl	}
117965793Smsmith
118083114Sscottl	*cmp = cm;
118183114Sscottl	return(0);
118265793Smsmith
118365793Smsmithfail:
1184151086Sscottl	if (bp != NULL)
1185151086Sscottl		aac_enqueue_bio(sc, bp);
118683114Sscottl	if (cm != NULL)
118783114Sscottl		aac_release_command(cm);
118883114Sscottl	return(ENOMEM);
118965793Smsmith}
119065793Smsmith
119183114Sscottl/*
119265793Smsmith * Handle a bio-instigated command that has been completed.
119365793Smsmith */
119465793Smsmithstatic void
119565793Smsmithaac_bio_complete(struct aac_command *cm)
119665793Smsmith{
119783114Sscottl	struct aac_blockread_response *brr;
119883114Sscottl	struct aac_blockwrite_response *bwr;
119983114Sscottl	struct bio *bp;
120083114Sscottl	AAC_FSAStatus status;
120165793Smsmith
120283114Sscottl	/* fetch relevant status and then release the command */
120383114Sscottl	bp = (struct bio *)cm->cm_private;
1204111691Sscottl	if (bp->bio_cmd == BIO_READ) {
120583114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
120683114Sscottl		status = brr->Status;
120783114Sscottl	} else {
120883114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
120983114Sscottl		status = bwr->Status;
121083114Sscottl	}
121183114Sscottl	aac_release_command(cm);
121265793Smsmith
121383114Sscottl	/* fix up the bio based on status */
121483114Sscottl	if (status == ST_OK) {
121583114Sscottl		bp->bio_resid = 0;
121683114Sscottl	} else {
121783114Sscottl		bp->bio_error = EIO;
121883114Sscottl		bp->bio_flags |= BIO_ERROR;
121983114Sscottl		/* pass an error string out to the disk layer */
122083114Sscottl		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
122183114Sscottl						    status);
122283114Sscottl	}
122383114Sscottl	aac_biodone(bp);
122465793Smsmith}
122565793Smsmith
122683114Sscottl/*
122765793Smsmith * Submit a command to the controller, return when it completes.
122887183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
122987183Sscottl *     be stuck here forever.  At the same time, signals are not caught
1230128258Sscottl *     because there is a risk that a signal could wakeup the sleep before
1231128258Sscottl *     the card has a chance to complete the command.  Since there is no way
1232128258Sscottl *     to cancel a command that is in progress, we can't protect against the
1233128258Sscottl *     card completing a command late and spamming the command and data
1234128258Sscottl *     memory.  So, we are held hostage until the command completes.
123565793Smsmith */
123665793Smsmithstatic int
1237128258Sscottlaac_wait_command(struct aac_command *cm)
123865793Smsmith{
1239111532Sscottl	struct aac_softc *sc;
1240128258Sscottl	int error;
124165793Smsmith
124283114Sscottl	debug_called(2);
124365793Smsmith
1244111532Sscottl	sc = cm->cm_sc;
1245111532Sscottl
124683114Sscottl	/* Put the command on the ready queue and get things going */
124783114Sscottl	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
124883114Sscottl	aac_enqueue_ready(cm);
1249111532Sscottl	aac_startio(sc);
1250128258Sscottl	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
125183114Sscottl	return(error);
125265793Smsmith}
125365793Smsmith
125483114Sscottl/*
125583114Sscottl *Command Buffer Management
125683114Sscottl */
125765793Smsmith
125883114Sscottl/*
125965793Smsmith * Allocate a command.
126065793Smsmith */
126195536Sscottlint
126265793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
126365793Smsmith{
126483114Sscottl	struct aac_command *cm;
126565793Smsmith
126683114Sscottl	debug_called(3);
126765793Smsmith
1268110604Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL) {
1269112856Sscottl		if (sc->total_fibs < sc->aac_max_fibs) {
1270112856Sscottl			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1271112856Sscottl			wakeup(sc->aifthread);
1272112856Sscottl		}
1273111532Sscottl		return (EBUSY);
1274110604Sscottl	}
127565793Smsmith
127683114Sscottl	*cmp = cm;
127783114Sscottl	return(0);
127870393Smsmith}
127970393Smsmith
128083114Sscottl/*
128170393Smsmith * Release a command back to the freelist.
128270393Smsmith */
128395536Sscottlvoid
128470393Smsmithaac_release_command(struct aac_command *cm)
128570393Smsmith{
1286151086Sscottl	struct aac_event *event;
1287151086Sscottl	struct aac_softc *sc;
1288151086Sscottl
128983114Sscottl	debug_called(3);
129070393Smsmith
129183114Sscottl	/* (re)initialise the command/FIB */
129283114Sscottl	cm->cm_sgtable = NULL;
129383114Sscottl	cm->cm_flags = 0;
129483114Sscottl	cm->cm_complete = NULL;
129583114Sscottl	cm->cm_private = NULL;
129683114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
129783114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
129883114Sscottl	cm->cm_fib->Header.Flags = 0;
1299151086Sscottl	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
130065793Smsmith
130183114Sscottl	/*
130283114Sscottl	 * These are duplicated in aac_start to cover the case where an
130383114Sscottl	 * intermediate stage may have destroyed them.  They're left
130483114Sscottl	 * initialised here for debugging purposes only.
130583114Sscottl	 */
1306109088Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1307109088Sscottl	cm->cm_fib->Header.SenderData = 0;
130865793Smsmith
130983114Sscottl	aac_enqueue_free(cm);
1310151086Sscottl
1311151086Sscottl	sc = cm->cm_sc;
1312151086Sscottl	event = TAILQ_FIRST(&sc->aac_ev_cmfree);
1313151086Sscottl	if (event != NULL) {
1314151086Sscottl		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
1315151086Sscottl		event->ev_callback(sc, event, event->ev_arg);
1316151086Sscottl	}
131765793Smsmith}
131865793Smsmith
131983114Sscottl/*
132070393Smsmith * Map helper for command/FIB allocation.
132165793Smsmith */
132265793Smsmithstatic void
132370393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
132465793Smsmith{
1325151086Sscottl	uint64_t	*fibphys;
132665793Smsmith
1327151086Sscottl	fibphys = (uint64_t *)arg;
132865793Smsmith
132983114Sscottl	debug_called(3);
133083114Sscottl
1331110604Sscottl	*fibphys = segs[0].ds_addr;
133265793Smsmith}
133365793Smsmith
133483114Sscottl/*
133570393Smsmith * Allocate and initialise commands/FIBs for this adapter.
133665793Smsmith */
133770393Smsmithstatic int
133870393Smsmithaac_alloc_commands(struct aac_softc *sc)
133965793Smsmith{
134083114Sscottl	struct aac_command *cm;
1341110604Sscottl	struct aac_fibmap *fm;
1342151086Sscottl	uint64_t fibphys;
1343110604Sscottl	int i, error;
134465793Smsmith
1345112679Sscottl	debug_called(2);
134665793Smsmith
1347151086Sscottl	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1348110604Sscottl		return (ENOMEM);
1349110604Sscottl
1350111141Sscottl	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1351112679Sscottl	if (fm == NULL)
1352112679Sscottl		return (ENOMEM);
1353110604Sscottl
135483114Sscottl	/* allocate the FIBs in DMAable memory and load them */
1355110604Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1356110604Sscottl			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1357110426Sscottl		device_printf(sc->aac_dev,
1358110426Sscottl			      "Not enough contiguous memory available.\n");
1359111141Sscottl		free(fm, M_AACBUF);
1360102602Sscottl		return (ENOMEM);
136183114Sscottl	}
1362109716Sscottl
1363117363Sscottl	/* Ignore errors since this doesn't bounce */
1364117363Sscottl	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1365151086Sscottl			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1366117363Sscottl			      aac_map_command_helper, &fibphys, 0);
1367109716Sscottl
1368109716Sscottl	/* initialise constant fields in the command structure */
1369133540Sscottl	mtx_lock(&sc->aac_io_lock);
1370151086Sscottl	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
1371151086Sscottl	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
1372111141Sscottl		cm = sc->aac_commands + sc->total_fibs;
1373110604Sscottl		fm->aac_commands = cm;
137483114Sscottl		cm->cm_sc = sc;
1375151086Sscottl		cm->cm_fib = (struct aac_fib *)
1376151086Sscottl			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
1377151086Sscottl		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1378111152Sscottl		cm->cm_index = sc->total_fibs;
137965793Smsmith
1380110604Sscottl		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1381110604Sscottl					       &cm->cm_datamap)) == 0)
138283114Sscottl			aac_release_command(cm);
1383111141Sscottl		else
1384111141Sscottl			break;
1385111141Sscottl		sc->total_fibs++;
138683114Sscottl	}
1387110604Sscottl
1388111141Sscottl	if (i > 0) {
1389111141Sscottl		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1390112679Sscottl		debug(1, "total_fibs= %d\n", sc->total_fibs);
1391133540Sscottl		mtx_unlock(&sc->aac_io_lock);
1392111141Sscottl		return (0);
1393111141Sscottl	}
1394110604Sscottl
1395133540Sscottl	mtx_unlock(&sc->aac_io_lock);
1396111141Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1397111141Sscottl	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1398111141Sscottl	free(fm, M_AACBUF);
1399111141Sscottl	return (ENOMEM);
140065793Smsmith}
140165793Smsmith
140283114Sscottl/*
140370393Smsmith * Free FIBs owned by this adapter.
140465793Smsmith */
140565793Smsmithstatic void
1406111141Sscottlaac_free_commands(struct aac_softc *sc)
140765793Smsmith{
1408111141Sscottl	struct aac_fibmap *fm;
1409110604Sscottl	struct aac_command *cm;
141083114Sscottl	int i;
141165793Smsmith
141283114Sscottl	debug_called(1);
141365793Smsmith
1414111141Sscottl	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1415111141Sscottl
1416111141Sscottl		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1417111141Sscottl		/*
1418111141Sscottl		 * We check against total_fibs to handle partially
1419111141Sscottl		 * allocated blocks.
1420111141Sscottl		 */
1421151086Sscottl		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1422111141Sscottl			cm = fm->aac_commands + i;
1423111141Sscottl			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1424111141Sscottl		}
1425111141Sscottl		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1426111141Sscottl		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1427111141Sscottl		free(fm, M_AACBUF);
1428110604Sscottl	}
142965793Smsmith}
143065793Smsmith
143183114Sscottl/*
143265793Smsmith * Command-mapping helper function - populate this command's s/g table.
143365793Smsmith */
143465793Smsmithstatic void
143565793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
143665793Smsmith{
1437117363Sscottl	struct aac_softc *sc;
143883114Sscottl	struct aac_command *cm;
143983114Sscottl	struct aac_fib *fib;
144083114Sscottl	int i;
144165793Smsmith
144283114Sscottl	debug_called(3);
144365793Smsmith
144483114Sscottl	cm = (struct aac_command *)arg;
1445117363Sscottl	sc = cm->cm_sc;
144683114Sscottl	fib = cm->cm_fib;
144765793Smsmith
144883114Sscottl	/* copy into the FIB */
1449112856Sscottl	if (cm->cm_sgtable != NULL) {
1450151086Sscottl		if (fib->Header.Command == RawIo) {
1451151086Sscottl			struct aac_sg_tableraw *sg;
1452151086Sscottl			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
1453151086Sscottl			sg->SgCount = nseg;
1454151086Sscottl			for (i = 0; i < nseg; i++) {
1455151086Sscottl				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
1456151086Sscottl				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
1457151086Sscottl				sg->SgEntryRaw[i].Next = 0;
1458151086Sscottl				sg->SgEntryRaw[i].Prev = 0;
1459151086Sscottl				sg->SgEntryRaw[i].Flags = 0;
1460151086Sscottl			}
1461151086Sscottl			/* update the FIB size for the s/g count */
1462151086Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
1463151086Sscottl		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1464112856Sscottl			struct aac_sg_table *sg;
1465112856Sscottl			sg = cm->cm_sgtable;
1466112856Sscottl			sg->SgCount = nseg;
1467112856Sscottl			for (i = 0; i < nseg; i++) {
1468112856Sscottl				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1469112856Sscottl				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1470112856Sscottl			}
1471112856Sscottl			/* update the FIB size for the s/g count */
1472151086Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1473112856Sscottl		} else {
1474112856Sscottl			struct aac_sg_table64 *sg;
1475112856Sscottl			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1476112856Sscottl			sg->SgCount = nseg;
1477112856Sscottl			for (i = 0; i < nseg; i++) {
1478112856Sscottl				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1479112856Sscottl				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1480112856Sscottl			}
1481112856Sscottl			/* update the FIB size for the s/g count */
1482112856Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
148383114Sscottl		}
148465793Smsmith	}
148565793Smsmith
1486117363Sscottl	/* Fix up the address values in the FIB.  Use the command array index
1487117363Sscottl	 * instead of a pointer since these fields are only 32 bits.  Shift
1488151086Sscottl	 * the SenderFibAddress over to make room for the fast response bit
1489151086Sscottl	 * and for the AIF bit
1490117363Sscottl	 */
1491151086Sscottl	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
1492151086Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
149365793Smsmith
1494117363Sscottl	/* save a pointer to the command for speedy reverse-lookup */
1495117363Sscottl	cm->cm_fib->Header.SenderData = cm->cm_index;
149665793Smsmith
1497117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAIN)
1498117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1499117363Sscottl				BUS_DMASYNC_PREREAD);
1500117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAOUT)
1501117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1502117363Sscottl				BUS_DMASYNC_PREWRITE);
1503117363Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
150465793Smsmith
1505151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1506151086Sscottl		int count = 10000000L;
1507151086Sscottl		while (AAC_SEND_COMMAND(sc, cm) != 0) {
1508151086Sscottl			if (--count == 0) {
1509151086Sscottl				aac_unmap_command(cm);
1510151086Sscottl				sc->flags |= AAC_QUEUE_FRZN;
1511151086Sscottl				aac_requeue_ready(cm);
1512151086Sscottl			}
1513151086Sscottl			DELAY(5);			/* wait 5 usec. */
1514151086Sscottl		}
1515151086Sscottl	} else {
1516151086Sscottl		/* Put the FIB on the outbound queue */
1517151086Sscottl		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
1518151086Sscottl			aac_unmap_command(cm);
1519151086Sscottl			sc->flags |= AAC_QUEUE_FRZN;
1520151086Sscottl			aac_requeue_ready(cm);
1521151086Sscottl		}
1522125559Sscottl	}
152365793Smsmith
1524117363Sscottl	return;
152565793Smsmith}
152665793Smsmith
152783114Sscottl/*
152865793Smsmith * Unmap a command from controller-visible space.
152965793Smsmith */
153065793Smsmithstatic void
153165793Smsmithaac_unmap_command(struct aac_command *cm)
153265793Smsmith{
153383114Sscottl	struct aac_softc *sc;
153465793Smsmith
153583114Sscottl	debug_called(2);
153665793Smsmith
153783114Sscottl	sc = cm->cm_sc;
153865793Smsmith
153983114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
154083114Sscottl		return;
154165793Smsmith
154283114Sscottl	if (cm->cm_datalen != 0) {
154383114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
154483114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
154583114Sscottl					BUS_DMASYNC_POSTREAD);
154683114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
154783114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
154883114Sscottl					BUS_DMASYNC_POSTWRITE);
154983114Sscottl
155083114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
155183114Sscottl	}
155283114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
155365793Smsmith}
155465793Smsmith
155583114Sscottl/*
155683114Sscottl * Hardware Interface
155783114Sscottl */
155865793Smsmith
155983114Sscottl/*
156065793Smsmith * Initialise the adapter.
156165793Smsmith */
156265793Smsmithstatic void
156365793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
156465793Smsmith{
156583114Sscottl	struct aac_softc *sc;
156665793Smsmith
156783114Sscottl	debug_called(1);
156865793Smsmith
156983114Sscottl	sc = (struct aac_softc *)arg;
157083114Sscottl
157183114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
157265793Smsmith}
157365793Smsmith
157465793Smsmithstatic int
157590275Sscottlaac_check_firmware(struct aac_softc *sc)
157690275Sscottl{
1577151086Sscottl	u_int32_t major, minor, options, atu_size;
157890275Sscottl
157990275Sscottl	debug_called(1);
158090275Sscottl
1581112679Sscottl	/*
1582112679Sscottl	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1583112679Sscottl	 * firmware version 1.x are not compatible with this driver.
1584112679Sscottl	 */
1585112679Sscottl	if (sc->flags & AAC_FLAGS_PERC2QC) {
158690275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
158790275Sscottl				     NULL)) {
158890275Sscottl			device_printf(sc->aac_dev,
158990275Sscottl				      "Error reading firmware version\n");
159090275Sscottl			return (EIO);
159190275Sscottl		}
159290275Sscottl
159390275Sscottl		/* These numbers are stored as ASCII! */
1594112679Sscottl		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1595112679Sscottl		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
159690275Sscottl		if (major == 1) {
159790275Sscottl			device_printf(sc->aac_dev,
159890275Sscottl			    "Firmware version %d.%d is not supported.\n",
159990275Sscottl			    major, minor);
160090275Sscottl			return (EINVAL);
160190275Sscottl		}
160290275Sscottl	}
160390275Sscottl
1604112679Sscottl	/*
1605112679Sscottl	 * Retrieve the capabilities/supported options word so we know what
1606112679Sscottl	 * work-arounds to enable.
1607112679Sscottl	 */
1608112679Sscottl	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, NULL)) {
1609112679Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
1610112679Sscottl		return (EIO);
1611112679Sscottl	}
1612112679Sscottl	options = AAC_GET_MAILBOX(sc, 1);
1613151086Sscottl	atu_size = AAC_GET_MAILBOX(sc, 2);
1614112679Sscottl	sc->supported_options = options;
1615112679Sscottl
1616112679Sscottl	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1617112679Sscottl	    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1618112679Sscottl		sc->flags |= AAC_FLAGS_4GB_WINDOW;
1619112679Sscottl	if (options & AAC_SUPPORTED_NONDASD)
1620112679Sscottl		sc->flags |= AAC_FLAGS_ENABLE_CAM;
1621117363Sscottl	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1622117363Sscottl	     && (sizeof(bus_addr_t) > 4)) {
1623112679Sscottl		device_printf(sc->aac_dev, "Enabling 64-bit address support\n");
1624112679Sscottl		sc->flags |= AAC_FLAGS_SG_64BIT;
1625112679Sscottl	}
1626151086Sscottl    if ((options & AAC_SUPPORTED_NEW_COMM) && sc->aac_if.aif_send_command)
1627151086Sscottl		sc->flags |= AAC_FLAGS_NEW_COMM;
1628151086Sscottl    if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
1629151086Sscottl		sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1630112679Sscottl
1631112679Sscottl	/* Check for broken hardware that does a lower number of commands */
1632151086Sscottl	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
1633151086Sscottl
1634151086Sscottl	/* Remap mem. resource, if required */
1635151086Sscottl	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1636151086Sscottl		atu_size > rman_get_size(sc->aac_regs_resource)) {
1637151086Sscottl		bus_release_resource(
1638151086Sscottl			sc->aac_dev, SYS_RES_MEMORY,
1639151086Sscottl			sc->aac_regs_rid, sc->aac_regs_resource);
1640151086Sscottl		sc->aac_regs_resource = bus_alloc_resource(
1641151086Sscottl			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid,
1642151086Sscottl			0ul, ~0ul, atu_size, RF_ACTIVE);
1643151086Sscottl		if (sc->aac_regs_resource == NULL) {
1644151086Sscottl			sc->aac_regs_resource = bus_alloc_resource_any(
1645151086Sscottl				sc->aac_dev, SYS_RES_MEMORY,
1646151086Sscottl				&sc->aac_regs_rid, RF_ACTIVE);
1647151086Sscottl			if (sc->aac_regs_resource == NULL) {
1648151086Sscottl				device_printf(sc->aac_dev,
1649151086Sscottl						  "couldn't allocate register window\n");
1650151086Sscottl				return (ENXIO);
1651151086Sscottl			}
1652151086Sscottl			sc->flags &= ~AAC_FLAGS_NEW_COMM;
1653151086Sscottl		}
1654151086Sscottl		sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
1655151086Sscottl		sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
1656151086Sscottl	}
1657151086Sscottl
1658151086Sscottl	/* Read preferred settings */
1659151086Sscottl	sc->aac_max_fib_size = sizeof(struct aac_fib);
1660151086Sscottl	sc->aac_max_sectors = 128;				/* 64KB */
1661151086Sscottl	if (sc->flags & AAC_FLAGS_SG_64BIT)
1662151086Sscottl		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite64)
1663151086Sscottl			+ sizeof(struct aac_sg_table64)) / sizeof(struct aac_sg_table64);
1664112679Sscottl	else
1665151086Sscottl		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE - sizeof(struct aac_blockwrite)
1666151086Sscottl			+ sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_table);
1667151086Sscottl	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
1668151086Sscottl		options = AAC_GET_MAILBOX(sc, 1);
1669151086Sscottl		sc->aac_max_fib_size = (options & 0xFFFF);
1670151086Sscottl		sc->aac_max_sectors = (options >> 16) << 1;
1671151086Sscottl		options = AAC_GET_MAILBOX(sc, 2);
1672151086Sscottl		sc->aac_sg_tablesize = (options >> 16);
1673151086Sscottl		options = AAC_GET_MAILBOX(sc, 3);
1674151086Sscottl		sc->aac_max_fibs = (options & 0xFFFF);
1675151086Sscottl	}
1676151086Sscottl	if (sc->aac_max_fib_size > PAGE_SIZE)
1677151086Sscottl		sc->aac_max_fib_size = PAGE_SIZE;
1678151086Sscottl	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1679151086Sscottl
168090275Sscottl	return (0);
168190275Sscottl}
168290275Sscottl
168390275Sscottlstatic int
168465793Smsmithaac_init(struct aac_softc *sc)
168565793Smsmith{
168683114Sscottl	struct aac_adapter_init	*ip;
168783114Sscottl	time_t then;
1688119146Sscottl	u_int32_t code, qoffset;
1689112679Sscottl	int error;
169065793Smsmith
169183114Sscottl	debug_called(1);
169265793Smsmith
169383114Sscottl	/*
169483114Sscottl	 * First wait for the adapter to come ready.
169583114Sscottl	 */
1696150119Sscottl	then = time_uptime;
169783114Sscottl	do {
169883114Sscottl		code = AAC_GET_FWSTATUS(sc);
169983114Sscottl		if (code & AAC_SELF_TEST_FAILED) {
170083114Sscottl			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
170183114Sscottl			return(ENXIO);
170283114Sscottl		}
170383114Sscottl		if (code & AAC_KERNEL_PANIC) {
170483114Sscottl			device_printf(sc->aac_dev,
170583114Sscottl				      "FATAL: controller kernel panic\n");
170683114Sscottl			return(ENXIO);
170783114Sscottl		}
1708150119Sscottl		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
170983114Sscottl			device_printf(sc->aac_dev,
171083114Sscottl				      "FATAL: controller not coming ready, "
171183114Sscottl					   "status %x\n", code);
171283114Sscottl			return(ENXIO);
171383114Sscottl		}
171483114Sscottl	} while (!(code & AAC_UP_AND_RUNNING));
171583114Sscottl
1716112679Sscottl	error = ENOMEM;
171783114Sscottl	/*
1718112679Sscottl	 * Create DMA tag for mapping buffers into controller-addressable space.
1719112679Sscottl	 */
1720112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
1721112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1722112679Sscottl			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
1723112679Sscottl			       BUS_SPACE_MAXADDR :
1724112679Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1725112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1726112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1727112679Sscottl			       MAXBSIZE,		/* maxsize */
1728151086Sscottl			       sc->aac_sg_tablesize,	/* nsegments */
1729112679Sscottl			       MAXBSIZE,		/* maxsegsize */
1730112679Sscottl			       BUS_DMA_ALLOCNOW,	/* flags */
1731117126Sscottl			       busdma_lock_mutex,	/* lockfunc */
1732117126Sscottl			       &sc->aac_io_lock,	/* lockfuncarg */
1733112679Sscottl			       &sc->aac_buffer_dmat)) {
1734112679Sscottl		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
1735112679Sscottl		goto out;
1736112679Sscottl	}
1737112679Sscottl
1738112679Sscottl	/*
1739112679Sscottl	 * Create DMA tag for mapping FIBs into controller-addressable space..
1740112679Sscottl	 */
1741112679Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
1742112679Sscottl			       1, 0, 			/* algnmnt, boundary */
1743112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1744112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1745112679Sscottl			       0x7fffffff,		/* lowaddr */
1746112679Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
1747112679Sscottl			       NULL, NULL, 		/* filter, filterarg */
1748151086Sscottl			       sc->aac_max_fibs_alloc *
1749151086Sscottl			       sc->aac_max_fib_size,  /* maxsize */
1750112679Sscottl			       1,			/* nsegments */
1751151086Sscottl			       sc->aac_max_fibs_alloc *
1752151086Sscottl			       sc->aac_max_fib_size,	/* maxsegsize */
1753137962Sscottl			       0,			/* flags */
1754117126Sscottl			       NULL, NULL,		/* No locking needed */
1755112679Sscottl			       &sc->aac_fib_dmat)) {
1756112679Sscottl		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
1757112679Sscottl		goto out;
1758112679Sscottl	}
1759112679Sscottl
1760112679Sscottl	/*
176183114Sscottl	 * Create DMA tag for the common structure and allocate it.
176283114Sscottl	 */
176383114Sscottl	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
176495536Sscottl			       1, 0,			/* algnmnt, boundary */
1765112679Sscottl			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
1766112679Sscottl			       BUS_SPACE_MAXADDR_32BIT :
1767112679Sscottl			       0x7fffffff,		/* lowaddr */
176883114Sscottl			       BUS_SPACE_MAXADDR, 	/* highaddr */
176983114Sscottl			       NULL, NULL, 		/* filter, filterarg */
1770110604Sscottl			       8192 + sizeof(struct aac_common), /* maxsize */
177183114Sscottl			       1,			/* nsegments */
177283114Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1773137962Sscottl			       0,			/* flags */
1774117126Sscottl			       NULL, NULL,		/* No locking needed */
177583114Sscottl			       &sc->aac_common_dmat)) {
177683114Sscottl		device_printf(sc->aac_dev,
177783114Sscottl			      "can't allocate common structure DMA tag\n");
1778112679Sscottl		goto out;
177965793Smsmith	}
178083114Sscottl	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
178183114Sscottl			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
178283114Sscottl		device_printf(sc->aac_dev, "can't allocate common structure\n");
1783112679Sscottl		goto out;
178465793Smsmith	}
1785110604Sscottl
1786110604Sscottl	/*
1787110604Sscottl	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
1788110604Sscottl	 * below address 8192 in physical memory.
1789110604Sscottl	 * XXX If the padding is not needed, can it be put to use instead
1790110604Sscottl	 * of ignored?
1791110604Sscottl	 */
1792117363Sscottl	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
1793110604Sscottl			sc->aac_common, 8192 + sizeof(*sc->aac_common),
1794110604Sscottl			aac_common_map, sc, 0);
1795110604Sscottl
1796110604Sscottl	if (sc->aac_common_busaddr < 8192) {
1797132771Skan		sc->aac_common = (struct aac_common *)
1798132771Skan		    ((uint8_t *)sc->aac_common + 8192);
1799110604Sscottl		sc->aac_common_busaddr += 8192;
1800110604Sscottl	}
180183114Sscottl	bzero(sc->aac_common, sizeof(*sc->aac_common));
1802110604Sscottl
1803110604Sscottl	/* Allocate some FIBs and associated command structs */
1804110604Sscottl	TAILQ_INIT(&sc->aac_fibmap_tqh);
1805151086Sscottl	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
1806111141Sscottl				  M_AACBUF, M_WAITOK|M_ZERO);
1807111141Sscottl	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
1808110604Sscottl		if (aac_alloc_commands(sc) != 0)
1809110604Sscottl			break;
1810110604Sscottl	}
1811110604Sscottl	if (sc->total_fibs == 0)
1812112679Sscottl		goto out;
181383114Sscottl
181483114Sscottl	/*
181583114Sscottl	 * Fill in the init structure.  This tells the adapter about the
181683114Sscottl	 * physical location of various important shared data structures.
181783114Sscottl	 */
181883114Sscottl	ip = &sc->aac_common->ac_init;
181983114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1820151086Sscottl	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1821151086Sscottl		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
1822151086Sscottl		sc->flags |= AAC_FLAGS_RAW_IO;
1823151086Sscottl	}
1824109088Sscottl	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
182565793Smsmith
182683114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
182783114Sscottl					 offsetof(struct aac_common, ac_fibs);
1828114151Sscottl	ip->AdapterFibsVirtualAddress = 0;
182983114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
183083114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
183165793Smsmith
183283114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
183383114Sscottl				  offsetof(struct aac_common, ac_printf);
183483114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
183565793Smsmith
1836117361Sscottl	/*
1837117361Sscottl	 * The adapter assumes that pages are 4K in size, except on some
1838117361Sscottl 	 * broken firmware versions that do the page->byte conversion twice,
1839117361Sscottl	 * therefore 'assuming' that this value is in 16MB units (2^24).
1840117361Sscottl	 * Round up since the granularity is so high.
1841117361Sscottl	 */
1842109088Sscottl	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1843117361Sscottl	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1844117361Sscottl		ip->HostPhysMemPages =
1845117361Sscottl		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1846117362Sscottl	}
1847150119Sscottl	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
184865793Smsmith
1849151086Sscottl	ip->InitFlags = 0;
1850151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1851151086Sscottl		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
1852151086Sscottl		device_printf(sc->aac_dev, "New comm. interface enabled\n");
1853151086Sscottl	}
1854151086Sscottl
1855151086Sscottl	ip->MaxIoCommands = sc->aac_max_fibs;
1856151086Sscottl	ip->MaxIoSize = sc->aac_max_sectors << 9;
1857151086Sscottl	ip->MaxFibSize = sc->aac_max_fib_size;
1858151086Sscottl
185983114Sscottl	/*
186083114Sscottl	 * Initialise FIB queues.  Note that it appears that the layout of the
186183114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
186283114Sscottl	 * adapter, which is only told about the base of the queue index fields.
186383114Sscottl	 *
186483114Sscottl	 * The initial values of the indices are assumed to inform the adapter
186583114Sscottl	 * of the sizes of the respective queues, and theoretically it could
186683114Sscottl	 * work out the entire layout of the queue structures from this.  We
186783114Sscottl	 * take the easy route and just lay this area out like everyone else
186883114Sscottl	 * does.
186983114Sscottl	 *
187083114Sscottl	 * The Linux driver uses a much more complex scheme whereby several
187183114Sscottl	 * header records are kept for each queue.  We use a couple of generic
187283114Sscottl	 * list manipulation functions which 'know' the size of each list by
187383114Sscottl	 * virtue of a table.
187483114Sscottl	 */
1875119146Sscottl	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
1876119625Sscottl	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
1877119625Sscottl	sc->aac_queues =
1878119625Sscottl	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1879119146Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
188065793Smsmith
188183114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
188281082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
188383114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
188481082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
188583114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
188681082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
188783114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
188881082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
188983114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
189081082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
189183114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
189281082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
189383114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
189481082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
189583114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
189681082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
189783114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
189881082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
189983114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
190081082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
190183114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
190281082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
190383114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
190481082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
190583114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
190681082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
190783114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
190881082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
190983114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
191081082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
191183114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
191281082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
191383114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
191481082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
191583114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
191681082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
191783114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
191881082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
191983114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
192081082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
192183114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
192281082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
192383114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
192481082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
192583114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
192681082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
192783114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
192881082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
192965793Smsmith
193083114Sscottl	/*
193183114Sscottl	 * Do controller-type-specific initialisation
193283114Sscottl	 */
193383114Sscottl	switch (sc->aac_hwif) {
193483114Sscottl	case AAC_HWIF_I960RX:
193583114Sscottl		AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
193683114Sscottl		break;
1937133606Sscottl	case AAC_HWIF_RKT:
1938133606Sscottl		AAC_SETREG4(sc, AAC_RKT_ODBR, ~0);
1939133606Sscottl		break;
1940133606Sscottl	default:
1941133606Sscottl		break;
194283114Sscottl	}
194365793Smsmith
194483114Sscottl	/*
194583114Sscottl	 * Give the init structure to the controller.
194683114Sscottl	 */
194783114Sscottl	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
194883114Sscottl			     sc->aac_common_busaddr +
194983114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
195083114Sscottl			     NULL)) {
195183114Sscottl		device_printf(sc->aac_dev,
195283114Sscottl			      "error establishing init structure\n");
1953112679Sscottl		error = EIO;
1954112679Sscottl		goto out;
195583114Sscottl	}
195665793Smsmith
1957112679Sscottl	error = 0;
1958112679Sscottlout:
1959112679Sscottl	return(error);
196065793Smsmith}
196165793Smsmith
196283114Sscottl/*
196365793Smsmith * Send a synchronous command to the controller and wait for a result.
1964151086Sscottl * Indicate if the controller completed the command with an error status.
196565793Smsmith */
196665793Smsmithstatic int
196765793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
196870393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
196970393Smsmith		 u_int32_t *sp)
197065793Smsmith{
197183114Sscottl	time_t then;
197283114Sscottl	u_int32_t status;
197365793Smsmith
197483114Sscottl	debug_called(3);
197565793Smsmith
197683114Sscottl	/* populate the mailbox */
197783114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
197865793Smsmith
197983114Sscottl	/* ensure the sync command doorbell flag is cleared */
198083114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
198165793Smsmith
198283114Sscottl	/* then set it to signal the adapter */
198383114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
198465793Smsmith
198583114Sscottl	/* spin waiting for the command to complete */
1986150119Sscottl	then = time_uptime;
198783114Sscottl	do {
1988150119Sscottl		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
1989112679Sscottl			debug(1, "timed out");
199083114Sscottl			return(EIO);
199183114Sscottl		}
199283114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
199365793Smsmith
199483114Sscottl	/* clear the completion flag */
199583114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
199665793Smsmith
199783114Sscottl	/* get the command status */
1998112679Sscottl	status = AAC_GET_MAILBOX(sc, 0);
199983114Sscottl	if (sp != NULL)
200083114Sscottl		*sp = status;
2001151086Sscottl
2002151086Sscottl	if (status != 0x01)
2003151086Sscottl		return (-1);
200483114Sscottl	return(0);
200565793Smsmith}
200665793Smsmith
200795350Sscottlint
200865793Smsmithaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
200995350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
201065793Smsmith{
201183114Sscottl	debug_called(3);
2012151086Sscottl	mtx_assert(&sc->aac_io_lock, MA_OWNED);
201365793Smsmith
201483114Sscottl	if (datasize > AAC_FIB_DATASIZE)
201583114Sscottl		return(EINVAL);
201665793Smsmith
201783114Sscottl	/*
201883114Sscottl	 * Set up the sync FIB
201983114Sscottl	 */
202083114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
202183114Sscottl				AAC_FIBSTATE_INITIALISED |
202283114Sscottl				AAC_FIBSTATE_EMPTY;
202383114Sscottl	fib->Header.XferState |= xferstate;
202483114Sscottl	fib->Header.Command = command;
202583114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
202683114Sscottl	fib->Header.Size = sizeof(struct aac_fib) + datasize;
202783114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
2028119146Sscottl	fib->Header.SenderFibAddress = 0;	/* Not needed */
202983114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
203083114Sscottl					 offsetof(struct aac_common,
203183114Sscottl						  ac_sync_fib);
203265793Smsmith
203383114Sscottl	/*
203483114Sscottl	 * Give the FIB to the controller, wait for a response.
203583114Sscottl	 */
203683114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
203783114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
203883114Sscottl		debug(2, "IO error");
203983114Sscottl		return(EIO);
204083114Sscottl	}
204181151Sscottl
204295350Sscottl	return (0);
204365793Smsmith}
204465793Smsmith
204583114Sscottl/*
204665793Smsmith * Adapter-space FIB queue manipulation
204765793Smsmith *
204865793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
204965793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
205065793Smsmith */
205165793Smsmithstatic struct {
205283114Sscottl	int		size;
205383114Sscottl	int		notify;
205465793Smsmith} aac_qinfo[] = {
205583114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
205683114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
205783114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
205883114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
205983114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
206083114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
206183114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
206283114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
206365793Smsmith};
206465793Smsmith
206565793Smsmith/*
206681082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
206781082Sscottl * EBUSY if the queue is full.
206865793Smsmith *
206970393Smsmith * Note: it would be more efficient to defer notifying the controller in
207083114Sscottl *	 the case where we may be inserting several entries in rapid succession,
207183114Sscottl *	 but implementing this usefully may be difficult (it would involve a
207283114Sscottl *	 separate queue/notify interface).
207365793Smsmith */
207465793Smsmithstatic int
207581151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
207665793Smsmith{
207783114Sscottl	u_int32_t pi, ci;
2078111691Sscottl	int error;
207983114Sscottl	u_int32_t fib_size;
208083114Sscottl	u_int32_t fib_addr;
208165793Smsmith
208283114Sscottl	debug_called(3);
208382527Sscottl
208483114Sscottl	fib_size = cm->cm_fib->Header.Size;
208583114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
208681151Sscottl
208783114Sscottl	/* get the producer/consumer indices */
208883114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
208983114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
209065793Smsmith
209183114Sscottl	/* wrap the queue? */
209283114Sscottl	if (pi >= aac_qinfo[queue].size)
209383114Sscottl		pi = 0;
209465793Smsmith
209583114Sscottl	/* check for queue full */
209683114Sscottl	if ((pi + 1) == ci) {
209783114Sscottl		error = EBUSY;
209883114Sscottl		goto out;
209983114Sscottl	}
210065793Smsmith
2101129946Sscottl	/*
2102129946Sscottl	 * To avoid a race with its completion interrupt, place this command on
2103129946Sscottl	 * the busy queue prior to advertising it to the controller.
2104129946Sscottl	 */
2105129946Sscottl	aac_enqueue_busy(cm);
2106129946Sscottl
210783114Sscottl	/* populate queue entry */
210883114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
210983114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
211065793Smsmith
211183114Sscottl	/* update producer index */
211283114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
211365793Smsmith
211483114Sscottl	/* notify the adapter if we know how */
211583114Sscottl	if (aac_qinfo[queue].notify != 0)
211683114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
211765793Smsmith
211883114Sscottl	error = 0;
211965793Smsmith
212065793Smsmithout:
212183114Sscottl	return(error);
212265793Smsmith}
212365793Smsmith
212465793Smsmith/*
212582527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
212682527Sscottl * success or ENOENT if the queue is empty.
212765793Smsmith */
212865793Smsmithstatic int
212981082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
213081082Sscottl		struct aac_fib **fib_addr)
213165793Smsmith{
213283114Sscottl	u_int32_t pi, ci;
2133114151Sscottl	u_int32_t fib_index;
2134111691Sscottl	int error;
213583114Sscottl	int notify;
213665793Smsmith
213783114Sscottl	debug_called(3);
213865793Smsmith
213983114Sscottl	/* get the producer/consumer indices */
214083114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
214183114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
214265793Smsmith
214383114Sscottl	/* check for queue empty */
214483114Sscottl	if (ci == pi) {
214583114Sscottl		error = ENOENT;
214683114Sscottl		goto out;
214783114Sscottl	}
2148120129Sscottl
2149120129Sscottl	/* wrap the pi so the following test works */
2150120129Sscottl	if (pi >= aac_qinfo[queue].size)
2151120129Sscottl		pi = 0;
2152120129Sscottl
215383114Sscottl	notify = 0;
215483114Sscottl	if (ci == pi + 1)
215583114Sscottl		notify++;
215681151Sscottl
215783114Sscottl	/* wrap the queue? */
215883114Sscottl	if (ci >= aac_qinfo[queue].size)
215983114Sscottl		ci = 0;
216065793Smsmith
216183114Sscottl	/* fetch the entry */
216283114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
216365793Smsmith
2164114151Sscottl	switch (queue) {
2165114151Sscottl	case AAC_HOST_NORM_CMD_QUEUE:
2166114151Sscottl	case AAC_HOST_HIGH_CMD_QUEUE:
2167114151Sscottl		/*
2168114151Sscottl		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2169114151Sscottl		 * on to hold an address.  For AIF's, the adapter assumes
2170114151Sscottl		 * that it's giving us an address into the array of AIF fibs.
2171114151Sscottl		 * Therefore, we have to convert it to an index.
2172114151Sscottl		 */
2173114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2174114151Sscottl			sizeof(struct aac_fib);
2175114151Sscottl		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2176114151Sscottl		break;
2177114151Sscottl
2178114151Sscottl	case AAC_HOST_NORM_RESP_QUEUE:
2179114151Sscottl	case AAC_HOST_HIGH_RESP_QUEUE:
2180114151Sscottl	{
2181114151Sscottl		struct aac_command *cm;
2182114151Sscottl
2183114151Sscottl		/*
2184114151Sscottl		 * As above, an index is used instead of an actual address.
2185114151Sscottl		 * Gotta shift the index to account for the fast response
2186114151Sscottl		 * bit.  No other correction is needed since this value was
2187114151Sscottl		 * originally provided by the driver via the SenderFibAddress
2188114151Sscottl		 * field.
2189114151Sscottl		 */
2190114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
2191151086Sscottl		cm = sc->aac_commands + (fib_index >> 2);
2192114151Sscottl		*fib_addr = cm->cm_fib;
2193114151Sscottl
2194114151Sscottl		/*
2195114151Sscottl		 * Is this a fast response? If it is, update the fib fields in
2196114151Sscottl		 * local memory since the whole fib isn't DMA'd back up.
2197114151Sscottl		 */
2198114151Sscottl		if (fib_index & 0x01) {
2199114151Sscottl			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2200114151Sscottl			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2201114151Sscottl		}
2202114151Sscottl		break;
2203109088Sscottl	}
2204114151Sscottl	default:
2205114151Sscottl		panic("Invalid queue in aac_dequeue_fib()");
2206114151Sscottl		break;
2207114151Sscottl	}
2208114151Sscottl
220983114Sscottl	/* update consumer index */
221083114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
221165793Smsmith
221283114Sscottl	/* if we have made the queue un-full, notify the adapter */
221383114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
221483114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
221583114Sscottl	error = 0;
221665793Smsmith
221765793Smsmithout:
221883114Sscottl	return(error);
221965793Smsmith}
222065793Smsmith
222183114Sscottl/*
222282527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
222382527Sscottl */
222482527Sscottlstatic int
222582527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
222682527Sscottl{
222783114Sscottl	u_int32_t pi, ci;
2228111691Sscottl	int error;
222983114Sscottl	u_int32_t fib_size;
223083114Sscottl	u_int32_t fib_addr;
223182527Sscottl
223283114Sscottl	debug_called(1);
223382527Sscottl
223483114Sscottl	/* Tell the adapter where the FIB is */
223583114Sscottl	fib_size = fib->Header.Size;
223683114Sscottl	fib_addr = fib->Header.SenderFibAddress;
223783114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
223882527Sscottl
223983114Sscottl	/* get the producer/consumer indices */
224083114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
224183114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
224282527Sscottl
224383114Sscottl	/* wrap the queue? */
224483114Sscottl	if (pi >= aac_qinfo[queue].size)
224583114Sscottl		pi = 0;
224682527Sscottl
224783114Sscottl	/* check for queue full */
224883114Sscottl	if ((pi + 1) == ci) {
224983114Sscottl		error = EBUSY;
225083114Sscottl		goto out;
225183114Sscottl	}
225282527Sscottl
225383114Sscottl	/* populate queue entry */
225483114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
225583114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
225682527Sscottl
225783114Sscottl	/* update producer index */
225883114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
225982527Sscottl
226083114Sscottl	/* notify the adapter if we know how */
226183114Sscottl	if (aac_qinfo[queue].notify != 0)
226283114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
226382527Sscottl
226483114Sscottl	error = 0;
226582527Sscottl
226682527Sscottlout:
226783114Sscottl	return(error);
226882527Sscottl}
226982527Sscottl
227083114Sscottl/*
227170393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
227270393Smsmith * and complain about them.
227370393Smsmith */
227470393Smsmithstatic void
227570393Smsmithaac_timeout(struct aac_softc *sc)
227670393Smsmith{
227783114Sscottl	struct aac_command *cm;
227883114Sscottl	time_t deadline;
2279135289Sscottl	int timedout, code;
228070393Smsmith
228183114Sscottl	/*
2282110426Sscottl	 * Traverse the busy command list, bitch about late commands once
228383114Sscottl	 * only.
228483114Sscottl	 */
2285135289Sscottl	timedout = 0;
2286150119Sscottl	deadline = time_uptime - AAC_CMD_TIMEOUT;
228783114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
228883114Sscottl		if ((cm->cm_timestamp  < deadline)
228983114Sscottl			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
229083114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
229183114Sscottl			device_printf(sc->aac_dev,
229283114Sscottl				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2293150119Sscottl				      cm, (int)(time_uptime-cm->cm_timestamp));
229483114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
2295135289Sscottl			timedout++;
229683114Sscottl		}
229770393Smsmith	}
229870393Smsmith
2299135289Sscottl	if (timedout) {
2300135289Sscottl		code = AAC_GET_FWSTATUS(sc);
2301135289Sscottl		if (code != AAC_UP_AND_RUNNING) {
2302135289Sscottl			device_printf(sc->aac_dev, "WARNING! Controller is no "
2303135289Sscottl				      "longer running! code= 0x%x\n", code);
2304135289Sscottl		}
2305135289Sscottl	}
230683114Sscottl	return;
230770393Smsmith}
230870393Smsmith
230983114Sscottl/*
231083114Sscottl * Interface Function Vectors
231183114Sscottl */
231265793Smsmith
231383114Sscottl/*
231465793Smsmith * Read the current firmware status word.
231565793Smsmith */
231665793Smsmithstatic int
231765793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
231865793Smsmith{
231983114Sscottl	debug_called(3);
232065793Smsmith
232183114Sscottl	return(AAC_GETREG4(sc, AAC_SA_FWSTATUS));
232265793Smsmith}
232365793Smsmith
232465793Smsmithstatic int
232565793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
232665793Smsmith{
232783114Sscottl	debug_called(3);
232865793Smsmith
232983114Sscottl	return(AAC_GETREG4(sc, AAC_RX_FWSTATUS));
233065793Smsmith}
233165793Smsmith
233287183Sscottlstatic int
233387183Sscottlaac_fa_get_fwstatus(struct aac_softc *sc)
233487183Sscottl{
233587183Sscottl	int val;
233687183Sscottl
233787183Sscottl	debug_called(3);
233887183Sscottl
233987183Sscottl	val = AAC_GETREG4(sc, AAC_FA_FWSTATUS);
234087183Sscottl	return (val);
234187183Sscottl}
234287183Sscottl
2343133606Sscottlstatic int
2344133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc)
2345133606Sscottl{
2346133606Sscottl	debug_called(3);
2347133606Sscottl
2348133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_FWSTATUS));
2349133606Sscottl}
2350133606Sscottl
235183114Sscottl/*
235265793Smsmith * Notify the controller of a change in a given queue
235365793Smsmith */
235465793Smsmith
235565793Smsmithstatic void
235665793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
235765793Smsmith{
235883114Sscottl	debug_called(3);
235965793Smsmith
236083114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
236165793Smsmith}
236265793Smsmith
236365793Smsmithstatic void
236465793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
236565793Smsmith{
236683114Sscottl	debug_called(3);
236765793Smsmith
236883114Sscottl	AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
236965793Smsmith}
237065793Smsmith
237187183Sscottlstatic void
237287183Sscottlaac_fa_qnotify(struct aac_softc *sc, int qbit)
237387183Sscottl{
237487183Sscottl	debug_called(3);
237587183Sscottl
237687183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
237787183Sscottl	AAC_FA_HACK(sc);
237887183Sscottl}
237987183Sscottl
2380133606Sscottlstatic void
2381133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit)
2382133606Sscottl{
2383133606Sscottl	debug_called(3);
2384133606Sscottl
2385133606Sscottl	AAC_SETREG4(sc, AAC_RKT_IDBR, qbit);
2386133606Sscottl}
2387133606Sscottl
238883114Sscottl/*
238965793Smsmith * Get the interrupt reason bits
239065793Smsmith */
239165793Smsmithstatic int
239265793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
239365793Smsmith{
239483114Sscottl	debug_called(3);
239565793Smsmith
239683114Sscottl	return(AAC_GETREG2(sc, AAC_SA_DOORBELL0));
239765793Smsmith}
239865793Smsmith
239965793Smsmithstatic int
240065793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
240165793Smsmith{
240283114Sscottl	debug_called(3);
240365793Smsmith
240483114Sscottl	return(AAC_GETREG4(sc, AAC_RX_ODBR));
240565793Smsmith}
240665793Smsmith
240787183Sscottlstatic int
240887183Sscottlaac_fa_get_istatus(struct aac_softc *sc)
240987183Sscottl{
241087183Sscottl	int val;
241187183Sscottl
241287183Sscottl	debug_called(3);
241387183Sscottl
241487183Sscottl	val = AAC_GETREG2(sc, AAC_FA_DOORBELL0);
241587183Sscottl	return (val);
241687183Sscottl}
241787183Sscottl
2418133606Sscottlstatic int
2419133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc)
2420133606Sscottl{
2421133606Sscottl	debug_called(3);
2422133606Sscottl
2423133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_ODBR));
2424133606Sscottl}
2425133606Sscottl
242683114Sscottl/*
242765793Smsmith * Clear some interrupt reason bits
242865793Smsmith */
242965793Smsmithstatic void
243065793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
243165793Smsmith{
243283114Sscottl	debug_called(3);
243365793Smsmith
243483114Sscottl	AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
243565793Smsmith}
243665793Smsmith
243765793Smsmithstatic void
243865793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
243965793Smsmith{
244083114Sscottl	debug_called(3);
244165793Smsmith
244283114Sscottl	AAC_SETREG4(sc, AAC_RX_ODBR, mask);
244365793Smsmith}
244465793Smsmith
244587183Sscottlstatic void
244687183Sscottlaac_fa_clear_istatus(struct aac_softc *sc, int mask)
244787183Sscottl{
244887183Sscottl	debug_called(3);
244987183Sscottl
245087183Sscottl	AAC_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
245187183Sscottl	AAC_FA_HACK(sc);
245287183Sscottl}
245387183Sscottl
2454133606Sscottlstatic void
2455133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask)
2456133606Sscottl{
2457133606Sscottl	debug_called(3);
2458133606Sscottl
2459133606Sscottl	AAC_SETREG4(sc, AAC_RKT_ODBR, mask);
2460133606Sscottl}
2461133606Sscottl
246283114Sscottl/*
246365793Smsmith * Populate the mailbox and set the command word
246465793Smsmith */
246565793Smsmithstatic void
246665793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
246765793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
246865793Smsmith{
246983114Sscottl	debug_called(4);
247065793Smsmith
247183114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
247283114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
247383114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
247483114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
247583114Sscottl	AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
247665793Smsmith}
247765793Smsmith
247865793Smsmithstatic void
247965793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
248065793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
248165793Smsmith{
248283114Sscottl	debug_called(4);
248365793Smsmith
248483114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
248583114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
248683114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
248783114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
248883114Sscottl	AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
248965793Smsmith}
249065793Smsmith
249187183Sscottlstatic void
249287183Sscottlaac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
249387183Sscottl		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249487183Sscottl{
249587183Sscottl	debug_called(4);
249687183Sscottl
249787183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX, command);
249887183Sscottl	AAC_FA_HACK(sc);
249987183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
250087183Sscottl	AAC_FA_HACK(sc);
250187183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
250287183Sscottl	AAC_FA_HACK(sc);
250387183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
250487183Sscottl	AAC_FA_HACK(sc);
250587183Sscottl	AAC_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
250687183Sscottl	AAC_FA_HACK(sc);
250787183Sscottl}
250887183Sscottl
2509133606Sscottlstatic void
2510133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2511133606Sscottl		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2512133606Sscottl{
2513133606Sscottl	debug_called(4);
2514133606Sscottl
2515133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX, command);
2516133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2517133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2518133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2519133606Sscottl	AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
2520133606Sscottl}
2521133606Sscottl
252283114Sscottl/*
252365793Smsmith * Fetch the immediate command status word
252465793Smsmith */
252565793Smsmithstatic int
2526112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb)
252765793Smsmith{
252883114Sscottl	debug_called(4);
252965793Smsmith
2530112679Sscottl	return(AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
253165793Smsmith}
253265793Smsmith
253365793Smsmithstatic int
2534112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb)
253565793Smsmith{
253683114Sscottl	debug_called(4);
253765793Smsmith
2538112679Sscottl	return(AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
253965793Smsmith}
254065793Smsmith
254187183Sscottlstatic int
2542112679Sscottlaac_fa_get_mailbox(struct aac_softc *sc, int mb)
254387183Sscottl{
254487183Sscottl	int val;
254587183Sscottl
254687183Sscottl	debug_called(4);
254787183Sscottl
2548112679Sscottl	val = AAC_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
254987183Sscottl	return (val);
255087183Sscottl}
255187183Sscottl
2552133606Sscottlstatic int
2553133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb)
2554133606Sscottl{
2555133606Sscottl	debug_called(4);
2556133606Sscottl
2557133606Sscottl	return(AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
2558133606Sscottl}
2559133606Sscottl
256083114Sscottl/*
256165793Smsmith * Set/clear interrupt masks
256265793Smsmith */
256365793Smsmithstatic void
256465793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
256565793Smsmith{
256683114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
256765793Smsmith
256883114Sscottl	if (enable) {
256983114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
257083114Sscottl	} else {
257183114Sscottl		AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
257283114Sscottl	}
257365793Smsmith}
257465793Smsmith
257565793Smsmithstatic void
257665793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
257765793Smsmith{
257883114Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
257965793Smsmith
258083114Sscottl	if (enable) {
2581151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
2582151086Sscottl			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
2583151086Sscottl		else
2584151086Sscottl			AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
258583114Sscottl	} else {
258683114Sscottl		AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
258783114Sscottl	}
258865793Smsmith}
258965793Smsmith
259087183Sscottlstatic void
259187183Sscottlaac_fa_set_interrupts(struct aac_softc *sc, int enable)
259287183Sscottl{
259387183Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
259487183Sscottl
259587183Sscottl	if (enable) {
259687183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
259787183Sscottl		AAC_FA_HACK(sc);
259887183Sscottl	} else {
259987183Sscottl		AAC_SETREG2((sc), AAC_FA_MASK0, ~0);
260087183Sscottl		AAC_FA_HACK(sc);
260187183Sscottl	}
260287183Sscottl}
260387183Sscottl
2604133606Sscottlstatic void
2605133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable)
2606133606Sscottl{
2607133606Sscottl	debug(2, "%sable interrupts", enable ? "en" : "dis");
2608133606Sscottl
2609133606Sscottl	if (enable) {
2610151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
2611151086Sscottl			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
2612151086Sscottl		else
2613151086Sscottl			AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
2614133606Sscottl	} else {
2615133606Sscottl		AAC_SETREG4(sc, AAC_RKT_OIMR, ~0);
2616133606Sscottl	}
2617133606Sscottl}
2618133606Sscottl
261983114Sscottl/*
2620151086Sscottl * New comm. interface: Send command functions
2621151086Sscottl */
2622151086Sscottlstatic int
2623151086Sscottlaac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
2624151086Sscottl{
2625151086Sscottl	u_int32_t index, device;
2626151086Sscottl
2627151086Sscottl	debug(2, "send command (new comm.)");
2628151086Sscottl
2629151086Sscottl	index = AAC_GETREG4(sc, AAC_RX_IQUE);
2630151086Sscottl	if (index == 0xffffffffL)
2631151086Sscottl		index = AAC_GETREG4(sc, AAC_RX_IQUE);
2632151086Sscottl	if (index == 0xffffffffL)
2633151086Sscottl		return index;
2634151086Sscottl	aac_enqueue_busy(cm);
2635151086Sscottl	device = index;
2636151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2637151086Sscottl	device += 4;
2638151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2639151086Sscottl	device += 4;
2640151086Sscottl	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
2641151086Sscottl	AAC_SETREG4(sc, AAC_RX_IQUE, index);
2642151086Sscottl	return 0;
2643151086Sscottl}
2644151086Sscottl
2645151086Sscottlstatic int
2646151086Sscottlaac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
2647151086Sscottl{
2648151086Sscottl	u_int32_t index, device;
2649151086Sscottl
2650151086Sscottl	debug(2, "send command (new comm.)");
2651151086Sscottl
2652151086Sscottl	index = AAC_GETREG4(sc, AAC_RKT_IQUE);
2653151086Sscottl	if (index == 0xffffffffL)
2654151086Sscottl		index = AAC_GETREG4(sc, AAC_RKT_IQUE);
2655151086Sscottl	if (index == 0xffffffffL)
2656151086Sscottl		return index;
2657151086Sscottl	aac_enqueue_busy(cm);
2658151086Sscottl	device = index;
2659151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2660151086Sscottl	device += 4;
2661151086Sscottl	AAC_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2662151086Sscottl	device += 4;
2663151086Sscottl	AAC_SETREG4(sc, device, cm->cm_fib->Header.Size);
2664151086Sscottl	AAC_SETREG4(sc, AAC_RKT_IQUE, index);
2665151086Sscottl	return 0;
2666151086Sscottl}
2667151086Sscottl
2668151086Sscottl/*
2669151086Sscottl * New comm. interface: get, set outbound queue index
2670151086Sscottl */
2671151086Sscottlstatic int
2672151086Sscottlaac_rx_get_outb_queue(struct aac_softc *sc)
2673151086Sscottl{
2674151086Sscottl	debug_called(3);
2675151086Sscottl
2676151086Sscottl	return(AAC_GETREG4(sc, AAC_RX_OQUE));
2677151086Sscottl}
2678151086Sscottl
2679151086Sscottlstatic int
2680151086Sscottlaac_rkt_get_outb_queue(struct aac_softc *sc)
2681151086Sscottl{
2682151086Sscottl	debug_called(3);
2683151086Sscottl
2684151086Sscottl	return(AAC_GETREG4(sc, AAC_RKT_OQUE));
2685151086Sscottl}
2686151086Sscottl
2687151086Sscottlstatic void
2688151086Sscottlaac_rx_set_outb_queue(struct aac_softc *sc, int index)
2689151086Sscottl{
2690151086Sscottl	debug_called(3);
2691151086Sscottl
2692151086Sscottl	AAC_SETREG4(sc, AAC_RX_OQUE, index);
2693151086Sscottl}
2694151086Sscottl
2695151086Sscottlstatic void
2696151086Sscottlaac_rkt_set_outb_queue(struct aac_softc *sc, int index)
2697151086Sscottl{
2698151086Sscottl	debug_called(3);
2699151086Sscottl
2700151086Sscottl	AAC_SETREG4(sc, AAC_RKT_OQUE, index);
2701151086Sscottl}
2702151086Sscottl
2703151086Sscottl/*
270483114Sscottl * Debugging and Diagnostics
270583114Sscottl */
270665793Smsmith
270783114Sscottl/*
270865793Smsmith * Print some information about the controller.
270965793Smsmith */
271065793Smsmithstatic void
271165793Smsmithaac_describe_controller(struct aac_softc *sc)
271265793Smsmith{
271395350Sscottl	struct aac_fib *fib;
271483114Sscottl	struct aac_adapter_info	*info;
271565793Smsmith
271683114Sscottl	debug_called(2);
271765793Smsmith
2718130006Sscottl	aac_alloc_sync_fib(sc, &fib);
271995350Sscottl
272095350Sscottl	fib->data[0] = 0;
272195350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
272283114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
272395536Sscottl		aac_release_sync_fib(sc);
272483114Sscottl		return;
272583114Sscottl	}
272665793Smsmith
272783114Sscottl	/* save the kernel revision structure for later use */
2728135095Sscottl	info = (struct aac_adapter_info *)&fib->data[0];
272983114Sscottl	sc->aac_revision = info->KernelRevision;
273095536Sscottl
2731151086Sscottl	device_printf(sc->aac_dev, "Adaptec Raid Controller %d.%d.%d-%d\n",
2732151086Sscottl		AAC_DRIVER_VERSION >> 24,
2733151086Sscottl		(AAC_DRIVER_VERSION >> 16) & 0xFF,
2734151086Sscottl		AAC_DRIVER_VERSION & 0xFF,
2735151086Sscottl		AAC_DRIVER_BUILD);
2736151086Sscottl
2737135095Sscottl	if (bootverbose) {
2738146851Sscottl		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2739146851Sscottl		    "(%dMB cache, %dMB execution), %s\n",
2740135095Sscottl		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2741146851Sscottl		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2742146851Sscottl		    info->BufferMem / (1024 * 1024),
2743146851Sscottl		    info->ExecutionMem / (1024 * 1024),
2744135095Sscottl		    aac_describe_code(aac_battery_platform,
2745135095Sscottl		    info->batteryPlatform));
2746112679Sscottl
2747135095Sscottl		device_printf(sc->aac_dev,
2748135095Sscottl		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2749135095Sscottl		    info->KernelRevision.external.comp.major,
2750135095Sscottl		    info->KernelRevision.external.comp.minor,
2751135095Sscottl		    info->KernelRevision.external.comp.dash,
2752135095Sscottl		    info->KernelRevision.buildNumber,
2753135095Sscottl		    (u_int32_t)(info->SerialNumber & 0xffffff));
2754135095Sscottl
2755112679Sscottl		device_printf(sc->aac_dev, "Supported Options=%b\n",
2756112679Sscottl			      sc->supported_options,
2757112679Sscottl			      "\20"
2758112679Sscottl			      "\1SNAPSHOT"
2759112679Sscottl			      "\2CLUSTERS"
2760112679Sscottl			      "\3WCACHE"
2761112679Sscottl			      "\4DATA64"
2762112679Sscottl			      "\5HOSTTIME"
2763112679Sscottl			      "\6RAID50"
2764112679Sscottl			      "\7WINDOW4GB"
2765112679Sscottl			      "\10SCSIUPGD"
2766112679Sscottl			      "\11SOFTERR"
2767112679Sscottl			      "\12NORECOND"
2768112679Sscottl			      "\13SGMAP64"
2769112679Sscottl			      "\14ALARM"
2770151086Sscottl			      "\15NONDASD"
2771151086Sscottl			      "\16SCSIMGT"
2772151086Sscottl			      "\17RAIDSCSI"
2773151086Sscottl			      "\21ADPTINFO"
2774151086Sscottl			      "\22NEWCOMM"
2775151086Sscottl			      "\23ARRAY64BIT"
2776151086Sscottl			      "\24HEATSENSOR");
2777112679Sscottl	}
2778135095Sscottl	aac_release_sync_fib(sc);
277965793Smsmith}
278065793Smsmith
278183114Sscottl/*
278265793Smsmith * Look up a text description of a numeric error code and return a pointer to
278365793Smsmith * same.
278465793Smsmith */
278565793Smsmithstatic char *
278665793Smsmithaac_describe_code(struct aac_code_lookup *table, u_int32_t code)
278765793Smsmith{
278883114Sscottl	int i;
278965793Smsmith
279083114Sscottl	for (i = 0; table[i].string != NULL; i++)
279183114Sscottl		if (table[i].code == code)
279283114Sscottl			return(table[i].string);
279383114Sscottl	return(table[i + 1].string);
279465793Smsmith}
279565793Smsmith
279683114Sscottl/*
279783114Sscottl * Management Interface
279883114Sscottl */
279965793Smsmith
280065793Smsmithstatic int
2801130585Sphkaac_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
280265793Smsmith{
280383114Sscottl	struct aac_softc *sc;
280465793Smsmith
280583114Sscottl	debug_called(2);
280665793Smsmith
280783114Sscottl	sc = dev->si_drv1;
280865793Smsmith
280983114Sscottl	/* Check to make sure the device isn't already open */
281083114Sscottl	if (sc->aac_state & AAC_STATE_OPEN) {
281183114Sscottl		return EBUSY;
281283114Sscottl	}
281383114Sscottl	sc->aac_state |= AAC_STATE_OPEN;
281483114Sscottl
281583114Sscottl	return 0;
281665793Smsmith}
281765793Smsmith
281865793Smsmithstatic int
2819130585Sphkaac_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
282065793Smsmith{
282183114Sscottl	struct aac_softc *sc;
282265793Smsmith
282383114Sscottl	debug_called(2);
282465793Smsmith
282583114Sscottl	sc = dev->si_drv1;
282665793Smsmith
282783114Sscottl	/* Mark this unit as no longer open  */
282883114Sscottl	sc->aac_state &= ~AAC_STATE_OPEN;
282983114Sscottl
283083114Sscottl	return 0;
283165793Smsmith}
283265793Smsmith
283365793Smsmithstatic int
2834130585Sphkaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
283565793Smsmith{
283683114Sscottl	union aac_statrequest *as;
283783114Sscottl	struct aac_softc *sc;
283883114Sscottl	int error = 0;
2839119146Sscottl	uint32_t cookie;
284065793Smsmith
284183114Sscottl	debug_called(2);
284265793Smsmith
284383114Sscottl	as = (union aac_statrequest *)arg;
284483114Sscottl	sc = dev->si_drv1;
284583114Sscottl
284683114Sscottl	switch (cmd) {
284783114Sscottl	case AACIO_STATS:
284883114Sscottl		switch (as->as_item) {
284983114Sscottl		case AACQ_FREE:
285083114Sscottl		case AACQ_BIO:
285183114Sscottl		case AACQ_READY:
285283114Sscottl		case AACQ_BUSY:
285383114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
285483114Sscottl			      sizeof(struct aac_qstat));
285583114Sscottl			break;
285683114Sscottl		default:
285783114Sscottl			error = ENOENT;
285883114Sscottl			break;
285983114Sscottl		}
286083114Sscottl	break;
286183114Sscottl
286283114Sscottl	case FSACTL_SENDFIB:
286383114Sscottl		arg = *(caddr_t*)arg;
286483114Sscottl	case FSACTL_LNX_SENDFIB:
286583114Sscottl		debug(1, "FSACTL_SENDFIB");
286683114Sscottl		error = aac_ioctl_sendfib(sc, arg);
286783114Sscottl		break;
286883114Sscottl	case FSACTL_AIF_THREAD:
286983114Sscottl	case FSACTL_LNX_AIF_THREAD:
287083114Sscottl		debug(1, "FSACTL_AIF_THREAD");
287183114Sscottl		error = EINVAL;
287283114Sscottl		break;
287383114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
287483114Sscottl		arg = *(caddr_t*)arg;
287587183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
287683114Sscottl		debug(1, "FSACTL_OPEN_GET_ADAPTER_FIB");
287783114Sscottl		/*
287883114Sscottl		 * Pass the caller out an AdapterFibContext.
287983114Sscottl		 *
288083114Sscottl		 * Note that because we only support one opener, we
288183114Sscottl		 * basically ignore this.  Set the caller's context to a magic
288283114Sscottl		 * number just in case.
288383114Sscottl		 *
288483114Sscottl		 * The Linux code hands the driver a pointer into kernel space,
288583114Sscottl		 * and then trusts it when the caller hands it back.  Aiee!
288683114Sscottl		 * Here, we give it the proc pointer of the per-adapter aif
288783114Sscottl		 * thread. It's only used as a sanity check in other calls.
288883114Sscottl		 */
2889119146Sscottl		cookie = (uint32_t)(uintptr_t)sc->aifthread;
2890119146Sscottl		error = copyout(&cookie, arg, sizeof(cookie));
289183114Sscottl		break;
289283114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
289383114Sscottl		arg = *(caddr_t*)arg;
289483114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
289583114Sscottl		debug(1, "FSACTL_GET_NEXT_ADAPTER_FIB");
289683114Sscottl		error = aac_getnext_aif(sc, arg);
289783114Sscottl		break;
289883114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
289983114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
290083114Sscottl		debug(1, "FSACTL_CLOSE_GET_ADAPTER_FIB");
290183114Sscottl		/* don't do anything here */
290283114Sscottl		break;
290383114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
290483114Sscottl		arg = *(caddr_t*)arg;
290583114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
290683114Sscottl		debug(1, "FSACTL_MINIPORT_REV_CHECK");
290783114Sscottl		error = aac_rev_check(sc, arg);
290883114Sscottl		break;
290983114Sscottl	case FSACTL_QUERY_DISK:
291083114Sscottl		arg = *(caddr_t*)arg;
291183114Sscottl	case FSACTL_LNX_QUERY_DISK:
291283114Sscottl		debug(1, "FSACTL_QUERY_DISK");
291383114Sscottl		error = aac_query_disk(sc, arg);
2914151086Sscottl		break;
291583114Sscottl	case FSACTL_DELETE_DISK:
291683114Sscottl	case FSACTL_LNX_DELETE_DISK:
291783114Sscottl		/*
291883114Sscottl		 * We don't trust the underland to tell us when to delete a
291983114Sscottl		 * container, rather we rely on an AIF coming from the
292083114Sscottl		 * controller
292183114Sscottl		 */
292283114Sscottl		error = 0;
292383114Sscottl		break;
2924151086Sscottl	case FSACTL_GET_PCI_INFO:
2925151086Sscottl		arg = *(caddr_t*)arg;
2926151086Sscottl	case FSACTL_LNX_GET_PCI_INFO:
2927151086Sscottl		debug(1, "FSACTL_GET_PCI_INFO");
2928151086Sscottl		error = aac_get_pci_info(sc, arg);
2929151086Sscottl		break;
293070393Smsmith	default:
293187183Sscottl		debug(1, "unsupported cmd 0x%lx\n", cmd);
293283114Sscottl		error = EINVAL;
293383114Sscottl		break;
293470393Smsmith	}
293583114Sscottl	return(error);
293665793Smsmith}
293765793Smsmith
293887183Sscottlstatic int
2939130585Sphkaac_poll(struct cdev *dev, int poll_events, d_thread_t *td)
294087183Sscottl{
294187183Sscottl	struct aac_softc *sc;
294287183Sscottl	int revents;
294387183Sscottl
294487183Sscottl	sc = dev->si_drv1;
294587183Sscottl	revents = 0;
294687183Sscottl
2947133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
294887183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
294987183Sscottl		if (sc->aac_aifq_tail != sc->aac_aifq_head)
295087183Sscottl			revents |= poll_events & (POLLIN | POLLRDNORM);
295187183Sscottl	}
2952133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
295387183Sscottl
295487183Sscottl	if (revents == 0) {
295587183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
295687183Sscottl			selrecord(td, &sc->rcv_select);
295787183Sscottl	}
295887183Sscottl
295987183Sscottl	return (revents);
296087183Sscottl}
296187183Sscottl
2962151086Sscottlstatic void
2963151086Sscottlaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
2964151086Sscottl{
2965151086Sscottl
2966151086Sscottl	switch (event->ev_type) {
2967151086Sscottl	case AAC_EVENT_CMFREE:
2968151086Sscottl		mtx_lock(&sc->aac_io_lock);
2969151086Sscottl		if (aac_alloc_command(sc, (struct aac_command **)arg) == 0) {
2970151086Sscottl			aac_add_event(sc, event);
2971151086Sscottl			mtx_unlock(&sc->aac_io_lock);
2972151086Sscottl			return;
2973151086Sscottl		}
2974151086Sscottl		free(event, M_AACBUF);
2975151086Sscottl		wakeup(aac_ioctl_sendfib);
2976151086Sscottl		mtx_unlock(&sc->aac_io_lock);
2977151086Sscottl		break;
2978151086Sscottl	default:
2979151086Sscottl		break;
2980151086Sscottl	}
2981151086Sscottl}
2982151086Sscottl
298383114Sscottl/*
298465793Smsmith * Send a FIB supplied from userspace
298565793Smsmith */
298665793Smsmithstatic int
298765793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
298865793Smsmith{
298983114Sscottl	struct aac_command *cm;
299083114Sscottl	int size, error;
299165793Smsmith
299283114Sscottl	debug_called(2);
299365793Smsmith
299483114Sscottl	cm = NULL;
299565793Smsmith
299683114Sscottl	/*
299783114Sscottl	 * Get a command
299883114Sscottl	 */
2999133540Sscottl	mtx_lock(&sc->aac_io_lock);
300083114Sscottl	if (aac_alloc_command(sc, &cm)) {
3001151086Sscottl		struct aac_event *event;
3002151086Sscottl
3003151086Sscottl		event = malloc(sizeof(struct aac_event), M_AACBUF,
3004151086Sscottl		    M_NOWAIT | M_ZERO);
3005151086Sscottl		if (event == NULL) {
3006151086Sscottl			error = EBUSY;
3007151086Sscottl			goto out;
3008151086Sscottl		}
3009151086Sscottl		event->ev_type = AAC_EVENT_CMFREE;
3010151086Sscottl		event->ev_callback = aac_ioctl_event;
3011151086Sscottl		event->ev_arg = &cm;
3012151086Sscottl		aac_add_event(sc, event);
3013151086Sscottl		msleep(aac_ioctl_sendfib, &sc->aac_io_lock, 0, "sendfib", 0);
301483114Sscottl	}
301565793Smsmith
301683114Sscottl	/*
301783114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
301883114Sscottl	 */
301983114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
302083114Sscottl			    sizeof(struct aac_fib_header))) != 0)
302183114Sscottl		goto out;
302283114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
302383114Sscottl	if (size > sizeof(struct aac_fib)) {
3024119146Sscottl		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %zd)\n",
302583114Sscottl			      size, sizeof(struct aac_fib));
302683114Sscottl		size = sizeof(struct aac_fib);
302783114Sscottl	}
302883114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
302983114Sscottl		goto out;
303083114Sscottl	cm->cm_fib->Header.Size = size;
3031150119Sscottl	cm->cm_timestamp = time_uptime;
303265793Smsmith
303383114Sscottl	/*
303483114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
303583114Sscottl	 */
3036128258Sscottl	if ((error = aac_wait_command(cm)) != 0) {
3037110426Sscottl		device_printf(sc->aac_dev,
3038110426Sscottl			      "aac_wait_command return %d\n", error);
303983114Sscottl		goto out;
304087183Sscottl	}
304165793Smsmith
304283114Sscottl	/*
304383114Sscottl	 * Copy the FIB and data back out to the caller.
304483114Sscottl	 */
304583114Sscottl	size = cm->cm_fib->Header.Size;
304683114Sscottl	if (size > sizeof(struct aac_fib)) {
3047119146Sscottl		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %zd)\n",
304883114Sscottl			      size, sizeof(struct aac_fib));
304983114Sscottl		size = sizeof(struct aac_fib);
305083114Sscottl	}
305183114Sscottl	error = copyout(cm->cm_fib, ufib, size);
305265793Smsmith
305365793Smsmithout:
305483114Sscottl	if (cm != NULL) {
305583114Sscottl		aac_release_command(cm);
305683114Sscottl	}
3057111532Sscottl
3058133540Sscottl	mtx_unlock(&sc->aac_io_lock);
305983114Sscottl	return(error);
306065793Smsmith}
306165793Smsmith
306283114Sscottl/*
306365793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
306482527Sscottl * If the queue fills up, then drop the older entries.
306565793Smsmith */
306665793Smsmithstatic void
306782527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
306865793Smsmith{
306983114Sscottl	struct aac_aif_command *aif;
307083114Sscottl	struct aac_container *co, *co_next;
307195350Sscottl	struct aac_mntinfo *mi;
307295350Sscottl	struct aac_mntinforesp *mir = NULL;
307383114Sscottl	u_int16_t rsize;
307487183Sscottl	int next, found;
3075115760Sscottl	int count = 0, added = 0, i = 0;
307665793Smsmith
307783114Sscottl	debug_called(2);
307865793Smsmith
307983114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
308083114Sscottl	aac_print_aif(sc, aif);
308182527Sscottl
308283114Sscottl	/* Is it an event that we should care about? */
308383114Sscottl	switch (aif->command) {
308483114Sscottl	case AifCmdEventNotify:
308583114Sscottl		switch (aif->data.EN.type) {
308683114Sscottl		case AifEnAddContainer:
308783114Sscottl		case AifEnDeleteContainer:
308883114Sscottl			/*
308983114Sscottl			 * A container was added or deleted, but the message
309083114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
309183114Sscottl			 * containers and sort things out.
309283114Sscottl			 */
3093130006Sscottl			aac_alloc_sync_fib(sc, &fib);
309495350Sscottl			mi = (struct aac_mntinfo *)&fib->data[0];
309583114Sscottl			do {
309683114Sscottl				/*
309783114Sscottl				 * Ask the controller for its containers one at
309883114Sscottl				 * a time.
309983114Sscottl				 * XXX What if the controller's list changes
310083114Sscottl				 * midway through this enumaration?
310183114Sscottl				 * XXX This should be done async.
310283114Sscottl				 */
310395966Sscottl				bzero(mi, sizeof(struct aac_mntinfo));
310495966Sscottl				mi->Command = VM_NameServe;
310595966Sscottl				mi->MntType = FT_FILESYS;
310695350Sscottl				mi->MntCount = i;
310783114Sscottl				rsize = sizeof(mir);
310895350Sscottl				if (aac_sync_fib(sc, ContainerCommand, 0, fib,
310995350Sscottl						 sizeof(struct aac_mntinfo))) {
3110115760Sscottl					printf("Error probing container %d\n",
311183114Sscottl					      i);
311283114Sscottl					continue;
311383114Sscottl				}
311495350Sscottl				mir = (struct aac_mntinforesp *)&fib->data[0];
3115115760Sscottl				/* XXX Need to check if count changed */
3116115760Sscottl				count = mir->MntRespCount;
311783114Sscottl				/*
311883114Sscottl				 * Check the container against our list.
311983114Sscottl				 * co->co_found was already set to 0 in a
312083114Sscottl				 * previous run.
312183114Sscottl				 */
312295350Sscottl				if ((mir->Status == ST_OK) &&
312395350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
312483114Sscottl					found = 0;
312583114Sscottl					TAILQ_FOREACH(co,
312683114Sscottl						      &sc->aac_container_tqh,
312783114Sscottl						      co_link) {
312883114Sscottl						if (co->co_mntobj.ObjectId ==
312995350Sscottl						    mir->MntTable[0].ObjectId) {
313083114Sscottl							co->co_found = 1;
313183114Sscottl							found = 1;
313283114Sscottl							break;
313383114Sscottl						}
313483114Sscottl					}
313583114Sscottl					/*
313683114Sscottl					 * If the container matched, continue
313783114Sscottl					 * in the list.
313883114Sscottl					 */
313983114Sscottl					if (found) {
314083114Sscottl						i++;
314183114Sscottl						continue;
314283114Sscottl					}
314383114Sscottl
314483114Sscottl					/*
314583114Sscottl					 * This is a new container.  Do all the
3146110426Sscottl					 * appropriate things to set it up.
3147110426Sscottl					 */
314895350Sscottl					aac_add_container(sc, mir, 1);
314983114Sscottl					added = 1;
315083114Sscottl				}
315183114Sscottl				i++;
3152115760Sscottl			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
315395350Sscottl			aac_release_sync_fib(sc);
315483114Sscottl
315583114Sscottl			/*
315683114Sscottl			 * Go through our list of containers and see which ones
315783114Sscottl			 * were not marked 'found'.  Since the controller didn't
315883114Sscottl			 * list them they must have been deleted.  Do the
315983114Sscottl			 * appropriate steps to destroy the device.  Also reset
316083114Sscottl			 * the co->co_found field.
316183114Sscottl			 */
316283114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
316383114Sscottl			while (co != NULL) {
316483114Sscottl				if (co->co_found == 0) {
3165151086Sscottl					mtx_unlock(&sc->aac_io_lock);
3166151086Sscottl					mtx_lock(&Giant);
316783114Sscottl					device_delete_child(sc->aac_dev,
316883114Sscottl							    co->co_disk);
3169151086Sscottl					mtx_unlock(&Giant);
3170151086Sscottl					mtx_lock(&sc->aac_io_lock);
317183114Sscottl					co_next = TAILQ_NEXT(co, co_link);
3172133540Sscottl					mtx_lock(&sc->aac_container_lock);
317383114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
317483114Sscottl						     co_link);
3175133540Sscottl					mtx_unlock(&sc->aac_container_lock);
3176133541Sscottl					free(co, M_AACBUF);
317783114Sscottl					co = co_next;
317883114Sscottl				} else {
317983114Sscottl					co->co_found = 0;
318083114Sscottl					co = TAILQ_NEXT(co, co_link);
318183114Sscottl				}
318282527Sscottl			}
318382527Sscottl
318483114Sscottl			/* Attach the newly created containers */
3185151086Sscottl			if (added) {
3186151086Sscottl				mtx_unlock(&sc->aac_io_lock);
3187151086Sscottl				mtx_lock(&Giant);
318883114Sscottl				bus_generic_attach(sc->aac_dev);
3189151086Sscottl				mtx_unlock(&Giant);
3190151086Sscottl				mtx_lock(&sc->aac_io_lock);
3191151086Sscottl			}
319283114Sscottl
3193105528Sphk			break;
319482527Sscottl
319583114Sscottl		default:
319683114Sscottl			break;
319782527Sscottl		}
319882527Sscottl
319982527Sscottl	default:
320083114Sscottl		break;
320182527Sscottl	}
320282527Sscottl
320383114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3204133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
320583114Sscottl	next = (sc->aac_aifq_head + 1) % AAC_AIFQ_LENGTH;
320683114Sscottl	if (next != sc->aac_aifq_tail) {
320783114Sscottl		bcopy(aif, &sc->aac_aifq[next], sizeof(struct aac_aif_command));
320887183Sscottl		sc->aac_aifq_head = next;
320987183Sscottl
321087183Sscottl		/* On the off chance that someone is sleeping for an aif... */
321187183Sscottl		if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
321287183Sscottl			wakeup(sc->aac_aifq);
321387183Sscottl		/* Wakeup any poll()ers */
3214122352Stanimura		selwakeuppri(&sc->rcv_select, PRIBIO);
321583114Sscottl	}
3216133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
321782527Sscottl
321883114Sscottl	return;
321965793Smsmith}
322065793Smsmith
322183114Sscottl/*
322270393Smsmith * Return the Revision of the driver to userspace and check to see if the
322382527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
322482527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
322582527Sscottl * returning what the card reported.
322665793Smsmith */
322765793Smsmithstatic int
322881189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
322965793Smsmith{
323083114Sscottl	struct aac_rev_check rev_check;
323183114Sscottl	struct aac_rev_check_resp rev_check_resp;
323283114Sscottl	int error = 0;
323365793Smsmith
323483114Sscottl	debug_called(2);
323565793Smsmith
323683114Sscottl	/*
323783114Sscottl	 * Copyin the revision struct from userspace
323883114Sscottl	 */
323983114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
324081082Sscottl			sizeof(struct aac_rev_check))) != 0) {
324183114Sscottl		return error;
324283114Sscottl	}
324365793Smsmith
324483114Sscottl	debug(2, "Userland revision= %d\n",
324583114Sscottl	      rev_check.callingRevision.buildNumber);
324665793Smsmith
324783114Sscottl	/*
324883114Sscottl	 * Doctor up the response struct.
324983114Sscottl	 */
325083114Sscottl	rev_check_resp.possiblyCompatible = 1;
325183114Sscottl	rev_check_resp.adapterSWRevision.external.ul =
325283114Sscottl	    sc->aac_revision.external.ul;
325383114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
325483114Sscottl	    sc->aac_revision.buildNumber;
325565793Smsmith
325683114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
325783114Sscottl			sizeof(struct aac_rev_check_resp)));
325865793Smsmith}
325965793Smsmith
326083114Sscottl/*
326165793Smsmith * Pass the caller the next AIF in their queue
326265793Smsmith */
326365793Smsmithstatic int
326481189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
326565793Smsmith{
326683114Sscottl	struct get_adapter_fib_ioctl agf;
3267111691Sscottl	int error;
326865793Smsmith
326983114Sscottl	debug_called(2);
327065793Smsmith
327183114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
327265793Smsmith
327383114Sscottl		/*
327483114Sscottl		 * Check the magic number that we gave the caller.
327583114Sscottl		 */
3276119146Sscottl		if (agf.AdapterFibContext != (int)(uintptr_t)sc->aifthread) {
327783114Sscottl			error = EFAULT;
327883114Sscottl		} else {
327981189Sscottl			error = aac_return_aif(sc, agf.AifFib);
328083114Sscottl			if ((error == EAGAIN) && (agf.Wait)) {
328183114Sscottl				sc->aac_state |= AAC_STATE_AIF_SLEEPER;
328283114Sscottl				while (error == EAGAIN) {
328383114Sscottl					error = tsleep(sc->aac_aifq, PRIBIO |
328483114Sscottl						       PCATCH, "aacaif", 0);
328583114Sscottl					if (error == 0)
328683114Sscottl						error = aac_return_aif(sc,
328783114Sscottl						    agf.AifFib);
328883114Sscottl				}
328983114Sscottl				sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
329083114Sscottl			}
329165793Smsmith		}
329265793Smsmith	}
329383114Sscottl	return(error);
329465793Smsmith}
329565793Smsmith
329683114Sscottl/*
329770393Smsmith * Hand the next AIF off the top of the queue out to userspace.
329870393Smsmith */
329970393Smsmithstatic int
330081189Sscottlaac_return_aif(struct aac_softc *sc, caddr_t uptr)
330170393Smsmith{
3302121173Sscottl	int next, error;
330370393Smsmith
330483114Sscottl	debug_called(2);
330570393Smsmith
3306133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
330783114Sscottl	if (sc->aac_aifq_tail == sc->aac_aifq_head) {
3308133540Sscottl		mtx_unlock(&sc->aac_aifq_lock);
3309121173Sscottl		return (EAGAIN);
331083114Sscottl	}
3311121173Sscottl
3312121173Sscottl	next = (sc->aac_aifq_tail + 1) % AAC_AIFQ_LENGTH;
3313121173Sscottl	error = copyout(&sc->aac_aifq[next], uptr,
3314121173Sscottl			sizeof(struct aac_aif_command));
3315121173Sscottl	if (error)
3316121173Sscottl		device_printf(sc->aac_dev,
3317121173Sscottl		    "aac_return_aif: copyout returned %d\n", error);
3318121173Sscottl	else
3319121173Sscottl		sc->aac_aifq_tail = next;
3320121173Sscottl
3321133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
332283114Sscottl	return(error);
332370393Smsmith}
332482527Sscottl
3325151086Sscottlstatic int
3326151086Sscottlaac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
3327151086Sscottl{
3328151086Sscottl	struct aac_pci_info {
3329151086Sscottl		u_int32_t bus;
3330151086Sscottl		u_int32_t slot;
3331151086Sscottl	} pciinf;
3332151086Sscottl	int error;
3333151086Sscottl
3334151086Sscottl	debug_called(2);
3335151086Sscottl
3336151086Sscottl	pciinf.bus = pci_get_bus(sc->aac_dev);
3337151086Sscottl	pciinf.slot = pci_get_slot(sc->aac_dev);
3338151086Sscottl
3339151086Sscottl	error = copyout((caddr_t)&pciinf, uptr,
3340151086Sscottl			sizeof(struct aac_pci_info));
3341151086Sscottl
3342151086Sscottl	return (error);
3343151086Sscottl}
3344151086Sscottl
334583114Sscottl/*
334682527Sscottl * Give the userland some information about the container.  The AAC arch
334782527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
334882527Sscottl * the containers to have b:t:l numbers.  Fake it.
334982527Sscottl */
335082527Sscottlstatic int
335182527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
335282527Sscottl{
335383114Sscottl	struct aac_query_disk query_disk;
335483114Sscottl	struct aac_container *co;
335583114Sscottl	struct aac_disk	*disk;
335683114Sscottl	int error, id;
335782527Sscottl
335883114Sscottl	debug_called(2);
335982527Sscottl
336083114Sscottl	disk = NULL;
336182527Sscottl
336283114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
336383114Sscottl		       sizeof(struct aac_query_disk));
336483114Sscottl	if (error)
336583114Sscottl		return (error);
336682527Sscottl
336783114Sscottl	id = query_disk.ContainerNumber;
336883114Sscottl	if (id == -1)
336983114Sscottl		return (EINVAL);
337082527Sscottl
3371133540Sscottl	mtx_lock(&sc->aac_container_lock);
337283114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
337383114Sscottl		if (co->co_mntobj.ObjectId == id)
337483114Sscottl			break;
337583114Sscottl		}
337682527Sscottl
3377105528Sphk	if (co == NULL) {
337883114Sscottl			query_disk.Valid = 0;
337983114Sscottl			query_disk.Locked = 0;
338083114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
3381105528Sphk	} else {
3382105528Sphk		disk = device_get_softc(co->co_disk);
3383105528Sphk		query_disk.Valid = 1;
3384105528Sphk		query_disk.Locked =
3385105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
3386105528Sphk		query_disk.Deleted = 0;
3387105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
3388105528Sphk		query_disk.Target = disk->unit;
3389105528Sphk		query_disk.Lun = 0;
3390105528Sphk		query_disk.UnMapped = 0;
3391111525Sscottl		sprintf(&query_disk.diskDeviceName[0], "%s%d",
3392125975Sphk		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
3393105528Sphk	}
3394133540Sscottl	mtx_unlock(&sc->aac_container_lock);
339582527Sscottl
339683114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
339783114Sscottl			sizeof(struct aac_query_disk));
339883114Sscottl
339983114Sscottl	return (error);
340082527Sscottl}
340182527Sscottl
340295536Sscottlstatic void
340395536Sscottlaac_get_bus_info(struct aac_softc *sc)
340495536Sscottl{
340595536Sscottl	struct aac_fib *fib;
340695536Sscottl	struct aac_ctcfg *c_cmd;
340795536Sscottl	struct aac_ctcfg_resp *c_resp;
340895536Sscottl	struct aac_vmioctl *vmi;
340995536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
341095536Sscottl	struct aac_getbusinf businfo;
3411110426Sscottl	struct aac_sim *caminf;
341295536Sscottl	device_t child;
341395536Sscottl	int i, found, error;
341495536Sscottl
3415130006Sscottl	aac_alloc_sync_fib(sc, &fib);
341695536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
341795966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
341895536Sscottl
341995536Sscottl	c_cmd->Command = VM_ContainerConfig;
342095536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
342195536Sscottl	c_cmd->param = 0;
342295536Sscottl
342395536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
342495536Sscottl	    sizeof(struct aac_ctcfg));
342595536Sscottl	if (error) {
342695536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
342795536Sscottl		    "VM_ContainerConfig command\n", error);
342895536Sscottl		aac_release_sync_fib(sc);
342995536Sscottl		return;
343095536Sscottl	}
343195536Sscottl
343295536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
343395536Sscottl	if (c_resp->Status != ST_OK) {
343495536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
343595536Sscottl		    c_resp->Status);
343695536Sscottl		aac_release_sync_fib(sc);
343795536Sscottl		return;
343895536Sscottl	}
343995536Sscottl
344095536Sscottl	sc->scsi_method_id = c_resp->param;
344195536Sscottl
344295536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
344395966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
344495966Sscottl
344595536Sscottl	vmi->Command = VM_Ioctl;
344695536Sscottl	vmi->ObjType = FT_DRIVE;
344795536Sscottl	vmi->MethId = sc->scsi_method_id;
344895536Sscottl	vmi->ObjId = 0;
344995536Sscottl	vmi->IoctlCmd = GetBusInfo;
345095536Sscottl
345195536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
345295536Sscottl	    sizeof(struct aac_vmioctl));
345395536Sscottl	if (error) {
345495536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
345595536Sscottl		    error);
345695536Sscottl		aac_release_sync_fib(sc);
345795536Sscottl		return;
345895536Sscottl	}
345995536Sscottl
346095536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
346195536Sscottl	if (vmi_resp->Status != ST_OK) {
346295536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
346395536Sscottl		    vmi_resp->Status);
346495536Sscottl		aac_release_sync_fib(sc);
346595536Sscottl		return;
346695536Sscottl	}
346795536Sscottl
346895536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
346995536Sscottl	aac_release_sync_fib(sc);
347095536Sscottl
347195536Sscottl	found = 0;
347295536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
347395536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
347495536Sscottl			continue;
347595536Sscottl
3476110428Sscottl		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3477110428Sscottl		    M_AACBUF, M_NOWAIT | M_ZERO);
3478143838Sscottl		if (caminf == NULL) {
3479143838Sscottl			device_printf(sc->aac_dev,
3480143838Sscottl			    "No memory to add passthrough bus %d\n", i);
3481143838Sscottl			break;
3482151086Sscottl		};
348395536Sscottl
348495536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
348595536Sscottl		if (child == NULL) {
3486143838Sscottl			device_printf(sc->aac_dev,
3487143838Sscottl			    "device_add_child failed for passthrough bus %d\n",
3488143838Sscottl			    i);
3489143838Sscottl			free(caminf, M_AACBUF);
3490151086Sscottl			break;
349195536Sscottl		}
349295536Sscottl
349395536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
349495536Sscottl		caminf->BusNumber = i;
349595536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
349695536Sscottl		caminf->aac_sc = sc;
3497110432Sscottl		caminf->sim_dev = child;
349895536Sscottl
349995536Sscottl		device_set_ivars(child, caminf);
350095536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
3501110426Sscottl		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
350295536Sscottl
350395536Sscottl		found = 1;
350495536Sscottl	}
350595536Sscottl
350695536Sscottl	if (found)
350795536Sscottl		bus_generic_attach(sc->aac_dev);
350895536Sscottl
350995536Sscottl	return;
351095536Sscottl}
3511