xref: /freebsd/sys/dev/aacraid/aacraid.c (revision 7029da5c36f2d3cf6bb6c81bf551229f416399e8)
1dce93cd0SAchim Leubner /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3718cf2ccSPedro F. Giffuni  *
4dce93cd0SAchim Leubner  * Copyright (c) 2000 Michael Smith
5dce93cd0SAchim Leubner  * Copyright (c) 2001 Scott Long
6dce93cd0SAchim Leubner  * Copyright (c) 2000 BSDi
7dce93cd0SAchim Leubner  * Copyright (c) 2001-2010 Adaptec, Inc.
8dce93cd0SAchim Leubner  * Copyright (c) 2010-2012 PMC-Sierra, Inc.
9dce93cd0SAchim Leubner  * All rights reserved.
10dce93cd0SAchim Leubner  *
11dce93cd0SAchim Leubner  * Redistribution and use in source and binary forms, with or without
12dce93cd0SAchim Leubner  * modification, are permitted provided that the following conditions
13dce93cd0SAchim Leubner  * are met:
14dce93cd0SAchim Leubner  * 1. Redistributions of source code must retain the above copyright
15dce93cd0SAchim Leubner  *    notice, this list of conditions and the following disclaimer.
16dce93cd0SAchim Leubner  * 2. Redistributions in binary form must reproduce the above copyright
17dce93cd0SAchim Leubner  *    notice, this list of conditions and the following disclaimer in the
18dce93cd0SAchim Leubner  *    documentation and/or other materials provided with the distribution.
19dce93cd0SAchim Leubner  *
20dce93cd0SAchim Leubner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21dce93cd0SAchim Leubner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22dce93cd0SAchim Leubner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23dce93cd0SAchim Leubner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24dce93cd0SAchim Leubner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25dce93cd0SAchim Leubner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26dce93cd0SAchim Leubner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27dce93cd0SAchim Leubner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28dce93cd0SAchim Leubner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29dce93cd0SAchim Leubner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30dce93cd0SAchim Leubner  * SUCH DAMAGE.
31dce93cd0SAchim Leubner  */
32dce93cd0SAchim Leubner 
33dce93cd0SAchim Leubner #include <sys/cdefs.h>
34dce93cd0SAchim Leubner __FBSDID("$FreeBSD$");
35dce93cd0SAchim Leubner 
36dce93cd0SAchim Leubner /*
37dce93cd0SAchim Leubner  * Driver for the Adaptec by PMC Series 6,7,8,... families of RAID controllers
38dce93cd0SAchim Leubner  */
39dce93cd0SAchim Leubner #define AAC_DRIVERNAME			"aacraid"
40dce93cd0SAchim Leubner 
41dce93cd0SAchim Leubner #include "opt_aacraid.h"
42dce93cd0SAchim Leubner 
43dce93cd0SAchim Leubner /* #include <stddef.h> */
44dce93cd0SAchim Leubner #include <sys/param.h>
45dce93cd0SAchim Leubner #include <sys/systm.h>
46dce93cd0SAchim Leubner #include <sys/malloc.h>
47dce93cd0SAchim Leubner #include <sys/kernel.h>
48dce93cd0SAchim Leubner #include <sys/kthread.h>
49f287c3e4SBrooks Davis #include <sys/proc.h>
50dce93cd0SAchim Leubner #include <sys/sysctl.h>
51f287c3e4SBrooks Davis #include <sys/sysent.h>
52dce93cd0SAchim Leubner #include <sys/poll.h>
53dce93cd0SAchim Leubner #include <sys/ioccom.h>
54dce93cd0SAchim Leubner 
55dce93cd0SAchim Leubner #include <sys/bus.h>
56dce93cd0SAchim Leubner #include <sys/conf.h>
57dce93cd0SAchim Leubner #include <sys/signalvar.h>
58dce93cd0SAchim Leubner #include <sys/time.h>
59dce93cd0SAchim Leubner #include <sys/eventhandler.h>
60dce93cd0SAchim Leubner #include <sys/rman.h>
61dce93cd0SAchim Leubner 
62dce93cd0SAchim Leubner #include <machine/bus.h>
63dce93cd0SAchim Leubner #include <machine/resource.h>
64dce93cd0SAchim Leubner 
65dce93cd0SAchim Leubner #include <dev/pci/pcireg.h>
66dce93cd0SAchim Leubner #include <dev/pci/pcivar.h>
67dce93cd0SAchim Leubner 
68dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_reg.h>
69dce93cd0SAchim Leubner #include <sys/aac_ioctl.h>
70dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_debug.h>
71dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_var.h>
72dce93cd0SAchim Leubner 
73dce93cd0SAchim Leubner #ifndef FILTER_HANDLED
74dce93cd0SAchim Leubner #define FILTER_HANDLED	0x02
75dce93cd0SAchim Leubner #endif
76dce93cd0SAchim Leubner 
77dce93cd0SAchim Leubner static void	aac_add_container(struct aac_softc *sc,
78dce93cd0SAchim Leubner 				  struct aac_mntinforesp *mir, int f,
79dce93cd0SAchim Leubner 				  u_int32_t uid);
80dce93cd0SAchim Leubner static void	aac_get_bus_info(struct aac_softc *sc);
81dce93cd0SAchim Leubner static void	aac_container_bus(struct aac_softc *sc);
82dce93cd0SAchim Leubner static void	aac_daemon(void *arg);
83dce93cd0SAchim Leubner static int aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw,
84dce93cd0SAchim Leubner 							  int pages, int nseg, int nseg_new);
85dce93cd0SAchim Leubner 
86dce93cd0SAchim Leubner /* Command Processing */
87dce93cd0SAchim Leubner static void	aac_timeout(struct aac_softc *sc);
88dce93cd0SAchim Leubner static void	aac_command_thread(struct aac_softc *sc);
89dce93cd0SAchim Leubner static int	aac_sync_fib(struct aac_softc *sc, u_int32_t command,
90dce93cd0SAchim Leubner 				     u_int32_t xferstate, struct aac_fib *fib,
91dce93cd0SAchim Leubner 				     u_int16_t datasize);
92dce93cd0SAchim Leubner /* Command Buffer Management */
93dce93cd0SAchim Leubner static void	aac_map_command_helper(void *arg, bus_dma_segment_t *segs,
94dce93cd0SAchim Leubner 				       int nseg, int error);
95dce93cd0SAchim Leubner static int	aac_alloc_commands(struct aac_softc *sc);
96dce93cd0SAchim Leubner static void	aac_free_commands(struct aac_softc *sc);
97dce93cd0SAchim Leubner static void	aac_unmap_command(struct aac_command *cm);
98dce93cd0SAchim Leubner 
99dce93cd0SAchim Leubner /* Hardware Interface */
100dce93cd0SAchim Leubner static int	aac_alloc(struct aac_softc *sc);
101dce93cd0SAchim Leubner static void	aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg,
102dce93cd0SAchim Leubner 			       int error);
103dce93cd0SAchim Leubner static int	aac_check_firmware(struct aac_softc *sc);
1043fea9c0dSAchim Leubner static void	aac_define_int_mode(struct aac_softc *sc);
105dce93cd0SAchim Leubner static int	aac_init(struct aac_softc *sc);
1063fea9c0dSAchim Leubner static int	aac_find_pci_capability(struct aac_softc *sc, int cap);
107dce93cd0SAchim Leubner static int	aac_setup_intr(struct aac_softc *sc);
1083fea9c0dSAchim Leubner static int	aac_check_config(struct aac_softc *sc);
109dce93cd0SAchim Leubner 
110dce93cd0SAchim Leubner /* PMC SRC interface */
111dce93cd0SAchim Leubner static int	aac_src_get_fwstatus(struct aac_softc *sc);
112dce93cd0SAchim Leubner static void	aac_src_qnotify(struct aac_softc *sc, int qbit);
113dce93cd0SAchim Leubner static int	aac_src_get_istatus(struct aac_softc *sc);
114dce93cd0SAchim Leubner static void	aac_src_clear_istatus(struct aac_softc *sc, int mask);
115dce93cd0SAchim Leubner static void	aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command,
116dce93cd0SAchim Leubner 				    u_int32_t arg0, u_int32_t arg1,
117dce93cd0SAchim Leubner 				    u_int32_t arg2, u_int32_t arg3);
118dce93cd0SAchim Leubner static int	aac_src_get_mailbox(struct aac_softc *sc, int mb);
1193fea9c0dSAchim Leubner static void	aac_src_access_devreg(struct aac_softc *sc, int mode);
120dce93cd0SAchim Leubner static int aac_src_send_command(struct aac_softc *sc, struct aac_command *cm);
121dce93cd0SAchim Leubner static int aac_src_get_outb_queue(struct aac_softc *sc);
122dce93cd0SAchim Leubner static void aac_src_set_outb_queue(struct aac_softc *sc, int index);
123dce93cd0SAchim Leubner 
124dce93cd0SAchim Leubner struct aac_interface aacraid_src_interface = {
125dce93cd0SAchim Leubner 	aac_src_get_fwstatus,
126dce93cd0SAchim Leubner 	aac_src_qnotify,
127dce93cd0SAchim Leubner 	aac_src_get_istatus,
128dce93cd0SAchim Leubner 	aac_src_clear_istatus,
129dce93cd0SAchim Leubner 	aac_src_set_mailbox,
130dce93cd0SAchim Leubner 	aac_src_get_mailbox,
1313fea9c0dSAchim Leubner 	aac_src_access_devreg,
132dce93cd0SAchim Leubner 	aac_src_send_command,
133dce93cd0SAchim Leubner 	aac_src_get_outb_queue,
134dce93cd0SAchim Leubner 	aac_src_set_outb_queue
135dce93cd0SAchim Leubner };
136dce93cd0SAchim Leubner 
137dce93cd0SAchim Leubner /* PMC SRCv interface */
138dce93cd0SAchim Leubner static void	aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command,
139dce93cd0SAchim Leubner 				    u_int32_t arg0, u_int32_t arg1,
140dce93cd0SAchim Leubner 				    u_int32_t arg2, u_int32_t arg3);
141dce93cd0SAchim Leubner static int	aac_srcv_get_mailbox(struct aac_softc *sc, int mb);
142dce93cd0SAchim Leubner 
143dce93cd0SAchim Leubner struct aac_interface aacraid_srcv_interface = {
144dce93cd0SAchim Leubner 	aac_src_get_fwstatus,
145dce93cd0SAchim Leubner 	aac_src_qnotify,
146dce93cd0SAchim Leubner 	aac_src_get_istatus,
147dce93cd0SAchim Leubner 	aac_src_clear_istatus,
148dce93cd0SAchim Leubner 	aac_srcv_set_mailbox,
149dce93cd0SAchim Leubner 	aac_srcv_get_mailbox,
1503fea9c0dSAchim Leubner 	aac_src_access_devreg,
151dce93cd0SAchim Leubner 	aac_src_send_command,
152dce93cd0SAchim Leubner 	aac_src_get_outb_queue,
153dce93cd0SAchim Leubner 	aac_src_set_outb_queue
154dce93cd0SAchim Leubner };
155dce93cd0SAchim Leubner 
156dce93cd0SAchim Leubner /* Debugging and Diagnostics */
157dce93cd0SAchim Leubner static struct aac_code_lookup aac_cpu_variant[] = {
158dce93cd0SAchim Leubner 	{"i960JX",		CPUI960_JX},
159dce93cd0SAchim Leubner 	{"i960CX",		CPUI960_CX},
160dce93cd0SAchim Leubner 	{"i960HX",		CPUI960_HX},
161dce93cd0SAchim Leubner 	{"i960RX",		CPUI960_RX},
162dce93cd0SAchim Leubner 	{"i960 80303",		CPUI960_80303},
163dce93cd0SAchim Leubner 	{"StrongARM SA110",	CPUARM_SA110},
164dce93cd0SAchim Leubner 	{"PPC603e",		CPUPPC_603e},
165dce93cd0SAchim Leubner 	{"XScale 80321",	CPU_XSCALE_80321},
166dce93cd0SAchim Leubner 	{"MIPS 4KC",		CPU_MIPS_4KC},
167dce93cd0SAchim Leubner 	{"MIPS 5KC",		CPU_MIPS_5KC},
168dce93cd0SAchim Leubner 	{"Unknown StrongARM",	CPUARM_xxx},
169dce93cd0SAchim Leubner 	{"Unknown PowerPC",	CPUPPC_xxx},
170dce93cd0SAchim Leubner 	{NULL, 0},
171dce93cd0SAchim Leubner 	{"Unknown processor",	0}
172dce93cd0SAchim Leubner };
173dce93cd0SAchim Leubner 
174dce93cd0SAchim Leubner static struct aac_code_lookup aac_battery_platform[] = {
175dce93cd0SAchim Leubner 	{"required battery present",		PLATFORM_BAT_REQ_PRESENT},
176dce93cd0SAchim Leubner 	{"REQUIRED BATTERY NOT PRESENT",	PLATFORM_BAT_REQ_NOTPRESENT},
177dce93cd0SAchim Leubner 	{"optional battery present",		PLATFORM_BAT_OPT_PRESENT},
178dce93cd0SAchim Leubner 	{"optional battery not installed",	PLATFORM_BAT_OPT_NOTPRESENT},
179dce93cd0SAchim Leubner 	{"no battery support",			PLATFORM_BAT_NOT_SUPPORTED},
180dce93cd0SAchim Leubner 	{NULL, 0},
181dce93cd0SAchim Leubner 	{"unknown battery platform",		0}
182dce93cd0SAchim Leubner };
183dce93cd0SAchim Leubner static void	aac_describe_controller(struct aac_softc *sc);
184dce93cd0SAchim Leubner static char	*aac_describe_code(struct aac_code_lookup *table,
185dce93cd0SAchim Leubner 				   u_int32_t code);
186dce93cd0SAchim Leubner 
187dce93cd0SAchim Leubner /* Management Interface */
188dce93cd0SAchim Leubner static d_open_t		aac_open;
189dce93cd0SAchim Leubner static d_ioctl_t	aac_ioctl;
190dce93cd0SAchim Leubner static d_poll_t		aac_poll;
191dce93cd0SAchim Leubner static void		aac_cdevpriv_dtor(void *arg);
192dce93cd0SAchim Leubner static int	aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib);
193dce93cd0SAchim Leubner static int	aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg);
194dce93cd0SAchim Leubner static void	aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib);
195dce93cd0SAchim Leubner static void	aac_request_aif(struct aac_softc *sc);
196dce93cd0SAchim Leubner static int	aac_rev_check(struct aac_softc *sc, caddr_t udata);
197dce93cd0SAchim Leubner static int	aac_open_aif(struct aac_softc *sc, caddr_t arg);
198dce93cd0SAchim Leubner static int	aac_close_aif(struct aac_softc *sc, caddr_t arg);
199dce93cd0SAchim Leubner static int	aac_getnext_aif(struct aac_softc *sc, caddr_t arg);
200dce93cd0SAchim Leubner static int	aac_return_aif(struct aac_softc *sc,
201dce93cd0SAchim Leubner 			       struct aac_fib_context *ctx, caddr_t uptr);
202dce93cd0SAchim Leubner static int	aac_query_disk(struct aac_softc *sc, caddr_t uptr);
203dce93cd0SAchim Leubner static int	aac_get_pci_info(struct aac_softc *sc, caddr_t uptr);
204dce93cd0SAchim Leubner static int	aac_supported_features(struct aac_softc *sc, caddr_t uptr);
205dce93cd0SAchim Leubner static void	aac_ioctl_event(struct aac_softc *sc,
206dce93cd0SAchim Leubner 				struct aac_event *event, void *arg);
207dce93cd0SAchim Leubner static int	aac_reset_adapter(struct aac_softc *sc);
208dce93cd0SAchim Leubner static int	aac_get_container_info(struct aac_softc *sc,
209dce93cd0SAchim Leubner 				       struct aac_fib *fib, int cid,
210dce93cd0SAchim Leubner 				       struct aac_mntinforesp *mir,
211dce93cd0SAchim Leubner 				       u_int32_t *uid);
212dce93cd0SAchim Leubner static u_int32_t
213dce93cd0SAchim Leubner 	aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled);
214dce93cd0SAchim Leubner 
215dce93cd0SAchim Leubner static struct cdevsw aacraid_cdevsw = {
216dce93cd0SAchim Leubner 	.d_version =	D_VERSION,
217dfdbb320SWarner Losh 	.d_flags =	0,
218dce93cd0SAchim Leubner 	.d_open =	aac_open,
219dce93cd0SAchim Leubner 	.d_ioctl =	aac_ioctl,
220dce93cd0SAchim Leubner 	.d_poll =	aac_poll,
221dce93cd0SAchim Leubner 	.d_name =	"aacraid",
222dce93cd0SAchim Leubner };
223dce93cd0SAchim Leubner 
224dce93cd0SAchim Leubner MALLOC_DEFINE(M_AACRAIDBUF, "aacraid_buf", "Buffers for the AACRAID driver");
225dce93cd0SAchim Leubner 
226dce93cd0SAchim Leubner /* sysctl node */
227*7029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, aacraid, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
228*7029da5cSPawel Biernacki     "AACRAID driver parameters");
229dce93cd0SAchim Leubner 
230dce93cd0SAchim Leubner /*
231dce93cd0SAchim Leubner  * Device Interface
232dce93cd0SAchim Leubner  */
233dce93cd0SAchim Leubner 
234dce93cd0SAchim Leubner /*
235dce93cd0SAchim Leubner  * Initialize the controller and softc
236dce93cd0SAchim Leubner  */
237dce93cd0SAchim Leubner int
238dce93cd0SAchim Leubner aacraid_attach(struct aac_softc *sc)
239dce93cd0SAchim Leubner {
240dce93cd0SAchim Leubner 	int error, unit;
241dce93cd0SAchim Leubner 	struct aac_fib *fib;
242dce93cd0SAchim Leubner 	struct aac_mntinforesp mir;
243dce93cd0SAchim Leubner 	int count = 0, i = 0;
244dce93cd0SAchim Leubner 	u_int32_t uid;
245dce93cd0SAchim Leubner 
246dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
247dce93cd0SAchim Leubner 	sc->hint_flags = device_get_flags(sc->aac_dev);
248dce93cd0SAchim Leubner 	/*
249dce93cd0SAchim Leubner 	 * Initialize per-controller queues.
250dce93cd0SAchim Leubner 	 */
251dce93cd0SAchim Leubner 	aac_initq_free(sc);
252dce93cd0SAchim Leubner 	aac_initq_ready(sc);
253dce93cd0SAchim Leubner 	aac_initq_busy(sc);
254dce93cd0SAchim Leubner 
255dce93cd0SAchim Leubner 	/* mark controller as suspended until we get ourselves organised */
256dce93cd0SAchim Leubner 	sc->aac_state |= AAC_STATE_SUSPEND;
257dce93cd0SAchim Leubner 
258dce93cd0SAchim Leubner 	/*
259dce93cd0SAchim Leubner 	 * Check that the firmware on the card is supported.
260dce93cd0SAchim Leubner 	 */
2614f1dfabaSMaxim Sobolev 	sc->msi_enabled = sc->msi_tupelo = FALSE;
262dce93cd0SAchim Leubner 	if ((error = aac_check_firmware(sc)) != 0)
263dce93cd0SAchim Leubner 		return(error);
264dce93cd0SAchim Leubner 
265dce93cd0SAchim Leubner 	/*
266dce93cd0SAchim Leubner 	 * Initialize locks
267dce93cd0SAchim Leubner 	 */
268dce93cd0SAchim Leubner 	mtx_init(&sc->aac_io_lock, "AACRAID I/O lock", NULL, MTX_DEF);
269dce93cd0SAchim Leubner 	TAILQ_INIT(&sc->aac_container_tqh);
270dce93cd0SAchim Leubner 	TAILQ_INIT(&sc->aac_ev_cmfree);
271dce93cd0SAchim Leubner 
272dce93cd0SAchim Leubner 	/* Initialize the clock daemon callout. */
273dce93cd0SAchim Leubner 	callout_init_mtx(&sc->aac_daemontime, &sc->aac_io_lock, 0);
274232d8889SWarner Losh 
275dce93cd0SAchim Leubner 	/*
276dce93cd0SAchim Leubner 	 * Initialize the adapter.
277dce93cd0SAchim Leubner 	 */
278dce93cd0SAchim Leubner 	if ((error = aac_alloc(sc)) != 0)
279dce93cd0SAchim Leubner 		return(error);
2803fea9c0dSAchim Leubner 	aac_define_int_mode(sc);
2814f1dfabaSMaxim Sobolev 	if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) {
282dce93cd0SAchim Leubner 		if ((error = aac_init(sc)) != 0)
283dce93cd0SAchim Leubner 			return(error);
284dce93cd0SAchim Leubner 	}
285dce93cd0SAchim Leubner 
286dce93cd0SAchim Leubner 	/*
287dce93cd0SAchim Leubner 	 * Allocate and connect our interrupt.
288dce93cd0SAchim Leubner 	 */
289dce93cd0SAchim Leubner 	if ((error = aac_setup_intr(sc)) != 0)
290dce93cd0SAchim Leubner 		return(error);
291dce93cd0SAchim Leubner 
292dce93cd0SAchim Leubner 	/*
293dce93cd0SAchim Leubner 	 * Print a little information about the controller.
294dce93cd0SAchim Leubner 	 */
295dce93cd0SAchim Leubner 	aac_describe_controller(sc);
296dce93cd0SAchim Leubner 
297dce93cd0SAchim Leubner 	/*
298dce93cd0SAchim Leubner 	 * Make the control device.
299dce93cd0SAchim Leubner 	 */
300dce93cd0SAchim Leubner 	unit = device_get_unit(sc->aac_dev);
301dce93cd0SAchim Leubner 	sc->aac_dev_t = make_dev(&aacraid_cdevsw, unit, UID_ROOT, GID_OPERATOR,
302dce93cd0SAchim Leubner 				 0640, "aacraid%d", unit);
303dce93cd0SAchim Leubner 	sc->aac_dev_t->si_drv1 = sc;
304dce93cd0SAchim Leubner 
305dce93cd0SAchim Leubner 	/* Create the AIF thread */
306dce93cd0SAchim Leubner 	if (aac_kthread_create((void(*)(void *))aac_command_thread, sc,
307dce93cd0SAchim Leubner 		   &sc->aifthread, 0, 0, "aacraid%daif", unit))
308dce93cd0SAchim Leubner 		panic("Could not create AIF thread");
309dce93cd0SAchim Leubner 
310dce93cd0SAchim Leubner 	/* Register the shutdown method to only be called post-dump */
311dce93cd0SAchim Leubner 	if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aacraid_shutdown,
312dce93cd0SAchim Leubner 	    sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL)
313dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
314dce93cd0SAchim Leubner 			      "shutdown event registration failed\n");
315dce93cd0SAchim Leubner 
316dce93cd0SAchim Leubner 	/* Find containers */
317dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
318dce93cd0SAchim Leubner 	aac_alloc_sync_fib(sc, &fib);
319dce93cd0SAchim Leubner 	/* loop over possible containers */
320dce93cd0SAchim Leubner 	do {
321dce93cd0SAchim Leubner 		if ((aac_get_container_info(sc, fib, i, &mir, &uid)) != 0)
322dce93cd0SAchim Leubner 			continue;
323dce93cd0SAchim Leubner 		if (i == 0)
324dce93cd0SAchim Leubner 			count = mir.MntRespCount;
325dce93cd0SAchim Leubner 		aac_add_container(sc, &mir, 0, uid);
326dce93cd0SAchim Leubner 		i++;
327dce93cd0SAchim Leubner 	} while ((i < count) && (i < AAC_MAX_CONTAINERS));
328dce93cd0SAchim Leubner 	aac_release_sync_fib(sc);
329dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
330dce93cd0SAchim Leubner 
331dce93cd0SAchim Leubner 	/* Register with CAM for the containers */
332dce93cd0SAchim Leubner 	TAILQ_INIT(&sc->aac_sim_tqh);
333dce93cd0SAchim Leubner 	aac_container_bus(sc);
334dce93cd0SAchim Leubner 	/* Register with CAM for the non-DASD devices */
335dce93cd0SAchim Leubner 	if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0)
336dce93cd0SAchim Leubner 		aac_get_bus_info(sc);
337dce93cd0SAchim Leubner 
338dce93cd0SAchim Leubner 	/* poke the bus to actually attach the child devices */
339dce93cd0SAchim Leubner 	bus_generic_attach(sc->aac_dev);
340dce93cd0SAchim Leubner 
341dce93cd0SAchim Leubner 	/* mark the controller up */
342dce93cd0SAchim Leubner 	sc->aac_state &= ~AAC_STATE_SUSPEND;
343dce93cd0SAchim Leubner 
344dce93cd0SAchim Leubner 	/* enable interrupts now */
3453fea9c0dSAchim Leubner 	AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT);
346dce93cd0SAchim Leubner 
347dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
348dce93cd0SAchim Leubner 	callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc);
349dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
350dce93cd0SAchim Leubner 
351dce93cd0SAchim Leubner 	return(0);
352dce93cd0SAchim Leubner }
353dce93cd0SAchim Leubner 
354dce93cd0SAchim Leubner static void
355dce93cd0SAchim Leubner aac_daemon(void *arg)
356dce93cd0SAchim Leubner {
357dce93cd0SAchim Leubner 	struct aac_softc *sc;
358dce93cd0SAchim Leubner 	struct timeval tv;
359dce93cd0SAchim Leubner 	struct aac_command *cm;
360dce93cd0SAchim Leubner 	struct aac_fib *fib;
361dce93cd0SAchim Leubner 
362dce93cd0SAchim Leubner 	sc = arg;
363dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
364dce93cd0SAchim Leubner 
365dce93cd0SAchim Leubner 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
366dce93cd0SAchim Leubner 	if (callout_pending(&sc->aac_daemontime) ||
367dce93cd0SAchim Leubner 	    callout_active(&sc->aac_daemontime) == 0)
368dce93cd0SAchim Leubner 		return;
369dce93cd0SAchim Leubner 	getmicrotime(&tv);
370dce93cd0SAchim Leubner 
371dce93cd0SAchim Leubner 	if (!aacraid_alloc_command(sc, &cm)) {
372dce93cd0SAchim Leubner 		fib = cm->cm_fib;
373dce93cd0SAchim Leubner 		cm->cm_timestamp = time_uptime;
374dce93cd0SAchim Leubner 		cm->cm_datalen = 0;
375dce93cd0SAchim Leubner 		cm->cm_flags |= AAC_CMD_WAIT;
376dce93cd0SAchim Leubner 
377dce93cd0SAchim Leubner 		fib->Header.Size =
378dce93cd0SAchim Leubner 			sizeof(struct aac_fib_header) + sizeof(u_int32_t);
379dce93cd0SAchim Leubner 		fib->Header.XferState =
380dce93cd0SAchim Leubner 			AAC_FIBSTATE_HOSTOWNED   |
381dce93cd0SAchim Leubner 			AAC_FIBSTATE_INITIALISED |
382dce93cd0SAchim Leubner 			AAC_FIBSTATE_EMPTY	 |
383dce93cd0SAchim Leubner 			AAC_FIBSTATE_FROMHOST	 |
384dce93cd0SAchim Leubner 			AAC_FIBSTATE_REXPECTED   |
385dce93cd0SAchim Leubner 			AAC_FIBSTATE_NORM	 |
386dce93cd0SAchim Leubner 			AAC_FIBSTATE_ASYNC	 |
387dce93cd0SAchim Leubner 			AAC_FIBSTATE_FAST_RESPONSE;
388dce93cd0SAchim Leubner 		fib->Header.Command = SendHostTime;
389dce93cd0SAchim Leubner 		*(uint32_t *)fib->data = tv.tv_sec;
390dce93cd0SAchim Leubner 
391dce93cd0SAchim Leubner 		aacraid_map_command_sg(cm, NULL, 0, 0);
392dce93cd0SAchim Leubner 		aacraid_release_command(cm);
393dce93cd0SAchim Leubner 	}
394dce93cd0SAchim Leubner 
395dce93cd0SAchim Leubner 	callout_schedule(&sc->aac_daemontime, 30 * 60 * hz);
396dce93cd0SAchim Leubner }
397dce93cd0SAchim Leubner 
398dce93cd0SAchim Leubner void
399dce93cd0SAchim Leubner aacraid_add_event(struct aac_softc *sc, struct aac_event *event)
400dce93cd0SAchim Leubner {
401dce93cd0SAchim Leubner 
402dce93cd0SAchim Leubner 	switch (event->ev_type & AAC_EVENT_MASK) {
403dce93cd0SAchim Leubner 	case AAC_EVENT_CMFREE:
404dce93cd0SAchim Leubner 		TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links);
405dce93cd0SAchim Leubner 		break;
406dce93cd0SAchim Leubner 	default:
407dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "aac_add event: unknown event %d\n",
408dce93cd0SAchim Leubner 		    event->ev_type);
409dce93cd0SAchim Leubner 		break;
410dce93cd0SAchim Leubner 	}
411dce93cd0SAchim Leubner 
412dce93cd0SAchim Leubner 	return;
413dce93cd0SAchim Leubner }
414dce93cd0SAchim Leubner 
415dce93cd0SAchim Leubner /*
416dce93cd0SAchim Leubner  * Request information of container #cid
417dce93cd0SAchim Leubner  */
418dce93cd0SAchim Leubner static int
419dce93cd0SAchim Leubner aac_get_container_info(struct aac_softc *sc, struct aac_fib *sync_fib, int cid,
420dce93cd0SAchim Leubner 		       struct aac_mntinforesp *mir, u_int32_t *uid)
421dce93cd0SAchim Leubner {
422dce93cd0SAchim Leubner 	struct aac_command *cm;
423dce93cd0SAchim Leubner 	struct aac_fib *fib;
424dce93cd0SAchim Leubner 	struct aac_mntinfo *mi;
425dce93cd0SAchim Leubner 	struct aac_cnt_config *ccfg;
4263fea9c0dSAchim Leubner 	int rval;
427dce93cd0SAchim Leubner 
428dce93cd0SAchim Leubner 	if (sync_fib == NULL) {
429dce93cd0SAchim Leubner 		if (aacraid_alloc_command(sc, &cm)) {
430dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
431dce93cd0SAchim Leubner 				"Warning, no free command available\n");
432dce93cd0SAchim Leubner 			return (-1);
433dce93cd0SAchim Leubner 		}
434dce93cd0SAchim Leubner 		fib = cm->cm_fib;
435dce93cd0SAchim Leubner 	} else {
436dce93cd0SAchim Leubner 		fib = sync_fib;
437dce93cd0SAchim Leubner 	}
438dce93cd0SAchim Leubner 
439dce93cd0SAchim Leubner 	mi = (struct aac_mntinfo *)&fib->data[0];
440dce93cd0SAchim Leubner 	/* 4KB support?, 64-bit LBA? */
441dce93cd0SAchim Leubner 	if (sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)
442dce93cd0SAchim Leubner 		mi->Command = VM_NameServeAllBlk;
443dce93cd0SAchim Leubner 	else if (sc->flags & AAC_FLAGS_LBA_64BIT)
444dce93cd0SAchim Leubner 		mi->Command = VM_NameServe64;
445dce93cd0SAchim Leubner 	else
446dce93cd0SAchim Leubner 		mi->Command = VM_NameServe;
447dce93cd0SAchim Leubner 	mi->MntType = FT_FILESYS;
448dce93cd0SAchim Leubner 	mi->MntCount = cid;
449dce93cd0SAchim Leubner 
450dce93cd0SAchim Leubner 	if (sync_fib) {
451dce93cd0SAchim Leubner 		if (aac_sync_fib(sc, ContainerCommand, 0, fib,
452dce93cd0SAchim Leubner 			 sizeof(struct aac_mntinfo))) {
453dce93cd0SAchim Leubner 			device_printf(sc->aac_dev, "Error probing container %d\n", cid);
454dce93cd0SAchim Leubner 			return (-1);
455dce93cd0SAchim Leubner 		}
456dce93cd0SAchim Leubner 	} else {
457dce93cd0SAchim Leubner 		cm->cm_timestamp = time_uptime;
458dce93cd0SAchim Leubner 		cm->cm_datalen = 0;
459dce93cd0SAchim Leubner 
460dce93cd0SAchim Leubner 		fib->Header.Size =
461dce93cd0SAchim Leubner 			sizeof(struct aac_fib_header) + sizeof(struct aac_mntinfo);
462dce93cd0SAchim Leubner 		fib->Header.XferState =
463dce93cd0SAchim Leubner 			AAC_FIBSTATE_HOSTOWNED   |
464dce93cd0SAchim Leubner 			AAC_FIBSTATE_INITIALISED |
465dce93cd0SAchim Leubner 			AAC_FIBSTATE_EMPTY	 |
466dce93cd0SAchim Leubner 			AAC_FIBSTATE_FROMHOST	 |
467dce93cd0SAchim Leubner 			AAC_FIBSTATE_REXPECTED   |
468dce93cd0SAchim Leubner 			AAC_FIBSTATE_NORM	 |
469dce93cd0SAchim Leubner 			AAC_FIBSTATE_ASYNC	 |
470dce93cd0SAchim Leubner 			AAC_FIBSTATE_FAST_RESPONSE;
471dce93cd0SAchim Leubner 		fib->Header.Command = ContainerCommand;
472dce93cd0SAchim Leubner 		if (aacraid_wait_command(cm) != 0) {
473dce93cd0SAchim Leubner 			device_printf(sc->aac_dev, "Error probing container %d\n", cid);
474dce93cd0SAchim Leubner 			aacraid_release_command(cm);
475dce93cd0SAchim Leubner 			return (-1);
476dce93cd0SAchim Leubner 		}
477dce93cd0SAchim Leubner 	}
478dce93cd0SAchim Leubner 	bcopy(&fib->data[0], mir, sizeof(struct aac_mntinforesp));
479dce93cd0SAchim Leubner 
480dce93cd0SAchim Leubner 	/* UID */
481dce93cd0SAchim Leubner 	*uid = cid;
482dce93cd0SAchim Leubner 	if (mir->MntTable[0].VolType != CT_NONE &&
483dce93cd0SAchim Leubner 		!(mir->MntTable[0].ContentState & AAC_FSCS_HIDDEN)) {
4843fea9c0dSAchim Leubner 		if (!(sc->aac_support_opt2 & AAC_SUPPORTED_VARIABLE_BLOCK_SIZE)) {
4853fea9c0dSAchim Leubner 			mir->MntTable[0].ObjExtension.BlockDevice.BlockSize = 0x200;
4863fea9c0dSAchim Leubner 			mir->MntTable[0].ObjExtension.BlockDevice.bdLgclPhysMap = 0;
4873fea9c0dSAchim Leubner 		}
488dce93cd0SAchim Leubner 		ccfg = (struct aac_cnt_config *)&fib->data[0];
489dce93cd0SAchim Leubner 		bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE);
490dce93cd0SAchim Leubner 		ccfg->Command = VM_ContainerConfig;
491dce93cd0SAchim Leubner 		ccfg->CTCommand.command = CT_CID_TO_32BITS_UID;
492dce93cd0SAchim Leubner 		ccfg->CTCommand.param[0] = cid;
493dce93cd0SAchim Leubner 
494dce93cd0SAchim Leubner 		if (sync_fib) {
4953fea9c0dSAchim Leubner 			rval = aac_sync_fib(sc, ContainerCommand, 0, fib,
4963fea9c0dSAchim Leubner 				sizeof(struct aac_cnt_config));
4973fea9c0dSAchim Leubner 			if (rval == 0 && ccfg->Command == ST_OK &&
4983fea9c0dSAchim Leubner 				ccfg->CTCommand.param[0] == CT_OK &&
499dce93cd0SAchim Leubner 				mir->MntTable[0].VolType != CT_PASSTHRU)
500dce93cd0SAchim Leubner 				*uid = ccfg->CTCommand.param[1];
501dce93cd0SAchim Leubner 		} else {
502dce93cd0SAchim Leubner 			fib->Header.Size =
503dce93cd0SAchim Leubner 				sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config);
504dce93cd0SAchim Leubner 			fib->Header.XferState =
505dce93cd0SAchim Leubner 				AAC_FIBSTATE_HOSTOWNED   |
506dce93cd0SAchim Leubner 				AAC_FIBSTATE_INITIALISED |
507dce93cd0SAchim Leubner 				AAC_FIBSTATE_EMPTY	 |
508dce93cd0SAchim Leubner 				AAC_FIBSTATE_FROMHOST	 |
509dce93cd0SAchim Leubner 				AAC_FIBSTATE_REXPECTED   |
510dce93cd0SAchim Leubner 				AAC_FIBSTATE_NORM	 |
511dce93cd0SAchim Leubner 				AAC_FIBSTATE_ASYNC	 |
512dce93cd0SAchim Leubner 				AAC_FIBSTATE_FAST_RESPONSE;
513dce93cd0SAchim Leubner 			fib->Header.Command = ContainerCommand;
5143fea9c0dSAchim Leubner 			rval = aacraid_wait_command(cm);
5153fea9c0dSAchim Leubner 			if (rval == 0 && ccfg->Command == ST_OK &&
5163fea9c0dSAchim Leubner 				ccfg->CTCommand.param[0] == CT_OK &&
517dce93cd0SAchim Leubner 				mir->MntTable[0].VolType != CT_PASSTHRU)
518dce93cd0SAchim Leubner 				*uid = ccfg->CTCommand.param[1];
519dce93cd0SAchim Leubner 			aacraid_release_command(cm);
520dce93cd0SAchim Leubner 		}
521dce93cd0SAchim Leubner 	}
522dce93cd0SAchim Leubner 
523dce93cd0SAchim Leubner 	return (0);
524dce93cd0SAchim Leubner }
525dce93cd0SAchim Leubner 
526dce93cd0SAchim Leubner /*
527dce93cd0SAchim Leubner  * Create a device to represent a new container
528dce93cd0SAchim Leubner  */
529dce93cd0SAchim Leubner static void
530dce93cd0SAchim Leubner aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f,
531dce93cd0SAchim Leubner 		  u_int32_t uid)
532dce93cd0SAchim Leubner {
533dce93cd0SAchim Leubner 	struct aac_container *co;
534dce93cd0SAchim Leubner 
535dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
536dce93cd0SAchim Leubner 
537dce93cd0SAchim Leubner 	/*
538dce93cd0SAchim Leubner 	 * Check container volume type for validity.  Note that many of
539dce93cd0SAchim Leubner 	 * the possible types may never show up.
540dce93cd0SAchim Leubner 	 */
541dce93cd0SAchim Leubner 	if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) {
542dce93cd0SAchim Leubner 		co = (struct aac_container *)malloc(sizeof *co, M_AACRAIDBUF,
543dce93cd0SAchim Leubner 		       M_NOWAIT | M_ZERO);
544dce93cd0SAchim Leubner 		if (co == NULL) {
545dce93cd0SAchim Leubner 			panic("Out of memory?!");
546dce93cd0SAchim Leubner 		}
547dce93cd0SAchim Leubner 
548dce93cd0SAchim Leubner 		co->co_found = f;
549dce93cd0SAchim Leubner 		bcopy(&mir->MntTable[0], &co->co_mntobj,
550dce93cd0SAchim Leubner 		      sizeof(struct aac_mntobj));
551dce93cd0SAchim Leubner 		co->co_uid = uid;
552dce93cd0SAchim Leubner 		TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link);
553dce93cd0SAchim Leubner 	}
554dce93cd0SAchim Leubner }
555dce93cd0SAchim Leubner 
556dce93cd0SAchim Leubner /*
557dce93cd0SAchim Leubner  * Allocate resources associated with (sc)
558dce93cd0SAchim Leubner  */
559dce93cd0SAchim Leubner static int
560dce93cd0SAchim Leubner aac_alloc(struct aac_softc *sc)
561dce93cd0SAchim Leubner {
562dce93cd0SAchim Leubner 	bus_size_t maxsize;
563dce93cd0SAchim Leubner 
564dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
565dce93cd0SAchim Leubner 
566dce93cd0SAchim Leubner 	/*
567dce93cd0SAchim Leubner 	 * Create DMA tag for mapping buffers into controller-addressable space.
568dce93cd0SAchim Leubner 	 */
569dce93cd0SAchim Leubner 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
570dce93cd0SAchim Leubner 			       1, 0, 			/* algnmnt, boundary */
571dce93cd0SAchim Leubner 			       (sc->flags & AAC_FLAGS_SG_64BIT) ?
572dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR :
573dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
574dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR, 	/* highaddr */
575dce93cd0SAchim Leubner 			       NULL, NULL, 		/* filter, filterarg */
5766f954fb3SAlexander Motin 			       sc->aac_max_sectors << 9, /* maxsize */
577dce93cd0SAchim Leubner 			       sc->aac_sg_tablesize,	/* nsegments */
5786f954fb3SAlexander Motin 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
579dce93cd0SAchim Leubner 			       BUS_DMA_ALLOCNOW,	/* flags */
580dce93cd0SAchim Leubner 			       busdma_lock_mutex,	/* lockfunc */
581dce93cd0SAchim Leubner 			       &sc->aac_io_lock,	/* lockfuncarg */
582dce93cd0SAchim Leubner 			       &sc->aac_buffer_dmat)) {
583dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
584dce93cd0SAchim Leubner 		return (ENOMEM);
585dce93cd0SAchim Leubner 	}
586dce93cd0SAchim Leubner 
587dce93cd0SAchim Leubner 	/*
588dce93cd0SAchim Leubner 	 * Create DMA tag for mapping FIBs into controller-addressable space..
589dce93cd0SAchim Leubner 	 */
590dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1)
591dce93cd0SAchim Leubner 		maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size +
592dce93cd0SAchim Leubner 			sizeof(struct aac_fib_xporthdr) + 31);
593dce93cd0SAchim Leubner 	else
594dce93cd0SAchim Leubner 		maxsize = sc->aac_max_fibs_alloc * (sc->aac_max_fib_size + 31);
595dce93cd0SAchim Leubner 	if (bus_dma_tag_create(sc->aac_parent_dmat,	/* parent */
596dce93cd0SAchim Leubner 			       1, 0, 			/* algnmnt, boundary */
597dce93cd0SAchim Leubner 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
598dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR_32BIT :
599dce93cd0SAchim Leubner 			       0x7fffffff,		/* lowaddr */
600dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR, 	/* highaddr */
601dce93cd0SAchim Leubner 			       NULL, NULL, 		/* filter, filterarg */
602dce93cd0SAchim Leubner 			       maxsize,  		/* maxsize */
603dce93cd0SAchim Leubner 			       1,			/* nsegments */
604dce93cd0SAchim Leubner 			       maxsize,			/* maxsize */
605dce93cd0SAchim Leubner 			       0,			/* flags */
606dce93cd0SAchim Leubner 			       NULL, NULL,		/* No locking needed */
607dce93cd0SAchim Leubner 			       &sc->aac_fib_dmat)) {
608dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");
609dce93cd0SAchim Leubner 		return (ENOMEM);
610dce93cd0SAchim Leubner 	}
611dce93cd0SAchim Leubner 
612dce93cd0SAchim Leubner 	/*
613dce93cd0SAchim Leubner 	 * Create DMA tag for the common structure and allocate it.
614dce93cd0SAchim Leubner 	 */
615dce93cd0SAchim Leubner 	maxsize = sizeof(struct aac_common);
616dce93cd0SAchim Leubner 	maxsize += sc->aac_max_fibs * sizeof(u_int32_t);
617dce93cd0SAchim Leubner 	if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
618dce93cd0SAchim Leubner 			       1, 0,			/* algnmnt, boundary */
619dce93cd0SAchim Leubner 			       (sc->flags & AAC_FLAGS_4GB_WINDOW) ?
620dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR_32BIT :
621dce93cd0SAchim Leubner 			       0x7fffffff,		/* lowaddr */
622dce93cd0SAchim Leubner 			       BUS_SPACE_MAXADDR, 	/* highaddr */
623dce93cd0SAchim Leubner 			       NULL, NULL, 		/* filter, filterarg */
624dce93cd0SAchim Leubner 			       maxsize, 		/* maxsize */
625dce93cd0SAchim Leubner 			       1,			/* nsegments */
626dce93cd0SAchim Leubner 			       maxsize,			/* maxsegsize */
627dce93cd0SAchim Leubner 			       0,			/* flags */
628dce93cd0SAchim Leubner 			       NULL, NULL,		/* No locking needed */
629dce93cd0SAchim Leubner 			       &sc->aac_common_dmat)) {
630dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
631dce93cd0SAchim Leubner 			      "can't allocate common structure DMA tag\n");
632dce93cd0SAchim Leubner 		return (ENOMEM);
633dce93cd0SAchim Leubner 	}
634dce93cd0SAchim Leubner 	if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common,
635dce93cd0SAchim Leubner 			     BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) {
636dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "can't allocate common structure\n");
637dce93cd0SAchim Leubner 		return (ENOMEM);
638dce93cd0SAchim Leubner 	}
639dce93cd0SAchim Leubner 
640dce93cd0SAchim Leubner 	(void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap,
641dce93cd0SAchim Leubner 			sc->aac_common, maxsize,
642dce93cd0SAchim Leubner 			aac_common_map, sc, 0);
643dce93cd0SAchim Leubner 	bzero(sc->aac_common, maxsize);
644dce93cd0SAchim Leubner 
645dce93cd0SAchim Leubner 	/* Allocate some FIBs and associated command structs */
646dce93cd0SAchim Leubner 	TAILQ_INIT(&sc->aac_fibmap_tqh);
647dce93cd0SAchim Leubner 	sc->aac_commands = malloc(sc->aac_max_fibs * sizeof(struct aac_command),
648dce93cd0SAchim Leubner 				  M_AACRAIDBUF, M_WAITOK|M_ZERO);
64961722264SAndriy Gapon 	mtx_lock(&sc->aac_io_lock);
650dce93cd0SAchim Leubner 	while (sc->total_fibs < sc->aac_max_fibs) {
651dce93cd0SAchim Leubner 		if (aac_alloc_commands(sc) != 0)
652dce93cd0SAchim Leubner 			break;
653dce93cd0SAchim Leubner 	}
65461722264SAndriy Gapon 	mtx_unlock(&sc->aac_io_lock);
655dce93cd0SAchim Leubner 	if (sc->total_fibs == 0)
656dce93cd0SAchim Leubner 		return (ENOMEM);
657dce93cd0SAchim Leubner 
658dce93cd0SAchim Leubner 	return (0);
659dce93cd0SAchim Leubner }
660dce93cd0SAchim Leubner 
661dce93cd0SAchim Leubner /*
662dce93cd0SAchim Leubner  * Free all of the resources associated with (sc)
663dce93cd0SAchim Leubner  *
664dce93cd0SAchim Leubner  * Should not be called if the controller is active.
665dce93cd0SAchim Leubner  */
666dce93cd0SAchim Leubner void
667dce93cd0SAchim Leubner aacraid_free(struct aac_softc *sc)
668dce93cd0SAchim Leubner {
6693fea9c0dSAchim Leubner 	int i;
6703fea9c0dSAchim Leubner 
671dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
672dce93cd0SAchim Leubner 
673dce93cd0SAchim Leubner 	/* remove the control device */
674dce93cd0SAchim Leubner 	if (sc->aac_dev_t != NULL)
675dce93cd0SAchim Leubner 		destroy_dev(sc->aac_dev_t);
676dce93cd0SAchim Leubner 
677dce93cd0SAchim Leubner 	/* throw away any FIB buffers, discard the FIB DMA tag */
678dce93cd0SAchim Leubner 	aac_free_commands(sc);
679dce93cd0SAchim Leubner 	if (sc->aac_fib_dmat)
680dce93cd0SAchim Leubner 		bus_dma_tag_destroy(sc->aac_fib_dmat);
681dce93cd0SAchim Leubner 
682dce93cd0SAchim Leubner 	free(sc->aac_commands, M_AACRAIDBUF);
683dce93cd0SAchim Leubner 
684dce93cd0SAchim Leubner 	/* destroy the common area */
685dce93cd0SAchim Leubner 	if (sc->aac_common) {
686dce93cd0SAchim Leubner 		bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap);
687dce93cd0SAchim Leubner 		bus_dmamem_free(sc->aac_common_dmat, sc->aac_common,
688dce93cd0SAchim Leubner 				sc->aac_common_dmamap);
689dce93cd0SAchim Leubner 	}
690dce93cd0SAchim Leubner 	if (sc->aac_common_dmat)
691dce93cd0SAchim Leubner 		bus_dma_tag_destroy(sc->aac_common_dmat);
692dce93cd0SAchim Leubner 
693dce93cd0SAchim Leubner 	/* disconnect the interrupt handler */
6943fea9c0dSAchim Leubner 	for (i = 0; i < AAC_MAX_MSIX; ++i) {
6953fea9c0dSAchim Leubner 		if (sc->aac_intr[i])
6963fea9c0dSAchim Leubner 			bus_teardown_intr(sc->aac_dev,
6973fea9c0dSAchim Leubner 				sc->aac_irq[i], sc->aac_intr[i]);
6983fea9c0dSAchim Leubner 		if (sc->aac_irq[i])
6993fea9c0dSAchim Leubner 			bus_release_resource(sc->aac_dev, SYS_RES_IRQ,
7003fea9c0dSAchim Leubner 				sc->aac_irq_rid[i], sc->aac_irq[i]);
7013fea9c0dSAchim Leubner 		else
7023fea9c0dSAchim Leubner 			break;
7033fea9c0dSAchim Leubner 	}
7044f1dfabaSMaxim Sobolev 	if (sc->msi_enabled || sc->msi_tupelo)
7053fea9c0dSAchim Leubner 		pci_release_msi(sc->aac_dev);
706dce93cd0SAchim Leubner 
707dce93cd0SAchim Leubner 	/* destroy data-transfer DMA tag */
708dce93cd0SAchim Leubner 	if (sc->aac_buffer_dmat)
709dce93cd0SAchim Leubner 		bus_dma_tag_destroy(sc->aac_buffer_dmat);
710dce93cd0SAchim Leubner 
711dce93cd0SAchim Leubner 	/* destroy the parent DMA tag */
712dce93cd0SAchim Leubner 	if (sc->aac_parent_dmat)
713dce93cd0SAchim Leubner 		bus_dma_tag_destroy(sc->aac_parent_dmat);
714dce93cd0SAchim Leubner 
715dce93cd0SAchim Leubner 	/* release the register window mapping */
716dce93cd0SAchim Leubner 	if (sc->aac_regs_res0 != NULL)
717dce93cd0SAchim Leubner 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
718dce93cd0SAchim Leubner 				     sc->aac_regs_rid0, sc->aac_regs_res0);
719dce93cd0SAchim Leubner 	if (sc->aac_regs_res1 != NULL)
720dce93cd0SAchim Leubner 		bus_release_resource(sc->aac_dev, SYS_RES_MEMORY,
721dce93cd0SAchim Leubner 				     sc->aac_regs_rid1, sc->aac_regs_res1);
722dce93cd0SAchim Leubner }
723dce93cd0SAchim Leubner 
724dce93cd0SAchim Leubner /*
725dce93cd0SAchim Leubner  * Disconnect from the controller completely, in preparation for unload.
726dce93cd0SAchim Leubner  */
727dce93cd0SAchim Leubner int
728dce93cd0SAchim Leubner aacraid_detach(device_t dev)
729dce93cd0SAchim Leubner {
730dce93cd0SAchim Leubner 	struct aac_softc *sc;
731dce93cd0SAchim Leubner 	struct aac_container *co;
732dce93cd0SAchim Leubner 	struct aac_sim	*sim;
733dce93cd0SAchim Leubner 	int error;
734dce93cd0SAchim Leubner 
735dce93cd0SAchim Leubner 	sc = device_get_softc(dev);
736dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
737dce93cd0SAchim Leubner 
738dce93cd0SAchim Leubner 	callout_drain(&sc->aac_daemontime);
739dce93cd0SAchim Leubner 	/* Remove the child containers */
740dce93cd0SAchim Leubner 	while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) {
741dce93cd0SAchim Leubner 		TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link);
742dce93cd0SAchim Leubner 		free(co, M_AACRAIDBUF);
743dce93cd0SAchim Leubner 	}
744dce93cd0SAchim Leubner 
745dce93cd0SAchim Leubner 	/* Remove the CAM SIMs */
746dce93cd0SAchim Leubner 	while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) {
747dce93cd0SAchim Leubner 		TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link);
748dce93cd0SAchim Leubner 		error = device_delete_child(dev, sim->sim_dev);
749dce93cd0SAchim Leubner 		if (error)
750dce93cd0SAchim Leubner 			return (error);
751dce93cd0SAchim Leubner 		free(sim, M_AACRAIDBUF);
752dce93cd0SAchim Leubner 	}
753dce93cd0SAchim Leubner 
754dce93cd0SAchim Leubner 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
755dce93cd0SAchim Leubner 		sc->aifflags |= AAC_AIFFLAGS_EXIT;
756dce93cd0SAchim Leubner 		wakeup(sc->aifthread);
757dce93cd0SAchim Leubner 		tsleep(sc->aac_dev, PUSER | PCATCH, "aac_dch", 30 * hz);
758dce93cd0SAchim Leubner 	}
759dce93cd0SAchim Leubner 
760dce93cd0SAchim Leubner 	if (sc->aifflags & AAC_AIFFLAGS_RUNNING)
761dce93cd0SAchim Leubner 		panic("Cannot shutdown AIF thread");
762dce93cd0SAchim Leubner 
763dce93cd0SAchim Leubner 	if ((error = aacraid_shutdown(dev)))
764dce93cd0SAchim Leubner 		return(error);
765dce93cd0SAchim Leubner 
766dce93cd0SAchim Leubner 	EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh);
767dce93cd0SAchim Leubner 
768dce93cd0SAchim Leubner 	aacraid_free(sc);
769dce93cd0SAchim Leubner 
770dce93cd0SAchim Leubner 	mtx_destroy(&sc->aac_io_lock);
771dce93cd0SAchim Leubner 
772dce93cd0SAchim Leubner 	return(0);
773dce93cd0SAchim Leubner }
774dce93cd0SAchim Leubner 
775dce93cd0SAchim Leubner /*
776dce93cd0SAchim Leubner  * Bring the controller down to a dormant state and detach all child devices.
777dce93cd0SAchim Leubner  *
778dce93cd0SAchim Leubner  * This function is called before detach or system shutdown.
779dce93cd0SAchim Leubner  *
780dce93cd0SAchim Leubner  * Note that we can assume that the bioq on the controller is empty, as we won't
781dce93cd0SAchim Leubner  * allow shutdown if any device is open.
782dce93cd0SAchim Leubner  */
783dce93cd0SAchim Leubner int
784dce93cd0SAchim Leubner aacraid_shutdown(device_t dev)
785dce93cd0SAchim Leubner {
786dce93cd0SAchim Leubner 	struct aac_softc *sc;
787dce93cd0SAchim Leubner 	struct aac_fib *fib;
788dce93cd0SAchim Leubner 	struct aac_close_command *cc;
789dce93cd0SAchim Leubner 
790dce93cd0SAchim Leubner 	sc = device_get_softc(dev);
791dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
792dce93cd0SAchim Leubner 
793dce93cd0SAchim Leubner 	sc->aac_state |= AAC_STATE_SUSPEND;
794dce93cd0SAchim Leubner 
795dce93cd0SAchim Leubner 	/*
796dce93cd0SAchim Leubner 	 * Send a Container shutdown followed by a HostShutdown FIB to the
797dce93cd0SAchim Leubner 	 * controller to convince it that we don't want to talk to it anymore.
798dce93cd0SAchim Leubner 	 * We've been closed and all I/O completed already
799dce93cd0SAchim Leubner 	 */
800dce93cd0SAchim Leubner 	device_printf(sc->aac_dev, "shutting down controller...");
801dce93cd0SAchim Leubner 
802dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
803dce93cd0SAchim Leubner 	aac_alloc_sync_fib(sc, &fib);
804dce93cd0SAchim Leubner 	cc = (struct aac_close_command *)&fib->data[0];
805dce93cd0SAchim Leubner 
806dce93cd0SAchim Leubner 	bzero(cc, sizeof(struct aac_close_command));
807dce93cd0SAchim Leubner 	cc->Command = VM_CloseAll;
8083fea9c0dSAchim Leubner 	cc->ContainerId = 0xfffffffe;
809dce93cd0SAchim Leubner 	if (aac_sync_fib(sc, ContainerCommand, 0, fib,
810dce93cd0SAchim Leubner 	    sizeof(struct aac_close_command)))
811dce93cd0SAchim Leubner 		printf("FAILED.\n");
812dce93cd0SAchim Leubner 	else
813dce93cd0SAchim Leubner 		printf("done\n");
814dce93cd0SAchim Leubner 
8153fea9c0dSAchim Leubner 	AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT);
816dce93cd0SAchim Leubner 	aac_release_sync_fib(sc);
817dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
818dce93cd0SAchim Leubner 
819dce93cd0SAchim Leubner 	return(0);
820dce93cd0SAchim Leubner }
821dce93cd0SAchim Leubner 
822dce93cd0SAchim Leubner /*
823dce93cd0SAchim Leubner  * Bring the controller to a quiescent state, ready for system suspend.
824dce93cd0SAchim Leubner  */
825dce93cd0SAchim Leubner int
826dce93cd0SAchim Leubner aacraid_suspend(device_t dev)
827dce93cd0SAchim Leubner {
828dce93cd0SAchim Leubner 	struct aac_softc *sc;
829dce93cd0SAchim Leubner 
830dce93cd0SAchim Leubner 	sc = device_get_softc(dev);
831dce93cd0SAchim Leubner 
832dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
833dce93cd0SAchim Leubner 	sc->aac_state |= AAC_STATE_SUSPEND;
834dce93cd0SAchim Leubner 
8353fea9c0dSAchim Leubner 	AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT);
836dce93cd0SAchim Leubner 	return(0);
837dce93cd0SAchim Leubner }
838dce93cd0SAchim Leubner 
839dce93cd0SAchim Leubner /*
840dce93cd0SAchim Leubner  * Bring the controller back to a state ready for operation.
841dce93cd0SAchim Leubner  */
842dce93cd0SAchim Leubner int
843dce93cd0SAchim Leubner aacraid_resume(device_t dev)
844dce93cd0SAchim Leubner {
845dce93cd0SAchim Leubner 	struct aac_softc *sc;
846dce93cd0SAchim Leubner 
847dce93cd0SAchim Leubner 	sc = device_get_softc(dev);
848dce93cd0SAchim Leubner 
849dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
850dce93cd0SAchim Leubner 	sc->aac_state &= ~AAC_STATE_SUSPEND;
8513fea9c0dSAchim Leubner 	AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT);
852dce93cd0SAchim Leubner 	return(0);
853dce93cd0SAchim Leubner }
854dce93cd0SAchim Leubner 
855dce93cd0SAchim Leubner /*
856dce93cd0SAchim Leubner  * Interrupt handler for NEW_COMM_TYPE1, NEW_COMM_TYPE2, NEW_COMM_TYPE34 interface.
857dce93cd0SAchim Leubner  */
858dce93cd0SAchim Leubner void
859dce93cd0SAchim Leubner aacraid_new_intr_type1(void *arg)
860dce93cd0SAchim Leubner {
8613fea9c0dSAchim Leubner 	struct aac_msix_ctx *ctx;
862dce93cd0SAchim Leubner 	struct aac_softc *sc;
8633fea9c0dSAchim Leubner 	int vector_no;
864dce93cd0SAchim Leubner 	struct aac_command *cm;
865dce93cd0SAchim Leubner 	struct aac_fib *fib;
866dce93cd0SAchim Leubner 	u_int32_t bellbits, bellbits_shifted, index, handle;
8673fea9c0dSAchim Leubner 	int isFastResponse, isAif, noMoreAif, mode;
868dce93cd0SAchim Leubner 
8693fea9c0dSAchim Leubner 	ctx = (struct aac_msix_ctx *)arg;
8703fea9c0dSAchim Leubner 	sc = ctx->sc;
8713fea9c0dSAchim Leubner 	vector_no = ctx->vector_no;
872dce93cd0SAchim Leubner 
873dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
874dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
8753fea9c0dSAchim Leubner 
8763fea9c0dSAchim Leubner 	if (sc->msi_enabled) {
8773fea9c0dSAchim Leubner 		mode = AAC_INT_MODE_MSI;
8783fea9c0dSAchim Leubner 		if (vector_no == 0) {
8793fea9c0dSAchim Leubner 			bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_MSI);
8803fea9c0dSAchim Leubner 			if (bellbits & 0x40000)
8813fea9c0dSAchim Leubner 				mode |= AAC_INT_MODE_AIF;
8823fea9c0dSAchim Leubner 			else if (bellbits & 0x1000)
8833fea9c0dSAchim Leubner 				mode |= AAC_INT_MODE_SYNC;
8843fea9c0dSAchim Leubner 		}
8853fea9c0dSAchim Leubner 	} else {
8863fea9c0dSAchim Leubner 		mode = AAC_INT_MODE_INTX;
887dce93cd0SAchim Leubner 		bellbits = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R);
888dce93cd0SAchim Leubner 		if (bellbits & AAC_DB_RESPONSE_SENT_NS) {
889dce93cd0SAchim Leubner 			bellbits = AAC_DB_RESPONSE_SENT_NS;
890dce93cd0SAchim Leubner 			AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits);
8913fea9c0dSAchim Leubner 		} else {
8923fea9c0dSAchim Leubner 			bellbits_shifted = (bellbits >> AAC_SRC_ODR_SHIFT);
8933fea9c0dSAchim Leubner 			AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, bellbits);
8943fea9c0dSAchim Leubner 			if (bellbits_shifted & AAC_DB_AIF_PENDING)
8953fea9c0dSAchim Leubner 				mode |= AAC_INT_MODE_AIF;
8963fea9c0dSAchim Leubner 			else if (bellbits_shifted & AAC_DB_SYNC_COMMAND)
8973fea9c0dSAchim Leubner 				mode |= AAC_INT_MODE_SYNC;
8983fea9c0dSAchim Leubner 		}
8993fea9c0dSAchim Leubner 		/* ODR readback, Prep #238630 */
9003fea9c0dSAchim Leubner 		AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R);
9013fea9c0dSAchim Leubner 	}
9023fea9c0dSAchim Leubner 
9033fea9c0dSAchim Leubner 	if (mode & AAC_INT_MODE_SYNC) {
9043fea9c0dSAchim Leubner 		if (sc->aac_sync_cm) {
9053fea9c0dSAchim Leubner 			cm = sc->aac_sync_cm;
9063fea9c0dSAchim Leubner 			cm->cm_flags |= AAC_CMD_COMPLETED;
9073fea9c0dSAchim Leubner 			/* is there a completion handler? */
9083fea9c0dSAchim Leubner 			if (cm->cm_complete != NULL) {
9093fea9c0dSAchim Leubner 				cm->cm_complete(cm);
9103fea9c0dSAchim Leubner 			} else {
9113fea9c0dSAchim Leubner 				/* assume that someone is sleeping on this command */
9123fea9c0dSAchim Leubner 				wakeup(cm);
9133fea9c0dSAchim Leubner 			}
9143fea9c0dSAchim Leubner 			sc->flags &= ~AAC_QUEUE_FRZN;
9153fea9c0dSAchim Leubner 			sc->aac_sync_cm = NULL;
9163fea9c0dSAchim Leubner 		}
9173fea9c0dSAchim Leubner 		mode = 0;
9183fea9c0dSAchim Leubner 	}
9193fea9c0dSAchim Leubner 
9203fea9c0dSAchim Leubner 	if (mode & AAC_INT_MODE_AIF) {
9213fea9c0dSAchim Leubner 		if (mode & AAC_INT_MODE_INTX) {
9223fea9c0dSAchim Leubner 			aac_request_aif(sc);
9233fea9c0dSAchim Leubner 			mode = 0;
9243fea9c0dSAchim Leubner 		}
9253fea9c0dSAchim Leubner 	}
9263fea9c0dSAchim Leubner 
9273fea9c0dSAchim Leubner 	if (mode) {
928dce93cd0SAchim Leubner 		/* handle async. status */
9293fea9c0dSAchim Leubner 		index = sc->aac_host_rrq_idx[vector_no];
930dce93cd0SAchim Leubner 		for (;;) {
931dce93cd0SAchim Leubner 			isFastResponse = isAif = noMoreAif = 0;
932dce93cd0SAchim Leubner 			/* remove toggle bit (31) */
933dce93cd0SAchim Leubner 			handle = (sc->aac_common->ac_host_rrq[index] & 0x7fffffff);
934dce93cd0SAchim Leubner 			/* check fast response bit (30) */
935dce93cd0SAchim Leubner 			if (handle & 0x40000000)
936dce93cd0SAchim Leubner 				isFastResponse = 1;
937dce93cd0SAchim Leubner 			/* check AIF bit (23) */
938dce93cd0SAchim Leubner 			else if (handle & 0x00800000)
939dce93cd0SAchim Leubner 				isAif = TRUE;
940dce93cd0SAchim Leubner 			handle &= 0x0000ffff;
941dce93cd0SAchim Leubner 			if (handle == 0)
942dce93cd0SAchim Leubner 				break;
943dce93cd0SAchim Leubner 
944dce93cd0SAchim Leubner 			cm = sc->aac_commands + (handle - 1);
945dce93cd0SAchim Leubner 			fib = cm->cm_fib;
9463fea9c0dSAchim Leubner 			sc->aac_rrq_outstanding[vector_no]--;
947dce93cd0SAchim Leubner 			if (isAif) {
948dce93cd0SAchim Leubner 				noMoreAif = (fib->Header.XferState & AAC_FIBSTATE_NOMOREAIF) ? 1:0;
949dce93cd0SAchim Leubner 				if (!noMoreAif)
950dce93cd0SAchim Leubner 					aac_handle_aif(sc, fib);
951dce93cd0SAchim Leubner 				aac_remove_busy(cm);
952dce93cd0SAchim Leubner 				aacraid_release_command(cm);
953dce93cd0SAchim Leubner 			} else {
954dce93cd0SAchim Leubner 				if (isFastResponse) {
955dce93cd0SAchim Leubner 					fib->Header.XferState |= AAC_FIBSTATE_DONEADAP;
956dce93cd0SAchim Leubner 					*((u_int32_t *)(fib->data)) = ST_OK;
957dce93cd0SAchim Leubner 					cm->cm_flags |= AAC_CMD_FASTRESP;
958dce93cd0SAchim Leubner 				}
959dce93cd0SAchim Leubner 				aac_remove_busy(cm);
960dce93cd0SAchim Leubner 				aac_unmap_command(cm);
961dce93cd0SAchim Leubner 				cm->cm_flags |= AAC_CMD_COMPLETED;
962dce93cd0SAchim Leubner 
963dce93cd0SAchim Leubner 				/* is there a completion handler? */
964dce93cd0SAchim Leubner 				if (cm->cm_complete != NULL) {
965dce93cd0SAchim Leubner 					cm->cm_complete(cm);
966dce93cd0SAchim Leubner 				} else {
967dce93cd0SAchim Leubner 					/* assume that someone is sleeping on this command */
968dce93cd0SAchim Leubner 					wakeup(cm);
969dce93cd0SAchim Leubner 				}
970dce93cd0SAchim Leubner 				sc->flags &= ~AAC_QUEUE_FRZN;
971dce93cd0SAchim Leubner 			}
972dce93cd0SAchim Leubner 
973dce93cd0SAchim Leubner 			sc->aac_common->ac_host_rrq[index++] = 0;
9743fea9c0dSAchim Leubner 			if (index == (vector_no + 1) * sc->aac_vector_cap)
9753fea9c0dSAchim Leubner 				index = vector_no * sc->aac_vector_cap;
9763fea9c0dSAchim Leubner 			sc->aac_host_rrq_idx[vector_no] = index;
977dce93cd0SAchim Leubner 
978dce93cd0SAchim Leubner 			if ((isAif && !noMoreAif) || sc->aif_pending)
979dce93cd0SAchim Leubner 				aac_request_aif(sc);
980dce93cd0SAchim Leubner 		}
9813fea9c0dSAchim Leubner 	}
9823fea9c0dSAchim Leubner 
9833fea9c0dSAchim Leubner 	if (mode & AAC_INT_MODE_AIF) {
984dce93cd0SAchim Leubner 		aac_request_aif(sc);
9853fea9c0dSAchim Leubner 		AAC_ACCESS_DEVREG(sc, AAC_CLEAR_AIF_BIT);
9863fea9c0dSAchim Leubner 		mode = 0;
987dce93cd0SAchim Leubner 	}
988dce93cd0SAchim Leubner 
989dce93cd0SAchim Leubner 	/* see if we can start some more I/O */
990dce93cd0SAchim Leubner 	if ((sc->flags & AAC_QUEUE_FRZN) == 0)
991dce93cd0SAchim Leubner 		aacraid_startio(sc);
992dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
993dce93cd0SAchim Leubner }
994dce93cd0SAchim Leubner 
995dce93cd0SAchim Leubner /*
996dce93cd0SAchim Leubner  * Handle notification of one or more FIBs coming from the controller.
997dce93cd0SAchim Leubner  */
998dce93cd0SAchim Leubner static void
999dce93cd0SAchim Leubner aac_command_thread(struct aac_softc *sc)
1000dce93cd0SAchim Leubner {
1001dce93cd0SAchim Leubner 	int retval;
1002dce93cd0SAchim Leubner 
1003dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1004dce93cd0SAchim Leubner 
1005dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
1006dce93cd0SAchim Leubner 	sc->aifflags = AAC_AIFFLAGS_RUNNING;
1007dce93cd0SAchim Leubner 
1008dce93cd0SAchim Leubner 	while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) {
1009dce93cd0SAchim Leubner 
1010dce93cd0SAchim Leubner 		retval = 0;
1011dce93cd0SAchim Leubner 		if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0)
1012dce93cd0SAchim Leubner 			retval = msleep(sc->aifthread, &sc->aac_io_lock, PRIBIO,
1013dce93cd0SAchim Leubner 					"aacraid_aifthd", AAC_PERIODIC_INTERVAL * hz);
1014dce93cd0SAchim Leubner 
1015dce93cd0SAchim Leubner 		/*
1016dfdbb320SWarner Losh 		 * First see if any FIBs need to be allocated.
1017dce93cd0SAchim Leubner 		 */
1018dce93cd0SAchim Leubner 		if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) {
1019dce93cd0SAchim Leubner 			aac_alloc_commands(sc);
1020dce93cd0SAchim Leubner 			sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS;
1021dce93cd0SAchim Leubner 			aacraid_startio(sc);
1022dce93cd0SAchim Leubner 		}
1023dce93cd0SAchim Leubner 
1024dce93cd0SAchim Leubner 		/*
1025dce93cd0SAchim Leubner 		 * While we're here, check to see if any commands are stuck.
1026dce93cd0SAchim Leubner 		 * This is pretty low-priority, so it's ok if it doesn't
1027dce93cd0SAchim Leubner 		 * always fire.
1028dce93cd0SAchim Leubner 		 */
1029dce93cd0SAchim Leubner 		if (retval == EWOULDBLOCK)
1030dce93cd0SAchim Leubner 			aac_timeout(sc);
1031dce93cd0SAchim Leubner 
1032dce93cd0SAchim Leubner 		/* Check the hardware printf message buffer */
1033dce93cd0SAchim Leubner 		if (sc->aac_common->ac_printf[0] != 0)
1034dce93cd0SAchim Leubner 			aac_print_printf(sc);
1035dce93cd0SAchim Leubner 	}
1036dce93cd0SAchim Leubner 	sc->aifflags &= ~AAC_AIFFLAGS_RUNNING;
1037dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
1038dce93cd0SAchim Leubner 	wakeup(sc->aac_dev);
1039dce93cd0SAchim Leubner 
1040dce93cd0SAchim Leubner 	aac_kthread_exit(0);
1041dce93cd0SAchim Leubner }
1042dce93cd0SAchim Leubner 
1043dce93cd0SAchim Leubner /*
1044dce93cd0SAchim Leubner  * Submit a command to the controller, return when it completes.
1045dce93cd0SAchim Leubner  * XXX This is very dangerous!  If the card has gone out to lunch, we could
1046dce93cd0SAchim Leubner  *     be stuck here forever.  At the same time, signals are not caught
1047dce93cd0SAchim Leubner  *     because there is a risk that a signal could wakeup the sleep before
1048dce93cd0SAchim Leubner  *     the card has a chance to complete the command.  Since there is no way
1049dce93cd0SAchim Leubner  *     to cancel a command that is in progress, we can't protect against the
1050dce93cd0SAchim Leubner  *     card completing a command late and spamming the command and data
1051dce93cd0SAchim Leubner  *     memory.  So, we are held hostage until the command completes.
1052dce93cd0SAchim Leubner  */
1053dce93cd0SAchim Leubner int
1054dce93cd0SAchim Leubner aacraid_wait_command(struct aac_command *cm)
1055dce93cd0SAchim Leubner {
1056dce93cd0SAchim Leubner 	struct aac_softc *sc;
1057dce93cd0SAchim Leubner 	int error;
1058dce93cd0SAchim Leubner 
1059dce93cd0SAchim Leubner 	sc = cm->cm_sc;
1060dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1061dce93cd0SAchim Leubner 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
1062dce93cd0SAchim Leubner 
1063dce93cd0SAchim Leubner 	/* Put the command on the ready queue and get things going */
1064dce93cd0SAchim Leubner 	aac_enqueue_ready(cm);
1065dce93cd0SAchim Leubner 	aacraid_startio(sc);
1066dce93cd0SAchim Leubner 	error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacraid_wait", 0);
1067dce93cd0SAchim Leubner 	return(error);
1068dce93cd0SAchim Leubner }
1069dce93cd0SAchim Leubner 
1070dce93cd0SAchim Leubner /*
1071dce93cd0SAchim Leubner  *Command Buffer Management
1072dce93cd0SAchim Leubner  */
1073dce93cd0SAchim Leubner 
1074dce93cd0SAchim Leubner /*
1075dce93cd0SAchim Leubner  * Allocate a command.
1076dce93cd0SAchim Leubner  */
1077dce93cd0SAchim Leubner int
1078dce93cd0SAchim Leubner aacraid_alloc_command(struct aac_softc *sc, struct aac_command **cmp)
1079dce93cd0SAchim Leubner {
1080dce93cd0SAchim Leubner 	struct aac_command *cm;
1081dce93cd0SAchim Leubner 
1082dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1083dce93cd0SAchim Leubner 
1084dce93cd0SAchim Leubner 	if ((cm = aac_dequeue_free(sc)) == NULL) {
1085dce93cd0SAchim Leubner 		if (sc->total_fibs < sc->aac_max_fibs) {
1086dce93cd0SAchim Leubner 			sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS;
1087dce93cd0SAchim Leubner 			wakeup(sc->aifthread);
1088dce93cd0SAchim Leubner 		}
1089dce93cd0SAchim Leubner 		return (EBUSY);
1090dce93cd0SAchim Leubner 	}
1091dce93cd0SAchim Leubner 
1092dce93cd0SAchim Leubner 	*cmp = cm;
1093dce93cd0SAchim Leubner 	return(0);
1094dce93cd0SAchim Leubner }
1095dce93cd0SAchim Leubner 
1096dce93cd0SAchim Leubner /*
1097dce93cd0SAchim Leubner  * Release a command back to the freelist.
1098dce93cd0SAchim Leubner  */
1099dce93cd0SAchim Leubner void
1100dce93cd0SAchim Leubner aacraid_release_command(struct aac_command *cm)
1101dce93cd0SAchim Leubner {
1102dce93cd0SAchim Leubner 	struct aac_event *event;
1103dce93cd0SAchim Leubner 	struct aac_softc *sc;
1104dce93cd0SAchim Leubner 
1105dce93cd0SAchim Leubner 	sc = cm->cm_sc;
1106dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1107dce93cd0SAchim Leubner 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
1108dce93cd0SAchim Leubner 
1109dce93cd0SAchim Leubner 	/* (re)initialize the command/FIB */
1110dce93cd0SAchim Leubner 	cm->cm_sgtable = NULL;
1111dce93cd0SAchim Leubner 	cm->cm_flags = 0;
1112dce93cd0SAchim Leubner 	cm->cm_complete = NULL;
1113dce93cd0SAchim Leubner 	cm->cm_ccb = NULL;
1114dce93cd0SAchim Leubner 	cm->cm_passthr_dmat = 0;
1115dce93cd0SAchim Leubner 	cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
1116dce93cd0SAchim Leubner 	cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
1117dce93cd0SAchim Leubner 	cm->cm_fib->Header.Unused = 0;
1118dce93cd0SAchim Leubner 	cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size;
1119dce93cd0SAchim Leubner 
1120dce93cd0SAchim Leubner 	/*
1121dce93cd0SAchim Leubner 	 * These are duplicated in aac_start to cover the case where an
1122dce93cd0SAchim Leubner 	 * intermediate stage may have destroyed them.  They're left
1123dce93cd0SAchim Leubner 	 * initialized here for debugging purposes only.
1124dce93cd0SAchim Leubner 	 */
1125dce93cd0SAchim Leubner 	cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1126dce93cd0SAchim Leubner 	cm->cm_fib->Header.Handle = 0;
1127dce93cd0SAchim Leubner 
1128dce93cd0SAchim Leubner 	aac_enqueue_free(cm);
1129dce93cd0SAchim Leubner 
1130dce93cd0SAchim Leubner 	/*
1131dce93cd0SAchim Leubner 	 * Dequeue all events so that there's no risk of events getting
1132dce93cd0SAchim Leubner 	 * stranded.
1133dce93cd0SAchim Leubner 	 */
1134dce93cd0SAchim Leubner 	while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) {
1135dce93cd0SAchim Leubner 		TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links);
1136dce93cd0SAchim Leubner 		event->ev_callback(sc, event, event->ev_arg);
1137dce93cd0SAchim Leubner 	}
1138dce93cd0SAchim Leubner }
1139dce93cd0SAchim Leubner 
1140dce93cd0SAchim Leubner /*
1141dce93cd0SAchim Leubner  * Map helper for command/FIB allocation.
1142dce93cd0SAchim Leubner  */
1143dce93cd0SAchim Leubner static void
1144dce93cd0SAchim Leubner aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1145dce93cd0SAchim Leubner {
1146dce93cd0SAchim Leubner 	uint64_t	*fibphys;
1147dce93cd0SAchim Leubner 
1148dce93cd0SAchim Leubner 	fibphys = (uint64_t *)arg;
1149dce93cd0SAchim Leubner 
1150dce93cd0SAchim Leubner 	*fibphys = segs[0].ds_addr;
1151dce93cd0SAchim Leubner }
1152dce93cd0SAchim Leubner 
1153dce93cd0SAchim Leubner /*
1154dce93cd0SAchim Leubner  * Allocate and initialize commands/FIBs for this adapter.
1155dce93cd0SAchim Leubner  */
1156dce93cd0SAchim Leubner static int
1157dce93cd0SAchim Leubner aac_alloc_commands(struct aac_softc *sc)
1158dce93cd0SAchim Leubner {
1159dce93cd0SAchim Leubner 	struct aac_command *cm;
1160dce93cd0SAchim Leubner 	struct aac_fibmap *fm;
1161dce93cd0SAchim Leubner 	uint64_t fibphys;
1162dce93cd0SAchim Leubner 	int i, error;
1163dce93cd0SAchim Leubner 	u_int32_t maxsize;
1164dce93cd0SAchim Leubner 
1165dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
116661722264SAndriy Gapon 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
1167dce93cd0SAchim Leubner 
1168dce93cd0SAchim Leubner 	if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs)
1169dce93cd0SAchim Leubner 		return (ENOMEM);
1170dce93cd0SAchim Leubner 
1171dce93cd0SAchim Leubner 	fm = malloc(sizeof(struct aac_fibmap), M_AACRAIDBUF, M_NOWAIT|M_ZERO);
1172dce93cd0SAchim Leubner 	if (fm == NULL)
1173dce93cd0SAchim Leubner 		return (ENOMEM);
1174dce93cd0SAchim Leubner 
117561722264SAndriy Gapon 	mtx_unlock(&sc->aac_io_lock);
1176dce93cd0SAchim Leubner 	/* allocate the FIBs in DMAable memory and load them */
1177dce93cd0SAchim Leubner 	if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs,
1178dce93cd0SAchim Leubner 			     BUS_DMA_NOWAIT, &fm->aac_fibmap)) {
1179dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
1180dce93cd0SAchim Leubner 			      "Not enough contiguous memory available.\n");
1181dce93cd0SAchim Leubner 		free(fm, M_AACRAIDBUF);
1182dce93cd0SAchim Leubner 		mtx_lock(&sc->aac_io_lock);
1183dce93cd0SAchim Leubner 		return (ENOMEM);
1184dce93cd0SAchim Leubner 	}
1185dce93cd0SAchim Leubner 
1186dce93cd0SAchim Leubner 	maxsize = sc->aac_max_fib_size + 31;
1187dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1)
1188dce93cd0SAchim Leubner 		maxsize += sizeof(struct aac_fib_xporthdr);
1189dce93cd0SAchim Leubner 	/* Ignore errors since this doesn't bounce */
1190dce93cd0SAchim Leubner 	(void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs,
1191dce93cd0SAchim Leubner 			      sc->aac_max_fibs_alloc * maxsize,
1192dce93cd0SAchim Leubner 			      aac_map_command_helper, &fibphys, 0);
119361722264SAndriy Gapon 	mtx_lock(&sc->aac_io_lock);
1194dce93cd0SAchim Leubner 
1195dce93cd0SAchim Leubner 	/* initialize constant fields in the command structure */
1196dce93cd0SAchim Leubner 	bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * maxsize);
1197dce93cd0SAchim Leubner 	for (i = 0; i < sc->aac_max_fibs_alloc; i++) {
1198dce93cd0SAchim Leubner 		cm = sc->aac_commands + sc->total_fibs;
1199dce93cd0SAchim Leubner 		fm->aac_commands = cm;
1200dce93cd0SAchim Leubner 		cm->cm_sc = sc;
1201dce93cd0SAchim Leubner 		cm->cm_fib = (struct aac_fib *)
1202dce93cd0SAchim Leubner 			((u_int8_t *)fm->aac_fibs + i * maxsize);
1203dce93cd0SAchim Leubner 		cm->cm_fibphys = fibphys + i * maxsize;
1204dce93cd0SAchim Leubner 		if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) {
1205dce93cd0SAchim Leubner 			u_int64_t fibphys_aligned;
1206dce93cd0SAchim Leubner 			fibphys_aligned =
1207dce93cd0SAchim Leubner 				(cm->cm_fibphys + sizeof(struct aac_fib_xporthdr) + 31) & ~31;
1208dce93cd0SAchim Leubner 			cm->cm_fib = (struct aac_fib *)
1209dce93cd0SAchim Leubner 				((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys));
1210dce93cd0SAchim Leubner 			cm->cm_fibphys = fibphys_aligned;
1211dce93cd0SAchim Leubner 		} else {
1212dce93cd0SAchim Leubner 			u_int64_t fibphys_aligned;
1213dce93cd0SAchim Leubner 			fibphys_aligned = (cm->cm_fibphys + 31) & ~31;
1214dce93cd0SAchim Leubner 			cm->cm_fib = (struct aac_fib *)
1215dce93cd0SAchim Leubner 				((u_int8_t *)cm->cm_fib + (fibphys_aligned - cm->cm_fibphys));
1216dce93cd0SAchim Leubner 			cm->cm_fibphys = fibphys_aligned;
1217dce93cd0SAchim Leubner 		}
1218dce93cd0SAchim Leubner 		cm->cm_index = sc->total_fibs;
1219dce93cd0SAchim Leubner 
1220dce93cd0SAchim Leubner 		if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0,
1221dce93cd0SAchim Leubner 					       &cm->cm_datamap)) != 0)
1222dce93cd0SAchim Leubner 			break;
122361722264SAndriy Gapon 		if (sc->aac_max_fibs <= 1 || sc->aac_max_fibs - sc->total_fibs > 1)
1224dce93cd0SAchim Leubner 			aacraid_release_command(cm);
1225dce93cd0SAchim Leubner 		sc->total_fibs++;
1226dce93cd0SAchim Leubner 	}
1227dce93cd0SAchim Leubner 
1228dce93cd0SAchim Leubner 	if (i > 0) {
1229dce93cd0SAchim Leubner 		TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link);
1230dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs);
1231dce93cd0SAchim Leubner 		return (0);
1232dce93cd0SAchim Leubner 	}
1233dce93cd0SAchim Leubner 
1234dce93cd0SAchim Leubner 	bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1235dce93cd0SAchim Leubner 	bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1236dce93cd0SAchim Leubner 	free(fm, M_AACRAIDBUF);
1237dce93cd0SAchim Leubner 	return (ENOMEM);
1238dce93cd0SAchim Leubner }
1239dce93cd0SAchim Leubner 
1240dce93cd0SAchim Leubner /*
1241dce93cd0SAchim Leubner  * Free FIBs owned by this adapter.
1242dce93cd0SAchim Leubner  */
1243dce93cd0SAchim Leubner static void
1244dce93cd0SAchim Leubner aac_free_commands(struct aac_softc *sc)
1245dce93cd0SAchim Leubner {
1246dce93cd0SAchim Leubner 	struct aac_fibmap *fm;
1247dce93cd0SAchim Leubner 	struct aac_command *cm;
1248dce93cd0SAchim Leubner 	int i;
1249dce93cd0SAchim Leubner 
1250dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1251dce93cd0SAchim Leubner 
1252dce93cd0SAchim Leubner 	while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) {
1253dce93cd0SAchim Leubner 
1254dce93cd0SAchim Leubner 		TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link);
1255dce93cd0SAchim Leubner 		/*
1256dce93cd0SAchim Leubner 		 * We check against total_fibs to handle partially
1257dce93cd0SAchim Leubner 		 * allocated blocks.
1258dce93cd0SAchim Leubner 		 */
1259dce93cd0SAchim Leubner 		for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) {
1260dce93cd0SAchim Leubner 			cm = fm->aac_commands + i;
1261dce93cd0SAchim Leubner 			bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap);
1262dce93cd0SAchim Leubner 		}
1263dce93cd0SAchim Leubner 		bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap);
1264dce93cd0SAchim Leubner 		bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap);
1265dce93cd0SAchim Leubner 		free(fm, M_AACRAIDBUF);
1266dce93cd0SAchim Leubner 	}
1267dce93cd0SAchim Leubner }
1268dce93cd0SAchim Leubner 
1269dce93cd0SAchim Leubner /*
1270dce93cd0SAchim Leubner  * Command-mapping helper function - populate this command's s/g table.
1271dce93cd0SAchim Leubner  */
1272dce93cd0SAchim Leubner void
1273dce93cd0SAchim Leubner aacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1274dce93cd0SAchim Leubner {
1275dce93cd0SAchim Leubner 	struct aac_softc *sc;
1276dce93cd0SAchim Leubner 	struct aac_command *cm;
1277dce93cd0SAchim Leubner 	struct aac_fib *fib;
1278dce93cd0SAchim Leubner 	int i;
1279dce93cd0SAchim Leubner 
1280dce93cd0SAchim Leubner 	cm = (struct aac_command *)arg;
1281dce93cd0SAchim Leubner 	sc = cm->cm_sc;
1282dce93cd0SAchim Leubner 	fib = cm->cm_fib;
1283dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "nseg %d", nseg);
1284dce93cd0SAchim Leubner 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
1285dce93cd0SAchim Leubner 
12864f1dfabaSMaxim Sobolev 	if ((sc->flags & AAC_FLAGS_SYNC_MODE) && sc->aac_sync_cm)
12874f1dfabaSMaxim Sobolev 		return;
12884f1dfabaSMaxim Sobolev 
1289dce93cd0SAchim Leubner 	/* copy into the FIB */
1290dce93cd0SAchim Leubner 	if (cm->cm_sgtable != NULL) {
1291dce93cd0SAchim Leubner 		if (fib->Header.Command == RawIo2) {
1292dce93cd0SAchim Leubner 			struct aac_raw_io2 *raw;
1293dce93cd0SAchim Leubner 			struct aac_sge_ieee1212 *sg;
1294dce93cd0SAchim Leubner 			u_int32_t min_size = PAGE_SIZE, cur_size;
1295dce93cd0SAchim Leubner 			int conformable = TRUE;
1296dce93cd0SAchim Leubner 
1297dce93cd0SAchim Leubner 			raw = (struct aac_raw_io2 *)&fib->data[0];
1298dce93cd0SAchim Leubner 			sg = (struct aac_sge_ieee1212 *)cm->cm_sgtable;
1299dce93cd0SAchim Leubner 			raw->sgeCnt = nseg;
1300dce93cd0SAchim Leubner 
1301dce93cd0SAchim Leubner 			for (i = 0; i < nseg; i++) {
1302dce93cd0SAchim Leubner 				cur_size = segs[i].ds_len;
1303dce93cd0SAchim Leubner 				sg[i].addrHigh = 0;
1304dce93cd0SAchim Leubner 				*(bus_addr_t *)&sg[i].addrLow = segs[i].ds_addr;
1305dce93cd0SAchim Leubner 				sg[i].length = cur_size;
1306dce93cd0SAchim Leubner 				sg[i].flags = 0;
1307dce93cd0SAchim Leubner 				if (i == 0) {
1308dce93cd0SAchim Leubner 					raw->sgeFirstSize = cur_size;
1309dce93cd0SAchim Leubner 				} else if (i == 1) {
1310dce93cd0SAchim Leubner 					raw->sgeNominalSize = cur_size;
1311dce93cd0SAchim Leubner 					min_size = cur_size;
1312dce93cd0SAchim Leubner 				} else if ((i+1) < nseg &&
1313dce93cd0SAchim Leubner 					cur_size != raw->sgeNominalSize) {
1314dce93cd0SAchim Leubner 					conformable = FALSE;
1315dce93cd0SAchim Leubner 					if (cur_size < min_size)
1316dce93cd0SAchim Leubner 						min_size = cur_size;
1317dce93cd0SAchim Leubner 				}
1318dce93cd0SAchim Leubner 			}
1319dce93cd0SAchim Leubner 
1320dce93cd0SAchim Leubner 			/* not conformable: evaluate required sg elements */
1321dce93cd0SAchim Leubner 			if (!conformable) {
1322dce93cd0SAchim Leubner 				int j, err_found, nseg_new = nseg;
1323dce93cd0SAchim Leubner 				for (i = min_size / PAGE_SIZE; i >= 1; --i) {
1324dce93cd0SAchim Leubner 					err_found = FALSE;
1325dce93cd0SAchim Leubner 					nseg_new = 2;
1326dce93cd0SAchim Leubner 					for (j = 1; j < nseg - 1; ++j) {
1327dce93cd0SAchim Leubner 						if (sg[j].length % (i*PAGE_SIZE)) {
1328dce93cd0SAchim Leubner 							err_found = TRUE;
1329dce93cd0SAchim Leubner 							break;
1330dce93cd0SAchim Leubner 						}
1331dce93cd0SAchim Leubner 						nseg_new += (sg[j].length / (i*PAGE_SIZE));
1332dce93cd0SAchim Leubner 					}
1333dce93cd0SAchim Leubner 					if (!err_found)
1334dce93cd0SAchim Leubner 						break;
1335dce93cd0SAchim Leubner 				}
1336dce93cd0SAchim Leubner 				if (i>0 && nseg_new<=sc->aac_sg_tablesize &&
1337dce93cd0SAchim Leubner 					!(sc->hint_flags & 4))
1338dce93cd0SAchim Leubner 					nseg = aac_convert_sgraw2(sc,
1339dce93cd0SAchim Leubner 						raw, i, nseg, nseg_new);
1340dce93cd0SAchim Leubner 			} else {
1341dce93cd0SAchim Leubner 				raw->flags |= RIO2_SGL_CONFORMANT;
1342dce93cd0SAchim Leubner 			}
1343dce93cd0SAchim Leubner 
1344dce93cd0SAchim Leubner 			/* update the FIB size for the s/g count */
1345dce93cd0SAchim Leubner 			fib->Header.Size += nseg *
1346dce93cd0SAchim Leubner 				sizeof(struct aac_sge_ieee1212);
1347dce93cd0SAchim Leubner 
1348dce93cd0SAchim Leubner 		} else if (fib->Header.Command == RawIo) {
1349dce93cd0SAchim Leubner 			struct aac_sg_tableraw *sg;
1350dce93cd0SAchim Leubner 			sg = (struct aac_sg_tableraw *)cm->cm_sgtable;
1351dce93cd0SAchim Leubner 			sg->SgCount = nseg;
1352dce93cd0SAchim Leubner 			for (i = 0; i < nseg; i++) {
1353dce93cd0SAchim Leubner 				sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr;
1354dce93cd0SAchim Leubner 				sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len;
1355dce93cd0SAchim Leubner 				sg->SgEntryRaw[i].Next = 0;
1356dce93cd0SAchim Leubner 				sg->SgEntryRaw[i].Prev = 0;
1357dce93cd0SAchim Leubner 				sg->SgEntryRaw[i].Flags = 0;
1358dce93cd0SAchim Leubner 			}
1359dce93cd0SAchim Leubner 			/* update the FIB size for the s/g count */
1360dce93cd0SAchim Leubner 			fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw);
1361dce93cd0SAchim Leubner 		} else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
1362dce93cd0SAchim Leubner 			struct aac_sg_table *sg;
1363dce93cd0SAchim Leubner 			sg = cm->cm_sgtable;
1364dce93cd0SAchim Leubner 			sg->SgCount = nseg;
1365dce93cd0SAchim Leubner 			for (i = 0; i < nseg; i++) {
1366dce93cd0SAchim Leubner 				sg->SgEntry[i].SgAddress = segs[i].ds_addr;
1367dce93cd0SAchim Leubner 				sg->SgEntry[i].SgByteCount = segs[i].ds_len;
1368dce93cd0SAchim Leubner 			}
1369dce93cd0SAchim Leubner 			/* update the FIB size for the s/g count */
1370dce93cd0SAchim Leubner 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry);
1371dce93cd0SAchim Leubner 		} else {
1372dce93cd0SAchim Leubner 			struct aac_sg_table64 *sg;
1373dce93cd0SAchim Leubner 			sg = (struct aac_sg_table64 *)cm->cm_sgtable;
1374dce93cd0SAchim Leubner 			sg->SgCount = nseg;
1375dce93cd0SAchim Leubner 			for (i = 0; i < nseg; i++) {
1376dce93cd0SAchim Leubner 				sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
1377dce93cd0SAchim Leubner 				sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
1378dce93cd0SAchim Leubner 			}
1379dce93cd0SAchim Leubner 			/* update the FIB size for the s/g count */
1380dce93cd0SAchim Leubner 			fib->Header.Size += nseg*sizeof(struct aac_sg_entry64);
1381dce93cd0SAchim Leubner 		}
1382dce93cd0SAchim Leubner 	}
1383dce93cd0SAchim Leubner 
1384dce93cd0SAchim Leubner 	/* Fix up the address values in the FIB.  Use the command array index
1385dce93cd0SAchim Leubner 	 * instead of a pointer since these fields are only 32 bits.  Shift
1386dce93cd0SAchim Leubner 	 * the SenderFibAddress over to make room for the fast response bit
1387dce93cd0SAchim Leubner 	 * and for the AIF bit
1388dce93cd0SAchim Leubner 	 */
1389dce93cd0SAchim Leubner 	cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2);
1390dce93cd0SAchim Leubner 	cm->cm_fib->Header.u.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
1391dce93cd0SAchim Leubner 
1392dce93cd0SAchim Leubner 	/* save a pointer to the command for speedy reverse-lookup */
1393dce93cd0SAchim Leubner 	cm->cm_fib->Header.Handle += cm->cm_index + 1;
1394dce93cd0SAchim Leubner 
1395dce93cd0SAchim Leubner 	if (cm->cm_passthr_dmat == 0) {
1396dce93cd0SAchim Leubner 		if (cm->cm_flags & AAC_CMD_DATAIN)
1397dce93cd0SAchim Leubner 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1398dce93cd0SAchim Leubner 							BUS_DMASYNC_PREREAD);
1399dce93cd0SAchim Leubner 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1400dce93cd0SAchim Leubner 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1401dce93cd0SAchim Leubner 							BUS_DMASYNC_PREWRITE);
1402dce93cd0SAchim Leubner 	}
1403dce93cd0SAchim Leubner 
1404dce93cd0SAchim Leubner 	cm->cm_flags |= AAC_CMD_MAPPED;
1405dce93cd0SAchim Leubner 
14064f1dfabaSMaxim Sobolev 	if (cm->cm_flags & AAC_CMD_WAIT) {
14074f1dfabaSMaxim Sobolev 		aacraid_sync_command(sc, AAC_MONKER_SYNCFIB,
14084f1dfabaSMaxim Sobolev 			cm->cm_fibphys, 0, 0, 0, NULL, NULL);
14094f1dfabaSMaxim Sobolev 	} else if (sc->flags & AAC_FLAGS_SYNC_MODE) {
1410dce93cd0SAchim Leubner 		u_int32_t wait = 0;
14114f1dfabaSMaxim Sobolev 		sc->aac_sync_cm = cm;
14124f1dfabaSMaxim Sobolev 		aacraid_sync_command(sc, AAC_MONKER_SYNCFIB,
14134f1dfabaSMaxim Sobolev 			cm->cm_fibphys, 0, 0, 0, &wait, NULL);
1414dce93cd0SAchim Leubner 	} else {
1415dce93cd0SAchim Leubner 		int count = 10000000L;
1416dce93cd0SAchim Leubner 		while (AAC_SEND_COMMAND(sc, cm) != 0) {
1417dce93cd0SAchim Leubner 			if (--count == 0) {
1418dce93cd0SAchim Leubner 				aac_unmap_command(cm);
1419dce93cd0SAchim Leubner 				sc->flags |= AAC_QUEUE_FRZN;
1420dce93cd0SAchim Leubner 				aac_requeue_ready(cm);
1421dce93cd0SAchim Leubner 			}
1422dce93cd0SAchim Leubner 			DELAY(5);			/* wait 5 usec. */
1423dce93cd0SAchim Leubner 		}
1424dce93cd0SAchim Leubner 	}
1425dce93cd0SAchim Leubner }
1426dce93cd0SAchim Leubner 
1427dce93cd0SAchim Leubner 
1428dce93cd0SAchim Leubner static int
1429dce93cd0SAchim Leubner aac_convert_sgraw2(struct aac_softc *sc, struct aac_raw_io2 *raw,
1430dce93cd0SAchim Leubner 				   int pages, int nseg, int nseg_new)
1431dce93cd0SAchim Leubner {
1432dce93cd0SAchim Leubner 	struct aac_sge_ieee1212 *sge;
1433dce93cd0SAchim Leubner 	int i, j, pos;
1434dce93cd0SAchim Leubner 	u_int32_t addr_low;
1435dce93cd0SAchim Leubner 
1436ac2fffa4SPedro F. Giffuni 	sge = malloc(nseg_new * sizeof(struct aac_sge_ieee1212),
1437dce93cd0SAchim Leubner 		M_AACRAIDBUF, M_NOWAIT|M_ZERO);
1438dce93cd0SAchim Leubner 	if (sge == NULL)
1439dce93cd0SAchim Leubner 		return nseg;
1440dce93cd0SAchim Leubner 
1441dce93cd0SAchim Leubner 	for (i = 1, pos = 1; i < nseg - 1; ++i) {
1442dce93cd0SAchim Leubner 		for (j = 0; j < raw->sge[i].length / (pages*PAGE_SIZE); ++j) {
1443dce93cd0SAchim Leubner 			addr_low = raw->sge[i].addrLow + j * pages * PAGE_SIZE;
1444dce93cd0SAchim Leubner 			sge[pos].addrLow = addr_low;
1445dce93cd0SAchim Leubner 			sge[pos].addrHigh = raw->sge[i].addrHigh;
1446dce93cd0SAchim Leubner 			if (addr_low < raw->sge[i].addrLow)
1447dce93cd0SAchim Leubner 				sge[pos].addrHigh++;
1448dce93cd0SAchim Leubner 			sge[pos].length = pages * PAGE_SIZE;
1449dce93cd0SAchim Leubner 			sge[pos].flags = 0;
1450dce93cd0SAchim Leubner 			pos++;
1451dce93cd0SAchim Leubner 		}
1452dce93cd0SAchim Leubner 	}
1453dce93cd0SAchim Leubner 	sge[pos] = raw->sge[nseg-1];
1454dce93cd0SAchim Leubner 	for (i = 1; i < nseg_new; ++i)
1455dce93cd0SAchim Leubner 		raw->sge[i] = sge[i];
1456dce93cd0SAchim Leubner 
1457dce93cd0SAchim Leubner 	free(sge, M_AACRAIDBUF);
1458dce93cd0SAchim Leubner 	raw->sgeCnt = nseg_new;
1459dce93cd0SAchim Leubner 	raw->flags |= RIO2_SGL_CONFORMANT;
1460dce93cd0SAchim Leubner 	raw->sgeNominalSize = pages * PAGE_SIZE;
1461dce93cd0SAchim Leubner 	return nseg_new;
1462dce93cd0SAchim Leubner }
1463dce93cd0SAchim Leubner 
1464dce93cd0SAchim Leubner 
1465dce93cd0SAchim Leubner /*
1466dce93cd0SAchim Leubner  * Unmap a command from controller-visible space.
1467dce93cd0SAchim Leubner  */
1468dce93cd0SAchim Leubner static void
1469dce93cd0SAchim Leubner aac_unmap_command(struct aac_command *cm)
1470dce93cd0SAchim Leubner {
1471dce93cd0SAchim Leubner 	struct aac_softc *sc;
1472dce93cd0SAchim Leubner 
1473dce93cd0SAchim Leubner 	sc = cm->cm_sc;
1474dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1475dce93cd0SAchim Leubner 
1476dce93cd0SAchim Leubner 	if (!(cm->cm_flags & AAC_CMD_MAPPED))
1477dce93cd0SAchim Leubner 		return;
1478dce93cd0SAchim Leubner 
1479dce93cd0SAchim Leubner 	if (cm->cm_datalen != 0 && cm->cm_passthr_dmat == 0) {
1480dce93cd0SAchim Leubner 		if (cm->cm_flags & AAC_CMD_DATAIN)
1481dce93cd0SAchim Leubner 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1482dce93cd0SAchim Leubner 					BUS_DMASYNC_POSTREAD);
1483dce93cd0SAchim Leubner 		if (cm->cm_flags & AAC_CMD_DATAOUT)
1484dce93cd0SAchim Leubner 			bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
1485dce93cd0SAchim Leubner 					BUS_DMASYNC_POSTWRITE);
1486dce93cd0SAchim Leubner 
1487dce93cd0SAchim Leubner 		bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap);
1488dce93cd0SAchim Leubner 	}
1489dce93cd0SAchim Leubner 	cm->cm_flags &= ~AAC_CMD_MAPPED;
1490dce93cd0SAchim Leubner }
1491dce93cd0SAchim Leubner 
1492dce93cd0SAchim Leubner /*
1493dce93cd0SAchim Leubner  * Hardware Interface
1494dce93cd0SAchim Leubner  */
1495dce93cd0SAchim Leubner 
1496dce93cd0SAchim Leubner /*
1497dce93cd0SAchim Leubner  * Initialize the adapter.
1498dce93cd0SAchim Leubner  */
1499dce93cd0SAchim Leubner static void
1500dce93cd0SAchim Leubner aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1501dce93cd0SAchim Leubner {
1502dce93cd0SAchim Leubner 	struct aac_softc *sc;
1503dce93cd0SAchim Leubner 
1504dce93cd0SAchim Leubner 	sc = (struct aac_softc *)arg;
1505dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1506dce93cd0SAchim Leubner 
1507dce93cd0SAchim Leubner 	sc->aac_common_busaddr = segs[0].ds_addr;
1508dce93cd0SAchim Leubner }
1509dce93cd0SAchim Leubner 
1510dce93cd0SAchim Leubner static int
1511dce93cd0SAchim Leubner aac_check_firmware(struct aac_softc *sc)
1512dce93cd0SAchim Leubner {
1513dce93cd0SAchim Leubner 	u_int32_t code, major, minor, maxsize;
15143fea9c0dSAchim Leubner 	u_int32_t options = 0, atu_size = 0, status, waitCount;
1515dce93cd0SAchim Leubner 	time_t then;
1516dce93cd0SAchim Leubner 
1517dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
15183fea9c0dSAchim Leubner 
15193fea9c0dSAchim Leubner 	/* check if flash update is running */
15203fea9c0dSAchim Leubner 	if (AAC_GET_FWSTATUS(sc) & AAC_FLASH_UPD_PENDING) {
15213fea9c0dSAchim Leubner 		then = time_uptime;
15223fea9c0dSAchim Leubner 		do {
15233fea9c0dSAchim Leubner 			code = AAC_GET_FWSTATUS(sc);
15243fea9c0dSAchim Leubner 			if (time_uptime > (then + AAC_FWUPD_TIMEOUT)) {
15253fea9c0dSAchim Leubner 				device_printf(sc->aac_dev,
15263fea9c0dSAchim Leubner 						  "FATAL: controller not coming ready, "
15273fea9c0dSAchim Leubner 						   "status %x\n", code);
15283fea9c0dSAchim Leubner 				return(ENXIO);
15293fea9c0dSAchim Leubner 			}
15303fea9c0dSAchim Leubner 		} while (!(code & AAC_FLASH_UPD_SUCCESS) && !(code & AAC_FLASH_UPD_FAILED));
15313fea9c0dSAchim Leubner 		/*
15323fea9c0dSAchim Leubner 		 * Delay 10 seconds. Because right now FW is doing a soft reset,
15333fea9c0dSAchim Leubner 		 * do not read scratch pad register at this time
15343fea9c0dSAchim Leubner 		 */
15353fea9c0dSAchim Leubner 		waitCount = 10 * 10000;
15363fea9c0dSAchim Leubner 		while (waitCount) {
15373fea9c0dSAchim Leubner 			DELAY(100);		/* delay 100 microseconds */
15383fea9c0dSAchim Leubner 			waitCount--;
15393fea9c0dSAchim Leubner 		}
15403fea9c0dSAchim Leubner 	}
15413fea9c0dSAchim Leubner 
1542dce93cd0SAchim Leubner 	/*
1543dce93cd0SAchim Leubner 	 * Wait for the adapter to come ready.
1544dce93cd0SAchim Leubner 	 */
1545dce93cd0SAchim Leubner 	then = time_uptime;
1546dce93cd0SAchim Leubner 	do {
1547dce93cd0SAchim Leubner 		code = AAC_GET_FWSTATUS(sc);
1548dce93cd0SAchim Leubner 		if (time_uptime > (then + AAC_BOOT_TIMEOUT)) {
1549dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
1550dce93cd0SAchim Leubner 				      "FATAL: controller not coming ready, "
1551dce93cd0SAchim Leubner 					   "status %x\n", code);
1552dce93cd0SAchim Leubner 			return(ENXIO);
1553dce93cd0SAchim Leubner 		}
15543fea9c0dSAchim Leubner 	} while (!(code & AAC_UP_AND_RUNNING) || code == 0xffffffff);
1555dce93cd0SAchim Leubner 
1556dce93cd0SAchim Leubner 	/*
1557dce93cd0SAchim Leubner 	 * Retrieve the firmware version numbers.  Dell PERC2/QC cards with
1558dce93cd0SAchim Leubner 	 * firmware version 1.x are not compatible with this driver.
1559dce93cd0SAchim Leubner 	 */
1560dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_PERC2QC) {
1561dce93cd0SAchim Leubner 		if (aacraid_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
1562dce93cd0SAchim Leubner 				     NULL, NULL)) {
1563dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
1564dce93cd0SAchim Leubner 				      "Error reading firmware version\n");
1565dce93cd0SAchim Leubner 			return (EIO);
1566dce93cd0SAchim Leubner 		}
1567dce93cd0SAchim Leubner 
1568dce93cd0SAchim Leubner 		/* These numbers are stored as ASCII! */
1569dce93cd0SAchim Leubner 		major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30;
1570dce93cd0SAchim Leubner 		minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30;
1571dce93cd0SAchim Leubner 		if (major == 1) {
1572dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
1573dce93cd0SAchim Leubner 			    "Firmware version %d.%d is not supported.\n",
1574dce93cd0SAchim Leubner 			    major, minor);
1575dce93cd0SAchim Leubner 			return (EINVAL);
1576dce93cd0SAchim Leubner 		}
1577dce93cd0SAchim Leubner 	}
1578dce93cd0SAchim Leubner 	/*
1579dce93cd0SAchim Leubner 	 * Retrieve the capabilities/supported options word so we know what
1580dce93cd0SAchim Leubner 	 * work-arounds to enable.  Some firmware revs don't support this
1581dce93cd0SAchim Leubner 	 * command.
1582dce93cd0SAchim Leubner 	 */
1583dce93cd0SAchim Leubner 	if (aacraid_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status, NULL)) {
1584dce93cd0SAchim Leubner 		if (status != AAC_SRB_STS_INVALID_REQUEST) {
1585dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
1586dce93cd0SAchim Leubner 			     "RequestAdapterInfo failed\n");
1587dce93cd0SAchim Leubner 			return (EIO);
1588dce93cd0SAchim Leubner 		}
1589dce93cd0SAchim Leubner 	} else {
1590dce93cd0SAchim Leubner 		options = AAC_GET_MAILBOX(sc, 1);
1591dce93cd0SAchim Leubner 		atu_size = AAC_GET_MAILBOX(sc, 2);
1592dce93cd0SAchim Leubner 		sc->supported_options = options;
15934f1dfabaSMaxim Sobolev 		sc->doorbell_mask = AAC_GET_MAILBOX(sc, 3);
1594dce93cd0SAchim Leubner 
1595dce93cd0SAchim Leubner 		if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
1596dce93cd0SAchim Leubner 		    (sc->flags & AAC_FLAGS_NO4GB) == 0)
1597dce93cd0SAchim Leubner 			sc->flags |= AAC_FLAGS_4GB_WINDOW;
1598dce93cd0SAchim Leubner 		if (options & AAC_SUPPORTED_NONDASD)
1599dce93cd0SAchim Leubner 			sc->flags |= AAC_FLAGS_ENABLE_CAM;
1600dce93cd0SAchim Leubner 		if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0
1601dce93cd0SAchim Leubner 			&& (sizeof(bus_addr_t) > 4)
1602dce93cd0SAchim Leubner 			&& (sc->hint_flags & 0x1)) {
1603dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
1604dce93cd0SAchim Leubner 			    "Enabling 64-bit address support\n");
1605dce93cd0SAchim Leubner 			sc->flags |= AAC_FLAGS_SG_64BIT;
1606dce93cd0SAchim Leubner 		}
1607dce93cd0SAchim Leubner 		if (sc->aac_if.aif_send_command) {
16084f1dfabaSMaxim Sobolev 			if (options & AAC_SUPPORTED_NEW_COMM_TYPE2)
16094f1dfabaSMaxim Sobolev 				sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2;
1610dce93cd0SAchim Leubner 			else if (options & AAC_SUPPORTED_NEW_COMM_TYPE1)
1611dce93cd0SAchim Leubner 				sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE1;
16124f1dfabaSMaxim Sobolev 			else if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) ||
16134f1dfabaSMaxim Sobolev 				(options & AAC_SUPPORTED_NEW_COMM_TYPE4))
16144f1dfabaSMaxim Sobolev 				sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34;
1615dce93cd0SAchim Leubner 		}
1616dce93cd0SAchim Leubner 		if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
1617dce93cd0SAchim Leubner 			sc->flags |= AAC_FLAGS_ARRAY_64BIT;
1618dce93cd0SAchim Leubner 	}
1619dce93cd0SAchim Leubner 
1620dce93cd0SAchim Leubner 	if (!(sc->flags & AAC_FLAGS_NEW_COMM)) {
1621dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Communication interface not supported!\n");
1622dce93cd0SAchim Leubner 		return (ENXIO);
1623dce93cd0SAchim Leubner 	}
1624dce93cd0SAchim Leubner 
1625dce93cd0SAchim Leubner 	if (sc->hint_flags & 2) {
1626dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
1627dce93cd0SAchim Leubner 			"Sync. mode enforced by driver parameter. This will cause a significant performance decrease!\n");
1628dce93cd0SAchim Leubner 		sc->flags |= AAC_FLAGS_SYNC_MODE;
1629dce93cd0SAchim Leubner 	} else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE34) {
1630dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
1631dce93cd0SAchim Leubner 			"Async. mode not supported by current driver, sync. mode enforced.\nPlease update driver to get full performance.\n");
1632dce93cd0SAchim Leubner 		sc->flags |= AAC_FLAGS_SYNC_MODE;
1633dce93cd0SAchim Leubner 	}
1634dce93cd0SAchim Leubner 
1635dce93cd0SAchim Leubner 	/* Check for broken hardware that does a lower number of commands */
1636dce93cd0SAchim Leubner 	sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512);
1637dce93cd0SAchim Leubner 
1638dce93cd0SAchim Leubner 	/* Remap mem. resource, if required */
1639dce93cd0SAchim Leubner 	if (atu_size > rman_get_size(sc->aac_regs_res0)) {
1640dce93cd0SAchim Leubner 		bus_release_resource(
1641dce93cd0SAchim Leubner 			sc->aac_dev, SYS_RES_MEMORY,
1642dce93cd0SAchim Leubner 			sc->aac_regs_rid0, sc->aac_regs_res0);
1643c47476d7SJustin Hibbits 		sc->aac_regs_res0 = bus_alloc_resource_anywhere(
1644dce93cd0SAchim Leubner 			sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid0,
1645c47476d7SJustin Hibbits 			atu_size, RF_ACTIVE);
1646dce93cd0SAchim Leubner 		if (sc->aac_regs_res0 == NULL) {
1647dce93cd0SAchim Leubner 			sc->aac_regs_res0 = bus_alloc_resource_any(
1648dce93cd0SAchim Leubner 				sc->aac_dev, SYS_RES_MEMORY,
1649dce93cd0SAchim Leubner 				&sc->aac_regs_rid0, RF_ACTIVE);
1650dce93cd0SAchim Leubner 			if (sc->aac_regs_res0 == NULL) {
1651dce93cd0SAchim Leubner 				device_printf(sc->aac_dev,
1652dce93cd0SAchim Leubner 					"couldn't allocate register window\n");
1653dce93cd0SAchim Leubner 				return (ENXIO);
1654dce93cd0SAchim Leubner 			}
1655dce93cd0SAchim Leubner 		}
1656dce93cd0SAchim Leubner 		sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0);
1657dce93cd0SAchim Leubner 		sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0);
1658dce93cd0SAchim Leubner 	}
1659dce93cd0SAchim Leubner 
1660dce93cd0SAchim Leubner 	/* Read preferred settings */
1661dce93cd0SAchim Leubner 	sc->aac_max_fib_size = sizeof(struct aac_fib);
1662dce93cd0SAchim Leubner 	sc->aac_max_sectors = 128;				/* 64KB */
1663dce93cd0SAchim Leubner 	sc->aac_max_aif = 1;
1664dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_SG_64BIT)
1665dce93cd0SAchim Leubner 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1666dce93cd0SAchim Leubner 		 - sizeof(struct aac_blockwrite64))
1667dce93cd0SAchim Leubner 		 / sizeof(struct aac_sg_entry64);
1668dce93cd0SAchim Leubner 	else
1669dce93cd0SAchim Leubner 		sc->aac_sg_tablesize = (AAC_FIB_DATASIZE
1670dce93cd0SAchim Leubner 		 - sizeof(struct aac_blockwrite))
1671dce93cd0SAchim Leubner 		 / sizeof(struct aac_sg_entry);
1672dce93cd0SAchim Leubner 
1673dce93cd0SAchim Leubner 	if (!aacraid_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL, NULL)) {
1674dce93cd0SAchim Leubner 		options = AAC_GET_MAILBOX(sc, 1);
1675dce93cd0SAchim Leubner 		sc->aac_max_fib_size = (options & 0xFFFF);
1676dce93cd0SAchim Leubner 		sc->aac_max_sectors = (options >> 16) << 1;
1677dce93cd0SAchim Leubner 		options = AAC_GET_MAILBOX(sc, 2);
1678dce93cd0SAchim Leubner 		sc->aac_sg_tablesize = (options >> 16);
1679dce93cd0SAchim Leubner 		options = AAC_GET_MAILBOX(sc, 3);
16803fea9c0dSAchim Leubner 		sc->aac_max_fibs = ((options >> 16) & 0xFFFF);
16813fea9c0dSAchim Leubner 		if (sc->aac_max_fibs == 0 || sc->aac_hwif != AAC_HWIF_SRCV)
1682dce93cd0SAchim Leubner 			sc->aac_max_fibs = (options & 0xFFFF);
1683dce93cd0SAchim Leubner 		options = AAC_GET_MAILBOX(sc, 4);
1684dce93cd0SAchim Leubner 		sc->aac_max_aif = (options & 0xFFFF);
16853fea9c0dSAchim Leubner 		options = AAC_GET_MAILBOX(sc, 5);
16863fea9c0dSAchim Leubner 		sc->aac_max_msix =(sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) ? options : 0;
1687dce93cd0SAchim Leubner 	}
1688dce93cd0SAchim Leubner 
1689dce93cd0SAchim Leubner 	maxsize = sc->aac_max_fib_size + 31;
1690dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1)
1691dce93cd0SAchim Leubner 		maxsize += sizeof(struct aac_fib_xporthdr);
1692dce93cd0SAchim Leubner 	if (maxsize > PAGE_SIZE) {
1693dce93cd0SAchim Leubner     	sc->aac_max_fib_size -= (maxsize - PAGE_SIZE);
1694dce93cd0SAchim Leubner 		maxsize = PAGE_SIZE;
1695dce93cd0SAchim Leubner 	}
1696dce93cd0SAchim Leubner 	sc->aac_max_fibs_alloc = PAGE_SIZE / maxsize;
1697dce93cd0SAchim Leubner 
1698dce93cd0SAchim Leubner 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1699dce93cd0SAchim Leubner 		sc->flags |= AAC_FLAGS_RAW_IO;
1700dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Enable Raw I/O\n");
1701dce93cd0SAchim Leubner 	}
1702dce93cd0SAchim Leubner 	if ((sc->flags & AAC_FLAGS_RAW_IO) &&
1703dce93cd0SAchim Leubner 	    (sc->flags & AAC_FLAGS_ARRAY_64BIT)) {
1704dce93cd0SAchim Leubner 		sc->flags |= AAC_FLAGS_LBA_64BIT;
1705dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Enable 64-bit array\n");
1706dce93cd0SAchim Leubner 	}
1707dce93cd0SAchim Leubner 
1708457b3426SSean Bruno #ifdef AACRAID_DEBUG
1709dce93cd0SAchim Leubner 	aacraid_get_fw_debug_buffer(sc);
1710457b3426SSean Bruno #endif
1711dce93cd0SAchim Leubner 	return (0);
1712dce93cd0SAchim Leubner }
1713dce93cd0SAchim Leubner 
1714dce93cd0SAchim Leubner static int
1715dce93cd0SAchim Leubner aac_init(struct aac_softc *sc)
1716dce93cd0SAchim Leubner {
1717dce93cd0SAchim Leubner 	struct aac_adapter_init	*ip;
17183fea9c0dSAchim Leubner 	int i, error;
1719dce93cd0SAchim Leubner 
1720dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
1721dce93cd0SAchim Leubner 
1722dce93cd0SAchim Leubner 	/* reset rrq index */
17233fea9c0dSAchim Leubner 	sc->aac_fibs_pushed_no = 0;
17243fea9c0dSAchim Leubner 	for (i = 0; i < sc->aac_max_msix; i++)
17253fea9c0dSAchim Leubner 		sc->aac_host_rrq_idx[i] = i * sc->aac_vector_cap;
1726dce93cd0SAchim Leubner 
1727dce93cd0SAchim Leubner 	/*
1728dce93cd0SAchim Leubner 	 * Fill in the init structure.  This tells the adapter about the
1729dce93cd0SAchim Leubner 	 * physical location of various important shared data structures.
1730dce93cd0SAchim Leubner 	 */
1731dce93cd0SAchim Leubner 	ip = &sc->aac_common->ac_init;
1732dce93cd0SAchim Leubner 	ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
1733dce93cd0SAchim Leubner 	if (sc->aac_max_fib_size > sizeof(struct aac_fib)) {
1734dce93cd0SAchim Leubner 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4;
1735dce93cd0SAchim Leubner 		sc->flags |= AAC_FLAGS_RAW_IO;
1736dce93cd0SAchim Leubner 	}
17373fea9c0dSAchim Leubner 	ip->NoOfMSIXVectors = sc->aac_max_msix;
1738dce93cd0SAchim Leubner 
1739dce93cd0SAchim Leubner 	ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
1740dce93cd0SAchim Leubner 					 offsetof(struct aac_common, ac_fibs);
1741dce93cd0SAchim Leubner 	ip->AdapterFibsVirtualAddress = 0;
1742dce93cd0SAchim Leubner 	ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
1743dce93cd0SAchim Leubner 	ip->AdapterFibAlign = sizeof(struct aac_fib);
1744dce93cd0SAchim Leubner 
1745dce93cd0SAchim Leubner 	ip->PrintfBufferAddress = sc->aac_common_busaddr +
1746dce93cd0SAchim Leubner 				  offsetof(struct aac_common, ac_printf);
1747dce93cd0SAchim Leubner 	ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
1748dce93cd0SAchim Leubner 
1749dce93cd0SAchim Leubner 	/*
1750dce93cd0SAchim Leubner 	 * The adapter assumes that pages are 4K in size, except on some
1751dce93cd0SAchim Leubner  	 * broken firmware versions that do the page->byte conversion twice,
1752dce93cd0SAchim Leubner 	 * therefore 'assuming' that this value is in 16MB units (2^24).
1753dce93cd0SAchim Leubner 	 * Round up since the granularity is so high.
1754dce93cd0SAchim Leubner 	 */
1755dce93cd0SAchim Leubner 	ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
1756dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) {
1757dce93cd0SAchim Leubner 		ip->HostPhysMemPages =
1758dce93cd0SAchim Leubner 		    (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE;
1759dce93cd0SAchim Leubner 	}
1760dce93cd0SAchim Leubner 	ip->HostElapsedSeconds = time_uptime;	/* reset later if invalid */
1761dce93cd0SAchim Leubner 
1762dce93cd0SAchim Leubner 	ip->InitFlags = AAC_INITFLAGS_NEW_COMM_SUPPORTED;
1763dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE1) {
1764dce93cd0SAchim Leubner 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_6;
1765dce93cd0SAchim Leubner 		ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE1_SUPPORTED |
1766dce93cd0SAchim Leubner 			AAC_INITFLAGS_FAST_JBOD_SUPPORTED);
1767dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "New comm. interface type1 enabled\n");
1768dce93cd0SAchim Leubner 	} else if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) {
1769dce93cd0SAchim Leubner 		ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_7;
1770dce93cd0SAchim Leubner 		ip->InitFlags |= (AAC_INITFLAGS_NEW_COMM_TYPE2_SUPPORTED |
1771dce93cd0SAchim Leubner 			AAC_INITFLAGS_FAST_JBOD_SUPPORTED);
1772dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "New comm. interface type2 enabled\n");
1773dce93cd0SAchim Leubner 	}
1774dce93cd0SAchim Leubner 	ip->MaxNumAif = sc->aac_max_aif;
1775dce93cd0SAchim Leubner 	ip->HostRRQ_AddrLow =
1776dce93cd0SAchim Leubner 		sc->aac_common_busaddr + offsetof(struct aac_common, ac_host_rrq);
1777dce93cd0SAchim Leubner 	/* always 32-bit address */
1778dce93cd0SAchim Leubner 	ip->HostRRQ_AddrHigh = 0;
1779dce93cd0SAchim Leubner 
1780dce93cd0SAchim Leubner 	if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
1781dce93cd0SAchim Leubner 		ip->InitFlags |= AAC_INITFLAGS_DRIVER_SUPPORTS_PM;
1782dce93cd0SAchim Leubner 		ip->InitFlags |= AAC_INITFLAGS_DRIVER_USES_UTC_TIME;
1783dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Power Management enabled\n");
1784dce93cd0SAchim Leubner 	}
1785dce93cd0SAchim Leubner 
1786dce93cd0SAchim Leubner 	ip->MaxIoCommands = sc->aac_max_fibs;
1787dce93cd0SAchim Leubner 	ip->MaxIoSize = sc->aac_max_sectors << 9;
1788dce93cd0SAchim Leubner 	ip->MaxFibSize = sc->aac_max_fib_size;
1789dce93cd0SAchim Leubner 
1790dce93cd0SAchim Leubner 	/*
1791dce93cd0SAchim Leubner 	 * Do controller-type-specific initialisation
1792dce93cd0SAchim Leubner 	 */
1793dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, ~0);
1794dce93cd0SAchim Leubner 
1795dce93cd0SAchim Leubner 	/*
1796dce93cd0SAchim Leubner 	 * Give the init structure to the controller.
1797dce93cd0SAchim Leubner 	 */
1798dce93cd0SAchim Leubner 	if (aacraid_sync_command(sc, AAC_MONKER_INITSTRUCT,
1799dce93cd0SAchim Leubner 			     sc->aac_common_busaddr +
1800dce93cd0SAchim Leubner 			     offsetof(struct aac_common, ac_init), 0, 0, 0,
1801dce93cd0SAchim Leubner 			     NULL, NULL)) {
1802dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
1803dce93cd0SAchim Leubner 			      "error establishing init structure\n");
1804dce93cd0SAchim Leubner 		error = EIO;
1805dce93cd0SAchim Leubner 		goto out;
1806dce93cd0SAchim Leubner 	}
1807dce93cd0SAchim Leubner 
18083fea9c0dSAchim Leubner 	/*
18093fea9c0dSAchim Leubner 	 * Check configuration issues
18103fea9c0dSAchim Leubner 	 */
18113fea9c0dSAchim Leubner 	if ((error = aac_check_config(sc)) != 0)
18123fea9c0dSAchim Leubner 		goto out;
18133fea9c0dSAchim Leubner 
1814dce93cd0SAchim Leubner 	error = 0;
1815dce93cd0SAchim Leubner out:
1816dce93cd0SAchim Leubner 	return(error);
1817dce93cd0SAchim Leubner }
1818dce93cd0SAchim Leubner 
18193fea9c0dSAchim Leubner static void
18203fea9c0dSAchim Leubner aac_define_int_mode(struct aac_softc *sc)
18213fea9c0dSAchim Leubner {
18223fea9c0dSAchim Leubner 	device_t dev;
18233fea9c0dSAchim Leubner 	int cap, msi_count, error = 0;
18243fea9c0dSAchim Leubner 	uint32_t val;
18253fea9c0dSAchim Leubner 
18263fea9c0dSAchim Leubner 	dev = sc->aac_dev;
18273fea9c0dSAchim Leubner 
18284f1dfabaSMaxim Sobolev 	if (sc->flags & AAC_FLAGS_SYNC_MODE) {
18294f1dfabaSMaxim Sobolev 		device_printf(dev, "using line interrupts\n");
18304f1dfabaSMaxim Sobolev 		sc->aac_max_msix = 1;
18314f1dfabaSMaxim Sobolev 		sc->aac_vector_cap = sc->aac_max_fibs;
18324f1dfabaSMaxim Sobolev 		return;
18334f1dfabaSMaxim Sobolev 	}
18344f1dfabaSMaxim Sobolev 
18353fea9c0dSAchim Leubner 	/* max. vectors from AAC_MONKER_GETCOMMPREF */
18363fea9c0dSAchim Leubner 	if (sc->aac_max_msix == 0) {
18374f1dfabaSMaxim Sobolev 		if (sc->aac_hwif == AAC_HWIF_SRC) {
18384f1dfabaSMaxim Sobolev 			msi_count = 1;
18394f1dfabaSMaxim Sobolev 			if ((error = pci_alloc_msi(dev, &msi_count)) != 0) {
18404f1dfabaSMaxim Sobolev 				device_printf(dev, "alloc msi failed - err=%d; "
18414f1dfabaSMaxim Sobolev 				    "will use INTx\n", error);
18424f1dfabaSMaxim Sobolev 				pci_release_msi(dev);
18434f1dfabaSMaxim Sobolev 			} else {
18444f1dfabaSMaxim Sobolev 				sc->msi_tupelo = TRUE;
18454f1dfabaSMaxim Sobolev 			}
18464f1dfabaSMaxim Sobolev 		}
18474f1dfabaSMaxim Sobolev 		if (sc->msi_tupelo)
18484f1dfabaSMaxim Sobolev 			device_printf(dev, "using MSI interrupts\n");
18494f1dfabaSMaxim Sobolev 		else
18504f1dfabaSMaxim Sobolev 			device_printf(dev, "using line interrupts\n");
18514f1dfabaSMaxim Sobolev 
18523fea9c0dSAchim Leubner 		sc->aac_max_msix = 1;
18533fea9c0dSAchim Leubner 		sc->aac_vector_cap = sc->aac_max_fibs;
18543fea9c0dSAchim Leubner 		return;
18553fea9c0dSAchim Leubner 	}
18563fea9c0dSAchim Leubner 
18573fea9c0dSAchim Leubner 	/* OS capability */
18583fea9c0dSAchim Leubner 	msi_count = pci_msix_count(dev);
18593fea9c0dSAchim Leubner 	if (msi_count > AAC_MAX_MSIX)
18603fea9c0dSAchim Leubner 		msi_count = AAC_MAX_MSIX;
18613fea9c0dSAchim Leubner 	if (msi_count > sc->aac_max_msix)
18623fea9c0dSAchim Leubner 		msi_count = sc->aac_max_msix;
18633fea9c0dSAchim Leubner 	if (msi_count == 0 || (error = pci_alloc_msix(dev, &msi_count)) != 0) {
18643fea9c0dSAchim Leubner 		device_printf(dev, "alloc msix failed - msi_count=%d, err=%d; "
18653fea9c0dSAchim Leubner 				   "will try MSI\n", msi_count, error);
18663fea9c0dSAchim Leubner 		pci_release_msi(dev);
18673fea9c0dSAchim Leubner 	} else {
18683fea9c0dSAchim Leubner 		sc->msi_enabled = TRUE;
18693fea9c0dSAchim Leubner 		device_printf(dev, "using MSI-X interrupts (%u vectors)\n",
18703fea9c0dSAchim Leubner 			msi_count);
18713fea9c0dSAchim Leubner 	}
18723fea9c0dSAchim Leubner 
18733fea9c0dSAchim Leubner 	if (!sc->msi_enabled) {
18743fea9c0dSAchim Leubner 		msi_count = 1;
18753fea9c0dSAchim Leubner 		if ((error = pci_alloc_msi(dev, &msi_count)) != 0) {
18763fea9c0dSAchim Leubner 			device_printf(dev, "alloc msi failed - err=%d; "
18773fea9c0dSAchim Leubner 				           "will use INTx\n", error);
18783fea9c0dSAchim Leubner 			pci_release_msi(dev);
18793fea9c0dSAchim Leubner 		} else {
18803fea9c0dSAchim Leubner 			sc->msi_enabled = TRUE;
18813fea9c0dSAchim Leubner 			device_printf(dev, "using MSI interrupts\n");
18823fea9c0dSAchim Leubner 		}
18833fea9c0dSAchim Leubner 	}
18843fea9c0dSAchim Leubner 
18853fea9c0dSAchim Leubner 	if (sc->msi_enabled) {
18863fea9c0dSAchim Leubner 		/* now read controller capability from PCI config. space */
18873fea9c0dSAchim Leubner 		cap = aac_find_pci_capability(sc, PCIY_MSIX);
18883fea9c0dSAchim Leubner 		val = (cap != 0 ? pci_read_config(dev, cap + 2, 2) : 0);
18893fea9c0dSAchim Leubner 		if (!(val & AAC_PCI_MSI_ENABLE)) {
18903fea9c0dSAchim Leubner 			pci_release_msi(dev);
18913fea9c0dSAchim Leubner 			sc->msi_enabled = FALSE;
18923fea9c0dSAchim Leubner 		}
18933fea9c0dSAchim Leubner 	}
18943fea9c0dSAchim Leubner 
18953fea9c0dSAchim Leubner 	if (!sc->msi_enabled) {
18963fea9c0dSAchim Leubner 		device_printf(dev, "using legacy interrupts\n");
18973fea9c0dSAchim Leubner 		sc->aac_max_msix = 1;
18983fea9c0dSAchim Leubner 	} else {
18993fea9c0dSAchim Leubner 		AAC_ACCESS_DEVREG(sc, AAC_ENABLE_MSIX);
19003fea9c0dSAchim Leubner 		if (sc->aac_max_msix > msi_count)
19013fea9c0dSAchim Leubner 			sc->aac_max_msix = msi_count;
19023fea9c0dSAchim Leubner 	}
19033fea9c0dSAchim Leubner 	sc->aac_vector_cap = sc->aac_max_fibs / sc->aac_max_msix;
19043fea9c0dSAchim Leubner 
19053fea9c0dSAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_DEBUG_B, "msi_enabled %d vector_cap %d max_fibs %d max_msix %d",
19063fea9c0dSAchim Leubner 		sc->msi_enabled,sc->aac_vector_cap, sc->aac_max_fibs, sc->aac_max_msix);
19073fea9c0dSAchim Leubner }
19083fea9c0dSAchim Leubner 
19093fea9c0dSAchim Leubner static int
19103fea9c0dSAchim Leubner aac_find_pci_capability(struct aac_softc *sc, int cap)
19113fea9c0dSAchim Leubner {
19123fea9c0dSAchim Leubner 	device_t dev;
19133fea9c0dSAchim Leubner 	uint32_t status;
19143fea9c0dSAchim Leubner 	uint8_t ptr;
19153fea9c0dSAchim Leubner 
19163fea9c0dSAchim Leubner 	dev = sc->aac_dev;
19173fea9c0dSAchim Leubner 
19183fea9c0dSAchim Leubner 	status = pci_read_config(dev, PCIR_STATUS, 2);
19193fea9c0dSAchim Leubner 	if (!(status & PCIM_STATUS_CAPPRESENT))
19203fea9c0dSAchim Leubner 		return (0);
19213fea9c0dSAchim Leubner 
19223fea9c0dSAchim Leubner 	status = pci_read_config(dev, PCIR_HDRTYPE, 1);
19233fea9c0dSAchim Leubner 	switch (status & PCIM_HDRTYPE) {
19243fea9c0dSAchim Leubner 	case 0:
19253fea9c0dSAchim Leubner 	case 1:
19263fea9c0dSAchim Leubner 		ptr = PCIR_CAP_PTR;
19273fea9c0dSAchim Leubner 		break;
19283fea9c0dSAchim Leubner 	case 2:
19293fea9c0dSAchim Leubner 		ptr = PCIR_CAP_PTR_2;
19303fea9c0dSAchim Leubner 		break;
19313fea9c0dSAchim Leubner 	default:
19323fea9c0dSAchim Leubner 		return (0);
19333fea9c0dSAchim Leubner 		break;
19343fea9c0dSAchim Leubner 	}
19353fea9c0dSAchim Leubner 	ptr = pci_read_config(dev, ptr, 1);
19363fea9c0dSAchim Leubner 
19373fea9c0dSAchim Leubner 	while (ptr != 0) {
19383fea9c0dSAchim Leubner 		int next, val;
19393fea9c0dSAchim Leubner 		next = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
19403fea9c0dSAchim Leubner 		val = pci_read_config(dev, ptr + PCICAP_ID, 1);
19413fea9c0dSAchim Leubner 		if (val == cap)
19423fea9c0dSAchim Leubner 			return (ptr);
19433fea9c0dSAchim Leubner 		ptr = next;
19443fea9c0dSAchim Leubner 	}
19453fea9c0dSAchim Leubner 
19463fea9c0dSAchim Leubner 	return (0);
19473fea9c0dSAchim Leubner }
19483fea9c0dSAchim Leubner 
1949dce93cd0SAchim Leubner static int
1950dce93cd0SAchim Leubner aac_setup_intr(struct aac_softc *sc)
1951dce93cd0SAchim Leubner {
19523fea9c0dSAchim Leubner 	int i, msi_count, rid;
19533fea9c0dSAchim Leubner 	struct resource *res;
19543fea9c0dSAchim Leubner 	void *tag;
19553fea9c0dSAchim Leubner 
19563fea9c0dSAchim Leubner 	msi_count = sc->aac_max_msix;
19574f1dfabaSMaxim Sobolev 	rid = ((sc->msi_enabled || sc->msi_tupelo)? 1:0);
19583fea9c0dSAchim Leubner 
19593fea9c0dSAchim Leubner 	for (i = 0; i < msi_count; i++, rid++) {
19603fea9c0dSAchim Leubner 		if ((res = bus_alloc_resource_any(sc->aac_dev,SYS_RES_IRQ, &rid,
19613fea9c0dSAchim Leubner 			RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1962dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,"can't allocate interrupt\n");
1963dce93cd0SAchim Leubner 			return (EINVAL);
1964dce93cd0SAchim Leubner 		}
19653fea9c0dSAchim Leubner 		sc->aac_irq_rid[i] = rid;
19663fea9c0dSAchim Leubner 		sc->aac_irq[i] = res;
19673fea9c0dSAchim Leubner 		if (aac_bus_setup_intr(sc->aac_dev, res,
1968dce93cd0SAchim Leubner 			INTR_MPSAFE | INTR_TYPE_BIO, NULL,
19693fea9c0dSAchim Leubner 			aacraid_new_intr_type1, &sc->aac_msix[i], &tag)) {
1970dce93cd0SAchim Leubner 			device_printf(sc->aac_dev, "can't set up interrupt\n");
1971dce93cd0SAchim Leubner 			return (EINVAL);
1972dce93cd0SAchim Leubner 		}
19733fea9c0dSAchim Leubner 		sc->aac_msix[i].vector_no = i;
19743fea9c0dSAchim Leubner 		sc->aac_msix[i].sc = sc;
19753fea9c0dSAchim Leubner 		sc->aac_intr[i] = tag;
19763fea9c0dSAchim Leubner 	}
19773fea9c0dSAchim Leubner 
1978dce93cd0SAchim Leubner 	return (0);
1979dce93cd0SAchim Leubner }
1980dce93cd0SAchim Leubner 
19813fea9c0dSAchim Leubner static int
19823fea9c0dSAchim Leubner aac_check_config(struct aac_softc *sc)
19833fea9c0dSAchim Leubner {
19843fea9c0dSAchim Leubner 	struct aac_fib *fib;
19853fea9c0dSAchim Leubner 	struct aac_cnt_config *ccfg;
19863fea9c0dSAchim Leubner 	struct aac_cf_status_hdr *cf_shdr;
19873fea9c0dSAchim Leubner 	int rval;
19883fea9c0dSAchim Leubner 
19893fea9c0dSAchim Leubner 	mtx_lock(&sc->aac_io_lock);
19903fea9c0dSAchim Leubner 	aac_alloc_sync_fib(sc, &fib);
19913fea9c0dSAchim Leubner 
19923fea9c0dSAchim Leubner 	ccfg = (struct aac_cnt_config *)&fib->data[0];
19933fea9c0dSAchim Leubner 	bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE);
19943fea9c0dSAchim Leubner 	ccfg->Command = VM_ContainerConfig;
19953fea9c0dSAchim Leubner 	ccfg->CTCommand.command = CT_GET_CONFIG_STATUS;
19963fea9c0dSAchim Leubner 	ccfg->CTCommand.param[CNT_SIZE] = sizeof(struct aac_cf_status_hdr);
19973fea9c0dSAchim Leubner 
19983fea9c0dSAchim Leubner 	rval = aac_sync_fib(sc, ContainerCommand, 0, fib,
19993fea9c0dSAchim Leubner 		sizeof (struct aac_cnt_config));
20003fea9c0dSAchim Leubner 	cf_shdr = (struct aac_cf_status_hdr *)ccfg->CTCommand.data;
20013fea9c0dSAchim Leubner 	if (rval == 0 && ccfg->Command == ST_OK &&
20023fea9c0dSAchim Leubner 		ccfg->CTCommand.param[0] == CT_OK) {
20033fea9c0dSAchim Leubner 		if (cf_shdr->action <= CFACT_PAUSE) {
20043fea9c0dSAchim Leubner 			bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE);
20053fea9c0dSAchim Leubner 			ccfg->Command = VM_ContainerConfig;
20063fea9c0dSAchim Leubner 			ccfg->CTCommand.command = CT_COMMIT_CONFIG;
20073fea9c0dSAchim Leubner 
20083fea9c0dSAchim Leubner 			rval = aac_sync_fib(sc, ContainerCommand, 0, fib,
20093fea9c0dSAchim Leubner 				sizeof (struct aac_cnt_config));
20103fea9c0dSAchim Leubner 			if (rval == 0 && ccfg->Command == ST_OK &&
20113fea9c0dSAchim Leubner 				ccfg->CTCommand.param[0] == CT_OK) {
20123fea9c0dSAchim Leubner 				/* successful completion */
20133fea9c0dSAchim Leubner 				rval = 0;
20143fea9c0dSAchim Leubner 			} else {
20153fea9c0dSAchim Leubner 				/* auto commit aborted due to error(s) */
20163fea9c0dSAchim Leubner 				rval = -2;
20173fea9c0dSAchim Leubner 			}
20183fea9c0dSAchim Leubner 		} else {
20193fea9c0dSAchim Leubner 			/* auto commit aborted due to adapter indicating
20203fea9c0dSAchim Leubner 			   config. issues too dangerous to auto commit  */
20213fea9c0dSAchim Leubner 			rval = -3;
20223fea9c0dSAchim Leubner 		}
20233fea9c0dSAchim Leubner 	} else {
20243fea9c0dSAchim Leubner 		/* error */
20253fea9c0dSAchim Leubner 		rval = -1;
20263fea9c0dSAchim Leubner 	}
20273fea9c0dSAchim Leubner 
20283fea9c0dSAchim Leubner 	aac_release_sync_fib(sc);
20293fea9c0dSAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
20303fea9c0dSAchim Leubner 	return(rval);
20313fea9c0dSAchim Leubner }
20323fea9c0dSAchim Leubner 
2033dce93cd0SAchim Leubner /*
2034dce93cd0SAchim Leubner  * Send a synchronous command to the controller and wait for a result.
2035dce93cd0SAchim Leubner  * Indicate if the controller completed the command with an error status.
2036dce93cd0SAchim Leubner  */
2037dce93cd0SAchim Leubner int
2038dce93cd0SAchim Leubner aacraid_sync_command(struct aac_softc *sc, u_int32_t command,
2039dce93cd0SAchim Leubner 		 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3,
2040dce93cd0SAchim Leubner 		 u_int32_t *sp, u_int32_t *r1)
2041dce93cd0SAchim Leubner {
2042dce93cd0SAchim Leubner 	time_t then;
2043dce93cd0SAchim Leubner 	u_int32_t status;
2044dce93cd0SAchim Leubner 
2045dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2046dce93cd0SAchim Leubner 
2047dce93cd0SAchim Leubner 	/* populate the mailbox */
2048dce93cd0SAchim Leubner 	AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
2049dce93cd0SAchim Leubner 
2050dce93cd0SAchim Leubner 	/* ensure the sync command doorbell flag is cleared */
20513fea9c0dSAchim Leubner 	if (!sc->msi_enabled)
2052dce93cd0SAchim Leubner 		AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
2053dce93cd0SAchim Leubner 
2054dce93cd0SAchim Leubner 	/* then set it to signal the adapter */
2055dce93cd0SAchim Leubner 	AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
2056dce93cd0SAchim Leubner 
2057dce93cd0SAchim Leubner 	if ((command != AAC_MONKER_SYNCFIB) || (sp == NULL) || (*sp != 0)) {
2058dce93cd0SAchim Leubner 		/* spin waiting for the command to complete */
2059dce93cd0SAchim Leubner 		then = time_uptime;
2060dce93cd0SAchim Leubner 		do {
20613fea9c0dSAchim Leubner 			if (time_uptime > (then + AAC_SYNC_TIMEOUT)) {
2062dce93cd0SAchim Leubner 				fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out");
2063dce93cd0SAchim Leubner 				return(EIO);
2064dce93cd0SAchim Leubner 			}
2065dce93cd0SAchim Leubner 		} while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND));
2066dce93cd0SAchim Leubner 
2067dce93cd0SAchim Leubner 		/* clear the completion flag */
2068dce93cd0SAchim Leubner 		AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
2069dce93cd0SAchim Leubner 
2070dce93cd0SAchim Leubner 		/* get the command status */
2071dce93cd0SAchim Leubner 		status = AAC_GET_MAILBOX(sc, 0);
2072dce93cd0SAchim Leubner 		if (sp != NULL)
2073dce93cd0SAchim Leubner 			*sp = status;
2074dce93cd0SAchim Leubner 
2075dce93cd0SAchim Leubner 		/* return parameter */
2076dce93cd0SAchim Leubner 		if (r1 != NULL)
2077dce93cd0SAchim Leubner 			*r1 = AAC_GET_MAILBOX(sc, 1);
2078dce93cd0SAchim Leubner 
2079dce93cd0SAchim Leubner 		if (status != AAC_SRB_STS_SUCCESS)
2080dce93cd0SAchim Leubner 			return (-1);
2081dce93cd0SAchim Leubner 	}
2082dce93cd0SAchim Leubner 	return(0);
2083dce93cd0SAchim Leubner }
2084dce93cd0SAchim Leubner 
2085dce93cd0SAchim Leubner static int
2086dce93cd0SAchim Leubner aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
2087dce93cd0SAchim Leubner 		 struct aac_fib *fib, u_int16_t datasize)
2088dce93cd0SAchim Leubner {
2089dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2090dce93cd0SAchim Leubner 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
2091dce93cd0SAchim Leubner 
2092dce93cd0SAchim Leubner 	if (datasize > AAC_FIB_DATASIZE)
2093dce93cd0SAchim Leubner 		return(EINVAL);
2094dce93cd0SAchim Leubner 
2095dce93cd0SAchim Leubner 	/*
2096dce93cd0SAchim Leubner 	 * Set up the sync FIB
2097dce93cd0SAchim Leubner 	 */
2098dce93cd0SAchim Leubner 	fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED |
2099dce93cd0SAchim Leubner 				AAC_FIBSTATE_INITIALISED |
2100dce93cd0SAchim Leubner 				AAC_FIBSTATE_EMPTY;
2101dce93cd0SAchim Leubner 	fib->Header.XferState |= xferstate;
2102dce93cd0SAchim Leubner 	fib->Header.Command = command;
2103dce93cd0SAchim Leubner 	fib->Header.StructType = AAC_FIBTYPE_TFIB;
2104dce93cd0SAchim Leubner 	fib->Header.Size = sizeof(struct aac_fib_header) + datasize;
2105dce93cd0SAchim Leubner 	fib->Header.SenderSize = sizeof(struct aac_fib);
2106dce93cd0SAchim Leubner 	fib->Header.SenderFibAddress = 0;	/* Not needed */
2107dce93cd0SAchim Leubner 	fib->Header.u.ReceiverFibAddress = sc->aac_common_busaddr +
21083fea9c0dSAchim Leubner 		offsetof(struct aac_common, ac_sync_fib);
2109dce93cd0SAchim Leubner 
2110dce93cd0SAchim Leubner 	/*
2111dce93cd0SAchim Leubner 	 * Give the FIB to the controller, wait for a response.
2112dce93cd0SAchim Leubner 	 */
2113dce93cd0SAchim Leubner 	if (aacraid_sync_command(sc, AAC_MONKER_SYNCFIB,
2114dce93cd0SAchim Leubner 		fib->Header.u.ReceiverFibAddress, 0, 0, 0, NULL, NULL)) {
2115dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error");
2116dce93cd0SAchim Leubner 		return(EIO);
2117dce93cd0SAchim Leubner 	}
2118dce93cd0SAchim Leubner 
2119dce93cd0SAchim Leubner 	return (0);
2120dce93cd0SAchim Leubner }
2121dce93cd0SAchim Leubner 
2122dce93cd0SAchim Leubner /*
2123dce93cd0SAchim Leubner  * Check for commands that have been outstanding for a suspiciously long time,
2124dce93cd0SAchim Leubner  * and complain about them.
2125dce93cd0SAchim Leubner  */
2126dce93cd0SAchim Leubner static void
2127dce93cd0SAchim Leubner aac_timeout(struct aac_softc *sc)
2128dce93cd0SAchim Leubner {
2129dce93cd0SAchim Leubner 	struct aac_command *cm;
2130dce93cd0SAchim Leubner 	time_t deadline;
21313fea9c0dSAchim Leubner 	int timedout;
2132dce93cd0SAchim Leubner 
2133dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2134dce93cd0SAchim Leubner 	/*
2135dce93cd0SAchim Leubner 	 * Traverse the busy command list, bitch about late commands once
2136dce93cd0SAchim Leubner 	 * only.
2137dce93cd0SAchim Leubner 	 */
2138dce93cd0SAchim Leubner 	timedout = 0;
2139dce93cd0SAchim Leubner 	deadline = time_uptime - AAC_CMD_TIMEOUT;
2140dce93cd0SAchim Leubner 	TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) {
21413fea9c0dSAchim Leubner 		if (cm->cm_timestamp < deadline) {
2142dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
2143dce93cd0SAchim Leubner 				      "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
2144dce93cd0SAchim Leubner 				      cm, (int)(time_uptime-cm->cm_timestamp));
2145dce93cd0SAchim Leubner 			AAC_PRINT_FIB(sc, cm->cm_fib);
2146dce93cd0SAchim Leubner 			timedout++;
2147dce93cd0SAchim Leubner 		}
2148dce93cd0SAchim Leubner 	}
2149dce93cd0SAchim Leubner 
21503fea9c0dSAchim Leubner 	if (timedout)
2151dce93cd0SAchim Leubner 		aac_reset_adapter(sc);
2152dce93cd0SAchim Leubner 	aacraid_print_queues(sc);
2153dce93cd0SAchim Leubner }
2154dce93cd0SAchim Leubner 
2155dce93cd0SAchim Leubner /*
2156dce93cd0SAchim Leubner  * Interface Function Vectors
2157dce93cd0SAchim Leubner  */
2158dce93cd0SAchim Leubner 
2159dce93cd0SAchim Leubner /*
2160dce93cd0SAchim Leubner  * Read the current firmware status word.
2161dce93cd0SAchim Leubner  */
2162dce93cd0SAchim Leubner static int
2163dce93cd0SAchim Leubner aac_src_get_fwstatus(struct aac_softc *sc)
2164dce93cd0SAchim Leubner {
2165dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2166dce93cd0SAchim Leubner 
2167dce93cd0SAchim Leubner 	return(AAC_MEM0_GETREG4(sc, AAC_SRC_OMR));
2168dce93cd0SAchim Leubner }
2169dce93cd0SAchim Leubner 
2170dce93cd0SAchim Leubner /*
2171dce93cd0SAchim Leubner  * Notify the controller of a change in a given queue
2172dce93cd0SAchim Leubner  */
2173dce93cd0SAchim Leubner static void
2174dce93cd0SAchim Leubner aac_src_qnotify(struct aac_softc *sc, int qbit)
2175dce93cd0SAchim Leubner {
2176dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2177dce93cd0SAchim Leubner 
2178dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, qbit << AAC_SRC_IDR_SHIFT);
2179dce93cd0SAchim Leubner }
2180dce93cd0SAchim Leubner 
2181dce93cd0SAchim Leubner /*
2182dce93cd0SAchim Leubner  * Get the interrupt reason bits
2183dce93cd0SAchim Leubner  */
2184dce93cd0SAchim Leubner static int
2185dce93cd0SAchim Leubner aac_src_get_istatus(struct aac_softc *sc)
2186dce93cd0SAchim Leubner {
21873fea9c0dSAchim Leubner 	int val;
21883fea9c0dSAchim Leubner 
2189dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2190dce93cd0SAchim Leubner 
21913fea9c0dSAchim Leubner 	if (sc->msi_enabled) {
21923fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_MSI);
21933fea9c0dSAchim Leubner 		if (val & AAC_MSI_SYNC_STATUS)
21943fea9c0dSAchim Leubner 			val = AAC_DB_SYNC_COMMAND;
21953fea9c0dSAchim Leubner 		else
21963fea9c0dSAchim Leubner 			val = 0;
21973fea9c0dSAchim Leubner 	} else {
21983fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_ODBR_R) >> AAC_SRC_ODR_SHIFT;
21993fea9c0dSAchim Leubner 	}
22003fea9c0dSAchim Leubner 	return(val);
2201dce93cd0SAchim Leubner }
2202dce93cd0SAchim Leubner 
2203dce93cd0SAchim Leubner /*
2204dce93cd0SAchim Leubner  * Clear some interrupt reason bits
2205dce93cd0SAchim Leubner  */
2206dce93cd0SAchim Leubner static void
2207dce93cd0SAchim Leubner aac_src_clear_istatus(struct aac_softc *sc, int mask)
2208dce93cd0SAchim Leubner {
2209dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2210dce93cd0SAchim Leubner 
22113fea9c0dSAchim Leubner 	if (sc->msi_enabled) {
22123fea9c0dSAchim Leubner 		if (mask == AAC_DB_SYNC_COMMAND)
22133fea9c0dSAchim Leubner 			AAC_ACCESS_DEVREG(sc, AAC_CLEAR_SYNC_BIT);
22143fea9c0dSAchim Leubner 	} else {
2215dce93cd0SAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_ODBR_C, mask << AAC_SRC_ODR_SHIFT);
2216dce93cd0SAchim Leubner 	}
22173fea9c0dSAchim Leubner }
2218dce93cd0SAchim Leubner 
2219dce93cd0SAchim Leubner /*
2220dce93cd0SAchim Leubner  * Populate the mailbox and set the command word
2221dce93cd0SAchim Leubner  */
2222dce93cd0SAchim Leubner static void
2223dce93cd0SAchim Leubner aac_src_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2224dce93cd0SAchim Leubner 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2225dce93cd0SAchim Leubner {
2226dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2227dce93cd0SAchim Leubner 
2228dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX, command);
2229dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 4, arg0);
2230dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 8, arg1);
2231dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 12, arg2);
2232dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRC_MAILBOX + 16, arg3);
2233dce93cd0SAchim Leubner }
2234dce93cd0SAchim Leubner 
2235dce93cd0SAchim Leubner static void
2236dce93cd0SAchim Leubner aac_srcv_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
2237dce93cd0SAchim Leubner 		    u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
2238dce93cd0SAchim Leubner {
2239dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2240dce93cd0SAchim Leubner 
2241dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX, command);
2242dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 4, arg0);
2243dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 8, arg1);
2244dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 12, arg2);
2245dce93cd0SAchim Leubner 	AAC_MEM0_SETREG4(sc, AAC_SRCV_MAILBOX + 16, arg3);
2246dce93cd0SAchim Leubner }
2247dce93cd0SAchim Leubner 
2248dce93cd0SAchim Leubner /*
2249dce93cd0SAchim Leubner  * Fetch the immediate command status word
2250dce93cd0SAchim Leubner  */
2251dce93cd0SAchim Leubner static int
2252dce93cd0SAchim Leubner aac_src_get_mailbox(struct aac_softc *sc, int mb)
2253dce93cd0SAchim Leubner {
2254dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2255dce93cd0SAchim Leubner 
2256dce93cd0SAchim Leubner 	return(AAC_MEM0_GETREG4(sc, AAC_SRC_MAILBOX + (mb * 4)));
2257dce93cd0SAchim Leubner }
2258dce93cd0SAchim Leubner 
2259dce93cd0SAchim Leubner static int
2260dce93cd0SAchim Leubner aac_srcv_get_mailbox(struct aac_softc *sc, int mb)
2261dce93cd0SAchim Leubner {
2262dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2263dce93cd0SAchim Leubner 
2264dce93cd0SAchim Leubner 	return(AAC_MEM0_GETREG4(sc, AAC_SRCV_MAILBOX + (mb * 4)));
2265dce93cd0SAchim Leubner }
2266dce93cd0SAchim Leubner 
2267dce93cd0SAchim Leubner /*
2268dce93cd0SAchim Leubner  * Set/clear interrupt masks
2269dce93cd0SAchim Leubner  */
2270dce93cd0SAchim Leubner static void
22713fea9c0dSAchim Leubner aac_src_access_devreg(struct aac_softc *sc, int mode)
2272dce93cd0SAchim Leubner {
22733fea9c0dSAchim Leubner 	u_int32_t val;
2274dce93cd0SAchim Leubner 
22753fea9c0dSAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
22763fea9c0dSAchim Leubner 
22773fea9c0dSAchim Leubner 	switch (mode) {
22783fea9c0dSAchim Leubner 	case AAC_ENABLE_INTERRUPT:
22793fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR,
22803fea9c0dSAchim Leubner 			(sc->msi_enabled ? AAC_INT_ENABLE_TYPE1_MSIX :
22813fea9c0dSAchim Leubner 				           AAC_INT_ENABLE_TYPE1_INTX));
22823fea9c0dSAchim Leubner 		break;
22833fea9c0dSAchim Leubner 
22843fea9c0dSAchim Leubner 	case AAC_DISABLE_INTERRUPT:
22853fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR, AAC_INT_DISABLE_ALL);
22863fea9c0dSAchim Leubner 		break;
22873fea9c0dSAchim Leubner 
22883fea9c0dSAchim Leubner 	case AAC_ENABLE_MSIX:
22893fea9c0dSAchim Leubner 		/* set bit 6 */
22903fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
22913fea9c0dSAchim Leubner 		val |= 0x40;
22923fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val);
22933fea9c0dSAchim Leubner 		AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
22943fea9c0dSAchim Leubner 		/* unmask int. */
22953fea9c0dSAchim Leubner 		val = PMC_ALL_INTERRUPT_BITS;
22963fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IOAR, val);
22973fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_OIMR);
22983fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR,
22993fea9c0dSAchim Leubner 			val & (~(PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0)));
23003fea9c0dSAchim Leubner 		break;
23013fea9c0dSAchim Leubner 
23023fea9c0dSAchim Leubner 	case AAC_DISABLE_MSIX:
23033fea9c0dSAchim Leubner 		/* reset bit 6 */
23043fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23053fea9c0dSAchim Leubner 		val &= ~0x40;
23063fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val);
23073fea9c0dSAchim Leubner 		AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23083fea9c0dSAchim Leubner 		break;
23093fea9c0dSAchim Leubner 
23103fea9c0dSAchim Leubner 	case AAC_CLEAR_AIF_BIT:
23113fea9c0dSAchim Leubner 		/* set bit 5 */
23123fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23133fea9c0dSAchim Leubner 		val |= 0x20;
23143fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val);
23153fea9c0dSAchim Leubner 		AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23163fea9c0dSAchim Leubner 		break;
23173fea9c0dSAchim Leubner 
23183fea9c0dSAchim Leubner 	case AAC_CLEAR_SYNC_BIT:
23193fea9c0dSAchim Leubner 		/* set bit 4 */
23203fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23213fea9c0dSAchim Leubner 		val |= 0x10;
23223fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val);
23233fea9c0dSAchim Leubner 		AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23243fea9c0dSAchim Leubner 		break;
23253fea9c0dSAchim Leubner 
23263fea9c0dSAchim Leubner 	case AAC_ENABLE_INTX:
23273fea9c0dSAchim Leubner 		/* set bit 7 */
23283fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23293fea9c0dSAchim Leubner 		val |= 0x80;
23303fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, val);
23313fea9c0dSAchim Leubner 		AAC_MEM0_GETREG4(sc, AAC_SRC_IDBR);
23323fea9c0dSAchim Leubner 		/* unmask int. */
23333fea9c0dSAchim Leubner 		val = PMC_ALL_INTERRUPT_BITS;
23343fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IOAR, val);
23353fea9c0dSAchim Leubner 		val = AAC_MEM0_GETREG4(sc, AAC_SRC_OIMR);
23363fea9c0dSAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_OIMR,
23373fea9c0dSAchim Leubner 			val & (~(PMC_GLOBAL_INT_BIT2)));
23383fea9c0dSAchim Leubner 		break;
23393fea9c0dSAchim Leubner 
23403fea9c0dSAchim Leubner 	default:
23413fea9c0dSAchim Leubner 		break;
2342dce93cd0SAchim Leubner 	}
2343dce93cd0SAchim Leubner }
2344dce93cd0SAchim Leubner 
2345dce93cd0SAchim Leubner /*
2346dce93cd0SAchim Leubner  * New comm. interface: Send command functions
2347dce93cd0SAchim Leubner  */
2348dce93cd0SAchim Leubner static int
2349dce93cd0SAchim Leubner aac_src_send_command(struct aac_softc *sc, struct aac_command *cm)
2350dce93cd0SAchim Leubner {
2351dce93cd0SAchim Leubner 	struct aac_fib_xporthdr *pFibX;
2352dce93cd0SAchim Leubner 	u_int32_t fibsize, high_addr;
2353dce93cd0SAchim Leubner 	u_int64_t address;
2354dce93cd0SAchim Leubner 
2355dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm. type1)");
2356dce93cd0SAchim Leubner 
23573fea9c0dSAchim Leubner 	if (sc->msi_enabled && cm->cm_fib->Header.Command != AifRequest &&
23583fea9c0dSAchim Leubner 		sc->aac_max_msix > 1) {
23593fea9c0dSAchim Leubner 		u_int16_t vector_no, first_choice = 0xffff;
23603fea9c0dSAchim Leubner 
23613fea9c0dSAchim Leubner 		vector_no = sc->aac_fibs_pushed_no % sc->aac_max_msix;
23623fea9c0dSAchim Leubner 		do {
23633fea9c0dSAchim Leubner 			vector_no += 1;
23643fea9c0dSAchim Leubner 			if (vector_no == sc->aac_max_msix)
23653fea9c0dSAchim Leubner 				vector_no = 1;
23663fea9c0dSAchim Leubner 			if (sc->aac_rrq_outstanding[vector_no] <
23673fea9c0dSAchim Leubner 				sc->aac_vector_cap)
23683fea9c0dSAchim Leubner 				break;
23693fea9c0dSAchim Leubner 			if (0xffff == first_choice)
23703fea9c0dSAchim Leubner 				first_choice = vector_no;
23713fea9c0dSAchim Leubner 			else if (vector_no == first_choice)
23723fea9c0dSAchim Leubner 				break;
23733fea9c0dSAchim Leubner 		} while (1);
23743fea9c0dSAchim Leubner 		if (vector_no == first_choice)
23753fea9c0dSAchim Leubner 			vector_no = 0;
23763fea9c0dSAchim Leubner 		sc->aac_rrq_outstanding[vector_no]++;
23773fea9c0dSAchim Leubner 		if (sc->aac_fibs_pushed_no == 0xffffffff)
23783fea9c0dSAchim Leubner 			sc->aac_fibs_pushed_no = 0;
23793fea9c0dSAchim Leubner 		else
23803fea9c0dSAchim Leubner 			sc->aac_fibs_pushed_no++;
23813fea9c0dSAchim Leubner 
23823fea9c0dSAchim Leubner 		cm->cm_fib->Header.Handle += (vector_no << 16);
23833fea9c0dSAchim Leubner 	}
23843fea9c0dSAchim Leubner 
2385dce93cd0SAchim Leubner 	if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) {
2386dce93cd0SAchim Leubner 		/* Calculate the amount to the fibsize bits */
2387dce93cd0SAchim Leubner 		fibsize = (cm->cm_fib->Header.Size + 127) / 128 - 1;
2388dce93cd0SAchim Leubner 		/* Fill new FIB header */
2389dce93cd0SAchim Leubner 		address = cm->cm_fibphys;
2390dce93cd0SAchim Leubner 		high_addr = (u_int32_t)(address >> 32);
2391dce93cd0SAchim Leubner 		if (high_addr == 0L) {
2392dce93cd0SAchim Leubner 			cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2;
2393dce93cd0SAchim Leubner 			cm->cm_fib->Header.u.TimeStamp = 0L;
2394dce93cd0SAchim Leubner 		} else {
2395dce93cd0SAchim Leubner 			cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB2_64;
2396dce93cd0SAchim Leubner 			cm->cm_fib->Header.u.SenderFibAddressHigh = high_addr;
2397dce93cd0SAchim Leubner 		}
2398dce93cd0SAchim Leubner 		cm->cm_fib->Header.SenderFibAddress = (u_int32_t)address;
2399dce93cd0SAchim Leubner 	} else {
2400dce93cd0SAchim Leubner 		/* Calculate the amount to the fibsize bits */
2401dce93cd0SAchim Leubner 		fibsize = (sizeof(struct aac_fib_xporthdr) +
2402dce93cd0SAchim Leubner 		   cm->cm_fib->Header.Size + 127) / 128 - 1;
2403dce93cd0SAchim Leubner 		/* Fill XPORT header */
2404dce93cd0SAchim Leubner 		pFibX = (struct aac_fib_xporthdr *)
2405dce93cd0SAchim Leubner 			((unsigned char *)cm->cm_fib - sizeof(struct aac_fib_xporthdr));
2406dce93cd0SAchim Leubner 		pFibX->Handle = cm->cm_fib->Header.Handle;
2407dce93cd0SAchim Leubner 		pFibX->HostAddress = cm->cm_fibphys;
2408dce93cd0SAchim Leubner 		pFibX->Size = cm->cm_fib->Header.Size;
2409dce93cd0SAchim Leubner 		address = cm->cm_fibphys - sizeof(struct aac_fib_xporthdr);
2410dce93cd0SAchim Leubner 		high_addr = (u_int32_t)(address >> 32);
2411dce93cd0SAchim Leubner 	}
2412dce93cd0SAchim Leubner 
2413dce93cd0SAchim Leubner 	if (fibsize > 31)
2414dce93cd0SAchim Leubner 		fibsize = 31;
2415dce93cd0SAchim Leubner 	aac_enqueue_busy(cm);
2416dce93cd0SAchim Leubner 	if (high_addr) {
2417dce93cd0SAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_H, high_addr);
2418dce93cd0SAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE64_L, (u_int32_t)address + fibsize);
2419dce93cd0SAchim Leubner 	} else {
2420dce93cd0SAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_SRC_IQUE32, (u_int32_t)address + fibsize);
2421dce93cd0SAchim Leubner 	}
2422dce93cd0SAchim Leubner 	return 0;
2423dce93cd0SAchim Leubner }
2424dce93cd0SAchim Leubner 
2425dce93cd0SAchim Leubner /*
2426dce93cd0SAchim Leubner  * New comm. interface: get, set outbound queue index
2427dce93cd0SAchim Leubner  */
2428dce93cd0SAchim Leubner static int
2429dce93cd0SAchim Leubner aac_src_get_outb_queue(struct aac_softc *sc)
2430dce93cd0SAchim Leubner {
2431dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2432dce93cd0SAchim Leubner 
2433dce93cd0SAchim Leubner 	return(-1);
2434dce93cd0SAchim Leubner }
2435dce93cd0SAchim Leubner 
2436dce93cd0SAchim Leubner static void
2437dce93cd0SAchim Leubner aac_src_set_outb_queue(struct aac_softc *sc, int index)
2438dce93cd0SAchim Leubner {
2439dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2440dce93cd0SAchim Leubner }
2441dce93cd0SAchim Leubner 
2442dce93cd0SAchim Leubner /*
2443dce93cd0SAchim Leubner  * Debugging and Diagnostics
2444dce93cd0SAchim Leubner  */
2445dce93cd0SAchim Leubner 
2446dce93cd0SAchim Leubner /*
2447dce93cd0SAchim Leubner  * Print some information about the controller.
2448dce93cd0SAchim Leubner  */
2449dce93cd0SAchim Leubner static void
2450dce93cd0SAchim Leubner aac_describe_controller(struct aac_softc *sc)
2451dce93cd0SAchim Leubner {
2452dce93cd0SAchim Leubner 	struct aac_fib *fib;
2453dce93cd0SAchim Leubner 	struct aac_adapter_info	*info;
2454dce93cd0SAchim Leubner 	char *adapter_type = "Adaptec RAID controller";
2455dce93cd0SAchim Leubner 
2456dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2457dce93cd0SAchim Leubner 
2458dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
2459dce93cd0SAchim Leubner 	aac_alloc_sync_fib(sc, &fib);
2460dce93cd0SAchim Leubner 
2461dce93cd0SAchim Leubner 	if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) {
2462dce93cd0SAchim Leubner 		fib->data[0] = 0;
2463dce93cd0SAchim Leubner 		if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1))
2464dce93cd0SAchim Leubner 			device_printf(sc->aac_dev, "RequestSupplementAdapterInfo failed\n");
2465dce93cd0SAchim Leubner 		else {
2466dce93cd0SAchim Leubner 			struct aac_supplement_adapter_info *supp_info;
2467dce93cd0SAchim Leubner 
2468dce93cd0SAchim Leubner 			supp_info = ((struct aac_supplement_adapter_info *)&fib->data[0]);
2469dce93cd0SAchim Leubner 			adapter_type = (char *)supp_info->AdapterTypeText;
2470dce93cd0SAchim Leubner 			sc->aac_feature_bits = supp_info->FeatureBits;
2471dce93cd0SAchim Leubner 			sc->aac_support_opt2 = supp_info->SupportedOptions2;
2472dce93cd0SAchim Leubner 		}
2473dce93cd0SAchim Leubner 	}
2474dce93cd0SAchim Leubner 	device_printf(sc->aac_dev, "%s, aacraid driver %d.%d.%d-%d\n",
2475dce93cd0SAchim Leubner 		adapter_type,
2476dce93cd0SAchim Leubner 		AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION,
2477dce93cd0SAchim Leubner 		AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD);
2478dce93cd0SAchim Leubner 
2479dce93cd0SAchim Leubner 	fib->data[0] = 0;
2480dce93cd0SAchim Leubner 	if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) {
2481dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "RequestAdapterInfo failed\n");
2482dce93cd0SAchim Leubner 		aac_release_sync_fib(sc);
2483dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
2484dce93cd0SAchim Leubner 		return;
2485dce93cd0SAchim Leubner 	}
2486dce93cd0SAchim Leubner 
2487dce93cd0SAchim Leubner 	/* save the kernel revision structure for later use */
2488dce93cd0SAchim Leubner 	info = (struct aac_adapter_info *)&fib->data[0];
2489dce93cd0SAchim Leubner 	sc->aac_revision = info->KernelRevision;
2490dce93cd0SAchim Leubner 
2491dce93cd0SAchim Leubner 	if (bootverbose) {
2492dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "%s %dMHz, %dMB memory "
2493dce93cd0SAchim Leubner 		    "(%dMB cache, %dMB execution), %s\n",
2494dce93cd0SAchim Leubner 		    aac_describe_code(aac_cpu_variant, info->CpuVariant),
2495dce93cd0SAchim Leubner 		    info->ClockSpeed, info->TotalMem / (1024 * 1024),
2496dce93cd0SAchim Leubner 		    info->BufferMem / (1024 * 1024),
2497dce93cd0SAchim Leubner 		    info->ExecutionMem / (1024 * 1024),
2498dce93cd0SAchim Leubner 		    aac_describe_code(aac_battery_platform,
2499dce93cd0SAchim Leubner 		    info->batteryPlatform));
2500dce93cd0SAchim Leubner 
2501dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
2502dce93cd0SAchim Leubner 		    "Kernel %d.%d-%d, Build %d, S/N %6X\n",
2503dce93cd0SAchim Leubner 		    info->KernelRevision.external.comp.major,
2504dce93cd0SAchim Leubner 		    info->KernelRevision.external.comp.minor,
2505dce93cd0SAchim Leubner 		    info->KernelRevision.external.comp.dash,
2506dce93cd0SAchim Leubner 		    info->KernelRevision.buildNumber,
2507dce93cd0SAchim Leubner 		    (u_int32_t)(info->SerialNumber & 0xffffff));
2508dce93cd0SAchim Leubner 
2509dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Supported Options=%b\n",
2510dce93cd0SAchim Leubner 			      sc->supported_options,
2511dce93cd0SAchim Leubner 			      "\20"
2512dce93cd0SAchim Leubner 			      "\1SNAPSHOT"
2513dce93cd0SAchim Leubner 			      "\2CLUSTERS"
2514dce93cd0SAchim Leubner 			      "\3WCACHE"
2515dce93cd0SAchim Leubner 			      "\4DATA64"
2516dce93cd0SAchim Leubner 			      "\5HOSTTIME"
2517dce93cd0SAchim Leubner 			      "\6RAID50"
2518dce93cd0SAchim Leubner 			      "\7WINDOW4GB"
2519dce93cd0SAchim Leubner 			      "\10SCSIUPGD"
2520dce93cd0SAchim Leubner 			      "\11SOFTERR"
2521dce93cd0SAchim Leubner 			      "\12NORECOND"
2522dce93cd0SAchim Leubner 			      "\13SGMAP64"
2523dce93cd0SAchim Leubner 			      "\14ALARM"
2524dce93cd0SAchim Leubner 			      "\15NONDASD"
2525dce93cd0SAchim Leubner 			      "\16SCSIMGT"
2526dce93cd0SAchim Leubner 			      "\17RAIDSCSI"
2527dce93cd0SAchim Leubner 			      "\21ADPTINFO"
2528dce93cd0SAchim Leubner 			      "\22NEWCOMM"
2529dce93cd0SAchim Leubner 			      "\23ARRAY64BIT"
2530dce93cd0SAchim Leubner 			      "\24HEATSENSOR");
2531dce93cd0SAchim Leubner 	}
2532dce93cd0SAchim Leubner 
2533dce93cd0SAchim Leubner 	aac_release_sync_fib(sc);
2534dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
2535dce93cd0SAchim Leubner }
2536dce93cd0SAchim Leubner 
2537dce93cd0SAchim Leubner /*
2538dce93cd0SAchim Leubner  * Look up a text description of a numeric error code and return a pointer to
2539dce93cd0SAchim Leubner  * same.
2540dce93cd0SAchim Leubner  */
2541dce93cd0SAchim Leubner static char *
2542dce93cd0SAchim Leubner aac_describe_code(struct aac_code_lookup *table, u_int32_t code)
2543dce93cd0SAchim Leubner {
2544dce93cd0SAchim Leubner 	int i;
2545dce93cd0SAchim Leubner 
2546dce93cd0SAchim Leubner 	for (i = 0; table[i].string != NULL; i++)
2547dce93cd0SAchim Leubner 		if (table[i].code == code)
2548dce93cd0SAchim Leubner 			return(table[i].string);
2549dce93cd0SAchim Leubner 	return(table[i + 1].string);
2550dce93cd0SAchim Leubner }
2551dce93cd0SAchim Leubner 
2552dce93cd0SAchim Leubner /*
2553dce93cd0SAchim Leubner  * Management Interface
2554dce93cd0SAchim Leubner  */
2555dce93cd0SAchim Leubner 
2556dce93cd0SAchim Leubner static int
2557dce93cd0SAchim Leubner aac_open(struct cdev *dev, int flags, int fmt, struct thread *td)
2558dce93cd0SAchim Leubner {
2559dce93cd0SAchim Leubner 	struct aac_softc *sc;
2560dce93cd0SAchim Leubner 
2561dce93cd0SAchim Leubner 	sc = dev->si_drv1;
2562dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2563dce93cd0SAchim Leubner 	device_busy(sc->aac_dev);
2564dce93cd0SAchim Leubner 	devfs_set_cdevpriv(sc, aac_cdevpriv_dtor);
2565dce93cd0SAchim Leubner 	return 0;
2566dce93cd0SAchim Leubner }
2567dce93cd0SAchim Leubner 
2568dce93cd0SAchim Leubner static int
2569dce93cd0SAchim Leubner aac_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
2570dce93cd0SAchim Leubner {
2571dce93cd0SAchim Leubner 	union aac_statrequest *as;
2572dce93cd0SAchim Leubner 	struct aac_softc *sc;
2573dce93cd0SAchim Leubner 	int error = 0;
2574dce93cd0SAchim Leubner 
2575dce93cd0SAchim Leubner 	as = (union aac_statrequest *)arg;
2576dce93cd0SAchim Leubner 	sc = dev->si_drv1;
2577dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2578dce93cd0SAchim Leubner 
2579dce93cd0SAchim Leubner 	switch (cmd) {
2580dce93cd0SAchim Leubner 	case AACIO_STATS:
2581dce93cd0SAchim Leubner 		switch (as->as_item) {
2582dce93cd0SAchim Leubner 		case AACQ_FREE:
2583dce93cd0SAchim Leubner 		case AACQ_READY:
2584dce93cd0SAchim Leubner 		case AACQ_BUSY:
2585dce93cd0SAchim Leubner 			bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat,
2586dce93cd0SAchim Leubner 			      sizeof(struct aac_qstat));
2587dce93cd0SAchim Leubner 			break;
2588dce93cd0SAchim Leubner 		default:
2589dce93cd0SAchim Leubner 			error = ENOENT;
2590dce93cd0SAchim Leubner 			break;
2591dce93cd0SAchim Leubner 		}
2592dce93cd0SAchim Leubner 	break;
2593dce93cd0SAchim Leubner 
2594dce93cd0SAchim Leubner 	case FSACTL_SENDFIB:
2595dce93cd0SAchim Leubner 	case FSACTL_SEND_LARGE_FIB:
2596dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2597dce93cd0SAchim Leubner 	case FSACTL_LNX_SENDFIB:
2598dce93cd0SAchim Leubner 	case FSACTL_LNX_SEND_LARGE_FIB:
2599dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB");
2600dce93cd0SAchim Leubner 		error = aac_ioctl_sendfib(sc, arg);
2601dce93cd0SAchim Leubner 		break;
2602dce93cd0SAchim Leubner 	case FSACTL_SEND_RAW_SRB:
2603dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2604dce93cd0SAchim Leubner 	case FSACTL_LNX_SEND_RAW_SRB:
2605dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB");
2606dce93cd0SAchim Leubner 		error = aac_ioctl_send_raw_srb(sc, arg);
2607dce93cd0SAchim Leubner 		break;
2608dce93cd0SAchim Leubner 	case FSACTL_AIF_THREAD:
2609dce93cd0SAchim Leubner 	case FSACTL_LNX_AIF_THREAD:
2610dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD");
2611dce93cd0SAchim Leubner 		error = EINVAL;
2612dce93cd0SAchim Leubner 		break;
2613dce93cd0SAchim Leubner 	case FSACTL_OPEN_GET_ADAPTER_FIB:
2614dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2615dce93cd0SAchim Leubner 	case FSACTL_LNX_OPEN_GET_ADAPTER_FIB:
2616dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB");
2617dce93cd0SAchim Leubner 		error = aac_open_aif(sc, arg);
2618dce93cd0SAchim Leubner 		break;
2619dce93cd0SAchim Leubner 	case FSACTL_GET_NEXT_ADAPTER_FIB:
2620dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2621dce93cd0SAchim Leubner 	case FSACTL_LNX_GET_NEXT_ADAPTER_FIB:
2622dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB");
2623dce93cd0SAchim Leubner 		error = aac_getnext_aif(sc, arg);
2624dce93cd0SAchim Leubner 		break;
2625dce93cd0SAchim Leubner 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
2626dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2627dce93cd0SAchim Leubner 	case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB:
2628dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB");
2629dce93cd0SAchim Leubner 		error = aac_close_aif(sc, arg);
2630dce93cd0SAchim Leubner 		break;
2631dce93cd0SAchim Leubner 	case FSACTL_MINIPORT_REV_CHECK:
2632dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2633dce93cd0SAchim Leubner 	case FSACTL_LNX_MINIPORT_REV_CHECK:
2634dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK");
2635dce93cd0SAchim Leubner 		error = aac_rev_check(sc, arg);
2636dce93cd0SAchim Leubner 		break;
2637dce93cd0SAchim Leubner 	case FSACTL_QUERY_DISK:
2638dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2639dce93cd0SAchim Leubner 	case FSACTL_LNX_QUERY_DISK:
2640dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK");
2641dce93cd0SAchim Leubner 		error = aac_query_disk(sc, arg);
2642dce93cd0SAchim Leubner 		break;
2643dce93cd0SAchim Leubner 	case FSACTL_DELETE_DISK:
2644dce93cd0SAchim Leubner 	case FSACTL_LNX_DELETE_DISK:
2645dce93cd0SAchim Leubner 		/*
2646dce93cd0SAchim Leubner 		 * We don't trust the underland to tell us when to delete a
2647dce93cd0SAchim Leubner 		 * container, rather we rely on an AIF coming from the
2648dce93cd0SAchim Leubner 		 * controller
2649dce93cd0SAchim Leubner 		 */
2650dce93cd0SAchim Leubner 		error = 0;
2651dce93cd0SAchim Leubner 		break;
2652dce93cd0SAchim Leubner 	case FSACTL_GET_PCI_INFO:
2653dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2654dce93cd0SAchim Leubner 	case FSACTL_LNX_GET_PCI_INFO:
2655dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO");
2656dce93cd0SAchim Leubner 		error = aac_get_pci_info(sc, arg);
2657dce93cd0SAchim Leubner 		break;
2658dce93cd0SAchim Leubner 	case FSACTL_GET_FEATURES:
2659dce93cd0SAchim Leubner 		arg = *(caddr_t*)arg;
2660dce93cd0SAchim Leubner 	case FSACTL_LNX_GET_FEATURES:
2661dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES");
2662dce93cd0SAchim Leubner 		error = aac_supported_features(sc, arg);
2663dce93cd0SAchim Leubner 		break;
2664dce93cd0SAchim Leubner 	default:
2665dce93cd0SAchim Leubner 		fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd);
2666dce93cd0SAchim Leubner 		error = EINVAL;
2667dce93cd0SAchim Leubner 		break;
2668dce93cd0SAchim Leubner 	}
2669dce93cd0SAchim Leubner 	return(error);
2670dce93cd0SAchim Leubner }
2671dce93cd0SAchim Leubner 
2672dce93cd0SAchim Leubner static int
2673dce93cd0SAchim Leubner aac_poll(struct cdev *dev, int poll_events, struct thread *td)
2674dce93cd0SAchim Leubner {
2675dce93cd0SAchim Leubner 	struct aac_softc *sc;
2676dce93cd0SAchim Leubner 	struct aac_fib_context *ctx;
2677dce93cd0SAchim Leubner 	int revents;
2678dce93cd0SAchim Leubner 
2679dce93cd0SAchim Leubner 	sc = dev->si_drv1;
2680dce93cd0SAchim Leubner 	revents = 0;
2681dce93cd0SAchim Leubner 
2682dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
2683dce93cd0SAchim Leubner 	if ((poll_events & (POLLRDNORM | POLLIN)) != 0) {
2684dce93cd0SAchim Leubner 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
2685dce93cd0SAchim Leubner 			if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) {
2686dce93cd0SAchim Leubner 				revents |= poll_events & (POLLIN | POLLRDNORM);
2687dce93cd0SAchim Leubner 				break;
2688dce93cd0SAchim Leubner 			}
2689dce93cd0SAchim Leubner 		}
2690dce93cd0SAchim Leubner 	}
2691dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
2692dce93cd0SAchim Leubner 
2693dce93cd0SAchim Leubner 	if (revents == 0) {
2694dce93cd0SAchim Leubner 		if (poll_events & (POLLIN | POLLRDNORM))
2695dce93cd0SAchim Leubner 			selrecord(td, &sc->rcv_select);
2696dce93cd0SAchim Leubner 	}
2697dce93cd0SAchim Leubner 
2698dce93cd0SAchim Leubner 	return (revents);
2699dce93cd0SAchim Leubner }
2700dce93cd0SAchim Leubner 
2701dce93cd0SAchim Leubner static void
2702dce93cd0SAchim Leubner aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg)
2703dce93cd0SAchim Leubner {
2704dce93cd0SAchim Leubner 
2705dce93cd0SAchim Leubner 	switch (event->ev_type) {
2706dce93cd0SAchim Leubner 	case AAC_EVENT_CMFREE:
2707dce93cd0SAchim Leubner 		mtx_assert(&sc->aac_io_lock, MA_OWNED);
2708dce93cd0SAchim Leubner 		if (aacraid_alloc_command(sc, (struct aac_command **)arg)) {
2709dce93cd0SAchim Leubner 			aacraid_add_event(sc, event);
2710dce93cd0SAchim Leubner 			return;
2711dce93cd0SAchim Leubner 		}
2712dce93cd0SAchim Leubner 		free(event, M_AACRAIDBUF);
2713dce93cd0SAchim Leubner 		wakeup(arg);
2714dce93cd0SAchim Leubner 		break;
2715dce93cd0SAchim Leubner 	default:
2716dce93cd0SAchim Leubner 		break;
2717dce93cd0SAchim Leubner 	}
2718dce93cd0SAchim Leubner }
2719dce93cd0SAchim Leubner 
2720dce93cd0SAchim Leubner /*
2721dce93cd0SAchim Leubner  * Send a FIB supplied from userspace
2722dce93cd0SAchim Leubner  */
2723dce93cd0SAchim Leubner static int
2724dce93cd0SAchim Leubner aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
2725dce93cd0SAchim Leubner {
2726dce93cd0SAchim Leubner 	struct aac_command *cm;
2727dce93cd0SAchim Leubner 	int size, error;
2728dce93cd0SAchim Leubner 
2729dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2730dce93cd0SAchim Leubner 
2731dce93cd0SAchim Leubner 	cm = NULL;
2732dce93cd0SAchim Leubner 
2733dce93cd0SAchim Leubner 	/*
2734dce93cd0SAchim Leubner 	 * Get a command
2735dce93cd0SAchim Leubner 	 */
2736dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
2737dce93cd0SAchim Leubner 	if (aacraid_alloc_command(sc, &cm)) {
2738dce93cd0SAchim Leubner 		struct aac_event *event;
2739dce93cd0SAchim Leubner 
2740dce93cd0SAchim Leubner 		event = malloc(sizeof(struct aac_event), M_AACRAIDBUF,
2741dce93cd0SAchim Leubner 		    M_NOWAIT | M_ZERO);
2742dce93cd0SAchim Leubner 		if (event == NULL) {
2743dce93cd0SAchim Leubner 			error = EBUSY;
2744dce93cd0SAchim Leubner 			mtx_unlock(&sc->aac_io_lock);
2745dce93cd0SAchim Leubner 			goto out;
2746dce93cd0SAchim Leubner 		}
2747dce93cd0SAchim Leubner 		event->ev_type = AAC_EVENT_CMFREE;
2748dce93cd0SAchim Leubner 		event->ev_callback = aac_ioctl_event;
2749dce93cd0SAchim Leubner 		event->ev_arg = &cm;
2750dce93cd0SAchim Leubner 		aacraid_add_event(sc, event);
2751dce93cd0SAchim Leubner 		msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsfib", 0);
2752dce93cd0SAchim Leubner 	}
2753dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
2754dce93cd0SAchim Leubner 
2755dce93cd0SAchim Leubner 	/*
2756dce93cd0SAchim Leubner 	 * Fetch the FIB header, then re-copy to get data as well.
2757dce93cd0SAchim Leubner 	 */
2758dce93cd0SAchim Leubner 	if ((error = copyin(ufib, cm->cm_fib,
2759dce93cd0SAchim Leubner 			    sizeof(struct aac_fib_header))) != 0)
2760dce93cd0SAchim Leubner 		goto out;
2761dce93cd0SAchim Leubner 	size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header);
2762dce93cd0SAchim Leubner 	if (size > sc->aac_max_fib_size) {
2763dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n",
2764dce93cd0SAchim Leubner 			      size, sc->aac_max_fib_size);
2765dce93cd0SAchim Leubner 		size = sc->aac_max_fib_size;
2766dce93cd0SAchim Leubner 	}
2767dce93cd0SAchim Leubner 	if ((error = copyin(ufib, cm->cm_fib, size)) != 0)
2768dce93cd0SAchim Leubner 		goto out;
2769dce93cd0SAchim Leubner 	cm->cm_fib->Header.Size = size;
2770dce93cd0SAchim Leubner 	cm->cm_timestamp = time_uptime;
2771dce93cd0SAchim Leubner 	cm->cm_datalen = 0;
2772dce93cd0SAchim Leubner 
2773dce93cd0SAchim Leubner 	/*
2774dce93cd0SAchim Leubner 	 * Pass the FIB to the controller, wait for it to complete.
2775dce93cd0SAchim Leubner 	 */
2776dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
2777dce93cd0SAchim Leubner 	error = aacraid_wait_command(cm);
2778dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
2779dce93cd0SAchim Leubner 	if (error != 0) {
2780dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
2781dce93cd0SAchim Leubner 			      "aacraid_wait_command return %d\n", error);
2782dce93cd0SAchim Leubner 		goto out;
2783dce93cd0SAchim Leubner 	}
2784dce93cd0SAchim Leubner 
2785dce93cd0SAchim Leubner 	/*
2786dce93cd0SAchim Leubner 	 * Copy the FIB and data back out to the caller.
2787dce93cd0SAchim Leubner 	 */
2788dce93cd0SAchim Leubner 	size = cm->cm_fib->Header.Size;
2789dce93cd0SAchim Leubner 	if (size > sc->aac_max_fib_size) {
2790dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n",
2791dce93cd0SAchim Leubner 			      size, sc->aac_max_fib_size);
2792dce93cd0SAchim Leubner 		size = sc->aac_max_fib_size;
2793dce93cd0SAchim Leubner 	}
2794dce93cd0SAchim Leubner 	error = copyout(cm->cm_fib, ufib, size);
2795dce93cd0SAchim Leubner 
2796dce93cd0SAchim Leubner out:
2797dce93cd0SAchim Leubner 	if (cm != NULL) {
2798dce93cd0SAchim Leubner 		mtx_lock(&sc->aac_io_lock);
2799dce93cd0SAchim Leubner 		aacraid_release_command(cm);
2800dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
2801dce93cd0SAchim Leubner 	}
2802dce93cd0SAchim Leubner 	return(error);
2803dce93cd0SAchim Leubner }
2804dce93cd0SAchim Leubner 
2805dce93cd0SAchim Leubner /*
2806dce93cd0SAchim Leubner  * Send a passthrough FIB supplied from userspace
2807dce93cd0SAchim Leubner  */
2808dce93cd0SAchim Leubner static int
2809dce93cd0SAchim Leubner aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
2810dce93cd0SAchim Leubner {
2811dce93cd0SAchim Leubner 	struct aac_command *cm;
2812dce93cd0SAchim Leubner 	struct aac_fib *fib;
2813dce93cd0SAchim Leubner 	struct aac_srb *srbcmd;
2814dce93cd0SAchim Leubner 	struct aac_srb *user_srb = (struct aac_srb *)arg;
2815dce93cd0SAchim Leubner 	void *user_reply;
2816dce93cd0SAchim Leubner 	int error, transfer_data = 0;
2817dce93cd0SAchim Leubner 	bus_dmamap_t orig_map = 0;
2818dce93cd0SAchim Leubner 	u_int32_t fibsize = 0;
2819dce93cd0SAchim Leubner 	u_int64_t srb_sg_address;
2820dce93cd0SAchim Leubner 	u_int32_t srb_sg_bytecount;
2821dce93cd0SAchim Leubner 
2822dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
2823dce93cd0SAchim Leubner 
2824dce93cd0SAchim Leubner 	cm = NULL;
2825dce93cd0SAchim Leubner 
2826dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
2827dce93cd0SAchim Leubner 	if (aacraid_alloc_command(sc, &cm)) {
2828dce93cd0SAchim Leubner 		struct aac_event *event;
2829dce93cd0SAchim Leubner 
2830dce93cd0SAchim Leubner 		event = malloc(sizeof(struct aac_event), M_AACRAIDBUF,
2831dce93cd0SAchim Leubner 		    M_NOWAIT | M_ZERO);
2832dce93cd0SAchim Leubner 		if (event == NULL) {
2833dce93cd0SAchim Leubner 			error = EBUSY;
2834dce93cd0SAchim Leubner 			mtx_unlock(&sc->aac_io_lock);
2835dce93cd0SAchim Leubner 			goto out;
2836dce93cd0SAchim Leubner 		}
2837dce93cd0SAchim Leubner 		event->ev_type = AAC_EVENT_CMFREE;
2838dce93cd0SAchim Leubner 		event->ev_callback = aac_ioctl_event;
2839dce93cd0SAchim Leubner 		event->ev_arg = &cm;
2840dce93cd0SAchim Leubner 		aacraid_add_event(sc, event);
2841dce93cd0SAchim Leubner 		msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsraw", 0);
2842dce93cd0SAchim Leubner 	}
2843dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
2844dce93cd0SAchim Leubner 
2845dce93cd0SAchim Leubner 	cm->cm_data = NULL;
2846dce93cd0SAchim Leubner 	/* save original dma map */
2847dce93cd0SAchim Leubner 	orig_map = cm->cm_datamap;
2848dce93cd0SAchim Leubner 
2849dce93cd0SAchim Leubner 	fib = cm->cm_fib;
2850dce93cd0SAchim Leubner 	srbcmd = (struct aac_srb *)fib->data;
2851dce93cd0SAchim Leubner 	if ((error = copyin((void *)&user_srb->data_len, &fibsize,
28524f1dfabaSMaxim Sobolev 	    sizeof (u_int32_t))) != 0)
2853dce93cd0SAchim Leubner 		goto out;
2854dce93cd0SAchim Leubner 	if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) {
2855dce93cd0SAchim Leubner 		error = EINVAL;
2856dce93cd0SAchim Leubner 		goto out;
2857dce93cd0SAchim Leubner 	}
28584f1dfabaSMaxim Sobolev 	if ((error = copyin((void *)user_srb, srbcmd, fibsize)) != 0)
2859dce93cd0SAchim Leubner 		goto out;
2860dce93cd0SAchim Leubner 
2861dce93cd0SAchim Leubner 	srbcmd->function = 0;		/* SRBF_ExecuteScsi */
2862dce93cd0SAchim Leubner 	srbcmd->retry_limit = 0;	/* obsolete */
2863dce93cd0SAchim Leubner 
2864dce93cd0SAchim Leubner 	/* only one sg element from userspace supported */
2865dce93cd0SAchim Leubner 	if (srbcmd->sg_map.SgCount > 1) {
2866dce93cd0SAchim Leubner 		error = EINVAL;
2867dce93cd0SAchim Leubner 		goto out;
2868dce93cd0SAchim Leubner 	}
2869dce93cd0SAchim Leubner 	/* check fibsize */
2870dce93cd0SAchim Leubner 	if (fibsize == (sizeof(struct aac_srb) +
2871dce93cd0SAchim Leubner 		srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) {
2872dce93cd0SAchim Leubner 		struct aac_sg_entry *sgp = srbcmd->sg_map.SgEntry;
2873f4a18258SSean Bruno 		struct aac_sg_entry sg;
2874f4a18258SSean Bruno 
2875f4a18258SSean Bruno 		if ((error = copyin(sgp, &sg, sizeof(sg))) != 0)
2876f4a18258SSean Bruno 			goto out;
2877f4a18258SSean Bruno 
2878f4a18258SSean Bruno 		srb_sg_bytecount = sg.SgByteCount;
2879f4a18258SSean Bruno 		srb_sg_address = (u_int64_t)sg.SgAddress;
2880dce93cd0SAchim Leubner 	} else if (fibsize == (sizeof(struct aac_srb) +
2881dce93cd0SAchim Leubner 		srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) {
2882dceba9b5SMarcel Moolenaar #ifdef __LP64__
2883dce93cd0SAchim Leubner 		struct aac_sg_entry64 *sgp =
2884dce93cd0SAchim Leubner 			(struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry;
2885f4a18258SSean Bruno 		struct aac_sg_entry64 sg;
2886f4a18258SSean Bruno 
2887f4a18258SSean Bruno 		if ((error = copyin(sgp, &sg, sizeof(sg))) != 0)
2888f4a18258SSean Bruno 			goto out;
2889f4a18258SSean Bruno 
2890f4a18258SSean Bruno 		srb_sg_bytecount = sg.SgByteCount;
2891f4a18258SSean Bruno 		srb_sg_address = sg.SgAddress;
28924f1dfabaSMaxim Sobolev #else
2893dce93cd0SAchim Leubner 		error = EINVAL;
2894dce93cd0SAchim Leubner 		goto out;
28954f1dfabaSMaxim Sobolev #endif
2896dce93cd0SAchim Leubner 	} else {
2897dce93cd0SAchim Leubner 		error = EINVAL;
2898dce93cd0SAchim Leubner 		goto out;
2899dce93cd0SAchim Leubner 	}
2900dce93cd0SAchim Leubner 	user_reply = (char *)arg + fibsize;
2901dce93cd0SAchim Leubner 	srbcmd->data_len = srb_sg_bytecount;
2902dce93cd0SAchim Leubner 	if (srbcmd->sg_map.SgCount == 1)
2903dce93cd0SAchim Leubner 		transfer_data = 1;
2904dce93cd0SAchim Leubner 
2905dce93cd0SAchim Leubner 	if (transfer_data) {
2906dce93cd0SAchim Leubner 		/*
2907dce93cd0SAchim Leubner 		 * Create DMA tag for the passthr. data buffer and allocate it.
2908dce93cd0SAchim Leubner 		 */
2909dce93cd0SAchim Leubner 		if (bus_dma_tag_create(sc->aac_parent_dmat, 	/* parent */
2910dce93cd0SAchim Leubner 			1, 0,			/* algnmnt, boundary */
2911dce93cd0SAchim Leubner 			(sc->flags & AAC_FLAGS_SG_64BIT) ?
2912dce93cd0SAchim Leubner 			BUS_SPACE_MAXADDR_32BIT :
2913dce93cd0SAchim Leubner 			0x7fffffff,		/* lowaddr */
2914dce93cd0SAchim Leubner 			BUS_SPACE_MAXADDR, 	/* highaddr */
2915dce93cd0SAchim Leubner 			NULL, NULL, 		/* filter, filterarg */
2916dce93cd0SAchim Leubner 			srb_sg_bytecount, 	/* size */
2917dce93cd0SAchim Leubner 			sc->aac_sg_tablesize,	/* nsegments */
2918dce93cd0SAchim Leubner 			srb_sg_bytecount, 	/* maxsegsize */
2919dce93cd0SAchim Leubner 			0,			/* flags */
2920dce93cd0SAchim Leubner 			NULL, NULL,		/* No locking needed */
2921dce93cd0SAchim Leubner 			&cm->cm_passthr_dmat)) {
2922dce93cd0SAchim Leubner 			error = ENOMEM;
2923dce93cd0SAchim Leubner 			goto out;
2924dce93cd0SAchim Leubner 		}
2925dce93cd0SAchim Leubner 		if (bus_dmamem_alloc(cm->cm_passthr_dmat, (void **)&cm->cm_data,
2926dce93cd0SAchim Leubner 			BUS_DMA_NOWAIT, &cm->cm_datamap)) {
2927dce93cd0SAchim Leubner 			error = ENOMEM;
2928dce93cd0SAchim Leubner 			goto out;
2929dce93cd0SAchim Leubner 		}
2930dce93cd0SAchim Leubner 		/* fill some cm variables */
2931dce93cd0SAchim Leubner 		cm->cm_datalen = srb_sg_bytecount;
2932dce93cd0SAchim Leubner 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)
2933dce93cd0SAchim Leubner 			cm->cm_flags |= AAC_CMD_DATAIN;
2934dce93cd0SAchim Leubner 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT)
2935dce93cd0SAchim Leubner 			cm->cm_flags |= AAC_CMD_DATAOUT;
2936dce93cd0SAchim Leubner 
2937dce93cd0SAchim Leubner 		if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) {
2938dceba9b5SMarcel Moolenaar 			if ((error = copyin((void *)(uintptr_t)srb_sg_address,
2939dce93cd0SAchim Leubner 				cm->cm_data, cm->cm_datalen)) != 0)
2940dce93cd0SAchim Leubner 				goto out;
2941dce93cd0SAchim Leubner 			/* sync required for bus_dmamem_alloc() alloc. mem.? */
2942dce93cd0SAchim Leubner 			bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap,
2943dce93cd0SAchim Leubner 				BUS_DMASYNC_PREWRITE);
2944dce93cd0SAchim Leubner 		}
2945dce93cd0SAchim Leubner 	}
2946dce93cd0SAchim Leubner 
2947dce93cd0SAchim Leubner 	/* build the FIB */
2948dce93cd0SAchim Leubner 	fib->Header.Size = sizeof(struct aac_fib_header) +
2949dce93cd0SAchim Leubner 		sizeof(struct aac_srb);
2950dce93cd0SAchim Leubner 	fib->Header.XferState =
2951dce93cd0SAchim Leubner 		AAC_FIBSTATE_HOSTOWNED   |
2952dce93cd0SAchim Leubner 		AAC_FIBSTATE_INITIALISED |
2953dce93cd0SAchim Leubner 		AAC_FIBSTATE_EMPTY	 |
2954dce93cd0SAchim Leubner 		AAC_FIBSTATE_FROMHOST	 |
2955dce93cd0SAchim Leubner 		AAC_FIBSTATE_REXPECTED   |
2956dce93cd0SAchim Leubner 		AAC_FIBSTATE_NORM	 |
2957dce93cd0SAchim Leubner 		AAC_FIBSTATE_ASYNC;
2958dce93cd0SAchim Leubner 
2959dce93cd0SAchim Leubner 	fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ?
2960dce93cd0SAchim Leubner 		ScsiPortCommandU64 : ScsiPortCommand;
2961dce93cd0SAchim Leubner 	cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map;
2962dce93cd0SAchim Leubner 
2963dce93cd0SAchim Leubner 	/* send command */
2964dce93cd0SAchim Leubner 	if (transfer_data) {
2965dce93cd0SAchim Leubner 		bus_dmamap_load(cm->cm_passthr_dmat,
2966dce93cd0SAchim Leubner 			cm->cm_datamap, cm->cm_data,
2967dce93cd0SAchim Leubner 			cm->cm_datalen,
2968dce93cd0SAchim Leubner 			aacraid_map_command_sg, cm, 0);
2969dce93cd0SAchim Leubner 	} else {
2970dce93cd0SAchim Leubner 		aacraid_map_command_sg(cm, NULL, 0, 0);
2971dce93cd0SAchim Leubner 	}
2972dce93cd0SAchim Leubner 
2973dce93cd0SAchim Leubner 	/* wait for completion */
2974dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
2975dce93cd0SAchim Leubner 	while (!(cm->cm_flags & AAC_CMD_COMPLETED))
2976dce93cd0SAchim Leubner 		msleep(cm, &sc->aac_io_lock, 0, "aacraid_ctlsrw2", 0);
2977dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
2978dce93cd0SAchim Leubner 
2979dce93cd0SAchim Leubner 	/* copy data */
2980dce93cd0SAchim Leubner 	if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)) {
2981dce93cd0SAchim Leubner 		if ((error = copyout(cm->cm_data,
2982dceba9b5SMarcel Moolenaar 			(void *)(uintptr_t)srb_sg_address,
2983dce93cd0SAchim Leubner 			cm->cm_datalen)) != 0)
2984dce93cd0SAchim Leubner 			goto out;
2985dce93cd0SAchim Leubner 		/* sync required for bus_dmamem_alloc() allocated mem.? */
2986dce93cd0SAchim Leubner 		bus_dmamap_sync(cm->cm_passthr_dmat, cm->cm_datamap,
2987dce93cd0SAchim Leubner 				BUS_DMASYNC_POSTREAD);
2988dce93cd0SAchim Leubner 	}
2989dce93cd0SAchim Leubner 
2990dce93cd0SAchim Leubner 	/* status */
2991dce93cd0SAchim Leubner 	error = copyout(fib->data, user_reply, sizeof(struct aac_srb_response));
2992dce93cd0SAchim Leubner 
2993dce93cd0SAchim Leubner out:
2994dce93cd0SAchim Leubner 	if (cm && cm->cm_data) {
2995dce93cd0SAchim Leubner 		if (transfer_data)
2996dce93cd0SAchim Leubner 			bus_dmamap_unload(cm->cm_passthr_dmat, cm->cm_datamap);
2997dce93cd0SAchim Leubner 		bus_dmamem_free(cm->cm_passthr_dmat, cm->cm_data, cm->cm_datamap);
2998dce93cd0SAchim Leubner 		cm->cm_datamap = orig_map;
2999dce93cd0SAchim Leubner 	}
3000dce93cd0SAchim Leubner 	if (cm && cm->cm_passthr_dmat)
3001dce93cd0SAchim Leubner 		bus_dma_tag_destroy(cm->cm_passthr_dmat);
3002dce93cd0SAchim Leubner 	if (cm) {
3003dce93cd0SAchim Leubner 		mtx_lock(&sc->aac_io_lock);
3004dce93cd0SAchim Leubner 		aacraid_release_command(cm);
3005dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3006dce93cd0SAchim Leubner 	}
3007dce93cd0SAchim Leubner 	return(error);
3008dce93cd0SAchim Leubner }
3009dce93cd0SAchim Leubner 
3010dce93cd0SAchim Leubner /*
3011dce93cd0SAchim Leubner  * Request an AIF from the controller (new comm. type1)
3012dce93cd0SAchim Leubner  */
3013dce93cd0SAchim Leubner static void
3014dce93cd0SAchim Leubner aac_request_aif(struct aac_softc *sc)
3015dce93cd0SAchim Leubner {
3016dce93cd0SAchim Leubner 	struct aac_command *cm;
3017dce93cd0SAchim Leubner 	struct aac_fib *fib;
3018dce93cd0SAchim Leubner 
3019dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3020dce93cd0SAchim Leubner 
3021dce93cd0SAchim Leubner 	if (aacraid_alloc_command(sc, &cm)) {
3022dce93cd0SAchim Leubner 		sc->aif_pending = 1;
3023dce93cd0SAchim Leubner 		return;
3024dce93cd0SAchim Leubner 	}
3025dce93cd0SAchim Leubner 	sc->aif_pending = 0;
3026dce93cd0SAchim Leubner 
3027dce93cd0SAchim Leubner 	/* build the FIB */
3028dce93cd0SAchim Leubner 	fib = cm->cm_fib;
3029dce93cd0SAchim Leubner 	fib->Header.Size = sizeof(struct aac_fib);
3030dce93cd0SAchim Leubner 	fib->Header.XferState =
3031dce93cd0SAchim Leubner         AAC_FIBSTATE_HOSTOWNED   |
3032dce93cd0SAchim Leubner         AAC_FIBSTATE_INITIALISED |
3033dce93cd0SAchim Leubner         AAC_FIBSTATE_EMPTY	 |
3034dce93cd0SAchim Leubner         AAC_FIBSTATE_FROMHOST	 |
3035dce93cd0SAchim Leubner         AAC_FIBSTATE_REXPECTED   |
3036dce93cd0SAchim Leubner         AAC_FIBSTATE_NORM	 |
3037dce93cd0SAchim Leubner         AAC_FIBSTATE_ASYNC;
3038dce93cd0SAchim Leubner 	/* set AIF marker */
3039dce93cd0SAchim Leubner 	fib->Header.Handle = 0x00800000;
3040dce93cd0SAchim Leubner 	fib->Header.Command = AifRequest;
3041dce93cd0SAchim Leubner 	((struct aac_aif_command *)fib->data)->command = AifReqEvent;
3042dce93cd0SAchim Leubner 
3043dce93cd0SAchim Leubner 	aacraid_map_command_sg(cm, NULL, 0, 0);
3044dce93cd0SAchim Leubner }
3045dce93cd0SAchim Leubner 
3046dce93cd0SAchim Leubner 
3047dce93cd0SAchim Leubner /*
3048dce93cd0SAchim Leubner  * cdevpriv interface private destructor.
3049dce93cd0SAchim Leubner  */
3050dce93cd0SAchim Leubner static void
3051dce93cd0SAchim Leubner aac_cdevpriv_dtor(void *arg)
3052dce93cd0SAchim Leubner {
3053dce93cd0SAchim Leubner 	struct aac_softc *sc;
3054dce93cd0SAchim Leubner 
3055dce93cd0SAchim Leubner 	sc = arg;
3056dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3057dce93cd0SAchim Leubner 	device_unbusy(sc->aac_dev);
3058dce93cd0SAchim Leubner }
3059dce93cd0SAchim Leubner 
3060dce93cd0SAchim Leubner /*
3061dce93cd0SAchim Leubner  * Handle an AIF sent to us by the controller; queue it for later reference.
3062dce93cd0SAchim Leubner  * If the queue fills up, then drop the older entries.
3063dce93cd0SAchim Leubner  */
3064dce93cd0SAchim Leubner static void
3065dce93cd0SAchim Leubner aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib)
3066dce93cd0SAchim Leubner {
3067dce93cd0SAchim Leubner 	struct aac_aif_command *aif;
3068dce93cd0SAchim Leubner 	struct aac_container *co, *co_next;
3069dce93cd0SAchim Leubner 	struct aac_fib_context *ctx;
3070dce93cd0SAchim Leubner 	struct aac_fib *sync_fib;
3071dce93cd0SAchim Leubner 	struct aac_mntinforesp mir;
3072dce93cd0SAchim Leubner 	int next, current, found;
3073dce93cd0SAchim Leubner 	int count = 0, changed = 0, i = 0;
3074dce93cd0SAchim Leubner 	u_int32_t channel, uid;
3075dce93cd0SAchim Leubner 
3076dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3077dce93cd0SAchim Leubner 
3078dce93cd0SAchim Leubner 	aif = (struct aac_aif_command*)&fib->data[0];
3079dce93cd0SAchim Leubner 	aacraid_print_aif(sc, aif);
3080dce93cd0SAchim Leubner 
3081dce93cd0SAchim Leubner 	/* Is it an event that we should care about? */
3082dce93cd0SAchim Leubner 	switch (aif->command) {
3083dce93cd0SAchim Leubner 	case AifCmdEventNotify:
3084dce93cd0SAchim Leubner 		switch (aif->data.EN.type) {
3085dce93cd0SAchim Leubner 		case AifEnAddContainer:
3086dce93cd0SAchim Leubner 		case AifEnDeleteContainer:
3087dce93cd0SAchim Leubner 			/*
3088dce93cd0SAchim Leubner 			 * A container was added or deleted, but the message
3089dce93cd0SAchim Leubner 			 * doesn't tell us anything else!  Re-enumerate the
3090dce93cd0SAchim Leubner 			 * containers and sort things out.
3091dce93cd0SAchim Leubner 			 */
3092dce93cd0SAchim Leubner 			aac_alloc_sync_fib(sc, &sync_fib);
3093dce93cd0SAchim Leubner 			do {
3094dce93cd0SAchim Leubner 				/*
3095dce93cd0SAchim Leubner 				 * Ask the controller for its containers one at
3096dce93cd0SAchim Leubner 				 * a time.
3097dce93cd0SAchim Leubner 				 * XXX What if the controller's list changes
3098dce93cd0SAchim Leubner 				 * midway through this enumaration?
3099dce93cd0SAchim Leubner 				 * XXX This should be done async.
3100dce93cd0SAchim Leubner 				 */
3101dce93cd0SAchim Leubner 				if (aac_get_container_info(sc, sync_fib, i,
3102dce93cd0SAchim Leubner 					&mir, &uid) != 0)
3103dce93cd0SAchim Leubner 					continue;
3104dce93cd0SAchim Leubner 				if (i == 0)
3105dce93cd0SAchim Leubner 					count = mir.MntRespCount;
3106dce93cd0SAchim Leubner 				/*
3107dce93cd0SAchim Leubner 				 * Check the container against our list.
3108dce93cd0SAchim Leubner 				 * co->co_found was already set to 0 in a
3109dce93cd0SAchim Leubner 				 * previous run.
3110dce93cd0SAchim Leubner 				 */
3111dce93cd0SAchim Leubner 				if ((mir.Status == ST_OK) &&
3112dce93cd0SAchim Leubner 				    (mir.MntTable[0].VolType != CT_NONE)) {
3113dce93cd0SAchim Leubner 					found = 0;
3114dce93cd0SAchim Leubner 					TAILQ_FOREACH(co,
3115dce93cd0SAchim Leubner 						      &sc->aac_container_tqh,
3116dce93cd0SAchim Leubner 						      co_link) {
3117dce93cd0SAchim Leubner 						if (co->co_mntobj.ObjectId ==
3118dce93cd0SAchim Leubner 						    mir.MntTable[0].ObjectId) {
3119dce93cd0SAchim Leubner 							co->co_found = 1;
3120dce93cd0SAchim Leubner 							found = 1;
3121dce93cd0SAchim Leubner 							break;
3122dce93cd0SAchim Leubner 						}
3123dce93cd0SAchim Leubner 					}
3124dce93cd0SAchim Leubner 					/*
3125dce93cd0SAchim Leubner 					 * If the container matched, continue
3126dce93cd0SAchim Leubner 					 * in the list.
3127dce93cd0SAchim Leubner 					 */
3128dce93cd0SAchim Leubner 					if (found) {
3129dce93cd0SAchim Leubner 						i++;
3130dce93cd0SAchim Leubner 						continue;
3131dce93cd0SAchim Leubner 					}
3132dce93cd0SAchim Leubner 
3133dce93cd0SAchim Leubner 					/*
3134dce93cd0SAchim Leubner 					 * This is a new container.  Do all the
3135dce93cd0SAchim Leubner 					 * appropriate things to set it up.
3136dce93cd0SAchim Leubner 					 */
3137dce93cd0SAchim Leubner 					aac_add_container(sc, &mir, 1, uid);
3138dce93cd0SAchim Leubner 					changed = 1;
3139dce93cd0SAchim Leubner 				}
3140dce93cd0SAchim Leubner 				i++;
3141dce93cd0SAchim Leubner 			} while ((i < count) && (i < AAC_MAX_CONTAINERS));
3142dce93cd0SAchim Leubner 			aac_release_sync_fib(sc);
3143dce93cd0SAchim Leubner 
3144dce93cd0SAchim Leubner 			/*
3145dce93cd0SAchim Leubner 			 * Go through our list of containers and see which ones
3146dce93cd0SAchim Leubner 			 * were not marked 'found'.  Since the controller didn't
3147dce93cd0SAchim Leubner 			 * list them they must have been deleted.  Do the
3148dce93cd0SAchim Leubner 			 * appropriate steps to destroy the device.  Also reset
3149dce93cd0SAchim Leubner 			 * the co->co_found field.
3150dce93cd0SAchim Leubner 			 */
3151dce93cd0SAchim Leubner 			co = TAILQ_FIRST(&sc->aac_container_tqh);
3152dce93cd0SAchim Leubner 			while (co != NULL) {
3153dce93cd0SAchim Leubner 				if (co->co_found == 0) {
3154dce93cd0SAchim Leubner 					co_next = TAILQ_NEXT(co, co_link);
3155dce93cd0SAchim Leubner 					TAILQ_REMOVE(&sc->aac_container_tqh, co,
3156dce93cd0SAchim Leubner 						     co_link);
3157dce93cd0SAchim Leubner 					free(co, M_AACRAIDBUF);
3158dce93cd0SAchim Leubner 					changed = 1;
3159dce93cd0SAchim Leubner 					co = co_next;
3160dce93cd0SAchim Leubner 				} else {
3161dce93cd0SAchim Leubner 					co->co_found = 0;
3162dce93cd0SAchim Leubner 					co = TAILQ_NEXT(co, co_link);
3163dce93cd0SAchim Leubner 				}
3164dce93cd0SAchim Leubner 			}
3165dce93cd0SAchim Leubner 
3166dce93cd0SAchim Leubner 			/* Attach the newly created containers */
3167dce93cd0SAchim Leubner 			if (changed) {
3168dce93cd0SAchim Leubner 				if (sc->cam_rescan_cb != NULL)
3169dce93cd0SAchim Leubner 					sc->cam_rescan_cb(sc, 0,
3170dce93cd0SAchim Leubner 				    	AAC_CAM_TARGET_WILDCARD);
3171dce93cd0SAchim Leubner 			}
3172dce93cd0SAchim Leubner 
3173dce93cd0SAchim Leubner 			break;
3174dce93cd0SAchim Leubner 
3175dce93cd0SAchim Leubner 		case AifEnEnclosureManagement:
3176dce93cd0SAchim Leubner 			switch (aif->data.EN.data.EEE.eventType) {
3177dce93cd0SAchim Leubner 			case AIF_EM_DRIVE_INSERTION:
3178dce93cd0SAchim Leubner 			case AIF_EM_DRIVE_REMOVAL:
3179dce93cd0SAchim Leubner 				channel = aif->data.EN.data.EEE.unitID;
3180dce93cd0SAchim Leubner 				if (sc->cam_rescan_cb != NULL)
3181dce93cd0SAchim Leubner 					sc->cam_rescan_cb(sc,
3182dce93cd0SAchim Leubner 					    ((channel>>24) & 0xF) + 1,
3183dce93cd0SAchim Leubner 					    (channel & 0xFFFF));
3184dce93cd0SAchim Leubner 				break;
3185dce93cd0SAchim Leubner 			}
3186dce93cd0SAchim Leubner 			break;
3187dce93cd0SAchim Leubner 
3188dce93cd0SAchim Leubner 		case AifEnAddJBOD:
3189dce93cd0SAchim Leubner 		case AifEnDeleteJBOD:
3190dce93cd0SAchim Leubner 		case AifRawDeviceRemove:
3191dce93cd0SAchim Leubner 			channel = aif->data.EN.data.ECE.container;
3192dce93cd0SAchim Leubner 			if (sc->cam_rescan_cb != NULL)
3193dce93cd0SAchim Leubner 				sc->cam_rescan_cb(sc, ((channel>>24) & 0xF) + 1,
3194dce93cd0SAchim Leubner 				    AAC_CAM_TARGET_WILDCARD);
3195dce93cd0SAchim Leubner 			break;
3196dce93cd0SAchim Leubner 
3197dce93cd0SAchim Leubner 		default:
3198dce93cd0SAchim Leubner 			break;
3199dce93cd0SAchim Leubner 		}
3200dce93cd0SAchim Leubner 
3201dce93cd0SAchim Leubner 	default:
3202dce93cd0SAchim Leubner 		break;
3203dce93cd0SAchim Leubner 	}
3204dce93cd0SAchim Leubner 
3205dce93cd0SAchim Leubner 	/* Copy the AIF data to the AIF queue for ioctl retrieval */
3206dce93cd0SAchim Leubner 	current = sc->aifq_idx;
3207dce93cd0SAchim Leubner 	next = (current + 1) % AAC_AIFQ_LENGTH;
3208dce93cd0SAchim Leubner 	if (next == 0)
3209dce93cd0SAchim Leubner 		sc->aifq_filled = 1;
3210dce93cd0SAchim Leubner 	bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib));
3211dce93cd0SAchim Leubner 	/* modify AIF contexts */
3212dce93cd0SAchim Leubner 	if (sc->aifq_filled) {
3213dce93cd0SAchim Leubner 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3214dce93cd0SAchim Leubner 			if (next == ctx->ctx_idx)
3215dce93cd0SAchim Leubner 				ctx->ctx_wrap = 1;
3216dce93cd0SAchim Leubner 			else if (current == ctx->ctx_idx && ctx->ctx_wrap)
3217dce93cd0SAchim Leubner 				ctx->ctx_idx = next;
3218dce93cd0SAchim Leubner 		}
3219dce93cd0SAchim Leubner 	}
3220dce93cd0SAchim Leubner 	sc->aifq_idx = next;
3221dce93cd0SAchim Leubner 	/* On the off chance that someone is sleeping for an aif... */
3222dce93cd0SAchim Leubner 	if (sc->aac_state & AAC_STATE_AIF_SLEEPER)
3223dce93cd0SAchim Leubner 		wakeup(sc->aac_aifq);
3224dce93cd0SAchim Leubner 	/* Wakeup any poll()ers */
3225dce93cd0SAchim Leubner 	selwakeuppri(&sc->rcv_select, PRIBIO);
3226dce93cd0SAchim Leubner 
3227dce93cd0SAchim Leubner 	return;
3228dce93cd0SAchim Leubner }
3229dce93cd0SAchim Leubner 
3230dce93cd0SAchim Leubner /*
3231dce93cd0SAchim Leubner  * Return the Revision of the driver to userspace and check to see if the
3232dce93cd0SAchim Leubner  * userspace app is possibly compatible.  This is extremely bogus since
3233dce93cd0SAchim Leubner  * our driver doesn't follow Adaptec's versioning system.  Cheat by just
3234dce93cd0SAchim Leubner  * returning what the card reported.
3235dce93cd0SAchim Leubner  */
3236dce93cd0SAchim Leubner static int
3237dce93cd0SAchim Leubner aac_rev_check(struct aac_softc *sc, caddr_t udata)
3238dce93cd0SAchim Leubner {
3239dce93cd0SAchim Leubner 	struct aac_rev_check rev_check;
3240dce93cd0SAchim Leubner 	struct aac_rev_check_resp rev_check_resp;
3241dce93cd0SAchim Leubner 	int error = 0;
3242dce93cd0SAchim Leubner 
3243dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3244dce93cd0SAchim Leubner 
3245dce93cd0SAchim Leubner 	/*
3246dce93cd0SAchim Leubner 	 * Copyin the revision struct from userspace
3247dce93cd0SAchim Leubner 	 */
3248dce93cd0SAchim Leubner 	if ((error = copyin(udata, (caddr_t)&rev_check,
3249dce93cd0SAchim Leubner 			sizeof(struct aac_rev_check))) != 0) {
3250dce93cd0SAchim Leubner 		return error;
3251dce93cd0SAchim Leubner 	}
3252dce93cd0SAchim Leubner 
3253dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n",
3254dce93cd0SAchim Leubner 	      rev_check.callingRevision.buildNumber);
3255dce93cd0SAchim Leubner 
3256dce93cd0SAchim Leubner 	/*
3257dce93cd0SAchim Leubner 	 * Doctor up the response struct.
3258dce93cd0SAchim Leubner 	 */
3259dce93cd0SAchim Leubner 	rev_check_resp.possiblyCompatible = 1;
3260dce93cd0SAchim Leubner 	rev_check_resp.adapterSWRevision.external.comp.major =
3261dce93cd0SAchim Leubner 	    AAC_DRIVER_MAJOR_VERSION;
3262dce93cd0SAchim Leubner 	rev_check_resp.adapterSWRevision.external.comp.minor =
3263dce93cd0SAchim Leubner 	    AAC_DRIVER_MINOR_VERSION;
3264dce93cd0SAchim Leubner 	rev_check_resp.adapterSWRevision.external.comp.type =
3265dce93cd0SAchim Leubner 	    AAC_DRIVER_TYPE;
3266dce93cd0SAchim Leubner 	rev_check_resp.adapterSWRevision.external.comp.dash =
3267dce93cd0SAchim Leubner 	    AAC_DRIVER_BUGFIX_LEVEL;
3268dce93cd0SAchim Leubner 	rev_check_resp.adapterSWRevision.buildNumber =
3269dce93cd0SAchim Leubner 	    AAC_DRIVER_BUILD;
3270dce93cd0SAchim Leubner 
3271dce93cd0SAchim Leubner 	return(copyout((caddr_t)&rev_check_resp, udata,
3272dce93cd0SAchim Leubner 			sizeof(struct aac_rev_check_resp)));
3273dce93cd0SAchim Leubner }
3274dce93cd0SAchim Leubner 
3275dce93cd0SAchim Leubner /*
3276dce93cd0SAchim Leubner  * Pass the fib context to the caller
3277dce93cd0SAchim Leubner  */
3278dce93cd0SAchim Leubner static int
3279dce93cd0SAchim Leubner aac_open_aif(struct aac_softc *sc, caddr_t arg)
3280dce93cd0SAchim Leubner {
3281dce93cd0SAchim Leubner 	struct aac_fib_context *fibctx, *ctx;
3282dce93cd0SAchim Leubner 	int error = 0;
3283dce93cd0SAchim Leubner 
3284dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3285dce93cd0SAchim Leubner 
3286dce93cd0SAchim Leubner 	fibctx = malloc(sizeof(struct aac_fib_context), M_AACRAIDBUF, M_NOWAIT|M_ZERO);
3287dce93cd0SAchim Leubner 	if (fibctx == NULL)
3288dce93cd0SAchim Leubner 		return (ENOMEM);
3289dce93cd0SAchim Leubner 
3290dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
3291dce93cd0SAchim Leubner 	/* all elements are already 0, add to queue */
3292dce93cd0SAchim Leubner 	if (sc->fibctx == NULL)
3293dce93cd0SAchim Leubner 		sc->fibctx = fibctx;
3294dce93cd0SAchim Leubner 	else {
3295dce93cd0SAchim Leubner 		for (ctx = sc->fibctx; ctx->next; ctx = ctx->next)
3296dce93cd0SAchim Leubner 			;
3297dce93cd0SAchim Leubner 		ctx->next = fibctx;
3298dce93cd0SAchim Leubner 		fibctx->prev = ctx;
3299dce93cd0SAchim Leubner 	}
3300dce93cd0SAchim Leubner 
3301dce93cd0SAchim Leubner 	/* evaluate unique value */
3302dce93cd0SAchim Leubner 	fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff);
3303dce93cd0SAchim Leubner 	ctx = sc->fibctx;
3304dce93cd0SAchim Leubner 	while (ctx != fibctx) {
3305dce93cd0SAchim Leubner 		if (ctx->unique == fibctx->unique) {
3306dce93cd0SAchim Leubner 			fibctx->unique++;
3307dce93cd0SAchim Leubner 			ctx = sc->fibctx;
3308dce93cd0SAchim Leubner 		} else {
3309dce93cd0SAchim Leubner 			ctx = ctx->next;
3310dce93cd0SAchim Leubner 		}
3311dce93cd0SAchim Leubner 	}
3312dce93cd0SAchim Leubner 
3313dce93cd0SAchim Leubner 	error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t));
3314dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
3315dce93cd0SAchim Leubner 	if (error)
3316dce93cd0SAchim Leubner 		aac_close_aif(sc, (caddr_t)ctx);
3317dce93cd0SAchim Leubner 	return error;
3318dce93cd0SAchim Leubner }
3319dce93cd0SAchim Leubner 
3320dce93cd0SAchim Leubner /*
3321dce93cd0SAchim Leubner  * Close the caller's fib context
3322dce93cd0SAchim Leubner  */
3323dce93cd0SAchim Leubner static int
3324dce93cd0SAchim Leubner aac_close_aif(struct aac_softc *sc, caddr_t arg)
3325dce93cd0SAchim Leubner {
3326dce93cd0SAchim Leubner 	struct aac_fib_context *ctx;
3327dce93cd0SAchim Leubner 
3328dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3329dce93cd0SAchim Leubner 
3330dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
3331dce93cd0SAchim Leubner 	for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3332dce93cd0SAchim Leubner 		if (ctx->unique == *(uint32_t *)&arg) {
3333dce93cd0SAchim Leubner 			if (ctx == sc->fibctx)
3334dce93cd0SAchim Leubner 				sc->fibctx = NULL;
3335dce93cd0SAchim Leubner 			else {
3336dce93cd0SAchim Leubner 				ctx->prev->next = ctx->next;
3337dce93cd0SAchim Leubner 				if (ctx->next)
3338dce93cd0SAchim Leubner 					ctx->next->prev = ctx->prev;
3339dce93cd0SAchim Leubner 			}
3340dce93cd0SAchim Leubner 			break;
3341dce93cd0SAchim Leubner 		}
3342dce93cd0SAchim Leubner 	}
3343dce93cd0SAchim Leubner 	if (ctx)
3344dce93cd0SAchim Leubner 		free(ctx, M_AACRAIDBUF);
3345dce93cd0SAchim Leubner 
3346dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
3347dce93cd0SAchim Leubner 	return 0;
3348dce93cd0SAchim Leubner }
3349dce93cd0SAchim Leubner 
3350dce93cd0SAchim Leubner /*
3351dce93cd0SAchim Leubner  * Pass the caller the next AIF in their queue
3352dce93cd0SAchim Leubner  */
3353dce93cd0SAchim Leubner static int
3354dce93cd0SAchim Leubner aac_getnext_aif(struct aac_softc *sc, caddr_t arg)
3355dce93cd0SAchim Leubner {
3356dce93cd0SAchim Leubner 	struct get_adapter_fib_ioctl agf;
3357dce93cd0SAchim Leubner 	struct aac_fib_context *ctx;
3358dce93cd0SAchim Leubner 	int error;
3359dce93cd0SAchim Leubner 
3360dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3361dce93cd0SAchim Leubner 
3362dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
3363f287c3e4SBrooks Davis #ifdef COMPAT_FREEBSD32
3364f287c3e4SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32)) {
3365f287c3e4SBrooks Davis 		struct get_adapter_fib_ioctl32 agf32;
3366f287c3e4SBrooks Davis 		error = copyin(arg, &agf32, sizeof(agf32));
3367f287c3e4SBrooks Davis 		if (error == 0) {
3368f287c3e4SBrooks Davis 			agf.AdapterFibContext = agf32.AdapterFibContext;
3369f287c3e4SBrooks Davis 			agf.Wait = agf32.Wait;
3370f287c3e4SBrooks Davis 			agf.AifFib = (caddr_t)(uintptr_t)agf32.AifFib;
3371f287c3e4SBrooks Davis 		}
3372f287c3e4SBrooks Davis 	} else
3373f287c3e4SBrooks Davis #endif
3374f287c3e4SBrooks Davis 		error = copyin(arg, &agf, sizeof(agf));
3375f287c3e4SBrooks Davis 	if (error == 0) {
3376dce93cd0SAchim Leubner 		for (ctx = sc->fibctx; ctx; ctx = ctx->next) {
3377dce93cd0SAchim Leubner 			if (agf.AdapterFibContext == ctx->unique)
3378dce93cd0SAchim Leubner 				break;
3379dce93cd0SAchim Leubner 		}
3380dce93cd0SAchim Leubner 		if (!ctx) {
3381dce93cd0SAchim Leubner 			mtx_unlock(&sc->aac_io_lock);
3382dce93cd0SAchim Leubner 			return (EFAULT);
3383dce93cd0SAchim Leubner 		}
3384dce93cd0SAchim Leubner 
3385dce93cd0SAchim Leubner 		error = aac_return_aif(sc, ctx, agf.AifFib);
3386dce93cd0SAchim Leubner 		if (error == EAGAIN && agf.Wait) {
3387dce93cd0SAchim Leubner 			fwprintf(sc, HBA_FLAGS_DBG_AIF_B, "aac_getnext_aif(): waiting for AIF");
3388dce93cd0SAchim Leubner 			sc->aac_state |= AAC_STATE_AIF_SLEEPER;
3389dce93cd0SAchim Leubner 			while (error == EAGAIN) {
3390dce93cd0SAchim Leubner 				mtx_unlock(&sc->aac_io_lock);
3391dce93cd0SAchim Leubner 				error = tsleep(sc->aac_aifq, PRIBIO |
3392dce93cd0SAchim Leubner 					       PCATCH, "aacaif", 0);
3393dce93cd0SAchim Leubner 				mtx_lock(&sc->aac_io_lock);
3394dce93cd0SAchim Leubner 				if (error == 0)
3395dce93cd0SAchim Leubner 					error = aac_return_aif(sc, ctx, agf.AifFib);
3396dce93cd0SAchim Leubner 			}
3397dce93cd0SAchim Leubner 			sc->aac_state &= ~AAC_STATE_AIF_SLEEPER;
3398dce93cd0SAchim Leubner 		}
3399dce93cd0SAchim Leubner 	}
3400dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
3401dce93cd0SAchim Leubner 	return(error);
3402dce93cd0SAchim Leubner }
3403dce93cd0SAchim Leubner 
3404dce93cd0SAchim Leubner /*
3405dce93cd0SAchim Leubner  * Hand the next AIF off the top of the queue out to userspace.
3406dce93cd0SAchim Leubner  */
3407dce93cd0SAchim Leubner static int
3408dce93cd0SAchim Leubner aac_return_aif(struct aac_softc *sc, struct aac_fib_context *ctx, caddr_t uptr)
3409dce93cd0SAchim Leubner {
3410dce93cd0SAchim Leubner 	int current, error;
3411dce93cd0SAchim Leubner 
3412dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3413dce93cd0SAchim Leubner 
3414dce93cd0SAchim Leubner 	current = ctx->ctx_idx;
3415dce93cd0SAchim Leubner 	if (current == sc->aifq_idx && !ctx->ctx_wrap) {
3416dce93cd0SAchim Leubner 		/* empty */
3417dce93cd0SAchim Leubner 		return (EAGAIN);
3418dce93cd0SAchim Leubner 	}
3419dce93cd0SAchim Leubner 	error =
3420dce93cd0SAchim Leubner 		copyout(&sc->aac_aifq[current], (void *)uptr, sizeof(struct aac_fib));
3421dce93cd0SAchim Leubner 	if (error)
3422dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
3423dce93cd0SAchim Leubner 		    "aac_return_aif: copyout returned %d\n", error);
3424dce93cd0SAchim Leubner 	else {
3425dce93cd0SAchim Leubner 		ctx->ctx_wrap = 0;
3426dce93cd0SAchim Leubner 		ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
3427dce93cd0SAchim Leubner 	}
3428dce93cd0SAchim Leubner 	return(error);
3429dce93cd0SAchim Leubner }
3430dce93cd0SAchim Leubner 
3431dce93cd0SAchim Leubner static int
3432dce93cd0SAchim Leubner aac_get_pci_info(struct aac_softc *sc, caddr_t uptr)
3433dce93cd0SAchim Leubner {
3434dce93cd0SAchim Leubner 	struct aac_pci_info {
3435dce93cd0SAchim Leubner 		u_int32_t bus;
3436dce93cd0SAchim Leubner 		u_int32_t slot;
3437dce93cd0SAchim Leubner 	} pciinf;
3438dce93cd0SAchim Leubner 	int error;
3439dce93cd0SAchim Leubner 
3440dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3441dce93cd0SAchim Leubner 
3442dce93cd0SAchim Leubner 	pciinf.bus = pci_get_bus(sc->aac_dev);
3443dce93cd0SAchim Leubner 	pciinf.slot = pci_get_slot(sc->aac_dev);
3444dce93cd0SAchim Leubner 
3445dce93cd0SAchim Leubner 	error = copyout((caddr_t)&pciinf, uptr,
3446dce93cd0SAchim Leubner 			sizeof(struct aac_pci_info));
3447dce93cd0SAchim Leubner 
3448dce93cd0SAchim Leubner 	return (error);
3449dce93cd0SAchim Leubner }
3450dce93cd0SAchim Leubner 
3451dce93cd0SAchim Leubner static int
3452dce93cd0SAchim Leubner aac_supported_features(struct aac_softc *sc, caddr_t uptr)
3453dce93cd0SAchim Leubner {
3454dce93cd0SAchim Leubner 	struct aac_features f;
3455dce93cd0SAchim Leubner 	int error;
3456dce93cd0SAchim Leubner 
3457dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3458dce93cd0SAchim Leubner 
3459dce93cd0SAchim Leubner 	if ((error = copyin(uptr, &f, sizeof (f))) != 0)
3460dce93cd0SAchim Leubner 		return (error);
3461dce93cd0SAchim Leubner 
3462dce93cd0SAchim Leubner 	/*
3463dce93cd0SAchim Leubner 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
3464dce93cd0SAchim Leubner 	 * ALL zero in the featuresState, the driver will return the current
3465dce93cd0SAchim Leubner 	 * state of all the supported features, the data field will not be
3466dce93cd0SAchim Leubner 	 * valid.
3467dce93cd0SAchim Leubner 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
3468dce93cd0SAchim Leubner 	 * a specific bit set in the featuresState, the driver will return the
3469dce93cd0SAchim Leubner 	 * current state of this specific feature and whatever data that are
3470dce93cd0SAchim Leubner 	 * associated with the feature in the data field or perform whatever
3471dce93cd0SAchim Leubner 	 * action needed indicates in the data field.
3472dce93cd0SAchim Leubner 	 */
3473dce93cd0SAchim Leubner 	 if (f.feat.fValue == 0) {
3474dce93cd0SAchim Leubner 		f.feat.fBits.largeLBA =
3475dce93cd0SAchim Leubner 		    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
3476dce93cd0SAchim Leubner 		f.feat.fBits.JBODSupport = 1;
3477dce93cd0SAchim Leubner 		/* TODO: In the future, add other features state here as well */
3478dce93cd0SAchim Leubner 	} else {
3479dce93cd0SAchim Leubner 		if (f.feat.fBits.largeLBA)
3480dce93cd0SAchim Leubner 			f.feat.fBits.largeLBA =
3481dce93cd0SAchim Leubner 			    (sc->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
3482dce93cd0SAchim Leubner 		/* TODO: Add other features state and data in the future */
3483dce93cd0SAchim Leubner 	}
3484dce93cd0SAchim Leubner 
3485dce93cd0SAchim Leubner 	error = copyout(&f, uptr, sizeof (f));
3486dce93cd0SAchim Leubner 	return (error);
3487dce93cd0SAchim Leubner }
3488dce93cd0SAchim Leubner 
3489dce93cd0SAchim Leubner /*
3490dce93cd0SAchim Leubner  * Give the userland some information about the container.  The AAC arch
3491dce93cd0SAchim Leubner  * expects the driver to be a SCSI passthrough type driver, so it expects
3492dce93cd0SAchim Leubner  * the containers to have b:t:l numbers.  Fake it.
3493dce93cd0SAchim Leubner  */
3494dce93cd0SAchim Leubner static int
3495dce93cd0SAchim Leubner aac_query_disk(struct aac_softc *sc, caddr_t uptr)
3496dce93cd0SAchim Leubner {
3497dce93cd0SAchim Leubner 	struct aac_query_disk query_disk;
3498dce93cd0SAchim Leubner 	struct aac_container *co;
3499dce93cd0SAchim Leubner 	int error, id;
3500dce93cd0SAchim Leubner 
3501dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
3502dce93cd0SAchim Leubner 
3503dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
3504dce93cd0SAchim Leubner 	error = copyin(uptr, (caddr_t)&query_disk,
3505dce93cd0SAchim Leubner 		       sizeof(struct aac_query_disk));
3506dce93cd0SAchim Leubner 	if (error) {
3507dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3508dce93cd0SAchim Leubner 		return (error);
3509dce93cd0SAchim Leubner 	}
3510dce93cd0SAchim Leubner 
3511dce93cd0SAchim Leubner 	id = query_disk.ContainerNumber;
3512dce93cd0SAchim Leubner 	if (id == -1) {
3513dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3514dce93cd0SAchim Leubner 		return (EINVAL);
3515dce93cd0SAchim Leubner 	}
3516dce93cd0SAchim Leubner 
3517dce93cd0SAchim Leubner 	TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) {
3518dce93cd0SAchim Leubner 		if (co->co_mntobj.ObjectId == id)
3519dce93cd0SAchim Leubner 			break;
3520dce93cd0SAchim Leubner 		}
3521dce93cd0SAchim Leubner 
3522dce93cd0SAchim Leubner 	if (co == NULL) {
3523dce93cd0SAchim Leubner 			query_disk.Valid = 0;
3524dce93cd0SAchim Leubner 			query_disk.Locked = 0;
3525dce93cd0SAchim Leubner 			query_disk.Deleted = 1;		/* XXX is this right? */
3526dce93cd0SAchim Leubner 	} else {
3527dce93cd0SAchim Leubner 		query_disk.Valid = 1;
3528dce93cd0SAchim Leubner 		query_disk.Locked = 1;
3529dce93cd0SAchim Leubner 		query_disk.Deleted = 0;
3530dce93cd0SAchim Leubner 		query_disk.Bus = device_get_unit(sc->aac_dev);
3531dce93cd0SAchim Leubner 		query_disk.Target = 0;
3532dce93cd0SAchim Leubner 		query_disk.Lun = 0;
3533dce93cd0SAchim Leubner 		query_disk.UnMapped = 0;
3534dce93cd0SAchim Leubner 	}
3535dce93cd0SAchim Leubner 
3536dce93cd0SAchim Leubner 	error = copyout((caddr_t)&query_disk, uptr,
3537dce93cd0SAchim Leubner 			sizeof(struct aac_query_disk));
3538dce93cd0SAchim Leubner 
3539dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
3540dce93cd0SAchim Leubner 	return (error);
3541dce93cd0SAchim Leubner }
3542dce93cd0SAchim Leubner 
3543dce93cd0SAchim Leubner static void
3544dce93cd0SAchim Leubner aac_container_bus(struct aac_softc *sc)
3545dce93cd0SAchim Leubner {
3546dce93cd0SAchim Leubner 	struct aac_sim *sim;
3547dce93cd0SAchim Leubner 	device_t child;
3548dce93cd0SAchim Leubner 
3549dce93cd0SAchim Leubner 	sim =(struct aac_sim *)malloc(sizeof(struct aac_sim),
3550dce93cd0SAchim Leubner 		M_AACRAIDBUF, M_NOWAIT | M_ZERO);
3551dce93cd0SAchim Leubner 	if (sim == NULL) {
3552dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
3553dce93cd0SAchim Leubner 	    	"No memory to add container bus\n");
3554dce93cd0SAchim Leubner 		panic("Out of memory?!");
355574b8d63dSPedro F. Giffuni 	}
3556dce93cd0SAchim Leubner 	child = device_add_child(sc->aac_dev, "aacraidp", -1);
3557dce93cd0SAchim Leubner 	if (child == NULL) {
3558dce93cd0SAchim Leubner 		device_printf(sc->aac_dev,
3559dce93cd0SAchim Leubner 	    	"device_add_child failed for container bus\n");
3560dce93cd0SAchim Leubner 		free(sim, M_AACRAIDBUF);
3561dce93cd0SAchim Leubner 		panic("Out of memory?!");
3562dce93cd0SAchim Leubner 	}
3563dce93cd0SAchim Leubner 
3564dce93cd0SAchim Leubner 	sim->TargetsPerBus = AAC_MAX_CONTAINERS;
3565dce93cd0SAchim Leubner 	sim->BusNumber = 0;
3566dce93cd0SAchim Leubner 	sim->BusType = CONTAINER_BUS;
3567dce93cd0SAchim Leubner 	sim->InitiatorBusId = -1;
3568dce93cd0SAchim Leubner 	sim->aac_sc = sc;
3569dce93cd0SAchim Leubner 	sim->sim_dev = child;
3570dce93cd0SAchim Leubner 	sim->aac_cam = NULL;
3571dce93cd0SAchim Leubner 
3572dce93cd0SAchim Leubner 	device_set_ivars(child, sim);
3573dce93cd0SAchim Leubner 	device_set_desc(child, "Container Bus");
3574dce93cd0SAchim Leubner 	TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, sim, sim_link);
3575dce93cd0SAchim Leubner 	/*
3576dce93cd0SAchim Leubner 	device_set_desc(child, aac_describe_code(aac_container_types,
3577dce93cd0SAchim Leubner 			mir->MntTable[0].VolType));
3578dce93cd0SAchim Leubner 	*/
3579dce93cd0SAchim Leubner 	bus_generic_attach(sc->aac_dev);
3580dce93cd0SAchim Leubner }
3581dce93cd0SAchim Leubner 
3582dce93cd0SAchim Leubner static void
3583dce93cd0SAchim Leubner aac_get_bus_info(struct aac_softc *sc)
3584dce93cd0SAchim Leubner {
3585dce93cd0SAchim Leubner 	struct aac_fib *fib;
3586dce93cd0SAchim Leubner 	struct aac_ctcfg *c_cmd;
3587dce93cd0SAchim Leubner 	struct aac_ctcfg_resp *c_resp;
3588dce93cd0SAchim Leubner 	struct aac_vmioctl *vmi;
3589dce93cd0SAchim Leubner 	struct aac_vmi_businf_resp *vmi_resp;
3590dce93cd0SAchim Leubner 	struct aac_getbusinf businfo;
3591dce93cd0SAchim Leubner 	struct aac_sim *caminf;
3592dce93cd0SAchim Leubner 	device_t child;
3593dce93cd0SAchim Leubner 	int i, error;
3594dce93cd0SAchim Leubner 
3595dce93cd0SAchim Leubner 	mtx_lock(&sc->aac_io_lock);
3596dce93cd0SAchim Leubner 	aac_alloc_sync_fib(sc, &fib);
3597dce93cd0SAchim Leubner 	c_cmd = (struct aac_ctcfg *)&fib->data[0];
3598dce93cd0SAchim Leubner 	bzero(c_cmd, sizeof(struct aac_ctcfg));
3599dce93cd0SAchim Leubner 
3600dce93cd0SAchim Leubner 	c_cmd->Command = VM_ContainerConfig;
3601dce93cd0SAchim Leubner 	c_cmd->cmd = CT_GET_SCSI_METHOD;
3602dce93cd0SAchim Leubner 	c_cmd->param = 0;
3603dce93cd0SAchim Leubner 
3604dce93cd0SAchim Leubner 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3605dce93cd0SAchim Leubner 	    sizeof(struct aac_ctcfg));
3606dce93cd0SAchim Leubner 	if (error) {
3607dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Error %d sending "
3608dce93cd0SAchim Leubner 		    "VM_ContainerConfig command\n", error);
3609dce93cd0SAchim Leubner 		aac_release_sync_fib(sc);
3610dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3611dce93cd0SAchim Leubner 		return;
3612dce93cd0SAchim Leubner 	}
3613dce93cd0SAchim Leubner 
3614dce93cd0SAchim Leubner 	c_resp = (struct aac_ctcfg_resp *)&fib->data[0];
3615dce93cd0SAchim Leubner 	if (c_resp->Status != ST_OK) {
3616dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "VM_ContainerConfig returned 0x%x\n",
3617dce93cd0SAchim Leubner 		    c_resp->Status);
3618dce93cd0SAchim Leubner 		aac_release_sync_fib(sc);
3619dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3620dce93cd0SAchim Leubner 		return;
3621dce93cd0SAchim Leubner 	}
3622dce93cd0SAchim Leubner 
3623dce93cd0SAchim Leubner 	sc->scsi_method_id = c_resp->param;
3624dce93cd0SAchim Leubner 
3625dce93cd0SAchim Leubner 	vmi = (struct aac_vmioctl *)&fib->data[0];
3626dce93cd0SAchim Leubner 	bzero(vmi, sizeof(struct aac_vmioctl));
3627dce93cd0SAchim Leubner 
3628dce93cd0SAchim Leubner 	vmi->Command = VM_Ioctl;
3629dce93cd0SAchim Leubner 	vmi->ObjType = FT_DRIVE;
3630dce93cd0SAchim Leubner 	vmi->MethId = sc->scsi_method_id;
3631dce93cd0SAchim Leubner 	vmi->ObjId = 0;
3632dce93cd0SAchim Leubner 	vmi->IoctlCmd = GetBusInfo;
3633dce93cd0SAchim Leubner 
3634dce93cd0SAchim Leubner 	error = aac_sync_fib(sc, ContainerCommand, 0, fib,
3635dce93cd0SAchim Leubner 	    sizeof(struct aac_vmi_businf_resp));
3636dce93cd0SAchim Leubner 	if (error) {
3637dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "Error %d sending VMIoctl command\n",
3638dce93cd0SAchim Leubner 		    error);
3639dce93cd0SAchim Leubner 		aac_release_sync_fib(sc);
3640dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3641dce93cd0SAchim Leubner 		return;
3642dce93cd0SAchim Leubner 	}
3643dce93cd0SAchim Leubner 
3644dce93cd0SAchim Leubner 	vmi_resp = (struct aac_vmi_businf_resp *)&fib->data[0];
3645dce93cd0SAchim Leubner 	if (vmi_resp->Status != ST_OK) {
3646dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "VM_Ioctl returned %d\n",
3647dce93cd0SAchim Leubner 		    vmi_resp->Status);
3648dce93cd0SAchim Leubner 		aac_release_sync_fib(sc);
3649dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3650dce93cd0SAchim Leubner 		return;
3651dce93cd0SAchim Leubner 	}
3652dce93cd0SAchim Leubner 
3653dce93cd0SAchim Leubner 	bcopy(&vmi_resp->BusInf, &businfo, sizeof(struct aac_getbusinf));
3654dce93cd0SAchim Leubner 	aac_release_sync_fib(sc);
3655dce93cd0SAchim Leubner 	mtx_unlock(&sc->aac_io_lock);
3656dce93cd0SAchim Leubner 
3657dce93cd0SAchim Leubner 	for (i = 0; i < businfo.BusCount; i++) {
3658dce93cd0SAchim Leubner 		if (businfo.BusValid[i] != AAC_BUS_VALID)
3659dce93cd0SAchim Leubner 			continue;
3660dce93cd0SAchim Leubner 
3661dce93cd0SAchim Leubner 		caminf = (struct aac_sim *)malloc( sizeof(struct aac_sim),
3662dce93cd0SAchim Leubner 		    M_AACRAIDBUF, M_NOWAIT | M_ZERO);
3663dce93cd0SAchim Leubner 		if (caminf == NULL) {
3664dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
3665dce93cd0SAchim Leubner 			    "No memory to add passthrough bus %d\n", i);
3666dce93cd0SAchim Leubner 			break;
366774b8d63dSPedro F. Giffuni 		}
3668dce93cd0SAchim Leubner 
3669dce93cd0SAchim Leubner 		child = device_add_child(sc->aac_dev, "aacraidp", -1);
3670dce93cd0SAchim Leubner 		if (child == NULL) {
3671dce93cd0SAchim Leubner 			device_printf(sc->aac_dev,
3672dce93cd0SAchim Leubner 			    "device_add_child failed for passthrough bus %d\n",
3673dce93cd0SAchim Leubner 			    i);
3674dce93cd0SAchim Leubner 			free(caminf, M_AACRAIDBUF);
3675dce93cd0SAchim Leubner 			break;
3676dce93cd0SAchim Leubner 		}
3677dce93cd0SAchim Leubner 
3678dce93cd0SAchim Leubner 		caminf->TargetsPerBus = businfo.TargetsPerBus;
3679dce93cd0SAchim Leubner 		caminf->BusNumber = i+1;
3680dce93cd0SAchim Leubner 		caminf->BusType = PASSTHROUGH_BUS;
36814f1dfabaSMaxim Sobolev 		caminf->InitiatorBusId = -1;
3682dce93cd0SAchim Leubner 		caminf->aac_sc = sc;
3683dce93cd0SAchim Leubner 		caminf->sim_dev = child;
3684dce93cd0SAchim Leubner 		caminf->aac_cam = NULL;
3685dce93cd0SAchim Leubner 
3686dce93cd0SAchim Leubner 		device_set_ivars(child, caminf);
3687dce93cd0SAchim Leubner 		device_set_desc(child, "SCSI Passthrough Bus");
3688dce93cd0SAchim Leubner 		TAILQ_INSERT_TAIL(&sc->aac_sim_tqh, caminf, sim_link);
3689dce93cd0SAchim Leubner 	}
3690dce93cd0SAchim Leubner }
3691dce93cd0SAchim Leubner 
3692dce93cd0SAchim Leubner /*
3693dce93cd0SAchim Leubner  * Check to see if the kernel is up and running. If we are in a
3694dce93cd0SAchim Leubner  * BlinkLED state, return the BlinkLED code.
3695dce93cd0SAchim Leubner  */
3696dce93cd0SAchim Leubner static u_int32_t
3697dce93cd0SAchim Leubner aac_check_adapter_health(struct aac_softc *sc, u_int8_t *bled)
3698dce93cd0SAchim Leubner {
3699dce93cd0SAchim Leubner 	u_int32_t ret;
3700dce93cd0SAchim Leubner 
3701dce93cd0SAchim Leubner 	ret = AAC_GET_FWSTATUS(sc);
3702dce93cd0SAchim Leubner 
3703dce93cd0SAchim Leubner 	if (ret & AAC_UP_AND_RUNNING)
3704dce93cd0SAchim Leubner 		ret = 0;
3705dce93cd0SAchim Leubner 	else if (ret & AAC_KERNEL_PANIC && bled)
3706dce93cd0SAchim Leubner 		*bled = (ret >> 16) & 0xff;
3707dce93cd0SAchim Leubner 
3708dce93cd0SAchim Leubner 	return (ret);
3709dce93cd0SAchim Leubner }
3710dce93cd0SAchim Leubner 
3711dce93cd0SAchim Leubner /*
3712dce93cd0SAchim Leubner  * Once do an IOP reset, basically have to re-initialize the card as
3713dce93cd0SAchim Leubner  * if coming up from a cold boot, and the driver is responsible for
3714dce93cd0SAchim Leubner  * any IO that was outstanding to the adapter at the time of the IOP
3715dce93cd0SAchim Leubner  * RESET. And prepare the driver for IOP RESET by making the init code
3716dce93cd0SAchim Leubner  * modular with the ability to call it from multiple places.
3717dce93cd0SAchim Leubner  */
3718dce93cd0SAchim Leubner static int
3719dce93cd0SAchim Leubner aac_reset_adapter(struct aac_softc *sc)
3720dce93cd0SAchim Leubner {
3721dce93cd0SAchim Leubner 	struct aac_command *cm;
3722dce93cd0SAchim Leubner 	struct aac_fib *fib;
3723dce93cd0SAchim Leubner 	struct aac_pause_command *pc;
37243fea9c0dSAchim Leubner 	u_int32_t status, reset_mask, waitCount, max_msix_orig;
37254f1dfabaSMaxim Sobolev 	int ret, msi_enabled_orig;
3726dce93cd0SAchim Leubner 
3727dce93cd0SAchim Leubner 	fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
37283fea9c0dSAchim Leubner 	mtx_assert(&sc->aac_io_lock, MA_OWNED);
3729dce93cd0SAchim Leubner 
3730dce93cd0SAchim Leubner 	if (sc->aac_state & AAC_STATE_RESET) {
3731dce93cd0SAchim Leubner 		device_printf(sc->aac_dev, "aac_reset_adapter() already in progress\n");
3732dce93cd0SAchim Leubner 		return (EINVAL);
3733dce93cd0SAchim Leubner 	}
3734dce93cd0SAchim Leubner 	sc->aac_state |= AAC_STATE_RESET;
3735dce93cd0SAchim Leubner 
3736dce93cd0SAchim Leubner 	/* disable interrupt */
37373fea9c0dSAchim Leubner 	AAC_ACCESS_DEVREG(sc, AAC_DISABLE_INTERRUPT);
3738dce93cd0SAchim Leubner 
3739dce93cd0SAchim Leubner 	/*
3740dce93cd0SAchim Leubner 	 * Abort all pending commands:
3741dce93cd0SAchim Leubner 	 * a) on the controller
3742dce93cd0SAchim Leubner 	 */
3743dce93cd0SAchim Leubner 	while ((cm = aac_dequeue_busy(sc)) != NULL) {
3744dce93cd0SAchim Leubner 		cm->cm_flags |= AAC_CMD_RESET;
3745dce93cd0SAchim Leubner 
3746dce93cd0SAchim Leubner 		/* is there a completion handler? */
3747dce93cd0SAchim Leubner 		if (cm->cm_complete != NULL) {
3748dce93cd0SAchim Leubner 			cm->cm_complete(cm);
3749dce93cd0SAchim Leubner 		} else {
3750dce93cd0SAchim Leubner 			/* assume that someone is sleeping on this
3751dce93cd0SAchim Leubner 			 * command
3752dce93cd0SAchim Leubner 			 */
3753dce93cd0SAchim Leubner 			wakeup(cm);
3754dce93cd0SAchim Leubner 		}
3755dce93cd0SAchim Leubner 	}
3756dce93cd0SAchim Leubner 
3757dce93cd0SAchim Leubner 	/* b) in the waiting queues */
3758dce93cd0SAchim Leubner 	while ((cm = aac_dequeue_ready(sc)) != NULL) {
3759dce93cd0SAchim Leubner 		cm->cm_flags |= AAC_CMD_RESET;
3760dce93cd0SAchim Leubner 
3761dce93cd0SAchim Leubner 		/* is there a completion handler? */
3762dce93cd0SAchim Leubner 		if (cm->cm_complete != NULL) {
3763dce93cd0SAchim Leubner 			cm->cm_complete(cm);
3764dce93cd0SAchim Leubner 		} else {
3765dce93cd0SAchim Leubner 			/* assume that someone is sleeping on this
3766dce93cd0SAchim Leubner 			 * command
3767dce93cd0SAchim Leubner 			 */
3768dce93cd0SAchim Leubner 			wakeup(cm);
3769dce93cd0SAchim Leubner 		}
3770dce93cd0SAchim Leubner 	}
3771dce93cd0SAchim Leubner 
3772dce93cd0SAchim Leubner 	/* flush drives */
3773dce93cd0SAchim Leubner 	if (aac_check_adapter_health(sc, NULL) == 0) {
3774dce93cd0SAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
3775dce93cd0SAchim Leubner 		(void) aacraid_shutdown(sc->aac_dev);
3776dce93cd0SAchim Leubner 		mtx_lock(&sc->aac_io_lock);
3777dce93cd0SAchim Leubner 	}
3778dce93cd0SAchim Leubner 
3779dce93cd0SAchim Leubner 	/* execute IOP reset */
3780dce93cd0SAchim Leubner 	if (sc->aac_support_opt2 & AAC_SUPPORTED_MU_RESET) {
3781dce93cd0SAchim Leubner 		AAC_MEM0_SETREG4(sc, AAC_IRCSR, AAC_IRCSR_CORES_RST);
3782dce93cd0SAchim Leubner 
3783dce93cd0SAchim Leubner 		/* We need to wait for 5 seconds before accessing the MU again
3784dce93cd0SAchim Leubner 		 * 10000 * 100us = 1000,000us = 1000ms = 1s
3785dce93cd0SAchim Leubner 		 */
3786dce93cd0SAchim Leubner 		waitCount = 5 * 10000;
3787dce93cd0SAchim Leubner 		while (waitCount) {
3788dce93cd0SAchim Leubner 			DELAY(100);			/* delay 100 microseconds */
3789dce93cd0SAchim Leubner 			waitCount--;
3790dce93cd0SAchim Leubner 		}
37914f1dfabaSMaxim Sobolev 	} else {
37924f1dfabaSMaxim Sobolev 		ret = aacraid_sync_command(sc, AAC_IOP_RESET_ALWAYS,
37934f1dfabaSMaxim Sobolev 			0, 0, 0, 0, &status, &reset_mask);
37944f1dfabaSMaxim Sobolev 		if (ret && !sc->doorbell_mask) {
3795dce93cd0SAchim Leubner 			/* call IOP_RESET for older firmware */
37964f1dfabaSMaxim Sobolev 			if ((aacraid_sync_command(sc, AAC_IOP_RESET, 0,0,0,0,
37974f1dfabaSMaxim Sobolev 			    &status, NULL)) != 0) {
37984f1dfabaSMaxim Sobolev 				if (status == AAC_SRB_STS_INVALID_REQUEST) {
37994f1dfabaSMaxim Sobolev 					device_printf(sc->aac_dev,
38004f1dfabaSMaxim Sobolev 					    "IOP_RESET not supported\n");
38014f1dfabaSMaxim Sobolev 				} else {
3802dce93cd0SAchim Leubner 					/* probably timeout */
38034f1dfabaSMaxim Sobolev 					device_printf(sc->aac_dev,
38044f1dfabaSMaxim Sobolev 					    "IOP_RESET failed\n");
38054f1dfabaSMaxim Sobolev 				}
3806dce93cd0SAchim Leubner 
3807dce93cd0SAchim Leubner 				/* unwind aac_shutdown() */
3808dce93cd0SAchim Leubner 				aac_alloc_sync_fib(sc, &fib);
3809dce93cd0SAchim Leubner 				pc = (struct aac_pause_command *)&fib->data[0];
3810dce93cd0SAchim Leubner 				pc->Command = VM_ContainerConfig;
3811dce93cd0SAchim Leubner 				pc->Type = CT_PAUSE_IO;
3812dce93cd0SAchim Leubner 				pc->Timeout = 1;
3813dce93cd0SAchim Leubner 				pc->Min = 1;
3814dce93cd0SAchim Leubner 				pc->NoRescan = 1;
3815dce93cd0SAchim Leubner 
38164f1dfabaSMaxim Sobolev 				(void) aac_sync_fib(sc, ContainerCommand, 0,
38174f1dfabaSMaxim Sobolev 				    fib, sizeof (struct aac_pause_command));
3818dce93cd0SAchim Leubner 				aac_release_sync_fib(sc);
3819dce93cd0SAchim Leubner 
3820dce93cd0SAchim Leubner 				goto finish;
3821dce93cd0SAchim Leubner 			}
38224f1dfabaSMaxim Sobolev 		} else if (sc->doorbell_mask) {
38234f1dfabaSMaxim Sobolev 			ret = 0;
38244f1dfabaSMaxim Sobolev 			reset_mask = sc->doorbell_mask;
38254f1dfabaSMaxim Sobolev 		}
38264f1dfabaSMaxim Sobolev 		if (!ret &&
38274f1dfabaSMaxim Sobolev 		    (sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET)) {
3828dce93cd0SAchim Leubner 			AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask);
38293fea9c0dSAchim Leubner 			/*
38304f1dfabaSMaxim Sobolev 			 * We need to wait for 5 seconds before accessing the
38314f1dfabaSMaxim Sobolev 			 * doorbell again;
38324f1dfabaSMaxim Sobolev 			 * 10000 * 100us = 1000,000us = 1000ms = 1s
3833dce93cd0SAchim Leubner 			 */
3834dce93cd0SAchim Leubner 			waitCount = 5 * 10000;
3835dce93cd0SAchim Leubner 			while (waitCount) {
3836dce93cd0SAchim Leubner 				DELAY(100);	/* delay 100 microseconds */
3837dce93cd0SAchim Leubner 				waitCount--;
3838dce93cd0SAchim Leubner 			}
3839dce93cd0SAchim Leubner 		}
38404f1dfabaSMaxim Sobolev 	}
3841dce93cd0SAchim Leubner 
3842dce93cd0SAchim Leubner 	/*
3843dce93cd0SAchim Leubner 	 * Initialize the adapter.
3844dce93cd0SAchim Leubner 	 */
38453fea9c0dSAchim Leubner 	max_msix_orig = sc->aac_max_msix;
38463fea9c0dSAchim Leubner 	msi_enabled_orig = sc->msi_enabled;
38473fea9c0dSAchim Leubner 	sc->msi_enabled = FALSE;
3848dce93cd0SAchim Leubner 	if (aac_check_firmware(sc) != 0)
3849dce93cd0SAchim Leubner 		goto finish;
3850dce93cd0SAchim Leubner 	if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) {
38513fea9c0dSAchim Leubner 		sc->aac_max_msix = max_msix_orig;
38523fea9c0dSAchim Leubner 		if (msi_enabled_orig) {
38533fea9c0dSAchim Leubner 			sc->msi_enabled = msi_enabled_orig;
38543fea9c0dSAchim Leubner 			AAC_ACCESS_DEVREG(sc, AAC_ENABLE_MSIX);
38553fea9c0dSAchim Leubner 		}
38563fea9c0dSAchim Leubner 		mtx_unlock(&sc->aac_io_lock);
38573fea9c0dSAchim Leubner 		aac_init(sc);
38583fea9c0dSAchim Leubner 		mtx_lock(&sc->aac_io_lock);
3859dce93cd0SAchim Leubner 	}
3860dce93cd0SAchim Leubner 
3861dce93cd0SAchim Leubner finish:
3862dce93cd0SAchim Leubner 	sc->aac_state &= ~AAC_STATE_RESET;
38633fea9c0dSAchim Leubner 	AAC_ACCESS_DEVREG(sc, AAC_ENABLE_INTERRUPT);
3864dce93cd0SAchim Leubner 	aacraid_startio(sc);
3865dce93cd0SAchim Leubner 	return (0);
3866dce93cd0SAchim Leubner }
3867