aac.c revision 196037
1170530Ssam/*-
2178354Ssam * Copyright (c) 2000 Michael Smith
3170530Ssam * Copyright (c) 2001 Scott Long
4170530Ssam * Copyright (c) 2000 BSDi
5170530Ssam * Copyright (c) 2001 Adaptec, Inc.
6170530Ssam * All rights reserved.
7170530Ssam *
8170530Ssam * Redistribution and use in source and binary forms, with or without
9170530Ssam * modification, are permitted provided that the following conditions
10170530Ssam * are met:
11170530Ssam * 1. Redistributions of source code must retain the above copyright
12170530Ssam *    notice, this list of conditions and the following disclaimer.
13170530Ssam * 2. Redistributions in binary form must reproduce the above copyright
14170530Ssam *    notice, this list of conditions and the following disclaimer in the
15170530Ssam *    documentation and/or other materials provided with the distribution.
16170530Ssam *
17170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18170530Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19170530Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20170530Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21170530Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22170530Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23170530Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24170530Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25170530Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26170530Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27170530Ssam * SUCH DAMAGE.
28170530Ssam */
29170530Ssam
30170530Ssam#include <sys/cdefs.h>
31170530Ssam__FBSDID("$FreeBSD: head/sys/dev/aac/aac.c 196037 2009-08-02 14:28:40Z attilio $");
32170530Ssam
33170530Ssam/*
34170530Ssam * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
35170530Ssam */
36178354Ssam#define AAC_DRIVER_VERSION		0x02000000
37170530Ssam#define AAC_DRIVERNAME			"aac"
38170530Ssam
39170530Ssam#include "opt_aac.h"
40170530Ssam
41170530Ssam/* #include <stddef.h> */
42170530Ssam#include <sys/param.h>
43170530Ssam#include <sys/systm.h>
44170530Ssam#include <sys/malloc.h>
45170530Ssam#include <sys/kernel.h>
46170530Ssam#include <sys/kthread.h>
47170530Ssam#include <sys/sysctl.h>
48170530Ssam#include <sys/poll.h>
49170530Ssam#include <sys/ioccom.h>
50178354Ssam
51170530Ssam#include <sys/bus.h>
52170530Ssam#include <sys/conf.h>
53170530Ssam#include <sys/signalvar.h>
54170530Ssam#include <sys/time.h>
55170530Ssam#include <sys/eventhandler.h>
56178354Ssam#include <sys/rman.h>
57178354Ssam
58178354Ssam#include <machine/bus.h>
59178354Ssam#include <sys/bus_dma.h>
60178354Ssam#include <machine/resource.h>
61178354Ssam
62178354Ssam#include <dev/pci/pcireg.h>
63178354Ssam#include <dev/pci/pcivar.h>
64178354Ssam
65178354Ssam#include <dev/aac/aacreg.h>
66178354Ssam#include <sys/aac_ioctl.h>
67178354Ssam#include <dev/aac/aacvar.h>
68178354Ssam#include <dev/aac/aac_tables.h>
69178354Ssam
70178354Ssamstatic void	aac_startup(void *arg);
71178354Ssamstatic void	aac_add_container(struct aac_softc *sc,
72178354Ssam				  struct aac_mntinforesp *mir, int f);
73170530Ssamstatic void	aac_get_bus_info(struct aac_softc *sc);
74170530Ssamstatic void	aac_daemon(void *arg);
75170530Ssam
76170530Ssam/* Command Processing */
77170530Ssamstatic void	aac_timeout(struct aac_softc *sc);
78170530Ssamstatic void	aac_complete(void *context, int pending);
79170530Ssamstatic int	aac_bio_command(struct aac_softc *sc, struct aac_command **cmp);
80170530Ssamstatic void	aac_bio_complete(struct aac_command *cm);
81173273Ssamstatic int	aac_wait_command(struct aac_command *cm);
82173273Ssamstatic void	aac_command_thread(struct aac_softc *sc);
83173273Ssam
84173273Ssam/* Command Buffer Management */
85173273Ssamstatic void	aac_map_command_sg(void *arg, bus_dma_segment_t *segs,
86178354Ssam				   int nseg, int error);
87178354Ssamstatic void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
88178354Ssam				       int nseg, int error);
89173273Ssamstatic int	aac_alloc_commands(struct aac_softc *sc);
90178354Ssamstatic void	aac_free_commands(struct aac_softc *sc);
91178354Ssamstatic void	aac_unmap_command(struct aac_command *cm);
92178354Ssam
93178354Ssam/* Hardware Interface */
94178354Ssamstatic int	aac_alloc(struct aac_softc *sc);
95178354Ssamstatic void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
96178354Ssam			       int error);
97178354Ssamstatic int	aac_check_firmware(struct aac_softc *sc);
98178354Ssamstatic int	aac_init(struct aac_softc *sc);
99178354Ssamstatic int	aac_sync_command(struct aac_softc *sc, u_int32_t command,
100178354Ssam				 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
101178354Ssam				 u_int32_t arg3, u_int32_t *sp);
102178354Ssamstatic int	aac_setup_intr(struct aac_softc *sc);
103170530Ssamstatic int	aac_enqueue_fib(struct aac_softc *sc, int queue,
104178354Ssam				struct aac_command *cm);
105178354Ssamstatic int	aac_dequeue_fib(struct aac_softc *sc, int queue,
106170530Ssam				u_int32_t *fib_size, struct aac_fib **fib_addr);
107170530Ssamstatic int	aac_enqueue_response(struct aac_softc *sc, int queue,
108170530Ssam				     struct aac_fib *fib);
109170530Ssam
110170530Ssam/* Falcon/PPC interface */
111170530Ssamstatic int	aac_fa_get_fwstatus(struct aac_softc *sc);
112170530Ssamstatic void	aac_fa_qnotify(struct aac_softc *sc, int qbit);
113170530Ssamstatic int	aac_fa_get_istatus(struct aac_softc *sc);
114170530Ssamstatic void	aac_fa_clear_istatus(struct aac_softc *sc, int mask);
115170530Ssamstatic void	aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
116170530Ssam				   u_int32_t arg0, u_int32_t arg1,
117170530Ssam				   u_int32_t arg2, u_int32_t arg3);
118170530Ssamstatic int	aac_fa_get_mailbox(struct aac_softc *sc, int mb);
119170530Ssamstatic void	aac_fa_set_interrupts(struct aac_softc *sc, int enable);
120170530Ssam
121170530Ssamstruct aac_interface aac_fa_interface = {
122170530Ssam	aac_fa_get_fwstatus,
123178354Ssam	aac_fa_qnotify,
124170530Ssam	aac_fa_get_istatus,
125170530Ssam	aac_fa_clear_istatus,
126170530Ssam	aac_fa_set_mailbox,
127170530Ssam	aac_fa_get_mailbox,
128173273Ssam	aac_fa_set_interrupts,
129173273Ssam	NULL, NULL, NULL
130178354Ssam};
131173273Ssam
132178354Ssam/* StrongARM interface */
133178354Ssamstatic int	aac_sa_get_fwstatus(struct aac_softc *sc);
134178354Ssamstatic void	aac_sa_qnotify(struct aac_softc *sc, int qbit);
135178354Ssamstatic int	aac_sa_get_istatus(struct aac_softc *sc);
136173273Ssamstatic void	aac_sa_clear_istatus(struct aac_softc *sc, int mask);
137178354Ssamstatic void	aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
138178354Ssam				   u_int32_t arg0, u_int32_t arg1,
139178354Ssam				   u_int32_t arg2, u_int32_t arg3);
140178354Ssamstatic int	aac_sa_get_mailbox(struct aac_softc *sc, int mb);
141178354Ssamstatic void	aac_sa_set_interrupts(struct aac_softc *sc, int enable);
142178354Ssam
143178354Ssamstruct aac_interface aac_sa_interface = {
144178354Ssam	aac_sa_get_fwstatus,
145178354Ssam	aac_sa_qnotify,
146178354Ssam	aac_sa_get_istatus,
147178354Ssam	aac_sa_clear_istatus,
148178354Ssam	aac_sa_set_mailbox,
149178354Ssam	aac_sa_get_mailbox,
150178354Ssam	aac_sa_set_interrupts,
151178354Ssam	NULL, NULL, NULL
152178354Ssam};
153170530Ssam
154173273Ssam/* i960Rx interface */
155173273Ssamstatic int	aac_rx_get_fwstatus(struct aac_softc *sc);
156170530Ssamstatic void	aac_rx_qnotify(struct aac_softc *sc, int qbit);
157170530Ssamstatic int	aac_rx_get_istatus(struct aac_softc *sc);
158178354Ssamstatic void	aac_rx_clear_istatus(struct aac_softc *sc, int mask);
159178354Ssamstatic void	aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
160178354Ssam				   u_int32_t arg0, u_int32_t arg1,
161178354Ssam				   u_int32_t arg2, u_int32_t arg3);
162178354Ssamstatic int	aac_rx_get_mailbox(struct aac_softc *sc, int mb);
163173273Ssamstatic void	aac_rx_set_interrupts(struct aac_softc *sc, int enable);
164178354Ssamstatic int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm);
165178354Ssamstatic int aac_rx_get_outb_queue(struct aac_softc *sc);
166178354Ssamstatic void aac_rx_set_outb_queue(struct aac_softc *sc, int index);
167178354Ssam
168170530Ssamstruct aac_interface aac_rx_interface = {
169183256Ssam	aac_rx_get_fwstatus,
170183256Ssam	aac_rx_qnotify,
171183256Ssam	aac_rx_get_istatus,
172183256Ssam	aac_rx_clear_istatus,
173170530Ssam	aac_rx_set_mailbox,
174178354Ssam	aac_rx_get_mailbox,
175178354Ssam	aac_rx_set_interrupts,
176178354Ssam	aac_rx_send_command,
177178354Ssam	aac_rx_get_outb_queue,
178178354Ssam	aac_rx_set_outb_queue
179178354Ssam};
180170530Ssam
181178354Ssam/* Rocket/MIPS interface */
182178354Ssamstatic int	aac_rkt_get_fwstatus(struct aac_softc *sc);
183178354Ssamstatic void	aac_rkt_qnotify(struct aac_softc *sc, int qbit);
184170530Ssamstatic int	aac_rkt_get_istatus(struct aac_softc *sc);
185170530Ssamstatic void	aac_rkt_clear_istatus(struct aac_softc *sc, int mask);
186170530Ssamstatic void	aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command,
187178354Ssam				    u_int32_t arg0, u_int32_t arg1,
188170530Ssam				    u_int32_t arg2, u_int32_t arg3);
189170530Ssamstatic int	aac_rkt_get_mailbox(struct aac_softc *sc, int mb);
190170530Ssamstatic void	aac_rkt_set_interrupts(struct aac_softc *sc, int enable);
191170530Ssamstatic int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm);
192170530Ssamstatic int aac_rkt_get_outb_queue(struct aac_softc *sc);
193170530Ssamstatic void aac_rkt_set_outb_queue(struct aac_softc *sc, int index);
194170530Ssam
195170530Ssamstruct aac_interface aac_rkt_interface = {
196170530Ssam	aac_rkt_get_fwstatus,
197170530Ssam	aac_rkt_qnotify,
198170530Ssam	aac_rkt_get_istatus,
199170530Ssam	aac_rkt_clear_istatus,
200172226Ssam	aac_rkt_set_mailbox,
201172226Ssam	aac_rkt_get_mailbox,
202170530Ssam	aac_rkt_set_interrupts,
203170530Ssam	aac_rkt_send_command,
204178354Ssam	aac_rkt_get_outb_queue,
205170530Ssam	aac_rkt_set_outb_queue
206170530Ssam};
207170530Ssam
208170530Ssam/* Debugging and Diagnostics */
209170530Ssamstatic void	aac_describe_controller(struct aac_softc *sc);
210170530Ssamstatic char	*aac_describe_code(struct aac_code_lookup *table,
211170530Ssam				   u_int32_t code);
212170530Ssam
213170530Ssam/* Management Interface */
214170530Ssamstatic d_open_t		aac_open;
215170530Ssamstatic d_close_t	aac_close;
216170530Ssamstatic d_ioctl_t	aac_ioctl;
217170530Ssamstatic d_poll_t		aac_poll;
218170530Ssamstatic int		aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
219170530Ssamstatic int		aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
220170530Ssamstatic void		aac_handle_aif(struct aac_softc *sc,
221170530Ssam					   struct aac_fib *fib);
222170530Ssamstatic int		aac_rev_check(struct aac_softc *sc, caddr_t udata);
223170530Ssamstatic int		aac_open_aif(struct aac_softc *sc, caddr_t arg);
224173273Ssamstatic int		aac_close_aif(struct aac_softc *sc, caddr_t arg);
225170530Ssamstatic int		aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
226170530Ssamstatic int		aac_return_aif(struct aac_softc *sc,
227170530Ssam					struct aac_fib_context *ctx, caddr_t uptr);
228170530Ssamstatic int		aac_query_disk(struct aac_softc *sc, caddr_t uptr);
229170530Ssamstatic int		aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
230170530Ssamstatic int		aac_supported_features(struct aac_softc *sc, caddr_t uptr);
231170530Ssamstatic void		aac_ioctl_event(struct aac_softc *sc,
232170530Ssam				        struct aac_event *event, void *arg);
233170530Ssamstatic struct aac_mntinforesp *
234170530Ssam	aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid);
235170530Ssam
236170530Ssamstatic struct cdevsw aac_cdevsw = {
237170530Ssam	.d_version =	D_VERSION,
238170530Ssam	.d_flags =	D_NEEDGIANT,
239178354Ssam	.d_open =	aac_open,
240173462Ssam	.d_close =	aac_close,
241170530Ssam	.d_ioctl =	aac_ioctl,
242170530Ssam	.d_poll =	aac_poll,
243170530Ssam	.d_name =	"aac",
244170530Ssam};
245170530Ssam
246178354SsamMALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver");
247170530Ssam
248170530Ssam/* sysctl node */
249170530SsamSYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters");
250170530Ssam
251170530Ssam/*
252170530Ssam * Device Interface
253170530Ssam */
254170530Ssam
255170530Ssam/*
256170530Ssam * Initialize the controller and softc
257178354Ssam */
258173462Ssamint
259178354Ssamaac_attach(struct aac_softc *sc)
260170530Ssam{
261170530Ssam	int error, unit;
262173462Ssam
263170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
264170530Ssam
265170530Ssam	/*
266178354Ssam	 * Initialize per-controller queues.
267170530Ssam	 */
268170530Ssam	aac_initq_free(sc);
269178354Ssam	aac_initq_ready(sc);
270170530Ssam	aac_initq_busy(sc);
271170530Ssam	aac_initq_bio(sc);
272170530Ssam
273178354Ssam	/*
274170530Ssam	 * Initialize command-completion task.
275170530Ssam	 */
276170530Ssam	TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc);
277170530Ssam
278170530Ssam	/* mark controller as suspended until we get ourselves organised */
279170530Ssam	sc->aac_state |= AAC_STATE_SUSPEND;
280170530Ssam
281170530Ssam	/*
282170530Ssam	 * Check that the firmware on the card is supported.
283170530Ssam	 */
284170530Ssam	if ((error = aac_check_firmware(sc)) != 0)
285170530Ssam		return(error);
286170530Ssam
287170530Ssam	/*
288170530Ssam	 * Initialize locks
289170530Ssam	 */
290170530Ssam	mtx_init(&sc->aac_aifq_lock, "AAC AIF lock", NULL, MTX_DEF);
291170530Ssam	mtx_init(&sc->aac_io_lock, "AAC I/O lock", NULL, MTX_DEF);
292170530Ssam	mtx_init(&sc->aac_container_lock, "AAC container lock", NULL, MTX_DEF);
293170530Ssam	TAILQ_INIT(&sc->aac_container_tqh);
294170530Ssam	TAILQ_INIT(&sc->aac_ev_cmfree);
295170530Ssam
296170530Ssam	/* Initialize the clock daemon callout. */
297170530Ssam	callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0);
298170530Ssam
299170530Ssam	/*
300170530Ssam	 * Initialize the adapter.
301170530Ssam	 */
302170530Ssam	if ((error = aac_alloc(sc)) != 0)
303170530Ssam		return(error);
304170530Ssam	if ((error = aac_init(sc)) != 0)
305170530Ssam		return(error);
306170530Ssam
307170530Ssam	/*
308170530Ssam	 * Allocate and connect our interrupt.
309170530Ssam	 */
310178354Ssam	if ((error = aac_setup_intr(sc)) != 0)
311178354Ssam		return(error);
312178354Ssam
313178354Ssam	/*
314178354Ssam	 * Print a little information about the controller.
315178354Ssam	 */
316178354Ssam	aac_describe_controller(sc);
317178354Ssam
318178354Ssam	/*
319178354Ssam	 * Register to probe our containers later.
320178354Ssam	 */
321178354Ssam	sc->aac_ich.ich_func = aac_startup;
322178354Ssam	sc->aac_ich.ich_arg = sc;
323178354Ssam	if (config_intrhook_establish(&sc->aac_ich) != 0) {
324178354Ssam		device_printf(sc->aac_dev,
325178354Ssam			      "can't establish configuration hook\n");
326178354Ssam		return(ENXIO);
327178354Ssam	}
328178354Ssam
329178354Ssam	/*
330170530Ssam	 * Make the control device.
331170530Ssam	 */
332170530Ssam	unit = device_get_unit(sc->aac_dev);
333170530Ssam	sc->aac_dev_t = make_dev(&aac_cdevsw, unit, UID_ROOT, GID_OPERATOR,
334170530Ssam				 0640, "aac%d", unit);
335170530Ssam	(void)make_dev_alias(sc->aac_dev_t, "afa%d", unit);
336178354Ssam	(void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit);
337170530Ssam	sc->aac_dev_t->si_drv1 = sc;
338170530Ssam
339170530Ssam	/* Create the AIF thread */
340170530Ssam	if (kproc_create((void(*)(void *))aac_command_thread, sc,
341170530Ssam		   &sc->aifthread, 0, 0, "aac%daif", unit))
342183247Ssam		panic("Could not create AIF thread");
343170530Ssam
344170530Ssam	/* Register the shutdown method to only be called post-dump */
345170530Ssam	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown,
346170530Ssam	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
347170530Ssam		device_printf(sc->aac_dev,
348183247Ssam			      "shutdown event registration failed\n");
349183247Ssam
350178354Ssam	/* Register with CAM for the non-DASD devices */
351170530Ssam	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) {
352170530Ssam		TAILQ_INIT(&sc->aac_sim_tqh);
353170530Ssam		aac_get_bus_info(sc);
354170530Ssam	}
355170530Ssam
356170530Ssam	mtx_lock(&sc->aac_io_lock);
357170530Ssam	callout_reset(&sc->aac_daemontime, 30 * 60 * hz, aac_daemon, sc);
358170530Ssam	mtx_unlock(&sc->aac_io_lock);
359170530Ssam
360170530Ssam	return(0);
361170530Ssam}
362170530Ssam
363170530Ssamstatic void
364178354Ssamaac_daemon(void *arg)
365170530Ssam{
366170530Ssam	struct timeval tv;
367170530Ssam	struct aac_softc *sc;
368170530Ssam	struct aac_fib *fib;
369170530Ssam
370170530Ssam	sc = arg;
371170530Ssam	mtx_assert(&sc->aac_io_lock, MA_OWNED);
372170530Ssam
373170530Ssam	if (callout_pending(&sc->aac_daemontime) ||
374170530Ssam	    callout_active(&sc->aac_daemontime) == 0)
375170530Ssam		return;
376170530Ssam	getmicrotime(&tv);
377170530Ssam	aac_alloc_sync_fib(sc, &fib);
378170530Ssam	*(uint32_t *)fib->data = tv.tv_sec;
379170530Ssam	aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t));
380170530Ssam	aac_release_sync_fib(sc);
381170530Ssam	callout_schedule(&sc->aac_daemontime, 30 * 60 * hz);
382170530Ssam}
383170530Ssam
384170530Ssamvoid
385170530Ssamaac_add_event(struct aac_softc *sc, struct aac_event *event)
386170530Ssam{
387170530Ssam
388170530Ssam	switch (event->ev_type & AAC_EVENT_MASK) {
389170530Ssam	case AAC_EVENT_CMFREE:
390170530Ssam		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
391170530Ssam		break;
392170530Ssam	default:
393170530Ssam		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
394178354Ssam		    event->ev_type);
395170530Ssam		break;
396173273Ssam	}
397173273Ssam
398173273Ssam	return;
399173273Ssam}
400173273Ssam
401178354Ssam/*
402170530Ssam * Request information of container #cid
403170530Ssam */
404173273Ssamstatic struct aac_mntinforesp *
405170530Ssamaac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid)
406173273Ssam{
407170530Ssam	struct aac_mntinfo *mi;
408170530Ssam
409173273Ssam	mi = (struct aac_mntinfo *)&fib->data[0];
410170530Ssam	/* use 64-bit LBA if enabled */
411178354Ssam	mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ?
412170530Ssam	    VM_NameServe64 : VM_NameServe;
413170530Ssam	mi->MntType = FT_FILESYS;
414170530Ssam	mi->MntCount = cid;
415173273Ssam
416170530Ssam	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
417170530Ssam			 sizeof(struct aac_mntinfo))) {
418170530Ssam		printf("Error probing container %d\n", cid);
419170530Ssam		return (NULL);
420170530Ssam	}
421173273Ssam
422178354Ssam	return ((struct aac_mntinforesp *)&fib->data[0]);
423173273Ssam}
424170530Ssam
425173273Ssam/*
426170530Ssam * Probe for containers, create disks.
427170530Ssam */
428170530Ssamstatic void
429173273Ssamaac_startup(void *arg)
430170530Ssam{
431170530Ssam	struct aac_softc *sc;
432173273Ssam	struct aac_fib *fib;
433173273Ssam	struct aac_mntinforesp *mir;
434173273Ssam	int count = 0, i = 0;
435173273Ssam
436173273Ssam	sc = (struct aac_softc *)arg;
437173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
438173273Ssam
439173273Ssam	/* disconnect ourselves from the intrhook chain */
440178354Ssam	config_intrhook_disestablish(&sc->aac_ich);
441173273Ssam
442173273Ssam	mtx_lock(&sc->aac_io_lock);
443173273Ssam	aac_alloc_sync_fib(sc, &fib);
444173273Ssam
445173273Ssam	/* loop over possible containers */
446173273Ssam	do {
447173273Ssam		if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
448173273Ssam			continue;
449173273Ssam		if (i == 0)
450173273Ssam			count = mir->MntRespCount;
451173273Ssam		aac_add_container(sc, mir, 0);
452173273Ssam		i++;
453173273Ssam	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
454173273Ssam
455173273Ssam	aac_release_sync_fib(sc);
456173273Ssam	mtx_unlock(&sc->aac_io_lock);
457173273Ssam
458173273Ssam	/* poke the bus to actually attach the child devices */
459178354Ssam	if (bus_generic_attach(sc->aac_dev))
460173273Ssam		device_printf(sc->aac_dev, "bus_generic_attach failed\n");
461173273Ssam
462173273Ssam	/* mark the controller up */
463173273Ssam	sc->aac_state &= ~AAC_STATE_SUSPEND;
464173273Ssam
465173273Ssam	/* enable interrupts now */
466173273Ssam	AAC_UNMASK_INTERRUPTS(sc);
467173273Ssam}
468173273Ssam
469173273Ssam/*
470173273Ssam * Create a device to represent a new container
471173273Ssam */
472173273Ssamstatic void
473173273Ssamaac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f)
474178354Ssam{
475178354Ssam	struct aac_container *co;
476178354Ssam	device_t child;
477178354Ssam
478173273Ssam	/*
479173273Ssam	 * Check container volume type for validity.  Note that many of
480173273Ssam	 * the possible types may never show up.
481173273Ssam	 */
482173273Ssam	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
483173273Ssam		co = (struct aac_container *)malloc(sizeof *co, M_AACBUF,
484173273Ssam		       M_NOWAIT | M_ZERO);
485173273Ssam		if (co == NULL)
486173273Ssam			panic("Out of memory?!");
487173273Ssam		fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x  name '%.16s'  size %u  type %d",
488173273Ssam		      mir->MntTable[0].ObjectId,
489173273Ssam		      mir->MntTable[0].FileSystemName,
490173273Ssam		      mir->MntTable[0].Capacity, mir->MntTable[0].VolType);
491178354Ssam
492173273Ssam		if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL)
493173273Ssam			device_printf(sc->aac_dev, "device_add_child failed\n");
494173273Ssam		else
495173273Ssam			device_set_ivars(child, co);
496173273Ssam		device_set_desc(child, aac_describe_code(aac_container_types,
497173273Ssam				mir->MntTable[0].VolType));
498173273Ssam		co->co_disk = child;
499173273Ssam		co->co_found = f;
500173273Ssam		bcopy(&mir->MntTable[0], &co->co_mntobj,
501173273Ssam		      sizeof(struct aac_mntobj));
502173273Ssam		mtx_lock(&sc->aac_container_lock);
503170530Ssam		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
504170530Ssam		mtx_unlock(&sc->aac_container_lock);
505170530Ssam	}
506173273Ssam}
507170530Ssam
508170530Ssam/*
509170530Ssam * Allocate resources associated with (sc)
510170530Ssam */
511170530Ssamstatic int
512170530Ssamaac_alloc(struct aac_softc *sc)
513170530Ssam{
514170530Ssam
515173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
516173273Ssam
517178354Ssam	/*
518170530Ssam	 * Create DMA tag for mapping buffers into controller-addressable space.
519170530Ssam	 */
520170530Ssam	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
521170530Ssam			       1, 0, 			/* algnmnt, boundary */
522170530Ssam			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
523170530Ssam			       BUS_SPACE_MAXADDR :
524183247Ssam			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
525183247Ssam			       BUS_SPACE_MAXADDR, 	/* highaddr */
526170530Ssam			       NULL, NULL, 		/* filter, filterarg */
527170530Ssam			       MAXBSIZE,		/* maxsize */
528170530Ssam			       sc->aac_sg_tablesize,	/* nsegments */
529170530Ssam			       MAXBSIZE,		/* maxsegsize */
530183247Ssam			       BUS_DMA_ALLOCNOW,	/* flags */
531183247Ssam			       busdma_lock_mutex,	/* lockfunc */
532183247Ssam			       &sc->aac_io_lock,	/* lockfuncarg */
533183247Ssam			       &sc->aac_buffer_dmat)) {
534183247Ssam		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
535183247Ssam		return (ENOMEM);
536183247Ssam	}
537170530Ssam
538173273Ssam	/*
539173273Ssam	 * Create DMA tag for mapping FIBs into controller-addressable space..
540173273Ssam	 */
541173273Ssam	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
542173273Ssam			       1, 0, 			/* algnmnt, boundary */
543170530Ssam			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
544170530Ssam			       BUS_SPACE_MAXADDR_32BIT :
545170530Ssam			       0x7fffffff,		/* lowaddr */
546170530Ssam			       BUS_SPACE_MAXADDR, 	/* highaddr */
547170530Ssam			       NULL, NULL, 		/* filter, filterarg */
548173273Ssam			       sc->aac_max_fibs_alloc *
549170530Ssam			       sc->aac_max_fib_size,  /* maxsize */
550182827Ssam			       1,			/* nsegments */
551182827Ssam			       sc->aac_max_fibs_alloc *
552182827Ssam			       sc->aac_max_fib_size,	/* maxsize */
553182827Ssam			       0,			/* flags */
554182827Ssam			       NULL, NULL,		/* No locking needed */
555182827Ssam			       &sc->aac_fib_dmat)) {
556182827Ssam		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
557182827Ssam		return (ENOMEM);
558182827Ssam	}
559182827Ssam
560182827Ssam	/*
561182827Ssam	 * Create DMA tag for the common structure and allocate it.
562182827Ssam	 */
563182827Ssam	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
564182827Ssam			       1, 0,			/* algnmnt, boundary */
565173273Ssam			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
566173273Ssam			       BUS_SPACE_MAXADDR_32BIT :
567170530Ssam			       0x7fffffff,		/* lowaddr */
568170530Ssam			       BUS_SPACE_MAXADDR, 	/* highaddr */
569170530Ssam			       NULL, NULL, 		/* filter, filterarg */
570170530Ssam			       8192 + sizeof(struct aac_common), /* maxsize */
571170530Ssam			       1,			/* nsegments */
572170530Ssam			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
573170530Ssam			       0,			/* flags */
574170530Ssam			       NULL, NULL,		/* No locking needed */
575170530Ssam			       &sc->aac_common_dmat)) {
576170530Ssam		device_printf(sc->aac_dev,
577170530Ssam			      "can't allocate common structure DMA tag\n");
578173273Ssam		return (ENOMEM);
579170530Ssam	}
580170530Ssam	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
581170530Ssam			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
582170530Ssam		device_printf(sc->aac_dev, "can't allocate common structure\n");
583170530Ssam		return (ENOMEM);
584170530Ssam	}
585173273Ssam
586170530Ssam	/*
587170530Ssam	 * Work around a bug in the 2120 and 2200 that cannot DMA commands
588170530Ssam	 * below address 8192 in physical memory.
589173273Ssam	 * XXX If the padding is not needed, can it be put to use instead
590170530Ssam	 * of ignored?
591170530Ssam	 */
592170530Ssam	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
593173273Ssam			sc->aac_common, 8192 + sizeof(*sc->aac_common),
594170530Ssam			aac_common_map, sc, 0);
595173273Ssam
596173273Ssam	if (sc->aac_common_busaddr < 8192) {
597173273Ssam		sc->aac_common = (struct aac_common *)
598173273Ssam		    ((uint8_t *)sc->aac_common + 8192);
599173273Ssam		sc->aac_common_busaddr += 8192;
600173273Ssam	}
601173273Ssam	bzero(sc->aac_common, sizeof(*sc->aac_common));
602173273Ssam
603173273Ssam	/* Allocate some FIBs and associated command structs */
604173273Ssam	TAILQ_INIT(&sc->aac_fibmap_tqh);
605173273Ssam	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
606173273Ssam				  M_AACBUF, M_WAITOK|M_ZERO);
607173273Ssam	while (sc->total_fibs < AAC_PREALLOCATE_FIBS) {
608173273Ssam		if (aac_alloc_commands(sc) != 0)
609170530Ssam			break;
610173273Ssam	}
611173273Ssam	if (sc->total_fibs == 0)
612173273Ssam		return (ENOMEM);
613173273Ssam
614173273Ssam	return (0);
615170530Ssam}
616173273Ssam
617173273Ssam/*
618173273Ssam * Free all of the resources associated with (sc)
619173273Ssam *
620173273Ssam * Should not be called if the controller is active.
621173273Ssam */
622173273Ssamvoid
623173273Ssamaac_free(struct aac_softc *sc)
624178354Ssam{
625173273Ssam
626173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
627173273Ssam
628173273Ssam	/* remove the control device */
629173273Ssam	if (sc->aac_dev_t != NULL)
630173273Ssam		destroy_dev(sc->aac_dev_t);
631173273Ssam
632173273Ssam	/* throw away any FIB buffers, discard the FIB DMA tag */
633173273Ssam	aac_free_commands(sc);
634173273Ssam	if (sc->aac_fib_dmat)
635173273Ssam		bus_dma_tag_destroy(sc->aac_fib_dmat);
636173273Ssam
637173273Ssam	free(sc->aac_commands, M_AACBUF);
638173273Ssam
639173273Ssam	/* destroy the common area */
640173273Ssam	if (sc->aac_common) {
641173273Ssam		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
642173273Ssam		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
643178354Ssam				sc->aac_common_dmamap);
644173273Ssam	}
645178354Ssam	if (sc->aac_common_dmat)
646173273Ssam		bus_dma_tag_destroy(sc->aac_common_dmat);
647173273Ssam
648173273Ssam	/* disconnect the interrupt handler */
649173273Ssam	if (sc->aac_intr)
650173273Ssam		bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr);
651178354Ssam	if (sc->aac_irq != NULL)
652173273Ssam		bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid,
653173273Ssam				     sc->aac_irq);
654173273Ssam
655173273Ssam	/* destroy data-transfer DMA tag */
656173273Ssam	if (sc->aac_buffer_dmat)
657173273Ssam		bus_dma_tag_destroy(sc->aac_buffer_dmat);
658173273Ssam
659173273Ssam	/* destroy the parent DMA tag */
660173273Ssam	if (sc->aac_parent_dmat)
661173273Ssam		bus_dma_tag_destroy(sc->aac_parent_dmat);
662173273Ssam
663178354Ssam	/* release the register window mapping */
664173273Ssam	if (sc->aac_regs_res0 != NULL)
665170530Ssam		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
666173273Ssam				     sc->aac_regs_rid0, sc->aac_regs_res0);
667170530Ssam	if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL)
668178354Ssam		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
669170530Ssam				     sc->aac_regs_rid1, sc->aac_regs_res1);
670173273Ssam}
671173273Ssam
672173273Ssam/*
673173273Ssam * Disconnect from the controller completely, in preparation for unload.
674173273Ssam */
675173273Ssamint
676173273Ssamaac_detach(device_t dev)
677173273Ssam{
678173273Ssam	struct aac_softc *sc;
679173273Ssam	struct aac_container *co;
680173273Ssam	struct aac_sim	*sim;
681173273Ssam	int error;
682170530Ssam
683170530Ssam	sc = device_get_softc(dev);
684173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
685173273Ssam
686170530Ssam	if (sc->aac_state & AAC_STATE_OPEN)
687178354Ssam		return(EBUSY);
688173273Ssam
689178354Ssam	callout_drain(&sc->aac_daemontime);
690173273Ssam
691173273Ssam	/* Remove the child containers */
692173273Ssam	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
693173273Ssam		error = device_delete_child(dev, co->co_disk);
694178354Ssam		if (error)
695173273Ssam			return (error);
696170530Ssam		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
697173273Ssam		free(co, M_AACBUF);
698170530Ssam	}
699173273Ssam
700173273Ssam	/* Remove the CAM SIMs */
701170530Ssam	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
702170530Ssam		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
703170530Ssam		error = device_delete_child(dev, sim->sim_dev);
704170530Ssam		if (error)
705170530Ssam			return (error);
706170530Ssam		free(sim, M_AACBUF);
707173273Ssam	}
708170530Ssam
709170530Ssam	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
710170530Ssam		sc->aifflags |= AAC_AIFFLAGS_EXIT;
711170530Ssam		wakeup(sc->aifthread);
712178354Ssam		tsleep(sc->aac_dev, PUSER | PCATCH, "aacdch", 30 * hz);
713170530Ssam	}
714170530Ssam
715170530Ssam	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
716170530Ssam		panic("Cannot shutdown AIF thread");
717170530Ssam
718173273Ssam	if ((error = aac_shutdown(dev)))
719173273Ssam		return(error);
720178354Ssam
721173273Ssam	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
722173273Ssam
723178354Ssam	aac_free(sc);
724173273Ssam
725173273Ssam	mtx_destroy(&sc->aac_aifq_lock);
726170530Ssam	mtx_destroy(&sc->aac_io_lock);
727170530Ssam	mtx_destroy(&sc->aac_container_lock);
728170530Ssam
729170530Ssam	return(0);
730170530Ssam}
731170530Ssam
732170530Ssam/*
733170530Ssam * Bring the controller down to a dormant state and detach all child devices.
734178354Ssam *
735170530Ssam * This function is called before detach or system shutdown.
736170530Ssam *
737178354Ssam * Note that we can assume that the bioq on the controller is empty, as we won't
738170530Ssam * allow shutdown if any device is open.
739170530Ssam */
740178354Ssamint
741170530Ssamaac_shutdown(device_t dev)
742173273Ssam{
743173273Ssam	struct aac_softc *sc;
744170530Ssam	struct aac_fib *fib;
745170530Ssam	struct aac_close_command *cc;
746173273Ssam
747170530Ssam	sc = device_get_softc(dev);
748173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
749173273Ssam
750170530Ssam	sc->aac_state |= AAC_STATE_SUSPEND;
751178354Ssam
752173273Ssam	/*
753170530Ssam	 * Send a Container shutdown followed by a HostShutdown FIB to the
754173273Ssam	 * controller to convince it that we don't want to talk to it anymore.
755173273Ssam	 * We've been closed and all I/O completed already
756178354Ssam	 */
757173273Ssam	device_printf(sc->aac_dev, "shutting down controller...");
758173273Ssam
759173273Ssam	mtx_lock(&sc->aac_io_lock);
760173273Ssam	aac_alloc_sync_fib(sc, &fib);
761173273Ssam	cc = (struct aac_close_command *)&fib->data[0];
762173273Ssam
763173273Ssam	bzero(cc, sizeof(struct aac_close_command));
764173273Ssam	cc->Command = VM_CloseAll;
765173273Ssam	cc->ContainerId = 0xffffffff;
766170530Ssam	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
767173273Ssam	    sizeof(struct aac_close_command)))
768170530Ssam		printf("FAILED.\n");
769173273Ssam	else
770173273Ssam		printf("done\n");
771170530Ssam#if 0
772178354Ssam	else {
773173273Ssam		fib->data[0] = 0;
774173273Ssam		/*
775173273Ssam		 * XXX Issuing this command to the controller makes it shut down
776173273Ssam		 * but also keeps it from coming back up without a reset of the
777173273Ssam		 * PCI bus.  This is not desirable if you are just unloading the
778173273Ssam		 * driver module with the intent to reload it later.
779178354Ssam		 */
780173273Ssam		if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
781170530Ssam		    fib, 1)) {
782170530Ssam			printf("FAILED.\n");
783170530Ssam		} else {
784170530Ssam			printf("done.\n");
785170530Ssam		}
786170530Ssam	}
787170530Ssam#endif
788170530Ssam
789170530Ssam	AAC_MASK_INTERRUPTS(sc);
790183254Ssam	aac_release_sync_fib(sc);
791170530Ssam	mtx_unlock(&sc->aac_io_lock);
792170530Ssam
793170530Ssam	return(0);
794170530Ssam}
795173273Ssam
796173273Ssam/*
797173273Ssam * Bring the controller to a quiescent state, ready for system suspend.
798173273Ssam */
799173273Ssamint
800173273Ssamaac_suspend(device_t dev)
801173273Ssam{
802173273Ssam	struct aac_softc *sc;
803170530Ssam
804170530Ssam	sc = device_get_softc(dev);
805170530Ssam
806173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
807170530Ssam	sc->aac_state |= AAC_STATE_SUSPEND;
808173273Ssam
809170530Ssam	AAC_MASK_INTERRUPTS(sc);
810170530Ssam	return(0);
811170530Ssam}
812170530Ssam
813170530Ssam/*
814170530Ssam * Bring the controller back to a state ready for operation.
815170530Ssam */
816170530Ssamint
817170530Ssamaac_resume(device_t dev)
818170530Ssam{
819170530Ssam	struct aac_softc *sc;
820170530Ssam
821170530Ssam	sc = device_get_softc(dev);
822170530Ssam
823170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
824170530Ssam	sc->aac_state &= ~AAC_STATE_SUSPEND;
825170530Ssam	AAC_UNMASK_INTERRUPTS(sc);
826173273Ssam	return(0);
827173273Ssam}
828173273Ssam
829173273Ssam/*
830173273Ssam * Interrupt handler for NEW_COMM interface.
831170530Ssam */
832178354Ssamvoid
833178354Ssamaac_new_intr(void *arg)
834173273Ssam{
835173273Ssam	struct aac_softc *sc;
836173273Ssam	u_int32_t index, fast;
837173273Ssam	struct aac_command *cm;
838170530Ssam	struct aac_fib *fib;
839170530Ssam	int i;
840170530Ssam
841170530Ssam	sc = (struct aac_softc *)arg;
842170530Ssam
843182828Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
844170530Ssam	mtx_lock(&sc->aac_io_lock);
845170530Ssam	while (1) {
846178354Ssam		index = AAC_GET_OUTB_QUEUE(sc);
847178354Ssam		if (index == 0xffffffff)
848178354Ssam			index = AAC_GET_OUTB_QUEUE(sc);
849178354Ssam		if (index == 0xffffffff)
850178354Ssam			break;
851178354Ssam		if (index & 2) {
852178354Ssam			if (index == 0xfffffffe) {
853178354Ssam				/* XXX This means that the controller wants
854178354Ssam				 * more work.  Ignore it for now.
855178354Ssam				 */
856178354Ssam				continue;
857178354Ssam			}
858178354Ssam			/* AIF */
859178354Ssam			fib = (struct aac_fib *)malloc(sizeof *fib, M_AACBUF,
860178354Ssam				   M_NOWAIT | M_ZERO);
861178354Ssam			if (fib == NULL) {
862178354Ssam				/* If we're really this short on memory,
863178354Ssam				 * hopefully breaking out of the handler will
864178354Ssam				 * allow something to get freed.  This
865178354Ssam				 * actually sucks a whole lot.
866178354Ssam				 */
867178354Ssam				break;
868178354Ssam			}
869178354Ssam			index &= ~2;
870178354Ssam			for (i = 0; i < sizeof(struct aac_fib)/4; ++i)
871178354Ssam				((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4);
872178354Ssam			aac_handle_aif(sc, fib);
873178354Ssam			free(fib, M_AACBUF);
874178354Ssam
875178354Ssam			/*
876178354Ssam			 * AIF memory is owned by the adapter, so let it
877178354Ssam			 * know that we are done with it.
878178354Ssam			 */
879178354Ssam			AAC_SET_OUTB_QUEUE(sc, index);
880178354Ssam			AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
881178354Ssam		} else {
882178354Ssam			fast = index & 1;
883178354Ssam			cm = sc->aac_commands + (index >> 2);
884178354Ssam			fib = cm->cm_fib;
885173273Ssam			if (fast) {
886173273Ssam				fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
887173273Ssam				*((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL;
888173273Ssam			}
889173273Ssam			aac_remove_busy(cm);
890173273Ssam 			aac_unmap_command(cm);
891173273Ssam			cm->cm_flags |= AAC_CMD_COMPLETED;
892173273Ssam
893173273Ssam			/* is there a completion handler? */
894173273Ssam			if (cm->cm_complete != NULL) {
895173273Ssam				cm->cm_complete(cm);
896173273Ssam			} else {
897173273Ssam				/* assume that someone is sleeping on this
898173273Ssam				 * command
899173273Ssam				 */
900173273Ssam				wakeup(cm);
901173273Ssam			}
902173273Ssam			sc->flags &= ~AAC_QUEUE_FRZN;
903173273Ssam		}
904173273Ssam	}
905173273Ssam	/* see if we can start some more I/O */
906173273Ssam	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
907173273Ssam		aac_startio(sc);
908173273Ssam
909173273Ssam	mtx_unlock(&sc->aac_io_lock);
910173273Ssam}
911173273Ssam
912173273Ssamint
913173273Ssamaac_fast_intr(void *arg)
914173273Ssam{
915173273Ssam	struct aac_softc *sc;
916173273Ssam	u_int16_t reason;
917173273Ssam
918173273Ssam	sc = (struct aac_softc *)arg;
919173273Ssam
920173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
921173273Ssam	/*
922173273Ssam	 * Read the status register directly.  This is faster than taking the
923173273Ssam	 * driver lock and reading the queues directly.  It also saves having
924173273Ssam	 * to turn parts of the driver lock into a spin mutex, which would be
925173273Ssam	 * ugly.
926173273Ssam	 */
927173273Ssam	reason = AAC_GET_ISTATUS(sc);
928173273Ssam	AAC_CLEAR_ISTATUS(sc, reason);
929173273Ssam
930173273Ssam	/* handle completion processing */
931173273Ssam	if (reason & AAC_DB_RESPONSE_READY)
932173273Ssam		taskqueue_enqueue_fast(taskqueue_fast, &sc->aac_task_complete);
933173273Ssam
934173273Ssam	/* controller wants to talk to us */
935173273Ssam	if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) {
936173273Ssam		/*
937178354Ssam		 * XXX Make sure that we don't get fooled by strange messages
938173273Ssam		 * that start with a NULL.
939173273Ssam		 */
940173273Ssam		if ((reason & AAC_DB_PRINTF) &&
941178354Ssam			(sc->aac_common->ac_printf[0] == 0))
942173273Ssam			sc->aac_common->ac_printf[0] = 32;
943173273Ssam
944173273Ssam		/*
945173273Ssam		 * This might miss doing the actual wakeup.  However, the
946173273Ssam		 * msleep that this is waking up has a timeout, so it will
947173273Ssam		 * wake up eventually.  AIFs and printfs are low enough
948173273Ssam		 * priority that they can handle hanging out for a few seconds
949173273Ssam		 * if needed.
950178354Ssam		 */
951178354Ssam		wakeup(sc->aifthread);
952173273Ssam	}
953173273Ssam	return (FILTER_HANDLED);
954178354Ssam}
955173273Ssam
956173273Ssam/*
957173273Ssam * Command Processing
958173273Ssam */
959173273Ssam
960173273Ssam/*
961173273Ssam * Start as much queued I/O as possible on the controller
962173273Ssam */
963178354Ssamvoid
964173273Ssamaac_startio(struct aac_softc *sc)
965173273Ssam{
966173273Ssam	struct aac_command *cm;
967173273Ssam	int error;
968173273Ssam
969173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
970183256Ssam
971183256Ssam	for (;;) {
972183256Ssam		/*
973173273Ssam		 * This flag might be set if the card is out of resources.
974173273Ssam		 * Checking it here prevents an infinite loop of deferrals.
975173273Ssam		 */
976173273Ssam		if (sc->flags & AAC_QUEUE_FRZN)
977173273Ssam			break;
978173273Ssam
979173273Ssam		/*
980173273Ssam		 * Try to get a command that's been put off for lack of
981173273Ssam		 * resources
982173273Ssam		 */
983173273Ssam		cm = aac_dequeue_ready(sc);
984173273Ssam
985173273Ssam		/*
986173273Ssam		 * Try to build a command off the bio queue (ignore error
987173273Ssam		 * return)
988173273Ssam		 */
989173273Ssam		if (cm == NULL)
990173273Ssam			aac_bio_command(sc, &cm);
991178354Ssam
992178354Ssam		/* nothing to do? */
993178354Ssam		if (cm == NULL)
994178354Ssam			break;
995178354Ssam
996178354Ssam		/* don't map more than once */
997178354Ssam		if (cm->cm_flags & AAC_CMD_MAPPED)
998178354Ssam			panic("aac: command %p already mapped", cm);
999183253Ssam
1000183253Ssam		/*
1001183253Ssam		 * Set up the command to go to the controller.  If there are no
1002178354Ssam		 * data buffers associated with the command then it can bypass
1003178354Ssam		 * busdma.
1004178354Ssam		 */
1005178354Ssam		if (cm->cm_datalen != 0) {
1006178354Ssam			error = bus_dmamap_load(sc->aac_buffer_dmat,
1007178354Ssam						cm->cm_datamap, cm->cm_data,
1008178354Ssam						cm->cm_datalen,
1009178354Ssam						aac_map_command_sg, cm, 0);
1010178354Ssam			if (error == EINPROGRESS) {
1011178354Ssam				fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n");
1012178354Ssam				sc->flags |= AAC_QUEUE_FRZN;
1013178354Ssam				error = 0;
1014178354Ssam			} else if (error != 0)
1015178354Ssam				panic("aac_startio: unexpected error %d from "
1016178354Ssam				      "busdma", error);
1017178354Ssam		} else
1018173273Ssam			aac_map_command_sg(cm, NULL, 0, 0);
1019173273Ssam	}
1020173273Ssam}
1021173273Ssam
1022173273Ssam/*
1023173273Ssam * Handle notification of one or more FIBs coming from the controller.
1024173273Ssam */
1025173273Ssamstatic void
1026173273Ssamaac_command_thread(struct aac_softc *sc)
1027173273Ssam{
1028173273Ssam	struct aac_fib *fib;
1029178354Ssam	u_int32_t fib_size;
1030178354Ssam	int size, retval;
1031178354Ssam
1032178354Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1033173273Ssam
1034178354Ssam	mtx_lock(&sc->aac_io_lock);
1035178354Ssam	sc->aifflags = AAC_AIFFLAGS_RUNNING;
1036178354Ssam
1037173273Ssam	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1038173273Ssam
1039173273Ssam		retval = 0;
1040173273Ssam		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1041173273Ssam			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1042173273Ssam					"aifthd", AAC_PERIODIC_INTERVAL * hz);
1043173273Ssam
1044173273Ssam		/*
1045173273Ssam		 * First see if any FIBs need to be allocated.  This needs
1046173273Ssam		 * to be called without the driver lock because contigmalloc
1047173273Ssam		 * will grab Giant, and would result in an LOR.
1048173273Ssam		 */
1049173273Ssam		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1050173273Ssam			mtx_unlock(&sc->aac_io_lock);
1051173273Ssam			aac_alloc_commands(sc);
1052173273Ssam			mtx_lock(&sc->aac_io_lock);
1053173273Ssam			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1054173273Ssam			aac_startio(sc);
1055173273Ssam		}
1056173273Ssam
1057173273Ssam		/*
1058173273Ssam		 * While we're here, check to see if any commands are stuck.
1059173273Ssam		 * This is pretty low-priority, so it's ok if it doesn't
1060173273Ssam		 * always fire.
1061173273Ssam		 */
1062173273Ssam		if (retval == EWOULDBLOCK)
1063173273Ssam			aac_timeout(sc);
1064173273Ssam
1065173273Ssam		/* Check the hardware printf message buffer */
1066173273Ssam		if (sc->aac_common->ac_printf[0] != 0)
1067173273Ssam			aac_print_printf(sc);
1068173273Ssam
1069173273Ssam		/* Also check to see if the adapter has a command for us. */
1070173273Ssam		if (sc->flags & AAC_FLAGS_NEW_COMM)
1071173273Ssam			continue;
1072173273Ssam		for (;;) {
1073173273Ssam			if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE,
1074173273Ssam					   &fib_size, &fib))
1075173273Ssam				break;
1076173273Ssam
1077173273Ssam			AAC_PRINT_FIB(sc, fib);
1078173273Ssam
1079173273Ssam			switch (fib->Header.Command) {
1080173273Ssam			case AifRequest:
1081173273Ssam				aac_handle_aif(sc, fib);
1082173273Ssam				break;
1083173273Ssam			default:
1084173273Ssam				device_printf(sc->aac_dev, "unknown command "
1085173273Ssam					      "from controller\n");
1086178354Ssam				break;
1087178354Ssam			}
1088178354Ssam
1089178354Ssam			if ((fib->Header.XferState == 0) ||
1090178354Ssam			    (fib->Header.StructType != AAC_FIBTYPE_TFIB)) {
1091178354Ssam				break;
1092178354Ssam			}
1093178354Ssam
1094178354Ssam			/* Return the AIF to the controller. */
1095173273Ssam			if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) {
1096173273Ssam				fib->Header.XferState |= AAC_FIBSTATE_DONEHOST;
1097178354Ssam				*(AAC_FSAStatus*)fib->data = ST_OK;
1098173273Ssam
1099178354Ssam				/* XXX Compute the Size field? */
1100183246Ssam				size = fib->Header.Size;
1101178354Ssam				if (size > sizeof(struct aac_fib)) {
1102178354Ssam					size = sizeof(struct aac_fib);
1103178354Ssam					fib->Header.Size = size;
1104183246Ssam				}
1105178354Ssam				/*
1106178354Ssam				 * Since we did not generate this command, it
1107178354Ssam				 * cannot go through the normal
1108183246Ssam				 * enqueue->startio chain.
1109183246Ssam				 */
1110183246Ssam				aac_enqueue_response(sc,
1111183246Ssam						 AAC_ADAP_NORM_RESP_QUEUE,
1112183246Ssam						 fib);
1113183246Ssam			}
1114183246Ssam		}
1115181197Ssam	}
1116178354Ssam	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1117173273Ssam	mtx_unlock(&sc->aac_io_lock);
1118173273Ssam	wakeup(sc->aac_dev);
1119173273Ssam
1120173273Ssam	kproc_exit(0);
1121173273Ssam}
1122173273Ssam
1123173273Ssam/*
1124173273Ssam * Process completed commands.
1125173273Ssam */
1126173273Ssamstatic void
1127173273Ssamaac_complete(void *context, int pending)
1128173273Ssam{
1129173273Ssam	struct aac_softc *sc;
1130173273Ssam	struct aac_command *cm;
1131173273Ssam	struct aac_fib *fib;
1132173273Ssam	u_int32_t fib_size;
1133173273Ssam
1134173273Ssam	sc = (struct aac_softc *)context;
1135178354Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1136173273Ssam
1137173273Ssam	mtx_lock(&sc->aac_io_lock);
1138173273Ssam
1139173273Ssam	/* pull completed commands off the queue */
1140173273Ssam	for (;;) {
1141173273Ssam		/* look for completed FIBs on our queue */
1142173273Ssam		if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
1143170530Ssam							&fib))
1144170530Ssam			break;	/* nothing to do */
1145170530Ssam
1146170530Ssam		/* get the command, unmap and hand off for processing */
1147170530Ssam		cm = sc->aac_commands + fib->Header.SenderData;
1148170530Ssam		if (cm == NULL) {
1149170530Ssam			AAC_PRINT_FIB(sc, fib);
1150170530Ssam			break;
1151170530Ssam		}
1152170530Ssam		aac_remove_busy(cm);
1153170530Ssam
1154170530Ssam 		aac_unmap_command(cm);
1155170530Ssam		cm->cm_flags |= AAC_CMD_COMPLETED;
1156170530Ssam
1157170530Ssam		/* is there a completion handler? */
1158170530Ssam		if (cm->cm_complete != NULL) {
1159170530Ssam			cm->cm_complete(cm);
1160170530Ssam		} else {
1161170530Ssam			/* assume that someone is sleeping on this command */
1162170530Ssam			wakeup(cm);
1163170530Ssam		}
1164170530Ssam	}
1165170530Ssam
1166170530Ssam	/* see if we can start some more I/O */
1167170530Ssam	sc->flags &= ~AAC_QUEUE_FRZN;
1168170530Ssam	aac_startio(sc);
1169170530Ssam
1170170530Ssam	mtx_unlock(&sc->aac_io_lock);
1171183254Ssam}
1172183254Ssam
1173183254Ssam/*
1174170530Ssam * Handle a bio submitted from a disk device.
1175170530Ssam */
1176170530Ssamvoid
1177170530Ssamaac_submit_bio(struct bio *bp)
1178170530Ssam{
1179172055Ssam	struct aac_disk *ad;
1180170530Ssam	struct aac_softc *sc;
1181170530Ssam
1182170530Ssam	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1183183254Ssam	sc = ad->ad_controller;
1184183254Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1185183254Ssam
1186183254Ssam	/* queue the BIO and try to get some work done */
1187183254Ssam	aac_enqueue_bio(sc, bp);
1188183254Ssam	aac_startio(sc);
1189183254Ssam}
1190183254Ssam
1191183254Ssam/*
1192183254Ssam * Get a bio and build a command to go with it.
1193183254Ssam */
1194183254Ssamstatic int
1195183254Ssamaac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
1196183254Ssam{
1197183254Ssam	struct aac_command *cm;
1198183254Ssam	struct aac_fib *fib;
1199183254Ssam	struct aac_disk *ad;
1200183254Ssam	struct bio *bp;
1201183254Ssam
1202183254Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1203183254Ssam
1204183254Ssam	/* get the resources we will need */
1205183254Ssam	cm = NULL;
1206183254Ssam	bp = NULL;
1207183254Ssam	if (aac_alloc_command(sc, &cm))	/* get a command */
1208183254Ssam		goto fail;
1209183254Ssam	if ((bp = aac_dequeue_bio(sc)) == NULL)
1210183254Ssam		goto fail;
1211183254Ssam
1212183254Ssam	/* fill out the command */
1213183254Ssam	cm->cm_data = (void *)bp->bio_data;
1214173273Ssam	cm->cm_datalen = bp->bio_bcount;
1215173273Ssam	cm->cm_complete = aac_bio_complete;
1216183254Ssam	cm->cm_private = bp;
1217173273Ssam	cm->cm_timestamp = time_uptime;
1218178354Ssam	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
1219173273Ssam
1220173273Ssam	/* build the FIB */
1221173273Ssam	fib = cm->cm_fib;
1222173273Ssam	fib->Header.Size = sizeof(struct aac_fib_header);
1223173273Ssam	fib->Header.XferState =
1224183254Ssam		AAC_FIBSTATE_HOSTOWNED   |
1225183254Ssam		AAC_FIBSTATE_INITIALISED |
1226173273Ssam		AAC_FIBSTATE_EMPTY	 |
1227173273Ssam		AAC_FIBSTATE_FROMHOST	 |
1228173273Ssam		AAC_FIBSTATE_REXPECTED   |
1229183254Ssam		AAC_FIBSTATE_NORM	 |
1230173273Ssam		AAC_FIBSTATE_ASYNC	 |
1231173273Ssam		AAC_FIBSTATE_FAST_RESPONSE;
1232173273Ssam
1233183254Ssam	/* build the read/write request */
1234173273Ssam	ad = (struct aac_disk *)bp->bio_disk->d_drv1;
1235173273Ssam
1236173273Ssam	if (sc->flags & AAC_FLAGS_RAW_IO) {
1237173273Ssam		struct aac_raw_io *raw;
1238173273Ssam		raw = (struct aac_raw_io *)&fib->data[0];
1239173273Ssam		fib->Header.Command = RawIo;
1240173273Ssam		raw->BlockNumber = (u_int64_t)bp->bio_pblkno;
1241173273Ssam		raw->ByteCount = bp->bio_bcount;
1242173273Ssam		raw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1243173273Ssam		raw->BpTotal = 0;
1244170530Ssam		raw->BpComplete = 0;
1245170530Ssam		fib->Header.Size += sizeof(struct aac_raw_io);
1246170530Ssam		cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw;
1247183255Ssam		if (bp->bio_cmd == BIO_READ) {
1248183255Ssam			raw->Flags = 1;
1249183255Ssam			cm->cm_flags |= AAC_CMD_DATAIN;
1250183255Ssam		} else {
1251183255Ssam			raw->Flags = 0;
1252183255Ssam			cm->cm_flags |= AAC_CMD_DATAOUT;
1253183255Ssam		}
1254183255Ssam	} else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1255183255Ssam		fib->Header.Command = ContainerCommand;
1256183255Ssam		if (bp->bio_cmd == BIO_READ) {
1257183255Ssam			struct aac_blockread *br;
1258183255Ssam			br = (struct aac_blockread *)&fib->data[0];
1259183255Ssam			br->Command = VM_CtBlockRead;
1260183255Ssam			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1261183255Ssam			br->BlockNumber = bp->bio_pblkno;
1262183255Ssam			br->ByteCount = bp->bio_bcount;
1263183255Ssam			fib->Header.Size += sizeof(struct aac_blockread);
1264183255Ssam			cm->cm_sgtable = &br->SgMap;
1265183255Ssam			cm->cm_flags |= AAC_CMD_DATAIN;
1266183255Ssam		} else {
1267183255Ssam			struct aac_blockwrite *bw;
1268183255Ssam			bw = (struct aac_blockwrite *)&fib->data[0];
1269183255Ssam			bw->Command = VM_CtBlockWrite;
1270183255Ssam			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1271183255Ssam			bw->BlockNumber = bp->bio_pblkno;
1272183255Ssam			bw->ByteCount = bp->bio_bcount;
1273183254Ssam			bw->Stable = CUNSTABLE;
1274183254Ssam			fib->Header.Size += sizeof(struct aac_blockwrite);
1275183254Ssam			cm->cm_flags |= AAC_CMD_DATAOUT;
1276183254Ssam			cm->cm_sgtable = &bw->SgMap;
1277183254Ssam		}
1278183254Ssam	} else {
1279183254Ssam		fib->Header.Command = ContainerCommand64;
1280183254Ssam		if (bp->bio_cmd == BIO_READ) {
1281183254Ssam			struct aac_blockread64 *br;
1282183254Ssam			br = (struct aac_blockread64 *)&fib->data[0];
1283183254Ssam			br->Command = VM_CtHostRead64;
1284183254Ssam			br->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1285183255Ssam			br->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1286183255Ssam			br->BlockNumber = bp->bio_pblkno;
1287183254Ssam			br->Pad = 0;
1288183254Ssam			br->Flags = 0;
1289183254Ssam			fib->Header.Size += sizeof(struct aac_blockread64);
1290183254Ssam			cm->cm_flags |= AAC_CMD_DATAIN;
1291183254Ssam			cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64;
1292183254Ssam		} else {
1293183254Ssam			struct aac_blockwrite64 *bw;
1294183254Ssam			bw = (struct aac_blockwrite64 *)&fib->data[0];
1295183254Ssam			bw->Command = VM_CtHostWrite64;
1296183254Ssam			bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
1297183254Ssam			bw->SectorCount = bp->bio_bcount / AAC_BLOCK_SIZE;
1298183254Ssam			bw->BlockNumber = bp->bio_pblkno;
1299183254Ssam			bw->Pad = 0;
1300183254Ssam			bw->Flags = 0;
1301183254Ssam			fib->Header.Size += sizeof(struct aac_blockwrite64);
1302183254Ssam			cm->cm_flags |= AAC_CMD_DATAOUT;
1303183254Ssam			cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64;
1304183256Ssam		}
1305183256Ssam	}
1306183256Ssam
1307183256Ssam	*cmp = cm;
1308183256Ssam	return(0);
1309183256Ssam
1310183254Ssamfail:
1311183254Ssam	if (bp != NULL)
1312183254Ssam		aac_enqueue_bio(sc, bp);
1313183254Ssam	if (cm != NULL)
1314183254Ssam		aac_release_command(cm);
1315183254Ssam	return(ENOMEM);
1316183254Ssam}
1317183254Ssam
1318183254Ssam/*
1319183254Ssam * Handle a bio-instigated command that has been completed.
1320183254Ssam */
1321183254Ssamstatic void
1322183254Ssamaac_bio_complete(struct aac_command *cm)
1323183255Ssam{
1324183255Ssam	struct aac_blockread_response *brr;
1325183254Ssam	struct aac_blockwrite_response *bwr;
1326183254Ssam	struct bio *bp;
1327183254Ssam	AAC_FSAStatus status;
1328183254Ssam
1329183254Ssam	/* fetch relevant status and then release the command */
1330183254Ssam	bp = (struct bio *)cm->cm_private;
1331183254Ssam	if (bp->bio_cmd == BIO_READ) {
1332183254Ssam		brr = (struct aac_blockread_response *)&cm->cm_fib->data[0];
1333183254Ssam		status = brr->Status;
1334183254Ssam	} else {
1335183254Ssam		bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0];
1336183254Ssam		status = bwr->Status;
1337183254Ssam	}
1338183254Ssam	aac_release_command(cm);
1339183254Ssam
1340183254Ssam	/* fix up the bio based on status */
1341170530Ssam	if (status == ST_OK) {
1342170530Ssam		bp->bio_resid = 0;
1343170530Ssam	} else {
1344170530Ssam		bp->bio_error = EIO;
1345170530Ssam		bp->bio_flags |= BIO_ERROR;
1346178354Ssam		/* pass an error string out to the disk layer */
1347170530Ssam		bp->bio_driver1 = aac_describe_code(aac_command_status_table,
1348170530Ssam						    status);
1349170530Ssam	}
1350170530Ssam	aac_biodone(bp);
1351170530Ssam}
1352170530Ssam
1353170530Ssam/*
1354170530Ssam * Submit a command to the controller, return when it completes.
1355170530Ssam * XXX This is very dangerous!  If the card has gone out to lunch, we could
1356170530Ssam *     be stuck here forever.  At the same time, signals are not caught
1357170530Ssam *     because there is a risk that a signal could wakeup the sleep before
1358170530Ssam *     the card has a chance to complete the command.  Since there is no way
1359170530Ssam *     to cancel a command that is in progress, we can't protect against the
1360170530Ssam *     card completing a command late and spamming the command and data
1361178354Ssam *     memory.  So, we are held hostage until the command completes.
1362170530Ssam */
1363170530Ssamstatic int
1364170530Ssamaac_wait_command(struct aac_command *cm)
1365178354Ssam{
1366170530Ssam	struct aac_softc *sc;
1367170530Ssam	int error;
1368170530Ssam
1369170530Ssam	sc = cm->cm_sc;
1370170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1371170530Ssam
1372170530Ssam	/* Put the command on the ready queue and get things going */
1373170530Ssam	cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
1374170530Ssam	aac_enqueue_ready(cm);
1375170530Ssam	aac_startio(sc);
1376170530Ssam	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
1377170530Ssam	return(error);
1378170530Ssam}
1379170530Ssam
1380170530Ssam/*
1381170530Ssam *Command Buffer Management
1382170530Ssam */
1383170530Ssam
1384170530Ssam/*
1385170530Ssam * Allocate a command.
1386170530Ssam */
1387170530Ssamint
1388170530Ssamaac_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
1389170530Ssam{
1390178354Ssam	struct aac_command *cm;
1391170530Ssam
1392170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1393170530Ssam
1394170530Ssam	if ((cm = aac_dequeue_free(sc)) == NULL) {
1395170530Ssam		if (sc->total_fibs < sc->aac_max_fibs) {
1396170530Ssam			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1397170530Ssam			wakeup(sc->aifthread);
1398170530Ssam		}
1399170530Ssam		return (EBUSY);
1400170530Ssam	}
1401170530Ssam
1402170530Ssam	*cmp = cm;
1403170530Ssam	return(0);
1404170530Ssam}
1405170530Ssam
1406170530Ssam/*
1407170530Ssam * Release a command back to the freelist.
1408170530Ssam */
1409170530Ssamvoid
1410170530Ssamaac_release_command(struct aac_command *cm)
1411170530Ssam{
1412170530Ssam	struct aac_event *event;
1413170530Ssam	struct aac_softc *sc;
1414170530Ssam
1415170530Ssam	sc = cm->cm_sc;
1416170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1417170530Ssam
1418178354Ssam	/* (re)initialize the command/FIB */
1419170530Ssam	cm->cm_sgtable = NULL;
1420170530Ssam	cm->cm_flags = 0;
1421178354Ssam	cm->cm_complete = NULL;
1422170530Ssam	cm->cm_private = NULL;
1423170530Ssam	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
1424170530Ssam	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
1425170530Ssam	cm->cm_fib->Header.Flags = 0;
1426170530Ssam	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
1427170530Ssam
1428170530Ssam	/*
1429170530Ssam	 * These are duplicated in aac_start to cover the case where an
1430170530Ssam	 * intermediate stage may have destroyed them.  They're left
1431170530Ssam	 * initialized here for debugging purposes only.
1432170530Ssam	 */
1433170530Ssam	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1434170530Ssam	cm->cm_fib->Header.SenderData = 0;
1435170530Ssam
1436170530Ssam	aac_enqueue_free(cm);
1437170530Ssam
1438170530Ssam	/*
1439170530Ssam	 * Dequeue all events so that there's no risk of events getting
1440170530Ssam	 * stranded.
1441170530Ssam	 */
1442170530Ssam	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
1443170530Ssam		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
1444170530Ssam		event->ev_callback(sc, event, event->ev_arg);
1445170530Ssam	}
1446170530Ssam}
1447170530Ssam
1448170530Ssam/*
1449183245Ssam * Map helper for command/FIB allocation.
1450170530Ssam */
1451170530Ssamstatic void
1452170530Ssamaac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1453170530Ssam{
1454170530Ssam	uint64_t	*fibphys;
1455170530Ssam
1456170530Ssam	fibphys = (uint64_t *)arg;
1457170530Ssam
1458170530Ssam	*fibphys = segs[0].ds_addr;
1459170530Ssam}
1460170530Ssam
1461170530Ssam/*
1462170530Ssam * Allocate and initialize commands/FIBs for this adapter.
1463170530Ssam */
1464170530Ssamstatic int
1465170530Ssamaac_alloc_commands(struct aac_softc *sc)
1466170530Ssam{
1467170530Ssam	struct aac_command *cm;
1468170530Ssam	struct aac_fibmap *fm;
1469170530Ssam	uint64_t fibphys;
1470170530Ssam	int i, error;
1471170530Ssam
1472170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1473170530Ssam
1474170530Ssam	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1475170530Ssam		return (ENOMEM);
1476170530Ssam
1477173273Ssam	fm = malloc(sizeof(struct aac_fibmap), M_AACBUF, M_NOWAIT|M_ZERO);
1478173273Ssam	if (fm == NULL)
1479173273Ssam		return (ENOMEM);
1480170530Ssam
1481170530Ssam	/* allocate the FIBs in DMAable memory and load them */
1482170530Ssam	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1483170530Ssam			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1484170530Ssam		device_printf(sc->aac_dev,
1485170530Ssam			      "Not enough contiguous memory available.\n");
1486170530Ssam		free(fm, M_AACBUF);
1487170530Ssam		return (ENOMEM);
1488170530Ssam	}
1489170530Ssam
1490170530Ssam	/* Ignore errors since this doesn't bounce */
1491170530Ssam	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1492170530Ssam			      sc->aac_max_fibs_alloc * sc->aac_max_fib_size,
1493170530Ssam			      aac_map_command_helper, &fibphys, 0);
1494182830Ssam
1495170530Ssam	/* initialize constant fields in the command structure */
1496170530Ssam	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size);
1497170530Ssam	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
1498170530Ssam		cm = sc->aac_commands + sc->total_fibs;
1499170530Ssam		fm->aac_commands = cm;
1500170530Ssam		cm->cm_sc = sc;
1501170530Ssam		cm->cm_fib = (struct aac_fib *)
1502170530Ssam			((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size);
1503170530Ssam		cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size;
1504170530Ssam		cm->cm_index = sc->total_fibs;
1505170530Ssam
1506170530Ssam		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1507170530Ssam					       &cm->cm_datamap)) != 0)
1508170530Ssam			break;
1509170530Ssam		mtx_lock(&sc->aac_io_lock);
1510170530Ssam		aac_release_command(cm);
1511178354Ssam		sc->total_fibs++;
1512170530Ssam		mtx_unlock(&sc->aac_io_lock);
1513170530Ssam	}
1514170530Ssam
1515182829Ssam	if (i > 0) {
1516170530Ssam		mtx_lock(&sc->aac_io_lock);
1517170530Ssam		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1518170530Ssam		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1519170530Ssam		mtx_unlock(&sc->aac_io_lock);
1520170530Ssam		return (0);
1521170530Ssam	}
1522170530Ssam
1523170530Ssam	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1524170530Ssam	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1525170530Ssam	free(fm, M_AACBUF);
1526170530Ssam	return (ENOMEM);
1527170530Ssam}
1528170530Ssam
1529170530Ssam/*
1530170530Ssam * Free FIBs owned by this adapter.
1531170530Ssam */
1532170530Ssamstatic void
1533178354Ssamaac_free_commands(struct aac_softc *sc)
1534170530Ssam{
1535170530Ssam	struct aac_fibmap *fm;
1536170530Ssam	struct aac_command *cm;
1537173273Ssam	int i;
1538173273Ssam
1539173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1540173273Ssam
1541170530Ssam	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1542170530Ssam
1543170530Ssam		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1544170530Ssam		/*
1545170530Ssam		 * We check against total_fibs to handle partially
1546173273Ssam		 * allocated blocks.
1547173273Ssam		 */
1548173273Ssam		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1549173273Ssam			cm = fm->aac_commands + i;
1550173273Ssam			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1551173273Ssam		}
1552178354Ssam		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1553170530Ssam		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1554170530Ssam		free(fm, M_AACBUF);
1555170530Ssam	}
1556170530Ssam}
1557173273Ssam
1558178354Ssam/*
1559173273Ssam * Command-mapping helper function - populate this command's s/g table.
1560173273Ssam */
1561173273Ssamstatic void
1562173273Ssamaac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1563173273Ssam{
1564178354Ssam	struct aac_softc *sc;
1565170530Ssam	struct aac_command *cm;
1566173273Ssam	struct aac_fib *fib;
1567170530Ssam	int i;
1568170530Ssam
1569170530Ssam	cm = (struct aac_command *)arg;
1570170530Ssam	sc = cm->cm_sc;
1571170530Ssam	fib = cm->cm_fib;
1572170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1573170530Ssam
1574170530Ssam	/* copy into the FIB */
1575170530Ssam	if (cm->cm_sgtable != NULL) {
1576170530Ssam		if (fib->Header.Command == RawIo) {
1577170530Ssam			struct aac_sg_tableraw *sg;
1578170530Ssam			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
1579170530Ssam			sg->SgCount = nseg;
1580170530Ssam			for (i = 0; i < nseg; i++) {
1581170530Ssam				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
1582170530Ssam				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
1583182829Ssam				sg->SgEntryRaw[i].Next = 0;
1584170530Ssam				sg->SgEntryRaw[i].Prev = 0;
1585170530Ssam				sg->SgEntryRaw[i].Flags = 0;
1586173273Ssam			}
1587173273Ssam			/* update the FIB size for the s/g count */
1588175877Ssam			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
1589178354Ssam		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1590173273Ssam			struct aac_sg_table *sg;
1591173273Ssam			sg = cm->cm_sgtable;
1592173273Ssam			sg->SgCount = nseg;
1593173273Ssam			for (i = 0; i < nseg; i++) {
1594178354Ssam				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1595173273Ssam				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1596173273Ssam			}
1597173273Ssam			/* update the FIB size for the s/g count */
1598178354Ssam			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1599173273Ssam		} else {
1600173273Ssam			struct aac_sg_table64 *sg;
1601173273Ssam			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1602173273Ssam			sg->SgCount = nseg;
1603173273Ssam			for (i = 0; i < nseg; i++) {
1604178354Ssam				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1605173273Ssam				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1606173273Ssam			}
1607182829Ssam			/* update the FIB size for the s/g count */
1608182829Ssam			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1609182829Ssam		}
1610182829Ssam	}
1611182829Ssam
1612182829Ssam	/* Fix up the address values in the FIB.  Use the command array index
1613182829Ssam	 * instead of a pointer since these fields are only 32 bits.  Shift
1614182829Ssam	 * the SenderFibAddress over to make room for the fast response bit
1615182829Ssam	 * and for the AIF bit
1616182829Ssam	 */
1617182829Ssam	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
1618182829Ssam	cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1619182829Ssam
1620182829Ssam	/* save a pointer to the command for speedy reverse-lookup */
1621182829Ssam	cm->cm_fib->Header.SenderData = cm->cm_index;
1622182829Ssam
1623182829Ssam	if (cm->cm_flags & AAC_CMD_DATAIN)
1624182829Ssam		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1625182829Ssam				BUS_DMASYNC_PREREAD);
1626182829Ssam	if (cm->cm_flags & AAC_CMD_DATAOUT)
1627182829Ssam		bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1628182829Ssam				BUS_DMASYNC_PREWRITE);
1629182829Ssam	cm->cm_flags |= AAC_CMD_MAPPED;
1630182829Ssam
1631182829Ssam	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1632173273Ssam		int count = 10000000L;
1633178354Ssam		while (AAC_SEND_COMMAND(sc, cm) != 0) {
1634170530Ssam			if (--count == 0) {
1635170530Ssam				aac_unmap_command(cm);
1636170530Ssam				sc->flags |= AAC_QUEUE_FRZN;
1637170530Ssam				aac_requeue_ready(cm);
1638170530Ssam			}
1639170530Ssam			DELAY(5);			/* wait 5 usec. */
1640170530Ssam		}
1641170530Ssam	} else {
1642170530Ssam		/* Put the FIB on the outbound queue */
1643170530Ssam		if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) {
1644170530Ssam			aac_unmap_command(cm);
1645170530Ssam			sc->flags |= AAC_QUEUE_FRZN;
1646170530Ssam			aac_requeue_ready(cm);
1647170530Ssam		}
1648170530Ssam	}
1649178354Ssam
1650170530Ssam	return;
1651170530Ssam}
1652170530Ssam
1653170530Ssam/*
1654170530Ssam * Unmap a command from controller-visible space.
1655170530Ssam */
1656170530Ssamstatic void
1657170530Ssamaac_unmap_command(struct aac_command *cm)
1658170530Ssam{
1659170530Ssam	struct aac_softc *sc;
1660170530Ssam
1661170530Ssam	sc = cm->cm_sc;
1662170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1663170530Ssam
1664170530Ssam	if (!(cm->cm_flags & AAC_CMD_MAPPED))
1665170530Ssam		return;
1666170530Ssam
1667173273Ssam	if (cm->cm_datalen != 0) {
1668170530Ssam		if (cm->cm_flags & AAC_CMD_DATAIN)
1669170530Ssam			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1670170530Ssam					BUS_DMASYNC_POSTREAD);
1671170530Ssam		if (cm->cm_flags & AAC_CMD_DATAOUT)
1672170530Ssam			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1673170530Ssam					BUS_DMASYNC_POSTWRITE);
1674170530Ssam
1675170530Ssam		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
1676170530Ssam	}
1677170530Ssam	cm->cm_flags &= ~AAC_CMD_MAPPED;
1678170530Ssam}
1679170530Ssam
1680178354Ssam/*
1681170530Ssam * Hardware Interface
1682170530Ssam */
1683170530Ssam
1684170530Ssam/*
1685170530Ssam * Initialize the adapter.
1686170530Ssam */
1687178354Ssamstatic void
1688170530Ssamaac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1689170530Ssam{
1690170530Ssam	struct aac_softc *sc;
1691178354Ssam
1692170530Ssam	sc = (struct aac_softc *)arg;
1693170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1694170530Ssam
1695170530Ssam	sc->aac_common_busaddr = segs[0].ds_addr;
1696170530Ssam}
1697182831Ssam
1698182831Ssamstatic int
1699182831Ssamaac_check_firmware(struct aac_softc *sc)
1700182831Ssam{
1701170530Ssam	u_int32_t code, major, minor, options = 0, atu_size = 0;
1702170530Ssam	int status;
1703182831Ssam	time_t then;
1704170530Ssam
1705170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1706183255Ssam	/*
1707183255Ssam	 * Wait for the adapter to come ready.
1708183255Ssam	 */
1709183255Ssam	then = time_uptime;
1710183255Ssam	do {
1711183255Ssam		code = AAC_GET_FWSTATUS(sc);
1712183255Ssam		if (code & AAC_SELF_TEST_FAILED) {
1713183255Ssam			device_printf(sc->aac_dev, "FATAL: selftest failed\n");
1714183255Ssam			return(ENXIO);
1715183255Ssam		}
1716183255Ssam		if (code & AAC_KERNEL_PANIC) {
1717183255Ssam			device_printf(sc->aac_dev,
1718183255Ssam				      "FATAL: controller kernel panic");
1719178354Ssam			return(ENXIO);
1720173273Ssam		}
1721183255Ssam		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
1722183255Ssam			device_printf(sc->aac_dev,
1723183255Ssam				      "FATAL: controller not coming ready, "
1724183255Ssam					   "status %x\n", code);
1725183255Ssam			return(ENXIO);
1726183255Ssam		}
1727173273Ssam	} while (!(code & AAC_UP_AND_RUNNING));
1728183255Ssam
1729170530Ssam	/*
1730178354Ssam	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1731170530Ssam	 * firmware version 1.x are not compatible with this driver.
1732170530Ssam	 */
1733170530Ssam	if (sc->flags & AAC_FLAGS_PERC2QC) {
1734178354Ssam		if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1735170530Ssam				     NULL)) {
1736170530Ssam			device_printf(sc->aac_dev,
1737170530Ssam				      "Error reading firmware version\n");
1738170530Ssam			return (EIO);
1739178354Ssam		}
1740170530Ssam
1741170530Ssam		/* These numbers are stored as ASCII! */
1742170530Ssam		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1743178354Ssam		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1744170530Ssam		if (major == 1) {
1745170530Ssam			device_printf(sc->aac_dev,
1746170530Ssam			    "Firmware version %d.%d is not supported.\n",
1747170530Ssam			    major, minor);
1748170530Ssam			return (EINVAL);
1749170530Ssam		}
1750170530Ssam	}
1751170530Ssam
1752170530Ssam	/*
1753178354Ssam	 * Retrieve the capabilities/supported options word so we know what
1754178354Ssam	 * work-arounds to enable.  Some firmware revs don't support this
1755178354Ssam	 * command.
1756178354Ssam	 */
1757178354Ssam	if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) {
1758178354Ssam		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1759178354Ssam			device_printf(sc->aac_dev,
1760178354Ssam			     "RequestAdapterInfo failed\n");
1761178354Ssam			return (EIO);
1762178354Ssam		}
1763178354Ssam	} else {
1764178354Ssam		options = AAC_GET_MAILBOX(sc, 1);
1765178354Ssam		atu_size = AAC_GET_MAILBOX(sc, 2);
1766178354Ssam		sc->supported_options = options;
1767178354Ssam
1768178354Ssam		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1769178354Ssam		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1770178354Ssam			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1771178354Ssam		if (options & AAC_SUPPORTED_NONDASD)
1772178354Ssam			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1773178354Ssam		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1774178354Ssam		     && (sizeof(bus_addr_t) > 4)) {
1775178354Ssam			device_printf(sc->aac_dev,
1776178354Ssam			    "Enabling 64-bit address support\n");
1777178354Ssam			sc->flags |= AAC_FLAGS_SG_64BIT;
1778178354Ssam		}
1779183249Ssam		if ((options & AAC_SUPPORTED_NEW_COMM)
1780183249Ssam		 && sc->aac_if.aif_send_command)
1781178354Ssam			sc->flags |= AAC_FLAGS_NEW_COMM;
1782178354Ssam		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
1783178354Ssam			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1784178354Ssam	}
1785170530Ssam
1786170530Ssam	/* Check for broken hardware that does a lower number of commands */
1787170530Ssam	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
1788170530Ssam
1789170530Ssam	/* Remap mem. resource, if required */
1790170530Ssam	if ((sc->flags & AAC_FLAGS_NEW_COMM) &&
1791170530Ssam		atu_size > rman_get_size(sc->aac_regs_res1)) {
1792170530Ssam		bus_release_resource(
1793170530Ssam			sc->aac_dev, SYS_RES_MEMORY,
1794170530Ssam			sc->aac_regs_rid1, sc->aac_regs_res1);
1795170530Ssam		sc->aac_regs_res1 = bus_alloc_resource(
1796170530Ssam			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1,
1797170530Ssam			0ul, ~0ul, atu_size, RF_ACTIVE);
1798170530Ssam		if (sc->aac_regs_res1 == NULL) {
1799170530Ssam			sc->aac_regs_res1 = bus_alloc_resource_any(
1800170530Ssam				sc->aac_dev, SYS_RES_MEMORY,
1801170530Ssam				&sc->aac_regs_rid1, RF_ACTIVE);
1802170530Ssam			if (sc->aac_regs_res1 == NULL) {
1803170530Ssam				device_printf(sc->aac_dev,
1804173273Ssam				    "couldn't allocate register window\n");
1805173273Ssam				return (ENXIO);
1806173273Ssam			}
1807170530Ssam			sc->flags &= ~AAC_FLAGS_NEW_COMM;
1808183245Ssam		}
1809183245Ssam		sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1);
1810170530Ssam		sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1);
1811170530Ssam
1812170530Ssam		if (sc->aac_hwif == AAC_HWIF_NARK) {
1813170530Ssam			sc->aac_regs_res0 = sc->aac_regs_res1;
1814170530Ssam			sc->aac_regs_rid0 = sc->aac_regs_rid1;
1815170530Ssam			sc->aac_btag0 = sc->aac_btag1;
1816170530Ssam			sc->aac_bhandle0 = sc->aac_bhandle1;
1817170530Ssam		}
1818170530Ssam	}
1819170530Ssam
1820170530Ssam	/* Read preferred settings */
1821178354Ssam	sc->aac_max_fib_size = sizeof(struct aac_fib);
1822173273Ssam	sc->aac_max_sectors = 128;				/* 64KB */
1823173273Ssam	if (sc->flags & AAC_FLAGS_SG_64BIT)
1824173273Ssam		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1825178354Ssam		 - sizeof(struct aac_blockwrite64))
1826178354Ssam		 / sizeof(struct aac_sg_entry64);
1827178354Ssam	else
1828178354Ssam		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1829170530Ssam		 - sizeof(struct aac_blockwrite))
1830170530Ssam		 / sizeof(struct aac_sg_entry);
1831170530Ssam
1832183245Ssam	if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) {
1833183245Ssam		options = AAC_GET_MAILBOX(sc, 1);
1834178953Ssam		sc->aac_max_fib_size = (options & 0xFFFF);
1835178953Ssam		sc->aac_max_sectors = (options >> 16) << 1;
1836170530Ssam		options = AAC_GET_MAILBOX(sc, 2);
1837170530Ssam		sc->aac_sg_tablesize = (options >> 16);
1838170530Ssam		options = AAC_GET_MAILBOX(sc, 3);
1839170530Ssam		sc->aac_max_fibs = (options & 0xFFFF);
1840170530Ssam	}
1841173273Ssam	if (sc->aac_max_fib_size > PAGE_SIZE)
1842173273Ssam		sc->aac_max_fib_size = PAGE_SIZE;
1843173273Ssam	sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size;
1844173273Ssam
1845183250Ssam	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1846183250Ssam		sc->flags |= AAC_FLAGS_RAW_IO;
1847173273Ssam		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1848173273Ssam	}
1849178354Ssam	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1850173273Ssam	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1851173273Ssam		sc->flags |= AAC_FLAGS_LBA_64BIT;
1852173273Ssam		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1853173273Ssam	}
1854178354Ssam
1855183250Ssam	return (0);
1856183250Ssam}
1857178354Ssam
1858173273Ssamstatic int
1859173273Ssamaac_init(struct aac_softc *sc)
1860173273Ssam{
1861173273Ssam	struct aac_adapter_init	*ip;
1862183250Ssam	u_int32_t qoffset;
1863173273Ssam	int error;
1864173273Ssam
1865173273Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1866178354Ssam
1867183250Ssam	/*
1868183250Ssam	 * Fill in the init structure.  This tells the adapter about the
1869178354Ssam	 * physical location of various important shared data structures.
1870173273Ssam	 */
1871173273Ssam	ip = &sc->aac_common->ac_init;
1872173273Ssam	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1873173273Ssam	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1874170530Ssam		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
1875170530Ssam		sc->flags |= AAC_FLAGS_RAW_IO;
1876170530Ssam	}
1877170530Ssam	ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
1878170530Ssam
1879170530Ssam	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1880170530Ssam					 offsetof(struct aac_common, ac_fibs);
1881170530Ssam	ip->AdapterFibsVirtualAddress = 0;
1882178354Ssam	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
1883170530Ssam	ip->AdapterFibAlign = sizeof(struct aac_fib);
1884170530Ssam
1885170530Ssam	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1886170530Ssam				  offsetof(struct aac_common, ac_printf);
1887170530Ssam	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
1888178354Ssam
1889170530Ssam	/*
1890170530Ssam	 * The adapter assumes that pages are 4K in size, except on some
1891170530Ssam 	 * broken firmware versions that do the page->byte conversion twice,
1892170530Ssam	 * therefore 'assuming' that this value is in 16MB units (2^24).
1893170530Ssam	 * Round up since the granularity is so high.
1894170530Ssam	 */
1895170530Ssam	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1896170530Ssam	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1897170530Ssam		ip->HostPhysMemPages =
1898170530Ssam		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1899170530Ssam	}
1900170530Ssam	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
1901170530Ssam
1902170530Ssam	ip->InitFlags = 0;
1903170530Ssam	if (sc->flags & AAC_FLAGS_NEW_COMM) {
1904170530Ssam		ip->InitFlags = INITFLAGS_NEW_COMM_SUPPORTED;
1905170530Ssam		device_printf(sc->aac_dev, "New comm. interface enabled\n");
1906170530Ssam	}
1907170530Ssam
1908170530Ssam	ip->MaxIoCommands = sc->aac_max_fibs;
1909170530Ssam	ip->MaxIoSize = sc->aac_max_sectors << 9;
1910178354Ssam	ip->MaxFibSize = sc->aac_max_fib_size;
1911170530Ssam
1912170530Ssam	/*
1913170530Ssam	 * Initialize FIB queues.  Note that it appears that the layout of the
1914170530Ssam	 * indexes and the segmentation of the entries may be mandated by the
1915170530Ssam	 * adapter, which is only told about the base of the queue index fields.
1916170530Ssam	 *
1917170530Ssam	 * The initial values of the indices are assumed to inform the adapter
1918170530Ssam	 * of the sizes of the respective queues, and theoretically it could
1919170530Ssam	 * work out the entire layout of the queue structures from this.  We
1920170530Ssam	 * take the easy route and just lay this area out like everyone else
1921170530Ssam	 * does.
1922170530Ssam	 *
1923170530Ssam	 * The Linux driver uses a much more complex scheme whereby several
1924170530Ssam	 * header records are kept for each queue.  We use a couple of generic
1925170530Ssam	 * list manipulation functions which 'know' the size of each list by
1926178354Ssam	 * virtue of a table.
1927178354Ssam	 */
1928170530Ssam	qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN;
1929170530Ssam	qoffset &= ~(AAC_QUEUE_ALIGN - 1);
1930178354Ssam	sc->aac_queues =
1931173273Ssam	    (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset);
1932173273Ssam	ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset;
1933170530Ssam
1934178354Ssam	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1935170530Ssam		AAC_HOST_NORM_CMD_ENTRIES;
1936170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1937170530Ssam		AAC_HOST_NORM_CMD_ENTRIES;
1938170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1939170530Ssam		AAC_HOST_HIGH_CMD_ENTRIES;
1940170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1941170530Ssam		AAC_HOST_HIGH_CMD_ENTRIES;
1942170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1943170530Ssam		AAC_ADAP_NORM_CMD_ENTRIES;
1944170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1945170530Ssam		AAC_ADAP_NORM_CMD_ENTRIES;
1946170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
1947170530Ssam		AAC_ADAP_HIGH_CMD_ENTRIES;
1948170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
1949170530Ssam		AAC_ADAP_HIGH_CMD_ENTRIES;
1950170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1951178354Ssam		AAC_HOST_NORM_RESP_ENTRIES;
1952170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1953170530Ssam		AAC_HOST_NORM_RESP_ENTRIES;
1954170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1955170530Ssam		AAC_HOST_HIGH_RESP_ENTRIES;
1956170530Ssam	sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1957178354Ssam		AAC_HOST_HIGH_RESP_ENTRIES;
1958170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1959170530Ssam		AAC_ADAP_NORM_RESP_ENTRIES;
1960170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1961170530Ssam		AAC_ADAP_NORM_RESP_ENTRIES;
1962170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]=
1963170530Ssam		AAC_ADAP_HIGH_RESP_ENTRIES;
1964170530Ssam	sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]=
1965170530Ssam		AAC_ADAP_HIGH_RESP_ENTRIES;
1966170530Ssam	sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] =
1967170530Ssam		&sc->aac_queues->qt_HostNormCmdQueue[0];
1968170530Ssam	sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
1969170530Ssam		&sc->aac_queues->qt_HostHighCmdQueue[0];
1970170530Ssam	sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
1971178354Ssam		&sc->aac_queues->qt_AdapNormCmdQueue[0];
1972170530Ssam	sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
1973170530Ssam		&sc->aac_queues->qt_AdapHighCmdQueue[0];
1974170530Ssam	sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] =
1975170530Ssam		&sc->aac_queues->qt_HostNormRespQueue[0];
1976170530Ssam	sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
1977170530Ssam		&sc->aac_queues->qt_HostHighRespQueue[0];
1978170530Ssam	sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
1979170530Ssam		&sc->aac_queues->qt_AdapNormRespQueue[0];
1980170530Ssam	sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
1981170530Ssam		&sc->aac_queues->qt_AdapHighRespQueue[0];
1982170530Ssam
1983170530Ssam	/*
1984170530Ssam	 * Do controller-type-specific initialisation
1985170530Ssam	 */
1986170530Ssam	switch (sc->aac_hwif) {
1987170530Ssam	case AAC_HWIF_I960RX:
1988170530Ssam		AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0);
1989170530Ssam		break;
1990170530Ssam	case AAC_HWIF_RKT:
1991170530Ssam		AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0);
1992170530Ssam		break;
1993178354Ssam	default:
1994170530Ssam		break;
1995173273Ssam	}
1996173273Ssam
1997173273Ssam	/*
1998173273Ssam	 * Give the init structure to the controller.
1999170530Ssam	 */
2000170530Ssam	if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
2001170530Ssam			     sc->aac_common_busaddr +
2002170530Ssam			     offsetof(struct aac_common, ac_init), 0, 0, 0,
2003170530Ssam			     NULL)) {
2004170530Ssam		device_printf(sc->aac_dev,
2005170530Ssam			      "error establishing init structure\n");
2006178354Ssam		error = EIO;
2007170530Ssam		goto out;
2008170530Ssam	}
2009170530Ssam
2010170530Ssam	error = 0;
2011170530Ssamout:
2012170530Ssam	return(error);
2013170530Ssam}
2014170530Ssam
2015170530Ssamstatic int
2016170530Ssamaac_setup_intr(struct aac_softc *sc)
2017170530Ssam{
2018170530Ssam	sc->aac_irq_rid = 0;
2019170530Ssam	if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ,
2020170530Ssam			   			  &sc->aac_irq_rid,
2021180309Ssam			   			  RF_SHAREABLE |
2022170530Ssam						  RF_ACTIVE)) == NULL) {
2023170530Ssam		device_printf(sc->aac_dev, "can't allocate interrupt\n");
2024170530Ssam		return (EINVAL);
2025170530Ssam	}
2026178354Ssam	if (sc->flags & AAC_FLAGS_NEW_COMM) {
2027170530Ssam		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2028170530Ssam				   INTR_MPSAFE|INTR_TYPE_BIO, NULL,
2029170530Ssam				   aac_new_intr, sc, &sc->aac_intr)) {
2030170530Ssam			device_printf(sc->aac_dev, "can't set up interrupt\n");
2031170530Ssam			return (EINVAL);
2032170530Ssam		}
2033170530Ssam	} else {
2034170530Ssam		if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2035170530Ssam				   INTR_TYPE_BIO, aac_fast_intr, NULL,
2036170530Ssam				   sc, &sc->aac_intr)) {
2037170530Ssam			device_printf(sc->aac_dev,
2038178354Ssam				      "can't set up FAST interrupt\n");
2039170530Ssam			if (bus_setup_intr(sc->aac_dev, sc->aac_irq,
2040170530Ssam					   INTR_MPSAFE|INTR_TYPE_BIO,
2041178354Ssam					   NULL, (driver_intr_t *)aac_fast_intr,
2042170530Ssam					   sc, &sc->aac_intr)) {
2043178354Ssam				device_printf(sc->aac_dev,
2044170530Ssam					     "can't set up MPSAFE interrupt\n");
2045170530Ssam				return (EINVAL);
2046170530Ssam			}
2047170530Ssam		}
2048170530Ssam	}
2049170530Ssam	return (0);
2050170530Ssam}
2051170530Ssam
2052170530Ssam/*
2053178354Ssam * Send a synchronous command to the controller and wait for a result.
2054170530Ssam * Indicate if the controller completed the command with an error status.
2055170530Ssam */
2056170530Ssamstatic int
2057170530Ssamaac_sync_command(struct aac_softc *sc, u_int32_t command,
2058170530Ssam		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
2059170530Ssam		 u_int32_t *sp)
2060170530Ssam{
2061170530Ssam	time_t then;
2062178354Ssam	u_int32_t status;
2063170530Ssam
2064170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2065178354Ssam
2066178354Ssam	/* populate the mailbox */
2067170530Ssam	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
2068170530Ssam
2069170530Ssam	/* ensure the sync command doorbell flag is cleared */
2070170530Ssam	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
2071170530Ssam
2072170530Ssam	/* then set it to signal the adapter */
2073170530Ssam	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
2074170530Ssam
2075170530Ssam	/* spin waiting for the command to complete */
2076170530Ssam	then = time_uptime;
2077170530Ssam	do {
2078170530Ssam		if (time_uptime > (then + AAC_IMMEDIATE_TIMEOUT)) {
2079170530Ssam			fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
2080170530Ssam			return(EIO);
2081170530Ssam		}
2082170530Ssam	} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
2083170530Ssam
2084170530Ssam	/* clear the completion flag */
2085170530Ssam	AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
2086170530Ssam
2087170530Ssam	/* get the command status */
2088170530Ssam	status = AAC_GET_MAILBOX(sc, 0);
2089170530Ssam	if (sp != NULL)
2090170530Ssam		*sp = status;
2091170530Ssam
2092170530Ssam	if (status != AAC_SRB_STS_SUCCESS)
2093170530Ssam		return (-1);
2094170530Ssam	return(0);
2095170530Ssam}
2096170530Ssam
2097170530Ssamint
2098170530Ssamaac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2099170530Ssam		 struct aac_fib *fib, u_int16_t datasize)
2100170530Ssam{
2101178354Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2102170530Ssam	mtx_assert(&sc->aac_io_lock, MA_OWNED);
2103173865Ssam
2104170530Ssam	if (datasize > AAC_FIB_DATASIZE)
2105170530Ssam		return(EINVAL);
2106178354Ssam
2107173273Ssam	/*
2108173273Ssam	 * Set up the sync FIB
2109173273Ssam	 */
2110173273Ssam	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2111173273Ssam				AAC_FIBSTATE_INITIALISED |
2112173273Ssam				AAC_FIBSTATE_EMPTY;
2113173273Ssam	fib->Header.XferState |= xferstate;
2114173273Ssam	fib->Header.Command = command;
2115178354Ssam	fib->Header.StructType = AAC_FIBTYPE_TFIB;
2116173273Ssam	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
2117178354Ssam	fib->Header.SenderSize = sizeof(struct aac_fib);
2118173273Ssam	fib->Header.SenderFibAddress = 0;	/* Not needed */
2119173273Ssam	fib->Header.ReceiverFibAddress = sc->aac_common_busaddr +
2120173273Ssam					 offsetof(struct aac_common,
2121173865Ssam						  ac_sync_fib);
2122173865Ssam
2123173865Ssam	/*
2124173273Ssam	 * Give the FIB to the controller, wait for a response.
2125173273Ssam	 */
2126178354Ssam	if (aac_sync_command(sc, AAC_MONKER_SYNCFIB,
2127173273Ssam			     fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) {
2128173273Ssam		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
2129173273Ssam		return(EIO);
2130178354Ssam	}
2131178354Ssam
2132173273Ssam	return (0);
2133170530Ssam}
2134178354Ssam
2135170530Ssam/*
2136178354Ssam * Adapter-space FIB queue manipulation
2137170530Ssam *
2138170530Ssam * Note that the queue implementation here is a little funky; neither the PI or
2139170530Ssam * CI will ever be zero.  This behaviour is a controller feature.
2140170530Ssam */
2141170530Ssamstatic struct {
2142173865Ssam	int		size;
2143173865Ssam	int		notify;
2144173273Ssam} aac_qinfo[] = {
2145170530Ssam	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
2146170530Ssam	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
2147170530Ssam	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
2148170530Ssam	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
2149170530Ssam	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
2150170530Ssam	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
2151170530Ssam	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
2152173273Ssam	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
2153173273Ssam};
2154173273Ssam
2155173273Ssam/*
2156173273Ssam * Atomically insert an entry into the nominated queue, returns 0 on success or
2157173273Ssam * EBUSY if the queue is full.
2158173273Ssam *
2159170530Ssam * Note: it would be more efficient to defer notifying the controller in
2160170530Ssam *	 the case where we may be inserting several entries in rapid succession,
2161170530Ssam *	 but implementing this usefully may be difficult (it would involve a
2162170530Ssam *	 separate queue/notify interface).
2163170530Ssam */
2164170530Ssamstatic int
2165170530Ssamaac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm)
2166170530Ssam{
2167170530Ssam	u_int32_t pi, ci;
2168170530Ssam	int error;
2169170530Ssam	u_int32_t fib_size;
2170170530Ssam	u_int32_t fib_addr;
2171170530Ssam
2172170530Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2173170530Ssam
2174170530Ssam	fib_size = cm->cm_fib->Header.Size;
2175170530Ssam	fib_addr = cm->cm_fib->Header.ReceiverFibAddress;
2176170530Ssam
2177170530Ssam	/* get the producer/consumer indices */
2178170530Ssam	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
2179170530Ssam	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
2180170530Ssam
2181170530Ssam	/* wrap the queue? */
2182170530Ssam	if (pi >= aac_qinfo[queue].size)
2183170530Ssam		pi = 0;
2184170530Ssam
2185170530Ssam	/* check for queue full */
2186170530Ssam	if ((pi + 1) == ci) {
2187170530Ssam		error = EBUSY;
2188170530Ssam		goto out;
2189170530Ssam	}
2190170530Ssam
2191170530Ssam	/*
2192170530Ssam	 * To avoid a race with its completion interrupt, place this command on
2193170530Ssam	 * the busy queue prior to advertising it to the controller.
2194170530Ssam	 */
2195170530Ssam	aac_enqueue_busy(cm);
2196170530Ssam
2197170530Ssam	/* populate queue entry */
2198170530Ssam	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
2199170530Ssam	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
2200170530Ssam
2201170530Ssam	/* update producer index */
2202170530Ssam	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
2203170530Ssam
2204170530Ssam	/* notify the adapter if we know how */
2205170530Ssam	if (aac_qinfo[queue].notify != 0)
2206170530Ssam		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
2207170530Ssam
2208170530Ssam	error = 0;
2209170530Ssam
2210170530Ssamout:
2211170530Ssam	return(error);
2212170530Ssam}
2213172211Ssam
2214172211Ssam/*
2215172211Ssam * Atomically remove one entry from the nominated queue, returns 0 on
2216178354Ssam * success or ENOENT if the queue is empty.
2217172211Ssam */
2218172211Ssamstatic int
2219172211Ssamaac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
2220178354Ssam		struct aac_fib **fib_addr)
2221178354Ssam{
2222172211Ssam	u_int32_t pi, ci;
2223172211Ssam	u_int32_t fib_index;
2224172211Ssam	int error;
2225172211Ssam	int notify;
2226178354Ssam
2227183256Ssam	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2228183256Ssam
2229183256Ssam	/* get the producer/consumer indices */
2230183256Ssam	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
2231178354Ssam	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
2232172211Ssam
2233178354Ssam	/* check for queue empty */
2234172211Ssam	if (ci == pi) {
2235172211Ssam		error = ENOENT;
2236172211Ssam		goto out;
2237178354Ssam	}
2238172211Ssam
2239172211Ssam	/* wrap the pi so the following test works */
2240172211Ssam	if (pi >= aac_qinfo[queue].size)
2241172211Ssam		pi = 0;
2242172211Ssam
2243172211Ssam	notify = 0;
2244172211Ssam	if (ci == pi + 1)
2245172211Ssam		notify++;
2246172211Ssam
2247172211Ssam	/* wrap the queue? */
2248170530Ssam	if (ci >= aac_qinfo[queue].size)
2249173273Ssam		ci = 0;
2250173273Ssam
2251173273Ssam	/* fetch the entry */
2252173273Ssam	*fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size;
2253170530Ssam
2254170530Ssam	switch (queue) {
2255170530Ssam	case AAC_HOST_NORM_CMD_QUEUE:
2256170530Ssam	case AAC_HOST_HIGH_CMD_QUEUE:
2257183256Ssam		/*
2258170530Ssam		 * The aq_fib_addr is only 32 bits wide so it can't be counted
2259170530Ssam		 * on to hold an address.  For AIF's, the adapter assumes
2260170530Ssam		 * that it's giving us an address into the array of AIF fibs.
2261170530Ssam		 * Therefore, we have to convert it to an index.
2262170530Ssam		 */
2263170530Ssam		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr /
2264178354Ssam			sizeof(struct aac_fib);
2265170530Ssam		*fib_addr = &sc->aac_common->ac_fibs[fib_index];
2266183256Ssam		break;
2267183256Ssam
2268183256Ssam	case AAC_HOST_NORM_RESP_QUEUE:
2269183256Ssam	case AAC_HOST_HIGH_RESP_QUEUE:
2270178354Ssam	{
2271170530Ssam		struct aac_command *cm;
2272178354Ssam
2273170530Ssam		/*
2274170530Ssam		 * As above, an index is used instead of an actual address.
2275170530Ssam		 * Gotta shift the index to account for the fast response
2276178354Ssam		 * bit.  No other correction is needed since this value was
2277170530Ssam		 * originally provided by the driver via the SenderFibAddress
2278170530Ssam		 * field.
2279172211Ssam		 */
2280170530Ssam		fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr;
2281170530Ssam		cm = sc->aac_commands + (fib_index >> 2);
2282170530Ssam		*fib_addr = cm->cm_fib;
2283170530Ssam
2284170530Ssam		/*
2285170530Ssam		 * Is this a fast response? If it is, update the fib fields in
2286170530Ssam		 * local memory since the whole fib isn't DMA'd back up.
2287170530Ssam		 */
2288170530Ssam		if (fib_index & 0x01) {
2289170530Ssam			(*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
2290170530Ssam			*((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
2291170530Ssam		}
2292170530Ssam		break;
2293170530Ssam	}
2294170530Ssam	default:
2295170530Ssam		panic("Invalid queue in aac_dequeue_fib()");
2296170530Ssam		break;
2297170530Ssam	}
2298170530Ssam
2299170530Ssam	/* update consumer index */
2300170530Ssam	sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
2301170530Ssam
2302170530Ssam	/* if we have made the queue un-full, notify the adapter */
2303170530Ssam	if (notify && (aac_qinfo[queue].notify != 0))
2304170530Ssam		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
2305170530Ssam	error = 0;
2306170530Ssam
2307170530Ssamout:
2308170530Ssam	return(error);
2309170530Ssam}
2310170530Ssam
2311170530Ssam/*
2312170530Ssam * Put our response to an Adapter Initialed Fib on the response queue
2313170530Ssam */
2314170530Ssamstatic int
2315170530Ssamaac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib)
2316{
2317	u_int32_t pi, ci;
2318	int error;
2319	u_int32_t fib_size;
2320	u_int32_t fib_addr;
2321
2322	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2323
2324	/* Tell the adapter where the FIB is */
2325	fib_size = fib->Header.Size;
2326	fib_addr = fib->Header.SenderFibAddress;
2327	fib->Header.ReceiverFibAddress = fib_addr;
2328
2329	/* get the producer/consumer indices */
2330	pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX];
2331	ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX];
2332
2333	/* wrap the queue? */
2334	if (pi >= aac_qinfo[queue].size)
2335		pi = 0;
2336
2337	/* check for queue full */
2338	if ((pi + 1) == ci) {
2339		error = EBUSY;
2340		goto out;
2341	}
2342
2343	/* populate queue entry */
2344	(sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size;
2345	(sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr;
2346
2347	/* update producer index */
2348	sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
2349
2350	/* notify the adapter if we know how */
2351	if (aac_qinfo[queue].notify != 0)
2352		AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
2353
2354	error = 0;
2355
2356out:
2357	return(error);
2358}
2359
2360/*
2361 * Check for commands that have been outstanding for a suspiciously long time,
2362 * and complain about them.
2363 */
2364static void
2365aac_timeout(struct aac_softc *sc)
2366{
2367	struct aac_command *cm;
2368	time_t deadline;
2369	int timedout, code;
2370
2371	/*
2372	 * Traverse the busy command list, bitch about late commands once
2373	 * only.
2374	 */
2375	timedout = 0;
2376	deadline = time_uptime - AAC_CMD_TIMEOUT;
2377	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
2378		if ((cm->cm_timestamp  < deadline)
2379			/* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) {
2380			cm->cm_flags |= AAC_CMD_TIMEDOUT;
2381			device_printf(sc->aac_dev,
2382				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2383				      cm, (int)(time_uptime-cm->cm_timestamp));
2384			AAC_PRINT_FIB(sc, cm->cm_fib);
2385			timedout++;
2386		}
2387	}
2388
2389	if (timedout) {
2390		code = AAC_GET_FWSTATUS(sc);
2391		if (code != AAC_UP_AND_RUNNING) {
2392			device_printf(sc->aac_dev, "WARNING! Controller is no "
2393				      "longer running! code= 0x%x\n", code);
2394		}
2395	}
2396	return;
2397}
2398
2399/*
2400 * Interface Function Vectors
2401 */
2402
2403/*
2404 * Read the current firmware status word.
2405 */
2406static int
2407aac_sa_get_fwstatus(struct aac_softc *sc)
2408{
2409	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2410
2411	return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS));
2412}
2413
2414static int
2415aac_rx_get_fwstatus(struct aac_softc *sc)
2416{
2417	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2418
2419	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
2420	    AAC_RX_OMR0 : AAC_RX_FWSTATUS));
2421}
2422
2423static int
2424aac_fa_get_fwstatus(struct aac_softc *sc)
2425{
2426	int val;
2427
2428	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2429
2430	val = AAC_MEM0_GETREG4(sc, AAC_FA_FWSTATUS);
2431	return (val);
2432}
2433
2434static int
2435aac_rkt_get_fwstatus(struct aac_softc *sc)
2436{
2437	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2438
2439	return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ?
2440	    AAC_RKT_OMR0 : AAC_RKT_FWSTATUS));
2441}
2442
2443/*
2444 * Notify the controller of a change in a given queue
2445 */
2446
2447static void
2448aac_sa_qnotify(struct aac_softc *sc, int qbit)
2449{
2450	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2451
2452	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
2453}
2454
2455static void
2456aac_rx_qnotify(struct aac_softc *sc, int qbit)
2457{
2458	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2459
2460	AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit);
2461}
2462
2463static void
2464aac_fa_qnotify(struct aac_softc *sc, int qbit)
2465{
2466	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2467
2468	AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL1, qbit);
2469	AAC_FA_HACK(sc);
2470}
2471
2472static void
2473aac_rkt_qnotify(struct aac_softc *sc, int qbit)
2474{
2475	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2476
2477	AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit);
2478}
2479
2480/*
2481 * Get the interrupt reason bits
2482 */
2483static int
2484aac_sa_get_istatus(struct aac_softc *sc)
2485{
2486	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2487
2488	return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0));
2489}
2490
2491static int
2492aac_rx_get_istatus(struct aac_softc *sc)
2493{
2494	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2495
2496	return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR));
2497}
2498
2499static int
2500aac_fa_get_istatus(struct aac_softc *sc)
2501{
2502	int val;
2503
2504	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2505
2506	val = AAC_MEM0_GETREG2(sc, AAC_FA_DOORBELL0);
2507	return (val);
2508}
2509
2510static int
2511aac_rkt_get_istatus(struct aac_softc *sc)
2512{
2513	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2514
2515	return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR));
2516}
2517
2518/*
2519 * Clear some interrupt reason bits
2520 */
2521static void
2522aac_sa_clear_istatus(struct aac_softc *sc, int mask)
2523{
2524	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2525
2526	AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
2527}
2528
2529static void
2530aac_rx_clear_istatus(struct aac_softc *sc, int mask)
2531{
2532	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2533
2534	AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask);
2535}
2536
2537static void
2538aac_fa_clear_istatus(struct aac_softc *sc, int mask)
2539{
2540	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2541
2542	AAC_MEM0_SETREG2(sc, AAC_FA_DOORBELL0_CLEAR, mask);
2543	AAC_FA_HACK(sc);
2544}
2545
2546static void
2547aac_rkt_clear_istatus(struct aac_softc *sc, int mask)
2548{
2549	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2550
2551	AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask);
2552}
2553
2554/*
2555 * Populate the mailbox and set the command word
2556 */
2557static void
2558aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2559		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2560{
2561	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2562
2563	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command);
2564	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
2565	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
2566	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
2567	AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
2568}
2569
2570static void
2571aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
2572		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2573{
2574	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2575
2576	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command);
2577	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
2578	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
2579	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
2580	AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
2581}
2582
2583static void
2584aac_fa_set_mailbox(struct aac_softc *sc, u_int32_t command,
2585		u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2586{
2587	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2588
2589	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX, command);
2590	AAC_FA_HACK(sc);
2591	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 4, arg0);
2592	AAC_FA_HACK(sc);
2593	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 8, arg1);
2594	AAC_FA_HACK(sc);
2595	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 12, arg2);
2596	AAC_FA_HACK(sc);
2597	AAC_MEM1_SETREG4(sc, AAC_FA_MAILBOX + 16, arg3);
2598	AAC_FA_HACK(sc);
2599}
2600
2601static void
2602aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2603		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2604{
2605	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2606
2607	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command);
2608	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0);
2609	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1);
2610	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2);
2611	AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3);
2612}
2613
2614/*
2615 * Fetch the immediate command status word
2616 */
2617static int
2618aac_sa_get_mailbox(struct aac_softc *sc, int mb)
2619{
2620	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2621
2622	return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
2623}
2624
2625static int
2626aac_rx_get_mailbox(struct aac_softc *sc, int mb)
2627{
2628	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2629
2630	return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
2631}
2632
2633static int
2634aac_fa_get_mailbox(struct aac_softc *sc, int mb)
2635{
2636	int val;
2637
2638	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2639
2640	val = AAC_MEM1_GETREG4(sc, AAC_FA_MAILBOX + (mb * 4));
2641	return (val);
2642}
2643
2644static int
2645aac_rkt_get_mailbox(struct aac_softc *sc, int mb)
2646{
2647	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2648
2649	return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4)));
2650}
2651
2652/*
2653 * Set/clear interrupt masks
2654 */
2655static void
2656aac_sa_set_interrupts(struct aac_softc *sc, int enable)
2657{
2658	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2659
2660	if (enable) {
2661		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2662	} else {
2663		AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
2664	}
2665}
2666
2667static void
2668aac_rx_set_interrupts(struct aac_softc *sc, int enable)
2669{
2670	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2671
2672	if (enable) {
2673		if (sc->flags & AAC_FLAGS_NEW_COMM)
2674			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM);
2675		else
2676			AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
2677	} else {
2678		AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0);
2679	}
2680}
2681
2682static void
2683aac_fa_set_interrupts(struct aac_softc *sc, int enable)
2684{
2685	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2686
2687	if (enable) {
2688		AAC_MEM0_SETREG2((sc), AAC_FA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
2689		AAC_FA_HACK(sc);
2690	} else {
2691		AAC_MEM0_SETREG2((sc), AAC_FA_MASK0, ~0);
2692		AAC_FA_HACK(sc);
2693	}
2694}
2695
2696static void
2697aac_rkt_set_interrupts(struct aac_softc *sc, int enable)
2698{
2699	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis");
2700
2701	if (enable) {
2702		if (sc->flags & AAC_FLAGS_NEW_COMM)
2703			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM);
2704		else
2705			AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS);
2706	} else {
2707		AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0);
2708	}
2709}
2710
2711/*
2712 * New comm. interface: Send command functions
2713 */
2714static int
2715aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm)
2716{
2717	u_int32_t index, device;
2718
2719	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
2720
2721	index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
2722	if (index == 0xffffffffL)
2723		index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE);
2724	if (index == 0xffffffffL)
2725		return index;
2726	aac_enqueue_busy(cm);
2727	device = index;
2728	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2729	device += 4;
2730	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2731	device += 4;
2732	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2733	AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index);
2734	return 0;
2735}
2736
2737static int
2738aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm)
2739{
2740	u_int32_t index, device;
2741
2742	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)");
2743
2744	index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
2745	if (index == 0xffffffffL)
2746		index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE);
2747	if (index == 0xffffffffL)
2748		return index;
2749	aac_enqueue_busy(cm);
2750	device = index;
2751	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL));
2752	device += 4;
2753	AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32));
2754	device += 4;
2755	AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size);
2756	AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index);
2757	return 0;
2758}
2759
2760/*
2761 * New comm. interface: get, set outbound queue index
2762 */
2763static int
2764aac_rx_get_outb_queue(struct aac_softc *sc)
2765{
2766	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2767
2768	return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE));
2769}
2770
2771static int
2772aac_rkt_get_outb_queue(struct aac_softc *sc)
2773{
2774	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2775
2776	return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE));
2777}
2778
2779static void
2780aac_rx_set_outb_queue(struct aac_softc *sc, int index)
2781{
2782	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2783
2784	AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index);
2785}
2786
2787static void
2788aac_rkt_set_outb_queue(struct aac_softc *sc, int index)
2789{
2790	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2791
2792	AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index);
2793}
2794
2795/*
2796 * Debugging and Diagnostics
2797 */
2798
2799/*
2800 * Print some information about the controller.
2801 */
2802static void
2803aac_describe_controller(struct aac_softc *sc)
2804{
2805	struct aac_fib *fib;
2806	struct aac_adapter_info	*info;
2807	char *adapter_type = "Adaptec RAID controller";
2808
2809	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2810
2811	mtx_lock(&sc->aac_io_lock);
2812	aac_alloc_sync_fib(sc, &fib);
2813
2814	fib->data[0] = 0;
2815	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
2816		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2817		aac_release_sync_fib(sc);
2818		mtx_unlock(&sc->aac_io_lock);
2819		return;
2820	}
2821
2822	/* save the kernel revision structure for later use */
2823	info = (struct aac_adapter_info *)&fib->data[0];
2824	sc->aac_revision = info->KernelRevision;
2825
2826	if (bootverbose) {
2827		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2828		    "(%dMB cache, %dMB execution), %s\n",
2829		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2830		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2831		    info->BufferMem / (1024 * 1024),
2832		    info->ExecutionMem / (1024 * 1024),
2833		    aac_describe_code(aac_battery_platform,
2834		    info->batteryPlatform));
2835
2836		device_printf(sc->aac_dev,
2837		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2838		    info->KernelRevision.external.comp.major,
2839		    info->KernelRevision.external.comp.minor,
2840		    info->KernelRevision.external.comp.dash,
2841		    info->KernelRevision.buildNumber,
2842		    (u_int32_t)(info->SerialNumber & 0xffffff));
2843
2844		device_printf(sc->aac_dev, "Supported Options=%b\n",
2845			      sc->supported_options,
2846			      "\20"
2847			      "\1SNAPSHOT"
2848			      "\2CLUSTERS"
2849			      "\3WCACHE"
2850			      "\4DATA64"
2851			      "\5HOSTTIME"
2852			      "\6RAID50"
2853			      "\7WINDOW4GB"
2854			      "\10SCSIUPGD"
2855			      "\11SOFTERR"
2856			      "\12NORECOND"
2857			      "\13SGMAP64"
2858			      "\14ALARM"
2859			      "\15NONDASD"
2860			      "\16SCSIMGT"
2861			      "\17RAIDSCSI"
2862			      "\21ADPTINFO"
2863			      "\22NEWCOMM"
2864			      "\23ARRAY64BIT"
2865			      "\24HEATSENSOR");
2866	}
2867
2868	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
2869		fib->data[0] = 0;
2870		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
2871			device_printf(sc->aac_dev,
2872			    "RequestSupplementAdapterInfo failed\n");
2873		else
2874			adapter_type = ((struct aac_supplement_adapter_info *)
2875			    &fib->data[0])->AdapterTypeText;
2876	}
2877	device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n",
2878		adapter_type,
2879		AAC_DRIVER_VERSION >> 24,
2880		(AAC_DRIVER_VERSION >> 16) & 0xFF,
2881		AAC_DRIVER_VERSION & 0xFF,
2882		AAC_DRIVER_BUILD);
2883
2884	aac_release_sync_fib(sc);
2885	mtx_unlock(&sc->aac_io_lock);
2886}
2887
2888/*
2889 * Look up a text description of a numeric error code and return a pointer to
2890 * same.
2891 */
2892static char *
2893aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
2894{
2895	int i;
2896
2897	for (i = 0; table[i].string != NULL; i++)
2898		if (table[i].code == code)
2899			return(table[i].string);
2900	return(table[i + 1].string);
2901}
2902
2903/*
2904 * Management Interface
2905 */
2906
2907static int
2908aac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2909{
2910	struct aac_softc *sc;
2911
2912	sc = dev->si_drv1;
2913	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2914	sc->aac_open_cnt++;
2915	sc->aac_state |= AAC_STATE_OPEN;
2916
2917	return 0;
2918}
2919
2920static int
2921aac_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2922{
2923	struct aac_softc *sc;
2924
2925	sc = dev->si_drv1;
2926	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2927	sc->aac_open_cnt--;
2928	/* Mark this unit as no longer open  */
2929	if (sc->aac_open_cnt == 0)
2930		sc->aac_state &= ~AAC_STATE_OPEN;
2931
2932	return 0;
2933}
2934
2935static int
2936aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
2937{
2938	union aac_statrequest *as;
2939	struct aac_softc *sc;
2940	int error = 0;
2941
2942	as = (union aac_statrequest *)arg;
2943	sc = dev->si_drv1;
2944	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2945
2946	switch (cmd) {
2947	case AACIO_STATS:
2948		switch (as->as_item) {
2949		case AACQ_FREE:
2950		case AACQ_BIO:
2951		case AACQ_READY:
2952		case AACQ_BUSY:
2953			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2954			      sizeof(struct aac_qstat));
2955			break;
2956		default:
2957			error = ENOENT;
2958			break;
2959		}
2960	break;
2961
2962	case FSACTL_SENDFIB:
2963	case FSACTL_SEND_LARGE_FIB:
2964		arg = *(caddr_t*)arg;
2965	case FSACTL_LNX_SENDFIB:
2966	case FSACTL_LNX_SEND_LARGE_FIB:
2967		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
2968		error = aac_ioctl_sendfib(sc, arg);
2969		break;
2970	case FSACTL_SEND_RAW_SRB:
2971		arg = *(caddr_t*)arg;
2972	case FSACTL_LNX_SEND_RAW_SRB:
2973		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2974		error = aac_ioctl_send_raw_srb(sc, arg);
2975		break;
2976	case FSACTL_AIF_THREAD:
2977	case FSACTL_LNX_AIF_THREAD:
2978		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
2979		error = EINVAL;
2980		break;
2981	case FSACTL_OPEN_GET_ADAPTER_FIB:
2982		arg = *(caddr_t*)arg;
2983	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
2984		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2985		error = aac_open_aif(sc, arg);
2986		break;
2987	case FSACTL_GET_NEXT_ADAPTER_FIB:
2988		arg = *(caddr_t*)arg;
2989	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
2990		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2991		error = aac_getnext_aif(sc, arg);
2992		break;
2993	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2994		arg = *(caddr_t*)arg;
2995	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
2996		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2997		error = aac_close_aif(sc, arg);
2998		break;
2999	case FSACTL_MINIPORT_REV_CHECK:
3000		arg = *(caddr_t*)arg;
3001	case FSACTL_LNX_MINIPORT_REV_CHECK:
3002		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
3003		error = aac_rev_check(sc, arg);
3004		break;
3005	case FSACTL_QUERY_DISK:
3006		arg = *(caddr_t*)arg;
3007	case FSACTL_LNX_QUERY_DISK:
3008		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
3009		error = aac_query_disk(sc, arg);
3010		break;
3011	case FSACTL_DELETE_DISK:
3012	case FSACTL_LNX_DELETE_DISK:
3013		/*
3014		 * We don't trust the underland to tell us when to delete a
3015		 * container, rather we rely on an AIF coming from the
3016		 * controller
3017		 */
3018		error = 0;
3019		break;
3020	case FSACTL_GET_PCI_INFO:
3021		arg = *(caddr_t*)arg;
3022	case FSACTL_LNX_GET_PCI_INFO:
3023		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
3024		error = aac_get_pci_info(sc, arg);
3025		break;
3026	case FSACTL_GET_FEATURES:
3027		arg = *(caddr_t*)arg;
3028	case FSACTL_LNX_GET_FEATURES:
3029		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
3030		error = aac_supported_features(sc, arg);
3031		break;
3032	default:
3033		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
3034		error = EINVAL;
3035		break;
3036	}
3037	return(error);
3038}
3039
3040static int
3041aac_poll(struct cdev *dev, int poll_events, struct thread *td)
3042{
3043	struct aac_softc *sc;
3044	struct aac_fib_context *ctx;
3045	int revents;
3046
3047	sc = dev->si_drv1;
3048	revents = 0;
3049
3050	mtx_lock(&sc->aac_aifq_lock);
3051	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
3052		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3053			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
3054				revents |= poll_events & (POLLIN | POLLRDNORM);
3055				break;
3056			}
3057		}
3058	}
3059	mtx_unlock(&sc->aac_aifq_lock);
3060
3061	if (revents == 0) {
3062		if (poll_events & (POLLIN | POLLRDNORM))
3063			selrecord(td, &sc->rcv_select);
3064	}
3065
3066	return (revents);
3067}
3068
3069static void
3070aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
3071{
3072
3073	switch (event->ev_type) {
3074	case AAC_EVENT_CMFREE:
3075		mtx_assert(&sc->aac_io_lock, MA_OWNED);
3076		if (aac_alloc_command(sc, (struct aac_command **)arg)) {
3077			aac_add_event(sc, event);
3078			return;
3079		}
3080		free(event, M_AACBUF);
3081		wakeup(arg);
3082		break;
3083	default:
3084		break;
3085	}
3086}
3087
3088/*
3089 * Send a FIB supplied from userspace
3090 */
3091static int
3092aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
3093{
3094	struct aac_command *cm;
3095	int size, error;
3096
3097	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3098
3099	cm = NULL;
3100
3101	/*
3102	 * Get a command
3103	 */
3104	mtx_lock(&sc->aac_io_lock);
3105	if (aac_alloc_command(sc, &cm)) {
3106		struct aac_event *event;
3107
3108		event = malloc(sizeof(struct aac_event), M_AACBUF,
3109		    M_NOWAIT | M_ZERO);
3110		if (event == NULL) {
3111			error = EBUSY;
3112			mtx_unlock(&sc->aac_io_lock);
3113			goto out;
3114		}
3115		event->ev_type = AAC_EVENT_CMFREE;
3116		event->ev_callback = aac_ioctl_event;
3117		event->ev_arg = &cm;
3118		aac_add_event(sc, event);
3119		msleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0);
3120	}
3121	mtx_unlock(&sc->aac_io_lock);
3122
3123	/*
3124	 * Fetch the FIB header, then re-copy to get data as well.
3125	 */
3126	if ((error = copyin(ufib, cm->cm_fib,
3127			    sizeof(struct aac_fib_header))) != 0)
3128		goto out;
3129	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
3130	if (size > sc->aac_max_fib_size) {
3131		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
3132			      size, sc->aac_max_fib_size);
3133		size = sc->aac_max_fib_size;
3134	}
3135	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
3136		goto out;
3137	cm->cm_fib->Header.Size = size;
3138	cm->cm_timestamp = time_uptime;
3139
3140	/*
3141	 * Pass the FIB to the controller, wait for it to complete.
3142	 */
3143	mtx_lock(&sc->aac_io_lock);
3144	error = aac_wait_command(cm);
3145	mtx_unlock(&sc->aac_io_lock);
3146	if (error != 0) {
3147		device_printf(sc->aac_dev,
3148			      "aac_wait_command return %d\n", error);
3149		goto out;
3150	}
3151
3152	/*
3153	 * Copy the FIB and data back out to the caller.
3154	 */
3155	size = cm->cm_fib->Header.Size;
3156	if (size > sc->aac_max_fib_size) {
3157		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
3158			      size, sc->aac_max_fib_size);
3159		size = sc->aac_max_fib_size;
3160	}
3161	error = copyout(cm->cm_fib, ufib, size);
3162
3163out:
3164	if (cm != NULL) {
3165		mtx_lock(&sc->aac_io_lock);
3166		aac_release_command(cm);
3167		mtx_unlock(&sc->aac_io_lock);
3168	}
3169	return(error);
3170}
3171
3172/*
3173 * Send a passthrough FIB supplied from userspace
3174 */
3175static int
3176aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
3177{
3178	return (EINVAL);
3179}
3180
3181/*
3182 * Handle an AIF sent to us by the controller; queue it for later reference.
3183 * If the queue fills up, then drop the older entries.
3184 */
3185static void
3186aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
3187{
3188	struct aac_aif_command *aif;
3189	struct aac_container *co, *co_next;
3190	struct aac_fib_context *ctx;
3191	struct aac_mntinforesp *mir;
3192	int next, current, found;
3193	int count = 0, added = 0, i = 0;
3194
3195	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3196
3197	aif = (struct aac_aif_command*)&fib->data[0];
3198	aac_print_aif(sc, aif);
3199
3200	/* Is it an event that we should care about? */
3201	switch (aif->command) {
3202	case AifCmdEventNotify:
3203		switch (aif->data.EN.type) {
3204		case AifEnAddContainer:
3205		case AifEnDeleteContainer:
3206			/*
3207			 * A container was added or deleted, but the message
3208			 * doesn't tell us anything else!  Re-enumerate the
3209			 * containers and sort things out.
3210			 */
3211			aac_alloc_sync_fib(sc, &fib);
3212			do {
3213				/*
3214				 * Ask the controller for its containers one at
3215				 * a time.
3216				 * XXX What if the controller's list changes
3217				 * midway through this enumaration?
3218				 * XXX This should be done async.
3219				 */
3220				if ((mir = aac_get_container_info(sc, fib, i)) == NULL)
3221					continue;
3222				if (i == 0)
3223					count = mir->MntRespCount;
3224				/*
3225				 * Check the container against our list.
3226				 * co->co_found was already set to 0 in a
3227				 * previous run.
3228				 */
3229				if ((mir->Status == ST_OK) &&
3230				    (mir->MntTable[0].VolType != CT_NONE)) {
3231					found = 0;
3232					TAILQ_FOREACH(co,
3233						      &sc->aac_container_tqh,
3234						      co_link) {
3235						if (co->co_mntobj.ObjectId ==
3236						    mir->MntTable[0].ObjectId) {
3237							co->co_found = 1;
3238							found = 1;
3239							break;
3240						}
3241					}
3242					/*
3243					 * If the container matched, continue
3244					 * in the list.
3245					 */
3246					if (found) {
3247						i++;
3248						continue;
3249					}
3250
3251					/*
3252					 * This is a new container.  Do all the
3253					 * appropriate things to set it up.
3254					 */
3255					aac_add_container(sc, mir, 1);
3256					added = 1;
3257				}
3258				i++;
3259			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3260			aac_release_sync_fib(sc);
3261
3262			/*
3263			 * Go through our list of containers and see which ones
3264			 * were not marked 'found'.  Since the controller didn't
3265			 * list them they must have been deleted.  Do the
3266			 * appropriate steps to destroy the device.  Also reset
3267			 * the co->co_found field.
3268			 */
3269			co = TAILQ_FIRST(&sc->aac_container_tqh);
3270			while (co != NULL) {
3271				if (co->co_found == 0) {
3272					mtx_unlock(&sc->aac_io_lock);
3273					newbus_xlock();
3274					device_delete_child(sc->aac_dev,
3275							    co->co_disk);
3276					newbus_xunlock();
3277					mtx_lock(&sc->aac_io_lock);
3278					co_next = TAILQ_NEXT(co, co_link);
3279					mtx_lock(&sc->aac_container_lock);
3280					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3281						     co_link);
3282					mtx_unlock(&sc->aac_container_lock);
3283					free(co, M_AACBUF);
3284					co = co_next;
3285				} else {
3286					co->co_found = 0;
3287					co = TAILQ_NEXT(co, co_link);
3288				}
3289			}
3290
3291			/* Attach the newly created containers */
3292			if (added) {
3293				mtx_unlock(&sc->aac_io_lock);
3294				newbus_xlock();
3295				bus_generic_attach(sc->aac_dev);
3296				newbus_xunlock();
3297				mtx_lock(&sc->aac_io_lock);
3298			}
3299
3300			break;
3301
3302		default:
3303			break;
3304		}
3305
3306	default:
3307		break;
3308	}
3309
3310	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3311	mtx_lock(&sc->aac_aifq_lock);
3312	current = sc->aifq_idx;
3313	next = (current + 1) % AAC_AIFQ_LENGTH;
3314	if (next == 0)
3315		sc->aifq_filled = 1;
3316	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3317	/* modify AIF contexts */
3318	if (sc->aifq_filled) {
3319		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3320			if (next == ctx->ctx_idx)
3321				ctx->ctx_wrap = 1;
3322			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3323				ctx->ctx_idx = next;
3324		}
3325	}
3326	sc->aifq_idx = next;
3327	/* On the off chance that someone is sleeping for an aif... */
3328	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
3329		wakeup(sc->aac_aifq);
3330	/* Wakeup any poll()ers */
3331	selwakeuppri(&sc->rcv_select, PRIBIO);
3332	mtx_unlock(&sc->aac_aifq_lock);
3333
3334	return;
3335}
3336
3337/*
3338 * Return the Revision of the driver to userspace and check to see if the
3339 * userspace app is possibly compatible.  This is extremely bogus since
3340 * our driver doesn't follow Adaptec's versioning system.  Cheat by just
3341 * returning what the card reported.
3342 */
3343static int
3344aac_rev_check(struct aac_softc *sc, caddr_t udata)
3345{
3346	struct aac_rev_check rev_check;
3347	struct aac_rev_check_resp rev_check_resp;
3348	int error = 0;
3349
3350	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3351
3352	/*
3353	 * Copyin the revision struct from userspace
3354	 */
3355	if ((error = copyin(udata, (caddr_t)&rev_check,
3356			sizeof(struct aac_rev_check))) != 0) {
3357		return error;
3358	}
3359
3360	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3361	      rev_check.callingRevision.buildNumber);
3362
3363	/*
3364	 * Doctor up the response struct.
3365	 */
3366	rev_check_resp.possiblyCompatible = 1;
3367	rev_check_resp.adapterSWRevision.external.ul =
3368	    sc->aac_revision.external.ul;
3369	rev_check_resp.adapterSWRevision.buildNumber =
3370	    sc->aac_revision.buildNumber;
3371
3372	return(copyout((caddr_t)&rev_check_resp, udata,
3373			sizeof(struct aac_rev_check_resp)));
3374}
3375
3376/*
3377 * Pass the fib context to the caller
3378 */
3379static int
3380aac_open_aif(struct aac_softc *sc, caddr_t arg)
3381{
3382	struct aac_fib_context *fibctx, *ctx;
3383	int error = 0;
3384
3385	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3386
3387	fibctx = malloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO);
3388	if (fibctx == NULL)
3389		return (ENOMEM);
3390
3391	mtx_lock(&sc->aac_aifq_lock);
3392	/* all elements are already 0, add to queue */
3393	if (sc->fibctx == NULL)
3394		sc->fibctx = fibctx;
3395	else {
3396		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3397			;
3398		ctx->next = fibctx;
3399		fibctx->prev = ctx;
3400	}
3401
3402	/* evaluate unique value */
3403	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3404	ctx = sc->fibctx;
3405	while (ctx != fibctx) {
3406		if (ctx->unique == fibctx->unique) {
3407			fibctx->unique++;
3408			ctx = sc->fibctx;
3409		} else {
3410			ctx = ctx->next;
3411		}
3412	}
3413	mtx_unlock(&sc->aac_aifq_lock);
3414
3415	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3416	if (error)
3417		aac_close_aif(sc, (caddr_t)ctx);
3418	return error;
3419}
3420
3421/*
3422 * Close the caller's fib context
3423 */
3424static int
3425aac_close_aif(struct aac_softc *sc, caddr_t arg)
3426{
3427	struct aac_fib_context *ctx;
3428
3429	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3430
3431	mtx_lock(&sc->aac_aifq_lock);
3432	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3433		if (ctx->unique == *(uint32_t *)&arg) {
3434			if (ctx == sc->fibctx)
3435				sc->fibctx = NULL;
3436			else {
3437				ctx->prev->next = ctx->next;
3438				if (ctx->next)
3439					ctx->next->prev = ctx->prev;
3440			}
3441			break;
3442		}
3443	}
3444	mtx_unlock(&sc->aac_aifq_lock);
3445	if (ctx)
3446		free(ctx, M_AACBUF);
3447
3448	return 0;
3449}
3450
3451/*
3452 * Pass the caller the next AIF in their queue
3453 */
3454static int
3455aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
3456{
3457	struct get_adapter_fib_ioctl agf;
3458	struct aac_fib_context *ctx;
3459	int error;
3460
3461	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3462
3463	if ((error = copyin(arg, &agf, sizeof(agf))) == 0) {
3464		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3465			if (agf.AdapterFibContext == ctx->unique)
3466				break;
3467		}
3468		if (!ctx)
3469			return (EFAULT);
3470
3471		error = aac_return_aif(sc, ctx, agf.AifFib);
3472		if (error == EAGAIN && agf.Wait) {
3473			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
3474			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
3475			while (error == EAGAIN) {
3476				error = tsleep(sc->aac_aifq, PRIBIO |
3477					       PCATCH, "aacaif", 0);
3478				if (error == 0)
3479					error = aac_return_aif(sc, ctx, agf.AifFib);
3480			}
3481			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
3482		}
3483	}
3484	return(error);
3485}
3486
3487/*
3488 * Hand the next AIF off the top of the queue out to userspace.
3489 */
3490static int
3491aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
3492{
3493	int current, error;
3494
3495	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3496
3497	mtx_lock(&sc->aac_aifq_lock);
3498	current = ctx->ctx_idx;
3499	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3500		/* empty */
3501		mtx_unlock(&sc->aac_aifq_lock);
3502		return (EAGAIN);
3503	}
3504	error =
3505		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
3506	if (error)
3507		device_printf(sc->aac_dev,
3508		    "aac_return_aif: copyout returned %d\n", error);
3509	else {
3510		ctx->ctx_wrap = 0;
3511		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3512	}
3513	mtx_unlock(&sc->aac_aifq_lock);
3514	return(error);
3515}
3516
3517static int
3518aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
3519{
3520	struct aac_pci_info {
3521		u_int32_t bus;
3522		u_int32_t slot;
3523	} pciinf;
3524	int error;
3525
3526	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3527
3528	pciinf.bus = pci_get_bus(sc->aac_dev);
3529	pciinf.slot = pci_get_slot(sc->aac_dev);
3530
3531	error = copyout((caddr_t)&pciinf, uptr,
3532			sizeof(struct aac_pci_info));
3533
3534	return (error);
3535}
3536
3537static int
3538aac_supported_features(struct aac_softc *sc, caddr_t uptr)
3539{
3540	struct aac_features f;
3541	int error;
3542
3543	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3544
3545	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
3546		return (error);
3547
3548	/*
3549	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
3550	 * ALL zero in the featuresState, the driver will return the current
3551	 * state of all the supported features, the data field will not be
3552	 * valid.
3553	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
3554	 * a specific bit set in the featuresState, the driver will return the
3555	 * current state of this specific feature and whatever data that are
3556	 * associated with the feature in the data field or perform whatever
3557	 * action needed indicates in the data field.
3558	 */
3559	 if (f.feat.fValue == 0) {
3560		f.feat.fBits.largeLBA =
3561		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
3562		/* TODO: In the future, add other features state here as well */
3563	} else {
3564		if (f.feat.fBits.largeLBA)
3565			f.feat.fBits.largeLBA =
3566			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
3567		/* TODO: Add other features state and data in the future */
3568	}
3569
3570	error = copyout(&f, uptr, sizeof (f));
3571	return (error);
3572}
3573
3574/*
3575 * Give the userland some information about the container.  The AAC arch
3576 * expects the driver to be a SCSI passthrough type driver, so it expects
3577 * the containers to have b:t:l numbers.  Fake it.
3578 */
3579static int
3580aac_query_disk(struct aac_softc *sc, caddr_t uptr)
3581{
3582	struct aac_query_disk query_disk;
3583	struct aac_container *co;
3584	struct aac_disk	*disk;
3585	int error, id;
3586
3587	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3588
3589	disk = NULL;
3590
3591	error = copyin(uptr, (caddr_t)&query_disk,
3592		       sizeof(struct aac_query_disk));
3593	if (error)
3594		return (error);
3595
3596	id = query_disk.ContainerNumber;
3597	if (id == -1)
3598		return (EINVAL);
3599
3600	mtx_lock(&sc->aac_container_lock);
3601	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
3602		if (co->co_mntobj.ObjectId == id)
3603			break;
3604		}
3605
3606	if (co == NULL) {
3607			query_disk.Valid = 0;
3608			query_disk.Locked = 0;
3609			query_disk.Deleted = 1;		/* XXX is this right? */
3610	} else {
3611		disk = device_get_softc(co->co_disk);
3612		query_disk.Valid = 1;
3613		query_disk.Locked =
3614		    (disk->ad_flags & AAC_DISK_OPEN) ? 1 : 0;
3615		query_disk.Deleted = 0;
3616		query_disk.Bus = device_get_unit(sc->aac_dev);
3617		query_disk.Target = disk->unit;
3618		query_disk.Lun = 0;
3619		query_disk.UnMapped = 0;
3620		sprintf(&query_disk.diskDeviceName[0], "%s%d",
3621		        disk->ad_disk->d_name, disk->ad_disk->d_unit);
3622	}
3623	mtx_unlock(&sc->aac_container_lock);
3624
3625	error = copyout((caddr_t)&query_disk, uptr,
3626			sizeof(struct aac_query_disk));
3627
3628	return (error);
3629}
3630
3631static void
3632aac_get_bus_info(struct aac_softc *sc)
3633{
3634	struct aac_fib *fib;
3635	struct aac_ctcfg *c_cmd;
3636	struct aac_ctcfg_resp *c_resp;
3637	struct aac_vmioctl *vmi;
3638	struct aac_vmi_businf_resp *vmi_resp;
3639	struct aac_getbusinf businfo;
3640	struct aac_sim *caminf;
3641	device_t child;
3642	int i, found, error;
3643
3644	mtx_lock(&sc->aac_io_lock);
3645	aac_alloc_sync_fib(sc, &fib);
3646	c_cmd = (struct aac_ctcfg *)&fib->data[0];
3647	bzero(c_cmd, sizeof(struct aac_ctcfg));
3648
3649	c_cmd->Command = VM_ContainerConfig;
3650	c_cmd->cmd = CT_GET_SCSI_METHOD;
3651	c_cmd->param = 0;
3652
3653	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3654	    sizeof(struct aac_ctcfg));
3655	if (error) {
3656		device_printf(sc->aac_dev, "Error %d sending "
3657		    "VM_ContainerConfig command\n", error);
3658		aac_release_sync_fib(sc);
3659		mtx_unlock(&sc->aac_io_lock);
3660		return;
3661	}
3662
3663	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3664	if (c_resp->Status != ST_OK) {
3665		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3666		    c_resp->Status);
3667		aac_release_sync_fib(sc);
3668		mtx_unlock(&sc->aac_io_lock);
3669		return;
3670	}
3671
3672	sc->scsi_method_id = c_resp->param;
3673
3674	vmi = (struct aac_vmioctl *)&fib->data[0];
3675	bzero(vmi, sizeof(struct aac_vmioctl));
3676
3677	vmi->Command = VM_Ioctl;
3678	vmi->ObjType = FT_DRIVE;
3679	vmi->MethId = sc->scsi_method_id;
3680	vmi->ObjId = 0;
3681	vmi->IoctlCmd = GetBusInfo;
3682
3683	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3684	    sizeof(struct aac_vmi_businf_resp));
3685	if (error) {
3686		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3687		    error);
3688		aac_release_sync_fib(sc);
3689		mtx_unlock(&sc->aac_io_lock);
3690		return;
3691	}
3692
3693	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3694	if (vmi_resp->Status != ST_OK) {
3695		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3696		    vmi_resp->Status);
3697		aac_release_sync_fib(sc);
3698		mtx_unlock(&sc->aac_io_lock);
3699		return;
3700	}
3701
3702	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3703	aac_release_sync_fib(sc);
3704	mtx_unlock(&sc->aac_io_lock);
3705
3706	found = 0;
3707	for (i = 0; i < businfo.BusCount; i++) {
3708		if (businfo.BusValid[i] != AAC_BUS_VALID)
3709			continue;
3710
3711		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3712		    M_AACBUF, M_NOWAIT | M_ZERO);
3713		if (caminf == NULL) {
3714			device_printf(sc->aac_dev,
3715			    "No memory to add passthrough bus %d\n", i);
3716			break;
3717		};
3718
3719		child = device_add_child(sc->aac_dev, "aacp", -1);
3720		if (child == NULL) {
3721			device_printf(sc->aac_dev,
3722			    "device_add_child failed for passthrough bus %d\n",
3723			    i);
3724			free(caminf, M_AACBUF);
3725			break;
3726		}
3727
3728		caminf->TargetsPerBus = businfo.TargetsPerBus;
3729		caminf->BusNumber = i;
3730		caminf->InitiatorBusId = businfo.InitiatorBusId[i];
3731		caminf->aac_sc = sc;
3732		caminf->sim_dev = child;
3733
3734		device_set_ivars(child, caminf);
3735		device_set_desc(child, "SCSI Passthrough Bus");
3736		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3737
3738		found = 1;
3739	}
3740
3741	if (found)
3742		bus_generic_attach(sc->aac_dev);
3743
3744	return;
3745}
3746