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