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