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$");
32119418Sobrien
3365793Smsmith/*
3465793Smsmith * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
3565793Smsmith */
36151086Sscottl#define AAC_DRIVERNAME			"aac"
3765793Smsmith
3881151Sscottl#include "opt_aac.h"
3981151Sscottl
4082527Sscottl/* #include <stddef.h> */
4165793Smsmith#include <sys/param.h>
4265793Smsmith#include <sys/systm.h>
4365793Smsmith#include <sys/malloc.h>
4465793Smsmith#include <sys/kernel.h>
4582527Sscottl#include <sys/kthread.h>
4681154Sscottl#include <sys/sysctl.h>
4787183Sscottl#include <sys/poll.h>
48112946Sphk#include <sys/ioccom.h>
4965793Smsmith
5065793Smsmith#include <sys/bus.h>
5165793Smsmith#include <sys/conf.h>
5265793Smsmith#include <sys/signalvar.h>
5370393Smsmith#include <sys/time.h>
5482527Sscottl#include <sys/eventhandler.h>
55151086Sscottl#include <sys/rman.h>
5665793Smsmith
5765793Smsmith#include <machine/bus.h>
58143838Sscottl#include <sys/bus_dma.h>
5965793Smsmith#include <machine/resource.h>
6065793Smsmith
61151086Sscottl#include <dev/pci/pcireg.h>
62151086Sscottl#include <dev/pci/pcivar.h>
63151086Sscottl
6465793Smsmith#include <dev/aac/aacreg.h>
65138635Sscottl#include <sys/aac_ioctl.h>
6665793Smsmith#include <dev/aac/aacvar.h>
6765793Smsmith#include <dev/aac/aac_tables.h>
6865793Smsmith
6965793Smsmithstatic void	aac_startup(void *arg);
7083114Sscottlstatic void	aac_add_container(struct aac_softc *sc,
7195350Sscottl				  struct aac_mntinforesp *mir, int f);
7295536Sscottlstatic void	aac_get_bus_info(struct aac_softc *sc);
73188896Sattiliostatic void	aac_daemon(void *arg);
7465793Smsmith
7565793Smsmith/* Command Processing */
7670393Smsmithstatic void	aac_timeout(struct aac_softc *sc);
7765793Smsmithstatic void	aac_complete(void *context, int pending);
7865793Smsmithstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
7965793Smsmithstatic void	aac_bio_complete(struct aac_command *cm);
80128258Sscottlstatic int	aac_wait_command(struct aac_command *cm);
81110426Sscottlstatic void	aac_command_thread(struct aac_softc *sc);
8265793Smsmith
8365793Smsmith/* Command Buffer Management */
84117363Sscottlstatic void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
85117363Sscottl				   int nseg, int error);
8681082Sscottlstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
8781082Sscottl				       int nseg, int error);
8870393Smsmithstatic int	aac_alloc_commands(struct aac_softc *sc);
89111141Sscottlstatic void	aac_free_commands(struct aac_softc *sc);
9065793Smsmithstatic void	aac_unmap_command(struct aac_command *cm);
9165793Smsmith
9265793Smsmith/* Hardware Interface */
93177557Semastestatic int	aac_alloc(struct aac_softc *sc);
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);
101177557Semastestatic int	aac_setup_intr(struct aac_softc *sc);
10281082Sscottlstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
10381151Sscottl				struct aac_command *cm);
10481082Sscottlstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
10583114Sscottl				u_int32_t *fib_size, struct aac_fib **fib_addr);
10682527Sscottlstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
10782527Sscottl				     struct aac_fib *fib);
10865793Smsmith
10965793Smsmith/* StrongARM interface */
11065793Smsmithstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
11165793Smsmithstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
11265793Smsmithstatic int	aac_sa_get_istatus(struct aac_softc *sc);
11365793Smsmithstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
11465793Smsmithstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
11581082Sscottl				   u_int32_t arg0, u_int32_t arg1,
11681082Sscottl				   u_int32_t arg2, u_int32_t arg3);
117112679Sscottlstatic int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
11865793Smsmithstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
11965793Smsmith
120251070Smariusconst struct aac_interface aac_sa_interface = {
12183114Sscottl	aac_sa_get_fwstatus,
12283114Sscottl	aac_sa_qnotify,
12383114Sscottl	aac_sa_get_istatus,
12483114Sscottl	aac_sa_clear_istatus,
12583114Sscottl	aac_sa_set_mailbox,
126112679Sscottl	aac_sa_get_mailbox,
127151086Sscottl	aac_sa_set_interrupts,
128151086Sscottl	NULL, NULL, NULL
12965793Smsmith};
13065793Smsmith
131152388Sschweikh/* i960Rx interface */
13265793Smsmithstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
13365793Smsmithstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
13465793Smsmithstatic int	aac_rx_get_istatus(struct aac_softc *sc);
13565793Smsmithstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
13665793Smsmithstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
13781082Sscottl				   u_int32_t arg0, u_int32_t arg1,
13881082Sscottl				   u_int32_t arg2, u_int32_t arg3);
139112679Sscottlstatic int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
14065793Smsmithstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
141151086Sscottlstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
142151086Sscottlstatic int aac_rx_get_outb_queue(struct aac_softc *sc);
143151086Sscottlstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
14465793Smsmith
145251070Smariusconst struct aac_interface aac_rx_interface = {
14683114Sscottl	aac_rx_get_fwstatus,
14783114Sscottl	aac_rx_qnotify,
14883114Sscottl	aac_rx_get_istatus,
14983114Sscottl	aac_rx_clear_istatus,
15083114Sscottl	aac_rx_set_mailbox,
151112679Sscottl	aac_rx_get_mailbox,
152151086Sscottl	aac_rx_set_interrupts,
153151086Sscottl	aac_rx_send_command,
154151086Sscottl	aac_rx_get_outb_queue,
155151086Sscottl	aac_rx_set_outb_queue
15665793Smsmith};
15765793Smsmith
158152388Sschweikh/* Rocket/MIPS interface */
159133606Sscottlstatic int	aac_rkt_get_fwstatus(struct aac_softc *sc);
160133606Sscottlstatic void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
161133606Sscottlstatic int	aac_rkt_get_istatus(struct aac_softc *sc);
162133606Sscottlstatic void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
163133606Sscottlstatic void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
164133606Sscottl				    u_int32_t arg0, u_int32_t arg1,
165133606Sscottl				    u_int32_t arg2, u_int32_t arg3);
166133606Sscottlstatic int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
167133606Sscottlstatic void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
168151086Sscottlstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
169151086Sscottlstatic int aac_rkt_get_outb_queue(struct aac_softc *sc);
170151086Sscottlstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
171133606Sscottl
172251070Smariusconst struct aac_interface aac_rkt_interface = {
173133606Sscottl	aac_rkt_get_fwstatus,
174133606Sscottl	aac_rkt_qnotify,
175133606Sscottl	aac_rkt_get_istatus,
176133606Sscottl	aac_rkt_clear_istatus,
177133606Sscottl	aac_rkt_set_mailbox,
178133606Sscottl	aac_rkt_get_mailbox,
179151086Sscottl	aac_rkt_set_interrupts,
180151086Sscottl	aac_rkt_send_command,
181151086Sscottl	aac_rkt_get_outb_queue,
182151086Sscottl	aac_rkt_set_outb_queue
183133606Sscottl};
184133606Sscottl
18565793Smsmith/* Debugging and Diagnostics */
186251070Smariusstatic void		aac_describe_controller(struct aac_softc *sc);
187251070Smariusstatic const char	*aac_describe_code(const struct aac_code_lookup *table,
18881082Sscottl				   u_int32_t code);
18965793Smsmith
19065793Smsmith/* Management Interface */
19165793Smsmithstatic d_open_t		aac_open;
19265793Smsmithstatic d_ioctl_t	aac_ioctl;
19387183Sscottlstatic d_poll_t		aac_poll;
194212756Sattiliostatic void		aac_cdevpriv_dtor(void *arg);
19581082Sscottlstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
196177462Semastestatic int		aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
19781082Sscottlstatic void		aac_handle_aif(struct aac_softc *sc,
19883114Sscottl					   struct aac_fib *fib);
19981189Sscottlstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
200174385Semastestatic int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
201174385Semastestatic int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
20281189Sscottlstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
203174385Semastestatic int		aac_return_aif(struct aac_softc *sc,
204174385Semaste					struct aac_fib_context *ctx, caddr_t uptr);
20582527Sscottlstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
206151086Sscottlstatic int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
207177695Semastestatic int		aac_supported_features(struct aac_softc *sc, caddr_t uptr);
208151086Sscottlstatic void		aac_ioctl_event(struct aac_softc *sc,
209198525Semaste					struct aac_event *event, void *arg);
210177557Semastestatic struct aac_mntinforesp *
211177557Semaste	aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid);
21265793Smsmith
21365793Smsmithstatic struct cdevsw aac_cdevsw = {
214126080Sphk	.d_version =	D_VERSION,
215212756Sattilio	.d_flags =	D_NEEDGIANT,
216111815Sphk	.d_open =	aac_open,
217111815Sphk	.d_ioctl =	aac_ioctl,
218111815Sphk	.d_poll =	aac_poll,
219111815Sphk	.d_name =	"aac",
22065793Smsmith};
22165793Smsmith
222249132Smavstatic MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
22382527Sscottl
22481154Sscottl/* sysctl node */
225251070SmariusSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
22681154Sscottl
22783114Sscottl/*
22883114Sscottl * Device Interface
22983114Sscottl */
23065793Smsmith
23183114Sscottl/*
232177184Semaste * Initialize the controller and softc
23365793Smsmith */
23465793Smsmithint
23565793Smsmithaac_attach(struct aac_softc *sc)
23665793Smsmith{
23783114Sscottl	int error, unit;
23865793Smsmith
239177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
24065793Smsmith
24183114Sscottl	/*
242177184Semaste	 * Initialize per-controller queues.
24383114Sscottl	 */
24483114Sscottl	aac_initq_free(sc);
24583114Sscottl	aac_initq_ready(sc);
24683114Sscottl	aac_initq_busy(sc);
24783114Sscottl	aac_initq_bio(sc);
24865793Smsmith
24983114Sscottl	/*
250177184Semaste	 * Initialize command-completion task.
25183114Sscottl	 */
25283114Sscottl	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
25365793Smsmith
25483114Sscottl	/* mark controller as suspended until we get ourselves organised */
25583114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
25665793Smsmith
25783114Sscottl	/*
25890275Sscottl	 * Check that the firmware on the card is supported.
25990275Sscottl	 */
26090275Sscottl	if ((error = aac_check_firmware(sc)) != 0)
26190275Sscottl		return(error);
26290275Sscottl
263117126Sscottl	/*
264117126Sscottl	 * Initialize locks
265117126Sscottl	 */
266133540Sscottl	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
267133540Sscottl	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
268133540Sscottl	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
269117126Sscottl	TAILQ_INIT(&sc->aac_container_tqh);
270153810Sscottl	TAILQ_INIT(&sc->aac_ev_cmfree);
27195350Sscottl
272188896Sattilio	/* Initialize the clock daemon callout. */
273188896Sattilio	callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0);
274188896Sattilio
27583114Sscottl	/*
276177184Semaste	 * Initialize the adapter.
27783114Sscottl	 */
278177557Semaste	if ((error = aac_alloc(sc)) != 0)
279177557Semaste		return(error);
28083114Sscottl	if ((error = aac_init(sc)) != 0)
28183114Sscottl		return(error);
28265793Smsmith
283152388Sschweikh	/*
284151086Sscottl	 * Allocate and connect our interrupt.
285151086Sscottl	 */
286177557Semaste	if ((error = aac_setup_intr(sc)) != 0)
287177557Semaste		return(error);
288151086Sscottl
289152388Sschweikh	/*
29083114Sscottl	 * Print a little information about the controller.
29183114Sscottl	 */
29283114Sscottl	aac_describe_controller(sc);
29365793Smsmith
29483114Sscottl	/*
295243286Semaste	 * Add sysctls.
296243286Semaste	 */
297243286Semaste	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->aac_dev),
298243286Semaste	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->aac_dev)),
299243286Semaste	    OID_AUTO, "firmware_build", CTLFLAG_RD,
300243286Semaste	    &sc->aac_revision.buildNumber, 0,
301243286Semaste	    "firmware build number");
302243286Semaste
303243286Semaste	/*
304111532Sscottl	 * Register to probe our containers later.
30587183Sscottl	 */
30683114Sscottl	sc->aac_ich.ich_func = aac_startup;
30783114Sscottl	sc->aac_ich.ich_arg = sc;
30883114Sscottl	if (config_intrhook_establish(&sc->aac_ich) != 0) {
30983114Sscottl		device_printf(sc->aac_dev,
31083114Sscottl			      "can't establish configuration hook\n");
31183114Sscottl		return(ENXIO);
31283114Sscottl	}
31365793Smsmith
31483114Sscottl	/*
31583114Sscottl	 * Make the control device.
31683114Sscottl	 */
31783114Sscottl	unit = device_get_unit(sc->aac_dev);
318108329Srwatson	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
319108329Srwatson				 0640, "aac%d", unit);
32083114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
32183114Sscottl	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
32283114Sscottl	sc->aac_dev_t->si_drv1 = sc;
32365793Smsmith
32483114Sscottl	/* Create the AIF thread */
325172836Sjulian	if (kproc_create((void(*)(void *))aac_command_thread, sc,
326151086Sscottl		   &sc->aifthread, 0, 0, "aac%daif", unit))
327177635Semaste		panic("Could not create AIF thread");
32882527Sscottl
32983114Sscottl	/* Register the shutdown method to only be called post-dump */
330110427Sscottl	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
331110427Sscottl	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
332110427Sscottl		device_printf(sc->aac_dev,
333110427Sscottl			      "shutdown event registration failed\n");
33482527Sscottl
33595536Sscottl	/* Register with CAM for the non-DASD devices */
336112679Sscottl	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
337110426Sscottl		TAILQ_INIT(&sc->aac_sim_tqh);
33895536Sscottl		aac_get_bus_info(sc);
339110426Sscottl	}
34095536Sscottl
341188896Sattilio	mtx_lock(&sc->aac_io_lock);
342198541Semaste	callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc);
343188896Sattilio	mtx_unlock(&sc->aac_io_lock);
344188896Sattilio
34583114Sscottl	return(0);
34665793Smsmith}
34765793Smsmith
348188896Sattiliostatic void
349188896Sattilioaac_daemon(void *arg)
350188896Sattilio{
351188896Sattilio	struct timeval tv;
352188896Sattilio	struct aac_softc *sc;
353188896Sattilio	struct aac_fib *fib;
354188896Sattilio
355188896Sattilio	sc = arg;
356188896Sattilio	mtx_assert(&sc->aac_io_lock, MA_OWNED);
357188896Sattilio
358188896Sattilio	if (callout_pending(&sc->aac_daemontime) ||
359188896Sattilio	    callout_active(&sc->aac_daemontime) == 0)
360188896Sattilio		return;
361188896Sattilio	getmicrotime(&tv);
362188896Sattilio	aac_alloc_sync_fib(sc, &fib);
363188896Sattilio	*(uint32_t *)fib->data = tv.tv_sec;
364188896Sattilio	aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t));
365188896Sattilio	aac_release_sync_fib(sc);
366188896Sattilio	callout_schedule(&sc->aac_daemontime, 30 * 60 * hz);
367188896Sattilio}
368188896Sattilio
369151086Sscottlvoid
370151086Sscottlaac_add_event(struct aac_softc *sc, struct aac_event *event)
371151086Sscottl{
372151086Sscottl
373151086Sscottl	switch (event->ev_type & AAC_EVENT_MASK) {
374151086Sscottl	case AAC_EVENT_CMFREE:
375151086Sscottl		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
376151086Sscottl		break;
377151086Sscottl	default:
378151086Sscottl		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
379151086Sscottl		    event->ev_type);
380151086Sscottl		break;
381151086Sscottl	}
382151086Sscottl}
383151086Sscottl
38483114Sscottl/*
385177557Semaste * Request information of container #cid
386177557Semaste */
387177557Semastestatic struct aac_mntinforesp *
388177557Semasteaac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid)
389177557Semaste{
390177557Semaste	struct aac_mntinfo *mi;
391177557Semaste
392177557Semaste	mi = (struct aac_mntinfo *)&fib->data[0];
393177619Semaste	/* use 64-bit LBA if enabled */
394177619Semaste	mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ?
395177619Semaste	    VM_NameServe64 : VM_NameServe;
396177557Semaste	mi->MntType = FT_FILESYS;
397177557Semaste	mi->MntCount = cid;
398177557Semaste
399177557Semaste	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
400177557Semaste			 sizeof(struct aac_mntinfo))) {
401212773Semaste		device_printf(sc->aac_dev, "Error probing container %d\n", cid);
402177557Semaste		return (NULL);
403177557Semaste	}
404177557Semaste
405177557Semaste	return ((struct aac_mntinforesp *)&fib->data[0]);
406177557Semaste}
407177557Semaste
408177557Semaste/*
40965793Smsmith * Probe for containers, create disks.
41065793Smsmith */
41165793Smsmithstatic void
41265793Smsmithaac_startup(void *arg)
41365793Smsmith{
41483114Sscottl	struct aac_softc *sc;
41595350Sscottl	struct aac_fib *fib;
416177557Semaste	struct aac_mntinforesp *mir;
417115760Sscottl	int count = 0, i = 0;
41865793Smsmith
41983114Sscottl	sc = (struct aac_softc *)arg;
420177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
42165793Smsmith
42283114Sscottl	/* disconnect ourselves from the intrhook chain */
42383114Sscottl	config_intrhook_disestablish(&sc->aac_ich);
42465793Smsmith
425151086Sscottl	mtx_lock(&sc->aac_io_lock);
426130006Sscottl	aac_alloc_sync_fib(sc, &fib);
42795350Sscottl
42883114Sscottl	/* loop over possible containers */
42983114Sscottl	do {
430177557Semaste		if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
43183114Sscottl			continue;
432177557Semaste		if (i == 0)
433177557Semaste			count = mir->MntRespCount;
43495350Sscottl		aac_add_container(sc, mir, 0);
43583114Sscottl		i++;
436115760Sscottl	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
43765793Smsmith
43895350Sscottl	aac_release_sync_fib(sc);
439151086Sscottl	mtx_unlock(&sc->aac_io_lock);
44095350Sscottl
44183114Sscottl	/* poke the bus to actually attach the child devices */
44283114Sscottl	if (bus_generic_attach(sc->aac_dev))
44383114Sscottl		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
44465793Smsmith
44583114Sscottl	/* mark the controller up */
44683114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
44770393Smsmith
44883114Sscottl	/* enable interrupts now */
44983114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
45065793Smsmith}
45165793Smsmith
45283114Sscottl/*
453177184Semaste * Create a device to represent a new container
45483114Sscottl */
45583114Sscottlstatic void
45695350Sscottlaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
45783114Sscottl{
45883114Sscottl	struct aac_container *co;
45983114Sscottl	device_t child;
46083114Sscottl
461152388Sschweikh	/*
46283114Sscottl	 * Check container volume type for validity.  Note that many of
46383114Sscottl	 * the possible types may never show up.
46483114Sscottl	 */
46583114Sscottl	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
466110428Sscottl		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
467110428Sscottl		       M_NOWAIT | M_ZERO);
46883114Sscottl		if (co == NULL)
469177635Semaste			panic("Out of memory?!");
470177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x  name '%.16s'  size %u  type %d",
47183114Sscottl		      mir->MntTable[0].ObjectId,
47283114Sscottl		      mir->MntTable[0].FileSystemName,
47383114Sscottl		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
474152388Sschweikh
47595536Sscottl		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
47683114Sscottl			device_printf(sc->aac_dev, "device_add_child failed\n");
47783114Sscottl		else
47883114Sscottl			device_set_ivars(child, co);
47983114Sscottl		device_set_desc(child, aac_describe_code(aac_container_types,
48083114Sscottl				mir->MntTable[0].VolType));
48183114Sscottl		co->co_disk = child;
48283114Sscottl		co->co_found = f;
48383114Sscottl		bcopy(&mir->MntTable[0], &co->co_mntobj,
48483114Sscottl		      sizeof(struct aac_mntobj));
485133540Sscottl		mtx_lock(&sc->aac_container_lock);
48683114Sscottl		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
487133540Sscottl		mtx_unlock(&sc->aac_container_lock);
48883114Sscottl	}
48983114Sscottl}
49083114Sscottl
49183114Sscottl/*
492177557Semaste * Allocate resources associated with (sc)
493177557Semaste */
494177557Semastestatic int
495177557Semasteaac_alloc(struct aac_softc *sc)
496177557Semaste{
497177567Semaste
498177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
499177567Semaste
500177557Semaste	/*
501177557Semaste	 * Create DMA tag for mapping buffers into controller-addressable space.
502177557Semaste	 */
503177557Semaste	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
504177557Semaste			       1, 0, 			/* algnmnt, boundary */
505177557Semaste			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
506177557Semaste			       BUS_SPACE_MAXADDR :
507177557Semaste			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
508177557Semaste			       BUS_SPACE_MAXADDR, 	/* highaddr */
509177557Semaste			       NULL, NULL, 		/* filter, filterarg */
510177557Semaste			       MAXBSIZE,		/* maxsize */
511177557Semaste			       sc->aac_sg_tablesize,	/* nsegments */
512177557Semaste			       MAXBSIZE,		/* maxsegsize */
513177557Semaste			       BUS_DMA_ALLOCNOW,	/* flags */
514177557Semaste			       busdma_lock_mutex,	/* lockfunc */
515177557Semaste			       &sc->aac_io_lock,	/* lockfuncarg */
516177557Semaste			       &sc->aac_buffer_dmat)) {
517177557Semaste		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
518177557Semaste		return (ENOMEM);
519177557Semaste	}
520177557Semaste
521177557Semaste	/*
522177557Semaste	 * Create DMA tag for mapping FIBs into controller-addressable space..
523177557Semaste	 */
524177557Semaste	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
525177557Semaste			       1, 0, 			/* algnmnt, boundary */
526177557Semaste			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
527177557Semaste			       BUS_SPACE_MAXADDR_32BIT :
528177557Semaste			       0x7fffffff,		/* lowaddr */
529177557Semaste			       BUS_SPACE_MAXADDR, 	/* highaddr */
530177557Semaste			       NULL, NULL, 		/* filter, filterarg */
531177557Semaste			       sc->aac_max_fibs_alloc *
532177557Semaste			       sc->aac_max_fib_size,  /* maxsize */
533177557Semaste			       1,			/* nsegments */
534177557Semaste			       sc->aac_max_fibs_alloc *
535177557Semaste			       sc->aac_max_fib_size,	/* maxsize */
536177557Semaste			       0,			/* flags */
537177557Semaste			       NULL, NULL,		/* No locking needed */
538177557Semaste			       &sc->aac_fib_dmat)) {
539201758Smbr		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");
540177557Semaste		return (ENOMEM);
541177557Semaste	}
542177557Semaste
543177557Semaste	/*
544177557Semaste	 * Create DMA tag for the common structure and allocate it.
545177557Semaste	 */
546177557Semaste	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
547177557Semaste			       1, 0,			/* algnmnt, boundary */
548177557Semaste			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
549177557Semaste			       BUS_SPACE_MAXADDR_32BIT :
550177557Semaste			       0x7fffffff,		/* lowaddr */
551177557Semaste			       BUS_SPACE_MAXADDR, 	/* highaddr */
552177557Semaste			       NULL, NULL, 		/* filter, filterarg */
553177557Semaste			       8192 + sizeof(struct aac_common), /* maxsize */
554177557Semaste			       1,			/* nsegments */
555177557Semaste			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
556177557Semaste			       0,			/* flags */
557177557Semaste			       NULL, NULL,		/* No locking needed */
558177557Semaste			       &sc->aac_common_dmat)) {
559177557Semaste		device_printf(sc->aac_dev,
560177557Semaste			      "can't allocate common structure DMA tag\n");
561177557Semaste		return (ENOMEM);
562177557Semaste	}
563177557Semaste	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
564177557Semaste			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
565177557Semaste		device_printf(sc->aac_dev, "can't allocate common structure\n");
566177557Semaste		return (ENOMEM);
567177557Semaste	}
568177557Semaste
569177557Semaste	/*
570177557Semaste	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
571177557Semaste	 * below address 8192 in physical memory.
572177557Semaste	 * XXX If the padding is not needed, can it be put to use instead
573177557Semaste	 * of ignored?
574177557Semaste	 */
575177557Semaste	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
576177557Semaste			sc->aac_common, 8192 + sizeof(*sc->aac_common),
577177557Semaste			aac_common_map, sc, 0);
578177557Semaste
579177557Semaste	if (sc->aac_common_busaddr < 8192) {
580177557Semaste		sc->aac_common = (struct aac_common *)
581177557Semaste		    ((uint8_t *)sc->aac_common + 8192);
582177557Semaste		sc->aac_common_busaddr += 8192;
583177557Semaste	}
584177557Semaste	bzero(sc->aac_common, sizeof(*sc->aac_common));
585177557Semaste
586177557Semaste	/* Allocate some FIBs and associated command structs */
587177557Semaste	TAILQ_INIT(&sc->aac_fibmap_tqh);
588177557Semaste	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
589177557Semaste				  M_AACBUF, M_WAITOK|M_ZERO);
590200251Sjkim	while (sc->total_fibs < sc->aac_max_fibs) {
591177557Semaste		if (aac_alloc_commands(sc) != 0)
592177557Semaste			break;
593177557Semaste	}
594177557Semaste	if (sc->total_fibs == 0)
595177557Semaste		return (ENOMEM);
596177557Semaste
597177557Semaste	return (0);
598177557Semaste}
599177557Semaste
600177557Semaste/*
60165793Smsmith * Free all of the resources associated with (sc)
60265793Smsmith *
60365793Smsmith * Should not be called if the controller is active.
60465793Smsmith */
60565793Smsmithvoid
60665793Smsmithaac_free(struct aac_softc *sc)
60765793Smsmith{
608110604Sscottl
609177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
61065793Smsmith
61183114Sscottl	/* remove the control device */
61283114Sscottl	if (sc->aac_dev_t != NULL)
61383114Sscottl		destroy_dev(sc->aac_dev_t);
61465793Smsmith
61583114Sscottl	/* throw away any FIB buffers, discard the FIB DMA tag */
616111141Sscottl	aac_free_commands(sc);
61783114Sscottl	if (sc->aac_fib_dmat)
61883114Sscottl		bus_dma_tag_destroy(sc->aac_fib_dmat);
61965793Smsmith
620110604Sscottl	free(sc->aac_commands, M_AACBUF);
621110604Sscottl
62283114Sscottl	/* destroy the common area */
62383114Sscottl	if (sc->aac_common) {
62483114Sscottl		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
62583114Sscottl		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
62683114Sscottl				sc->aac_common_dmamap);
62783114Sscottl	}
62883114Sscottl	if (sc->aac_common_dmat)
62983114Sscottl		bus_dma_tag_destroy(sc->aac_common_dmat);
63065793Smsmith
63183114Sscottl	/* disconnect the interrupt handler */
63283114Sscottl	if (sc->aac_intr)
63383114Sscottl		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
634264939Smarius	if (sc->aac_irq != NULL) {
635251070Smarius		bus_release_resource(sc->aac_dev, SYS_RES_IRQ,
636251070Smarius		    rman_get_rid(sc->aac_irq), sc->aac_irq);
637264939Smarius		pci_release_msi(sc->aac_dev);
638264939Smarius	}
63965793Smsmith
64083114Sscottl	/* destroy data-transfer DMA tag */
64183114Sscottl	if (sc->aac_buffer_dmat)
64283114Sscottl		bus_dma_tag_destroy(sc->aac_buffer_dmat);
64365793Smsmith
64483114Sscottl	/* destroy the parent DMA tag */
64583114Sscottl	if (sc->aac_parent_dmat)
64683114Sscottl		bus_dma_tag_destroy(sc->aac_parent_dmat);
64765793Smsmith
64883114Sscottl	/* release the register window mapping */
649188896Sattilio	if (sc->aac_regs_res0 != NULL)
65083114Sscottl		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
651251070Smarius		    rman_get_rid(sc->aac_regs_res0), sc->aac_regs_res0);
652188896Sattilio	if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL)
653188896Sattilio		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
654251070Smarius		    rman_get_rid(sc->aac_regs_res1), sc->aac_regs_res1);
65565793Smsmith}
65665793Smsmith
65783114Sscottl/*
65865793Smsmith * Disconnect from the controller completely, in preparation for unload.
65965793Smsmith */
66065793Smsmithint
66165793Smsmithaac_detach(device_t dev)
66265793Smsmith{
66383114Sscottl	struct aac_softc *sc;
664110426Sscottl	struct aac_container *co;
665110426Sscottl	struct aac_sim	*sim;
66683114Sscottl	int error;
66765793Smsmith
66883114Sscottl	sc = device_get_softc(dev);
669177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
67083114Sscottl
671188896Sattilio	callout_drain(&sc->aac_daemontime);
672188896Sattilio
673222951Sattilio	mtx_lock(&sc->aac_io_lock);
674222951Sattilio	while (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
675222951Sattilio		sc->aifflags |= AAC_AIFFLAGS_EXIT;
676222951Sattilio		wakeup(sc->aifthread);
677222951Sattilio		msleep(sc->aac_dev, &sc->aac_io_lock, PUSER, "aacdch", 0);
678222951Sattilio	}
679222951Sattilio	mtx_unlock(&sc->aac_io_lock);
680222951Sattilio	KASSERT((sc->aifflags & AAC_AIFFLAGS_RUNNING) == 0,
681222951Sattilio	    ("%s: invalid detach state", __func__));
682222951Sattilio
683110426Sscottl	/* Remove the child containers */
684110428Sscottl	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
685110426Sscottl		error = device_delete_child(dev, co->co_disk);
686110426Sscottl		if (error)
687110426Sscottl			return (error);
688111196Sscottl		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
689110428Sscottl		free(co, M_AACBUF);
690110426Sscottl	}
691110426Sscottl
692110426Sscottl	/* Remove the CAM SIMs */
693110428Sscottl	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
694110428Sscottl		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
695110426Sscottl		error = device_delete_child(dev, sim->sim_dev);
696110426Sscottl		if (error)
697110426Sscottl			return (error);
698110428Sscottl		free(sim, M_AACBUF);
699110426Sscottl	}
700110426Sscottl
70183114Sscottl	if ((error = aac_shutdown(dev)))
70283114Sscottl		return(error);
70365793Smsmith
704110427Sscottl	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
705110427Sscottl
70683114Sscottl	aac_free(sc);
70765793Smsmith
708133542Sscottl	mtx_destroy(&sc->aac_aifq_lock);
709133542Sscottl	mtx_destroy(&sc->aac_io_lock);
710133542Sscottl	mtx_destroy(&sc->aac_container_lock);
711133542Sscottl
71283114Sscottl	return(0);
71365793Smsmith}
71465793Smsmith
71583114Sscottl/*
71665793Smsmith * Bring the controller down to a dormant state and detach all child devices.
71765793Smsmith *
71865793Smsmith * This function is called before detach or system shutdown.
71965793Smsmith *
72070393Smsmith * Note that we can assume that the bioq on the controller is empty, as we won't
72165793Smsmith * allow shutdown if any device is open.
72265793Smsmith */
72365793Smsmithint
72465793Smsmithaac_shutdown(device_t dev)
72565793Smsmith{
72683114Sscottl	struct aac_softc *sc;
72795350Sscottl	struct aac_fib *fib;
72895350Sscottl	struct aac_close_command *cc;
72965793Smsmith
73083114Sscottl	sc = device_get_softc(dev);
731177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
73265793Smsmith
73383114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
73465793Smsmith
735152388Sschweikh	/*
73683114Sscottl	 * Send a Container shutdown followed by a HostShutdown FIB to the
73783114Sscottl	 * controller to convince it that we don't want to talk to it anymore.
73883114Sscottl	 * We've been closed and all I/O completed already
73982527Sscottl	 */
74083114Sscottl	device_printf(sc->aac_dev, "shutting down controller...");
74183114Sscottl
742151086Sscottl	mtx_lock(&sc->aac_io_lock);
743130006Sscottl	aac_alloc_sync_fib(sc, &fib);
74495350Sscottl	cc = (struct aac_close_command *)&fib->data[0];
74595350Sscottl
74695966Sscottl	bzero(cc, sizeof(struct aac_close_command));
74795350Sscottl	cc->Command = VM_CloseAll;
74895350Sscottl	cc->ContainerId = 0xffffffff;
74995350Sscottl	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
75095350Sscottl	    sizeof(struct aac_close_command)))
75183114Sscottl		printf("FAILED.\n");
752110426Sscottl	else
753110426Sscottl		printf("done\n");
754110426Sscottl#if 0
75583114Sscottl	else {
75695350Sscottl		fib->data[0] = 0;
75783114Sscottl		/*
75883114Sscottl		 * XXX Issuing this command to the controller makes it shut down
75983114Sscottl		 * but also keeps it from coming back up without a reset of the
76083114Sscottl		 * PCI bus.  This is not desirable if you are just unloading the
76183114Sscottl		 * driver module with the intent to reload it later.
76283114Sscottl		 */
76395350Sscottl		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
76495350Sscottl		    fib, 1)) {
76583114Sscottl			printf("FAILED.\n");
76683114Sscottl		} else {
76783114Sscottl			printf("done.\n");
76883114Sscottl		}
76965793Smsmith	}
770110426Sscottl#endif
77165793Smsmith
77283114Sscottl	AAC_MASK_INTERRUPTS(sc);
773133539Sscottl	aac_release_sync_fib(sc);
774151086Sscottl	mtx_unlock(&sc->aac_io_lock);
77565793Smsmith
77683114Sscottl	return(0);
77765793Smsmith}
77865793Smsmith
77983114Sscottl/*
78065793Smsmith * Bring the controller to a quiescent state, ready for system suspend.
78165793Smsmith */
78265793Smsmithint
78365793Smsmithaac_suspend(device_t dev)
78465793Smsmith{
78583114Sscottl	struct aac_softc *sc;
78665793Smsmith
78783114Sscottl	sc = device_get_softc(dev);
78883114Sscottl
789177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
79083114Sscottl	sc->aac_state |= AAC_STATE_SUSPEND;
791152388Sschweikh
79283114Sscottl	AAC_MASK_INTERRUPTS(sc);
79383114Sscottl	return(0);
79465793Smsmith}
79565793Smsmith
79683114Sscottl/*
79765793Smsmith * Bring the controller back to a state ready for operation.
79865793Smsmith */
79965793Smsmithint
80065793Smsmithaac_resume(device_t dev)
80165793Smsmith{
80283114Sscottl	struct aac_softc *sc;
80365793Smsmith
80483114Sscottl	sc = device_get_softc(dev);
80583114Sscottl
806177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
80783114Sscottl	sc->aac_state &= ~AAC_STATE_SUSPEND;
80883114Sscottl	AAC_UNMASK_INTERRUPTS(sc);
80983114Sscottl	return(0);
81065793Smsmith}
81165793Smsmith
81283114Sscottl/*
813151086Sscottl * Interrupt handler for NEW_COMM interface.
81465793Smsmith */
81565793Smsmithvoid
816151086Sscottlaac_new_intr(void *arg)
81765793Smsmith{
81883114Sscottl	struct aac_softc *sc;
819151086Sscottl	u_int32_t index, fast;
820151086Sscottl	struct aac_command *cm;
821151086Sscottl	struct aac_fib *fib;
822151086Sscottl	int i;
823151086Sscottl
824151086Sscottl	sc = (struct aac_softc *)arg;
825151086Sscottl
826177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
827151086Sscottl	mtx_lock(&sc->aac_io_lock);
828151086Sscottl	while (1) {
829151086Sscottl		index = AAC_GET_OUTB_QUEUE(sc);
830151086Sscottl		if (index == 0xffffffff)
831151086Sscottl			index = AAC_GET_OUTB_QUEUE(sc);
832151086Sscottl		if (index == 0xffffffff)
833151086Sscottl			break;
834151086Sscottl		if (index & 2) {
835151086Sscottl			if (index == 0xfffffffe) {
836151086Sscottl				/* XXX This means that the controller wants
837151086Sscottl				 * more work.  Ignore it for now.
838151086Sscottl				 */
839151086Sscottl				continue;
840151086Sscottl			}
841151086Sscottl			/* AIF */
842151086Sscottl			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
843151086Sscottl				   M_NOWAIT | M_ZERO);
844151086Sscottl			if (fib == NULL) {
845151086Sscottl				/* If we're really this short on memory,
846151086Sscottl				 * hopefully breaking out of the handler will
847151086Sscottl				 * allow something to get freed.  This
848151086Sscottl				 * actually sucks a whole lot.
849151086Sscottl				 */
850151086Sscottl				break;
851151086Sscottl			}
852151086Sscottl			index &= ~2;
853151086Sscottl			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
854188896Sattilio				((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4);
855151086Sscottl			aac_handle_aif(sc, fib);
856151086Sscottl			free(fib, M_AACBUF);
857151086Sscottl
858151086Sscottl			/*
859151086Sscottl			 * AIF memory is owned by the adapter, so let it
860151086Sscottl			 * know that we are done with it.
861151086Sscottl			 */
862151086Sscottl			AAC_SET_OUTB_QUEUE(sc, index);
863151086Sscottl			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
864151086Sscottl		} else {
865151086Sscottl			fast = index & 1;
866151086Sscottl			cm = sc->aac_commands + (index >> 2);
867151086Sscottl			fib = cm->cm_fib;
868151086Sscottl			if (fast) {
869151086Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
870151086Sscottl				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
871151086Sscottl			}
872151086Sscottl			aac_remove_busy(cm);
873151086Sscottl 			aac_unmap_command(cm);
874151086Sscottl			cm->cm_flags |= AAC_CMD_COMPLETED;
875151086Sscottl
876151086Sscottl			/* is there a completion handler? */
877151086Sscottl			if (cm->cm_complete != NULL) {
878151086Sscottl				cm->cm_complete(cm);
879151086Sscottl			} else {
880151086Sscottl				/* assume that someone is sleeping on this
881151086Sscottl				 * command
882151086Sscottl				 */
883151086Sscottl				wakeup(cm);
884151086Sscottl			}
885151086Sscottl			sc->flags &= ~AAC_QUEUE_FRZN;
886151086Sscottl		}
887151086Sscottl	}
888151086Sscottl	/* see if we can start some more I/O */
889151086Sscottl	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
890151086Sscottl		aac_startio(sc);
891151086Sscottl
892151086Sscottl	mtx_unlock(&sc->aac_io_lock);
893151086Sscottl}
894151086Sscottl
895198593Semaste/*
896198593Semaste * Interrupt filter for !NEW_COMM interface.
897198593Semaste */
898166901Spisoint
899198593Semasteaac_filter(void *arg)
900151086Sscottl{
901151086Sscottl	struct aac_softc *sc;
90283114Sscottl	u_int16_t reason;
90365793Smsmith
90483114Sscottl	sc = (struct aac_softc *)arg;
90565793Smsmith
906177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
907109088Sscottl	/*
908125225Sscottl	 * Read the status register directly.  This is faster than taking the
909125225Sscottl	 * driver lock and reading the queues directly.  It also saves having
910125225Sscottl	 * to turn parts of the driver lock into a spin mutex, which would be
911125225Sscottl	 * ugly.
912109088Sscottl	 */
913125225Sscottl	reason = AAC_GET_ISTATUS(sc);
914109088Sscottl	AAC_CLEAR_ISTATUS(sc, reason);
91565793Smsmith
916125225Sscottl	/* handle completion processing */
917109088Sscottl	if (reason & AAC_DB_RESPONSE_READY)
918125225Sscottl		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
919109088Sscottl
920125225Sscottl	/* controller wants to talk to us */
921125225Sscottl	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
922125225Sscottl		/*
923125225Sscottl		 * XXX Make sure that we don't get fooled by strange messages
924125225Sscottl		 * that start with a NULL.
925125225Sscottl		 */
926125225Sscottl		if ((reason & AAC_DB_PRINTF) &&
927151086Sscottl			(sc->aac_common->ac_printf[0] == 0))
928125225Sscottl			sc->aac_common->ac_printf[0] = 32;
92965793Smsmith
930125225Sscottl		/*
931125225Sscottl		 * This might miss doing the actual wakeup.  However, the
932125542Sscottl		 * msleep that this is waking up has a timeout, so it will
933125225Sscottl		 * wake up eventually.  AIFs and printfs are low enough
934125225Sscottl		 * priority that they can handle hanging out for a few seconds
935125225Sscottl		 * if needed.
936125225Sscottl		 */
937125225Sscottl		wakeup(sc->aifthread);
93883114Sscottl	}
939166901Spiso	return (FILTER_HANDLED);
940109088Sscottl}
94183114Sscottl
94283114Sscottl/*
94383114Sscottl * Command Processing
94483114Sscottl */
94565793Smsmith
94683114Sscottl/*
94765793Smsmith * Start as much queued I/O as possible on the controller
94865793Smsmith */
94995536Sscottlvoid
95065793Smsmithaac_startio(struct aac_softc *sc)
95165793Smsmith{
95283114Sscottl	struct aac_command *cm;
953129923Sscottl	int error;
95465793Smsmith
955177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
95665793Smsmith
95783114Sscottl	for (;;) {
95883114Sscottl		/*
959129923Sscottl		 * This flag might be set if the card is out of resources.
960129923Sscottl		 * Checking it here prevents an infinite loop of deferrals.
961129923Sscottl		 */
962129923Sscottl		if (sc->flags & AAC_QUEUE_FRZN)
963129923Sscottl			break;
964129923Sscottl
965129923Sscottl		/*
966152388Sschweikh		 * Try to get a command that's been put off for lack of
96783114Sscottl		 * resources
96883114Sscottl		 */
96983114Sscottl		cm = aac_dequeue_ready(sc);
97065793Smsmith
97183114Sscottl		/*
972152388Sschweikh		 * Try to build a command off the bio queue (ignore error
97383114Sscottl		 * return)
97483114Sscottl		 */
97583114Sscottl		if (cm == NULL)
97683114Sscottl			aac_bio_command(sc, &cm);
97765793Smsmith
97883114Sscottl		/* nothing to do? */
97983114Sscottl		if (cm == NULL)
98083114Sscottl			break;
98165793Smsmith
982129923Sscottl		/* don't map more than once */
983129923Sscottl		if (cm->cm_flags & AAC_CMD_MAPPED)
984129923Sscottl			panic("aac: command %p already mapped", cm);
985129923Sscottl
986125559Sscottl		/*
987129923Sscottl		 * Set up the command to go to the controller.  If there are no
988129923Sscottl		 * data buffers associated with the command then it can bypass
989129923Sscottl		 * busdma.
990125559Sscottl		 */
991129923Sscottl		if (cm->cm_datalen != 0) {
992251941Smarius			if (cm->cm_flags & AAC_REQ_BIO)
993251941Smarius				error = bus_dmamap_load_bio(
994251941Smarius				    sc->aac_buffer_dmat, cm->cm_datamap,
995251941Smarius				    (struct bio *)cm->cm_private,
996251941Smarius				    aac_map_command_sg, cm, 0);
997251941Smarius			else
998251941Smarius				error = bus_dmamap_load(sc->aac_buffer_dmat,
999251941Smarius				    cm->cm_datamap, cm->cm_data,
1000251941Smarius				    cm->cm_datalen, aac_map_command_sg, cm, 0);
1001129923Sscottl			if (error == EINPROGRESS) {
1002177567Semaste				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
1003129923Sscottl				sc->flags |= AAC_QUEUE_FRZN;
1004129946Sscottl			} else if (error != 0)
1005129923Sscottl				panic("aac_startio: unexpected error %d from "
1006177635Semaste				      "busdma", error);
1007129923Sscottl		} else
1008129923Sscottl			aac_map_command_sg(cm, NULL, 0, 0);
100965793Smsmith	}
101065793Smsmith}
101165793Smsmith
101283114Sscottl/*
101365793Smsmith * Handle notification of one or more FIBs coming from the controller.
101465793Smsmith */
101565793Smsmithstatic void
1016110426Sscottlaac_command_thread(struct aac_softc *sc)
101765793Smsmith{
101883114Sscottl	struct aac_fib *fib;
101983114Sscottl	u_int32_t fib_size;
1020125225Sscottl	int size, retval;
102165793Smsmith
1022177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
102365793Smsmith
1024133540Sscottl	mtx_lock(&sc->aac_io_lock);
1025125542Sscottl	sc->aifflags = AAC_AIFFLAGS_RUNNING;
102665793Smsmith
1027125542Sscottl	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
102882527Sscottl
1029125542Sscottl		retval = 0;
1030125542Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1031125542Sscottl			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1032125542Sscottl					"aifthd", AAC_PERIODIC_INTERVAL * hz);
1033125542Sscottl
1034125225Sscottl		/*
1035125225Sscottl		 * First see if any FIBs need to be allocated.  This needs
1036125225Sscottl		 * to be called without the driver lock because contigmalloc
1037222951Sattilio		 * can sleep.
1038125225Sscottl		 */
1039125225Sscottl		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1040133540Sscottl			mtx_unlock(&sc->aac_io_lock);
1041125225Sscottl			aac_alloc_commands(sc);
1042133540Sscottl			mtx_lock(&sc->aac_io_lock);
1043125559Sscottl			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1044125542Sscottl			aac_startio(sc);
1045125225Sscottl		}
1046125225Sscottl
1047125225Sscottl		/*
1048125225Sscottl		 * While we're here, check to see if any commands are stuck.
1049125225Sscottl		 * This is pretty low-priority, so it's ok if it doesn't
1050125225Sscottl		 * always fire.
1051125225Sscottl		 */
1052125225Sscottl		if (retval == EWOULDBLOCK)
1053110426Sscottl			aac_timeout(sc);
1054110426Sscottl
1055110426Sscottl		/* Check the hardware printf message buffer */
1056125225Sscottl		if (sc->aac_common->ac_printf[0] != 0)
1057110426Sscottl			aac_print_printf(sc);
1058110426Sscottl
1059125225Sscottl		/* Also check to see if the adapter has a command for us. */
1060151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
1061151086Sscottl			continue;
1062151086Sscottl		for (;;) {
1063151086Sscottl			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
1064152388Sschweikh					   &fib_size, &fib))
1065151086Sscottl				break;
1066152388Sschweikh
106783114Sscottl			AAC_PRINT_FIB(sc, fib);
1068152388Sschweikh
106983114Sscottl			switch (fib->Header.Command) {
107083114Sscottl			case AifRequest:
107183114Sscottl				aac_handle_aif(sc, fib);
107283114Sscottl				break;
107383114Sscottl			default:
107483114Sscottl				device_printf(sc->aac_dev, "unknown command "
107583114Sscottl					      "from controller\n");
107683114Sscottl				break;
107783114Sscottl			}
107882527Sscottl
107983114Sscottl			if ((fib->Header.XferState == 0) ||
1080151086Sscottl			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
108183114Sscottl				break;
1082151086Sscottl			}
108382527Sscottl
1084110426Sscottl			/* Return the AIF to the controller. */
108583114Sscottl			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
108683114Sscottl				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
108783114Sscottl				*(AAC_FSAStatus*)fib->data = ST_OK;
108882527Sscottl
108983114Sscottl				/* XXX Compute the Size field? */
109083114Sscottl				size = fib->Header.Size;
109183114Sscottl				if (size > sizeof(struct aac_fib)) {
109295536Sscottl					size = sizeof(struct aac_fib);
109383114Sscottl					fib->Header.Size = size;
109483114Sscottl				}
109583114Sscottl				/*
109683114Sscottl				 * Since we did not generate this command, it
109783114Sscottl				 * cannot go through the normal
109883114Sscottl				 * enqueue->startio chain.
109983114Sscottl				 */
110083114Sscottl				aac_enqueue_response(sc,
1101151086Sscottl						 AAC_ADAP_NORM_RESP_QUEUE,
1102151086Sscottl						 fib);
110383114Sscottl			}
110482527Sscottl		}
110565793Smsmith	}
110683114Sscottl	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1107133540Sscottl	mtx_unlock(&sc->aac_io_lock);
110883114Sscottl	wakeup(sc->aac_dev);
110965793Smsmith
1110172836Sjulian	kproc_exit(0);
111165793Smsmith}
111265793Smsmith
111383114Sscottl/*
1114111143Sscottl * Process completed commands.
111565793Smsmith */
111665793Smsmithstatic void
1117111143Sscottlaac_complete(void *context, int pending)
111865793Smsmith{
1119111143Sscottl	struct aac_softc *sc;
112083114Sscottl	struct aac_command *cm;
112183114Sscottl	struct aac_fib *fib;
112283114Sscottl	u_int32_t fib_size;
112365793Smsmith
1124111143Sscottl	sc = (struct aac_softc *)context;
1125177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1126111143Sscottl
1127133540Sscottl	mtx_lock(&sc->aac_io_lock);
1128111532Sscottl
1129111143Sscottl	/* pull completed commands off the queue */
113083114Sscottl	for (;;) {
113183114Sscottl		/* look for completed FIBs on our queue */
113283114Sscottl		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1133151086Sscottl							&fib))
113483114Sscottl			break;	/* nothing to do */
1135111143Sscottl
1136125574Sscottl		/* get the command, unmap and hand off for processing */
1137111152Sscottl		cm = sc->aac_commands + fib->Header.SenderData;
113883114Sscottl		if (cm == NULL) {
113983114Sscottl			AAC_PRINT_FIB(sc, fib);
1140111143Sscottl			break;
114183114Sscottl		}
1142212594Semaste		if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0)
1143212594Semaste			device_printf(sc->aac_dev,
1144212594Semaste			    "COMMAND %p COMPLETED AFTER %d SECONDS\n",
1145212594Semaste			    cm, (int)(time_uptime-cm->cm_timestamp));
1146212594Semaste
1147151086Sscottl		aac_remove_busy(cm);
114865793Smsmith
1149151086Sscottl 		aac_unmap_command(cm);
115083114Sscottl		cm->cm_flags |= AAC_CMD_COMPLETED;
115183114Sscottl
115283114Sscottl		/* is there a completion handler? */
115383114Sscottl		if (cm->cm_complete != NULL) {
115483114Sscottl			cm->cm_complete(cm);
115583114Sscottl		} else {
115683114Sscottl			/* assume that someone is sleeping on this command */
115783114Sscottl			wakeup(cm);
115883114Sscottl		}
115965793Smsmith	}
116070393Smsmith
116183114Sscottl	/* see if we can start some more I/O */
1162117363Sscottl	sc->flags &= ~AAC_QUEUE_FRZN;
116383114Sscottl	aac_startio(sc);
1164111532Sscottl
1165133540Sscottl	mtx_unlock(&sc->aac_io_lock);
116665793Smsmith}
116765793Smsmith
116883114Sscottl/*
116965793Smsmith * Handle a bio submitted from a disk device.
117065793Smsmith */
117165793Smsmithvoid
117265793Smsmithaac_submit_bio(struct bio *bp)
117365793Smsmith{
117483114Sscottl	struct aac_disk *ad;
117583114Sscottl	struct aac_softc *sc;
117665793Smsmith
1177111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
117883114Sscottl	sc = ad->ad_controller;
1179177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
118083114Sscottl
118183114Sscottl	/* queue the BIO and try to get some work done */
118283114Sscottl	aac_enqueue_bio(sc, bp);
118383114Sscottl	aac_startio(sc);
118465793Smsmith}
118565793Smsmith
118683114Sscottl/*
118765793Smsmith * Get a bio and build a command to go with it.
118865793Smsmith */
118965793Smsmithstatic int
119065793Smsmithaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
119165793Smsmith{
119283114Sscottl	struct aac_command *cm;
119383114Sscottl	struct aac_fib *fib;
119483114Sscottl	struct aac_disk *ad;
119583114Sscottl	struct bio *bp;
119665793Smsmith
1197177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
119865793Smsmith
119983114Sscottl	/* get the resources we will need */
120083114Sscottl	cm = NULL;
1201125542Sscottl	bp = NULL;
1202125542Sscottl	if (aac_alloc_command(sc, &cm))	/* get a command */
1203125542Sscottl		goto fail;
120483114Sscottl	if ((bp = aac_dequeue_bio(sc)) == NULL)
120583114Sscottl		goto fail;
120665793Smsmith
120783114Sscottl	/* fill out the command */
120883114Sscottl	cm->cm_datalen = bp->bio_bcount;
120983114Sscottl	cm->cm_complete = aac_bio_complete;
1210251941Smarius	cm->cm_flags = AAC_REQ_BIO;
121183114Sscottl	cm->cm_private = bp;
1212150119Sscottl	cm->cm_timestamp = time_uptime;
121365793Smsmith
121483114Sscottl	/* build the FIB */
121583114Sscottl	fib = cm->cm_fib;
1216112856Sscottl	fib->Header.Size = sizeof(struct aac_fib_header);
1217152388Sschweikh	fib->Header.XferState =
1218152388Sschweikh		AAC_FIBSTATE_HOSTOWNED   |
1219152388Sschweikh		AAC_FIBSTATE_INITIALISED |
1220152388Sschweikh		AAC_FIBSTATE_EMPTY	 |
1221109088Sscottl		AAC_FIBSTATE_FROMHOST	 |
1222109088Sscottl		AAC_FIBSTATE_REXPECTED   |
1223109088Sscottl		AAC_FIBSTATE_NORM	 |
1224109088Sscottl		AAC_FIBSTATE_ASYNC	 |
1225109088Sscottl		AAC_FIBSTATE_FAST_RESPONSE;
122665793Smsmith
122783114Sscottl	/* build the read/write request */
1228111525Sscottl	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1229112856Sscottl
1230151086Sscottl	if (sc->flags & AAC_FLAGS_RAW_IO) {
1231151086Sscottl		struct aac_raw_io *raw;
1232151086Sscottl		raw = (struct aac_raw_io *)&fib->data[0];
1233151086Sscottl		fib->Header.Command = RawIo;
1234151086Sscottl		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
1235151086Sscottl		raw->ByteCount = bp->bio_bcount;
1236151086Sscottl		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1237151086Sscottl		raw->BpTotal = 0;
1238151086Sscottl		raw->BpComplete = 0;
1239151086Sscottl		fib->Header.Size += sizeof(struct aac_raw_io);
1240151086Sscottl		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
1241151086Sscottl		if (bp->bio_cmd == BIO_READ) {
1242151086Sscottl			raw->Flags = 1;
1243151086Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1244151086Sscottl		} else {
1245151086Sscottl			raw->Flags = 0;
1246151086Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1247151086Sscottl		}
1248151086Sscottl	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1249112856Sscottl		fib->Header.Command = ContainerCommand;
1250112856Sscottl		if (bp->bio_cmd == BIO_READ) {
1251112856Sscottl			struct aac_blockread *br;
1252112856Sscottl			br = (struct aac_blockread *)&fib->data[0];
1253112856Sscottl			br->Command = VM_CtBlockRead;
1254112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1255112856Sscottl			br->BlockNumber = bp->bio_pblkno;
1256112856Sscottl			br->ByteCount = bp->bio_bcount;
1257112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread);
1258112856Sscottl			cm->cm_sgtable = &br->SgMap;
1259112856Sscottl			cm->cm_flags |= AAC_CMD_DATAIN;
1260112856Sscottl		} else {
1261112856Sscottl			struct aac_blockwrite *bw;
1262112856Sscottl			bw = (struct aac_blockwrite *)&fib->data[0];
1263112856Sscottl			bw->Command = VM_CtBlockWrite;
1264112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1265112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
1266112856Sscottl			bw->ByteCount = bp->bio_bcount;
1267112856Sscottl			bw->Stable = CUNSTABLE;
1268112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite);
1269112856Sscottl			cm->cm_flags |= AAC_CMD_DATAOUT;
1270112856Sscottl			cm->cm_sgtable = &bw->SgMap;
1271112856Sscottl		}
127283114Sscottl	} else {
1273112856Sscottl		fib->Header.Command = ContainerCommand64;
1274112856Sscottl		if (bp->bio_cmd == BIO_READ) {
1275112856Sscottl			struct aac_blockread64 *br;
1276112856Sscottl			br = (struct aac_blockread64 *)&fib->data[0];
1277112856Sscottl			br->Command = VM_CtHostRead64;
1278112856Sscottl			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1279112856Sscottl			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1280112856Sscottl			br->BlockNumber = bp->bio_pblkno;
1281112856Sscottl			br->Pad = 0;
1282112856Sscottl			br->Flags = 0;
1283112856Sscottl			fib->Header.Size += sizeof(struct aac_blockread64);
1284177611Semaste			cm->cm_flags |= AAC_CMD_DATAIN;
1285132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1286112856Sscottl		} else {
1287112856Sscottl			struct aac_blockwrite64 *bw;
1288112856Sscottl			bw = (struct aac_blockwrite64 *)&fib->data[0];
1289112856Sscottl			bw->Command = VM_CtHostWrite64;
1290112856Sscottl			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1291112856Sscottl			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1292112856Sscottl			bw->BlockNumber = bp->bio_pblkno;
1293112856Sscottl			bw->Pad = 0;
1294112856Sscottl			bw->Flags = 0;
1295112856Sscottl			fib->Header.Size += sizeof(struct aac_blockwrite64);
1296177611Semaste			cm->cm_flags |= AAC_CMD_DATAOUT;
1297132771Skan			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1298112856Sscottl		}
129983114Sscottl	}
130065793Smsmith
130183114Sscottl	*cmp = cm;
130283114Sscottl	return(0);
130365793Smsmith
130465793Smsmithfail:
1305151086Sscottl	if (bp != NULL)
1306151086Sscottl		aac_enqueue_bio(sc, bp);
130783114Sscottl	if (cm != NULL)
130883114Sscottl		aac_release_command(cm);
130983114Sscottl	return(ENOMEM);
131065793Smsmith}
131165793Smsmith
131283114Sscottl/*
131365793Smsmith * Handle a bio-instigated command that has been completed.
131465793Smsmith */
131565793Smsmithstatic void
131665793Smsmithaac_bio_complete(struct aac_command *cm)
131765793Smsmith{
131883114Sscottl	struct aac_blockread_response *brr;
131983114Sscottl	struct aac_blockwrite_response *bwr;
132083114Sscottl	struct bio *bp;
132183114Sscottl	AAC_FSAStatus status;
132265793Smsmith
132383114Sscottl	/* fetch relevant status and then release the command */
132483114Sscottl	bp = (struct bio *)cm->cm_private;
1325111691Sscottl	if (bp->bio_cmd == BIO_READ) {
132683114Sscottl		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
132783114Sscottl		status = brr->Status;
132883114Sscottl	} else {
132983114Sscottl		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
133083114Sscottl		status = bwr->Status;
133183114Sscottl	}
133283114Sscottl	aac_release_command(cm);
133365793Smsmith
133483114Sscottl	/* fix up the bio based on status */
133583114Sscottl	if (status == ST_OK) {
133683114Sscottl		bp->bio_resid = 0;
133783114Sscottl	} else {
133883114Sscottl		bp->bio_error = EIO;
133983114Sscottl		bp->bio_flags |= BIO_ERROR;
134083114Sscottl	}
134183114Sscottl	aac_biodone(bp);
134265793Smsmith}
134365793Smsmith
134483114Sscottl/*
134565793Smsmith * Submit a command to the controller, return when it completes.
134687183Sscottl * XXX This is very dangerous!  If the card has gone out to lunch, we could
134787183Sscottl *     be stuck here forever.  At the same time, signals are not caught
1348128258Sscottl *     because there is a risk that a signal could wakeup the sleep before
1349128258Sscottl *     the card has a chance to complete the command.  Since there is no way
1350128258Sscottl *     to cancel a command that is in progress, we can't protect against the
1351128258Sscottl *     card completing a command late and spamming the command and data
1352128258Sscottl *     memory.  So, we are held hostage until the command completes.
135365793Smsmith */
135465793Smsmithstatic int
1355128258Sscottlaac_wait_command(struct aac_command *cm)
135665793Smsmith{
1357111532Sscottl	struct aac_softc *sc;
1358128258Sscottl	int error;
135965793Smsmith
1360111532Sscottl	sc = cm->cm_sc;
1361177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1362111532Sscottl
136383114Sscottl	/* Put the command on the ready queue and get things going */
136483114Sscottl	aac_enqueue_ready(cm);
1365111532Sscottl	aac_startio(sc);
1366128258Sscottl	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
136783114Sscottl	return(error);
136865793Smsmith}
136965793Smsmith
137083114Sscottl/*
137183114Sscottl *Command Buffer Management
137283114Sscottl */
137365793Smsmith
137483114Sscottl/*
137565793Smsmith * Allocate a command.
137665793Smsmith */
137795536Sscottlint
137865793Smsmithaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
137965793Smsmith{
138083114Sscottl	struct aac_command *cm;
138165793Smsmith
1382177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
138365793Smsmith
1384110604Sscottl	if ((cm = aac_dequeue_free(sc)) == NULL) {
1385112856Sscottl		if (sc->total_fibs < sc->aac_max_fibs) {
1386222951Sattilio			mtx_lock(&sc->aac_io_lock);
1387112856Sscottl			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1388222951Sattilio			mtx_unlock(&sc->aac_io_lock);
1389112856Sscottl			wakeup(sc->aifthread);
1390112856Sscottl		}
1391111532Sscottl		return (EBUSY);
1392110604Sscottl	}
139365793Smsmith
139483114Sscottl	*cmp = cm;
139583114Sscottl	return(0);
139670393Smsmith}
139770393Smsmith
139883114Sscottl/*
139970393Smsmith * Release a command back to the freelist.
140070393Smsmith */
140195536Sscottlvoid
140270393Smsmithaac_release_command(struct aac_command *cm)
140370393Smsmith{
1404151086Sscottl	struct aac_event *event;
1405151086Sscottl	struct aac_softc *sc;
1406151086Sscottl
1407177567Semaste	sc = cm->cm_sc;
1408177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
140970393Smsmith
1410177184Semaste	/* (re)initialize the command/FIB */
1411267076Sjhb	cm->cm_datalen = 0;
141283114Sscottl	cm->cm_sgtable = NULL;
141383114Sscottl	cm->cm_flags = 0;
141483114Sscottl	cm->cm_complete = NULL;
141583114Sscottl	cm->cm_private = NULL;
1416204264Semaste	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
141783114Sscottl	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
141883114Sscottl	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
141983114Sscottl	cm->cm_fib->Header.Flags = 0;
1420151086Sscottl	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
142165793Smsmith
1422152388Sschweikh	/*
142383114Sscottl	 * These are duplicated in aac_start to cover the case where an
142483114Sscottl	 * intermediate stage may have destroyed them.  They're left
1425177184Semaste	 * initialized here for debugging purposes only.
142683114Sscottl	 */
1427109088Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1428109088Sscottl	cm->cm_fib->Header.SenderData = 0;
142965793Smsmith
143083114Sscottl	aac_enqueue_free(cm);
1431151086Sscottl
1432218207Semaste	if ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
1433151086Sscottl		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
1434151086Sscottl		event->ev_callback(sc, event, event->ev_arg);
1435151086Sscottl	}
143665793Smsmith}
143765793Smsmith
143883114Sscottl/*
143970393Smsmith * Map helper for command/FIB allocation.
144065793Smsmith */
144165793Smsmithstatic void
144270393Smsmithaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
144365793Smsmith{
1444151086Sscottl	uint64_t	*fibphys;
144565793Smsmith
1446151086Sscottl	fibphys = (uint64_t *)arg;
144765793Smsmith
1448110604Sscottl	*fibphys = segs[0].ds_addr;
144965793Smsmith}
145065793Smsmith
145183114Sscottl/*
1452177184Semaste * Allocate and initialize commands/FIBs for this adapter.
145365793Smsmith */
145470393Smsmithstatic int
145570393Smsmithaac_alloc_commands(struct aac_softc *sc)
145665793Smsmith{
145783114Sscottl	struct aac_command *cm;
1458110604Sscottl	struct aac_fibmap *fm;
1459151086Sscottl	uint64_t fibphys;
1460110604Sscottl	int i, error;
1461152388Sschweikh
1462177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
146365793Smsmith
1464151086Sscottl	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1465110604Sscottl		return (ENOMEM);
1466110604Sscottl
1467111141Sscottl	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1468112679Sscottl	if (fm == NULL)
1469112679Sscottl		return (ENOMEM);
1470110604Sscottl
147183114Sscottl	/* allocate the FIBs in DMAable memory and load them */
1472110604Sscottl	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1473110604Sscottl			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1474110426Sscottl		device_printf(sc->aac_dev,
1475110426Sscottl			      "Not enough contiguous memory available.\n");
1476111141Sscottl		free(fm, M_AACBUF);
1477102602Sscottl		return (ENOMEM);
147883114Sscottl	}
1479109716Sscottl
1480117363Sscottl	/* Ignore errors since this doesn't bounce */
1481152388Sschweikh	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1482151086Sscottl			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1483117363Sscottl			      aac_map_command_helper, &fibphys, 0);
1484109716Sscottl
1485177184Semaste	/* initialize constant fields in the command structure */
1486151086Sscottl	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
1487151086Sscottl	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
1488111141Sscottl		cm = sc->aac_commands + sc->total_fibs;
1489110604Sscottl		fm->aac_commands = cm;
149083114Sscottl		cm->cm_sc = sc;
1491151086Sscottl		cm->cm_fib = (struct aac_fib *)
1492151086Sscottl			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
1493151086Sscottl		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1494111152Sscottl		cm->cm_index = sc->total_fibs;
149565793Smsmith
1496110604Sscottl		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1497157587Sscottl					       &cm->cm_datamap)) != 0)
1498111141Sscottl			break;
1499157587Sscottl		mtx_lock(&sc->aac_io_lock);
1500157587Sscottl		aac_release_command(cm);
1501111141Sscottl		sc->total_fibs++;
1502157587Sscottl		mtx_unlock(&sc->aac_io_lock);
150383114Sscottl	}
1504110604Sscottl
1505111141Sscottl	if (i > 0) {
1506157587Sscottl		mtx_lock(&sc->aac_io_lock);
1507111141Sscottl		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1508177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1509133540Sscottl		mtx_unlock(&sc->aac_io_lock);
1510111141Sscottl		return (0);
1511152388Sschweikh	}
1512110604Sscottl
1513111141Sscottl	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1514111141Sscottl	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1515111141Sscottl	free(fm, M_AACBUF);
1516111141Sscottl	return (ENOMEM);
151765793Smsmith}
151865793Smsmith
151983114Sscottl/*
152070393Smsmith * Free FIBs owned by this adapter.
152165793Smsmith */
152265793Smsmithstatic void
1523111141Sscottlaac_free_commands(struct aac_softc *sc)
152465793Smsmith{
1525111141Sscottl	struct aac_fibmap *fm;
1526110604Sscottl	struct aac_command *cm;
152783114Sscottl	int i;
152865793Smsmith
1529177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
153065793Smsmith
1531111141Sscottl	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1532111141Sscottl
1533111141Sscottl		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1534111141Sscottl		/*
1535111141Sscottl		 * We check against total_fibs to handle partially
1536111141Sscottl		 * allocated blocks.
1537111141Sscottl		 */
1538151086Sscottl		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1539111141Sscottl			cm = fm->aac_commands + i;
1540111141Sscottl			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1541111141Sscottl		}
1542111141Sscottl		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1543111141Sscottl		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1544111141Sscottl		free(fm, M_AACBUF);
1545110604Sscottl	}
154665793Smsmith}
154765793Smsmith
154883114Sscottl/*
154965793Smsmith * Command-mapping helper function - populate this command's s/g table.
155065793Smsmith */
155165793Smsmithstatic void
155265793Smsmithaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
155365793Smsmith{
1554117363Sscottl	struct aac_softc *sc;
155583114Sscottl	struct aac_command *cm;
155683114Sscottl	struct aac_fib *fib;
155783114Sscottl	int i;
155865793Smsmith
155983114Sscottl	cm = (struct aac_command *)arg;
1560117363Sscottl	sc = cm->cm_sc;
156183114Sscottl	fib = cm->cm_fib;
1562177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
156365793Smsmith
156483114Sscottl	/* copy into the FIB */
1565112856Sscottl	if (cm->cm_sgtable != NULL) {
1566151086Sscottl		if (fib->Header.Command == RawIo) {
1567151086Sscottl			struct aac_sg_tableraw *sg;
1568151086Sscottl			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
1569151086Sscottl			sg->SgCount = nseg;
1570151086Sscottl			for (i = 0; i < nseg; i++) {
1571151086Sscottl				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
1572151086Sscottl				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
1573151086Sscottl				sg->SgEntryRaw[i].Next = 0;
1574151086Sscottl				sg->SgEntryRaw[i].Prev = 0;
1575151086Sscottl				sg->SgEntryRaw[i].Flags = 0;
1576151086Sscottl			}
1577151086Sscottl			/* update the FIB size for the s/g count */
1578151086Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
1579151086Sscottl		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1580112856Sscottl			struct aac_sg_table *sg;
1581112856Sscottl			sg = cm->cm_sgtable;
1582112856Sscottl			sg->SgCount = nseg;
1583112856Sscottl			for (i = 0; i < nseg; i++) {
1584112856Sscottl				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1585112856Sscottl				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1586112856Sscottl			}
1587112856Sscottl			/* update the FIB size for the s/g count */
1588151086Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1589112856Sscottl		} else {
1590112856Sscottl			struct aac_sg_table64 *sg;
1591112856Sscottl			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1592112856Sscottl			sg->SgCount = nseg;
1593112856Sscottl			for (i = 0; i < nseg; i++) {
1594112856Sscottl				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1595112856Sscottl				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1596112856Sscottl			}
1597112856Sscottl			/* update the FIB size for the s/g count */
1598112856Sscottl			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
159983114Sscottl		}
160065793Smsmith	}
160165793Smsmith
1602117363Sscottl	/* Fix up the address values in the FIB.  Use the command array index
1603117363Sscottl	 * instead of a pointer since these fields are only 32 bits.  Shift
1604152388Sschweikh	 * the SenderFibAddress over to make room for the fast response bit
1605151086Sscottl	 * and for the AIF bit
1606117363Sscottl	 */
1607151086Sscottl	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
1608151086Sscottl	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
160965793Smsmith
1610117363Sscottl	/* save a pointer to the command for speedy reverse-lookup */
1611117363Sscottl	cm->cm_fib->Header.SenderData = cm->cm_index;
161265793Smsmith
1613117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAIN)
1614117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1615117363Sscottl				BUS_DMASYNC_PREREAD);
1616117363Sscottl	if (cm->cm_flags & AAC_CMD_DATAOUT)
1617117363Sscottl		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1618117363Sscottl				BUS_DMASYNC_PREWRITE);
1619117363Sscottl	cm->cm_flags |= AAC_CMD_MAPPED;
162065793Smsmith
1621151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1622151086Sscottl		int count = 10000000L;
1623151086Sscottl		while (AAC_SEND_COMMAND(sc, cm) != 0) {
1624151086Sscottl			if (--count == 0) {
1625151086Sscottl				aac_unmap_command(cm);
1626151086Sscottl				sc->flags |= AAC_QUEUE_FRZN;
1627151086Sscottl				aac_requeue_ready(cm);
1628151086Sscottl			}
1629151086Sscottl			DELAY(5);			/* wait 5 usec. */
1630151086Sscottl		}
1631151086Sscottl	} else {
1632151086Sscottl		/* Put the FIB on the outbound queue */
1633151086Sscottl		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
1634151086Sscottl			aac_unmap_command(cm);
1635151086Sscottl			sc->flags |= AAC_QUEUE_FRZN;
1636151086Sscottl			aac_requeue_ready(cm);
1637151086Sscottl		}
1638125559Sscottl	}
163965793Smsmith}
164065793Smsmith
164183114Sscottl/*
164265793Smsmith * Unmap a command from controller-visible space.
164365793Smsmith */
164465793Smsmithstatic void
164565793Smsmithaac_unmap_command(struct aac_command *cm)
164665793Smsmith{
164783114Sscottl	struct aac_softc *sc;
164865793Smsmith
164983114Sscottl	sc = cm->cm_sc;
1650177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
165165793Smsmith
165283114Sscottl	if (!(cm->cm_flags & AAC_CMD_MAPPED))
165383114Sscottl		return;
165465793Smsmith
165583114Sscottl	if (cm->cm_datalen != 0) {
165683114Sscottl		if (cm->cm_flags & AAC_CMD_DATAIN)
165783114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
165883114Sscottl					BUS_DMASYNC_POSTREAD);
165983114Sscottl		if (cm->cm_flags & AAC_CMD_DATAOUT)
166083114Sscottl			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
166183114Sscottl					BUS_DMASYNC_POSTWRITE);
166283114Sscottl
166383114Sscottl		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
166483114Sscottl	}
166583114Sscottl	cm->cm_flags &= ~AAC_CMD_MAPPED;
166665793Smsmith}
166765793Smsmith
166883114Sscottl/*
166983114Sscottl * Hardware Interface
167083114Sscottl */
167165793Smsmith
167283114Sscottl/*
1673177184Semaste * Initialize the adapter.
167465793Smsmith */
167565793Smsmithstatic void
167665793Smsmithaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
167765793Smsmith{
167883114Sscottl	struct aac_softc *sc;
167965793Smsmith
168083114Sscottl	sc = (struct aac_softc *)arg;
1681177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
168283114Sscottl
168383114Sscottl	sc->aac_common_busaddr = segs[0].ds_addr;
168465793Smsmith}
168565793Smsmith
168665793Smsmithstatic int
168790275Sscottlaac_check_firmware(struct aac_softc *sc)
168890275Sscottl{
1689177557Semaste	u_int32_t code, major, minor, options = 0, atu_size = 0;
1690251070Smarius	int rid, status;
1691177557Semaste	time_t then;
169290275Sscottl
1693177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1694177557Semaste	/*
1695177557Semaste	 * Wait for the adapter to come ready.
1696177557Semaste	 */
1697177557Semaste	then = time_uptime;
1698177557Semaste	do {
1699177557Semaste		code = AAC_GET_FWSTATUS(sc);
1700177557Semaste		if (code & AAC_SELF_TEST_FAILED) {
1701177557Semaste			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
1702177557Semaste			return(ENXIO);
1703177557Semaste		}
1704177557Semaste		if (code & AAC_KERNEL_PANIC) {
1705177557Semaste			device_printf(sc->aac_dev,
1706177635Semaste				      "FATAL: controller kernel panic");
1707177557Semaste			return(ENXIO);
1708177557Semaste		}
1709177557Semaste		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
1710177557Semaste			device_printf(sc->aac_dev,
1711177557Semaste				      "FATAL: controller not coming ready, "
1712177557Semaste					   "status %x\n", code);
1713177557Semaste			return(ENXIO);
1714177557Semaste		}
1715177557Semaste	} while (!(code & AAC_UP_AND_RUNNING));
171690275Sscottl
1717112679Sscottl	/*
1718112679Sscottl	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1719112679Sscottl	 * firmware version 1.x are not compatible with this driver.
1720112679Sscottl	 */
1721112679Sscottl	if (sc->flags & AAC_FLAGS_PERC2QC) {
172290275Sscottl		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
172390275Sscottl				     NULL)) {
172490275Sscottl			device_printf(sc->aac_dev,
172590275Sscottl				      "Error reading firmware version\n");
172690275Sscottl			return (EIO);
172790275Sscottl		}
172890275Sscottl
172990275Sscottl		/* These numbers are stored as ASCII! */
1730112679Sscottl		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1731112679Sscottl		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
173290275Sscottl		if (major == 1) {
173390275Sscottl			device_printf(sc->aac_dev,
173490275Sscottl			    "Firmware version %d.%d is not supported.\n",
173590275Sscottl			    major, minor);
173690275Sscottl			return (EINVAL);
173790275Sscottl		}
173890275Sscottl	}
173990275Sscottl
1740112679Sscottl	/*
1741112679Sscottl	 * Retrieve the capabilities/supported options word so we know what
1742151330Sscottl	 * work-arounds to enable.  Some firmware revs don't support this
1743151330Sscottl	 * command.
1744112679Sscottl	 */
1745151330Sscottl	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1746151330Sscottl		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1747151330Sscottl			device_printf(sc->aac_dev,
1748151330Sscottl			     "RequestAdapterInfo failed\n");
1749151330Sscottl			return (EIO);
1750151330Sscottl		}
1751151330Sscottl	} else {
1752151330Sscottl		options = AAC_GET_MAILBOX(sc, 1);
1753151330Sscottl		atu_size = AAC_GET_MAILBOX(sc, 2);
1754151330Sscottl		sc->supported_options = options;
1755112679Sscottl
1756151330Sscottl		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1757151330Sscottl		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1758151330Sscottl			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1759151330Sscottl		if (options & AAC_SUPPORTED_NONDASD)
1760151330Sscottl			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1761151330Sscottl		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1762151330Sscottl		     && (sizeof(bus_addr_t) > 4)) {
1763151330Sscottl			device_printf(sc->aac_dev,
1764151330Sscottl			    "Enabling 64-bit address support\n");
1765151330Sscottl			sc->flags |= AAC_FLAGS_SG_64BIT;
1766151330Sscottl		}
1767151330Sscottl		if ((options & AAC_SUPPORTED_NEW_COMM)
1768251070Smarius		 && sc->aac_if->aif_send_command)
1769151330Sscottl			sc->flags |= AAC_FLAGS_NEW_COMM;
1770151330Sscottl		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
1771151330Sscottl			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1772112679Sscottl	}
1773112679Sscottl
1774112679Sscottl	/* Check for broken hardware that does a lower number of commands */
1775152388Sschweikh	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
1776151086Sscottl
1777151086Sscottl	/* Remap mem. resource, if required */
1778152388Sschweikh	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1779251070Smarius	    atu_size > rman_get_size(sc->aac_regs_res1)) {
1780251070Smarius		rid = rman_get_rid(sc->aac_regs_res1);
1781251070Smarius		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, rid,
1782251070Smarius		    sc->aac_regs_res1);
1783251070Smarius		sc->aac_regs_res1 = bus_alloc_resource(sc->aac_dev,
1784251070Smarius		    SYS_RES_MEMORY, &rid, 0ul, ~0ul, atu_size, RF_ACTIVE);
1785188896Sattilio		if (sc->aac_regs_res1 == NULL) {
1786188896Sattilio			sc->aac_regs_res1 = bus_alloc_resource_any(
1787251070Smarius			    sc->aac_dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
1788188896Sattilio			if (sc->aac_regs_res1 == NULL) {
1789151086Sscottl				device_printf(sc->aac_dev,
1790151109Sscottl				    "couldn't allocate register window\n");
1791151086Sscottl				return (ENXIO);
1792151086Sscottl			}
1793151086Sscottl			sc->flags &= ~AAC_FLAGS_NEW_COMM;
1794151086Sscottl		}
1795188896Sattilio		sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1);
1796188896Sattilio		sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1);
1797188896Sattilio
1798188896Sattilio		if (sc->aac_hwif == AAC_HWIF_NARK) {
1799188896Sattilio			sc->aac_regs_res0 = sc->aac_regs_res1;
1800188896Sattilio			sc->aac_btag0 = sc->aac_btag1;
1801188896Sattilio			sc->aac_bhandle0 = sc->aac_bhandle1;
1802188896Sattilio		}
1803151086Sscottl	}
1804151086Sscottl
1805151086Sscottl	/* Read preferred settings */
1806151086Sscottl	sc->aac_max_fib_size = sizeof(struct aac_fib);
1807151086Sscottl	sc->aac_max_sectors = 128;				/* 64KB */
1808151086Sscottl	if (sc->flags & AAC_FLAGS_SG_64BIT)
1809151330Sscottl		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1810172672Semaste		 - sizeof(struct aac_blockwrite64))
1811172672Semaste		 / sizeof(struct aac_sg_entry64);
1812112679Sscottl	else
1813151330Sscottl		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1814172672Semaste		 - sizeof(struct aac_blockwrite))
1815172672Semaste		 / sizeof(struct aac_sg_entry);
1816151330Sscottl
1817151086Sscottl	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
1818151086Sscottl		options = AAC_GET_MAILBOX(sc, 1);
1819151086Sscottl		sc->aac_max_fib_size = (options & 0xFFFF);
1820151086Sscottl		sc->aac_max_sectors = (options >> 16) << 1;
1821151086Sscottl		options = AAC_GET_MAILBOX(sc, 2);
1822151086Sscottl		sc->aac_sg_tablesize = (options >> 16);
1823151086Sscottl		options = AAC_GET_MAILBOX(sc, 3);
1824151086Sscottl		sc->aac_max_fibs = (options & 0xFFFF);
1825151086Sscottl	}
1826151086Sscottl	if (sc->aac_max_fib_size > PAGE_SIZE)
1827151086Sscottl		sc->aac_max_fib_size = PAGE_SIZE;
1828151086Sscottl	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1829152388Sschweikh
1830177462Semaste	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1831177462Semaste		sc->flags |= AAC_FLAGS_RAW_IO;
1832177462Semaste		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1833177462Semaste	}
1834177619Semaste	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1835177619Semaste	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1836177619Semaste		sc->flags |= AAC_FLAGS_LBA_64BIT;
1837177619Semaste		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1838177619Semaste	}
1839177462Semaste
184090275Sscottl	return (0);
184190275Sscottl}
184290275Sscottl
184390275Sscottlstatic int
184465793Smsmithaac_init(struct aac_softc *sc)
184565793Smsmith{
184683114Sscottl	struct aac_adapter_init	*ip;
1847177557Semaste	u_int32_t qoffset;
1848112679Sscottl	int error;
184965793Smsmith
1850177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
185165793Smsmith
185283114Sscottl	/*
185383114Sscottl	 * Fill in the init structure.  This tells the adapter about the
185483114Sscottl	 * physical location of various important shared data structures.
185583114Sscottl	 */
185683114Sscottl	ip = &sc->aac_common->ac_init;
185783114Sscottl	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1858151086Sscottl	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1859151086Sscottl		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
1860151086Sscottl		sc->flags |= AAC_FLAGS_RAW_IO;
1861151086Sscottl	}
1862109088Sscottl	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
186365793Smsmith
186483114Sscottl	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
186583114Sscottl					 offsetof(struct aac_common, ac_fibs);
1866114151Sscottl	ip->AdapterFibsVirtualAddress = 0;
186783114Sscottl	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
186883114Sscottl	ip->AdapterFibAlign = sizeof(struct aac_fib);
186965793Smsmith
187083114Sscottl	ip->PrintfBufferAddress = sc->aac_common_busaddr +
187183114Sscottl				  offsetof(struct aac_common, ac_printf);
187283114Sscottl	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
187365793Smsmith
1874152388Sschweikh	/*
1875117361Sscottl	 * The adapter assumes that pages are 4K in size, except on some
1876117361Sscottl 	 * broken firmware versions that do the page->byte conversion twice,
1877117361Sscottl	 * therefore 'assuming' that this value is in 16MB units (2^24).
1878117361Sscottl	 * Round up since the granularity is so high.
1879117361Sscottl	 */
1880109088Sscottl	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1881117361Sscottl	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1882117361Sscottl		ip->HostPhysMemPages =
1883117361Sscottl		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1884117362Sscottl	}
1885150119Sscottl	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
188665793Smsmith
1887151086Sscottl	ip->InitFlags = 0;
1888151086Sscottl	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1889206540Semaste		ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED;
1890151086Sscottl		device_printf(sc->aac_dev, "New comm. interface enabled\n");
1891151086Sscottl	}
1892151086Sscottl
1893151086Sscottl	ip->MaxIoCommands = sc->aac_max_fibs;
1894151086Sscottl	ip->MaxIoSize = sc->aac_max_sectors << 9;
1895151086Sscottl	ip->MaxFibSize = sc->aac_max_fib_size;
1896151086Sscottl
189783114Sscottl	/*
1898177184Semaste	 * Initialize FIB queues.  Note that it appears that the layout of the
189983114Sscottl	 * indexes and the segmentation of the entries may be mandated by the
190083114Sscottl	 * adapter, which is only told about the base of the queue index fields.
190183114Sscottl	 *
190283114Sscottl	 * The initial values of the indices are assumed to inform the adapter
1903152388Sschweikh	 * of the sizes of the respective queues, and theoretically it could
190483114Sscottl	 * work out the entire layout of the queue structures from this.  We
190583114Sscottl	 * take the easy route and just lay this area out like everyone else
190683114Sscottl	 * does.
190783114Sscottl	 *
1908152388Sschweikh	 * The Linux driver uses a much more complex scheme whereby several
1909152388Sschweikh	 * header records are kept for each queue.  We use a couple of generic
191083114Sscottl	 * list manipulation functions which 'know' the size of each list by
191183114Sscottl	 * virtue of a table.
191283114Sscottl	 */
1913119146Sscottl	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
1914119625Sscottl	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
1915119625Sscottl	sc->aac_queues =
1916119625Sscottl	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1917119146Sscottl	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
191865793Smsmith
191983114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
192081082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
192183114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
192281082Sscottl		AAC_HOST_NORM_CMD_ENTRIES;
192383114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
192481082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
192583114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
192681082Sscottl		AAC_HOST_HIGH_CMD_ENTRIES;
192783114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
192881082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
192983114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
193081082Sscottl		AAC_ADAP_NORM_CMD_ENTRIES;
193183114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
193281082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
193383114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
193481082Sscottl		AAC_ADAP_HIGH_CMD_ENTRIES;
193583114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
193681082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
193783114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
193881082Sscottl		AAC_HOST_NORM_RESP_ENTRIES;
193983114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
194081082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
194183114Sscottl	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
194281082Sscottl		AAC_HOST_HIGH_RESP_ENTRIES;
194383114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
194481082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
194583114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
194681082Sscottl		AAC_ADAP_NORM_RESP_ENTRIES;
194783114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
194881082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
194983114Sscottl	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
195081082Sscottl		AAC_ADAP_HIGH_RESP_ENTRIES;
195183114Sscottl	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
195281082Sscottl		&sc->aac_queues->qt_HostNormCmdQueue[0];
195383114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
195481082Sscottl		&sc->aac_queues->qt_HostHighCmdQueue[0];
195583114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
195681082Sscottl		&sc->aac_queues->qt_AdapNormCmdQueue[0];
195783114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
195881082Sscottl		&sc->aac_queues->qt_AdapHighCmdQueue[0];
195983114Sscottl	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
196081082Sscottl		&sc->aac_queues->qt_HostNormRespQueue[0];
196183114Sscottl	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
196281082Sscottl		&sc->aac_queues->qt_HostHighRespQueue[0];
196383114Sscottl	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
196481082Sscottl		&sc->aac_queues->qt_AdapNormRespQueue[0];
196583114Sscottl	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
196681082Sscottl		&sc->aac_queues->qt_AdapHighRespQueue[0];
196765793Smsmith
196883114Sscottl	/*
196983114Sscottl	 * Do controller-type-specific initialisation
197083114Sscottl	 */
197183114Sscottl	switch (sc->aac_hwif) {
197283114Sscottl	case AAC_HWIF_I960RX:
1973188896Sattilio		AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0);
197483114Sscottl		break;
1975133606Sscottl	case AAC_HWIF_RKT:
1976188896Sattilio		AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0);
1977133606Sscottl		break;
1978133606Sscottl	default:
1979133606Sscottl		break;
198083114Sscottl	}
198165793Smsmith
198283114Sscottl	/*
198383114Sscottl	 * Give the init structure to the controller.
198483114Sscottl	 */
1985152388Sschweikh	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
198683114Sscottl			     sc->aac_common_busaddr +
198783114Sscottl			     offsetof(struct aac_common, ac_init), 0, 0, 0,
198883114Sscottl			     NULL)) {
198983114Sscottl		device_printf(sc->aac_dev,
199083114Sscottl			      "error establishing init structure\n");
1991112679Sscottl		error = EIO;
1992112679Sscottl		goto out;
199383114Sscottl	}
199465793Smsmith
1995112679Sscottl	error = 0;
1996112679Sscottlout:
1997112679Sscottl	return(error);
199865793Smsmith}
199965793Smsmith
2000177557Semastestatic int
2001177557Semasteaac_setup_intr(struct aac_softc *sc)
2002177557Semaste{
2003251070Smarius
2004177557Semaste	if (sc->flags & AAC_FLAGS_NEW_COMM) {
2005177557Semaste		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2006206534Semaste				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
2007177557Semaste				   aac_new_intr, sc, &sc->aac_intr)) {
2008177557Semaste			device_printf(sc->aac_dev, "can't set up interrupt\n");
2009177557Semaste			return (EINVAL);
2010177557Semaste		}
2011177557Semaste	} else {
2012177557Semaste		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2013198593Semaste				   INTR_TYPE_BIO, aac_filter, NULL,
2014177557Semaste				   sc, &sc->aac_intr)) {
2015177557Semaste			device_printf(sc->aac_dev,
2016198593Semaste				      "can't set up interrupt filter\n");
2017198593Semaste			return (EINVAL);
2018177557Semaste		}
2019177557Semaste	}
2020177557Semaste	return (0);
2021177557Semaste}
2022177557Semaste
202383114Sscottl/*
202465793Smsmith * Send a synchronous command to the controller and wait for a result.
2025151086Sscottl * Indicate if the controller completed the command with an error status.
202665793Smsmith */
202765793Smsmithstatic int
202865793Smsmithaac_sync_command(struct aac_softc *sc, u_int32_t command,
202970393Smsmith		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
203070393Smsmith		 u_int32_t *sp)
203165793Smsmith{
203283114Sscottl	time_t then;
203383114Sscottl	u_int32_t status;
203465793Smsmith
2035177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
203665793Smsmith
203783114Sscottl	/* populate the mailbox */
203883114Sscottl	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
203965793Smsmith
204083114Sscottl	/* ensure the sync command doorbell flag is cleared */
204183114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
204265793Smsmith
204383114Sscottl	/* then set it to signal the adapter */
204483114Sscottl	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
204565793Smsmith
204683114Sscottl	/* spin waiting for the command to complete */
2047150119Sscottl	then = time_uptime;
204883114Sscottl	do {
2049150119Sscottl		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
2050177567Semaste			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
205183114Sscottl			return(EIO);
205283114Sscottl		}
205383114Sscottl	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
205465793Smsmith
205583114Sscottl	/* clear the completion flag */
205683114Sscottl	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
205765793Smsmith
205883114Sscottl	/* get the command status */
2059112679Sscottl	status = AAC_GET_MAILBOX(sc, 0);
206083114Sscottl	if (sp != NULL)
206183114Sscottl		*sp = status;
2062151086Sscottl
2063151330Sscottl	if (status != AAC_SRB_STS_SUCCESS)
2064151086Sscottl		return (-1);
206583114Sscottl	return(0);
206665793Smsmith}
206765793Smsmith
206895350Sscottlint
2069152388Sschweikhaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
207095350Sscottl		 struct aac_fib *fib, u_int16_t datasize)
207165793Smsmith{
2072177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2073151086Sscottl	mtx_assert(&sc->aac_io_lock, MA_OWNED);
207465793Smsmith
207583114Sscottl	if (datasize > AAC_FIB_DATASIZE)
207683114Sscottl		return(EINVAL);
207765793Smsmith
207883114Sscottl	/*
207983114Sscottl	 * Set up the sync FIB
208083114Sscottl	 */
208183114Sscottl	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
208283114Sscottl				AAC_FIBSTATE_INITIALISED |
208383114Sscottl				AAC_FIBSTATE_EMPTY;
208483114Sscottl	fib->Header.XferState |= xferstate;
208583114Sscottl	fib->Header.Command = command;
208683114Sscottl	fib->Header.StructType = AAC_FIBTYPE_TFIB;
2087177463Semaste	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
208883114Sscottl	fib->Header.SenderSize = sizeof(struct aac_fib);
2089119146Sscottl	fib->Header.SenderFibAddress = 0;	/* Not needed */
209083114Sscottl	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
209183114Sscottl					 offsetof(struct aac_common,
209283114Sscottl						  ac_sync_fib);
209365793Smsmith
209483114Sscottl	/*
209583114Sscottl	 * Give the FIB to the controller, wait for a response.
209683114Sscottl	 */
209783114Sscottl	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
209883114Sscottl			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
2099177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
210083114Sscottl		return(EIO);
210183114Sscottl	}
210281151Sscottl
210395350Sscottl	return (0);
210465793Smsmith}
210565793Smsmith
210683114Sscottl/*
210765793Smsmith * Adapter-space FIB queue manipulation
210865793Smsmith *
210965793Smsmith * Note that the queue implementation here is a little funky; neither the PI or
211065793Smsmith * CI will ever be zero.  This behaviour is a controller feature.
211165793Smsmith */
2112251070Smariusstatic const struct {
211383114Sscottl	int		size;
211483114Sscottl	int		notify;
211565793Smsmith} aac_qinfo[] = {
211683114Sscottl	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
211783114Sscottl	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
211883114Sscottl	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
211983114Sscottl	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
212083114Sscottl	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
212183114Sscottl	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
212283114Sscottl	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
212383114Sscottl	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
212465793Smsmith};
212565793Smsmith
212665793Smsmith/*
212781082Sscottl * Atomically insert an entry into the nominated queue, returns 0 on success or
212881082Sscottl * EBUSY if the queue is full.
212965793Smsmith *
213070393Smsmith * Note: it would be more efficient to defer notifying the controller in
213183114Sscottl *	 the case where we may be inserting several entries in rapid succession,
213283114Sscottl *	 but implementing this usefully may be difficult (it would involve a
213383114Sscottl *	 separate queue/notify interface).
213465793Smsmith */
213565793Smsmithstatic int
213681151Sscottlaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
213765793Smsmith{
213883114Sscottl	u_int32_t pi, ci;
2139111691Sscottl	int error;
214083114Sscottl	u_int32_t fib_size;
214183114Sscottl	u_int32_t fib_addr;
214265793Smsmith
2143177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
214482527Sscottl
2145152388Sschweikh	fib_size = cm->cm_fib->Header.Size;
214683114Sscottl	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
214781151Sscottl
214883114Sscottl	/* get the producer/consumer indices */
214983114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
215083114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
215165793Smsmith
215283114Sscottl	/* wrap the queue? */
215383114Sscottl	if (pi >= aac_qinfo[queue].size)
215483114Sscottl		pi = 0;
215565793Smsmith
215683114Sscottl	/* check for queue full */
215783114Sscottl	if ((pi + 1) == ci) {
215883114Sscottl		error = EBUSY;
215983114Sscottl		goto out;
216083114Sscottl	}
216165793Smsmith
2162129946Sscottl	/*
2163129946Sscottl	 * To avoid a race with its completion interrupt, place this command on
2164129946Sscottl	 * the busy queue prior to advertising it to the controller.
2165129946Sscottl	 */
2166129946Sscottl	aac_enqueue_busy(cm);
2167129946Sscottl
216883114Sscottl	/* populate queue entry */
216983114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
217083114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
217165793Smsmith
217283114Sscottl	/* update producer index */
217383114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
217465793Smsmith
217583114Sscottl	/* notify the adapter if we know how */
217683114Sscottl	if (aac_qinfo[queue].notify != 0)
217783114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
217865793Smsmith
217983114Sscottl	error = 0;
218065793Smsmith
218165793Smsmithout:
218283114Sscottl	return(error);
218365793Smsmith}
218465793Smsmith
218565793Smsmith/*
218682527Sscottl * Atomically remove one entry from the nominated queue, returns 0 on
218782527Sscottl * success or ENOENT if the queue is empty.
218865793Smsmith */
218965793Smsmithstatic int
219081082Sscottlaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
219181082Sscottl		struct aac_fib **fib_addr)
219265793Smsmith{
219383114Sscottl	u_int32_t pi, ci;
2194114151Sscottl	u_int32_t fib_index;
2195111691Sscottl	int error;
219683114Sscottl	int notify;
219765793Smsmith
2198177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
219965793Smsmith
220083114Sscottl	/* get the producer/consumer indices */
220183114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
220283114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
220365793Smsmith
220483114Sscottl	/* check for queue empty */
220583114Sscottl	if (ci == pi) {
220683114Sscottl		error = ENOENT;
220783114Sscottl		goto out;
220883114Sscottl	}
2209120129Sscottl
2210120129Sscottl	/* wrap the pi so the following test works */
2211120129Sscottl	if (pi >= aac_qinfo[queue].size)
2212120129Sscottl		pi = 0;
2213120129Sscottl
221483114Sscottl	notify = 0;
221583114Sscottl	if (ci == pi + 1)
221683114Sscottl		notify++;
221781151Sscottl
221883114Sscottl	/* wrap the queue? */
221983114Sscottl	if (ci >= aac_qinfo[queue].size)
222083114Sscottl		ci = 0;
222165793Smsmith
222283114Sscottl	/* fetch the entry */
222383114Sscottl	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
222465793Smsmith
2225114151Sscottl	switch (queue) {
2226114151Sscottl	case AAC_HOST_NORM_CMD_QUEUE:
2227114151Sscottl	case AAC_HOST_HIGH_CMD_QUEUE:
2228114151Sscottl		/*
2229114151Sscottl		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2230114151Sscottl		 * on to hold an address.  For AIF's, the adapter assumes
2231114151Sscottl		 * that it's giving us an address into the array of AIF fibs.
2232114151Sscottl		 * Therefore, we have to convert it to an index.
2233114151Sscottl		 */
2234114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2235114151Sscottl			sizeof(struct aac_fib);
2236114151Sscottl		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2237114151Sscottl		break;
2238114151Sscottl
2239114151Sscottl	case AAC_HOST_NORM_RESP_QUEUE:
2240114151Sscottl	case AAC_HOST_HIGH_RESP_QUEUE:
2241114151Sscottl	{
2242114151Sscottl		struct aac_command *cm;
2243114151Sscottl
2244114151Sscottl		/*
2245114151Sscottl		 * As above, an index is used instead of an actual address.
2246114151Sscottl		 * Gotta shift the index to account for the fast response
2247114151Sscottl		 * bit.  No other correction is needed since this value was
2248114151Sscottl		 * originally provided by the driver via the SenderFibAddress
2249114151Sscottl		 * field.
2250114151Sscottl		 */
2251114151Sscottl		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
2252151086Sscottl		cm = sc->aac_commands + (fib_index >> 2);
2253114151Sscottl		*fib_addr = cm->cm_fib;
2254114151Sscottl
2255114151Sscottl		/*
2256114151Sscottl		 * Is this a fast response? If it is, update the fib fields in
2257114151Sscottl		 * local memory since the whole fib isn't DMA'd back up.
2258114151Sscottl		 */
2259114151Sscottl		if (fib_index & 0x01) {
2260114151Sscottl			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2261114151Sscottl			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2262114151Sscottl		}
2263114151Sscottl		break;
2264109088Sscottl	}
2265114151Sscottl	default:
2266114151Sscottl		panic("Invalid queue in aac_dequeue_fib()");
2267114151Sscottl		break;
2268114151Sscottl	}
2269114151Sscottl
227083114Sscottl	/* update consumer index */
227183114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
227265793Smsmith
227383114Sscottl	/* if we have made the queue un-full, notify the adapter */
227483114Sscottl	if (notify && (aac_qinfo[queue].notify != 0))
227583114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
227683114Sscottl	error = 0;
227765793Smsmith
227865793Smsmithout:
227983114Sscottl	return(error);
228065793Smsmith}
228165793Smsmith
228283114Sscottl/*
228382527Sscottl * Put our response to an Adapter Initialed Fib on the response queue
228482527Sscottl */
228582527Sscottlstatic int
228682527Sscottlaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
228782527Sscottl{
228883114Sscottl	u_int32_t pi, ci;
2289111691Sscottl	int error;
229083114Sscottl	u_int32_t fib_size;
229183114Sscottl	u_int32_t fib_addr;
229282527Sscottl
2293177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
229482527Sscottl
229583114Sscottl	/* Tell the adapter where the FIB is */
2296152388Sschweikh	fib_size = fib->Header.Size;
229783114Sscottl	fib_addr = fib->Header.SenderFibAddress;
229883114Sscottl	fib->Header.ReceiverFibAddress = fib_addr;
229982527Sscottl
230083114Sscottl	/* get the producer/consumer indices */
230183114Sscottl	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
230283114Sscottl	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
230382527Sscottl
230483114Sscottl	/* wrap the queue? */
230583114Sscottl	if (pi >= aac_qinfo[queue].size)
230683114Sscottl		pi = 0;
230782527Sscottl
230883114Sscottl	/* check for queue full */
230983114Sscottl	if ((pi + 1) == ci) {
231083114Sscottl		error = EBUSY;
231183114Sscottl		goto out;
231283114Sscottl	}
231382527Sscottl
231483114Sscottl	/* populate queue entry */
231583114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
231683114Sscottl	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
231782527Sscottl
231883114Sscottl	/* update producer index */
231983114Sscottl	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
232082527Sscottl
232183114Sscottl	/* notify the adapter if we know how */
232283114Sscottl	if (aac_qinfo[queue].notify != 0)
232383114Sscottl		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
232482527Sscottl
232583114Sscottl	error = 0;
232682527Sscottl
232782527Sscottlout:
232883114Sscottl	return(error);
232982527Sscottl}
233082527Sscottl
233183114Sscottl/*
233270393Smsmith * Check for commands that have been outstanding for a suspiciously long time,
233370393Smsmith * and complain about them.
233470393Smsmith */
233570393Smsmithstatic void
233670393Smsmithaac_timeout(struct aac_softc *sc)
233770393Smsmith{
233883114Sscottl	struct aac_command *cm;
233983114Sscottl	time_t deadline;
2340135289Sscottl	int timedout, code;
234170393Smsmith
234283114Sscottl	/*
2343110426Sscottl	 * Traverse the busy command list, bitch about late commands once
234483114Sscottl	 * only.
234583114Sscottl	 */
2346135289Sscottl	timedout = 0;
2347150119Sscottl	deadline = time_uptime - AAC_CMD_TIMEOUT;
234883114Sscottl	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
234983114Sscottl		if ((cm->cm_timestamp  < deadline)
2350212594Semaste		    && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) {
235183114Sscottl			cm->cm_flags |= AAC_CMD_TIMEDOUT;
235283114Sscottl			device_printf(sc->aac_dev,
2353204019Semaste			    "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n",
2354204019Semaste			    cm, cm->cm_fib->Header.Command,
2355204019Semaste			    (int)(time_uptime-cm->cm_timestamp));
235683114Sscottl			AAC_PRINT_FIB(sc, cm->cm_fib);
2357135289Sscottl			timedout++;
235883114Sscottl		}
235970393Smsmith	}
236070393Smsmith
2361135289Sscottl	if (timedout) {
2362135289Sscottl		code = AAC_GET_FWSTATUS(sc);
2363135289Sscottl		if (code != AAC_UP_AND_RUNNING) {
2364135289Sscottl			device_printf(sc->aac_dev, "WARNING! Controller is no "
2365135289Sscottl				      "longer running! code= 0x%x\n", code);
2366135289Sscottl		}
2367135289Sscottl	}
236870393Smsmith}
236970393Smsmith
237083114Sscottl/*
237183114Sscottl * Interface Function Vectors
237283114Sscottl */
237365793Smsmith
237483114Sscottl/*
237565793Smsmith * Read the current firmware status word.
237665793Smsmith */
237765793Smsmithstatic int
237865793Smsmithaac_sa_get_fwstatus(struct aac_softc *sc)
237965793Smsmith{
2380177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
238165793Smsmith
2382188896Sattilio	return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS));
238365793Smsmith}
238465793Smsmith
238565793Smsmithstatic int
238665793Smsmithaac_rx_get_fwstatus(struct aac_softc *sc)
238765793Smsmith{
2388177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
238965793Smsmith
2390188940Semaste	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
2391188940Semaste	    AAC_RX_OMR0 : AAC_RX_FWSTATUS));
239265793Smsmith}
239365793Smsmith
239487183Sscottlstatic int
2395133606Sscottlaac_rkt_get_fwstatus(struct aac_softc *sc)
2396133606Sscottl{
2397177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2398133606Sscottl
2399188940Semaste	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
2400188940Semaste	    AAC_RKT_OMR0 : AAC_RKT_FWSTATUS));
2401133606Sscottl}
2402133606Sscottl
240383114Sscottl/*
240465793Smsmith * Notify the controller of a change in a given queue
240565793Smsmith */
240665793Smsmith
240765793Smsmithstatic void
240865793Smsmithaac_sa_qnotify(struct aac_softc *sc, int qbit)
240965793Smsmith{
2410177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241165793Smsmith
2412188896Sattilio	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
241365793Smsmith}
241465793Smsmith
241565793Smsmithstatic void
241665793Smsmithaac_rx_qnotify(struct aac_softc *sc, int qbit)
241765793Smsmith{
2418177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
241965793Smsmith
2420188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit);
242165793Smsmith}
242265793Smsmith
242387183Sscottlstatic void
2424133606Sscottlaac_rkt_qnotify(struct aac_softc *sc, int qbit)
2425133606Sscottl{
2426177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2427133606Sscottl
2428188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit);
2429133606Sscottl}
2430133606Sscottl
243183114Sscottl/*
243265793Smsmith * Get the interrupt reason bits
243365793Smsmith */
243465793Smsmithstatic int
243565793Smsmithaac_sa_get_istatus(struct aac_softc *sc)
243665793Smsmith{
2437177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
243865793Smsmith
2439188896Sattilio	return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0));
244065793Smsmith}
244165793Smsmith
244265793Smsmithstatic int
244365793Smsmithaac_rx_get_istatus(struct aac_softc *sc)
244465793Smsmith{
2445177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
244665793Smsmith
2447188896Sattilio	return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR));
244865793Smsmith}
244965793Smsmith
245087183Sscottlstatic int
2451133606Sscottlaac_rkt_get_istatus(struct aac_softc *sc)
2452133606Sscottl{
2453177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2454133606Sscottl
2455188896Sattilio	return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR));
2456133606Sscottl}
2457133606Sscottl
245883114Sscottl/*
245965793Smsmith * Clear some interrupt reason bits
246065793Smsmith */
246165793Smsmithstatic void
246265793Smsmithaac_sa_clear_istatus(struct aac_softc *sc, int mask)
246365793Smsmith{
2464177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
246565793Smsmith
2466188896Sattilio	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
246765793Smsmith}
246865793Smsmith
246965793Smsmithstatic void
247065793Smsmithaac_rx_clear_istatus(struct aac_softc *sc, int mask)
247165793Smsmith{
2472177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
247365793Smsmith
2474188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask);
247565793Smsmith}
247665793Smsmith
247787183Sscottlstatic void
2478133606Sscottlaac_rkt_clear_istatus(struct aac_softc *sc, int mask)
2479133606Sscottl{
2480177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2481133606Sscottl
2482188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask);
2483133606Sscottl}
2484133606Sscottl
248583114Sscottl/*
248665793Smsmith * Populate the mailbox and set the command word
248765793Smsmith */
248865793Smsmithstatic void
248965793Smsmithaac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
249065793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
249165793Smsmith{
2492177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
249365793Smsmith
2494188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command);
2495188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2496188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2497188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2498188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
249965793Smsmith}
250065793Smsmith
250165793Smsmithstatic void
250265793Smsmithaac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
250365793Smsmith		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
250465793Smsmith{
2505177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
250665793Smsmith
2507188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command);
2508188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2509188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2510188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2511188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
251265793Smsmith}
251365793Smsmith
251487183Sscottlstatic void
2515133606Sscottlaac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2516133606Sscottl		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2517133606Sscottl{
2518177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2519133606Sscottl
2520188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command);
2521188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2522188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2523188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2524188896Sattilio	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
2525133606Sscottl}
2526133606Sscottl
252783114Sscottl/*
252865793Smsmith * Fetch the immediate command status word
252965793Smsmith */
253065793Smsmithstatic int
2531112679Sscottlaac_sa_get_mailbox(struct aac_softc *sc, int mb)
253265793Smsmith{
2533177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
253465793Smsmith
2535188896Sattilio	return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
253665793Smsmith}
253765793Smsmith
253865793Smsmithstatic int
2539112679Sscottlaac_rx_get_mailbox(struct aac_softc *sc, int mb)
254065793Smsmith{
2541177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
254265793Smsmith
2543188896Sattilio	return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
254465793Smsmith}
254565793Smsmith
254687183Sscottlstatic int
2547133606Sscottlaac_rkt_get_mailbox(struct aac_softc *sc, int mb)
2548133606Sscottl{
2549177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2550133606Sscottl
2551188896Sattilio	return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
2552133606Sscottl}
2553133606Sscottl
255483114Sscottl/*
255565793Smsmith * Set/clear interrupt masks
255665793Smsmith */
255765793Smsmithstatic void
255865793Smsmithaac_sa_set_interrupts(struct aac_softc *sc, int enable)
255965793Smsmith{
2560177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
256165793Smsmith
256283114Sscottl	if (enable) {
2563188896Sattilio		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
256483114Sscottl	} else {
2565188896Sattilio		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
256683114Sscottl	}
256765793Smsmith}
256865793Smsmith
256965793Smsmithstatic void
257065793Smsmithaac_rx_set_interrupts(struct aac_softc *sc, int enable)
257165793Smsmith{
2572177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
257365793Smsmith
257483114Sscottl	if (enable) {
2575151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
2576188896Sattilio			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
2577151086Sscottl		else
2578188896Sattilio			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
257983114Sscottl	} else {
2580188896Sattilio		AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0);
258183114Sscottl	}
258265793Smsmith}
258365793Smsmith
258487183Sscottlstatic void
2585133606Sscottlaac_rkt_set_interrupts(struct aac_softc *sc, int enable)
2586133606Sscottl{
2587177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2588133606Sscottl
2589133606Sscottl	if (enable) {
2590151086Sscottl		if (sc->flags & AAC_FLAGS_NEW_COMM)
2591188896Sattilio			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
2592151086Sscottl		else
2593188896Sattilio			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
2594133606Sscottl	} else {
2595188896Sattilio		AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0);
2596133606Sscottl	}
2597133606Sscottl}
2598133606Sscottl
259983114Sscottl/*
2600151086Sscottl * New comm. interface: Send command functions
2601151086Sscottl */
2602151086Sscottlstatic int
2603151086Sscottlaac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
2604151086Sscottl{
2605151086Sscottl	u_int32_t index, device;
2606151086Sscottl
2607177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
2608151086Sscottl
2609188896Sattilio	index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
2610151086Sscottl	if (index == 0xffffffffL)
2611188896Sattilio		index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
2612151086Sscottl	if (index == 0xffffffffL)
2613151086Sscottl		return index;
2614151086Sscottl	aac_enqueue_busy(cm);
2615151086Sscottl	device = index;
2616188896Sattilio	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2617151086Sscottl	device += 4;
2618188896Sattilio	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2619151086Sscottl	device += 4;
2620188896Sattilio	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2621188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index);
2622151086Sscottl	return 0;
2623151086Sscottl}
2624151086Sscottl
2625151086Sscottlstatic int
2626151086Sscottlaac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
2627151086Sscottl{
2628151086Sscottl	u_int32_t index, device;
2629151086Sscottl
2630177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
2631151086Sscottl
2632188896Sattilio	index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
2633151086Sscottl	if (index == 0xffffffffL)
2634188896Sattilio		index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
2635151086Sscottl	if (index == 0xffffffffL)
2636151086Sscottl		return index;
2637151086Sscottl	aac_enqueue_busy(cm);
2638151086Sscottl	device = index;
2639188896Sattilio	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2640151086Sscottl	device += 4;
2641188896Sattilio	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2642151086Sscottl	device += 4;
2643188896Sattilio	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2644188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index);
2645151086Sscottl	return 0;
2646151086Sscottl}
2647151086Sscottl
2648152388Sschweikh/*
2649152388Sschweikh * New comm. interface: get, set outbound queue index
2650151086Sscottl */
2651151086Sscottlstatic int
2652151086Sscottlaac_rx_get_outb_queue(struct aac_softc *sc)
2653151086Sscottl{
2654177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2655151086Sscottl
2656188896Sattilio	return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE));
2657151086Sscottl}
2658151086Sscottl
2659151086Sscottlstatic int
2660151086Sscottlaac_rkt_get_outb_queue(struct aac_softc *sc)
2661151086Sscottl{
2662177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2663151086Sscottl
2664188896Sattilio	return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE));
2665151086Sscottl}
2666151086Sscottl
2667151086Sscottlstatic void
2668151086Sscottlaac_rx_set_outb_queue(struct aac_softc *sc, int index)
2669151086Sscottl{
2670177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2671151086Sscottl
2672188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index);
2673151086Sscottl}
2674151086Sscottl
2675151086Sscottlstatic void
2676151086Sscottlaac_rkt_set_outb_queue(struct aac_softc *sc, int index)
2677151086Sscottl{
2678177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2679151086Sscottl
2680188896Sattilio	AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index);
2681151086Sscottl}
2682151086Sscottl
2683151086Sscottl/*
268483114Sscottl * Debugging and Diagnostics
268583114Sscottl */
268665793Smsmith
268783114Sscottl/*
268865793Smsmith * Print some information about the controller.
268965793Smsmith */
269065793Smsmithstatic void
269165793Smsmithaac_describe_controller(struct aac_softc *sc)
269265793Smsmith{
269395350Sscottl	struct aac_fib *fib;
269483114Sscottl	struct aac_adapter_info	*info;
2695174412Semaste	char *adapter_type = "Adaptec RAID controller";
269665793Smsmith
2697177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
269865793Smsmith
2699151222Sscottl	mtx_lock(&sc->aac_io_lock);
2700130006Sscottl	aac_alloc_sync_fib(sc, &fib);
270195350Sscottl
270295350Sscottl	fib->data[0] = 0;
270395350Sscottl	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
270483114Sscottl		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
270595536Sscottl		aac_release_sync_fib(sc);
2706151222Sscottl		mtx_unlock(&sc->aac_io_lock);
270783114Sscottl		return;
270883114Sscottl	}
270965793Smsmith
271083114Sscottl	/* save the kernel revision structure for later use */
2711152388Sschweikh	info = (struct aac_adapter_info *)&fib->data[0];
271283114Sscottl	sc->aac_revision = info->KernelRevision;
271395536Sscottl
2714135095Sscottl	if (bootverbose) {
2715146851Sscottl		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2716152388Sschweikh		    "(%dMB cache, %dMB execution), %s\n",
2717135095Sscottl		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2718152388Sschweikh		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2719146851Sscottl		    info->BufferMem / (1024 * 1024),
2720146851Sscottl		    info->ExecutionMem / (1024 * 1024),
2721135095Sscottl		    aac_describe_code(aac_battery_platform,
2722135095Sscottl		    info->batteryPlatform));
2723112679Sscottl
2724135095Sscottl		device_printf(sc->aac_dev,
2725135095Sscottl		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2726135095Sscottl		    info->KernelRevision.external.comp.major,
2727135095Sscottl		    info->KernelRevision.external.comp.minor,
2728135095Sscottl		    info->KernelRevision.external.comp.dash,
2729135095Sscottl		    info->KernelRevision.buildNumber,
2730135095Sscottl		    (u_int32_t)(info->SerialNumber & 0xffffff));
2731135095Sscottl
2732112679Sscottl		device_printf(sc->aac_dev, "Supported Options=%b\n",
2733112679Sscottl			      sc->supported_options,
2734112679Sscottl			      "\20"
2735112679Sscottl			      "\1SNAPSHOT"
2736112679Sscottl			      "\2CLUSTERS"
2737112679Sscottl			      "\3WCACHE"
2738112679Sscottl			      "\4DATA64"
2739112679Sscottl			      "\5HOSTTIME"
2740112679Sscottl			      "\6RAID50"
2741112679Sscottl			      "\7WINDOW4GB"
2742112679Sscottl			      "\10SCSIUPGD"
2743112679Sscottl			      "\11SOFTERR"
2744112679Sscottl			      "\12NORECOND"
2745112679Sscottl			      "\13SGMAP64"
2746112679Sscottl			      "\14ALARM"
2747151086Sscottl			      "\15NONDASD"
2748151086Sscottl			      "\16SCSIMGT"
2749151086Sscottl			      "\17RAIDSCSI"
2750151086Sscottl			      "\21ADPTINFO"
2751151086Sscottl			      "\22NEWCOMM"
2752151086Sscottl			      "\23ARRAY64BIT"
2753151086Sscottl			      "\24HEATSENSOR");
2754112679Sscottl	}
2755177845Semaste
2756177845Semaste	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
2757177845Semaste		fib->data[0] = 0;
2758177845Semaste		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
2759177845Semaste			device_printf(sc->aac_dev,
2760177845Semaste			    "RequestSupplementAdapterInfo failed\n");
2761177845Semaste		else
2762177845Semaste			adapter_type = ((struct aac_supplement_adapter_info *)
2763177845Semaste			    &fib->data[0])->AdapterTypeText;
2764177845Semaste	}
2765177845Semaste	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
2766177845Semaste		adapter_type,
2767203885Semaste		AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION,
2768203885Semaste		AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD);
2769177845Semaste
2770135095Sscottl	aac_release_sync_fib(sc);
2771151222Sscottl	mtx_unlock(&sc->aac_io_lock);
277265793Smsmith}
277365793Smsmith
277483114Sscottl/*
277565793Smsmith * Look up a text description of a numeric error code and return a pointer to
277665793Smsmith * same.
277765793Smsmith */
2778251070Smariusstatic const char *
2779251070Smariusaac_describe_code(const struct aac_code_lookup *table, u_int32_t code)
278065793Smsmith{
278183114Sscottl	int i;
278265793Smsmith
278383114Sscottl	for (i = 0; table[i].string != NULL; i++)
278483114Sscottl		if (table[i].code == code)
278583114Sscottl			return(table[i].string);
278683114Sscottl	return(table[i + 1].string);
278765793Smsmith}
278865793Smsmith
278983114Sscottl/*
279083114Sscottl * Management Interface
279183114Sscottl */
279265793Smsmith
279365793Smsmithstatic int
2794192450Simpaac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
279565793Smsmith{
279683114Sscottl	struct aac_softc *sc;
279765793Smsmith
279883114Sscottl	sc = dev->si_drv1;
2799177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2800212661Sattilio	device_busy(sc->aac_dev);
2801212756Sattilio	devfs_set_cdevpriv(sc, aac_cdevpriv_dtor);
280283114Sscottl
280383114Sscottl	return 0;
280465793Smsmith}
280565793Smsmith
280665793Smsmithstatic int
2807192450Simpaac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
280865793Smsmith{
280983114Sscottl	union aac_statrequest *as;
281083114Sscottl	struct aac_softc *sc;
281183114Sscottl	int error = 0;
281265793Smsmith
281383114Sscottl	as = (union aac_statrequest *)arg;
281483114Sscottl	sc = dev->si_drv1;
2815177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
281683114Sscottl
281783114Sscottl	switch (cmd) {
281883114Sscottl	case AACIO_STATS:
281983114Sscottl		switch (as->as_item) {
282083114Sscottl		case AACQ_FREE:
282183114Sscottl		case AACQ_BIO:
282283114Sscottl		case AACQ_READY:
282383114Sscottl		case AACQ_BUSY:
282483114Sscottl			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
282583114Sscottl			      sizeof(struct aac_qstat));
282683114Sscottl			break;
282783114Sscottl		default:
282883114Sscottl			error = ENOENT;
282983114Sscottl			break;
283083114Sscottl		}
283183114Sscottl	break;
2832152388Sschweikh
283383114Sscottl	case FSACTL_SENDFIB:
2834177462Semaste	case FSACTL_SEND_LARGE_FIB:
283583114Sscottl		arg = *(caddr_t*)arg;
283683114Sscottl	case FSACTL_LNX_SENDFIB:
2837177462Semaste	case FSACTL_LNX_SEND_LARGE_FIB:
2838177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
283983114Sscottl		error = aac_ioctl_sendfib(sc, arg);
284083114Sscottl		break;
2841177462Semaste	case FSACTL_SEND_RAW_SRB:
2842177462Semaste		arg = *(caddr_t*)arg;
2843177462Semaste	case FSACTL_LNX_SEND_RAW_SRB:
2844177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2845177462Semaste		error = aac_ioctl_send_raw_srb(sc, arg);
2846177462Semaste		break;
284783114Sscottl	case FSACTL_AIF_THREAD:
284883114Sscottl	case FSACTL_LNX_AIF_THREAD:
2849177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
285083114Sscottl		error = EINVAL;
285183114Sscottl		break;
285283114Sscottl	case FSACTL_OPEN_GET_ADAPTER_FIB:
285383114Sscottl		arg = *(caddr_t*)arg;
285487183Sscottl	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
2855177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2856174385Semaste		error = aac_open_aif(sc, arg);
285783114Sscottl		break;
285883114Sscottl	case FSACTL_GET_NEXT_ADAPTER_FIB:
285983114Sscottl		arg = *(caddr_t*)arg;
286083114Sscottl	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
2861177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
286283114Sscottl		error = aac_getnext_aif(sc, arg);
286383114Sscottl		break;
286483114Sscottl	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2865174385Semaste		arg = *(caddr_t*)arg;
286683114Sscottl	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
2867177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2868174385Semaste		error = aac_close_aif(sc, arg);
286983114Sscottl		break;
287083114Sscottl	case FSACTL_MINIPORT_REV_CHECK:
287183114Sscottl		arg = *(caddr_t*)arg;
287283114Sscottl	case FSACTL_LNX_MINIPORT_REV_CHECK:
2873177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
287483114Sscottl		error = aac_rev_check(sc, arg);
287583114Sscottl		break;
287683114Sscottl	case FSACTL_QUERY_DISK:
287783114Sscottl		arg = *(caddr_t*)arg;
287883114Sscottl	case FSACTL_LNX_QUERY_DISK:
2879177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
288083114Sscottl		error = aac_query_disk(sc, arg);
2881151086Sscottl		break;
288283114Sscottl	case FSACTL_DELETE_DISK:
288383114Sscottl	case FSACTL_LNX_DELETE_DISK:
288483114Sscottl		/*
288583114Sscottl		 * We don't trust the underland to tell us when to delete a
2886152388Sschweikh		 * container, rather we rely on an AIF coming from the
288783114Sscottl		 * controller
288883114Sscottl		 */
288983114Sscottl		error = 0;
289083114Sscottl		break;
2891151086Sscottl	case FSACTL_GET_PCI_INFO:
2892151086Sscottl		arg = *(caddr_t*)arg;
2893151086Sscottl	case FSACTL_LNX_GET_PCI_INFO:
2894177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
2895151086Sscottl		error = aac_get_pci_info(sc, arg);
2896151086Sscottl		break;
2897177695Semaste	case FSACTL_GET_FEATURES:
2898177695Semaste		arg = *(caddr_t*)arg;
2899177695Semaste	case FSACTL_LNX_GET_FEATURES:
2900177695Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
2901177695Semaste		error = aac_supported_features(sc, arg);
2902177695Semaste		break;
290370393Smsmith	default:
2904177567Semaste		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
290583114Sscottl		error = EINVAL;
290683114Sscottl		break;
290770393Smsmith	}
290883114Sscottl	return(error);
290965793Smsmith}
291065793Smsmith
291187183Sscottlstatic int
2912192450Simpaac_poll(struct cdev *dev, int poll_events, struct thread *td)
291387183Sscottl{
291487183Sscottl	struct aac_softc *sc;
2915179969Semaste	struct aac_fib_context *ctx;
291687183Sscottl	int revents;
291787183Sscottl
291887183Sscottl	sc = dev->si_drv1;
291987183Sscottl	revents = 0;
292087183Sscottl
2921133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
292287183Sscottl	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2923179969Semaste		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
2924179969Semaste			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
2925179969Semaste				revents |= poll_events & (POLLIN | POLLRDNORM);
2926179969Semaste				break;
2927179969Semaste			}
2928179969Semaste		}
292987183Sscottl	}
2930133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
293187183Sscottl
293287183Sscottl	if (revents == 0) {
293387183Sscottl		if (poll_events & (POLLIN | POLLRDNORM))
293487183Sscottl			selrecord(td, &sc->rcv_select);
293587183Sscottl	}
293687183Sscottl
293787183Sscottl	return (revents);
293887183Sscottl}
293987183Sscottl
2940151086Sscottlstatic void
2941151086Sscottlaac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
2942151086Sscottl{
2943151086Sscottl
2944151086Sscottl	switch (event->ev_type) {
2945151086Sscottl	case AAC_EVENT_CMFREE:
2946174774Semaste		mtx_assert(&sc->aac_io_lock, MA_OWNED);
2947166704Sluoqi		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
2948151086Sscottl			aac_add_event(sc, event);
2949151086Sscottl			return;
2950151086Sscottl		}
2951151086Sscottl		free(event, M_AACBUF);
2952151109Sscottl		wakeup(arg);
2953151086Sscottl		break;
2954151086Sscottl	default:
2955151086Sscottl		break;
2956151086Sscottl	}
2957151086Sscottl}
2958151086Sscottl
295983114Sscottl/*
296065793Smsmith * Send a FIB supplied from userspace
296165793Smsmith */
296265793Smsmithstatic int
296365793Smsmithaac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
296465793Smsmith{
296583114Sscottl	struct aac_command *cm;
296683114Sscottl	int size, error;
296765793Smsmith
2968177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
296965793Smsmith
297083114Sscottl	cm = NULL;
297165793Smsmith
297283114Sscottl	/*
297383114Sscottl	 * Get a command
297483114Sscottl	 */
2975133540Sscottl	mtx_lock(&sc->aac_io_lock);
297683114Sscottl	if (aac_alloc_command(sc, &cm)) {
2977151086Sscottl		struct aac_event *event;
2978151086Sscottl
2979151086Sscottl		event = malloc(sizeof(struct aac_event), M_AACBUF,
2980151086Sscottl		    M_NOWAIT | M_ZERO);
2981151086Sscottl		if (event == NULL) {
2982151086Sscottl			error = EBUSY;
2983174819Semaste			mtx_unlock(&sc->aac_io_lock);
2984151086Sscottl			goto out;
2985151086Sscottl		}
2986151086Sscottl		event->ev_type = AAC_EVENT_CMFREE;
2987151086Sscottl		event->ev_callback = aac_ioctl_event;
2988151086Sscottl		event->ev_arg = &cm;
2989151086Sscottl		aac_add_event(sc, event);
2990151109Sscottl		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
299183114Sscottl	}
2992157587Sscottl	mtx_unlock(&sc->aac_io_lock);
299365793Smsmith
299483114Sscottl	/*
299583114Sscottl	 * Fetch the FIB header, then re-copy to get data as well.
299683114Sscottl	 */
299783114Sscottl	if ((error = copyin(ufib, cm->cm_fib,
299883114Sscottl			    sizeof(struct aac_fib_header))) != 0)
299983114Sscottl		goto out;
300083114Sscottl	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3001177462Semaste	if (size > sc->aac_max_fib_size) {
3002177462Semaste		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3003177462Semaste			      size, sc->aac_max_fib_size);
3004177462Semaste		size = sc->aac_max_fib_size;
300583114Sscottl	}
300683114Sscottl	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
300783114Sscottl		goto out;
300883114Sscottl	cm->cm_fib->Header.Size = size;
3009150119Sscottl	cm->cm_timestamp = time_uptime;
301065793Smsmith
301183114Sscottl	/*
301283114Sscottl	 * Pass the FIB to the controller, wait for it to complete.
301383114Sscottl	 */
3014157587Sscottl	mtx_lock(&sc->aac_io_lock);
3015174819Semaste	error = aac_wait_command(cm);
3016174819Semaste	mtx_unlock(&sc->aac_io_lock);
3017174819Semaste	if (error != 0) {
3018110426Sscottl		device_printf(sc->aac_dev,
3019110426Sscottl			      "aac_wait_command return %d\n", error);
302083114Sscottl		goto out;
302187183Sscottl	}
302265793Smsmith
302383114Sscottl	/*
302483114Sscottl	 * Copy the FIB and data back out to the caller.
302583114Sscottl	 */
302683114Sscottl	size = cm->cm_fib->Header.Size;
3027177462Semaste	if (size > sc->aac_max_fib_size) {
3028177462Semaste		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3029177462Semaste			      size, sc->aac_max_fib_size);
3030177462Semaste		size = sc->aac_max_fib_size;
303183114Sscottl	}
303283114Sscottl	error = copyout(cm->cm_fib, ufib, size);
303365793Smsmith
303465793Smsmithout:
303583114Sscottl	if (cm != NULL) {
3036174819Semaste		mtx_lock(&sc->aac_io_lock);
303783114Sscottl		aac_release_command(cm);
3038174819Semaste		mtx_unlock(&sc->aac_io_lock);
303983114Sscottl	}
304083114Sscottl	return(error);
304165793Smsmith}
304265793Smsmith
304383114Sscottl/*
3044177462Semaste * Send a passthrough FIB supplied from userspace
3045177462Semaste */
3046177462Semastestatic int
3047177462Semasteaac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3048177462Semaste{
3049205160Sattilio	struct aac_command *cm;
3050205160Sattilio	struct aac_event *event;
3051205160Sattilio	struct aac_fib *fib;
3052205160Sattilio	struct aac_srb *srbcmd, *user_srb;
3053205160Sattilio	struct aac_sg_entry *sge;
3054205160Sattilio	struct aac_sg_entry64 *sge64;
3055205160Sattilio	void *srb_sg_address, *ureply;
3056205160Sattilio	uint32_t fibsize, srb_sg_bytecount;
3057205160Sattilio	int error, transfer_data;
3058205160Sattilio
3059205160Sattilio	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3060205160Sattilio
3061205160Sattilio	cm = NULL;
3062205160Sattilio	transfer_data = 0;
3063205160Sattilio	fibsize = 0;
3064205160Sattilio	user_srb = (struct aac_srb *)arg;
3065205160Sattilio
3066205160Sattilio	mtx_lock(&sc->aac_io_lock);
3067205160Sattilio	if (aac_alloc_command(sc, &cm)) {
3068205160Sattilio		 event = malloc(sizeof(struct aac_event), M_AACBUF,
3069205160Sattilio		    M_NOWAIT | M_ZERO);
3070205160Sattilio		if (event == NULL) {
3071205160Sattilio			error = EBUSY;
3072205160Sattilio			mtx_unlock(&sc->aac_io_lock);
3073205160Sattilio			goto out;
3074205160Sattilio		}
3075205160Sattilio		event->ev_type = AAC_EVENT_CMFREE;
3076205160Sattilio		event->ev_callback = aac_ioctl_event;
3077205160Sattilio		event->ev_arg = &cm;
3078205160Sattilio		aac_add_event(sc, event);
3079205160Sattilio		msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0);
3080205160Sattilio	}
3081205160Sattilio	mtx_unlock(&sc->aac_io_lock);
3082205160Sattilio
3083205160Sattilio	cm->cm_data = NULL;
3084205160Sattilio	fib = cm->cm_fib;
3085205160Sattilio	srbcmd = (struct aac_srb *)fib->data;
3086205160Sattilio	error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t));
3087205160Sattilio	if (error != 0)
3088205160Sattilio		goto out;
3089205160Sattilio	if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) {
3090205160Sattilio		error = EINVAL;
3091205160Sattilio		goto out;
3092205160Sattilio	}
3093205160Sattilio	error = copyin(user_srb, srbcmd, fibsize);
3094205160Sattilio	if (error != 0)
3095205160Sattilio		goto out;
3096205160Sattilio	srbcmd->function = 0;
3097205160Sattilio	srbcmd->retry_limit = 0;
3098205160Sattilio	if (srbcmd->sg_map.SgCount > 1) {
3099205160Sattilio		error = EINVAL;
3100205160Sattilio		goto out;
3101205160Sattilio	}
3102205160Sattilio
3103205160Sattilio	/* Retrieve correct SG entries. */
3104205160Sattilio	if (fibsize == (sizeof(struct aac_srb) +
3105205160Sattilio	    srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) {
3106205160Sattilio		sge = srbcmd->sg_map.SgEntry;
3107205160Sattilio		sge64 = NULL;
3108205160Sattilio		srb_sg_bytecount = sge->SgByteCount;
3109205167Sattilio		srb_sg_address = (void *)(uintptr_t)sge->SgAddress;
3110205160Sattilio	}
3111205160Sattilio#ifdef __amd64__
3112205160Sattilio	else if (fibsize == (sizeof(struct aac_srb) +
3113205160Sattilio	    srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) {
3114205160Sattilio		sge = NULL;
3115205160Sattilio		sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry;
3116205160Sattilio		srb_sg_bytecount = sge64->SgByteCount;
3117205160Sattilio		srb_sg_address = (void *)sge64->SgAddress;
3118205160Sattilio		if (sge64->SgAddress > 0xffffffffull &&
3119205160Sattilio		    (sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
3120205160Sattilio			error = EINVAL;
3121205160Sattilio			goto out;
3122205160Sattilio		}
3123205160Sattilio	}
3124205160Sattilio#endif
3125205160Sattilio	else {
3126205160Sattilio		error = EINVAL;
3127205160Sattilio		goto out;
3128205160Sattilio	}
3129205160Sattilio	ureply = (char *)arg + fibsize;
3130205160Sattilio	srbcmd->data_len = srb_sg_bytecount;
3131205160Sattilio	if (srbcmd->sg_map.SgCount == 1)
3132205160Sattilio		transfer_data = 1;
3133205160Sattilio
3134205160Sattilio	cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map;
3135205160Sattilio	if (transfer_data) {
3136205160Sattilio		cm->cm_datalen = srb_sg_bytecount;
3137205160Sattilio		cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT);
3138205160Sattilio		if (cm->cm_data == NULL) {
3139205160Sattilio			error = ENOMEM;
3140205160Sattilio			goto out;
3141205160Sattilio		}
3142205160Sattilio		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)
3143205160Sattilio			cm->cm_flags |= AAC_CMD_DATAIN;
3144205160Sattilio		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) {
3145205160Sattilio			cm->cm_flags |= AAC_CMD_DATAOUT;
3146205160Sattilio			error = copyin(srb_sg_address, cm->cm_data,
3147205160Sattilio			    cm->cm_datalen);
3148205160Sattilio			if (error != 0)
3149205160Sattilio				goto out;
3150205160Sattilio		}
3151205160Sattilio	}
3152205160Sattilio
3153205160Sattilio	fib->Header.Size = sizeof(struct aac_fib_header) +
3154205160Sattilio	    sizeof(struct aac_srb);
3155205160Sattilio	fib->Header.XferState =
3156205160Sattilio	    AAC_FIBSTATE_HOSTOWNED   |
3157205160Sattilio	    AAC_FIBSTATE_INITIALISED |
3158205160Sattilio	    AAC_FIBSTATE_EMPTY       |
3159205160Sattilio	    AAC_FIBSTATE_FROMHOST    |
3160205160Sattilio	    AAC_FIBSTATE_REXPECTED   |
3161205160Sattilio	    AAC_FIBSTATE_NORM        |
3162205160Sattilio	    AAC_FIBSTATE_ASYNC       |
3163205160Sattilio	    AAC_FIBSTATE_FAST_RESPONSE;
3164205160Sattilio	fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ?
3165205160Sattilio	    ScsiPortCommandU64 : ScsiPortCommand;
3166205160Sattilio
3167205160Sattilio	mtx_lock(&sc->aac_io_lock);
3168205160Sattilio	aac_wait_command(cm);
3169205160Sattilio	mtx_unlock(&sc->aac_io_lock);
3170205160Sattilio
3171205160Sattilio	if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) {
3172205160Sattilio		error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen);
3173205160Sattilio		if (error != 0)
3174205160Sattilio			goto out;
3175205160Sattilio	}
3176205160Sattilio	error = copyout(fib->data, ureply, sizeof(struct aac_srb_response));
3177205160Sattilioout:
3178205160Sattilio	if (cm != NULL) {
3179205160Sattilio		if (cm->cm_data != NULL)
3180205160Sattilio			free(cm->cm_data, M_AACBUF);
3181205160Sattilio		mtx_lock(&sc->aac_io_lock);
3182205160Sattilio		aac_release_command(cm);
3183205160Sattilio		mtx_unlock(&sc->aac_io_lock);
3184205160Sattilio	}
3185205160Sattilio	return(error);
3186177462Semaste}
3187177462Semaste
3188177462Semaste/*
3189212756Sattilio * cdevpriv interface private destructor.
3190212756Sattilio */
3191212756Sattiliostatic void
3192212756Sattilioaac_cdevpriv_dtor(void *arg)
3193212756Sattilio{
3194212756Sattilio	struct aac_softc *sc;
3195212756Sattilio
3196212756Sattilio	sc = arg;
3197212756Sattilio	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3198212756Sattilio	mtx_lock(&Giant);
3199212756Sattilio	device_unbusy(sc->aac_dev);
3200212756Sattilio	mtx_unlock(&Giant);
3201212756Sattilio}
3202212756Sattilio
3203212756Sattilio/*
320465793Smsmith * Handle an AIF sent to us by the controller; queue it for later reference.
320582527Sscottl * If the queue fills up, then drop the older entries.
320665793Smsmith */
320765793Smsmithstatic void
320882527Sscottlaac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
320965793Smsmith{
321083114Sscottl	struct aac_aif_command *aif;
321183114Sscottl	struct aac_container *co, *co_next;
3212174385Semaste	struct aac_fib_context *ctx;
3213177557Semaste	struct aac_mntinforesp *mir;
3214174385Semaste	int next, current, found;
3215115760Sscottl	int count = 0, added = 0, i = 0;
3216213272Semaste	uint32_t channel;
321765793Smsmith
3218177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
321965793Smsmith
322083114Sscottl	aif = (struct aac_aif_command*)&fib->data[0];
322183114Sscottl	aac_print_aif(sc, aif);
322282527Sscottl
322383114Sscottl	/* Is it an event that we should care about? */
322483114Sscottl	switch (aif->command) {
322583114Sscottl	case AifCmdEventNotify:
322683114Sscottl		switch (aif->data.EN.type) {
322783114Sscottl		case AifEnAddContainer:
322883114Sscottl		case AifEnDeleteContainer:
322983114Sscottl			/*
3230152388Sschweikh			 * A container was added or deleted, but the message
323183114Sscottl			 * doesn't tell us anything else!  Re-enumerate the
323283114Sscottl			 * containers and sort things out.
323383114Sscottl			 */
3234130006Sscottl			aac_alloc_sync_fib(sc, &fib);
323583114Sscottl			do {
323683114Sscottl				/*
323783114Sscottl				 * Ask the controller for its containers one at
323883114Sscottl				 * a time.
323983114Sscottl				 * XXX What if the controller's list changes
324083114Sscottl				 * midway through this enumaration?
324183114Sscottl				 * XXX This should be done async.
324283114Sscottl				 */
3243177557Semaste				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
324483114Sscottl					continue;
3245177557Semaste				if (i == 0)
3246177557Semaste					count = mir->MntRespCount;
324783114Sscottl				/*
324883114Sscottl				 * Check the container against our list.
324983114Sscottl				 * co->co_found was already set to 0 in a
325083114Sscottl				 * previous run.
325183114Sscottl				 */
325295350Sscottl				if ((mir->Status == ST_OK) &&
325395350Sscottl				    (mir->MntTable[0].VolType != CT_NONE)) {
325483114Sscottl					found = 0;
325583114Sscottl					TAILQ_FOREACH(co,
3256152388Sschweikh						      &sc->aac_container_tqh,
325783114Sscottl						      co_link) {
325883114Sscottl						if (co->co_mntobj.ObjectId ==
325995350Sscottl						    mir->MntTable[0].ObjectId) {
326083114Sscottl							co->co_found = 1;
326183114Sscottl							found = 1;
326283114Sscottl							break;
326383114Sscottl						}
326483114Sscottl					}
326583114Sscottl					/*
326683114Sscottl					 * If the container matched, continue
326783114Sscottl					 * in the list.
326883114Sscottl					 */
326983114Sscottl					if (found) {
327083114Sscottl						i++;
327183114Sscottl						continue;
327283114Sscottl					}
327383114Sscottl
327483114Sscottl					/*
327583114Sscottl					 * This is a new container.  Do all the
3276110426Sscottl					 * appropriate things to set it up.
3277110426Sscottl					 */
327895350Sscottl					aac_add_container(sc, mir, 1);
327983114Sscottl					added = 1;
328083114Sscottl				}
328183114Sscottl				i++;
3282115760Sscottl			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
328395350Sscottl			aac_release_sync_fib(sc);
328483114Sscottl
328583114Sscottl			/*
328683114Sscottl			 * Go through our list of containers and see which ones
328783114Sscottl			 * were not marked 'found'.  Since the controller didn't
328883114Sscottl			 * list them they must have been deleted.  Do the
328983114Sscottl			 * appropriate steps to destroy the device.  Also reset
329083114Sscottl			 * the co->co_found field.
329183114Sscottl			 */
329283114Sscottl			co = TAILQ_FIRST(&sc->aac_container_tqh);
329383114Sscottl			while (co != NULL) {
329483114Sscottl				if (co->co_found == 0) {
3295151086Sscottl					mtx_unlock(&sc->aac_io_lock);
3296196403Sjhb					mtx_lock(&Giant);
329783114Sscottl					device_delete_child(sc->aac_dev,
329883114Sscottl							    co->co_disk);
3299196403Sjhb					mtx_unlock(&Giant);
3300151086Sscottl					mtx_lock(&sc->aac_io_lock);
330183114Sscottl					co_next = TAILQ_NEXT(co, co_link);
3302133540Sscottl					mtx_lock(&sc->aac_container_lock);
330383114Sscottl					TAILQ_REMOVE(&sc->aac_container_tqh, co,
330483114Sscottl						     co_link);
3305133540Sscottl					mtx_unlock(&sc->aac_container_lock);
3306133541Sscottl					free(co, M_AACBUF);
330783114Sscottl					co = co_next;
330883114Sscottl				} else {
330983114Sscottl					co->co_found = 0;
331083114Sscottl					co = TAILQ_NEXT(co, co_link);
331183114Sscottl				}
331282527Sscottl			}
331382527Sscottl
331483114Sscottl			/* Attach the newly created containers */
3315151086Sscottl			if (added) {
3316151086Sscottl				mtx_unlock(&sc->aac_io_lock);
3317196403Sjhb				mtx_lock(&Giant);
331883114Sscottl				bus_generic_attach(sc->aac_dev);
3319196403Sjhb				mtx_unlock(&Giant);
3320151086Sscottl				mtx_lock(&sc->aac_io_lock);
3321151086Sscottl			}
3322152388Sschweikh
3323105528Sphk			break;
332482527Sscottl
3325213272Semaste		case AifEnEnclosureManagement:
3326213272Semaste			switch (aif->data.EN.data.EEE.eventType) {
3327213272Semaste			case AIF_EM_DRIVE_INSERTION:
3328213272Semaste			case AIF_EM_DRIVE_REMOVAL:
3329213272Semaste				channel = aif->data.EN.data.EEE.unitID;
3330213272Semaste				if (sc->cam_rescan_cb != NULL)
3331213272Semaste					sc->cam_rescan_cb(sc,
3332213272Semaste					    (channel >> 24) & 0xF,
3333213272Semaste					    (channel & 0xFFFF));
3334213272Semaste				break;
3335213272Semaste			}
3336213272Semaste			break;
3337213272Semaste
3338213272Semaste		case AifEnAddJBOD:
3339213272Semaste		case AifEnDeleteJBOD:
3340213272Semaste			channel = aif->data.EN.data.ECE.container;
3341213272Semaste			if (sc->cam_rescan_cb != NULL)
3342213272Semaste				sc->cam_rescan_cb(sc, (channel >> 24) & 0xF,
3343213272Semaste				    AAC_CAM_TARGET_WILDCARD);
3344213272Semaste			break;
3345213272Semaste
334683114Sscottl		default:
334783114Sscottl			break;
334882527Sscottl		}
334982527Sscottl
335082527Sscottl	default:
335183114Sscottl		break;
335282527Sscottl	}
335382527Sscottl
335483114Sscottl	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3355133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
3356174385Semaste	current = sc->aifq_idx;
3357174385Semaste	next = (current + 1) % AAC_AIFQ_LENGTH;
3358174385Semaste	if (next == 0)
3359174385Semaste		sc->aifq_filled = 1;
3360174385Semaste	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3361174385Semaste	/* modify AIF contexts */
3362174385Semaste	if (sc->aifq_filled) {
3363174385Semaste		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3364174385Semaste			if (next == ctx->ctx_idx)
3365174385Semaste				ctx->ctx_wrap = 1;
3366174385Semaste			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3367174385Semaste				ctx->ctx_idx = next;
3368174385Semaste		}
336983114Sscottl	}
3370174385Semaste	sc->aifq_idx = next;
3371174385Semaste	/* On the off chance that someone is sleeping for an aif... */
3372174385Semaste	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
3373174385Semaste		wakeup(sc->aac_aifq);
3374174385Semaste	/* Wakeup any poll()ers */
3375174385Semaste	selwakeuppri(&sc->rcv_select, PRIBIO);
3376133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
337765793Smsmith}
337865793Smsmith
337983114Sscottl/*
338070393Smsmith * Return the Revision of the driver to userspace and check to see if the
338182527Sscottl * userspace app is possibly compatible.  This is extremely bogus since
338282527Sscottl * our driver doesn't follow Adaptec's versioning system.  Cheat by just
338382527Sscottl * returning what the card reported.
338465793Smsmith */
338565793Smsmithstatic int
338681189Sscottlaac_rev_check(struct aac_softc *sc, caddr_t udata)
338765793Smsmith{
338883114Sscottl	struct aac_rev_check rev_check;
338983114Sscottl	struct aac_rev_check_resp rev_check_resp;
339083114Sscottl	int error = 0;
339165793Smsmith
3392177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
339365793Smsmith
339483114Sscottl	/*
339583114Sscottl	 * Copyin the revision struct from userspace
339683114Sscottl	 */
339783114Sscottl	if ((error = copyin(udata, (caddr_t)&rev_check,
339881082Sscottl			sizeof(struct aac_rev_check))) != 0) {
339983114Sscottl		return error;
340083114Sscottl	}
340165793Smsmith
3402177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
340383114Sscottl	      rev_check.callingRevision.buildNumber);
340465793Smsmith
340583114Sscottl	/*
340683114Sscottl	 * Doctor up the response struct.
340783114Sscottl	 */
340883114Sscottl	rev_check_resp.possiblyCompatible = 1;
3409203885Semaste	rev_check_resp.adapterSWRevision.external.comp.major =
3410203885Semaste	    AAC_DRIVER_MAJOR_VERSION;
3411203885Semaste	rev_check_resp.adapterSWRevision.external.comp.minor =
3412203885Semaste	    AAC_DRIVER_MINOR_VERSION;
3413203885Semaste	rev_check_resp.adapterSWRevision.external.comp.type =
3414203885Semaste	    AAC_DRIVER_TYPE;
3415203885Semaste	rev_check_resp.adapterSWRevision.external.comp.dash =
3416203885Semaste	    AAC_DRIVER_BUGFIX_LEVEL;
341783114Sscottl	rev_check_resp.adapterSWRevision.buildNumber =
3418203885Semaste	    AAC_DRIVER_BUILD;
341965793Smsmith
342083114Sscottl	return(copyout((caddr_t)&rev_check_resp, udata,
342183114Sscottl			sizeof(struct aac_rev_check_resp)));
342265793Smsmith}
342365793Smsmith
342483114Sscottl/*
3425174385Semaste * Pass the fib context to the caller
3426174385Semaste */
3427174385Semastestatic int
3428174385Semasteaac_open_aif(struct aac_softc *sc, caddr_t arg)
3429174385Semaste{
3430174385Semaste	struct aac_fib_context *fibctx, *ctx;
3431174385Semaste	int error = 0;
3432174385Semaste
3433177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3434174385Semaste
3435174385Semaste	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3436174385Semaste	if (fibctx == NULL)
3437174385Semaste		return (ENOMEM);
3438174385Semaste
3439174385Semaste	mtx_lock(&sc->aac_aifq_lock);
3440174385Semaste	/* all elements are already 0, add to queue */
3441174385Semaste	if (sc->fibctx == NULL)
3442174385Semaste		sc->fibctx = fibctx;
3443174385Semaste	else {
3444174385Semaste		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3445174385Semaste			;
3446174385Semaste		ctx->next = fibctx;
3447174385Semaste		fibctx->prev = ctx;
3448174385Semaste	}
3449174385Semaste
3450174385Semaste	/* evaluate unique value */
3451174385Semaste	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3452174385Semaste	ctx = sc->fibctx;
3453174385Semaste	while (ctx != fibctx) {
3454174385Semaste		if (ctx->unique == fibctx->unique) {
3455174385Semaste			fibctx->unique++;
3456174385Semaste			ctx = sc->fibctx;
3457174385Semaste		} else {
3458174385Semaste			ctx = ctx->next;
3459174385Semaste		}
3460174385Semaste	}
3461174385Semaste	mtx_unlock(&sc->aac_aifq_lock);
3462174385Semaste
3463174385Semaste	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3464174385Semaste	if (error)
3465174385Semaste		aac_close_aif(sc, (caddr_t)ctx);
3466174385Semaste	return error;
3467174385Semaste}
3468174385Semaste
3469174385Semaste/*
3470174385Semaste * Close the caller's fib context
3471174385Semaste */
3472174385Semastestatic int
3473174385Semasteaac_close_aif(struct aac_softc *sc, caddr_t arg)
3474174385Semaste{
3475174385Semaste	struct aac_fib_context *ctx;
3476174385Semaste
3477177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3478174385Semaste
3479174385Semaste	mtx_lock(&sc->aac_aifq_lock);
3480174385Semaste	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3481174385Semaste		if (ctx->unique == *(uint32_t *)&arg) {
3482174385Semaste			if (ctx == sc->fibctx)
3483174385Semaste				sc->fibctx = NULL;
3484174385Semaste			else {
3485174385Semaste				ctx->prev->next = ctx->next;
3486174385Semaste				if (ctx->next)
3487174385Semaste					ctx->next->prev = ctx->prev;
3488174385Semaste			}
3489174385Semaste			break;
3490174385Semaste		}
3491174385Semaste	}
3492174385Semaste	mtx_unlock(&sc->aac_aifq_lock);
3493174385Semaste	if (ctx)
3494174385Semaste		free(ctx, M_AACBUF);
3495174385Semaste
3496174385Semaste	return 0;
3497174385Semaste}
3498174385Semaste
3499174385Semaste/*
350065793Smsmith * Pass the caller the next AIF in their queue
350165793Smsmith */
350265793Smsmithstatic int
350381189Sscottlaac_getnext_aif(struct aac_softc *sc, caddr_t arg)
350465793Smsmith{
350583114Sscottl	struct get_adapter_fib_ioctl agf;
3506174385Semaste	struct aac_fib_context *ctx;
3507111691Sscottl	int error;
350865793Smsmith
3509177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
351065793Smsmith
351183114Sscottl	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3512174385Semaste		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3513174385Semaste			if (agf.AdapterFibContext == ctx->unique)
3514174385Semaste				break;
3515174385Semaste		}
3516174385Semaste		if (!ctx)
3517174385Semaste			return (EFAULT);
351865793Smsmith
3519174385Semaste		error = aac_return_aif(sc, ctx, agf.AifFib);
3520174385Semaste		if (error == EAGAIN && agf.Wait) {
3521177567Semaste			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
3522174385Semaste			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
3523174385Semaste			while (error == EAGAIN) {
3524174385Semaste				error = tsleep(sc->aac_aifq, PRIBIO |
3525174385Semaste					       PCATCH, "aacaif", 0);
3526174385Semaste				if (error == 0)
3527174385Semaste					error = aac_return_aif(sc, ctx, agf.AifFib);
352883114Sscottl			}
3529174385Semaste			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
353065793Smsmith		}
353165793Smsmith	}
353283114Sscottl	return(error);
353365793Smsmith}
353465793Smsmith
353583114Sscottl/*
353670393Smsmith * Hand the next AIF off the top of the queue out to userspace.
353770393Smsmith */
353870393Smsmithstatic int
3539174385Semasteaac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
354070393Smsmith{
3541174385Semaste	int current, error;
354270393Smsmith
3543177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
354470393Smsmith
3545133540Sscottl	mtx_lock(&sc->aac_aifq_lock);
3546174385Semaste	current = ctx->ctx_idx;
3547174385Semaste	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3548174385Semaste		/* empty */
3549133540Sscottl		mtx_unlock(&sc->aac_aifq_lock);
3550121173Sscottl		return (EAGAIN);
355183114Sscottl	}
3552174385Semaste	error =
3553174385Semaste		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
3554121173Sscottl	if (error)
3555121173Sscottl		device_printf(sc->aac_dev,
3556121173Sscottl		    "aac_return_aif: copyout returned %d\n", error);
3557174385Semaste	else {
3558174385Semaste		ctx->ctx_wrap = 0;
3559174385Semaste		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3560174385Semaste	}
3561133540Sscottl	mtx_unlock(&sc->aac_aifq_lock);
356283114Sscottl	return(error);
356370393Smsmith}
356482527Sscottl
3565151086Sscottlstatic int
3566151086Sscottlaac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
3567151086Sscottl{
3568151086Sscottl	struct aac_pci_info {
3569151086Sscottl		u_int32_t bus;
3570151086Sscottl		u_int32_t slot;
3571151086Sscottl	} pciinf;
3572151086Sscottl	int error;
3573151086Sscottl
3574177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3575151086Sscottl
3576151086Sscottl	pciinf.bus = pci_get_bus(sc->aac_dev);
3577151086Sscottl	pciinf.slot = pci_get_slot(sc->aac_dev);
3578151086Sscottl
3579151086Sscottl	error = copyout((caddr_t)&pciinf, uptr,
3580151086Sscottl			sizeof(struct aac_pci_info));
3581151086Sscottl
3582151086Sscottl	return (error);
3583151086Sscottl}
3584151086Sscottl
3585177695Semastestatic int
3586177695Semasteaac_supported_features(struct aac_softc *sc, caddr_t uptr)
3587177695Semaste{
3588177695Semaste	struct aac_features f;
3589177695Semaste	int error;
3590177695Semaste
3591177695Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3592177695Semaste
3593177695Semaste	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
3594177695Semaste		return (error);
3595177695Semaste
3596177695Semaste	/*
3597177695Semaste	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
3598177695Semaste	 * ALL zero in the featuresState, the driver will return the current
3599177695Semaste	 * state of all the supported features, the data field will not be
3600177695Semaste	 * valid.
3601177695Semaste	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
3602177695Semaste	 * a specific bit set in the featuresState, the driver will return the
3603177695Semaste	 * current state of this specific feature and whatever data that are
3604177695Semaste	 * associated with the feature in the data field or perform whatever
3605177695Semaste	 * action needed indicates in the data field.
3606177695Semaste	 */
3607197016Semaste	if (f.feat.fValue == 0) {
3608177695Semaste		f.feat.fBits.largeLBA =
3609177695Semaste		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
3610177695Semaste		/* TODO: In the future, add other features state here as well */
3611177695Semaste	} else {
3612177695Semaste		if (f.feat.fBits.largeLBA)
3613177695Semaste			f.feat.fBits.largeLBA =
3614177695Semaste			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
3615177695Semaste		/* TODO: Add other features state and data in the future */
3616177695Semaste	}
3617177695Semaste
3618177695Semaste	error = copyout(&f, uptr, sizeof (f));
3619177695Semaste	return (error);
3620177695Semaste}
3621177695Semaste
362283114Sscottl/*
362382527Sscottl * Give the userland some information about the container.  The AAC arch
362482527Sscottl * expects the driver to be a SCSI passthrough type driver, so it expects
362582527Sscottl * the containers to have b:t:l numbers.  Fake it.
362682527Sscottl */
362782527Sscottlstatic int
362882527Sscottlaac_query_disk(struct aac_softc *sc, caddr_t uptr)
362982527Sscottl{
363083114Sscottl	struct aac_query_disk query_disk;
363183114Sscottl	struct aac_container *co;
363283114Sscottl	struct aac_disk	*disk;
363383114Sscottl	int error, id;
363482527Sscottl
3635177567Semaste	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
363682527Sscottl
363783114Sscottl	disk = NULL;
363882527Sscottl
363983114Sscottl	error = copyin(uptr, (caddr_t)&query_disk,
364083114Sscottl		       sizeof(struct aac_query_disk));
364183114Sscottl	if (error)
364283114Sscottl		return (error);
364382527Sscottl
364483114Sscottl	id = query_disk.ContainerNumber;
364583114Sscottl	if (id == -1)
364683114Sscottl		return (EINVAL);
364782527Sscottl
3648133540Sscottl	mtx_lock(&sc->aac_container_lock);
364983114Sscottl	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
365083114Sscottl		if (co->co_mntobj.ObjectId == id)
365183114Sscottl			break;
365283114Sscottl		}
365382527Sscottl
3654105528Sphk	if (co == NULL) {
365583114Sscottl			query_disk.Valid = 0;
365683114Sscottl			query_disk.Locked = 0;
365783114Sscottl			query_disk.Deleted = 1;		/* XXX is this right? */
3658105528Sphk	} else {
3659105528Sphk		disk = device_get_softc(co->co_disk);
3660105528Sphk		query_disk.Valid = 1;
3661105528Sphk		query_disk.Locked =
3662105528Sphk		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
3663105528Sphk		query_disk.Deleted = 0;
3664105528Sphk		query_disk.Bus = device_get_unit(sc->aac_dev);
3665105528Sphk		query_disk.Target = disk->unit;
3666105528Sphk		query_disk.Lun = 0;
3667105528Sphk		query_disk.UnMapped = 0;
3668111525Sscottl		sprintf(&query_disk.diskDeviceName[0], "%s%d",
3669198525Semaste			disk->ad_disk->d_name, disk->ad_disk->d_unit);
3670105528Sphk	}
3671133540Sscottl	mtx_unlock(&sc->aac_container_lock);
367282527Sscottl
367383114Sscottl	error = copyout((caddr_t)&query_disk, uptr,
367483114Sscottl			sizeof(struct aac_query_disk));
367583114Sscottl
367683114Sscottl	return (error);
367782527Sscottl}
367882527Sscottl
367995536Sscottlstatic void
368095536Sscottlaac_get_bus_info(struct aac_softc *sc)
368195536Sscottl{
368295536Sscottl	struct aac_fib *fib;
368395536Sscottl	struct aac_ctcfg *c_cmd;
368495536Sscottl	struct aac_ctcfg_resp *c_resp;
368595536Sscottl	struct aac_vmioctl *vmi;
368695536Sscottl	struct aac_vmi_businf_resp *vmi_resp;
368795536Sscottl	struct aac_getbusinf businfo;
3688110426Sscottl	struct aac_sim *caminf;
368995536Sscottl	device_t child;
369095536Sscottl	int i, found, error;
369195536Sscottl
3692151893Scsjp	mtx_lock(&sc->aac_io_lock);
3693130006Sscottl	aac_alloc_sync_fib(sc, &fib);
369495536Sscottl	c_cmd = (struct aac_ctcfg *)&fib->data[0];
369595966Sscottl	bzero(c_cmd, sizeof(struct aac_ctcfg));
369695536Sscottl
369795536Sscottl	c_cmd->Command = VM_ContainerConfig;
369895536Sscottl	c_cmd->cmd = CT_GET_SCSI_METHOD;
369995536Sscottl	c_cmd->param = 0;
370095536Sscottl
370195536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
370295536Sscottl	    sizeof(struct aac_ctcfg));
370395536Sscottl	if (error) {
370495536Sscottl		device_printf(sc->aac_dev, "Error %d sending "
370595536Sscottl		    "VM_ContainerConfig command\n", error);
370695536Sscottl		aac_release_sync_fib(sc);
3707151893Scsjp		mtx_unlock(&sc->aac_io_lock);
370895536Sscottl		return;
370995536Sscottl	}
371095536Sscottl
371195536Sscottl	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
371295536Sscottl	if (c_resp->Status != ST_OK) {
371395536Sscottl		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
371495536Sscottl		    c_resp->Status);
371595536Sscottl		aac_release_sync_fib(sc);
3716151893Scsjp		mtx_unlock(&sc->aac_io_lock);
371795536Sscottl		return;
371895536Sscottl	}
371995536Sscottl
372095536Sscottl	sc->scsi_method_id = c_resp->param;
372195536Sscottl
372295536Sscottl	vmi = (struct aac_vmioctl *)&fib->data[0];
372395966Sscottl	bzero(vmi, sizeof(struct aac_vmioctl));
372495966Sscottl
372595536Sscottl	vmi->Command = VM_Ioctl;
372695536Sscottl	vmi->ObjType = FT_DRIVE;
372795536Sscottl	vmi->MethId = sc->scsi_method_id;
372895536Sscottl	vmi->ObjId = 0;
372995536Sscottl	vmi->IoctlCmd = GetBusInfo;
373095536Sscottl
373195536Sscottl	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3732177463Semaste	    sizeof(struct aac_vmi_businf_resp));
373395536Sscottl	if (error) {
373495536Sscottl		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
373595536Sscottl		    error);
373695536Sscottl		aac_release_sync_fib(sc);
3737151893Scsjp		mtx_unlock(&sc->aac_io_lock);
373895536Sscottl		return;
373995536Sscottl	}
374095536Sscottl
374195536Sscottl	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
374295536Sscottl	if (vmi_resp->Status != ST_OK) {
374395536Sscottl		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
374495536Sscottl		    vmi_resp->Status);
374595536Sscottl		aac_release_sync_fib(sc);
3746151893Scsjp		mtx_unlock(&sc->aac_io_lock);
374795536Sscottl		return;
374895536Sscottl	}
374995536Sscottl
375095536Sscottl	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
375195536Sscottl	aac_release_sync_fib(sc);
3752151893Scsjp	mtx_unlock(&sc->aac_io_lock);
375395536Sscottl
375495536Sscottl	found = 0;
375595536Sscottl	for (i = 0; i < businfo.BusCount; i++) {
375695536Sscottl		if (businfo.BusValid[i] != AAC_BUS_VALID)
375795536Sscottl			continue;
375895536Sscottl
3759110428Sscottl		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3760110428Sscottl		    M_AACBUF, M_NOWAIT | M_ZERO);
3761143838Sscottl		if (caminf == NULL) {
3762143838Sscottl			device_printf(sc->aac_dev,
3763143838Sscottl			    "No memory to add passthrough bus %d\n", i);
3764143838Sscottl			break;
3765151086Sscottl		};
376695536Sscottl
376795536Sscottl		child = device_add_child(sc->aac_dev, "aacp", -1);
376895536Sscottl		if (child == NULL) {
3769143838Sscottl			device_printf(sc->aac_dev,
3770143838Sscottl			    "device_add_child failed for passthrough bus %d\n",
3771143838Sscottl			    i);
3772143838Sscottl			free(caminf, M_AACBUF);
3773152388Sschweikh			break;
377495536Sscottl		}
377595536Sscottl
377695536Sscottl		caminf->TargetsPerBus = businfo.TargetsPerBus;
377795536Sscottl		caminf->BusNumber = i;
377895536Sscottl		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
377995536Sscottl		caminf->aac_sc = sc;
3780110432Sscottl		caminf->sim_dev = child;
378195536Sscottl
378295536Sscottl		device_set_ivars(child, caminf);
378395536Sscottl		device_set_desc(child, "SCSI Passthrough Bus");
3784110426Sscottl		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
378595536Sscottl
378695536Sscottl		found = 1;
378795536Sscottl	}
378895536Sscottl
378995536Sscottl	if (found)
379095536Sscottl		bus_generic_attach(sc->aac_dev);
379195536Sscottl}
3792