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