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