mfi.c revision 186132
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 186132 2008-12-15 17:11:40Z ambrisko $");
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 *);
107158737Sambriskostatic int	mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, d_thread_t *);
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{
233157114Sscottl	int32_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;
263157114Sscottl		default:
264157114Sscottl			device_printf(sc->mfi_dev,"Unknown firmware state %d\n",
265157114Sscottl			    fw_state);
266157114Sscottl			return (ENXIO);
267157114Sscottl		}
268157114Sscottl		for (i = 0; i < (max_wait * 10); i++) {
269171980Sscottl			fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK;
270157114Sscottl			if (fw_state == cur_state)
271157114Sscottl				DELAY(100000);
272157114Sscottl			else
273157114Sscottl				break;
274157114Sscottl		}
275157114Sscottl		if (fw_state == cur_state) {
276157114Sscottl			device_printf(sc->mfi_dev, "firmware stuck in state "
277157114Sscottl			    "%#x\n", fw_state);
278157114Sscottl			return (ENXIO);
279157114Sscottl		}
280157114Sscottl	}
281157114Sscottl	return (0);
282157114Sscottl}
283157114Sscottl
284157114Sscottlstatic void
285157114Sscottlmfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
286157114Sscottl{
287157114Sscottl	uint32_t *addr;
288157114Sscottl
289157114Sscottl	addr = arg;
290157114Sscottl	*addr = segs[0].ds_addr;
291157114Sscottl}
292157114Sscottl
293157114Sscottlint
294157114Sscottlmfi_attach(struct mfi_softc *sc)
295157114Sscottl{
296157114Sscottl	uint32_t status;
297157114Sscottl	int error, commsz, framessz, sensesz;
298162458Sscottl	int frames, unit, max_fw_sge;
299157114Sscottl
300186132Sambrisko	device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.00 \n");
301186132Sambrisko
302157114Sscottl	mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
303171821Sjhb	sx_init(&sc->mfi_config_lock, "MFI config");
304157114Sscottl	TAILQ_INIT(&sc->mfi_ld_tqh);
305158737Sambrisko	TAILQ_INIT(&sc->mfi_aen_pids);
306169611Sscottl	TAILQ_INIT(&sc->mfi_cam_ccbq);
307157114Sscottl
308157114Sscottl	mfi_initq_free(sc);
309157114Sscottl	mfi_initq_ready(sc);
310157114Sscottl	mfi_initq_busy(sc);
311157114Sscottl	mfi_initq_bio(sc);
312157114Sscottl
313171980Sscottl	if (sc->mfi_flags & MFI_FLAGS_1064R) {
314171980Sscottl		sc->mfi_enable_intr = mfi_enable_intr_xscale;
315171980Sscottl		sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
316171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
317171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
318171980Sscottl	}
319171980Sscottl	else {
320171980Sscottl		sc->mfi_enable_intr =  mfi_enable_intr_ppc;
321171980Sscottl 		sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
322171980Sscottl		sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
323171980Sscottl		sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
324171980Sscottl	}
325171980Sscottl
326171980Sscottl
327157114Sscottl	/* Before we get too far, see if the firmware is working */
328157114Sscottl	if ((error = mfi_transition_firmware(sc)) != 0) {
329157114Sscottl		device_printf(sc->mfi_dev, "Firmware not in READY state, "
330157114Sscottl		    "error %d\n", error);
331157114Sscottl		return (ENXIO);
332157114Sscottl	}
333157114Sscottl
334157114Sscottl	/*
335157114Sscottl	 * Get information needed for sizing the contiguous memory for the
336157114Sscottl	 * frame pool.  Size down the sgl parameter since we know that
337157114Sscottl	 * we will never need more than what's required for MAXPHYS.
338157114Sscottl	 * It would be nice if these constants were available at runtime
339157114Sscottl	 * instead of compile time.
340157114Sscottl	 */
341171980Sscottl	status = sc->mfi_read_fw_status(sc);
342157114Sscottl	sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
343162458Sscottl	max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
344162458Sscottl	sc->mfi_max_sge = min(max_fw_sge, ((MAXPHYS / PAGE_SIZE) + 1));
345157114Sscottl
346157114Sscottl	/*
347157114Sscottl	 * Create the dma tag for data buffers.  Used both for block I/O
348157114Sscottl	 * and for various internal data queries.
349157114Sscottl	 */
350157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
351157114Sscottl				1, 0,			/* algnmnt, boundary */
352157114Sscottl				BUS_SPACE_MAXADDR,	/* lowaddr */
353157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
354157114Sscottl				NULL, NULL,		/* filter, filterarg */
355157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
356162458Sscottl				sc->mfi_max_sge,	/* nsegments */
357157114Sscottl				BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
358157114Sscottl				BUS_DMA_ALLOCNOW,	/* flags */
359157114Sscottl				busdma_lock_mutex,	/* lockfunc */
360157114Sscottl				&sc->mfi_io_lock,	/* lockfuncarg */
361157114Sscottl				&sc->mfi_buffer_dmat)) {
362157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
363157114Sscottl		return (ENOMEM);
364157114Sscottl	}
365157114Sscottl
366157114Sscottl	/*
367157114Sscottl	 * Allocate DMA memory for the comms queues.  Keep it under 4GB for
368157114Sscottl	 * efficiency.  The mfi_hwcomms struct includes space for 1 reply queue
369157114Sscottl	 * entry, so the calculated size here will be will be 1 more than
370157114Sscottl	 * mfi_max_fw_cmds.  This is apparently a requirement of the hardware.
371157114Sscottl	 */
372157114Sscottl	commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
373157114Sscottl	    sizeof(struct mfi_hwcomms);
374157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
375157114Sscottl				1, 0,			/* algnmnt, boundary */
376157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
377157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
378157114Sscottl				NULL, NULL,		/* filter, filterarg */
379157114Sscottl				commsz,			/* maxsize */
380157114Sscottl				1,			/* msegments */
381157114Sscottl				commsz,			/* maxsegsize */
382157114Sscottl				0,			/* flags */
383157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
384157114Sscottl				&sc->mfi_comms_dmat)) {
385157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
386157114Sscottl		return (ENOMEM);
387157114Sscottl	}
388157114Sscottl	if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
389157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
390157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
391157114Sscottl		return (ENOMEM);
392157114Sscottl	}
393157114Sscottl	bzero(sc->mfi_comms, commsz);
394157114Sscottl	bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
395157114Sscottl	    sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
396157114Sscottl
397157114Sscottl	/*
398157114Sscottl	 * Allocate DMA memory for the command frames.  Keep them in the
399162458Sscottl	 * lower 4GB for efficiency.  Calculate the size of the commands at
400162458Sscottl	 * the same time; each command is one 64 byte frame plus a set of
401162458Sscottl         * additional frames for holding sg lists or other data.
402157114Sscottl	 * The assumption here is that the SG list will start at the second
403162458Sscottl	 * frame and not use the unused bytes in the first frame.  While this
404162458Sscottl	 * isn't technically correct, it simplifies the calculation and allows
405162458Sscottl	 * for command frames that might be larger than an mfi_io_frame.
406157114Sscottl	 */
407157114Sscottl	if (sizeof(bus_addr_t) == 8) {
408162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg64);
409157114Sscottl		sc->mfi_flags |= MFI_FLAGS_SG64;
410157114Sscottl	} else {
411162458Sscottl		sc->mfi_sge_size = sizeof(struct mfi_sg32);
412157114Sscottl	}
413162458Sscottl	frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
414162458Sscottl	sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
415162458Sscottl	framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
416157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
417157114Sscottl				64, 0,			/* algnmnt, boundary */
418157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
419157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
420157114Sscottl				NULL, NULL,		/* filter, filterarg */
421157114Sscottl				framessz,		/* maxsize */
422157114Sscottl				1,			/* nsegments */
423157114Sscottl				framessz,		/* maxsegsize */
424157114Sscottl				0,			/* flags */
425157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
426157114Sscottl				&sc->mfi_frames_dmat)) {
427157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
428157114Sscottl		return (ENOMEM);
429157114Sscottl	}
430157114Sscottl	if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
431157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
432157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
433157114Sscottl		return (ENOMEM);
434157114Sscottl	}
435157114Sscottl	bzero(sc->mfi_frames, framessz);
436157114Sscottl	bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
437157114Sscottl	    sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
438157114Sscottl
439157114Sscottl	/*
440157114Sscottl	 * Allocate DMA memory for the frame sense data.  Keep them in the
441157114Sscottl	 * lower 4GB for efficiency
442157114Sscottl	 */
443157114Sscottl	sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
444157114Sscottl	if (bus_dma_tag_create( sc->mfi_parent_dmat,	/* parent */
445157114Sscottl				4, 0,			/* algnmnt, boundary */
446157114Sscottl				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
447157114Sscottl				BUS_SPACE_MAXADDR,	/* highaddr */
448157114Sscottl				NULL, NULL,		/* filter, filterarg */
449157114Sscottl				sensesz,		/* maxsize */
450157114Sscottl				1,			/* nsegments */
451157114Sscottl				sensesz,		/* maxsegsize */
452157114Sscottl				0,			/* flags */
453157114Sscottl				NULL, NULL,		/* lockfunc, lockarg */
454157114Sscottl				&sc->mfi_sense_dmat)) {
455157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
456157114Sscottl		return (ENOMEM);
457157114Sscottl	}
458157114Sscottl	if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
459157114Sscottl	    BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
460157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
461157114Sscottl		return (ENOMEM);
462157114Sscottl	}
463157114Sscottl	bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
464157114Sscottl	    sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
465157114Sscottl
466157114Sscottl	if ((error = mfi_alloc_commands(sc)) != 0)
467157114Sscottl		return (error);
468157114Sscottl
469157114Sscottl	if ((error = mfi_comms_init(sc)) != 0)
470157114Sscottl		return (error);
471157114Sscottl
472157114Sscottl	if ((error = mfi_get_controller_info(sc)) != 0)
473157114Sscottl		return (error);
474157114Sscottl
475163398Sscottl	mtx_lock(&sc->mfi_io_lock);
476163398Sscottl	if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
477163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
478157114Sscottl		return (error);
479163398Sscottl	}
480163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
481157114Sscottl
482157114Sscottl	/*
483157114Sscottl	 * Set up the interrupt handler.  XXX This should happen in
484157114Sscottl	 * mfi_pci.c
485157114Sscottl	 */
486157114Sscottl	sc->mfi_irq_rid = 0;
487157114Sscottl	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
488157114Sscottl	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
489157114Sscottl		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
490157114Sscottl		return (EINVAL);
491157114Sscottl	}
492157114Sscottl	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
493166901Spiso	    NULL, mfi_intr, sc, &sc->mfi_intr)) {
494157114Sscottl		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
495157114Sscottl		return (EINVAL);
496157114Sscottl	}
497157114Sscottl
498157114Sscottl	/* Register a config hook to probe the bus for arrays */
499157114Sscottl	sc->mfi_ich.ich_func = mfi_startup;
500157114Sscottl	sc->mfi_ich.ich_arg = sc;
501157114Sscottl	if (config_intrhook_establish(&sc->mfi_ich) != 0) {
502157114Sscottl		device_printf(sc->mfi_dev, "Cannot establish configuration "
503157114Sscottl		    "hook\n");
504157114Sscottl		return (EINVAL);
505157114Sscottl	}
506157114Sscottl
507157114Sscottl	/*
508157114Sscottl	 * Register a shutdown handler.
509157114Sscottl	 */
510157114Sscottl	if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
511157114Sscottl	    sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
512157114Sscottl		device_printf(sc->mfi_dev, "Warning: shutdown event "
513157114Sscottl		    "registration failed\n");
514157114Sscottl	}
515157114Sscottl
516157114Sscottl	/*
517157114Sscottl	 * Create the control device for doing management
518157114Sscottl	 */
519157114Sscottl	unit = device_get_unit(sc->mfi_dev);
520157114Sscottl	sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
521157114Sscottl	    0640, "mfi%d", unit);
522158737Sambrisko	if (unit == 0)
523158737Sambrisko		make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node");
524157114Sscottl	if (sc->mfi_cdev != NULL)
525157114Sscottl		sc->mfi_cdev->si_drv1 = sc;
526171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
527171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
528171821Sjhb	    OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
529171821Sjhb	    &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
530171821Sjhb	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
531171821Sjhb	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
532171821Sjhb	    OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
533171821Sjhb	    &sc->mfi_keep_deleted_volumes, 0,
534171821Sjhb	    "Don't detach the mfid device for a busy volume that is deleted");
535157114Sscottl
536169611Sscottl	device_add_child(sc->mfi_dev, "mfip", -1);
537169611Sscottl	bus_generic_attach(sc->mfi_dev);
538169611Sscottl
539162619Sscottl	/* Start the timeout watchdog */
540178250Skris	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
541162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
542162619Sscottl	    mfi_timeout, sc);
543162619Sscottl
544157114Sscottl	return (0);
545157114Sscottl}
546157114Sscottl
547157114Sscottlstatic int
548157114Sscottlmfi_alloc_commands(struct mfi_softc *sc)
549157114Sscottl{
550157114Sscottl	struct mfi_command *cm;
551157114Sscottl	int i, ncmds;
552157114Sscottl
553157114Sscottl	/*
554157114Sscottl	 * XXX Should we allocate all the commands up front, or allocate on
555157114Sscottl	 * demand later like 'aac' does?
556157114Sscottl	 */
557178968Sscottl	ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds);
558178968Sscottl	if (bootverbose)
559178968Sscottl		device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver "
560178968Sscottl		   "pool to %d\n", sc->mfi_max_fw_cmds, ncmds);
561178968Sscottl
562157114Sscottl	sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF,
563157114Sscottl	    M_WAITOK | M_ZERO);
564157114Sscottl
565157114Sscottl	for (i = 0; i < ncmds; i++) {
566157114Sscottl		cm = &sc->mfi_commands[i];
567158737Sambrisko		cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
568162458Sscottl		    sc->mfi_cmd_size * i);
569157114Sscottl		cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
570162458Sscottl		    sc->mfi_cmd_size * i;
571157114Sscottl		cm->cm_frame->header.context = i;
572157114Sscottl		cm->cm_sense = &sc->mfi_sense[i];
573157114Sscottl		cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
574157114Sscottl		cm->cm_sc = sc;
575162619Sscottl		cm->cm_index = i;
576157114Sscottl		if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
577157114Sscottl		    &cm->cm_dmamap) == 0)
578157114Sscottl			mfi_release_command(cm);
579157114Sscottl		else
580157114Sscottl			break;
581157114Sscottl		sc->mfi_total_cmds++;
582157114Sscottl	}
583157114Sscottl
584157114Sscottl	return (0);
585157114Sscottl}
586157114Sscottl
587169611Sscottlvoid
588157114Sscottlmfi_release_command(struct mfi_command *cm)
589157114Sscottl{
590163398Sscottl	struct mfi_frame_header *hdr;
591157114Sscottl	uint32_t *hdr_data;
592157114Sscottl
593157114Sscottl	/*
594157114Sscottl	 * Zero out the important fields of the frame, but make sure the
595165727Sscottl	 * context field is preserved.  For efficiency, handle the fields
596165727Sscottl	 * as 32 bit words.  Clear out the first S/G entry too for safety.
597157114Sscottl	 */
598163398Sscottl	hdr = &cm->cm_frame->header;
599175897Sambrisko	if (cm->cm_data != NULL && hdr->sg_count) {
600163398Sscottl		cm->cm_sg->sg32[0].len = 0;
601163398Sscottl		cm->cm_sg->sg32[0].addr = 0;
602163398Sscottl	}
603165727Sscottl
604165727Sscottl	hdr_data = (uint32_t *)cm->cm_frame;
605165727Sscottl	hdr_data[0] = 0;	/* cmd, sense_len, cmd_status, scsi_status */
606165727Sscottl	hdr_data[1] = 0;	/* target_id, lun_id, cdb_len, sg_count */
607165727Sscottl	hdr_data[4] = 0;	/* flags, timeout */
608165727Sscottl	hdr_data[5] = 0;	/* data_len */
609165727Sscottl
610157114Sscottl	cm->cm_extra_frames = 0;
611157114Sscottl	cm->cm_flags = 0;
612157114Sscottl	cm->cm_complete = NULL;
613157114Sscottl	cm->cm_private = NULL;
614169611Sscottl	cm->cm_data = NULL;
615157114Sscottl	cm->cm_sg = 0;
616157114Sscottl	cm->cm_total_frame_size = 0;
617163398Sscottl
618157114Sscottl	mfi_enqueue_free(cm);
619157114Sscottl}
620157114Sscottl
621157114Sscottlstatic int
622159806Spsmfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
623159806Sps    void **bufp, size_t bufsize)
624159806Sps{
625159806Sps	struct mfi_command *cm;
626159806Sps	struct mfi_dcmd_frame *dcmd;
627159806Sps	void *buf = NULL;
628159806Sps
629159806Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
630159806Sps
631159806Sps	cm = mfi_dequeue_free(sc);
632159806Sps	if (cm == NULL)
633159806Sps		return (EBUSY);
634159806Sps
635159806Sps	if ((bufsize > 0) && (bufp != NULL)) {
636159806Sps		if (*bufp == NULL) {
637159806Sps			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
638159806Sps			if (buf == NULL) {
639159806Sps				mfi_release_command(cm);
640159806Sps				return (ENOMEM);
641159806Sps			}
642159806Sps			*bufp = buf;
643159806Sps		} else {
644159806Sps			buf = *bufp;
645159806Sps		}
646159806Sps	}
647159806Sps
648159806Sps	dcmd =  &cm->cm_frame->dcmd;
649159806Sps	bzero(dcmd->mbox, MFI_MBOX_SIZE);
650159806Sps	dcmd->header.cmd = MFI_CMD_DCMD;
651159806Sps	dcmd->header.timeout = 0;
652159806Sps	dcmd->header.flags = 0;
653159806Sps	dcmd->header.data_len = bufsize;
654159806Sps	dcmd->opcode = opcode;
655159806Sps	cm->cm_sg = &dcmd->sgl;
656159806Sps	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
657159806Sps	cm->cm_flags = 0;
658159806Sps	cm->cm_data = buf;
659159806Sps	cm->cm_private = buf;
660159806Sps	cm->cm_len = bufsize;
661159806Sps
662159806Sps	*cmp = cm;
663159806Sps	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
664159806Sps		*bufp = buf;
665159806Sps	return (0);
666159806Sps}
667159806Sps
668159806Spsstatic int
669157114Sscottlmfi_comms_init(struct mfi_softc *sc)
670157114Sscottl{
671157114Sscottl	struct mfi_command *cm;
672157114Sscottl	struct mfi_init_frame *init;
673157114Sscottl	struct mfi_init_qinfo *qinfo;
674157114Sscottl	int error;
675157114Sscottl
676163398Sscottl	mtx_lock(&sc->mfi_io_lock);
677157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
678157114Sscottl		return (EBUSY);
679157114Sscottl
680157114Sscottl	/*
681157114Sscottl	 * Abuse the SG list area of the frame to hold the init_qinfo
682157114Sscottl	 * object;
683157114Sscottl	 */
684157114Sscottl	init = &cm->cm_frame->init;
685157114Sscottl	qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
686157114Sscottl
687157114Sscottl	bzero(qinfo, sizeof(struct mfi_init_qinfo));
688157114Sscottl	qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
689157114Sscottl	qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
690157114Sscottl	    offsetof(struct mfi_hwcomms, hw_reply_q);
691157114Sscottl	qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
692157114Sscottl	    offsetof(struct mfi_hwcomms, hw_pi);
693157114Sscottl	qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
694157114Sscottl	    offsetof(struct mfi_hwcomms, hw_ci);
695157114Sscottl
696157114Sscottl	init->header.cmd = MFI_CMD_INIT;
697157114Sscottl	init->header.data_len = sizeof(struct mfi_init_qinfo);
698157114Sscottl	init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
699164375Sscottl	cm->cm_data = NULL;
700164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
701157114Sscottl
702164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
703157114Sscottl		device_printf(sc->mfi_dev, "failed to send init command\n");
704163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
705157114Sscottl		return (error);
706157114Sscottl	}
707157114Sscottl	mfi_release_command(cm);
708163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
709157114Sscottl
710157114Sscottl	return (0);
711157114Sscottl}
712157114Sscottl
713157114Sscottlstatic int
714157114Sscottlmfi_get_controller_info(struct mfi_softc *sc)
715157114Sscottl{
716159806Sps	struct mfi_command *cm = NULL;
717159806Sps	struct mfi_ctrl_info *ci = NULL;
718157114Sscottl	uint32_t max_sectors_1, max_sectors_2;
719157114Sscottl	int error;
720157114Sscottl
721159806Sps	mtx_lock(&sc->mfi_io_lock);
722159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
723159806Sps	    (void **)&ci, sizeof(*ci));
724159806Sps	if (error)
725159806Sps		goto out;
726157114Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
727157114Sscottl
728157114Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
729157114Sscottl		device_printf(sc->mfi_dev, "Failed to get controller info\n");
730162458Sscottl		sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
731157114Sscottl		    MFI_SECTOR_LEN;
732159806Sps		error = 0;
733159806Sps		goto out;
734157114Sscottl	}
735157114Sscottl
736157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
737157114Sscottl	    BUS_DMASYNC_POSTREAD);
738157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
739157114Sscottl
740157114Sscottl	max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io;
741157114Sscottl	max_sectors_2 = ci->max_request_size;
742157114Sscottl	sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
743157114Sscottl
744159806Spsout:
745159806Sps	if (ci)
746159806Sps		free(ci, M_MFIBUF);
747159806Sps	if (cm)
748159806Sps		mfi_release_command(cm);
749159806Sps	mtx_unlock(&sc->mfi_io_lock);
750157114Sscottl	return (error);
751157114Sscottl}
752157114Sscottl
753157114Sscottlstatic int
754159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
755158737Sambrisko{
756159812Sps	struct mfi_command *cm = NULL;
757158737Sambrisko	int error;
758158737Sambrisko
759159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
760159806Sps	    (void **)log_state, sizeof(**log_state));
761159806Sps	if (error)
762159806Sps		goto out;
763159810Sps	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
764158737Sambrisko
765158737Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
766159802Sps		device_printf(sc->mfi_dev, "Failed to get log state\n");
767159806Sps		goto out;
768158737Sambrisko	}
769158737Sambrisko
770158737Sambrisko	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
771158737Sambrisko	    BUS_DMASYNC_POSTREAD);
772158737Sambrisko	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
773158737Sambrisko
774159806Spsout:
775159812Sps	if (cm)
776159812Sps		mfi_release_command(cm);
777158737Sambrisko
778158737Sambrisko	return (error);
779158737Sambrisko}
780158737Sambrisko
781158737Sambriskostatic int
782158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
783158737Sambrisko{
784159806Sps	struct mfi_evt_log_state *log_state = NULL;
785158737Sambrisko	union mfi_evt class_locale;
786158737Sambrisko	int error = 0;
787158737Sambrisko	uint32_t seq;
788158737Sambrisko
789158737Sambrisko	class_locale.members.reserved = 0;
790162118Sambrisko	class_locale.members.locale = mfi_event_locale;
791162118Sambrisko	class_locale.members.class  = mfi_event_class;
792158737Sambrisko
793158737Sambrisko	if (seq_start == 0) {
794158737Sambrisko		error = mfi_get_log_state(sc, &log_state);
795159806Sps		if (error) {
796159806Sps			if (log_state)
797159806Sps				free(log_state, M_MFIBUF);
798158737Sambrisko			return (error);
799159806Sps		}
800180037Sjhb
801180037Sjhb		/*
802180037Sjhb		 * Walk through any events that fired since the last
803180037Sjhb		 * shutdown.
804180037Sjhb		 */
805180037Sjhb		mfi_parse_entries(sc, log_state->shutdown_seq_num,
806180037Sjhb		    log_state->newest_seq_num);
807180037Sjhb		seq = log_state->newest_seq_num;
808158737Sambrisko	} else
809158737Sambrisko		seq = seq_start;
810158737Sambrisko	mfi_aen_register(sc, seq, class_locale.word);
811159806Sps	free(log_state, M_MFIBUF);
812158737Sambrisko
813158737Sambrisko	return 0;
814158737Sambrisko}
815158737Sambrisko
816158737Sambriskostatic int
817159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
818159811Sps{
819159811Sps
820159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
821159811Sps	cm->cm_complete = NULL;
822159811Sps
823170284Sambrisko
824170284Sambrisko	/*
825170284Sambrisko	 * MegaCli can issue a DCMD of 0.  In this case do nothing
826170284Sambrisko	 * and return 0 to it as status
827170284Sambrisko	 */
828170284Sambrisko	if (cm->cm_frame->dcmd.opcode == 0) {
829170284Sambrisko		cm->cm_frame->header.cmd_status = MFI_STAT_OK;
830170284Sambrisko		cm->cm_error = 0;
831170284Sambrisko		return (cm->cm_error);
832170284Sambrisko	}
833159811Sps	mfi_enqueue_ready(cm);
834159811Sps	mfi_startio(sc);
835170284Sambrisko	if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
836170284Sambrisko		msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
837170284Sambrisko	return (cm->cm_error);
838159811Sps}
839159811Sps
840157114Sscottlvoid
841157114Sscottlmfi_free(struct mfi_softc *sc)
842157114Sscottl{
843157114Sscottl	struct mfi_command *cm;
844157114Sscottl	int i;
845157114Sscottl
846162619Sscottl	callout_drain(&sc->mfi_watchdog_callout);
847162619Sscottl
848157114Sscottl	if (sc->mfi_cdev != NULL)
849157114Sscottl		destroy_dev(sc->mfi_cdev);
850157114Sscottl
851157114Sscottl	if (sc->mfi_total_cmds != 0) {
852157114Sscottl		for (i = 0; i < sc->mfi_total_cmds; i++) {
853157114Sscottl			cm = &sc->mfi_commands[i];
854157114Sscottl			bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
855157114Sscottl		}
856157114Sscottl		free(sc->mfi_commands, M_MFIBUF);
857157114Sscottl	}
858157114Sscottl
859157114Sscottl	if (sc->mfi_intr)
860157114Sscottl		bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
861157114Sscottl	if (sc->mfi_irq != NULL)
862157114Sscottl		bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
863157114Sscottl		    sc->mfi_irq);
864157114Sscottl
865157114Sscottl	if (sc->mfi_sense_busaddr != 0)
866157114Sscottl		bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
867157114Sscottl	if (sc->mfi_sense != NULL)
868157114Sscottl		bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
869157114Sscottl		    sc->mfi_sense_dmamap);
870157114Sscottl	if (sc->mfi_sense_dmat != NULL)
871157114Sscottl		bus_dma_tag_destroy(sc->mfi_sense_dmat);
872157114Sscottl
873157114Sscottl	if (sc->mfi_frames_busaddr != 0)
874157114Sscottl		bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
875157114Sscottl	if (sc->mfi_frames != NULL)
876157114Sscottl		bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
877157114Sscottl		    sc->mfi_frames_dmamap);
878157114Sscottl	if (sc->mfi_frames_dmat != NULL)
879157114Sscottl		bus_dma_tag_destroy(sc->mfi_frames_dmat);
880157114Sscottl
881157114Sscottl	if (sc->mfi_comms_busaddr != 0)
882157114Sscottl		bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
883157114Sscottl	if (sc->mfi_comms != NULL)
884157114Sscottl		bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
885157114Sscottl		    sc->mfi_comms_dmamap);
886157114Sscottl	if (sc->mfi_comms_dmat != NULL)
887157114Sscottl		bus_dma_tag_destroy(sc->mfi_comms_dmat);
888157114Sscottl
889157114Sscottl	if (sc->mfi_buffer_dmat != NULL)
890157114Sscottl		bus_dma_tag_destroy(sc->mfi_buffer_dmat);
891157114Sscottl	if (sc->mfi_parent_dmat != NULL)
892157114Sscottl		bus_dma_tag_destroy(sc->mfi_parent_dmat);
893157114Sscottl
894171821Sjhb	if (mtx_initialized(&sc->mfi_io_lock)) {
895157114Sscottl		mtx_destroy(&sc->mfi_io_lock);
896171821Sjhb		sx_destroy(&sc->mfi_config_lock);
897171821Sjhb	}
898157114Sscottl
899157114Sscottl	return;
900157114Sscottl}
901157114Sscottl
902157114Sscottlstatic void
903157114Sscottlmfi_startup(void *arg)
904157114Sscottl{
905157114Sscottl	struct mfi_softc *sc;
906157114Sscottl
907157114Sscottl	sc = (struct mfi_softc *)arg;
908157114Sscottl
909157114Sscottl	config_intrhook_disestablish(&sc->mfi_ich);
910157114Sscottl
911171980Sscottl	sc->mfi_enable_intr(sc);
912171821Sjhb	sx_xlock(&sc->mfi_config_lock);
913163398Sscottl	mtx_lock(&sc->mfi_io_lock);
914159811Sps	mfi_ldprobe(sc);
915163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
916171821Sjhb	sx_xunlock(&sc->mfi_config_lock);
917157114Sscottl}
918157114Sscottl
919157114Sscottlstatic void
920157114Sscottlmfi_intr(void *arg)
921157114Sscottl{
922157114Sscottl	struct mfi_softc *sc;
923157114Sscottl	struct mfi_command *cm;
924171980Sscottl	uint32_t pi, ci, context;
925157114Sscottl
926157114Sscottl	sc = (struct mfi_softc *)arg;
927157114Sscottl
928171980Sscottl	if (sc->mfi_check_clear_intr(sc))
929157114Sscottl		return;
930163398Sscottl
931157114Sscottl	pi = sc->mfi_comms->hw_pi;
932157114Sscottl	ci = sc->mfi_comms->hw_ci;
933157114Sscottl	mtx_lock(&sc->mfi_io_lock);
934157114Sscottl	while (ci != pi) {
935157114Sscottl		context = sc->mfi_comms->hw_reply_q[ci];
936170284Sambrisko		if (context < sc->mfi_max_fw_cmds) {
937170284Sambrisko			cm = &sc->mfi_commands[context];
938170284Sambrisko			mfi_remove_busy(cm);
939170284Sambrisko			cm->cm_error = 0;
940170284Sambrisko			mfi_complete(sc, cm);
941170284Sambrisko		}
942162099Sscottl		if (++ci == (sc->mfi_max_fw_cmds + 1)) {
943157114Sscottl			ci = 0;
944157114Sscottl		}
945157114Sscottl	}
946157114Sscottl
947157114Sscottl	sc->mfi_comms->hw_ci = ci;
948157114Sscottl
949163398Sscottl	/* Give defered I/O a chance to run */
950163398Sscottl	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
951163398Sscottl		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
952163398Sscottl	mfi_startio(sc);
953163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
954163398Sscottl
955157114Sscottl	return;
956157114Sscottl}
957157114Sscottl
958157114Sscottlint
959157114Sscottlmfi_shutdown(struct mfi_softc *sc)
960157114Sscottl{
961157114Sscottl	struct mfi_dcmd_frame *dcmd;
962157114Sscottl	struct mfi_command *cm;
963157114Sscottl	int error;
964157114Sscottl
965159806Sps	mtx_lock(&sc->mfi_io_lock);
966159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
967163398Sscottl	if (error) {
968163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
969159806Sps		return (error);
970163398Sscottl	}
971157114Sscottl
972158737Sambrisko	if (sc->mfi_aen_cm != NULL)
973158737Sambrisko		mfi_abort(sc, sc->mfi_aen_cm);
974157114Sscottl
975157114Sscottl	dcmd = &cm->cm_frame->dcmd;
976157114Sscottl	dcmd->header.flags = MFI_FRAME_DIR_NONE;
977164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
978164375Sscottl	cm->cm_data = NULL;
979157114Sscottl
980164375Sscottl	if ((error = mfi_mapcmd(sc, cm)) != 0) {
981157114Sscottl		device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
982157114Sscottl	}
983157114Sscottl
984159812Sps	mfi_release_command(cm);
985163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
986157114Sscottl	return (error);
987157114Sscottl}
988157114Sscottl
989157114Sscottlstatic void
990159811Spsmfi_ldprobe(struct mfi_softc *sc)
991157114Sscottl{
992159811Sps	struct mfi_frame_header *hdr;
993159811Sps	struct mfi_command *cm = NULL;
994159811Sps	struct mfi_ld_list *list = NULL;
995171821Sjhb	struct mfi_disk *ld;
996159811Sps	int error, i;
997157114Sscottl
998171821Sjhb	sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
999163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1000163398Sscottl
1001159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1002159811Sps	    (void **)&list, sizeof(*list));
1003159811Sps	if (error)
1004159811Sps		goto out;
1005159811Sps
1006159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1007159811Sps	if (mfi_wait_command(sc, cm) != 0) {
1008159811Sps		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1009159811Sps		goto out;
1010157114Sscottl	}
1011157114Sscottl
1012157114Sscottl	hdr = &cm->cm_frame->header;
1013159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1014159811Sps		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1015159811Sps		    hdr->cmd_status);
1016159811Sps		goto out;
1017157114Sscottl	}
1018157114Sscottl
1019171821Sjhb	for (i = 0; i < list->ld_count; i++) {
1020171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1021171821Sjhb			if (ld->ld_id == list->ld_list[i].ld.v.target_id)
1022171821Sjhb				goto skip_add;
1023171821Sjhb		}
1024163398Sscottl		mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
1025171821Sjhb	skip_add:;
1026171821Sjhb	}
1027159811Spsout:
1028159811Sps	if (list)
1029159811Sps		free(list, M_MFIBUF);
1030159811Sps	if (cm)
1031157114Sscottl		mfi_release_command(cm);
1032163398Sscottl
1033159811Sps	return;
1034157114Sscottl}
1035157114Sscottl
1036180038Sjhb/*
1037180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000.  If
1038180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since
1039180038Sjhb * boot.
1040180038Sjhb */
1041180038Sjhbstatic const char *
1042180038Sjhbformat_timestamp(uint32_t timestamp)
1043158737Sambrisko{
1044180038Sjhb	static char buffer[32];
1045180038Sjhb
1046180038Sjhb	if ((timestamp & 0xff000000) == 0xff000000)
1047180038Sjhb		snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
1048180038Sjhb		    0x00ffffff);
1049180038Sjhb	else
1050180038Sjhb		snprintf(buffer, sizeof(buffer), "%us", timestamp);
1051180038Sjhb	return (buffer);
1052180038Sjhb}
1053180038Sjhb
1054180038Sjhbstatic const char *
1055180038Sjhbformat_class(int8_t class)
1056180038Sjhb{
1057180038Sjhb	static char buffer[6];
1058180038Sjhb
1059180038Sjhb	switch (class) {
1060180038Sjhb	case MFI_EVT_CLASS_DEBUG:
1061180038Sjhb		return ("debug");
1062180038Sjhb	case MFI_EVT_CLASS_PROGRESS:
1063180038Sjhb		return ("progress");
1064180038Sjhb	case MFI_EVT_CLASS_INFO:
1065180038Sjhb		return ("info");
1066180038Sjhb	case MFI_EVT_CLASS_WARNING:
1067180038Sjhb		return ("WARN");
1068180038Sjhb	case MFI_EVT_CLASS_CRITICAL:
1069180038Sjhb		return ("CRIT");
1070180038Sjhb	case MFI_EVT_CLASS_FATAL:
1071180038Sjhb		return ("FATAL");
1072180038Sjhb	case MFI_EVT_CLASS_DEAD:
1073180038Sjhb		return ("DEAD");
1074158737Sambrisko	default:
1075180038Sjhb		snprintf(buffer, sizeof(buffer), "%d", class);
1076180038Sjhb		return (buffer);
1077158737Sambrisko	}
1078158737Sambrisko}
1079158737Sambrisko
1080180038Sjhbstatic void
1081180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1082180038Sjhb{
1083180038Sjhb
1084180038Sjhb	device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1085180038Sjhb	    format_timestamp(detail->time), detail->class.members.locale,
1086180038Sjhb	    format_class(detail->class.members.class), detail->description);
1087180038Sjhb}
1088180038Sjhb
1089157114Sscottlstatic int
1090158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1091158737Sambrisko{
1092158737Sambrisko	struct mfi_command *cm;
1093158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1094158737Sambrisko	union mfi_evt current_aen, prior_aen;
1095159806Sps	struct mfi_evt_detail *ed = NULL;
1096163398Sscottl	int error = 0;
1097158737Sambrisko
1098158737Sambrisko	current_aen.word = locale;
1099158737Sambrisko	if (sc->mfi_aen_cm != NULL) {
1100158737Sambrisko		prior_aen.word =
1101158737Sambrisko		    ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1102158737Sambrisko		if (prior_aen.members.class <= current_aen.members.class &&
1103158737Sambrisko		    !((prior_aen.members.locale & current_aen.members.locale)
1104158737Sambrisko		    ^current_aen.members.locale)) {
1105158737Sambrisko			return (0);
1106158737Sambrisko		} else {
1107158737Sambrisko			prior_aen.members.locale |= current_aen.members.locale;
1108158737Sambrisko			if (prior_aen.members.class
1109158737Sambrisko			    < current_aen.members.class)
1110158737Sambrisko				current_aen.members.class =
1111158737Sambrisko				    prior_aen.members.class;
1112158737Sambrisko			mfi_abort(sc, sc->mfi_aen_cm);
1113158737Sambrisko		}
1114158737Sambrisko	}
1115158737Sambrisko
1116159806Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1117159806Sps	    (void **)&ed, sizeof(*ed));
1118163398Sscottl	if (error) {
1119163398Sscottl		goto out;
1120163398Sscottl	}
1121158737Sambrisko
1122158737Sambrisko	dcmd = &cm->cm_frame->dcmd;
1123158737Sambrisko	((uint32_t *)&dcmd->mbox)[0] = seq;
1124158737Sambrisko	((uint32_t *)&dcmd->mbox)[1] = locale;
1125158737Sambrisko	cm->cm_flags = MFI_CMD_DATAIN;
1126158737Sambrisko	cm->cm_complete = mfi_aen_complete;
1127158737Sambrisko
1128158737Sambrisko	sc->mfi_aen_cm = cm;
1129158737Sambrisko
1130158737Sambrisko	mfi_enqueue_ready(cm);
1131158737Sambrisko	mfi_startio(sc);
1132158737Sambrisko
1133163398Sscottlout:
1134163398Sscottl	return (error);
1135158737Sambrisko}
1136158737Sambrisko
1137158737Sambriskostatic void
1138158737Sambriskomfi_aen_complete(struct mfi_command *cm)
1139158737Sambrisko{
1140158737Sambrisko	struct mfi_frame_header *hdr;
1141158737Sambrisko	struct mfi_softc *sc;
1142158737Sambrisko	struct mfi_evt_detail *detail;
1143163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1144158737Sambrisko	int seq = 0, aborted = 0;
1145158737Sambrisko
1146158737Sambrisko	sc = cm->cm_sc;
1147158737Sambrisko	hdr = &cm->cm_frame->header;
1148158737Sambrisko
1149158737Sambrisko	if (sc->mfi_aen_cm == NULL)
1150158737Sambrisko		return;
1151158737Sambrisko
1152158737Sambrisko	if (sc->mfi_aen_cm->cm_aen_abort || hdr->cmd_status == 0xff) {
1153158737Sambrisko		sc->mfi_aen_cm->cm_aen_abort = 0;
1154158737Sambrisko		aborted = 1;
1155158737Sambrisko	} else {
1156158737Sambrisko		sc->mfi_aen_triggered = 1;
1157163398Sscottl		if (sc->mfi_poll_waiting) {
1158163398Sscottl			sc->mfi_poll_waiting = 0;
1159158737Sambrisko			selwakeup(&sc->mfi_select);
1160163398Sscottl		}
1161158737Sambrisko		detail = cm->cm_data;
1162163398Sscottl		/*
1163163398Sscottl		 * XXX If this function is too expensive or is recursive, then
1164163398Sscottl		 * events should be put onto a queue and processed later.
1165163398Sscottl		 */
1166158737Sambrisko		mfi_decode_evt(sc, detail);
1167158737Sambrisko		seq = detail->seq + 1;
1168163398Sscottl		TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1169158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1170158737Sambrisko			    aen_link);
1171163398Sscottl			PROC_LOCK(mfi_aen_entry->p);
1172158737Sambrisko			psignal(mfi_aen_entry->p, SIGIO);
1173163398Sscottl			PROC_UNLOCK(mfi_aen_entry->p);
1174158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1175158737Sambrisko		}
1176158737Sambrisko	}
1177158737Sambrisko
1178158737Sambrisko	free(cm->cm_data, M_MFIBUF);
1179158737Sambrisko	sc->mfi_aen_cm = NULL;
1180158737Sambrisko	wakeup(&sc->mfi_aen_cm);
1181158737Sambrisko	mfi_release_command(cm);
1182158737Sambrisko
1183158737Sambrisko	/* set it up again so the driver can catch more events */
1184158737Sambrisko	if (!aborted) {
1185158737Sambrisko		mfi_aen_setup(sc, seq);
1186158737Sambrisko	}
1187158737Sambrisko}
1188158737Sambrisko
1189180037Sjhb#define MAX_EVENTS 15
1190180037Sjhb
1191158737Sambriskostatic int
1192180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1193158737Sambrisko{
1194158737Sambrisko	struct mfi_command *cm;
1195158737Sambrisko	struct mfi_dcmd_frame *dcmd;
1196162118Sambrisko	struct mfi_evt_list *el;
1197180037Sjhb	union mfi_evt class_locale;
1198180037Sjhb	int error, i, seq, size;
1199158737Sambrisko
1200180037Sjhb	class_locale.members.reserved = 0;
1201180037Sjhb	class_locale.members.locale = mfi_event_locale;
1202180037Sjhb	class_locale.members.class  = mfi_event_class;
1203158737Sambrisko
1204162118Sambrisko	size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
1205162118Sambrisko		* (MAX_EVENTS - 1);
1206162118Sambrisko	el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1207180037Sjhb	if (el == NULL)
1208158737Sambrisko		return (ENOMEM);
1209158737Sambrisko
1210180037Sjhb	for (seq = start_seq;;) {
1211180037Sjhb		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1212180037Sjhb			free(el, M_MFIBUF);
1213180037Sjhb			return (EBUSY);
1214180037Sjhb		}
1215158737Sambrisko
1216180037Sjhb		dcmd = &cm->cm_frame->dcmd;
1217180037Sjhb		bzero(dcmd->mbox, MFI_MBOX_SIZE);
1218180037Sjhb		dcmd->header.cmd = MFI_CMD_DCMD;
1219180037Sjhb		dcmd->header.timeout = 0;
1220180037Sjhb		dcmd->header.data_len = size;
1221180037Sjhb		dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1222180037Sjhb		((uint32_t *)&dcmd->mbox)[0] = seq;
1223180037Sjhb		((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1224180037Sjhb		cm->cm_sg = &dcmd->sgl;
1225180037Sjhb		cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1226180037Sjhb		cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1227180037Sjhb		cm->cm_data = el;
1228180037Sjhb		cm->cm_len = size;
1229180037Sjhb
1230180037Sjhb		if ((error = mfi_mapcmd(sc, cm)) != 0) {
1231180037Sjhb			device_printf(sc->mfi_dev,
1232180037Sjhb			    "Failed to get controller entries\n");
1233180037Sjhb			mfi_release_command(cm);
1234180037Sjhb			break;
1235180037Sjhb		}
1236180037Sjhb
1237180037Sjhb		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1238180037Sjhb		    BUS_DMASYNC_POSTREAD);
1239180037Sjhb		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1240180037Sjhb
1241180037Sjhb		if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1242180037Sjhb			mfi_release_command(cm);
1243180037Sjhb			break;
1244180037Sjhb		}
1245180037Sjhb		if (dcmd->header.cmd_status != MFI_STAT_OK) {
1246180037Sjhb			device_printf(sc->mfi_dev,
1247180037Sjhb			    "Error %d fetching controller entries\n",
1248180037Sjhb			    dcmd->header.cmd_status);
1249180037Sjhb			mfi_release_command(cm);
1250180037Sjhb			break;
1251180037Sjhb		}
1252158737Sambrisko		mfi_release_command(cm);
1253158737Sambrisko
1254162473Sambrisko		for (i = 0; i < el->count; i++) {
1255180037Sjhb			/*
1256180037Sjhb			 * If this event is newer than 'stop_seq' then
1257180037Sjhb			 * break out of the loop.  Note that the log
1258180037Sjhb			 * is a circular buffer so we have to handle
1259180037Sjhb			 * the case that our stop point is earlier in
1260180037Sjhb			 * the buffer than our start point.
1261180037Sjhb			 */
1262180037Sjhb			if (el->event[i].seq >= stop_seq) {
1263180037Sjhb				if (start_seq <= stop_seq)
1264180037Sjhb					break;
1265180037Sjhb				else if (el->event[i].seq < start_seq)
1266180037Sjhb					break;
1267180037Sjhb			}
1268180037Sjhb			mfi_decode_evt(sc, &el->event[i]);
1269162473Sambrisko		}
1270180037Sjhb		seq = el->event[el->count - 1].seq + 1;
1271162118Sambrisko	}
1272158737Sambrisko
1273180037Sjhb	free(el, M_MFIBUF);
1274158737Sambrisko	return (0);
1275158737Sambrisko}
1276158737Sambrisko
1277158737Sambriskostatic int
1278159811Spsmfi_add_ld(struct mfi_softc *sc, int id)
1279157114Sscottl{
1280157114Sscottl	struct mfi_command *cm;
1281159811Sps	struct mfi_dcmd_frame *dcmd = NULL;
1282159811Sps	struct mfi_ld_info *ld_info = NULL;
1283159811Sps	int error;
1284157114Sscottl
1285159811Sps	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1286159811Sps
1287159811Sps	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1288159811Sps	    (void **)&ld_info, sizeof(*ld_info));
1289159811Sps	if (error) {
1290159811Sps		device_printf(sc->mfi_dev,
1291159811Sps		    "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1292159811Sps		if (ld_info)
1293159811Sps			free(ld_info, M_MFIBUF);
1294159811Sps		return (error);
1295157624Sscottl	}
1296159811Sps	cm->cm_flags = MFI_CMD_DATAIN;
1297159811Sps	dcmd = &cm->cm_frame->dcmd;
1298159811Sps	dcmd->mbox[0] = id;
1299160052Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1300160052Sambrisko		device_printf(sc->mfi_dev,
1301160052Sambrisko		    "Failed to get logical drive: %d\n", id);
1302160052Sambrisko		free(ld_info, M_MFIBUF);
1303160052Sambrisko		return (0);
1304160052Sambrisko	}
1305159811Sps
1306160052Sambrisko	mfi_add_ld_complete(cm);
1307157114Sscottl	return (0);
1308157114Sscottl}
1309157114Sscottl
1310157114Sscottlstatic void
1311159811Spsmfi_add_ld_complete(struct mfi_command *cm)
1312157114Sscottl{
1313157114Sscottl	struct mfi_frame_header *hdr;
1314159811Sps	struct mfi_ld_info *ld_info;
1315157114Sscottl	struct mfi_softc *sc;
1316159811Sps	device_t child;
1317157114Sscottl
1318157114Sscottl	sc = cm->cm_sc;
1319157114Sscottl	hdr = &cm->cm_frame->header;
1320159811Sps	ld_info = cm->cm_private;
1321157114Sscottl
1322159811Sps	if (hdr->cmd_status != MFI_STAT_OK) {
1323159811Sps		free(ld_info, M_MFIBUF);
1324157114Sscottl		mfi_release_command(cm);
1325157114Sscottl		return;
1326157114Sscottl	}
1327157114Sscottl	mfi_release_command(cm);
1328157114Sscottl
1329169611Sscottl	mtx_unlock(&sc->mfi_io_lock);
1330169611Sscottl	mtx_lock(&Giant);
1331157114Sscottl	if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) {
1332157114Sscottl		device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1333159811Sps		free(ld_info, M_MFIBUF);
1334169611Sscottl		mtx_unlock(&Giant);
1335169611Sscottl		mtx_lock(&sc->mfi_io_lock);
1336159811Sps		return;
1337157114Sscottl	}
1338157114Sscottl
1339169451Sscottl	device_set_ivars(child, ld_info);
1340157114Sscottl	device_set_desc(child, "MFI Logical Disk");
1341157114Sscottl	bus_generic_attach(sc->mfi_dev);
1342157114Sscottl	mtx_unlock(&Giant);
1343157114Sscottl	mtx_lock(&sc->mfi_io_lock);
1344157114Sscottl}
1345163399Sscottl
1346157114Sscottlstatic struct mfi_command *
1347157114Sscottlmfi_bio_command(struct mfi_softc *sc)
1348157114Sscottl{
1349157114Sscottl	struct mfi_io_frame *io;
1350157114Sscottl	struct mfi_command *cm;
1351157114Sscottl	struct bio *bio;
1352158737Sambrisko	int flags, blkcount;
1353157114Sscottl
1354157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1355157114Sscottl		return (NULL);
1356157114Sscottl
1357157114Sscottl	if ((bio = mfi_dequeue_bio(sc)) == NULL) {
1358157114Sscottl		mfi_release_command(cm);
1359157114Sscottl		return (NULL);
1360157114Sscottl	}
1361157114Sscottl
1362157114Sscottl	io = &cm->cm_frame->io;
1363157114Sscottl	switch (bio->bio_cmd & 0x03) {
1364157114Sscottl	case BIO_READ:
1365157114Sscottl		io->header.cmd = MFI_CMD_LD_READ;
1366157114Sscottl		flags = MFI_CMD_DATAIN;
1367157114Sscottl		break;
1368157114Sscottl	case BIO_WRITE:
1369157114Sscottl		io->header.cmd = MFI_CMD_LD_WRITE;
1370157114Sscottl		flags = MFI_CMD_DATAOUT;
1371157114Sscottl		break;
1372157114Sscottl	default:
1373157114Sscottl		panic("Invalid bio command");
1374157114Sscottl	}
1375157114Sscottl
1376157114Sscottl	/* Cheat with the sector length to avoid a non-constant division */
1377157114Sscottl	blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1378157114Sscottl	io->header.target_id = (uintptr_t)bio->bio_driver1;
1379157114Sscottl	io->header.timeout = 0;
1380157114Sscottl	io->header.flags = 0;
1381157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1382157114Sscottl	io->header.data_len = blkcount;
1383157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1384157114Sscottl	io->sense_addr_hi = 0;
1385157114Sscottl	io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
1386157114Sscottl	io->lba_lo = bio->bio_pblkno & 0xffffffff;
1387157114Sscottl	cm->cm_complete = mfi_bio_complete;
1388157114Sscottl	cm->cm_private = bio;
1389157114Sscottl	cm->cm_data = bio->bio_data;
1390157114Sscottl	cm->cm_len = bio->bio_bcount;
1391157114Sscottl	cm->cm_sg = &io->sgl;
1392157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1393157114Sscottl	cm->cm_flags = flags;
1394157114Sscottl	return (cm);
1395157114Sscottl}
1396157114Sscottl
1397157114Sscottlstatic void
1398157114Sscottlmfi_bio_complete(struct mfi_command *cm)
1399157114Sscottl{
1400157114Sscottl	struct bio *bio;
1401157114Sscottl	struct mfi_frame_header *hdr;
1402157114Sscottl	struct mfi_softc *sc;
1403157114Sscottl
1404157114Sscottl	bio = cm->cm_private;
1405157114Sscottl	hdr = &cm->cm_frame->header;
1406157114Sscottl	sc = cm->cm_sc;
1407157114Sscottl
1408157114Sscottl	if ((hdr->cmd_status != 0) || (hdr->scsi_status != 0)) {
1409157114Sscottl		bio->bio_flags |= BIO_ERROR;
1410157114Sscottl		bio->bio_error = EIO;
1411157114Sscottl		device_printf(sc->mfi_dev, "I/O error, status= %d "
1412157114Sscottl		    "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
1413157114Sscottl		mfi_print_sense(cm->cm_sc, cm->cm_sense);
1414184897Sambrisko	} else if (cm->cm_error != 0) {
1415184897Sambrisko		bio->bio_flags |= BIO_ERROR;
1416157114Sscottl	}
1417157114Sscottl
1418157114Sscottl	mfi_release_command(cm);
1419157114Sscottl	mfi_disk_complete(bio);
1420157114Sscottl}
1421157114Sscottl
1422157114Sscottlvoid
1423157114Sscottlmfi_startio(struct mfi_softc *sc)
1424157114Sscottl{
1425157114Sscottl	struct mfi_command *cm;
1426169611Sscottl	struct ccb_hdr *ccbh;
1427157114Sscottl
1428157114Sscottl	for (;;) {
1429157114Sscottl		/* Don't bother if we're short on resources */
1430157114Sscottl		if (sc->mfi_flags & MFI_FLAGS_QFRZN)
1431157114Sscottl			break;
1432157114Sscottl
1433157114Sscottl		/* Try a command that has already been prepared */
1434157114Sscottl		cm = mfi_dequeue_ready(sc);
1435157114Sscottl
1436169611Sscottl		if (cm == NULL) {
1437169611Sscottl			if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
1438169611Sscottl				cm = sc->mfi_cam_start(ccbh);
1439169611Sscottl		}
1440169611Sscottl
1441157114Sscottl		/* Nope, so look for work on the bioq */
1442157114Sscottl		if (cm == NULL)
1443157114Sscottl			cm = mfi_bio_command(sc);
1444157114Sscottl
1445157114Sscottl		/* No work available, so exit */
1446157114Sscottl		if (cm == NULL)
1447157114Sscottl			break;
1448157114Sscottl
1449157114Sscottl		/* Send the command to the controller */
1450157114Sscottl		if (mfi_mapcmd(sc, cm) != 0) {
1451157114Sscottl			mfi_requeue_ready(cm);
1452157114Sscottl			break;
1453157114Sscottl		}
1454157114Sscottl	}
1455157114Sscottl}
1456157114Sscottl
1457157114Sscottlstatic int
1458157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
1459157114Sscottl{
1460157114Sscottl	int error, polled;
1461157114Sscottl
1462163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1463163398Sscottl
1464157114Sscottl	if (cm->cm_data != NULL) {
1465157114Sscottl		polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
1466157114Sscottl		error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
1467157114Sscottl		    cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
1468157114Sscottl		if (error == EINPROGRESS) {
1469157114Sscottl			sc->mfi_flags |= MFI_FLAGS_QFRZN;
1470157114Sscottl			return (0);
1471157114Sscottl		}
1472157114Sscottl	} else {
1473157114Sscottl		error = mfi_send_frame(sc, cm);
1474157114Sscottl	}
1475157114Sscottl
1476157114Sscottl	return (error);
1477157114Sscottl}
1478157114Sscottl
1479157114Sscottlstatic void
1480157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1481157114Sscottl{
1482157114Sscottl	struct mfi_frame_header *hdr;
1483157114Sscottl	struct mfi_command *cm;
1484157237Sscottl	union mfi_sgl *sgl;
1485157114Sscottl	struct mfi_softc *sc;
1486157114Sscottl	int i, dir;
1487157114Sscottl
1488157114Sscottl	cm = (struct mfi_command *)arg;
1489157114Sscottl	sc = cm->cm_sc;
1490157237Sscottl	hdr = &cm->cm_frame->header;
1491157237Sscottl	sgl = cm->cm_sg;
1492157114Sscottl
1493170284Sambrisko	if (error) {
1494170284Sambrisko		printf("error %d in callback\n", error);
1495170284Sambrisko		cm->cm_error = error;
1496170284Sambrisko		mfi_complete(sc, cm);
1497170284Sambrisko		return;
1498170284Sambrisko	}
1499170284Sambrisko
1500157237Sscottl	if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
1501157237Sscottl		for (i = 0; i < nsegs; i++) {
1502157237Sscottl			sgl->sg32[i].addr = segs[i].ds_addr;
1503157237Sscottl			sgl->sg32[i].len = segs[i].ds_len;
1504157114Sscottl		}
1505157237Sscottl	} else {
1506157237Sscottl		for (i = 0; i < nsegs; i++) {
1507157237Sscottl			sgl->sg64[i].addr = segs[i].ds_addr;
1508157237Sscottl			sgl->sg64[i].len = segs[i].ds_len;
1509157237Sscottl		}
1510157237Sscottl		hdr->flags |= MFI_FRAME_SGL64;
1511157114Sscottl	}
1512157114Sscottl	hdr->sg_count = nsegs;
1513157114Sscottl
1514157114Sscottl	dir = 0;
1515157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAIN) {
1516157114Sscottl		dir |= BUS_DMASYNC_PREREAD;
1517157114Sscottl		hdr->flags |= MFI_FRAME_DIR_READ;
1518157114Sscottl	}
1519157114Sscottl	if (cm->cm_flags & MFI_CMD_DATAOUT) {
1520157114Sscottl		dir |= BUS_DMASYNC_PREWRITE;
1521157114Sscottl		hdr->flags |= MFI_FRAME_DIR_WRITE;
1522157114Sscottl	}
1523157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1524157114Sscottl	cm->cm_flags |= MFI_CMD_MAPPED;
1525157114Sscottl
1526157114Sscottl	/*
1527157114Sscottl	 * Instead of calculating the total number of frames in the
1528157114Sscottl	 * compound frame, it's already assumed that there will be at
1529157114Sscottl	 * least 1 frame, so don't compensate for the modulo of the
1530157114Sscottl	 * following division.
1531157114Sscottl	 */
1532162458Sscottl	cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
1533157114Sscottl	cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
1534157114Sscottl
1535164375Sscottl	mfi_send_frame(sc, cm);
1536157114Sscottl
1537157114Sscottl	return;
1538157114Sscottl}
1539157114Sscottl
1540157114Sscottlstatic int
1541157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1542157114Sscottl{
1543164375Sscottl	struct mfi_frame_header *hdr;
1544165225Sambrisko	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
1545157114Sscottl
1546164375Sscottl	hdr = &cm->cm_frame->header;
1547164375Sscottl
1548164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1549164375Sscottl		cm->cm_timestamp = time_uptime;
1550164375Sscottl		mfi_enqueue_busy(cm);
1551164375Sscottl	} else {
1552164375Sscottl		hdr->cmd_status = 0xff;
1553164375Sscottl		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
1554164375Sscottl	}
1555164375Sscottl
1556157114Sscottl	/*
1557157114Sscottl	 * The bus address of the command is aligned on a 64 byte boundary,
1558157114Sscottl	 * leaving the least 6 bits as zero.  For whatever reason, the
1559157114Sscottl	 * hardware wants the address shifted right by three, leaving just
1560162458Sscottl	 * 3 zero bits.  These three bits are then used as a prefetching
1561162458Sscottl	 * hint for the hardware to predict how many frames need to be
1562162458Sscottl	 * fetched across the bus.  If a command has more than 8 frames
1563162458Sscottl	 * then the 3 bits are set to 0x7 and the firmware uses other
1564162458Sscottl	 * information in the command to determine the total amount to fetch.
1565162458Sscottl	 * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
1566162458Sscottl	 * is enough for both 32bit and 64bit systems.
1567157114Sscottl	 */
1568162458Sscottl	if (cm->cm_extra_frames > 7)
1569162458Sscottl		cm->cm_extra_frames = 7;
1570162458Sscottl
1571171980Sscottl	sc->mfi_issue_cmd(sc,cm->cm_frame_busaddr,cm->cm_extra_frames);
1572164375Sscottl
1573164375Sscottl	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
1574164375Sscottl		return (0);
1575164375Sscottl
1576164375Sscottl	/* This is a polled command, so busy-wait for it to complete. */
1577164375Sscottl	while (hdr->cmd_status == 0xff) {
1578164375Sscottl		DELAY(1000);
1579165225Sambrisko		tm -= 1;
1580164375Sscottl		if (tm <= 0)
1581164375Sscottl			break;
1582164375Sscottl	}
1583164375Sscottl
1584164375Sscottl	if (hdr->cmd_status == 0xff) {
1585165225Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
1586165225Sambrisko			      "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
1587164375Sscottl		return (ETIMEDOUT);
1588164375Sscottl	}
1589164375Sscottl
1590157114Sscottl	return (0);
1591157114Sscottl}
1592157114Sscottl
1593157114Sscottlstatic void
1594157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
1595157114Sscottl{
1596157114Sscottl	int dir;
1597157114Sscottl
1598157114Sscottl	if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
1599157114Sscottl		dir = 0;
1600157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAIN)
1601157114Sscottl			dir |= BUS_DMASYNC_POSTREAD;
1602157114Sscottl		if (cm->cm_flags & MFI_CMD_DATAOUT)
1603157114Sscottl			dir |= BUS_DMASYNC_POSTWRITE;
1604157114Sscottl
1605157114Sscottl		bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
1606157114Sscottl		bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1607157114Sscottl		cm->cm_flags &= ~MFI_CMD_MAPPED;
1608157114Sscottl	}
1609157114Sscottl
1610170284Sambrisko	cm->cm_flags |= MFI_CMD_COMPLETED;
1611170284Sambrisko
1612157114Sscottl	if (cm->cm_complete != NULL)
1613157114Sscottl		cm->cm_complete(cm);
1614159811Sps	else
1615159811Sps		wakeup(cm);
1616157114Sscottl}
1617157114Sscottl
1618158737Sambriskostatic int
1619158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
1620158737Sambrisko{
1621158737Sambrisko	struct mfi_command *cm;
1622158737Sambrisko	struct mfi_abort_frame *abort;
1623165225Sambrisko	int i = 0;
1624158737Sambrisko
1625163398Sscottl	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1626163398Sscottl
1627158737Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
1628158737Sambrisko		return (EBUSY);
1629158737Sambrisko	}
1630158737Sambrisko
1631158737Sambrisko	abort = &cm->cm_frame->abort;
1632158737Sambrisko	abort->header.cmd = MFI_CMD_ABORT;
1633158737Sambrisko	abort->header.flags = 0;
1634158737Sambrisko	abort->abort_context = cm_abort->cm_frame->header.context;
1635158737Sambrisko	abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
1636158737Sambrisko	abort->abort_mfi_addr_hi = 0;
1637158737Sambrisko	cm->cm_data = NULL;
1638164375Sscottl	cm->cm_flags = MFI_CMD_POLLED;
1639158737Sambrisko
1640158737Sambrisko	sc->mfi_aen_cm->cm_aen_abort = 1;
1641158737Sambrisko	mfi_mapcmd(sc, cm);
1642158737Sambrisko	mfi_release_command(cm);
1643158737Sambrisko
1644165225Sambrisko	while (i < 5 && sc->mfi_aen_cm != NULL) {
1645163398Sscottl		msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
1646165225Sambrisko		i++;
1647158737Sambrisko	}
1648158737Sambrisko
1649158737Sambrisko	return (0);
1650158737Sambrisko}
1651158737Sambrisko
1652157114Sscottlint
1653157114Sscottlmfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
1654157114Sscottl{
1655157114Sscottl	struct mfi_command *cm;
1656157114Sscottl	struct mfi_io_frame *io;
1657157114Sscottl	int error;
1658157114Sscottl
1659157114Sscottl	if ((cm = mfi_dequeue_free(sc)) == NULL)
1660157114Sscottl		return (EBUSY);
1661157114Sscottl
1662157114Sscottl	io = &cm->cm_frame->io;
1663157114Sscottl	io->header.cmd = MFI_CMD_LD_WRITE;
1664157114Sscottl	io->header.target_id = id;
1665157114Sscottl	io->header.timeout = 0;
1666157114Sscottl	io->header.flags = 0;
1667157114Sscottl	io->header.sense_len = MFI_SENSE_LEN;
1668157114Sscottl	io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
1669157114Sscottl	io->sense_addr_lo = cm->cm_sense_busaddr;
1670157114Sscottl	io->sense_addr_hi = 0;
1671157114Sscottl	io->lba_hi = (lba & 0xffffffff00000000) >> 32;
1672157114Sscottl	io->lba_lo = lba & 0xffffffff;
1673157114Sscottl	cm->cm_data = virt;
1674157114Sscottl	cm->cm_len = len;
1675157114Sscottl	cm->cm_sg = &io->sgl;
1676157114Sscottl	cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
1677157114Sscottl	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
1678157114Sscottl
1679164375Sscottl	error = mfi_mapcmd(sc, cm);
1680157114Sscottl	bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1681157114Sscottl	    BUS_DMASYNC_POSTWRITE);
1682157114Sscottl	bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1683157114Sscottl	mfi_release_command(cm);
1684157114Sscottl
1685157114Sscottl	return (error);
1686157114Sscottl}
1687157114Sscottl
1688157114Sscottlstatic int
1689157114Sscottlmfi_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1690157114Sscottl{
1691157114Sscottl	struct mfi_softc *sc;
1692171822Sjhb	int error;
1693157114Sscottl
1694157114Sscottl	sc = dev->si_drv1;
1695163398Sscottl
1696163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1697171822Sjhb	if (sc->mfi_detaching)
1698171822Sjhb		error = ENXIO;
1699171822Sjhb	else {
1700171822Sjhb		sc->mfi_flags |= MFI_FLAGS_OPEN;
1701171822Sjhb		error = 0;
1702171822Sjhb	}
1703163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1704157114Sscottl
1705171822Sjhb	return (error);
1706157114Sscottl}
1707157114Sscottl
1708157114Sscottlstatic int
1709157114Sscottlmfi_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
1710157114Sscottl{
1711157114Sscottl	struct mfi_softc *sc;
1712163398Sscottl	struct mfi_aen *mfi_aen_entry, *tmp;
1713157114Sscottl
1714157114Sscottl	sc = dev->si_drv1;
1715163398Sscottl
1716163398Sscottl	mtx_lock(&sc->mfi_io_lock);
1717157114Sscottl	sc->mfi_flags &= ~MFI_FLAGS_OPEN;
1718157114Sscottl
1719163398Sscottl	TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
1720158737Sambrisko		if (mfi_aen_entry->p == curproc) {
1721158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1722158737Sambrisko			    aen_link);
1723158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
1724158737Sambrisko		}
1725158737Sambrisko	}
1726163398Sscottl	mtx_unlock(&sc->mfi_io_lock);
1727157114Sscottl	return (0);
1728157114Sscottl}
1729157114Sscottl
1730157114Sscottlstatic int
1731171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
1732171821Sjhb{
1733171821Sjhb
1734171821Sjhb	switch (opcode) {
1735171821Sjhb	case MFI_DCMD_LD_DELETE:
1736171821Sjhb	case MFI_DCMD_CFG_ADD:
1737171821Sjhb	case MFI_DCMD_CFG_CLEAR:
1738171821Sjhb		sx_xlock(&sc->mfi_config_lock);
1739171821Sjhb		return (1);
1740171821Sjhb	default:
1741171821Sjhb		return (0);
1742171821Sjhb	}
1743171821Sjhb}
1744171821Sjhb
1745171821Sjhbstatic void
1746171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked)
1747171821Sjhb{
1748171821Sjhb
1749171821Sjhb	if (locked)
1750171821Sjhb		sx_xunlock(&sc->mfi_config_lock);
1751171821Sjhb}
1752171821Sjhb
1753171821Sjhb/* Perform pre-issue checks on commands from userland and possibly veto them. */
1754171821Sjhbstatic int
1755171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
1756171821Sjhb{
1757171821Sjhb	struct mfi_disk *ld, *ld2;
1758171821Sjhb	int error;
1759171821Sjhb
1760171821Sjhb	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1761171821Sjhb	error = 0;
1762171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
1763171821Sjhb	case MFI_DCMD_LD_DELETE:
1764171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1765171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
1766171821Sjhb				break;
1767171821Sjhb		}
1768171821Sjhb		if (ld == NULL)
1769171821Sjhb			error = ENOENT;
1770171821Sjhb		else
1771171821Sjhb			error = mfi_disk_disable(ld);
1772171821Sjhb		break;
1773171821Sjhb	case MFI_DCMD_CFG_CLEAR:
1774171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1775171821Sjhb			error = mfi_disk_disable(ld);
1776171821Sjhb			if (error)
1777171821Sjhb				break;
1778171821Sjhb		}
1779171821Sjhb		if (error) {
1780171821Sjhb			TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
1781171821Sjhb				if (ld2 == ld)
1782171821Sjhb					break;
1783171821Sjhb				mfi_disk_enable(ld2);
1784171821Sjhb			}
1785171821Sjhb		}
1786171821Sjhb		break;
1787171821Sjhb	default:
1788171821Sjhb		break;
1789171821Sjhb	}
1790171821Sjhb	return (error);
1791171821Sjhb}
1792171821Sjhb
1793171821Sjhb/* Perform post-issue checks on commands from userland. */
1794171821Sjhbstatic void
1795171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
1796171821Sjhb{
1797171821Sjhb	struct mfi_disk *ld, *ldn;
1798171821Sjhb
1799171821Sjhb	switch (cm->cm_frame->dcmd.opcode) {
1800171821Sjhb	case MFI_DCMD_LD_DELETE:
1801171821Sjhb		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1802171821Sjhb			if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
1803171821Sjhb				break;
1804171821Sjhb		}
1805171821Sjhb		KASSERT(ld != NULL, ("volume dissappeared"));
1806171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
1807171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
1808171821Sjhb			mtx_lock(&Giant);
1809171821Sjhb			device_delete_child(sc->mfi_dev, ld->ld_dev);
1810171821Sjhb			mtx_unlock(&Giant);
1811171821Sjhb			mtx_lock(&sc->mfi_io_lock);
1812171821Sjhb		} else
1813171821Sjhb			mfi_disk_enable(ld);
1814171821Sjhb		break;
1815171821Sjhb	case MFI_DCMD_CFG_CLEAR:
1816171821Sjhb		if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
1817171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
1818171821Sjhb			mtx_lock(&Giant);
1819171821Sjhb			TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
1820171821Sjhb				device_delete_child(sc->mfi_dev, ld->ld_dev);
1821171821Sjhb			}
1822171821Sjhb			mtx_unlock(&Giant);
1823171821Sjhb			mtx_lock(&sc->mfi_io_lock);
1824171821Sjhb		} else {
1825171821Sjhb			TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
1826171821Sjhb				mfi_disk_enable(ld);
1827171821Sjhb		}
1828171821Sjhb		break;
1829171821Sjhb	case MFI_DCMD_CFG_ADD:
1830171821Sjhb		mfi_ldprobe(sc);
1831171821Sjhb		break;
1832184897Sambrisko	case MFI_DCMD_CFG_FOREIGN_IMPORT:
1833184897Sambrisko		mfi_ldprobe(sc);
1834184897Sambrisko		break;
1835171821Sjhb	}
1836171821Sjhb}
1837171821Sjhb
1838171821Sjhbstatic int
1839178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
1840178968Sscottl{
1841178968Sscottl	struct mfi_command *cm;
1842178968Sscottl	struct mfi_dcmd_frame *dcmd;
1843178968Sscottl	void *ioc_buf = NULL;
1844178968Sscottl	uint32_t context;
1845178968Sscottl	int error = 0, locked;
1846178968Sscottl
1847178968Sscottl
1848178968Sscottl	if (ioc->buf_size > 0) {
1849178968Sscottl		ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
1850178968Sscottl		if (ioc_buf == NULL) {
1851178968Sscottl			return (ENOMEM);
1852178968Sscottl		}
1853178968Sscottl		error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
1854178968Sscottl		if (error) {
1855178968Sscottl			device_printf(sc->mfi_dev, "failed to copyin\n");
1856178968Sscottl			free(ioc_buf, M_MFIBUF);
1857178968Sscottl			return (error);
1858178968Sscottl		}
1859178968Sscottl	}
1860178968Sscottl
1861178968Sscottl	locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
1862178968Sscottl
1863178968Sscottl	mtx_lock(&sc->mfi_io_lock);
1864178968Sscottl	while ((cm = mfi_dequeue_free(sc)) == NULL)
1865178968Sscottl		msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
1866178968Sscottl
1867178968Sscottl	/* Save context for later */
1868178968Sscottl	context = cm->cm_frame->header.context;
1869178968Sscottl
1870178968Sscottl	dcmd = &cm->cm_frame->dcmd;
1871178968Sscottl	bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
1872178968Sscottl
1873178968Sscottl	cm->cm_sg = &dcmd->sgl;
1874178968Sscottl	cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1875178968Sscottl	cm->cm_data = ioc_buf;
1876178968Sscottl	cm->cm_len = ioc->buf_size;
1877178968Sscottl
1878178968Sscottl	/* restore context */
1879178968Sscottl	cm->cm_frame->header.context = context;
1880178968Sscottl
1881178968Sscottl	/* Cheat since we don't know if we're writing or reading */
1882178968Sscottl	cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
1883178968Sscottl
1884178968Sscottl	error = mfi_check_command_pre(sc, cm);
1885178968Sscottl	if (error)
1886178968Sscottl		goto out;
1887178968Sscottl
1888178968Sscottl	error = mfi_wait_command(sc, cm);
1889178968Sscottl	if (error) {
1890178968Sscottl		device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
1891178968Sscottl		goto out;
1892178968Sscottl	}
1893178968Sscottl	bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
1894178968Sscottl	mfi_check_command_post(sc, cm);
1895178968Sscottlout:
1896178968Sscottl	mfi_release_command(cm);
1897178968Sscottl	mtx_unlock(&sc->mfi_io_lock);
1898178968Sscottl	mfi_config_unlock(sc, locked);
1899178968Sscottl	if (ioc->buf_size > 0)
1900178968Sscottl		error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
1901178968Sscottl	if (ioc_buf)
1902178968Sscottl		free(ioc_buf, M_MFIBUF);
1903178968Sscottl	return (error);
1904178968Sscottl}
1905178968Sscottl
1906178968Sscottl#ifdef __amd64__
1907178968Sscottl#define	PTRIN(p)		((void *)(uintptr_t)(p))
1908178968Sscottl#else
1909178968Sscottl#define	PTRIN(p)		(p)
1910178968Sscottl#endif
1911178968Sscottl
1912178968Sscottlstatic int
1913157114Sscottlmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1914157114Sscottl{
1915157114Sscottl	struct mfi_softc *sc;
1916157114Sscottl	union mfi_statrequest *ms;
1917164281Sambrisko	struct mfi_ioc_packet *ioc;
1918179392Sambrisko#ifdef __amd64__
1919179392Sambrisko	struct mfi_ioc_packet32 *ioc32;
1920179392Sambrisko#endif
1921164281Sambrisko	struct mfi_ioc_aen *aen;
1922164281Sambrisko	struct mfi_command *cm = NULL;
1923164281Sambrisko	uint32_t context;
1924184897Sambrisko	union mfi_sense_ptr sense_ptr;
1925164281Sambrisko	uint8_t *data = NULL, *temp;
1926164281Sambrisko	int i;
1927178968Sscottl	struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
1928178968Sscottl#ifdef __amd64__
1929178968Sscottl	struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
1930178968Sscottl	struct mfi_ioc_passthru iop_swab;
1931178968Sscottl#endif
1932171821Sjhb	int error, locked;
1933157114Sscottl
1934157114Sscottl	sc = dev->si_drv1;
1935157114Sscottl	error = 0;
1936157114Sscottl
1937157114Sscottl	switch (cmd) {
1938157114Sscottl	case MFIIO_STATS:
1939157114Sscottl		ms = (union mfi_statrequest *)arg;
1940157114Sscottl		switch (ms->ms_item) {
1941157114Sscottl		case MFIQ_FREE:
1942157114Sscottl		case MFIQ_BIO:
1943157114Sscottl		case MFIQ_READY:
1944157114Sscottl		case MFIQ_BUSY:
1945157114Sscottl			bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
1946157114Sscottl			    sizeof(struct mfi_qstat));
1947157114Sscottl			break;
1948157114Sscottl		default:
1949158737Sambrisko			error = ENOIOCTL;
1950157114Sscottl			break;
1951157114Sscottl		}
1952157114Sscottl		break;
1953169451Sscottl	case MFIIO_QUERY_DISK:
1954169451Sscottl	{
1955169451Sscottl		struct mfi_query_disk *qd;
1956169451Sscottl		struct mfi_disk *ld;
1957169451Sscottl
1958169451Sscottl		qd = (struct mfi_query_disk *)arg;
1959169451Sscottl		mtx_lock(&sc->mfi_io_lock);
1960169451Sscottl		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1961169451Sscottl			if (ld->ld_id == qd->array_id)
1962169451Sscottl				break;
1963169451Sscottl		}
1964169451Sscottl		if (ld == NULL) {
1965169451Sscottl			qd->present = 0;
1966169451Sscottl			mtx_unlock(&sc->mfi_io_lock);
1967169451Sscottl			return (0);
1968169451Sscottl		}
1969169451Sscottl		qd->present = 1;
1970169451Sscottl		if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
1971169451Sscottl			qd->open = 1;
1972169451Sscottl		bzero(qd->devname, SPECNAMELEN + 1);
1973169451Sscottl		snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
1974169451Sscottl		mtx_unlock(&sc->mfi_io_lock);
1975169451Sscottl		break;
1976169451Sscottl	}
1977164281Sambrisko	case MFI_CMD:
1978179392Sambrisko#ifdef __amd64__
1979179392Sambrisko	case MFI_CMD32:
1980179392Sambrisko#endif
1981177489Sambrisko		{
1982177489Sambrisko		devclass_t devclass;
1983164281Sambrisko		ioc = (struct mfi_ioc_packet *)arg;
1984177489Sambrisko		int adapter;
1985164281Sambrisko
1986177489Sambrisko		adapter = ioc->mfi_adapter_no;
1987177489Sambrisko		if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
1988177489Sambrisko			devclass = devclass_find("mfi");
1989177489Sambrisko			sc = devclass_get_softc(devclass, adapter);
1990177489Sambrisko		}
1991164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
1992164281Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
1993164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
1994164281Sambrisko			return (EBUSY);
1995164281Sambrisko		}
1996164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
1997171821Sjhb		locked = 0;
1998164281Sambrisko
1999164281Sambrisko		/*
2000164281Sambrisko		 * save off original context since copying from user
2001164281Sambrisko		 * will clobber some data
2002164281Sambrisko		 */
2003164281Sambrisko		context = cm->cm_frame->header.context;
2004164281Sambrisko
2005165225Sambrisko		bcopy(ioc->mfi_frame.raw, cm->cm_frame,
2006184897Sambrisko		    2 * MFI_DCMD_FRAME_SIZE);  /* this isn't quite right */
2007184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
2008184897Sambrisko		    * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
2009175897Sambrisko		if (ioc->mfi_sge_count) {
2010175897Sambrisko			cm->cm_sg =
2011175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
2012175897Sambrisko		}
2013175897Sambrisko		cm->cm_flags = 0;
2014175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
2015175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
2016175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
2017175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
2018175897Sambrisko		/* Legacy app shim */
2019175897Sambrisko		if (cm->cm_flags == 0)
2020175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
2021164281Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
2022184897Sambrisko		if (cm->cm_len &&
2023184897Sambrisko		    (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
2024175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
2025175897Sambrisko			    M_WAITOK | M_ZERO);
2026175897Sambrisko			if (cm->cm_data == NULL) {
2027175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
2028175897Sambrisko				goto out;
2029175897Sambrisko			}
2030175897Sambrisko		} else {
2031175897Sambrisko			cm->cm_data = 0;
2032165225Sambrisko		}
2033164281Sambrisko
2034164281Sambrisko		/* restore header context */
2035164281Sambrisko		cm->cm_frame->header.context = context;
2036164281Sambrisko
2037164281Sambrisko		temp = data;
2038175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
2039175897Sambrisko			for (i = 0; i < ioc->mfi_sge_count; i++) {
2040179392Sambrisko#ifdef __amd64__
2041179392Sambrisko				if (cmd == MFI_CMD) {
2042179392Sambrisko					/* Native */
2043179392Sambrisko					error = copyin(ioc->mfi_sgl[i].iov_base,
2044179392Sambrisko					       temp,
2045179392Sambrisko					       ioc->mfi_sgl[i].iov_len);
2046179392Sambrisko				} else {
2047179392Sambrisko					void *temp_convert;
2048179392Sambrisko					/* 32bit */
2049179392Sambrisko					ioc32 = (struct mfi_ioc_packet32 *)ioc;
2050179392Sambrisko					temp_convert =
2051179392Sambrisko					    PTRIN(ioc32->mfi_sgl[i].iov_base);
2052179392Sambrisko					error = copyin(temp_convert,
2053179392Sambrisko					       temp,
2054179392Sambrisko					       ioc32->mfi_sgl[i].iov_len);
2055179392Sambrisko				}
2056179392Sambrisko#else
2057175897Sambrisko				error = copyin(ioc->mfi_sgl[i].iov_base,
2058175897Sambrisko				       temp,
2059175897Sambrisko				       ioc->mfi_sgl[i].iov_len);
2060179392Sambrisko#endif
2061175897Sambrisko				if (error != 0) {
2062175897Sambrisko					device_printf(sc->mfi_dev,
2063175897Sambrisko					    "Copy in failed\n");
2064175897Sambrisko					goto out;
2065175897Sambrisko				}
2066175897Sambrisko				temp = &temp[ioc->mfi_sgl[i].iov_len];
2067164281Sambrisko			}
2068164281Sambrisko		}
2069164281Sambrisko
2070171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
2071171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
2072171821Sjhb
2073184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
2074184933Sambrisko			cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
2075184933Sambrisko			cm->cm_frame->pass.sense_addr_hi = 0;
2076184933Sambrisko		}
2077184933Sambrisko
2078164281Sambrisko		mtx_lock(&sc->mfi_io_lock);
2079171821Sjhb		error = mfi_check_command_pre(sc, cm);
2080171821Sjhb		if (error) {
2081171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2082171821Sjhb			goto out;
2083171821Sjhb		}
2084171821Sjhb
2085170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
2086164281Sambrisko			device_printf(sc->mfi_dev,
2087165225Sambrisko			    "Controller polled failed\n");
2088164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2089164281Sambrisko			goto out;
2090164281Sambrisko		}
2091164281Sambrisko
2092171821Sjhb		mfi_check_command_post(sc, cm);
2093164281Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2094164281Sambrisko
2095164281Sambrisko		temp = data;
2096175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
2097175897Sambrisko			for (i = 0; i < ioc->mfi_sge_count; i++) {
2098179392Sambrisko#ifdef __amd64__
2099179392Sambrisko				if (cmd == MFI_CMD) {
2100179392Sambrisko					/* Native */
2101179392Sambrisko					error = copyout(temp,
2102179392Sambrisko						ioc->mfi_sgl[i].iov_base,
2103179392Sambrisko						ioc->mfi_sgl[i].iov_len);
2104179392Sambrisko				} else {
2105179392Sambrisko					void *temp_convert;
2106179392Sambrisko					/* 32bit */
2107179392Sambrisko					ioc32 = (struct mfi_ioc_packet32 *)ioc;
2108179392Sambrisko					temp_convert =
2109179392Sambrisko					    PTRIN(ioc32->mfi_sgl[i].iov_base);
2110179392Sambrisko					error = copyout(temp,
2111179392Sambrisko						temp_convert,
2112179392Sambrisko						ioc32->mfi_sgl[i].iov_len);
2113179392Sambrisko				}
2114179392Sambrisko#else
2115175897Sambrisko				error = copyout(temp,
2116175897Sambrisko					ioc->mfi_sgl[i].iov_base,
2117175897Sambrisko					ioc->mfi_sgl[i].iov_len);
2118179392Sambrisko#endif
2119175897Sambrisko				if (error != 0) {
2120175897Sambrisko					device_printf(sc->mfi_dev,
2121175897Sambrisko					    "Copy out failed\n");
2122175897Sambrisko					goto out;
2123175897Sambrisko				}
2124175897Sambrisko				temp = &temp[ioc->mfi_sgl[i].iov_len];
2125164281Sambrisko			}
2126164281Sambrisko		}
2127164281Sambrisko
2128165225Sambrisko		if (ioc->mfi_sense_len) {
2129184897Sambrisko			/* get user-space sense ptr then copy out sense */
2130184897Sambrisko			bcopy(&((struct mfi_ioc_packet*)arg)
2131184897Sambrisko			    ->mfi_frame.raw[ioc->mfi_sense_off],
2132184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
2133184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
2134184974Sambrisko#ifdef __amd64__
2135184974Sambrisko			if (cmd != MFI_CMD) {
2136184974Sambrisko				/*
2137184974Sambrisko				 * not 64bit native so zero out any address
2138184974Sambrisko				 * over 32bit */
2139184975Sambrisko				sense_ptr.addr.high = 0;
2140184974Sambrisko			}
2141184974Sambrisko#endif
2142184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
2143165225Sambrisko			    ioc->mfi_sense_len);
2144164281Sambrisko			if (error != 0) {
2145164281Sambrisko				device_printf(sc->mfi_dev,
2146165225Sambrisko				    "Copy out failed\n");
2147164281Sambrisko				goto out;
2148164281Sambrisko			}
2149164281Sambrisko		}
2150164281Sambrisko
2151165225Sambrisko		ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
2152164281Sambriskoout:
2153171821Sjhb		mfi_config_unlock(sc, locked);
2154164281Sambrisko		if (data)
2155164281Sambrisko			free(data, M_MFIBUF);
2156164281Sambrisko		if (cm) {
2157164281Sambrisko			mtx_lock(&sc->mfi_io_lock);
2158164281Sambrisko			mfi_release_command(cm);
2159164281Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2160164281Sambrisko		}
2161164281Sambrisko
2162164281Sambrisko		break;
2163177489Sambrisko		}
2164164281Sambrisko	case MFI_SET_AEN:
2165164281Sambrisko		aen = (struct mfi_ioc_aen *)arg;
2166164281Sambrisko		error = mfi_aen_register(sc, aen->aen_seq_num,
2167164281Sambrisko		    aen->aen_class_locale);
2168164281Sambrisko
2169164281Sambrisko		break;
2170164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
2171158737Sambrisko		{
2172158737Sambrisko			devclass_t devclass;
2173158737Sambrisko			struct mfi_linux_ioc_packet l_ioc;
2174158737Sambrisko			int adapter;
2175158737Sambrisko
2176158737Sambrisko			devclass = devclass_find("mfi");
2177158737Sambrisko			if (devclass == NULL)
2178158737Sambrisko				return (ENOENT);
2179158737Sambrisko
2180158737Sambrisko			error = copyin(arg, &l_ioc, sizeof(l_ioc));
2181158737Sambrisko			if (error)
2182158737Sambrisko				return (error);
2183158737Sambrisko			adapter = l_ioc.lioc_adapter_no;
2184158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
2185158737Sambrisko			if (sc == NULL)
2186158737Sambrisko				return (ENOENT);
2187158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
2188158737Sambrisko			    cmd, arg, flag, td));
2189158737Sambrisko			break;
2190158737Sambrisko		}
2191164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
2192158737Sambrisko		{
2193158737Sambrisko			devclass_t devclass;
2194158737Sambrisko			struct mfi_linux_ioc_aen l_aen;
2195158737Sambrisko			int adapter;
2196158737Sambrisko
2197158737Sambrisko			devclass = devclass_find("mfi");
2198158737Sambrisko			if (devclass == NULL)
2199158737Sambrisko				return (ENOENT);
2200158737Sambrisko
2201158737Sambrisko			error = copyin(arg, &l_aen, sizeof(l_aen));
2202158737Sambrisko			if (error)
2203158737Sambrisko				return (error);
2204158737Sambrisko			adapter = l_aen.laen_adapter_no;
2205158737Sambrisko			sc = devclass_get_softc(devclass, adapter);
2206158737Sambrisko			if (sc == NULL)
2207158737Sambrisko				return (ENOENT);
2208158737Sambrisko			return (mfi_linux_ioctl_int(sc->mfi_cdev,
2209158737Sambrisko			    cmd, arg, flag, td));
2210158737Sambrisko			break;
2211158737Sambrisko		}
2212178968Sscottl#ifdef __amd64__
2213178968Sscottl	case MFIIO_PASSTHRU32:
2214178968Sscottl		iop_swab.ioc_frame	= iop32->ioc_frame;
2215178968Sscottl		iop_swab.buf_size	= iop32->buf_size;
2216178968Sscottl		iop_swab.buf		= PTRIN(iop32->buf);
2217178968Sscottl		iop			= &iop_swab;
2218178968Sscottl		/* FALLTHROUGH */
2219178968Sscottl#endif
2220178968Sscottl	case MFIIO_PASSTHRU:
2221178968Sscottl		error = mfi_user_command(sc, iop);
2222178968Sscottl#ifdef __amd64__
2223178968Sscottl		if (cmd == MFIIO_PASSTHRU32)
2224178968Sscottl			iop32->ioc_frame = iop_swab.ioc_frame;
2225178968Sscottl#endif
2226178968Sscottl		break;
2227157114Sscottl	default:
2228163398Sscottl		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
2229157114Sscottl		error = ENOENT;
2230157114Sscottl		break;
2231157114Sscottl	}
2232157114Sscottl
2233157114Sscottl	return (error);
2234157114Sscottl}
2235158737Sambrisko
2236158737Sambriskostatic int
2237158737Sambriskomfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
2238158737Sambrisko{
2239158737Sambrisko	struct mfi_softc *sc;
2240158737Sambrisko	struct mfi_linux_ioc_packet l_ioc;
2241158737Sambrisko	struct mfi_linux_ioc_aen l_aen;
2242158737Sambrisko	struct mfi_command *cm = NULL;
2243158737Sambrisko	struct mfi_aen *mfi_aen_entry;
2244184897Sambrisko	union mfi_sense_ptr sense_ptr;
2245158737Sambrisko	uint32_t context;
2246158737Sambrisko	uint8_t *data = NULL, *temp;
2247158737Sambrisko	int i;
2248171821Sjhb	int error, locked;
2249158737Sambrisko
2250158737Sambrisko	sc = dev->si_drv1;
2251158737Sambrisko	error = 0;
2252158737Sambrisko	switch (cmd) {
2253164281Sambrisko	case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
2254158737Sambrisko		error = copyin(arg, &l_ioc, sizeof(l_ioc));
2255158737Sambrisko		if (error != 0)
2256158737Sambrisko			return (error);
2257158737Sambrisko
2258158737Sambrisko		if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
2259158737Sambrisko			return (EINVAL);
2260158737Sambrisko		}
2261158737Sambrisko
2262158737Sambrisko		mtx_lock(&sc->mfi_io_lock);
2263158737Sambrisko		if ((cm = mfi_dequeue_free(sc)) == NULL) {
2264158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2265158737Sambrisko			return (EBUSY);
2266158737Sambrisko		}
2267158737Sambrisko		mtx_unlock(&sc->mfi_io_lock);
2268171821Sjhb		locked = 0;
2269158737Sambrisko
2270158737Sambrisko		/*
2271158737Sambrisko		 * save off original context since copying from user
2272158737Sambrisko		 * will clobber some data
2273158737Sambrisko		 */
2274158737Sambrisko		context = cm->cm_frame->header.context;
2275158737Sambrisko
2276158737Sambrisko		bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
2277175897Sambrisko		      2 * MFI_DCMD_FRAME_SIZE);	/* this isn't quite right */
2278184897Sambrisko		cm->cm_total_frame_size = (sizeof(union mfi_sgl)
2279184897Sambrisko		      * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
2280175897Sambrisko		if (l_ioc.lioc_sge_count)
2281175897Sambrisko			cm->cm_sg =
2282175897Sambrisko			    (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
2283175897Sambrisko		cm->cm_flags = 0;
2284175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
2285175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAIN;
2286175897Sambrisko		if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
2287175897Sambrisko			cm->cm_flags |= MFI_CMD_DATAOUT;
2288158737Sambrisko		cm->cm_len = cm->cm_frame->header.data_len;
2289184897Sambrisko		if (cm->cm_len &&
2290184897Sambrisko		      (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
2291175897Sambrisko			cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
2292175897Sambrisko			    M_WAITOK | M_ZERO);
2293175897Sambrisko			if (cm->cm_data == NULL) {
2294175897Sambrisko				device_printf(sc->mfi_dev, "Malloc failed\n");
2295175897Sambrisko				goto out;
2296175897Sambrisko			}
2297175897Sambrisko		} else {
2298175897Sambrisko			cm->cm_data = 0;
2299175897Sambrisko		}
2300158737Sambrisko
2301158737Sambrisko		/* restore header context */
2302158737Sambrisko		cm->cm_frame->header.context = context;
2303158737Sambrisko
2304158737Sambrisko		temp = data;
2305175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAOUT) {
2306175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
2307178968Sscottl				error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
2308175897Sambrisko				       temp,
2309175897Sambrisko				       l_ioc.lioc_sgl[i].iov_len);
2310175897Sambrisko				if (error != 0) {
2311175897Sambrisko					device_printf(sc->mfi_dev,
2312175897Sambrisko					    "Copy in failed\n");
2313175897Sambrisko					goto out;
2314175897Sambrisko				}
2315175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
2316158737Sambrisko			}
2317158737Sambrisko		}
2318158737Sambrisko
2319171821Sjhb		if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
2320171821Sjhb			locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
2321171821Sjhb
2322184933Sambrisko		if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
2323184933Sambrisko			cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
2324184933Sambrisko			cm->cm_frame->pass.sense_addr_hi = 0;
2325184933Sambrisko		}
2326184933Sambrisko
2327163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2328171821Sjhb		error = mfi_check_command_pre(sc, cm);
2329171821Sjhb		if (error) {
2330171821Sjhb			mtx_unlock(&sc->mfi_io_lock);
2331171821Sjhb			goto out;
2332171821Sjhb		}
2333171821Sjhb
2334170284Sambrisko		if ((error = mfi_wait_command(sc, cm)) != 0) {
2335158737Sambrisko			device_printf(sc->mfi_dev,
2336165225Sambrisko			    "Controller polled failed\n");
2337163398Sscottl			mtx_unlock(&sc->mfi_io_lock);
2338158737Sambrisko			goto out;
2339158737Sambrisko		}
2340158737Sambrisko
2341171821Sjhb		mfi_check_command_post(sc, cm);
2342163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2343158737Sambrisko
2344158737Sambrisko		temp = data;
2345175897Sambrisko		if (cm->cm_flags & MFI_CMD_DATAIN) {
2346175897Sambrisko			for (i = 0; i < l_ioc.lioc_sge_count; i++) {
2347175897Sambrisko				error = copyout(temp,
2348178968Sscottl					PTRIN(l_ioc.lioc_sgl[i].iov_base),
2349175897Sambrisko					l_ioc.lioc_sgl[i].iov_len);
2350175897Sambrisko				if (error != 0) {
2351175897Sambrisko					device_printf(sc->mfi_dev,
2352175897Sambrisko					    "Copy out failed\n");
2353175897Sambrisko					goto out;
2354175897Sambrisko				}
2355175897Sambrisko				temp = &temp[l_ioc.lioc_sgl[i].iov_len];
2356158737Sambrisko			}
2357158737Sambrisko		}
2358158737Sambrisko
2359158737Sambrisko		if (l_ioc.lioc_sense_len) {
2360184897Sambrisko			/* get user-space sense ptr then copy out sense */
2361184897Sambrisko			bcopy(&((struct mfi_linux_ioc_packet*)arg)
2362184897Sambrisko                            ->lioc_frame.raw[l_ioc.lioc_sense_off],
2363184897Sambrisko			    &sense_ptr.sense_ptr_data[0],
2364184897Sambrisko			    sizeof(sense_ptr.sense_ptr_data));
2365184974Sambrisko#ifdef __amd64__
2366184974Sambrisko			/*
2367184974Sambrisko			 * only 32bit Linux support so zero out any
2368184974Sambrisko			 * address over 32bit
2369184974Sambrisko			 */
2370184975Sambrisko			sense_ptr.addr.high = 0;
2371184974Sambrisko#endif
2372184897Sambrisko			error = copyout(cm->cm_sense, sense_ptr.user_space,
2373158737Sambrisko			    l_ioc.lioc_sense_len);
2374158737Sambrisko			if (error != 0) {
2375158737Sambrisko				device_printf(sc->mfi_dev,
2376165225Sambrisko				    "Copy out failed\n");
2377158737Sambrisko				goto out;
2378158737Sambrisko			}
2379158737Sambrisko		}
2380158737Sambrisko
2381158737Sambrisko		error = copyout(&cm->cm_frame->header.cmd_status,
2382158737Sambrisko			&((struct mfi_linux_ioc_packet*)arg)
2383158737Sambrisko			->lioc_frame.hdr.cmd_status,
2384158737Sambrisko			1);
2385158737Sambrisko		if (error != 0) {
2386158737Sambrisko			device_printf(sc->mfi_dev,
2387165225Sambrisko				      "Copy out failed\n");
2388158737Sambrisko			goto out;
2389158737Sambrisko		}
2390158737Sambrisko
2391158737Sambriskoout:
2392171821Sjhb		mfi_config_unlock(sc, locked);
2393158737Sambrisko		if (data)
2394158737Sambrisko			free(data, M_MFIBUF);
2395158737Sambrisko		if (cm) {
2396158737Sambrisko			mtx_lock(&sc->mfi_io_lock);
2397158737Sambrisko			mfi_release_command(cm);
2398158737Sambrisko			mtx_unlock(&sc->mfi_io_lock);
2399158737Sambrisko		}
2400158737Sambrisko
2401158737Sambrisko		return (error);
2402164281Sambrisko	case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
2403158737Sambrisko		error = copyin(arg, &l_aen, sizeof(l_aen));
2404158737Sambrisko		if (error != 0)
2405158737Sambrisko			return (error);
2406158737Sambrisko		printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
2407158737Sambrisko		mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
2408158737Sambrisko		    M_WAITOK);
2409163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2410158737Sambrisko		if (mfi_aen_entry != NULL) {
2411158737Sambrisko			mfi_aen_entry->p = curproc;
2412158737Sambrisko			TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry,
2413158737Sambrisko			    aen_link);
2414158737Sambrisko		}
2415158737Sambrisko		error = mfi_aen_register(sc, l_aen.laen_seq_num,
2416158737Sambrisko		    l_aen.laen_class_locale);
2417158737Sambrisko
2418158737Sambrisko		if (error != 0) {
2419158737Sambrisko			TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2420158737Sambrisko			    aen_link);
2421158737Sambrisko			free(mfi_aen_entry, M_MFIBUF);
2422158737Sambrisko		}
2423163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2424158737Sambrisko
2425158737Sambrisko		return (error);
2426158737Sambrisko	default:
2427158737Sambrisko		device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
2428158737Sambrisko		error = ENOENT;
2429158737Sambrisko		break;
2430158737Sambrisko	}
2431158737Sambrisko
2432158737Sambrisko	return (error);
2433158737Sambrisko}
2434158737Sambrisko
2435158737Sambriskostatic int
2436158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td)
2437158737Sambrisko{
2438158737Sambrisko	struct mfi_softc *sc;
2439158737Sambrisko	int revents = 0;
2440158737Sambrisko
2441158737Sambrisko	sc = dev->si_drv1;
2442158737Sambrisko
2443158737Sambrisko	if (poll_events & (POLLIN | POLLRDNORM)) {
2444163398Sscottl		if (sc->mfi_aen_triggered != 0) {
2445158737Sambrisko			revents |= poll_events & (POLLIN | POLLRDNORM);
2446163398Sscottl			sc->mfi_aen_triggered = 0;
2447163398Sscottl		}
2448158737Sambrisko		if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
2449158737Sambrisko			revents |= POLLERR;
2450158737Sambrisko		}
2451158737Sambrisko	}
2452158737Sambrisko
2453158737Sambrisko	if (revents == 0) {
2454158737Sambrisko		if (poll_events & (POLLIN | POLLRDNORM)) {
2455158737Sambrisko			sc->mfi_poll_waiting = 1;
2456158737Sambrisko			selrecord(td, &sc->mfi_select);
2457158737Sambrisko		}
2458158737Sambrisko	}
2459158737Sambrisko
2460158737Sambrisko	return revents;
2461158737Sambrisko}
2462162619Sscottl
2463163398Sscottl
2464162619Sscottlstatic void
2465163398Sscottlmfi_dump_all(void)
2466163398Sscottl{
2467163398Sscottl	struct mfi_softc *sc;
2468163398Sscottl	struct mfi_command *cm;
2469163398Sscottl	devclass_t dc;
2470163398Sscottl	time_t deadline;
2471163398Sscottl	int timedout;
2472163398Sscottl	int i;
2473163398Sscottl
2474163398Sscottl	dc = devclass_find("mfi");
2475163398Sscottl	if (dc == NULL) {
2476163398Sscottl		printf("No mfi dev class\n");
2477163398Sscottl		return;
2478163398Sscottl	}
2479163398Sscottl
2480163398Sscottl	for (i = 0; ; i++) {
2481163398Sscottl		sc = devclass_get_softc(dc, i);
2482163398Sscottl		if (sc == NULL)
2483163398Sscottl			break;
2484163398Sscottl		device_printf(sc->mfi_dev, "Dumping\n\n");
2485163398Sscottl		timedout = 0;
2486163398Sscottl		deadline = time_uptime - MFI_CMD_TIMEOUT;
2487163398Sscottl		mtx_lock(&sc->mfi_io_lock);
2488163398Sscottl		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2489163398Sscottl			if (cm->cm_timestamp < deadline) {
2490163398Sscottl				device_printf(sc->mfi_dev,
2491163398Sscottl				    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2492163398Sscottl				    (int)(time_uptime - cm->cm_timestamp));
2493163398Sscottl				MFI_PRINT_CMD(cm);
2494163398Sscottl				timedout++;
2495163398Sscottl			}
2496163398Sscottl		}
2497163398Sscottl
2498163398Sscottl#if 0
2499163398Sscottl		if (timedout)
2500163398Sscottl			MFI_DUMP_CMDS(SC);
2501163398Sscottl#endif
2502163398Sscottl
2503163398Sscottl		mtx_unlock(&sc->mfi_io_lock);
2504163398Sscottl	}
2505163398Sscottl
2506163398Sscottl	return;
2507163398Sscottl}
2508163398Sscottl
2509163398Sscottlstatic void
2510162619Sscottlmfi_timeout(void *data)
2511162619Sscottl{
2512162619Sscottl	struct mfi_softc *sc = (struct mfi_softc *)data;
2513162619Sscottl	struct mfi_command *cm;
2514162619Sscottl	time_t deadline;
2515162619Sscottl	int timedout = 0;
2516162619Sscottl
2517162619Sscottl	deadline = time_uptime - MFI_CMD_TIMEOUT;
2518162619Sscottl	mtx_lock(&sc->mfi_io_lock);
2519162619Sscottl	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
2520162688Sscottl		if (sc->mfi_aen_cm == cm)
2521162688Sscottl			continue;
2522163398Sscottl		if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
2523162619Sscottl			device_printf(sc->mfi_dev,
2524162619Sscottl			    "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
2525162619Sscottl			    (int)(time_uptime - cm->cm_timestamp));
2526162619Sscottl			MFI_PRINT_CMD(cm);
2527163398Sscottl			MFI_VALIDATE_CMD(sc, cm);
2528162619Sscottl			timedout++;
2529162619Sscottl		}
2530162619Sscottl	}
2531162619Sscottl
2532162619Sscottl#if 0
2533162619Sscottl	if (timedout)
2534162619Sscottl		MFI_DUMP_CMDS(SC);
2535162619Sscottl#endif
2536162619Sscottl
2537162619Sscottl	mtx_unlock(&sc->mfi_io_lock);
2538162619Sscottl
2539162619Sscottl	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
2540162619Sscottl	    mfi_timeout, sc);
2541162619Sscottl
2542163398Sscottl	if (0)
2543163398Sscottl		mfi_dump_all();
2544162619Sscottl	return;
2545162619Sscottl}
2546