mfi.c revision 224041
1157114Sscottl/*-
2157114Sscottl * Copyright (c) 2006 IronPort Systems
3157114Sscottl * All rights reserved.
4157114Sscottl *
5157114Sscottl * Redistribution and use in source and binary forms, with or without
6157114Sscottl * modification, are permitted provided that the following conditions
7157114Sscottl * are met:
8157114Sscottl * 1. Redistributions of source code must retain the above copyright
9157114Sscottl *    notice, this list of conditions and the following disclaimer.
10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11157114Sscottl *    notice, this list of conditions and the following disclaimer in the
12157114Sscottl *    documentation and/or other materials provided with the distribution.
13157114Sscottl *
14157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17157114Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23157114Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24157114Sscottl * SUCH DAMAGE.
25157114Sscottl */
26171980Sscottl/*-
27171980Sscottl * Copyright (c) 2007 LSI Corp.
28171980Sscottl * Copyright (c) 2007 Rajesh Prabhakaran.
29171980Sscottl * All rights reserved.
30171980Sscottl *
31171980Sscottl * Redistribution and use in source and binary forms, with or without
32171980Sscottl * modification, are permitted provided that the following conditions
33171980Sscottl * are met:
34171980Sscottl * 1. Redistributions of source code must retain the above copyright
35171980Sscottl *    notice, this list of conditions and the following disclaimer.
36171980Sscottl * 2. Redistributions in binary form must reproduce the above copyright
37171980Sscottl *    notice, this list of conditions and the following disclaimer in the
38171980Sscottl *    documentation and/or other materials provided with the distribution.
39171980Sscottl *
40171980Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
41171980Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42171980Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43171980Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44171980Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45171980Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46171980Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47171980Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48171980Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49171980Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50171980Sscottl * SUCH DAMAGE.
51171980Sscottl */
52157114Sscottl
53157114Sscottl#include <sys/cdefs.h>
54157114Sscottl__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi.c 224041 2011-07-14 20:20:33Z jhb $");
55157114Sscottl
56157114Sscottl#include "opt_mfi.h"
57157114Sscottl
58157114Sscottl#include <sys/param.h>
59157114Sscottl#include <sys/systm.h>
60162118Sambrisko#include <sys/sysctl.h>
61157114Sscottl#include <sys/malloc.h>
62157114Sscottl#include <sys/kernel.h>
63158737Sambrisko#include <sys/poll.h>
64158737Sambrisko#include <sys/selinfo.h>
65157114Sscottl#include <sys/bus.h>
66157114Sscottl#include <sys/conf.h>
67157114Sscottl#include <sys/eventhandler.h>
68157114Sscottl#include <sys/rman.h>
69157114Sscottl#include <sys/bus_dma.h>
70157114Sscottl#include <sys/bio.h>
71157114Sscottl#include <sys/ioccom.h>
72158737Sambrisko#include <sys/uio.h>
73158737Sambrisko#include <sys/proc.h>
74163398Sscottl#include <sys/signalvar.h>
75157114Sscottl
76157114Sscottl#include <machine/bus.h>
77157114Sscottl#include <machine/resource.h>
78157114Sscottl
79157114Sscottl#include <dev/mfi/mfireg.h>
80157114Sscottl#include <dev/mfi/mfi_ioctl.h>
81157114Sscottl#include <dev/mfi/mfivar.h>
82157114Sscottl
83157114Sscottlstatic int	mfi_alloc_commands(struct mfi_softc *);
84157114Sscottlstatic int	mfi_comms_init(struct mfi_softc *);
85159811Spsstatic int	mfi_wait_command(struct mfi_softc *, struct mfi_command *);
86157114Sscottlstatic int	mfi_get_controller_info(struct mfi_softc *);
87158737Sambriskostatic int	mfi_get_log_state(struct mfi_softc *,
88159806Sps		    struct mfi_evt_log_state **);
89180037Sjhbstatic int	mfi_parse_entries(struct mfi_softc *, int, int);
90159806Spsstatic int	mfi_dcmd_command(struct mfi_softc *, struct mfi_command **,
91159806Sps		    uint32_t, void **, size_t);
92157114Sscottlstatic void	mfi_data_cb(void *, bus_dma_segment_t *, int, int);
93157114Sscottlstatic void	mfi_startup(void *arg);
94157114Sscottlstatic void	mfi_intr(void *arg);
95159811Spsstatic void	mfi_ldprobe(struct mfi_softc *sc);
96158737Sambriskostatic int	mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
97158737Sambriskostatic void	mfi_aen_complete(struct mfi_command *);
98158737Sambriskostatic int	mfi_aen_setup(struct mfi_softc *, uint32_t);
99159811Spsstatic int	mfi_add_ld(struct mfi_softc *sc, int);
100159811Spsstatic void	mfi_add_ld_complete(struct mfi_command *);
101157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *);
102157114Sscottlstatic void	mfi_bio_complete(struct mfi_command *);
103157114Sscottlstatic int	mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
104157114Sscottlstatic int	mfi_send_frame(struct mfi_softc *, struct mfi_command *);
105157114Sscottlstatic void	mfi_complete(struct mfi_softc *, struct mfi_command *);
106158737Sambriskostatic int	mfi_abort(struct mfi_softc *, struct mfi_command *);
107192450Simpstatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
108162619Sscottlstatic void	mfi_timeout(void *);
109178968Sscottlstatic int	mfi_user_command(struct mfi_softc *,
110178968Sscottl		    struct mfi_ioc_passthru *);
111171980Sscottlstatic void 	mfi_enable_intr_xscale(struct mfi_softc *sc);
112171980Sscottlstatic void 	mfi_enable_intr_ppc(struct mfi_softc *sc);
113171980Sscottlstatic int32_t 	mfi_read_fw_status_xscale(struct mfi_softc *sc);
114171980Sscottlstatic int32_t 	mfi_read_fw_status_ppc(struct mfi_softc *sc);
115171980Sscottlstatic int 	mfi_check_clear_intr_xscale(struct mfi_softc *sc);
116171980Sscottlstatic int 	mfi_check_clear_intr_ppc(struct mfi_softc *sc);
117171980Sscottlstatic void 	mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
118171980Sscottlstatic void 	mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
119157114Sscottl
120162118SambriskoSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
121162118Sambriskostatic int	mfi_event_locale = MFI_EVT_LOCALE_ALL;
122162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale);
123162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale,
124162118Sambrisko            0, "event message locale");
125162473Sambrisko
126165852Sscottlstatic int	mfi_event_class = MFI_EVT_CLASS_INFO;
127162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class);
128162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class,
129162118Sambrisko          0, "event message class");
130162118Sambrisko
131178968Sscottlstatic int	mfi_max_cmds = 128;
132178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
133178968SscottlSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,
134178968Sscottl	   0, "Max commands");
135178968Sscottl
136157114Sscottl/* Management interface */
137157114Sscottlstatic d_open_t		mfi_open;
138157114Sscottlstatic d_close_t	mfi_close;
139157114Sscottlstatic d_ioctl_t	mfi_ioctl;
140158737Sambriskostatic d_poll_t		mfi_poll;
141157114Sscottl
142157114Sscottlstatic struct cdevsw mfi_cdevsw = {
143157114Sscottl	.d_version = 	D_VERSION,
144157114Sscottl	.d_flags =	0,
145157114Sscottl	.d_open = 	mfi_open,
146157114Sscottl	.d_close =	mfi_close,
147157114Sscottl	.d_ioctl =	mfi_ioctl,
148158737Sambrisko	.d_poll =	mfi_poll,
149157114Sscottl	.d_name =	"mfi",
150157114Sscottl};
151157114Sscottl
152157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
153157114Sscottl
154158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
155157114Sscottl
156171980Sscottlstatic void
157171980Sscottlmfi_enable_intr_xscale(struct mfi_softc *sc)
158171980Sscottl{
159171980Sscottl	MFI_WRITE4(sc, MFI_OMSK, 0x01);
160171980Sscottl}
161171980Sscottl
162171980Sscottlstatic void
163171980Sscottlmfi_enable_intr_ppc(struct mfi_softc *sc)
164171980Sscottl{
165171980Sscottl	MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
166184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
167184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
168184897Sambrisko	} else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
169184897Sambrisko		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
170184897Sambrisko	}
171171980Sscottl}
172171980Sscottl
173171980Sscottlstatic int32_t
174171980Sscottlmfi_read_fw_status_xscale(struct mfi_softc *sc)
175171980Sscottl{
176171980Sscottl	return MFI_READ4(sc, MFI_OMSG0);
177171980Sscottl}
178184897Sambrisko
179171980Sscottlstatic int32_t
180171980Sscottlmfi_read_fw_status_ppc(struct mfi_softc *sc)
181171980Sscottl{
182171980Sscottl	return MFI_READ4(sc, MFI_OSP0);
183171980Sscottl}
184171980Sscottl
185184897Sambriskostatic int
186171980Sscottlmfi_check_clear_intr_xscale(struct mfi_softc *sc)
187171980Sscottl{
188171980Sscottl	int32_t status;
189171980Sscottl
190171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
191171980Sscottl	if ((status & MFI_OSTS_INTR_VALID) == 0)
192171980Sscottl		return 1;
193171980Sscottl
194171980Sscottl	MFI_WRITE4(sc, MFI_OSTS, status);
195171980Sscottl	return 0;
196182085Simp}
197171980Sscottl
198184897Sambriskostatic int
199171980Sscottlmfi_check_clear_intr_ppc(struct mfi_softc *sc)
200171980Sscottl{
201171980Sscottl	int32_t status;
202171980Sscottl
203171980Sscottl	status = MFI_READ4(sc, MFI_OSTS);
204184897Sambrisko	if (sc->mfi_flags & MFI_FLAGS_1078) {
205184897Sambrisko		if (!(status & MFI_1078_RM)) {
206184897Sambrisko			return 1;
207184897Sambrisko		}
208184897Sambrisko	} else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
209184897Sambrisko		if (!(status & MFI_GEN2_RM)) {
210184897Sambrisko			return 1;
211184897Sambrisko		}
212184897Sambrisko	}
213171980Sscottl
214171980Sscottl	MFI_WRITE4(sc, MFI_ODCR0, status);
215171980Sscottl	return 0;
216182085Simp}
217171980Sscottl
218184897Sambriskostatic void
219171980Sscottlmfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
220171980Sscottl{
221171980Sscottl	MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
222171980Sscottl}
223184897Sambrisko
224184897Sambriskostatic void
225171980Sscottlmfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
226171980Sscottl{
227171980Sscottl	MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
228171980Sscottl}
229171980Sscottl
230157114Sscottlstatic int
231157114Sscottlmfi_transition_firmware(struct mfi_softc *sc)
232157114Sscottl{
233194851Sscottl	uint32_t fw_state, cur_state;
234157114Sscottl	int max_wait, i;
235157114Sscottl
236171980Sscottl	fw_state = sc->mfi_read_fw_status(sc)& MFI_FWSTATE_MASK;
237157114Sscottl	while (fw_state != MFI_FWSTATE_READY) {
238157114Sscottl		if (bootverbose)
239157114Sscottl			device_printf(sc->mfi_dev, "Waiting for firmware to "
240171980Sscottl			"become ready\n");
241157114Sscottl		cur_state = fw_state;
242157114Sscottl		switch (fw_state) {
243157114Sscottl		case MFI_FWSTATE_FAULT:
244157114Sscottl			device_printf(sc->mfi_dev, "Firmware fault\n");
245157114Sscottl			return (ENXIO);
246157114Sscottl		case MFI_FWSTATE_WAIT_HANDSHAKE:
247157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
248157114Sscottl			max_wait = 2;
249157114Sscottl			break;
250157114Sscottl		case MFI_FWSTATE_OPERATIONAL:
251157114Sscottl			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
252157114Sscottl			max_wait = 10;
253157114Sscottl			break;
254157114Sscottl		case MFI_FWSTATE_UNDEFINED:
255157114Sscottl		case MFI_FWSTATE_BB_INIT:
256157114Sscottl			max_wait = 2;
257157114Sscottl			break;
258157114Sscottl		case MFI_FWSTATE_FW_INIT:
259157114Sscottl		case MFI_FWSTATE_DEVICE_SCAN:
260157114Sscottl		case MFI_FWSTATE_FLUSH_CACHE:
261157114Sscottl			max_wait = 20;
262157114Sscottl			break;
263224041Sjhb		case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
264224041Sjhb			MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
265224041Sjhb			max_wait = 10;
266224041Sjhb			break;
267157114Sscottl		default:
268224041Sjhb			device_printf(sc->mfi_dev,"Unknown firmware state %#x\n",
269157114Sscottl			    fw_state);
270157114Sscottl			return (ENXIO);
271157114Sscottl		}
272157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
273171980Sscottl			fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK;
274157114Sscottl			if (fw_state == cur_state)
275157114Sscottl				DELAY(100000);
276157114Sscottl			else
277157114Sscottl				break;
278157114Sscottl		}
279157114Sscottl		if (fw_state == cur_state) {
280224041Sjhb			device_printf(sc->mfi_dev, "Firmware stuck in state "
281157114Sscottl			    "%#x\n", fw_state);
282157114Sscottl			return (ENXIO);
283157114Sscottl		}
284157114Sscottl	}
285157114Sscottl	return (0);
286157114Sscottl}
287157114Sscottl
288157114Sscottlstatic void
289157114Sscottlmfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
290157114Sscottl{
291157114Sscottl	uint32_t *addr;
292157114Sscottl
293157114Sscottl	addr = arg;
294157114Sscottl	*addr = segs[0].ds_addr;
295157114Sscottl}
296157114Sscottl
297157114Sscottlint
298157114Sscottlmfi_attach(struct mfi_softc *sc)
299157114Sscottl{
300157114Sscottl	uint32_t status;
301157114Sscottl	int error, commsz, framessz, sensesz;
302162458Sscottl	int frames, unit, max_fw_sge;
303157114Sscottl
304186132Sambrisko	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.00 \n");
305186132Sambrisko
306157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
307171821Sjhb	sx_init(&sc->mfi_config_lock, "MFI config");
308157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
309158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
310169611Sscottl	TAILQ_INIT(&sc->mfi_cam_ccbq);
311157114Sscottl
312157114Sscottl	mfi_initq_free(sc);
313157114Sscottl	mfi_initq_ready(sc);
314157114Sscottl	mfi_initq_busy(sc);
315157114Sscottl	mfi_initq_bio(sc);
316157114Sscottl
317171980Sscottl	if (sc->mfi_flags & MFI_FLAGS_1064R) {
318171980Sscottl		sc->mfi_enable_intr = mfi_enable_intr_xscale;
319171980Sscottl		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
320171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
321171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
322171980Sscottl	}
323171980Sscottl	else {
324171980Sscottl		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
325171980Sscottl 		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
326171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
327171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
328171980Sscottl	}
329171980Sscottl
330171980Sscottl
331157114Sscottl	/* Before we get too far, see if the firmware is working */
332157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
333157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
334157114Sscottl		    "error %d\n", error);
335157114Sscottl		return (ENXIO);
336157114Sscottl	}
337157114Sscottl
338157114Sscottl	/*
339157114Sscottl	 * Get information needed for sizing the contiguous memory for the
340157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
341157114Sscottl	 * we will never need more than what's required for MAXPHYS.
342157114Sscottl	 * It would be nice if these constants were available at runtime
343157114Sscottl	 * instead of compile time.
344157114Sscottl	 */
345171980Sscottl	status = sc->mfi_read_fw_status(sc);
346157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
347162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
348195534Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
349157114Sscottl
350157114Sscottl	/*
351157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
352157114Sscottl	 * and for various internal data queries.
353157114Sscottl	 */
354157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
355157114Sscottl				1, 0,			/* algnmnt, boundary */
356157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
357157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
358157114Sscottl				NULL, NULL,		/* filter, filterarg */
359157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
360162458Sscottl				sc->mfi_max_sge,	/* nsegments */
361157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
362157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
363157114Sscottl				busdma_lock_mutex,	/* lockfunc */
364157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
365157114Sscottl				&sc->mfi_buffer_dmat)) {
366157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
367157114Sscottl		return (ENOMEM);
368157114Sscottl	}
369157114Sscottl
370157114Sscottl	/*
371157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
372157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
373157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
374157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
375157114Sscottl	 */
376157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
377157114Sscottl	    sizeof(struct mfi_hwcomms);
378157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
379157114Sscottl				1, 0,			/* algnmnt, boundary */
380157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
381157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
382157114Sscottl				NULL, NULL,		/* filter, filterarg */
383157114Sscottl				commsz,			/* maxsize */
384157114Sscottl				1,			/* msegments */
385157114Sscottl				commsz,			/* maxsegsize */
386157114Sscottl				0,			/* flags */
387157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
388157114Sscottl				&sc->mfi_comms_dmat)) {
389157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
390157114Sscottl		return (ENOMEM);
391157114Sscottl	}
392157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
393157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
394157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
395157114Sscottl		return (ENOMEM);
396157114Sscottl	}
397157114Sscottl	bzero(sc->mfi_comms, commsz);
398157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
399157114Sscottl	    sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
400157114Sscottl
401157114Sscottl	/*
402157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
403162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
404162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
405162458Sscottl         * additional frames for holding sg lists or other data.
406157114Sscottl	 * The assumption here is that the SG list will start at the second
407162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
408162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
409162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
410157114Sscottl	 */
411157114Sscottl	if (sizeof(bus_addr_t) == 8) {
412162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
413157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
414157114Sscottl	} else {
415162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
416157114Sscottl	}
417162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
418162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
419162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
420157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
421157114Sscottl				64, 0,			/* algnmnt, boundary */
422157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
423157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
424157114Sscottl				NULL, NULL,		/* filter, filterarg */
425157114Sscottl				framessz,		/* maxsize */
426157114Sscottl				1,			/* nsegments */
427157114Sscottl				framessz,		/* maxsegsize */
428157114Sscottl				0,			/* flags */
429157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
430157114Sscottl				&sc->mfi_frames_dmat)) {
431157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
432157114Sscottl		return (ENOMEM);
433157114Sscottl	}
434157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
435157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
436157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
437157114Sscottl		return (ENOMEM);
438157114Sscottl	}
439157114Sscottl	bzero(sc->mfi_frames, framessz);
440157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
441157114Sscottl	    sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
442157114Sscottl
443157114Sscottl	/*
444157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
445157114Sscottl	 * lower 4GB for efficiency
446157114Sscottl	 */
447157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
448157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
449157114Sscottl				4, 0,			/* algnmnt, boundary */
450157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
451157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
452157114Sscottl				NULL, NULL,		/* filter, filterarg */
453157114Sscottl				sensesz,		/* maxsize */
454157114Sscottl				1,			/* nsegments */
455157114Sscottl				sensesz,		/* maxsegsize */
456157114Sscottl				0,			/* flags */
457157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
458157114Sscottl				&sc->mfi_sense_dmat)) {
459157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
460157114Sscottl		return (ENOMEM);
461157114Sscottl	}
462157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
463157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
464157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
465157114Sscottl		return (ENOMEM);
466157114Sscottl	}
467157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
468157114Sscottl	    sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
469157114Sscottl
470157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
471157114Sscottl		return (error);
472157114Sscottl
473157114Sscottl	if ((error = mfi_comms_init(sc)) != 0)
474157114Sscottl		return (error);
475157114Sscottl
476157114Sscottl	if ((error = mfi_get_controller_info(sc)) != 0)
477157114Sscottl		return (error);
478157114Sscottl
479163398Sscottl	mtx_lock(&sc->mfi_io_lock);
480163398Sscottl	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
481163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
482157114Sscottl		return (error);
483163398Sscottl	}
484163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
485157114Sscottl
486157114Sscottl	/*
487157114Sscottl	 * Set up the interrupt handler.  XXX This should happen in
488157114Sscottl	 * mfi_pci.c
489157114Sscottl	 */
490157114Sscottl	sc->mfi_irq_rid = 0;
491157114Sscottl	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
492157114Sscottl	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
493157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
494157114Sscottl		return (EINVAL);
495157114Sscottl	}
496157114Sscottl	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
497166901Spiso	    NULL, mfi_intr, sc, &sc->mfi_intr)) {
498157114Sscottl		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
499157114Sscottl		return (EINVAL);
500157114Sscottl	}
501157114Sscottl
502157114Sscottl	/* Register a config hook to probe the bus for arrays */
503157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
504157114Sscottl	sc->mfi_ich.ich_arg = sc;
505157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
506157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
507157114Sscottl		    "hook\n");
508157114Sscottl		return (EINVAL);
509157114Sscottl	}
510157114Sscottl
511157114Sscottl	/*
512157114Sscottl	 * Register a shutdown handler.
513157114Sscottl	 */
514157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
515157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
516157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
517157114Sscottl		    "registration failed\n");
518157114Sscottl	}
519157114Sscottl
520157114Sscottl	/*
521157114Sscottl	 * Create the control device for doing management
522157114Sscottl	 */
523157114Sscottl	unit = device_get_unit(sc->mfi_dev);
524157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
525157114Sscottl	    0640, "mfi%d", unit);
526158737Sambrisko	if (unit == 0)
527158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
528157114Sscottl	if (sc->mfi_cdev != NULL)
529157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
530171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
531171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
532171821Sjhb	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
533171821Sjhb	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
534171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
535171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
536171821Sjhb	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
537171821Sjhb	    &sc->mfi_keep_deleted_volumes, 0,
538171821Sjhb	    "Don't detach the mfid device for a busy volume that is deleted");
539157114Sscottl
540169611Sscottl	device_add_child(sc->mfi_dev, "mfip", -1);
541169611Sscottl	bus_generic_attach(sc->mfi_dev);
542169611Sscottl
543162619Sscottl	/* Start the timeout watchdog */
544178250Skris	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
545162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
546162619Sscottl	    mfi_timeout, sc);
547162619Sscottl
548157114Sscottl	return (0);
549157114Sscottl}
550157114Sscottl
551157114Sscottlstatic int
552157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
553157114Sscottl{
554157114Sscottl	struct mfi_command *cm;
555157114Sscottl	int i, ncmds;
556157114Sscottl
557157114Sscottl	/*
558157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
559157114Sscottl	 * demand later like 'aac' does?
560157114Sscottl	 */
561178968Sscottl	ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds);
562178968Sscottl	if (bootverbose)
563178968Sscottl		device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver "
564178968Sscottl		   "pool to %d\n", sc->mfi_max_fw_cmds, ncmds);
565178968Sscottl
566157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
567157114Sscottl	    M_WAITOK | M_ZERO);
568157114Sscottl
569157114Sscottl	for (i = 0; i < ncmds; i++) {
570157114Sscottl		cm = &sc->mfi_commands[i];
571158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
572162458Sscottl		    sc->mfi_cmd_size * i);
573157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
574162458Sscottl		    sc->mfi_cmd_size * i;
575157114Sscottl		cm->cm_frame->header.context = i;
576157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
577157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
578157114Sscottl		cm->cm_sc = sc;
579162619Sscottl		cm->cm_index = i;
580157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
581157114Sscottl		    &cm->cm_dmamap) == 0)
582157114Sscottl			mfi_release_command(cm);
583157114Sscottl		else
584157114Sscottl			break;
585157114Sscottl		sc->mfi_total_cmds++;
586157114Sscottl	}
587157114Sscottl
588157114Sscottl	return (0);
589157114Sscottl}
590157114Sscottl
591169611Sscottlvoid
592157114Sscottlmfi_release_command(struct mfi_command *cm)
593157114Sscottl{
594163398Sscottl	struct mfi_frame_header *hdr;
595157114Sscottl	uint32_t *hdr_data;
596157114Sscottl
597157114Sscottl	/*
598157114Sscottl	 * Zero out the important fields of the frame, but make sure the
599165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
600165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
601157114Sscottl	 */
602163398Sscottl	hdr = &cm->cm_frame->header;
603175897Sambrisko	if (cm->cm_data != NULL && hdr->sg_count) {
604163398Sscottl		cm->cm_sg->sg32[0].len = 0;
605163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
606163398Sscottl	}
607165727Sscottl
608165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
609165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
610165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
611165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
612165727Sscottl	hdr_data[5] = 0;	/* data_len */
613165727Sscottl
614157114Sscottl	cm->cm_extra_frames = 0;
615157114Sscottl	cm->cm_flags = 0;
616157114Sscottl	cm->cm_complete = NULL;
617157114Sscottl	cm->cm_private = NULL;
618169611Sscottl	cm->cm_data = NULL;
619157114Sscottl	cm->cm_sg = 0;
620157114Sscottl	cm->cm_total_frame_size = 0;
621163398Sscottl
622157114Sscottl	mfi_enqueue_free(cm);
623157114Sscottl}
624157114Sscottl
625157114Sscottlstatic int
626159806Spsmfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
627159806Sps    void **bufp, size_t bufsize)
628159806Sps{
629159806Sps	struct mfi_command *cm;
630159806Sps	struct mfi_dcmd_frame *dcmd;
631159806Sps	void *buf = NULL;
632159806Sps
633159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
634159806Sps
635159806Sps	cm = mfi_dequeue_free(sc);
636159806Sps	if (cm == NULL)
637159806Sps		return (EBUSY);
638159806Sps
639159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
640159806Sps		if (*bufp == NULL) {
641159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
642159806Sps			if (buf == NULL) {
643159806Sps				mfi_release_command(cm);
644159806Sps				return (ENOMEM);
645159806Sps			}
646159806Sps			*bufp = buf;
647159806Sps		} else {
648159806Sps			buf = *bufp;
649159806Sps		}
650159806Sps	}
651159806Sps
652159806Sps	dcmd =  &cm->cm_frame->dcmd;
653159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
654159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
655159806Sps	dcmd->header.timeout = 0;
656159806Sps	dcmd->header.flags = 0;
657159806Sps	dcmd->header.data_len = bufsize;
658159806Sps	dcmd->opcode = opcode;
659159806Sps	cm->cm_sg = &dcmd->sgl;
660159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
661159806Sps	cm->cm_flags = 0;
662159806Sps	cm->cm_data = buf;
663159806Sps	cm->cm_private = buf;
664159806Sps	cm->cm_len = bufsize;
665159806Sps
666159806Sps	*cmp = cm;
667159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
668159806Sps		*bufp = buf;
669159806Sps	return (0);
670159806Sps}
671159806Sps
672159806Spsstatic int
673157114Sscottlmfi_comms_init(struct mfi_softc *sc)
674157114Sscottl{
675157114Sscottl	struct mfi_command *cm;
676157114Sscottl	struct mfi_init_frame *init;
677157114Sscottl	struct mfi_init_qinfo *qinfo;
678157114Sscottl	int error;
679157114Sscottl
680163398Sscottl	mtx_lock(&sc->mfi_io_lock);
681157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
682157114Sscottl		return (EBUSY);
683157114Sscottl
684157114Sscottl	/*
685157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
686157114Sscottl	 * object;
687157114Sscottl	 */
688157114Sscottl	init = &cm->cm_frame->init;
689157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
690157114Sscottl
691157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
692157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
693157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
694157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
695157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
696157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
697157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
698157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
699157114Sscottl
700157114Sscottl	init->header.cmd = MFI_CMD_INIT;
701157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
702157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
703164375Sscottl	cm->cm_data = NULL;
704164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
705157114Sscottl
706164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
707157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
708163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
709157114Sscottl		return (error);
710157114Sscottl	}
711157114Sscottl	mfi_release_command(cm);
712163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
713157114Sscottl
714157114Sscottl	return (0);
715157114Sscottl}
716157114Sscottl
717157114Sscottlstatic int
718157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
719157114Sscottl{
720159806Sps	struct mfi_command *cm = NULL;
721159806Sps	struct mfi_ctrl_info *ci = NULL;
722157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
723157114Sscottl	int error;
724157114Sscottl
725159806Sps	mtx_lock(&sc->mfi_io_lock);
726159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
727159806Sps	    (void **)&ci, sizeof(*ci));
728159806Sps	if (error)
729159806Sps		goto out;
730157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
731157114Sscottl
732157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
733157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
734162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
735157114Sscottl		    MFI_SECTOR_LEN;
736159806Sps		error = 0;
737159806Sps		goto out;
738157114Sscottl	}
739157114Sscottl
740157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
741157114Sscottl	    BUS_DMASYNC_POSTREAD);
742157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
743157114Sscottl
744157114Sscottl	max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io;
745157114Sscottl	max_sectors_2 = ci->max_request_size;
746157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
747157114Sscottl
748159806Spsout:
749159806Sps	if (ci)
750159806Sps		free(ci, M_MFIBUF);
751159806Sps	if (cm)
752159806Sps		mfi_release_command(cm);
753159806Sps	mtx_unlock(&sc->mfi_io_lock);
754157114Sscottl	return (error);
755157114Sscottl}
756157114Sscottl
757157114Sscottlstatic int
758159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
759158737Sambrisko{
760159812Sps	struct mfi_command *cm = NULL;
761158737Sambrisko	int error;
762158737Sambrisko
763159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
764159806Sps	    (void **)log_state, sizeof(**log_state));
765159806Sps	if (error)
766159806Sps		goto out;
767159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
768158737Sambrisko
769158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
770159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
771159806Sps		goto out;
772158737Sambrisko	}
773158737Sambrisko
774158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
775158737Sambrisko	    BUS_DMASYNC_POSTREAD);
776158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
777158737Sambrisko
778159806Spsout:
779159812Sps	if (cm)
780159812Sps		mfi_release_command(cm);
781158737Sambrisko
782158737Sambrisko	return (error);
783158737Sambrisko}
784158737Sambrisko
785158737Sambriskostatic int
786158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
787158737Sambrisko{
788159806Sps	struct mfi_evt_log_state *log_state = NULL;
789158737Sambrisko	union mfi_evt class_locale;
790158737Sambrisko	int error = 0;
791158737Sambrisko	uint32_t seq;
792158737Sambrisko
793158737Sambrisko	class_locale.members.reserved = 0;
794162118Sambrisko	class_locale.members.locale = mfi_event_locale;
795222589Semaste	class_locale.members.evt_class  = mfi_event_class;
796158737Sambrisko
797158737Sambrisko	if (seq_start == 0) {
798158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
799159806Sps		if (error) {
800159806Sps			if (log_state)
801159806Sps				free(log_state, M_MFIBUF);
802158737Sambrisko			return (error);
803159806Sps		}
804180037Sjhb
805180037Sjhb		/*
806180037Sjhb		 * Walk through any events that fired since the last
807180037Sjhb		 * shutdown.
808180037Sjhb		 */
809180037Sjhb		mfi_parse_entries(sc, log_state->shutdown_seq_num,
810180037Sjhb		    log_state->newest_seq_num);
811180037Sjhb		seq = log_state->newest_seq_num;
812158737Sambrisko	} else
813158737Sambrisko		seq = seq_start;
814158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
815159806Sps	free(log_state, M_MFIBUF);
816158737Sambrisko
817158737Sambrisko	return 0;
818158737Sambrisko}
819158737Sambrisko
820158737Sambriskostatic int
821159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
822159811Sps{
823159811Sps
824159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
825159811Sps	cm->cm_complete = NULL;
826159811Sps
827170284Sambrisko
828170284Sambrisko	/*
829170284Sambrisko	 * MegaCli can issue a DCMD of 0.  In this case do nothing
830170284Sambrisko	 * and return 0 to it as status
831170284Sambrisko	 */
832170284Sambrisko	if (cm->cm_frame->dcmd.opcode == 0) {
833170284Sambrisko		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
834170284Sambrisko		cm->cm_error = 0;
835170284Sambrisko		return (cm->cm_error);
836170284Sambrisko	}
837159811Sps	mfi_enqueue_ready(cm);
838159811Sps	mfi_startio(sc);
839170284Sambrisko	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
840170284Sambrisko		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
841170284Sambrisko	return (cm->cm_error);
842159811Sps}
843159811Sps
844157114Sscottlvoid
845157114Sscottlmfi_free(struct mfi_softc *sc)
846157114Sscottl{
847157114Sscottl	struct mfi_command *cm;
848157114Sscottl	int i;
849157114Sscottl
850162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
851162619Sscottl
852157114Sscottl	if (sc->mfi_cdev != NULL)
853157114Sscottl		destroy_dev(sc->mfi_cdev);
854157114Sscottl
855157114Sscottl	if (sc->mfi_total_cmds != 0) {
856157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
857157114Sscottl			cm = &sc->mfi_commands[i];
858157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
859157114Sscottl		}
860157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
861157114Sscottl	}
862157114Sscottl
863157114Sscottl	if (sc->mfi_intr)
864157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
865157114Sscottl	if (sc->mfi_irq != NULL)
866157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
867157114Sscottl		    sc->mfi_irq);
868157114Sscottl
869157114Sscottl	if (sc->mfi_sense_busaddr != 0)
870157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
871157114Sscottl	if (sc->mfi_sense != NULL)
872157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
873157114Sscottl		    sc->mfi_sense_dmamap);
874157114Sscottl	if (sc->mfi_sense_dmat != NULL)
875157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
876157114Sscottl
877157114Sscottl	if (sc->mfi_frames_busaddr != 0)
878157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
879157114Sscottl	if (sc->mfi_frames != NULL)
880157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
881157114Sscottl		    sc->mfi_frames_dmamap);
882157114Sscottl	if (sc->mfi_frames_dmat != NULL)
883157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
884157114Sscottl
885157114Sscottl	if (sc->mfi_comms_busaddr != 0)
886157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
887157114Sscottl	if (sc->mfi_comms != NULL)
888157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
889157114Sscottl		    sc->mfi_comms_dmamap);
890157114Sscottl	if (sc->mfi_comms_dmat != NULL)
891157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
892157114Sscottl
893157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
894157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
895157114Sscottl	if (sc->mfi_parent_dmat != NULL)
896157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
897157114Sscottl
898171821Sjhb	if (mtx_initialized(&sc->mfi_io_lock)) {
899157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
900171821Sjhb		sx_destroy(&sc->mfi_config_lock);
901171821Sjhb	}
902157114Sscottl
903157114Sscottl	return;
904157114Sscottl}
905157114Sscottl
906157114Sscottlstatic void
907157114Sscottlmfi_startup(void *arg)
908157114Sscottl{
909157114Sscottl	struct mfi_softc *sc;
910157114Sscottl
911157114Sscottl	sc = (struct mfi_softc *)arg;
912157114Sscottl
913157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
914157114Sscottl
915171980Sscottl	sc->mfi_enable_intr(sc);
916171821Sjhb	sx_xlock(&sc->mfi_config_lock);
917163398Sscottl	mtx_lock(&sc->mfi_io_lock);
918159811Sps	mfi_ldprobe(sc);
919163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
920171821Sjhb	sx_xunlock(&sc->mfi_config_lock);
921157114Sscottl}
922157114Sscottl
923157114Sscottlstatic void
924157114Sscottlmfi_intr(void *arg)
925157114Sscottl{
926157114Sscottl	struct mfi_softc *sc;
927157114Sscottl	struct mfi_command *cm;
928171980Sscottl	uint32_t pi, ci, context;
929157114Sscottl
930157114Sscottl	sc = (struct mfi_softc *)arg;
931157114Sscottl
932171980Sscottl	if (sc->mfi_check_clear_intr(sc))
933157114Sscottl		return;
934163398Sscottl
935157114Sscottl	pi = sc->mfi_comms->hw_pi;
936157114Sscottl	ci = sc->mfi_comms->hw_ci;
937157114Sscottl	mtx_lock(&sc->mfi_io_lock);
938157114Sscottl	while (ci != pi) {
939157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
940170284Sambrisko		if (context < sc->mfi_max_fw_cmds) {
941170284Sambrisko			cm = &sc->mfi_commands[context];
942170284Sambrisko			mfi_remove_busy(cm);
943170284Sambrisko			cm->cm_error = 0;
944170284Sambrisko			mfi_complete(sc, cm);
945170284Sambrisko		}
946162099Sscottl		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
947157114Sscottl			ci = 0;
948157114Sscottl		}
949157114Sscottl	}
950157114Sscottl
951157114Sscottl	sc->mfi_comms->hw_ci = ci;
952157114Sscottl
953163398Sscottl	/* Give defered I/O a chance to run */
954163398Sscottl	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
955163398Sscottl		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
956163398Sscottl	mfi_startio(sc);
957163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
958163398Sscottl
959157114Sscottl	return;
960157114Sscottl}
961157114Sscottl
962157114Sscottlint
963157114Sscottlmfi_shutdown(struct mfi_softc *sc)
964157114Sscottl{
965157114Sscottl	struct mfi_dcmd_frame *dcmd;
966157114Sscottl	struct mfi_command *cm;
967157114Sscottl	int error;
968157114Sscottl
969159806Sps	mtx_lock(&sc->mfi_io_lock);
970159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
971163398Sscottl	if (error) {
972163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
973159806Sps		return (error);
974163398Sscottl	}
975157114Sscottl
976158737Sambrisko	if (sc->mfi_aen_cm != NULL)
977158737Sambrisko		mfi_abort(sc, sc->mfi_aen_cm);
978157114Sscottl
979157114Sscottl	dcmd = &cm->cm_frame->dcmd;
980157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
981164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
982164375Sscottl	cm->cm_data = NULL;
983157114Sscottl
984164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
985157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
986157114Sscottl	}
987157114Sscottl
988159812Sps	mfi_release_command(cm);
989163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
990157114Sscottl	return (error);
991157114Sscottl}
992157114Sscottl
993157114Sscottlstatic void
994159811Spsmfi_ldprobe(struct mfi_softc *sc)
995157114Sscottl{
996159811Sps	struct mfi_frame_header *hdr;
997159811Sps	struct mfi_command *cm = NULL;
998159811Sps	struct mfi_ld_list *list = NULL;
999171821Sjhb	struct mfi_disk *ld;
1000159811Sps	int error, i;
1001157114Sscottl
1002171821Sjhb	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1003163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1004163398Sscottl
1005159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1006159811Sps	    (void **)&list, sizeof(*list));
1007159811Sps	if (error)
1008159811Sps		goto out;
1009159811Sps
1010159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1011159811Sps	if (mfi_wait_command(sc, cm) != 0) {
1012159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1013159811Sps		goto out;
1014157114Sscottl	}
1015157114Sscottl
1016157114Sscottl	hdr = &cm->cm_frame->header;
1017159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1018159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1019159811Sps		    hdr->cmd_status);
1020159811Sps		goto out;
1021157114Sscottl	}
1022157114Sscottl
1023171821Sjhb	for (i = 0; i < list->ld_count; i++) {
1024171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1025171821Sjhb			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1026171821Sjhb				goto skip_add;
1027171821Sjhb		}
1028163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1029171821Sjhb	skip_add:;
1030171821Sjhb	}
1031159811Spsout:
1032159811Sps	if (list)
1033159811Sps		free(list, M_MFIBUF);
1034159811Sps	if (cm)
1035157114Sscottl		mfi_release_command(cm);
1036163398Sscottl
1037159811Sps	return;
1038157114Sscottl}
1039157114Sscottl
1040180038Sjhb/*
1041180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1042180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since
1043180038Sjhb * boot.
1044180038Sjhb */
1045180038Sjhbstatic const char *
1046180038Sjhbformat_timestamp(uint32_t timestamp)
1047158737Sambrisko{
1048180038Sjhb	static char buffer[32];
1049180038Sjhb
1050180038Sjhb	if ((timestamp & 0xff000000) == 0xff000000)
1051180038Sjhb		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1052180038Sjhb		    0x00ffffff);
1053180038Sjhb	else
1054180038Sjhb		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1055180038Sjhb	return (buffer);
1056180038Sjhb}
1057180038Sjhb
1058180038Sjhbstatic const char *
1059180038Sjhbformat_class(int8_t class)
1060180038Sjhb{
1061180038Sjhb	static char buffer[6];
1062180038Sjhb
1063180038Sjhb	switch (class) {
1064180038Sjhb	case MFI_EVT_CLASS_DEBUG:
1065180038Sjhb		return ("debug");
1066180038Sjhb	case MFI_EVT_CLASS_PROGRESS:
1067180038Sjhb		return ("progress");
1068180038Sjhb	case MFI_EVT_CLASS_INFO:
1069180038Sjhb		return ("info");
1070180038Sjhb	case MFI_EVT_CLASS_WARNING:
1071180038Sjhb		return ("WARN");
1072180038Sjhb	case MFI_EVT_CLASS_CRITICAL:
1073180038Sjhb		return ("CRIT");
1074180038Sjhb	case MFI_EVT_CLASS_FATAL:
1075180038Sjhb		return ("FATAL");
1076180038Sjhb	case MFI_EVT_CLASS_DEAD:
1077180038Sjhb		return ("DEAD");
1078158737Sambrisko	default:
1079180038Sjhb		snprintf(buffer, sizeof(buffer), "%d", class);
1080180038Sjhb		return (buffer);
1081158737Sambrisko	}
1082158737Sambrisko}
1083158737Sambrisko
1084180038Sjhbstatic void
1085180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1086180038Sjhb{
1087180038Sjhb
1088200238Sjkim	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1089222589Semaste	    format_timestamp(detail->time), detail->evt_class.members.locale,
1090222589Semaste	    format_class(detail->evt_class.members.evt_class), detail->description);
1091180038Sjhb}
1092180038Sjhb
1093157114Sscottlstatic int
1094158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1095158737Sambrisko{
1096158737Sambrisko	struct mfi_command *cm;
1097158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1098158737Sambrisko	union mfi_evt current_aen, prior_aen;
1099159806Sps	struct mfi_evt_detail *ed = NULL;
1100163398Sscottl	int error = 0;
1101158737Sambrisko
1102158737Sambrisko	current_aen.word = locale;
1103158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1104158737Sambrisko		prior_aen.word =
1105158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1106222589Semaste		if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1107158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1108158737Sambrisko		    ^current_aen.members.locale)) {
1109158737Sambrisko			return (0);
1110158737Sambrisko		} else {
1111158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1112222589Semaste			if (prior_aen.members.evt_class
1113222589Semaste			    < current_aen.members.evt_class)
1114222589Semaste				current_aen.members.evt_class =
1115222589Semaste				    prior_aen.members.evt_class;
1116158737Sambrisko			mfi_abort(sc, sc->mfi_aen_cm);
1117158737Sambrisko		}
1118158737Sambrisko	}
1119158737Sambrisko
1120159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1121159806Sps	    (void **)&ed, sizeof(*ed));
1122163398Sscottl	if (error) {
1123163398Sscottl		goto out;
1124163398Sscottl	}
1125158737Sambrisko
1126158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1127158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1128158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1129158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1130158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1131158737Sambrisko
1132158737Sambrisko	sc->mfi_aen_cm = cm;
1133158737Sambrisko
1134158737Sambrisko	mfi_enqueue_ready(cm);
1135158737Sambrisko	mfi_startio(sc);
1136158737Sambrisko
1137163398Sscottlout:
1138163398Sscottl	return (error);
1139158737Sambrisko}
1140158737Sambrisko
1141158737Sambriskostatic void
1142158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1143158737Sambrisko{
1144158737Sambrisko	struct mfi_frame_header *hdr;
1145158737Sambrisko	struct mfi_softc *sc;
1146158737Sambrisko	struct mfi_evt_detail *detail;
1147163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1148158737Sambrisko	int seq = 0, aborted = 0;
1149158737Sambrisko
1150158737Sambrisko	sc = cm->cm_sc;
1151158737Sambrisko	hdr = &cm->cm_frame->header;
1152158737Sambrisko
1153158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1154158737Sambrisko		return;
1155158737Sambrisko
1156224039Sjhb	if (sc->mfi_aen_cm->cm_aen_abort ||
1157224039Sjhb	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1158158737Sambrisko		sc->mfi_aen_cm->cm_aen_abort = 0;
1159158737Sambrisko		aborted = 1;
1160158737Sambrisko	} else {
1161158737Sambrisko		sc->mfi_aen_triggered = 1;
1162163398Sscottl		if (sc->mfi_poll_waiting) {
1163163398Sscottl			sc->mfi_poll_waiting = 0;
1164158737Sambrisko			selwakeup(&sc->mfi_select);
1165163398Sscottl		}
1166158737Sambrisko		detail = cm->cm_data;
1167163398Sscottl		/*
1168163398Sscottl		 * XXX If this function is too expensive or is recursive, then
1169163398Sscottl		 * events should be put onto a queue and processed later.
1170163398Sscottl		 */
1171158737Sambrisko		mfi_decode_evt(sc, detail);
1172158737Sambrisko		seq = detail->seq + 1;
1173163398Sscottl		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1174158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1175158737Sambrisko			    aen_link);
1176163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1177158737Sambrisko			psignal(mfi_aen_entry->p, SIGIO);
1178163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1179158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1180158737Sambrisko		}
1181158737Sambrisko	}
1182158737Sambrisko
1183158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1184158737Sambrisko	sc->mfi_aen_cm = NULL;
1185158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1186158737Sambrisko	mfi_release_command(cm);
1187158737Sambrisko
1188158737Sambrisko	/* set it up again so the driver can catch more events */
1189158737Sambrisko	if (!aborted) {
1190158737Sambrisko		mfi_aen_setup(sc, seq);
1191158737Sambrisko	}
1192158737Sambrisko}
1193158737Sambrisko
1194180037Sjhb#define MAX_EVENTS 15
1195180037Sjhb
1196158737Sambriskostatic int
1197180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1198158737Sambrisko{
1199158737Sambrisko	struct mfi_command *cm;
1200158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1201162118Sambrisko	struct mfi_evt_list *el;
1202180037Sjhb	union mfi_evt class_locale;
1203180037Sjhb	int error, i, seq, size;
1204158737Sambrisko
1205180037Sjhb	class_locale.members.reserved = 0;
1206180037Sjhb	class_locale.members.locale = mfi_event_locale;
1207222589Semaste	class_locale.members.evt_class  = mfi_event_class;
1208158737Sambrisko
1209162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1210162118Sambrisko		* (MAX_EVENTS - 1);
1211162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1212180037Sjhb	if (el == NULL)
1213158737Sambrisko		return (ENOMEM);
1214158737Sambrisko
1215180037Sjhb	for (seq = start_seq;;) {
1216180037Sjhb		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1217180037Sjhb			free(el, M_MFIBUF);
1218180037Sjhb			return (EBUSY);
1219180037Sjhb		}
1220158737Sambrisko
1221180037Sjhb		dcmd = &cm->cm_frame->dcmd;
1222180037Sjhb		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1223180037Sjhb		dcmd->header.cmd = MFI_CMD_DCMD;
1224180037Sjhb		dcmd->header.timeout = 0;
1225180037Sjhb		dcmd->header.data_len = size;
1226180037Sjhb		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1227180037Sjhb		((uint32_t *)&dcmd->mbox)[0] = seq;
1228180037Sjhb		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1229180037Sjhb		cm->cm_sg = &dcmd->sgl;
1230180037Sjhb		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1231180037Sjhb		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1232180037Sjhb		cm->cm_data = el;
1233180037Sjhb		cm->cm_len = size;
1234180037Sjhb
1235180037Sjhb		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1236180037Sjhb			device_printf(sc->mfi_dev,
1237180037Sjhb			    "Failed to get controller entries\n");
1238180037Sjhb			mfi_release_command(cm);
1239180037Sjhb			break;
1240180037Sjhb		}
1241180037Sjhb
1242180037Sjhb		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1243180037Sjhb		    BUS_DMASYNC_POSTREAD);
1244180037Sjhb		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1245180037Sjhb
1246180037Sjhb		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1247180037Sjhb			mfi_release_command(cm);
1248180037Sjhb			break;
1249180037Sjhb		}
1250180037Sjhb		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1251180037Sjhb			device_printf(sc->mfi_dev,
1252180037Sjhb			    "Error %d fetching controller entries\n",
1253180037Sjhb			    dcmd->header.cmd_status);
1254180037Sjhb			mfi_release_command(cm);
1255180037Sjhb			break;
1256180037Sjhb		}
1257158737Sambrisko		mfi_release_command(cm);
1258158737Sambrisko
1259162473Sambrisko		for (i = 0; i < el->count; i++) {
1260180037Sjhb			/*
1261180037Sjhb			 * If this event is newer than 'stop_seq' then
1262180037Sjhb			 * break out of the loop.  Note that the log
1263180037Sjhb			 * is a circular buffer so we have to handle
1264180037Sjhb			 * the case that our stop point is earlier in
1265180037Sjhb			 * the buffer than our start point.
1266180037Sjhb			 */
1267180037Sjhb			if (el->event[i].seq >= stop_seq) {
1268180037Sjhb				if (start_seq <= stop_seq)
1269180037Sjhb					break;
1270180037Sjhb				else if (el->event[i].seq < start_seq)
1271180037Sjhb					break;
1272180037Sjhb			}
1273180037Sjhb			mfi_decode_evt(sc, &el->event[i]);
1274162473Sambrisko		}
1275180037Sjhb		seq = el->event[el->count - 1].seq + 1;
1276162118Sambrisko	}
1277158737Sambrisko
1278180037Sjhb	free(el, M_MFIBUF);
1279158737Sambrisko	return (0);
1280158737Sambrisko}
1281158737Sambrisko
1282158737Sambriskostatic int
1283159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1284157114Sscottl{
1285157114Sscottl	struct mfi_command *cm;
1286159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1287159811Sps	struct mfi_ld_info *ld_info = NULL;
1288159811Sps	int error;
1289157114Sscottl
1290159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1291159811Sps
1292159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1293159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1294159811Sps	if (error) {
1295159811Sps		device_printf(sc->mfi_dev,
1296159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1297159811Sps		if (ld_info)
1298159811Sps			free(ld_info, M_MFIBUF);
1299159811Sps		return (error);
1300157624Sscottl	}
1301159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1302159811Sps	dcmd = &cm->cm_frame->dcmd;
1303159811Sps	dcmd->mbox[0] = id;
1304160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1305160052Sambrisko		device_printf(sc->mfi_dev,
1306160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1307160052Sambrisko		free(ld_info, M_MFIBUF);
1308160052Sambrisko		return (0);
1309160052Sambrisko	}
1310159811Sps
1311160052Sambrisko	mfi_add_ld_complete(cm);
1312157114Sscottl	return (0);
1313157114Sscottl}
1314157114Sscottl
1315157114Sscottlstatic void
1316159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1317157114Sscottl{
1318157114Sscottl	struct mfi_frame_header *hdr;
1319159811Sps	struct mfi_ld_info *ld_info;
1320157114Sscottl	struct mfi_softc *sc;
1321159811Sps	device_t child;
1322157114Sscottl
1323157114Sscottl	sc = cm->cm_sc;
1324157114Sscottl	hdr = &cm->cm_frame->header;
1325159811Sps	ld_info = cm->cm_private;
1326157114Sscottl
1327159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1328159811Sps		free(ld_info, M_MFIBUF);
1329157114Sscottl		mfi_release_command(cm);
1330157114Sscottl		return;
1331157114Sscottl	}
1332157114Sscottl	mfi_release_command(cm);
1333157114Sscottl
1334169611Sscottl	mtx_unlock(&sc->mfi_io_lock);
1335196403Sjhb	mtx_lock(&Giant);
1336157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1337157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1338159811Sps		free(ld_info, M_MFIBUF);
1339196403Sjhb		mtx_unlock(&Giant);
1340169611Sscottl		mtx_lock(&sc->mfi_io_lock);
1341159811Sps		return;
1342157114Sscottl	}
1343157114Sscottl
1344169451Sscottl	device_set_ivars(child, ld_info);
1345157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1346157114Sscottl	bus_generic_attach(sc->mfi_dev);
1347196403Sjhb	mtx_unlock(&Giant);
1348157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1349157114Sscottl}
1350163399Sscottl
1351157114Sscottlstatic struct mfi_command *
1352157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1353157114Sscottl{
1354157114Sscottl	struct mfi_io_frame *io;
1355157114Sscottl	struct mfi_command *cm;
1356157114Sscottl	struct bio *bio;
1357158737Sambrisko	int flags, blkcount;
1358157114Sscottl
1359157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1360157114Sscottl		return (NULL);
1361157114Sscottl
1362157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1363157114Sscottl		mfi_release_command(cm);
1364157114Sscottl		return (NULL);
1365157114Sscottl	}
1366157114Sscottl
1367157114Sscottl	io = &cm->cm_frame->io;
1368157114Sscottl	switch (bio->bio_cmd & 0x03) {
1369157114Sscottl	case BIO_READ:
1370157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
1371157114Sscottl		flags = MFI_CMD_DATAIN;
1372157114Sscottl		break;
1373157114Sscottl	case BIO_WRITE:
1374157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
1375157114Sscottl		flags = MFI_CMD_DATAOUT;
1376157114Sscottl		break;
1377157114Sscottl	default:
1378157114Sscottl		panic("Invalid bio command");
1379157114Sscottl	}
1380157114Sscottl
1381157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
1382157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1383157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
1384157114Sscottl	io->header.timeout = 0;
1385157114Sscottl	io->header.flags = 0;
1386157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1387157114Sscottl	io->header.data_len = blkcount;
1388157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1389157114Sscottl	io->sense_addr_hi = 0;
1390157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
1391157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
1392157114Sscottl	cm->cm_complete = mfi_bio_complete;
1393157114Sscottl	cm->cm_private = bio;
1394157114Sscottl	cm->cm_data = bio->bio_data;
1395157114Sscottl	cm->cm_len = bio->bio_bcount;
1396157114Sscottl	cm->cm_sg = &io->sgl;
1397157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1398157114Sscottl	cm->cm_flags = flags;
1399157114Sscottl	return (cm);
1400157114Sscottl}
1401157114Sscottl
1402157114Sscottlstatic void
1403157114Sscottlmfi_bio_complete(struct mfi_command *cm)
1404157114Sscottl{
1405157114Sscottl	struct bio *bio;
1406157114Sscottl	struct mfi_frame_header *hdr;
1407157114Sscottl	struct mfi_softc *sc;
1408157114Sscottl
1409157114Sscottl	bio = cm->cm_private;
1410157114Sscottl	hdr = &cm->cm_frame->header;
1411157114Sscottl	sc = cm->cm_sc;
1412157114Sscottl
1413224039Sjhb	if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
1414157114Sscottl		bio->bio_flags |= BIO_ERROR;
1415157114Sscottl		bio->bio_error = EIO;
1416157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
1417157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
1418157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
1419184897Sambrisko	} else if (cm->cm_error != 0) {
1420184897Sambrisko		bio->bio_flags |= BIO_ERROR;
1421157114Sscottl	}
1422157114Sscottl
1423157114Sscottl	mfi_release_command(cm);
1424157114Sscottl	mfi_disk_complete(bio);
1425157114Sscottl}
1426157114Sscottl
1427157114Sscottlvoid
1428157114Sscottlmfi_startio(struct mfi_softc *sc)
1429157114Sscottl{
1430157114Sscottl	struct mfi_command *cm;
1431169611Sscottl	struct ccb_hdr *ccbh;
1432157114Sscottl
1433157114Sscottl	for (;;) {
1434157114Sscottl		/* Don't bother if we're short on resources */
1435157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1436157114Sscottl			break;
1437157114Sscottl
1438157114Sscottl		/* Try a command that has already been prepared */
1439157114Sscottl		cm = mfi_dequeue_ready(sc);
1440157114Sscottl
1441169611Sscottl		if (cm == NULL) {
1442169611Sscottl			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
1443169611Sscottl				cm = sc->mfi_cam_start(ccbh);
1444169611Sscottl		}
1445169611Sscottl
1446157114Sscottl		/* Nope, so look for work on the bioq */
1447157114Sscottl		if (cm == NULL)
1448157114Sscottl			cm = mfi_bio_command(sc);
1449157114Sscottl
1450157114Sscottl		/* No work available, so exit */
1451157114Sscottl		if (cm == NULL)
1452157114Sscottl			break;
1453157114Sscottl
1454157114Sscottl		/* Send the command to the controller */
1455157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
1456157114Sscottl			mfi_requeue_ready(cm);
1457157114Sscottl			break;
1458157114Sscottl		}
1459157114Sscottl	}
1460157114Sscottl}
1461157114Sscottl
1462157114Sscottlstatic int
1463157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
1464157114Sscottl{
1465157114Sscottl	int error, polled;
1466157114Sscottl
1467163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1468163398Sscottl
1469157114Sscottl	if (cm->cm_data != NULL) {
1470157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
1471157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
1472157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
1473157114Sscottl		if (error == EINPROGRESS) {
1474157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
1475157114Sscottl			return (0);
1476157114Sscottl		}
1477157114Sscottl	} else {
1478157114Sscottl		error = mfi_send_frame(sc, cm);
1479157114Sscottl	}
1480157114Sscottl
1481157114Sscottl	return (error);
1482157114Sscottl}
1483157114Sscottl
1484157114Sscottlstatic void
1485157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1486157114Sscottl{
1487157114Sscottl	struct mfi_frame_header *hdr;
1488157114Sscottl	struct mfi_command *cm;
1489157237Sscottl	union mfi_sgl *sgl;
1490157114Sscottl	struct mfi_softc *sc;
1491157114Sscottl	int i, dir;
1492157114Sscottl
1493157114Sscottl	cm = (struct mfi_command *)arg;
1494157114Sscottl	sc = cm->cm_sc;
1495157237Sscottl	hdr = &cm->cm_frame->header;
1496157237Sscottl	sgl = cm->cm_sg;
1497157114Sscottl
1498170284Sambrisko	if (error) {
1499170284Sambrisko		printf("error %d in callback\n", error);
1500170284Sambrisko		cm->cm_error = error;
1501170284Sambrisko		mfi_complete(sc, cm);
1502170284Sambrisko		return;
1503170284Sambrisko	}
1504170284Sambrisko
1505157237Sscottl	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
1506157237Sscottl		for (i = 0; i < nsegs; i++) {
1507157237Sscottl			sgl->sg32[i].addr = segs[i].ds_addr;
1508157237Sscottl			sgl->sg32[i].len = segs[i].ds_len;
1509157114Sscottl		}
1510157237Sscottl	} else {
1511157237Sscottl		for (i = 0; i < nsegs; i++) {
1512157237Sscottl			sgl->sg64[i].addr = segs[i].ds_addr;
1513157237Sscottl			sgl->sg64[i].len = segs[i].ds_len;
1514157237Sscottl		}
1515157237Sscottl		hdr->flags |= MFI_FRAME_SGL64;
1516157114Sscottl	}
1517157114Sscottl	hdr->sg_count = nsegs;
1518157114Sscottl
1519157114Sscottl	dir = 0;
1520157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
1521157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
1522157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
1523157114Sscottl	}
1524157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
1525157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
1526157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
1527157114Sscottl	}
1528157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1529157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
1530157114Sscottl
1531157114Sscottl	/*
1532157114Sscottl	 * Instead of calculating the total number of frames in the
1533157114Sscottl	 * compound frame, it's already assumed that there will be at
1534157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
1535157114Sscottl	 * following division.
1536157114Sscottl	 */
1537162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
1538157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
1539157114Sscottl
1540164375Sscottl	mfi_send_frame(sc, cm);
1541157114Sscottl
1542157114Sscottl	return;
1543157114Sscottl}
1544157114Sscottl
1545157114Sscottlstatic int
1546157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1547157114Sscottl{
1548164375Sscottl	struct mfi_frame_header *hdr;
1549165225Sambrisko	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
1550157114Sscottl
1551164375Sscottl	hdr = &cm->cm_frame->header;
1552164375Sscottl
1553164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1554164375Sscottl		cm->cm_timestamp = time_uptime;
1555164375Sscottl		mfi_enqueue_busy(cm);
1556164375Sscottl	} else {
1557224039Sjhb		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
1558164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
1559164375Sscottl	}
1560164375Sscottl
1561157114Sscottl	/*
1562157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
1563157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
1564157114Sscottl	 * hardware wants the address shifted right by three, leaving just
1565162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
1566162458Sscottl	 * hint for the hardware to predict how many frames need to be
1567162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
1568162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
1569162458Sscottl	 * information in the command to determine the total amount to fetch.
1570162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
1571162458Sscottl	 * is enough for both 32bit and 64bit systems.
1572157114Sscottl	 */
1573162458Sscottl	if (cm->cm_extra_frames > 7)
1574162458Sscottl		cm->cm_extra_frames = 7;
1575162458Sscottl
1576171980Sscottl	sc->mfi_issue_cmd(sc,cm->cm_frame_busaddr,cm->cm_extra_frames);
1577164375Sscottl
1578164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
1579164375Sscottl		return (0);
1580164375Sscottl
1581164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
1582224039Sjhb	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1583164375Sscottl		DELAY(1000);
1584165225Sambrisko		tm -= 1;
1585164375Sscottl		if (tm <= 0)
1586164375Sscottl			break;
1587164375Sscottl	}
1588164375Sscottl
1589224039Sjhb	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1590165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
1591165225Sambrisko			      "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
1592164375Sscottl		return (ETIMEDOUT);
1593164375Sscottl	}
1594164375Sscottl
1595157114Sscottl	return (0);
1596157114Sscottl}
1597157114Sscottl
1598157114Sscottlstatic void
1599157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
1600157114Sscottl{
1601157114Sscottl	int dir;
1602157114Sscottl
1603157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
1604157114Sscottl		dir = 0;
1605157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAIN)
1606157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
1607157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
1608157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
1609157114Sscottl
1610157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1611157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1612157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
1613157114Sscottl	}
1614157114Sscottl
1615170284Sambrisko	cm->cm_flags |= MFI_CMD_COMPLETED;
1616170284Sambrisko
1617157114Sscottl	if (cm->cm_complete != NULL)
1618157114Sscottl		cm->cm_complete(cm);
1619159811Sps	else
1620159811Sps		wakeup(cm);
1621157114Sscottl}
1622157114Sscottl
1623158737Sambriskostatic int
1624158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
1625158737Sambrisko{
1626158737Sambrisko	struct mfi_command *cm;
1627158737Sambrisko	struct mfi_abort_frame *abort;
1628165225Sambrisko	int i = 0;
1629158737Sambrisko
1630163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1631163398Sscottl
1632158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1633158737Sambrisko		return (EBUSY);
1634158737Sambrisko	}
1635158737Sambrisko
1636158737Sambrisko	abort = &cm->cm_frame->abort;
1637158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
1638158737Sambrisko	abort->header.flags = 0;
1639158737Sambrisko	abort->abort_context = cm_abort->cm_frame->header.context;
1640158737Sambrisko	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
1641158737Sambrisko	abort->abort_mfi_addr_hi = 0;
1642158737Sambrisko	cm->cm_data = NULL;
1643164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1644158737Sambrisko
1645158737Sambrisko	sc->mfi_aen_cm->cm_aen_abort = 1;
1646158737Sambrisko	mfi_mapcmd(sc, cm);
1647158737Sambrisko	mfi_release_command(cm);
1648158737Sambrisko
1649165225Sambrisko	while (i < 5 && sc->mfi_aen_cm != NULL) {
1650163398Sscottl		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
1651165225Sambrisko		i++;
1652158737Sambrisko	}
1653158737Sambrisko
1654158737Sambrisko	return (0);
1655158737Sambrisko}
1656158737Sambrisko
1657157114Sscottlint
1658157114Sscottlmfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
1659157114Sscottl{
1660157114Sscottl	struct mfi_command *cm;
1661157114Sscottl	struct mfi_io_frame *io;
1662157114Sscottl	int error;
1663157114Sscottl
1664157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1665157114Sscottl		return (EBUSY);
1666157114Sscottl
1667157114Sscottl	io = &cm->cm_frame->io;
1668157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
1669157114Sscottl	io->header.target_id = id;
1670157114Sscottl	io->header.timeout = 0;
1671157114Sscottl	io->header.flags = 0;
1672157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1673157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1674157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1675157114Sscottl	io->sense_addr_hi = 0;
1676157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
1677157114Sscottl	io->lba_lo = lba & 0xffffffff;
1678157114Sscottl	cm->cm_data = virt;
1679157114Sscottl	cm->cm_len = len;
1680157114Sscottl	cm->cm_sg = &io->sgl;
1681157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1682157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
1683157114Sscottl
1684164375Sscottl	error = mfi_mapcmd(sc, cm);
1685157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1686157114Sscottl	    BUS_DMASYNC_POSTWRITE);
1687157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1688157114Sscottl	mfi_release_command(cm);
1689157114Sscottl
1690157114Sscottl	return (error);
1691157114Sscottl}
1692157114Sscottl
1693157114Sscottlstatic int
1694192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
1695157114Sscottl{
1696157114Sscottl	struct mfi_softc *sc;
1697171822Sjhb	int error;
1698157114Sscottl
1699157114Sscottl	sc = dev->si_drv1;
1700163398Sscottl
1701163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1702171822Sjhb	if (sc->mfi_detaching)
1703171822Sjhb		error = ENXIO;
1704171822Sjhb	else {
1705171822Sjhb		sc->mfi_flags |= MFI_FLAGS_OPEN;
1706171822Sjhb		error = 0;
1707171822Sjhb	}
1708163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1709157114Sscottl
1710171822Sjhb	return (error);
1711157114Sscottl}
1712157114Sscottl
1713157114Sscottlstatic int
1714192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
1715157114Sscottl{
1716157114Sscottl	struct mfi_softc *sc;
1717163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1718157114Sscottl
1719157114Sscottl	sc = dev->si_drv1;
1720163398Sscottl
1721163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1722157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
1723157114Sscottl
1724163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1725158737Sambrisko		if (mfi_aen_entry->p == curproc) {
1726158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1727158737Sambrisko			    aen_link);
1728158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1729158737Sambrisko		}
1730158737Sambrisko	}
1731163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1732157114Sscottl	return (0);
1733157114Sscottl}
1734157114Sscottl
1735157114Sscottlstatic int
1736171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
1737171821Sjhb{
1738171821Sjhb
1739171821Sjhb	switch (opcode) {
1740171821Sjhb	case MFI_DCMD_LD_DELETE:
1741171821Sjhb	case MFI_DCMD_CFG_ADD:
1742171821Sjhb	case MFI_DCMD_CFG_CLEAR:
1743171821Sjhb		sx_xlock(&sc->mfi_config_lock);
1744171821Sjhb		return (1);
1745171821Sjhb	default:
1746171821Sjhb		return (0);
1747171821Sjhb	}
1748171821Sjhb}
1749171821Sjhb
1750171821Sjhbstatic void
1751171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked)
1752171821Sjhb{
1753171821Sjhb
1754171821Sjhb	if (locked)
1755171821Sjhb		sx_xunlock(&sc->mfi_config_lock);
1756171821Sjhb}
1757171821Sjhb
1758171821Sjhb/* Perform pre-issue checks on commands from userland and possibly veto them. */
1759171821Sjhbstatic int
1760171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
1761171821Sjhb{
1762171821Sjhb	struct mfi_disk *ld, *ld2;
1763171821Sjhb	int error;
1764171821Sjhb
1765171821Sjhb	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1766171821Sjhb	error = 0;
1767171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
1768171821Sjhb	case MFI_DCMD_LD_DELETE:
1769171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1770171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
1771171821Sjhb				break;
1772171821Sjhb		}
1773171821Sjhb		if (ld == NULL)
1774171821Sjhb			error = ENOENT;
1775171821Sjhb		else
1776171821Sjhb			error = mfi_disk_disable(ld);
1777171821Sjhb		break;
1778171821Sjhb	case MFI_DCMD_CFG_CLEAR:
1779171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1780171821Sjhb			error = mfi_disk_disable(ld);
1781171821Sjhb			if (error)
1782171821Sjhb				break;
1783171821Sjhb		}
1784171821Sjhb		if (error) {
1785171821Sjhb			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
1786171821Sjhb				if (ld2 == ld)
1787171821Sjhb					break;
1788171821Sjhb				mfi_disk_enable(ld2);
1789171821Sjhb			}
1790171821Sjhb		}
1791171821Sjhb		break;
1792171821Sjhb	default:
1793171821Sjhb		break;
1794171821Sjhb	}
1795171821Sjhb	return (error);
1796171821Sjhb}
1797171821Sjhb
1798171821Sjhb/* Perform post-issue checks on commands from userland. */
1799171821Sjhbstatic void
1800171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
1801171821Sjhb{
1802171821Sjhb	struct mfi_disk *ld, *ldn;
1803171821Sjhb
1804171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
1805171821Sjhb	case MFI_DCMD_LD_DELETE:
1806171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1807171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
1808171821Sjhb				break;
1809171821Sjhb		}
1810171821Sjhb		KASSERT(ld != NULL, ("volume dissappeared"));
1811171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
1812171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
1813196403Sjhb			mtx_lock(&Giant);
1814171821Sjhb			device_delete_child(sc->mfi_dev, ld->ld_dev);
1815196403Sjhb			mtx_unlock(&Giant);
1816171821Sjhb			mtx_lock(&sc->mfi_io_lock);
1817171821Sjhb		} else
1818171821Sjhb			mfi_disk_enable(ld);
1819171821Sjhb		break;
1820171821Sjhb	case MFI_DCMD_CFG_CLEAR:
1821171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
1822171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
1823196403Sjhb			mtx_lock(&Giant);
1824171821Sjhb			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
1825171821Sjhb				device_delete_child(sc->mfi_dev, ld->ld_dev);
1826171821Sjhb			}
1827196403Sjhb			mtx_unlock(&Giant);
1828171821Sjhb			mtx_lock(&sc->mfi_io_lock);
1829171821Sjhb		} else {
1830171821Sjhb			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
1831171821Sjhb				mfi_disk_enable(ld);
1832171821Sjhb		}
1833171821Sjhb		break;
1834171821Sjhb	case MFI_DCMD_CFG_ADD:
1835171821Sjhb		mfi_ldprobe(sc);
1836171821Sjhb		break;
1837184897Sambrisko	case MFI_DCMD_CFG_FOREIGN_IMPORT:
1838184897Sambrisko		mfi_ldprobe(sc);
1839184897Sambrisko		break;
1840171821Sjhb	}
1841171821Sjhb}
1842171821Sjhb
1843171821Sjhbstatic int
1844178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
1845178968Sscottl{
1846178968Sscottl	struct mfi_command *cm;
1847178968Sscottl	struct mfi_dcmd_frame *dcmd;
1848178968Sscottl	void *ioc_buf = NULL;
1849178968Sscottl	uint32_t context;
1850178968Sscottl	int error = 0, locked;
1851178968Sscottl
1852178968Sscottl
1853178968Sscottl	if (ioc->buf_size > 0) {
1854178968Sscottl		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
1855178968Sscottl		if (ioc_buf == NULL) {
1856178968Sscottl			return (ENOMEM);
1857178968Sscottl		}
1858178968Sscottl		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
1859178968Sscottl		if (error) {
1860178968Sscottl			device_printf(sc->mfi_dev, "failed to copyin\n");
1861178968Sscottl			free(ioc_buf, M_MFIBUF);
1862178968Sscottl			return (error);
1863178968Sscottl		}
1864178968Sscottl	}
1865178968Sscottl
1866178968Sscottl	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
1867178968Sscottl
1868178968Sscottl	mtx_lock(&sc->mfi_io_lock);
1869178968Sscottl	while ((cm = mfi_dequeue_free(sc)) == NULL)
1870178968Sscottl		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
1871178968Sscottl
1872178968Sscottl	/* Save context for later */
1873178968Sscottl	context = cm->cm_frame->header.context;
1874178968Sscottl
1875178968Sscottl	dcmd = &cm->cm_frame->dcmd;
1876178968Sscottl	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
1877178968Sscottl
1878178968Sscottl	cm->cm_sg = &dcmd->sgl;
1879178968Sscottl	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1880178968Sscottl	cm->cm_data = ioc_buf;
1881178968Sscottl	cm->cm_len = ioc->buf_size;
1882178968Sscottl
1883178968Sscottl	/* restore context */
1884178968Sscottl	cm->cm_frame->header.context = context;
1885178968Sscottl
1886178968Sscottl	/* Cheat since we don't know if we're writing or reading */
1887178968Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
1888178968Sscottl
1889178968Sscottl	error = mfi_check_command_pre(sc, cm);
1890178968Sscottl	if (error)
1891178968Sscottl		goto out;
1892178968Sscottl
1893178968Sscottl	error = mfi_wait_command(sc, cm);
1894178968Sscottl	if (error) {
1895178968Sscottl		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
1896178968Sscottl		goto out;
1897178968Sscottl	}
1898178968Sscottl	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
1899178968Sscottl	mfi_check_command_post(sc, cm);
1900178968Sscottlout:
1901178968Sscottl	mfi_release_command(cm);
1902178968Sscottl	mtx_unlock(&sc->mfi_io_lock);
1903178968Sscottl	mfi_config_unlock(sc, locked);
1904178968Sscottl	if (ioc->buf_size > 0)
1905178968Sscottl		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
1906178968Sscottl	if (ioc_buf)
1907178968Sscottl		free(ioc_buf, M_MFIBUF);
1908178968Sscottl	return (error);
1909178968Sscottl}
1910178968Sscottl
1911178968Sscottl#ifdef __amd64__
1912178968Sscottl#define	PTRIN(p)		((void *)(uintptr_t)(p))
1913178968Sscottl#else
1914178968Sscottl#define	PTRIN(p)		(p)
1915178968Sscottl#endif
1916178968Sscottl
1917178968Sscottlstatic int
1918192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
1919157114Sscottl{
1920157114Sscottl	struct mfi_softc *sc;
1921157114Sscottl	union mfi_statrequest *ms;
1922164281Sambrisko	struct mfi_ioc_packet *ioc;
1923179392Sambrisko#ifdef __amd64__
1924179392Sambrisko	struct mfi_ioc_packet32 *ioc32;
1925179392Sambrisko#endif
1926164281Sambrisko	struct mfi_ioc_aen *aen;
1927164281Sambrisko	struct mfi_command *cm = NULL;
1928164281Sambrisko	uint32_t context;
1929184897Sambrisko	union mfi_sense_ptr sense_ptr;
1930164281Sambrisko	uint8_t *data = NULL, *temp;
1931164281Sambrisko	int i;
1932178968Sscottl	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
1933178968Sscottl#ifdef __amd64__
1934178968Sscottl	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
1935178968Sscottl	struct mfi_ioc_passthru iop_swab;
1936178968Sscottl#endif
1937171821Sjhb	int error, locked;
1938157114Sscottl
1939157114Sscottl	sc = dev->si_drv1;
1940157114Sscottl	error = 0;
1941157114Sscottl
1942157114Sscottl	switch (cmd) {
1943157114Sscottl	case MFIIO_STATS:
1944157114Sscottl		ms = (union mfi_statrequest *)arg;
1945157114Sscottl		switch (ms->ms_item) {
1946157114Sscottl		case MFIQ_FREE:
1947157114Sscottl		case MFIQ_BIO:
1948157114Sscottl		case MFIQ_READY:
1949157114Sscottl		case MFIQ_BUSY:
1950157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
1951157114Sscottl			    sizeof(struct mfi_qstat));
1952157114Sscottl			break;
1953157114Sscottl		default:
1954158737Sambrisko			error = ENOIOCTL;
1955157114Sscottl			break;
1956157114Sscottl		}
1957157114Sscottl		break;
1958169451Sscottl	case MFIIO_QUERY_DISK:
1959169451Sscottl	{
1960169451Sscottl		struct mfi_query_disk *qd;
1961169451Sscottl		struct mfi_disk *ld;
1962169451Sscottl
1963169451Sscottl		qd = (struct mfi_query_disk *)arg;
1964169451Sscottl		mtx_lock(&sc->mfi_io_lock);
1965169451Sscottl		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1966169451Sscottl			if (ld->ld_id == qd->array_id)
1967169451Sscottl				break;
1968169451Sscottl		}
1969169451Sscottl		if (ld == NULL) {
1970169451Sscottl			qd->present = 0;
1971169451Sscottl			mtx_unlock(&sc->mfi_io_lock);
1972169451Sscottl			return (0);
1973169451Sscottl		}
1974169451Sscottl		qd->present = 1;
1975169451Sscottl		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
1976169451Sscottl			qd->open = 1;
1977169451Sscottl		bzero(qd->devname, SPECNAMELEN + 1);
1978169451Sscottl		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
1979169451Sscottl		mtx_unlock(&sc->mfi_io_lock);
1980169451Sscottl		break;
1981169451Sscottl	}
1982164281Sambrisko	case MFI_CMD:
1983179392Sambrisko#ifdef __amd64__
1984179392Sambrisko	case MFI_CMD32:
1985179392Sambrisko#endif
1986177489Sambrisko		{
1987177489Sambrisko		devclass_t devclass;
1988164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
1989177489Sambrisko		int adapter;
1990164281Sambrisko
1991177489Sambrisko		adapter = ioc->mfi_adapter_no;
1992177489Sambrisko		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
1993177489Sambrisko			devclass = devclass_find("mfi");
1994177489Sambrisko			sc = devclass_get_softc(devclass, adapter);
1995177489Sambrisko		}
1996164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
1997164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1998164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1999164281Sambrisko			return (EBUSY);
2000164281Sambrisko		}
2001164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2002171821Sjhb		locked = 0;
2003164281Sambrisko
2004164281Sambrisko		/*
2005164281Sambrisko		 * save off original context since copying from user
2006164281Sambrisko		 * will clobber some data
2007164281Sambrisko		 */
2008164281Sambrisko		context = cm->cm_frame->header.context;
2009164281Sambrisko
2010165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
2011184897Sambrisko		    2 * MFI_DCMD_FRAME_SIZE);  /* this isn't quite right */
2012184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
2013184897Sambrisko		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
2014175897Sambrisko		if (ioc->mfi_sge_count) {
2015175897Sambrisko			cm->cm_sg =
2016175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
2017175897Sambrisko		}
2018175897Sambrisko		cm->cm_flags = 0;
2019175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
2020175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
2021175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
2022175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
2023175897Sambrisko		/* Legacy app shim */
2024175897Sambrisko		if (cm->cm_flags == 0)
2025175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
2026164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
2027184897Sambrisko		if (cm->cm_len &&
2028184897Sambrisko		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
2029175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
2030175897Sambrisko			    M_WAITOK | M_ZERO);
2031175897Sambrisko			if (cm->cm_data == NULL) {
2032175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
2033175897Sambrisko				goto out;
2034175897Sambrisko			}
2035175897Sambrisko		} else {
2036175897Sambrisko			cm->cm_data = 0;
2037165225Sambrisko		}
2038164281Sambrisko
2039164281Sambrisko		/* restore header context */
2040164281Sambrisko		cm->cm_frame->header.context = context;
2041164281Sambrisko
2042164281Sambrisko		temp = data;
2043175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
2044175897Sambrisko			for (i = 0; i < ioc->mfi_sge_count; i++) {
2045179392Sambrisko#ifdef __amd64__
2046179392Sambrisko				if (cmd == MFI_CMD) {
2047179392Sambrisko					/* Native */
2048179392Sambrisko					error = copyin(ioc->mfi_sgl[i].iov_base,
2049179392Sambrisko					       temp,
2050179392Sambrisko					       ioc->mfi_sgl[i].iov_len);
2051179392Sambrisko				} else {
2052179392Sambrisko					void *temp_convert;
2053179392Sambrisko					/* 32bit */
2054179392Sambrisko					ioc32 = (struct mfi_ioc_packet32 *)ioc;
2055179392Sambrisko					temp_convert =
2056179392Sambrisko					    PTRIN(ioc32->mfi_sgl[i].iov_base);
2057179392Sambrisko					error = copyin(temp_convert,
2058179392Sambrisko					       temp,
2059179392Sambrisko					       ioc32->mfi_sgl[i].iov_len);
2060179392Sambrisko				}
2061179392Sambrisko#else
2062175897Sambrisko				error = copyin(ioc->mfi_sgl[i].iov_base,
2063175897Sambrisko				       temp,
2064175897Sambrisko				       ioc->mfi_sgl[i].iov_len);
2065179392Sambrisko#endif
2066175897Sambrisko				if (error != 0) {
2067175897Sambrisko					device_printf(sc->mfi_dev,
2068175897Sambrisko					    "Copy in failed\n");
2069175897Sambrisko					goto out;
2070175897Sambrisko				}
2071175897Sambrisko				temp = &temp[ioc->mfi_sgl[i].iov_len];
2072164281Sambrisko			}
2073164281Sambrisko		}
2074164281Sambrisko
2075171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
2076171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
2077171821Sjhb
2078184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
2079184933Sambrisko			cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
2080184933Sambrisko			cm->cm_frame->pass.sense_addr_hi = 0;
2081184933Sambrisko		}
2082184933Sambrisko
2083164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
2084171821Sjhb		error = mfi_check_command_pre(sc, cm);
2085171821Sjhb		if (error) {
2086171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2087171821Sjhb			goto out;
2088171821Sjhb		}
2089171821Sjhb
2090170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
2091164281Sambrisko			device_printf(sc->mfi_dev,
2092165225Sambrisko			    "Controller polled failed\n");
2093164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2094164281Sambrisko			goto out;
2095164281Sambrisko		}
2096164281Sambrisko
2097171821Sjhb		mfi_check_command_post(sc, cm);
2098164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2099164281Sambrisko
2100164281Sambrisko		temp = data;
2101175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
2102175897Sambrisko			for (i = 0; i < ioc->mfi_sge_count; i++) {
2103179392Sambrisko#ifdef __amd64__
2104179392Sambrisko				if (cmd == MFI_CMD) {
2105179392Sambrisko					/* Native */
2106179392Sambrisko					error = copyout(temp,
2107179392Sambrisko						ioc->mfi_sgl[i].iov_base,
2108179392Sambrisko						ioc->mfi_sgl[i].iov_len);
2109179392Sambrisko				} else {
2110179392Sambrisko					void *temp_convert;
2111179392Sambrisko					/* 32bit */
2112179392Sambrisko					ioc32 = (struct mfi_ioc_packet32 *)ioc;
2113179392Sambrisko					temp_convert =
2114179392Sambrisko					    PTRIN(ioc32->mfi_sgl[i].iov_base);
2115179392Sambrisko					error = copyout(temp,
2116179392Sambrisko						temp_convert,
2117179392Sambrisko						ioc32->mfi_sgl[i].iov_len);
2118179392Sambrisko				}
2119179392Sambrisko#else
2120175897Sambrisko				error = copyout(temp,
2121175897Sambrisko					ioc->mfi_sgl[i].iov_base,
2122175897Sambrisko					ioc->mfi_sgl[i].iov_len);
2123179392Sambrisko#endif
2124175897Sambrisko				if (error != 0) {
2125175897Sambrisko					device_printf(sc->mfi_dev,
2126175897Sambrisko					    "Copy out failed\n");
2127175897Sambrisko					goto out;
2128175897Sambrisko				}
2129175897Sambrisko				temp = &temp[ioc->mfi_sgl[i].iov_len];
2130164281Sambrisko			}
2131164281Sambrisko		}
2132164281Sambrisko
2133165225Sambrisko		if (ioc->mfi_sense_len) {
2134184897Sambrisko			/* get user-space sense ptr then copy out sense */
2135184897Sambrisko			bcopy(&((struct mfi_ioc_packet*)arg)
2136184897Sambrisko			    ->mfi_frame.raw[ioc->mfi_sense_off],
2137184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
2138184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
2139184974Sambrisko#ifdef __amd64__
2140184974Sambrisko			if (cmd != MFI_CMD) {
2141184974Sambrisko				/*
2142184974Sambrisko				 * not 64bit native so zero out any address
2143184974Sambrisko				 * over 32bit */
2144184975Sambrisko				sense_ptr.addr.high = 0;
2145184974Sambrisko			}
2146184974Sambrisko#endif
2147184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
2148165225Sambrisko			    ioc->mfi_sense_len);
2149164281Sambrisko			if (error != 0) {
2150164281Sambrisko				device_printf(sc->mfi_dev,
2151165225Sambrisko				    "Copy out failed\n");
2152164281Sambrisko				goto out;
2153164281Sambrisko			}
2154164281Sambrisko		}
2155164281Sambrisko
2156165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
2157164281Sambriskoout:
2158171821Sjhb		mfi_config_unlock(sc, locked);
2159164281Sambrisko		if (data)
2160164281Sambrisko			free(data, M_MFIBUF);
2161164281Sambrisko		if (cm) {
2162164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
2163164281Sambrisko			mfi_release_command(cm);
2164164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2165164281Sambrisko		}
2166164281Sambrisko
2167164281Sambrisko		break;
2168177489Sambrisko		}
2169164281Sambrisko	case MFI_SET_AEN:
2170164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
2171164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
2172164281Sambrisko		    aen->aen_class_locale);
2173164281Sambrisko
2174164281Sambrisko		break;
2175164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
2176158737Sambrisko		{
2177158737Sambrisko			devclass_t devclass;
2178158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
2179158737Sambrisko			int adapter;
2180158737Sambrisko
2181158737Sambrisko			devclass = devclass_find("mfi");
2182158737Sambrisko			if (devclass == NULL)
2183158737Sambrisko				return (ENOENT);
2184158737Sambrisko
2185158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
2186158737Sambrisko			if (error)
2187158737Sambrisko				return (error);
2188158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
2189158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
2190158737Sambrisko			if (sc == NULL)
2191158737Sambrisko				return (ENOENT);
2192158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
2193158737Sambrisko			    cmd, arg, flag, td));
2194158737Sambrisko			break;
2195158737Sambrisko		}
2196164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
2197158737Sambrisko		{
2198158737Sambrisko			devclass_t devclass;
2199158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
2200158737Sambrisko			int adapter;
2201158737Sambrisko
2202158737Sambrisko			devclass = devclass_find("mfi");
2203158737Sambrisko			if (devclass == NULL)
2204158737Sambrisko				return (ENOENT);
2205158737Sambrisko
2206158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
2207158737Sambrisko			if (error)
2208158737Sambrisko				return (error);
2209158737Sambrisko			adapter = l_aen.laen_adapter_no;
2210158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
2211158737Sambrisko			if (sc == NULL)
2212158737Sambrisko				return (ENOENT);
2213158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
2214158737Sambrisko			    cmd, arg, flag, td));
2215158737Sambrisko			break;
2216158737Sambrisko		}
2217178968Sscottl#ifdef __amd64__
2218178968Sscottl	case MFIIO_PASSTHRU32:
2219178968Sscottl		iop_swab.ioc_frame	= iop32->ioc_frame;
2220178968Sscottl		iop_swab.buf_size	= iop32->buf_size;
2221178968Sscottl		iop_swab.buf		= PTRIN(iop32->buf);
2222178968Sscottl		iop			= &iop_swab;
2223178968Sscottl		/* FALLTHROUGH */
2224178968Sscottl#endif
2225178968Sscottl	case MFIIO_PASSTHRU:
2226178968Sscottl		error = mfi_user_command(sc, iop);
2227178968Sscottl#ifdef __amd64__
2228178968Sscottl		if (cmd == MFIIO_PASSTHRU32)
2229178968Sscottl			iop32->ioc_frame = iop_swab.ioc_frame;
2230178968Sscottl#endif
2231178968Sscottl		break;
2232157114Sscottl	default:
2233163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
2234157114Sscottl		error = ENOENT;
2235157114Sscottl		break;
2236157114Sscottl	}
2237157114Sscottl
2238157114Sscottl	return (error);
2239157114Sscottl}
2240158737Sambrisko
2241158737Sambriskostatic int
2242192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
2243158737Sambrisko{
2244158737Sambrisko	struct mfi_softc *sc;
2245158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
2246158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
2247158737Sambrisko	struct mfi_command *cm = NULL;
2248158737Sambrisko	struct mfi_aen *mfi_aen_entry;
2249184897Sambrisko	union mfi_sense_ptr sense_ptr;
2250158737Sambrisko	uint32_t context;
2251158737Sambrisko	uint8_t *data = NULL, *temp;
2252158737Sambrisko	int i;
2253171821Sjhb	int error, locked;
2254158737Sambrisko
2255158737Sambrisko	sc = dev->si_drv1;
2256158737Sambrisko	error = 0;
2257158737Sambrisko	switch (cmd) {
2258164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
2259158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
2260158737Sambrisko		if (error != 0)
2261158737Sambrisko			return (error);
2262158737Sambrisko
2263158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
2264158737Sambrisko			return (EINVAL);
2265158737Sambrisko		}
2266158737Sambrisko
2267158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
2268158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
2269158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2270158737Sambrisko			return (EBUSY);
2271158737Sambrisko		}
2272158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2273171821Sjhb		locked = 0;
2274158737Sambrisko
2275158737Sambrisko		/*
2276158737Sambrisko		 * save off original context since copying from user
2277158737Sambrisko		 * will clobber some data
2278158737Sambrisko		 */
2279158737Sambrisko		context = cm->cm_frame->header.context;
2280158737Sambrisko
2281158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
2282175897Sambrisko		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
2283184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
2284184897Sambrisko		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
2285175897Sambrisko		if (l_ioc.lioc_sge_count)
2286175897Sambrisko			cm->cm_sg =
2287175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
2288175897Sambrisko		cm->cm_flags = 0;
2289175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
2290175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
2291175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
2292175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
2293158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
2294184897Sambrisko		if (cm->cm_len &&
2295184897Sambrisko		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
2296175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
2297175897Sambrisko			    M_WAITOK | M_ZERO);
2298175897Sambrisko			if (cm->cm_data == NULL) {
2299175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
2300175897Sambrisko				goto out;
2301175897Sambrisko			}
2302175897Sambrisko		} else {
2303175897Sambrisko			cm->cm_data = 0;
2304175897Sambrisko		}
2305158737Sambrisko
2306158737Sambrisko		/* restore header context */
2307158737Sambrisko		cm->cm_frame->header.context = context;
2308158737Sambrisko
2309158737Sambrisko		temp = data;
2310175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
2311175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
2312178968Sscottl				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
2313175897Sambrisko				       temp,
2314175897Sambrisko				       l_ioc.lioc_sgl[i].iov_len);
2315175897Sambrisko				if (error != 0) {
2316175897Sambrisko					device_printf(sc->mfi_dev,
2317175897Sambrisko					    "Copy in failed\n");
2318175897Sambrisko					goto out;
2319175897Sambrisko				}
2320175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
2321158737Sambrisko			}
2322158737Sambrisko		}
2323158737Sambrisko
2324171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
2325171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
2326171821Sjhb
2327184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
2328184933Sambrisko			cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
2329184933Sambrisko			cm->cm_frame->pass.sense_addr_hi = 0;
2330184933Sambrisko		}
2331184933Sambrisko
2332163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2333171821Sjhb		error = mfi_check_command_pre(sc, cm);
2334171821Sjhb		if (error) {
2335171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2336171821Sjhb			goto out;
2337171821Sjhb		}
2338171821Sjhb
2339170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
2340158737Sambrisko			device_printf(sc->mfi_dev,
2341165225Sambrisko			    "Controller polled failed\n");
2342163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
2343158737Sambrisko			goto out;
2344158737Sambrisko		}
2345158737Sambrisko
2346171821Sjhb		mfi_check_command_post(sc, cm);
2347163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2348158737Sambrisko
2349158737Sambrisko		temp = data;
2350175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
2351175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
2352175897Sambrisko				error = copyout(temp,
2353178968Sscottl					PTRIN(l_ioc.lioc_sgl[i].iov_base),
2354175897Sambrisko					l_ioc.lioc_sgl[i].iov_len);
2355175897Sambrisko				if (error != 0) {
2356175897Sambrisko					device_printf(sc->mfi_dev,
2357175897Sambrisko					    "Copy out failed\n");
2358175897Sambrisko					goto out;
2359175897Sambrisko				}
2360175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
2361158737Sambrisko			}
2362158737Sambrisko		}
2363158737Sambrisko
2364158737Sambrisko		if (l_ioc.lioc_sense_len) {
2365184897Sambrisko			/* get user-space sense ptr then copy out sense */
2366184897Sambrisko			bcopy(&((struct mfi_linux_ioc_packet*)arg)
2367184897Sambrisko                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
2368184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
2369184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
2370184974Sambrisko#ifdef __amd64__
2371184974Sambrisko			/*
2372184974Sambrisko			 * only 32bit Linux support so zero out any
2373184974Sambrisko			 * address over 32bit
2374184974Sambrisko			 */
2375184975Sambrisko			sense_ptr.addr.high = 0;
2376184974Sambrisko#endif
2377184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
2378158737Sambrisko			    l_ioc.lioc_sense_len);
2379158737Sambrisko			if (error != 0) {
2380158737Sambrisko				device_printf(sc->mfi_dev,
2381165225Sambrisko				    "Copy out failed\n");
2382158737Sambrisko				goto out;
2383158737Sambrisko			}
2384158737Sambrisko		}
2385158737Sambrisko
2386158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
2387158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
2388158737Sambrisko			->lioc_frame.hdr.cmd_status,
2389158737Sambrisko			1);
2390158737Sambrisko		if (error != 0) {
2391158737Sambrisko			device_printf(sc->mfi_dev,
2392165225Sambrisko				      "Copy out failed\n");
2393158737Sambrisko			goto out;
2394158737Sambrisko		}
2395158737Sambrisko
2396158737Sambriskoout:
2397171821Sjhb		mfi_config_unlock(sc, locked);
2398158737Sambrisko		if (data)
2399158737Sambrisko			free(data, M_MFIBUF);
2400158737Sambrisko		if (cm) {
2401158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
2402158737Sambrisko			mfi_release_command(cm);
2403158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2404158737Sambrisko		}
2405158737Sambrisko
2406158737Sambrisko		return (error);
2407164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
2408158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
2409158737Sambrisko		if (error != 0)
2410158737Sambrisko			return (error);
2411158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
2412158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
2413158737Sambrisko		    M_WAITOK);
2414163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2415158737Sambrisko		if (mfi_aen_entry != NULL) {
2416158737Sambrisko			mfi_aen_entry->p = curproc;
2417158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
2418158737Sambrisko			    aen_link);
2419158737Sambrisko		}
2420158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
2421158737Sambrisko		    l_aen.laen_class_locale);
2422158737Sambrisko
2423158737Sambrisko		if (error != 0) {
2424158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2425158737Sambrisko			    aen_link);
2426158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2427158737Sambrisko		}
2428163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2429158737Sambrisko
2430158737Sambrisko		return (error);
2431158737Sambrisko	default:
2432158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
2433158737Sambrisko		error = ENOENT;
2434158737Sambrisko		break;
2435158737Sambrisko	}
2436158737Sambrisko
2437158737Sambrisko	return (error);
2438158737Sambrisko}
2439158737Sambrisko
2440158737Sambriskostatic int
2441158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
2442158737Sambrisko{
2443158737Sambrisko	struct mfi_softc *sc;
2444158737Sambrisko	int revents = 0;
2445158737Sambrisko
2446158737Sambrisko	sc = dev->si_drv1;
2447158737Sambrisko
2448158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
2449163398Sscottl		if (sc->mfi_aen_triggered != 0) {
2450158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
2451163398Sscottl			sc->mfi_aen_triggered = 0;
2452163398Sscottl		}
2453158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
2454158737Sambrisko			revents |= POLLERR;
2455158737Sambrisko		}
2456158737Sambrisko	}
2457158737Sambrisko
2458158737Sambrisko	if (revents == 0) {
2459158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
2460158737Sambrisko			sc->mfi_poll_waiting = 1;
2461158737Sambrisko			selrecord(td, &sc->mfi_select);
2462158737Sambrisko		}
2463158737Sambrisko	}
2464158737Sambrisko
2465158737Sambrisko	return revents;
2466158737Sambrisko}
2467162619Sscottl
2468163398Sscottl
2469162619Sscottlstatic void
2470163398Sscottlmfi_dump_all(void)
2471163398Sscottl{
2472163398Sscottl	struct mfi_softc *sc;
2473163398Sscottl	struct mfi_command *cm;
2474163398Sscottl	devclass_t dc;
2475163398Sscottl	time_t deadline;
2476163398Sscottl	int timedout;
2477163398Sscottl	int i;
2478163398Sscottl
2479163398Sscottl	dc = devclass_find("mfi");
2480163398Sscottl	if (dc == NULL) {
2481163398Sscottl		printf("No mfi dev class\n");
2482163398Sscottl		return;
2483163398Sscottl	}
2484163398Sscottl
2485163398Sscottl	for (i = 0; ; i++) {
2486163398Sscottl		sc = devclass_get_softc(dc, i);
2487163398Sscottl		if (sc == NULL)
2488163398Sscottl			break;
2489163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
2490163398Sscottl		timedout = 0;
2491163398Sscottl		deadline = time_uptime - MFI_CMD_TIMEOUT;
2492163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2493163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2494163398Sscottl			if (cm->cm_timestamp < deadline) {
2495163398Sscottl				device_printf(sc->mfi_dev,
2496163398Sscottl				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2497163398Sscottl				    (int)(time_uptime - cm->cm_timestamp));
2498163398Sscottl				MFI_PRINT_CMD(cm);
2499163398Sscottl				timedout++;
2500163398Sscottl			}
2501163398Sscottl		}
2502163398Sscottl
2503163398Sscottl#if 0
2504163398Sscottl		if (timedout)
2505163398Sscottl			MFI_DUMP_CMDS(SC);
2506163398Sscottl#endif
2507163398Sscottl
2508163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2509163398Sscottl	}
2510163398Sscottl
2511163398Sscottl	return;
2512163398Sscottl}
2513163398Sscottl
2514163398Sscottlstatic void
2515162619Sscottlmfi_timeout(void *data)
2516162619Sscottl{
2517162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
2518162619Sscottl	struct mfi_command *cm;
2519162619Sscottl	time_t deadline;
2520162619Sscottl	int timedout = 0;
2521162619Sscottl
2522162619Sscottl	deadline = time_uptime - MFI_CMD_TIMEOUT;
2523162619Sscottl	mtx_lock(&sc->mfi_io_lock);
2524162619Sscottl	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2525162688Sscottl		if (sc->mfi_aen_cm == cm)
2526162688Sscottl			continue;
2527163398Sscottl		if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
2528162619Sscottl			device_printf(sc->mfi_dev,
2529162619Sscottl			    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2530162619Sscottl			    (int)(time_uptime - cm->cm_timestamp));
2531162619Sscottl			MFI_PRINT_CMD(cm);
2532163398Sscottl			MFI_VALIDATE_CMD(sc, cm);
2533162619Sscottl			timedout++;
2534162619Sscottl		}
2535162619Sscottl	}
2536162619Sscottl
2537162619Sscottl#if 0
2538162619Sscottl	if (timedout)
2539162619Sscottl		MFI_DUMP_CMDS(SC);
2540162619Sscottl#endif
2541162619Sscottl
2542162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
2543162619Sscottl
2544162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
2545162619Sscottl	    mfi_timeout, sc);
2546162619Sscottl
2547163398Sscottl	if (0)
2548163398Sscottl		mfi_dump_all();
2549162619Sscottl	return;
2550162619Sscottl}
2551